Bitcoin Core 32.99.0
P2P Digital Currency
transaction.h
Go to the documentation of this file.
1// Copyright (c) 2021-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_WALLET_TRANSACTION_H
6#define BITCOIN_WALLET_TRANSACTION_H
7
8#include <attributes.h>
9#include <consensus/amount.h>
11#include <tinyformat.h>
12#include <uint256.h>
13#include <util/check.h>
14#include <util/overloaded.h>
15#include <util/strencodings.h>
16#include <util/string.h>
17#include <wallet/types.h>
18
19#include <bitset>
20#include <cstdint>
21#include <map>
22#include <utility>
23#include <variant>
24#include <vector>
25
26namespace interfaces {
27class Chain;
28} // namespace interfaces
29
30namespace wallet {
31class WalletBatch;
32
38
39 explicit TxStateConfirmed(const uint256& block_hash, int height, int index) : confirmed_block_hash(block_hash), confirmed_block_height(height), position_in_block(index) {}
40 std::string toString() const { return strprintf("Confirmed (block=%s, height=%i, index=%i)", confirmed_block_hash.ToString(), confirmed_block_height, position_in_block); }
41};
42
45 std::string toString() const { return strprintf("InMempool"); }
46};
47
52
53 explicit TxStateBlockConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
54 std::string toString() const { return strprintf("BlockConflicted (block=%s, height=%i)", conflicting_block_hash.ToString(), conflicting_block_height); }
55};
56
63
64 explicit TxStateInactive(bool abandoned = false) : abandoned(abandoned) {}
65 std::string toString() const { return strprintf("Inactive (abandoned=%i)", abandoned); }
66};
67
74 int index;
75
77 std::string toString() const { return strprintf("Unrecognized (block=%s, index=%i)", block_hash.ToString(), index); }
78};
79
81using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized>;
82
84using SyncTxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateInactive>;
85
88{
89 if (data.block_hash == uint256::ZERO) {
90 if (data.index == 0) return TxStateInactive{};
91 } else if (data.block_hash == uint256::ONE) {
92 if (data.index == -1) return TxStateInactive{/*abandoned=*/true};
93 } else if (data.index >= 0) {
94 return TxStateConfirmed{data.block_hash, /*height=*/-1, data.index};
95 } else if (data.index == -1) {
96 return TxStateBlockConflicted{data.block_hash, /*height=*/-1};
97 }
98 return data;
99}
100
102static inline uint256 TxStateSerializedBlockHash(const TxState& state)
103{
104 return std::visit(util::Overloaded{
105 [](const TxStateInactive& inactive) { return inactive.abandoned ? uint256::ONE : uint256::ZERO; },
106 [](const TxStateInMempool& in_mempool) { return uint256::ZERO; },
107 [](const TxStateConfirmed& confirmed) { return confirmed.confirmed_block_hash; },
108 [](const TxStateBlockConflicted& conflicted) { return conflicted.conflicting_block_hash; },
109 [](const TxStateUnrecognized& unrecognized) { return unrecognized.block_hash; }
110 }, state);
111}
112
114static inline int TxStateSerializedIndex(const TxState& state)
115{
116 return std::visit(util::Overloaded{
117 [](const TxStateInactive& inactive) { return inactive.abandoned ? -1 : 0; },
118 [](const TxStateInMempool& in_mempool) { return 0; },
119 [](const TxStateConfirmed& confirmed) { return confirmed.position_in_block; },
120 [](const TxStateBlockConflicted& conflicted) { return -1; },
121 [](const TxStateUnrecognized& unrecognized) { return unrecognized.index; }
122 }, state);
123}
124
126template<typename T>
127std::string TxStateString(const T& state)
128{
129 return std::visit([](const auto& s) { return s.toString(); }, state);
130}
131
136{
137 std::optional<CAmount> m_avoid_reuse_value;
138 std::optional<CAmount> m_all_value;
139 inline void Reset()
140 {
141 m_avoid_reuse_value.reset();
142 m_all_value.reset();
143 }
144 void Set(bool avoid_reuse, CAmount value)
145 {
146 if (avoid_reuse) {
147 m_avoid_reuse_value = value;
148 } else {
149 m_all_value = value;
150 }
151 }
152 CAmount Get(bool avoid_reuse)
153 {
154 if (avoid_reuse) {
155 Assert(m_avoid_reuse_value.has_value());
156 return m_avoid_reuse_value.value();
157 }
158 Assert(m_all_value.has_value());
159 return m_all_value.value();
160 }
161 bool IsCached(bool avoid_reuse)
162 {
163 if (avoid_reuse) return m_avoid_reuse_value.has_value();
164 return m_all_value.has_value();
165 }
166};
167
168
175{
176public:
177 template<typename Stream>
179 {
181 uint256 hashBlock;
182 std::vector<uint256> vMerkleBranch;
183 int nIndex;
184
185 s >> TX_WITH_WITNESS(tx) >> hashBlock >> vMerkleBranch >> nIndex;
186 }
187};
188
194{
195public:
196 // "from" and "message" are obsolete fields that could be set in
197 // the UI prior to 2011 (removed in commit 4d9b223)
198 // These fields are kept to avoid losing metadata.
199 std::optional<std::string> m_from;
200 std::optional<std::string> m_message;
201 // Comment strings provided by the user
202 std::optional<std::string> m_comment;
203 std::optional<std::string> m_comment_to;
204 std::optional<Txid> m_replaces_txid;
205 std::optional<Txid> m_replaced_by_txid;
206 // BIP 21 URI Messages
207 std::vector<std::string> m_messages;
208 // BIP 70 Payment Request (deprecated, field kept to preserve metadata from old wallets)
209 std::vector<std::string> m_payment_requests;
210 unsigned int nTimeReceived;
220 unsigned int nTimeSmart;
221 // Cached value for whether the transaction spends any inputs known to the wallet
222 mutable std::optional<bool> m_cached_from_me{std::nullopt};
223 int64_t nOrderPos;
224 std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
225
226 // memory only
235 mutable bool m_is_cache_empty{true};
236 mutable bool fChangeCached;
238
240 {
241 Assert(tx);
242 m_canonical_wtxid = tx->GetWitnessHash();
243 m_txs.emplace(tx->GetWitnessHash(), std::move(tx));
244 SetDefaults();
245 }
246
247 template <typename Stream>
248 CWalletTx(deserialize_type, Stream& s, const std::map<Wtxid, CTransactionRef>& variants) : m_state(TxStateInactive{})
249 {
250 Unserialize(s);
251 const Txid& canonical_txid = GetHash();
252 for (const auto& [wtxid, tx] : variants) {
253 if (tx->GetHash() != canonical_txid) throw std::runtime_error("variant txid does not match wallet txid");
254 }
255 // Merge witness variants
256 m_txs.insert(variants.begin(), variants.end());
257 Assert(m_txs.contains(GetWitnessHash()));
258 }
259
261
262 // Set of mempool transactions that conflict
263 // directly with the transaction, or that conflict
264 // with an ancestor transaction. This set will be
265 // empty if state is InMempool or Confirmed, but
266 // can be nonempty if state is Inactive or
267 // BlockConflicted.
268 std::set<Txid> mempool_conflicts;
269
270 // Track v3 mempool tx that spends from this tx
271 // so that we don't try to create another unconfirmed child
272 std::optional<Txid> truc_child_in_mempool;
273
274 template<typename Stream>
275 void Serialize(Stream& s) const
276 {
277 std::map<std::string, std::string> string_values;
278 if (m_from) string_values["from"] = *m_from;
279 if (m_message) string_values["message"] = *m_message;
280 if (m_comment) string_values["comment"] = *m_comment;
281 if (m_comment_to) string_values["to"] = *m_comment_to;
282 if (m_replaces_txid) string_values["replaces_txid"] = m_replaces_txid->ToString();
283 if (m_replaced_by_txid) string_values["replaced_by_txid"] = m_replaced_by_txid->ToString();
284 string_values["fromaccount"] = "";
285 if (nOrderPos != -1) string_values["n"] = util::ToString(nOrderPos);
286 if (nTimeSmart) string_values["timesmart"] = strprintf("%u", nTimeSmart);
287
288 std::vector<std::pair<std::string, std::string>> msgs_reqs;
289 msgs_reqs.reserve(m_messages.size() + m_payment_requests.size());
290 for (const std::string& msg : m_messages) {
291 msgs_reqs.emplace_back("Message", msg);
292 }
293 for (const std::string& req : m_payment_requests) {
294 msgs_reqs.emplace_back("PaymentRequest", req);
295 }
296
297 std::vector<uint8_t> dummy_vector1; // Used to be vMerkleBranch
298 std::vector<uint8_t> dummy_vector2; // Used to be vtxPrev
299 bool dummy_bool = false; // Used to be fFromMe, and fSpent
300 uint32_t dummy_int = 0; // Used to be fTimeReceivedIsTxTime
302 int serializedIndex = TxStateSerializedIndex(m_state);
303 s << TX_WITH_WITNESS(GetTx()) << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << string_values << msgs_reqs << dummy_int << nTimeReceived << dummy_bool << dummy_bool;
304 }
305
306 template<typename Stream>
308 {
309 Init();
310
311 std::vector<uint256> dummy_vector1; // Used to be vMerkleBranch
312 std::vector<CMerkleTx> dummy_vector2; // Used to be vtxPrev
313 bool dummy_bool; // Used to be fFromMe, and fSpent
314 uint32_t dummy_int; // Used to be fTimeReceivedIsTxTime
315 uint256 serialized_block_hash;
316 int serializedIndex;
317 std::map<std::string, std::string> string_values;
318 std::vector<std::pair<std::string, std::string>> msgs_reqs;
319 CTransactionRef canonical_tx;
320 s >> TX_WITH_WITNESS(canonical_tx) >> serialized_block_hash >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> string_values >> msgs_reqs >> dummy_int >> nTimeReceived >> dummy_bool >> dummy_bool;
321 m_canonical_wtxid = canonical_tx->GetWitnessHash();
322 m_txs.emplace(m_canonical_wtxid, std::move(canonical_tx));
323
324 m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});
325
326 string_values.erase("fromaccount");
327 string_values.erase("spent");
328 for (const auto& [key, value] : string_values) {
329 if (key == "n") nOrderPos = LocaleIndependentAtoi<int64_t>(value);
330 else if (key == "timesmart") nTimeSmart = LocaleIndependentAtoi<int64_t>(value);
331 else if (key == "from") m_from = value;
332 else if (key == "message") m_message = value;
333 else if (key == "comment") m_comment = value;
334 else if (key == "to") m_comment_to = value;
335 else if (key == "replaces_txid") m_replaces_txid = Txid::FromHex(value);
336 else if (key == "replaced_by_txid") m_replaced_by_txid = Txid::FromHex(value);
337 else {
338 throw std::runtime_error("Unexpected value in CWalletTx strings value map");
339 }
340 }
341
342 for (const auto& [type, data] : msgs_reqs) {
343 if (type == "Message") m_messages.emplace_back(data);
344 else if (type == "PaymentRequest") m_payment_requests.emplace_back(data);
345 else {
346 throw std::runtime_error("Unknown type in CWalletTx messages and requests vector");
347 }
348 }
349 }
350
352
353 // Update the state of this wallet transaction along with a transaction that may have a different wtxid.
354 // If the given transaction has a different wtxid, the transaction is stored if it has not been seen before.
355 // The canonical wtxid is also updated. The tx that is confirmed becomes canonical. For unconfirmed txs,
356 // those with witnesses are preferred, followed by least weight.
357 bool Update(CTransactionRef tx, const TxState& new_state, WalletBatch& batch, bool metadata_changed);
358
361 {
364 fChangeCached = false;
365 m_is_cache_empty = true;
366 m_cached_from_me = std::nullopt;
367 }
368
371 bool IsMalleation(const CWalletTx& tx) const;
372
373 bool InMempool() const;
374
375 int64_t GetTxTime() const;
376
377 template<typename T> const T* state() const { return std::get_if<T>(&m_state); }
378 template<typename T> T* state() { return std::get_if<T>(&m_state); }
379
382 void updateState(interfaces::Chain& chain);
383
384 bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
385 bool isMempoolConflicted() const { return !mempool_conflicts.empty(); }
386 bool isBlockConflicted() const { return state<TxStateBlockConflicted>(); }
387 bool isInactive() const { return state<TxStateInactive>(); }
388 bool isUnconfirmed() const { return !isAbandoned() && !isBlockConflicted() && !isMempoolConflicted() && !isConfirmed(); }
389 bool isConfirmed() const { return state<TxStateConfirmed>(); }
390 const Txid& GetHash() const LIFETIMEBOUND { return GetTx()->GetHash(); }
391 const Wtxid& GetWitnessHash() const LIFETIMEBOUND { return GetTx()->GetWitnessHash(); }
392 bool IsCoinBase() const { return GetTx()->IsCoinBase(); }
393
394 const std::map<Wtxid, CTransactionRef>& GetTxs() const { return m_txs; }
395
396 // Disable copying of CWalletTx objects to prevent bugs where instances get
397 // copied in and out of the mapWallet map, and fields are updated in the
398 // wrong copy.
399 CWalletTx(const CWalletTx&) = delete;
400 CWalletTx& operator=(const CWalletTx&) = delete;
401
402 // Enable the default move constructor
403 CWalletTx(CWalletTx&&) = default;
404
405private:
407 {
408 nTimeReceived = 0;
409 nTimeSmart = 0;
410 fChangeCached = false;
411 nChangeCached = 0;
412 nOrderPos = -1;
413 }
414
415 void Init()
416 {
417 m_txs.clear();
419 SetDefaults();
420 }
421
423 std::map<Wtxid, CTransactionRef> m_txs;
424
427 void RecomputeCanonical();
428};
429
431 bool operator()(const CWalletTx* a, const CWalletTx* b) const
432 {
433 return a->nOrderPos < b->nOrderPos;
434 }
435};
436
438{
439private:
442
443public:
444 WalletTXO(const CWalletTx& wtx, const CTxOut& output)
445 : m_wtx(wtx),
446 m_output(output)
447 {
448 Assume(std::ranges::find(wtx.GetTx()->vout, output) != wtx.GetTx()->vout.end());
449 }
450
451 const CWalletTx& GetWalletTx() const { return m_wtx; }
452
453 const CTxOut& GetTxOut() const { return m_output; }
454};
455} // namespace wallet
456
457#endif // BITCOIN_WALLET_TRANSACTION_H
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
#define LIFETIMEBOUND
Definition: attributes.h:16
#define Assert(val)
Identity function.
Definition: check.h:116
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
An output of a transaction.
Definition: transaction.h:141
std::string ToString() const
Definition: uint256.cpp:21
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:117
static std::optional< transaction_identifier > FromHex(std::string_view hex)
256-bit opaque blob.
Definition: uint256.h:196
static const uint256 ONE
Definition: uint256.h:205
static const uint256 ZERO
Definition: uint256.h:204
Legacy class used for deserializing vtxPrev for backwards compatibility.
Definition: transaction.h:175
void Unserialize(Stream &s)
Definition: transaction.h:178
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:194
bool Update(CTransactionRef tx, const TxState &new_state, WalletBatch &batch, bool metadata_changed)
Definition: transaction.cpp:55
bool isConfirmed() const
Definition: transaction.h:389
bool isBlockConflicted() const
Definition: transaction.h:386
CWalletTx(CWalletTx &&)=default
std::vector< std::string > m_messages
Definition: transaction.h:207
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:390
const T * state() const
Definition: transaction.h:377
std::set< Txid > mempool_conflicts
Definition: transaction.h:268
std::optional< Txid > m_replaces_txid
Definition: transaction.h:204
std::map< Wtxid, CTransactionRef > m_txs
Definition: transaction.h:423
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
Definition: transaction.cpp:30
std::optional< std::string > m_comment_to
Definition: transaction.h:203
CAmount nChangeCached
Definition: transaction.h:237
void Serialize(Stream &s) const
Definition: transaction.h:275
const std::map< Wtxid, CTransactionRef > & GetTxs() const
Definition: transaction.h:394
std::optional< std::string > m_message
Definition: transaction.h:200
int64_t nOrderPos
position in ordered transaction list
Definition: transaction.h:223
bool isUnconfirmed() const
Definition: transaction.h:388
std::optional< bool > m_cached_from_me
Definition: transaction.h:222
std::optional< std::string > m_comment
Definition: transaction.h:202
unsigned int nTimeReceived
time received by this node
Definition: transaction.h:210
std::optional< std::string > m_from
Definition: transaction.h:199
std::optional< Txid > m_replaced_by_txid
Definition: transaction.h:205
void Unserialize(Stream &s)
Definition: transaction.h:307
bool isMempoolConflicted() const
Definition: transaction.h:385
CWalletTx & operator=(const CWalletTx &)=delete
bool IsCoinBase() const
Definition: transaction.h:392
CWalletTx(deserialize_type, Stream &s, const std::map< Wtxid, CTransactionRef > &variants)
Definition: transaction.h:248
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
Definition: transaction.h:228
bool InMempool() const
Definition: transaction.cpp:19
bool isAbandoned() const
Definition: transaction.h:384
std::optional< Txid > truc_child_in_mempool
Definition: transaction.h:272
bool isInactive() const
Definition: transaction.h:387
CWalletTx(const CWalletTx &)=delete
std::vector< std::string > m_payment_requests
Definition: transaction.h:209
int64_t GetTxTime() const
Definition: transaction.cpp:24
CTransactionRef GetTx() const
Definition: transaction.h:351
CWalletTx(CTransactionRef tx, const TxState &state)
Definition: transaction.h:239
bool IsMalleation(const CWalletTx &tx) const
True if tx is a malleation of this, i.e.
Definition: transaction.cpp:14
void RecomputeCanonical()
Set m_canonical_wtxid to the best variant under the unconfirmed rule (witnessed preferred,...
Definition: transaction.cpp:98
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Definition: transaction.h:235
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
Definition: transaction.h:224
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet.
Definition: transaction.h:220
const Wtxid & GetWitnessHash() const LIFETIMEBOUND
Definition: transaction.h:391
void MarkDirty()
make sure balances are recalculated
Definition: transaction.h:360
Access to the wallet database.
Definition: walletdb.h:197
WalletTXO(const CWalletTx &wtx, const CTxOut &output)
Definition: transaction.h:444
const CTxOut & m_output
Definition: transaction.h:441
const CWalletTx & m_wtx
Definition: transaction.h:440
const CWalletTx & GetWalletTx() const
Definition: transaction.h:451
const CTxOut & GetTxOut() const
Definition: transaction.h:453
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
#define T(expected, seed, data)
SocketId Stream
Definition: util.h:30
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:250
std::variant< TxStateConfirmed, TxStateInMempool, TxStateInactive > SyncTxState
Subset of states transaction sync logic is implemented to handle.
Definition: transaction.h:84
std::variant< TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized > TxState
All possible CWalletTx states.
Definition: transaction.h:81
static int TxStateSerializedIndex(const TxState &state)
Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
Definition: transaction.h:114
static TxState TxStateInterpretSerialized(TxStateUnrecognized data)
Try to interpret deserialized TxStateUnrecognized data as a recognized state.
Definition: transaction.h:87
static uint256 TxStateSerializedBlockHash(const TxState &state)
Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
Definition: transaction.h:102
std::string TxStateString(const T &state)
Return TxState or SyncTxState as a string for logging or debugging.
Definition: transaction.h:127
constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:181
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:417
Dummy data type to identify deserializing constructors.
Definition: serialize.h:51
Overloaded helper for std::visit.
Definition: overloaded.h:16
Cachable amount subdivided into avoid reuse and all balances.
Definition: transaction.h:136
std::optional< CAmount > m_avoid_reuse_value
Definition: transaction.h:137
std::optional< CAmount > m_all_value
Definition: transaction.h:138
bool IsCached(bool avoid_reuse)
Definition: transaction.h:161
CAmount Get(bool avoid_reuse)
Definition: transaction.h:152
void Set(bool avoid_reuse, CAmount value)
Definition: transaction.h:144
State of rejected transaction that conflicts with a confirmed block.
Definition: transaction.h:49
std::string toString() const
Definition: transaction.h:54
TxStateBlockConflicted(const uint256 &block_hash, int height)
Definition: transaction.h:53
State of transaction confirmed in a block.
Definition: transaction.h:34
std::string toString() const
Definition: transaction.h:40
TxStateConfirmed(const uint256 &block_hash, int height, int index)
Definition: transaction.h:39
State of transaction added to mempool.
Definition: transaction.h:44
std::string toString() const
Definition: transaction.h:45
State of transaction not confirmed or conflicting with a known block and not in the mempool.
Definition: transaction.h:61
std::string toString() const
Definition: transaction.h:65
TxStateInactive(bool abandoned=false)
Definition: transaction.h:64
State of transaction loaded in an unrecognized state with unexpected hash or index values.
Definition: transaction.h:72
TxStateUnrecognized(const uint256 &block_hash, int index)
Definition: transaction.h:76
std::string toString() const
Definition: transaction.h:77
bool operator()(const CWalletTx *a, const CWalletTx *b) const
Definition: transaction.h:431
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
is a home for public enum and struct type definitions that are used by internally by wallet code,...