Bitcoin Core  31.0.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>
10 #include <primitives/transaction.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 
26 namespace interfaces {
27 class Chain;
28 } // namespace interfaces
29 
30 namespace wallet {
36 
37  explicit TxStateConfirmed(const uint256& block_hash, int height, int index) : confirmed_block_hash(block_hash), confirmed_block_height(height), position_in_block(index) {}
38  std::string toString() const { return strprintf("Confirmed (block=%s, height=%i, index=%i)", confirmed_block_hash.ToString(), confirmed_block_height, position_in_block); }
39 };
40 
43  std::string toString() const { return strprintf("InMempool"); }
44 };
45 
50 
51  explicit TxStateBlockConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
52  std::string toString() const { return strprintf("BlockConflicted (block=%s, height=%i)", conflicting_block_hash.ToString(), conflicting_block_height); }
53 };
54 
60  bool abandoned;
61 
62  explicit TxStateInactive(bool abandoned = false) : abandoned(abandoned) {}
63  std::string toString() const { return strprintf("Inactive (abandoned=%i)", abandoned); }
64 };
65 
72  int index;
73 
75  std::string toString() const { return strprintf("Unrecognized (block=%s, index=%i)", block_hash.ToString(), index); }
76 };
77 
79 using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized>;
80 
82 using SyncTxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateInactive>;
83 
86 {
87  if (data.block_hash == uint256::ZERO) {
88  if (data.index == 0) return TxStateInactive{};
89  } else if (data.block_hash == uint256::ONE) {
90  if (data.index == -1) return TxStateInactive{/*abandoned=*/true};
91  } else if (data.index >= 0) {
92  return TxStateConfirmed{data.block_hash, /*height=*/-1, data.index};
93  } else if (data.index == -1) {
94  return TxStateBlockConflicted{data.block_hash, /*height=*/-1};
95  }
96  return data;
97 }
98 
100 static inline uint256 TxStateSerializedBlockHash(const TxState& state)
101 {
102  return std::visit(util::Overloaded{
103  [](const TxStateInactive& inactive) { return inactive.abandoned ? uint256::ONE : uint256::ZERO; },
104  [](const TxStateInMempool& in_mempool) { return uint256::ZERO; },
105  [](const TxStateConfirmed& confirmed) { return confirmed.confirmed_block_hash; },
106  [](const TxStateBlockConflicted& conflicted) { return conflicted.conflicting_block_hash; },
107  [](const TxStateUnrecognized& unrecognized) { return unrecognized.block_hash; }
108  }, state);
109 }
110 
112 static inline int TxStateSerializedIndex(const TxState& state)
113 {
114  return std::visit(util::Overloaded{
115  [](const TxStateInactive& inactive) { return inactive.abandoned ? -1 : 0; },
116  [](const TxStateInMempool& in_mempool) { return 0; },
117  [](const TxStateConfirmed& confirmed) { return confirmed.position_in_block; },
118  [](const TxStateBlockConflicted& conflicted) { return -1; },
119  [](const TxStateUnrecognized& unrecognized) { return unrecognized.index; }
120  }, state);
121 }
122 
124 template<typename T>
125 std::string TxStateString(const T& state)
126 {
127  return std::visit([](const auto& s) { return s.toString(); }, state);
128 }
129 
134 {
135  std::optional<CAmount> m_avoid_reuse_value;
136  std::optional<CAmount> m_all_value;
137  inline void Reset()
138  {
139  m_avoid_reuse_value.reset();
140  m_all_value.reset();
141  }
142  void Set(bool avoid_reuse, CAmount value)
143  {
144  if (avoid_reuse) {
145  m_avoid_reuse_value = value;
146  } else {
147  m_all_value = value;
148  }
149  }
150  CAmount Get(bool avoid_reuse)
151  {
152  if (avoid_reuse) {
153  Assert(m_avoid_reuse_value.has_value());
154  return m_avoid_reuse_value.value();
155  }
156  Assert(m_all_value.has_value());
157  return m_all_value.value();
158  }
159  bool IsCached(bool avoid_reuse)
160  {
161  if (avoid_reuse) return m_avoid_reuse_value.has_value();
162  return m_all_value.has_value();
163  }
164 };
165 
166 
167 typedef std::map<std::string, std::string> mapValue_t;
168 
169 
176 {
177 public:
178  template<typename Stream>
179  void Unserialize(Stream& s)
180  {
181  CTransactionRef tx;
182  uint256 hashBlock;
183  std::vector<uint256> vMerkleBranch;
184  int nIndex;
185 
186  s >> TX_WITH_WITNESS(tx) >> hashBlock >> vMerkleBranch >> nIndex;
187  }
188 };
189 
195 {
196 public:
223  std::vector<std::pair<std::string, std::string> > vOrderForm;
224  unsigned int nTimeReceived;
225 
234  unsigned int nTimeSmart;
235  // Cached value for whether the transaction spends any inputs known to the wallet
236  mutable std::optional<bool> m_cached_from_me{std::nullopt};
237  int64_t nOrderPos;
238  std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
239 
240  // memory only
249  mutable bool m_is_cache_empty{true};
250  mutable bool fChangeCached;
252 
254  {
255  Init();
256  }
257 
258  void Init()
259  {
260  mapValue.clear();
261  vOrderForm.clear();
262  nTimeReceived = 0;
263  nTimeSmart = 0;
264  fChangeCached = false;
265  nChangeCached = 0;
266  nOrderPos = -1;
267  }
268 
271 
272  // Set of mempool transactions that conflict
273  // directly with the transaction, or that conflict
274  // with an ancestor transaction. This set will be
275  // empty if state is InMempool or Confirmed, but
276  // can be nonempty if state is Inactive or
277  // BlockConflicted.
278  std::set<Txid> mempool_conflicts;
279 
280  // Track v3 mempool tx that spends from this tx
281  // so that we don't try to create another unconfirmed child
282  std::optional<Txid> truc_child_in_mempool;
283 
284  template<typename Stream>
285  void Serialize(Stream& s) const
286  {
287  mapValue_t mapValueCopy = mapValue;
288 
289  mapValueCopy["fromaccount"] = "";
290  if (nOrderPos != -1) {
291  mapValueCopy["n"] = util::ToString(nOrderPos);
292  }
293  if (nTimeSmart) {
294  mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
295  }
296 
297  std::vector<uint8_t> dummy_vector1;
298  std::vector<uint8_t> dummy_vector2;
299  bool dummy_bool = false;
300  uint32_t dummy_int = 0; // Used to be fTimeReceivedIsTxTime
301  uint256 serializedHash = TxStateSerializedBlockHash(m_state);
302  int serializedIndex = TxStateSerializedIndex(m_state);
303  s << TX_WITH_WITNESS(tx) << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << dummy_int << nTimeReceived << dummy_bool << dummy_bool;
304  }
305 
306  template<typename Stream>
307  void Unserialize(Stream& s)
308  {
309  Init();
310 
311  std::vector<uint256> dummy_vector1;
312  std::vector<CMerkleTx> dummy_vector2;
313  bool dummy_bool;
314  uint32_t dummy_int; // Used to be fTimeReceivedIsTxTime
315  uint256 serialized_block_hash;
316  int serializedIndex;
317  s >> TX_WITH_WITNESS(tx) >> serialized_block_hash >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> dummy_int >> nTimeReceived >> dummy_bool >> dummy_bool;
318 
319  m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});
320 
321  const auto it_op = mapValue.find("n");
322  nOrderPos = (it_op != mapValue.end()) ? LocaleIndependentAtoi<int64_t>(it_op->second) : -1;
323  const auto it_ts = mapValue.find("timesmart");
324  nTimeSmart = (it_ts != mapValue.end()) ? static_cast<unsigned int>(LocaleIndependentAtoi<int64_t>(it_ts->second)) : 0;
325 
326  mapValue.erase("fromaccount");
327  mapValue.erase("spent");
328  mapValue.erase("n");
329  mapValue.erase("timesmart");
330  }
331 
333  {
334  tx = std::move(arg);
335  }
336 
338  void MarkDirty()
339  {
340  m_amounts[DEBIT].Reset();
342  fChangeCached = false;
343  m_is_cache_empty = true;
344  m_cached_from_me = std::nullopt;
345  }
346 
348  bool IsEquivalentTo(const CWalletTx& tx) const;
349 
350  bool InMempool() const;
351 
352  int64_t GetTxTime() const;
353 
354  template<typename T> const T* state() const { return std::get_if<T>(&m_state); }
355  template<typename T> T* state() { return std::get_if<T>(&m_state); }
356 
359  void updateState(interfaces::Chain& chain);
360 
361  bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
362  bool isMempoolConflicted() const { return !mempool_conflicts.empty(); }
363  bool isBlockConflicted() const { return state<TxStateBlockConflicted>(); }
364  bool isInactive() const { return state<TxStateInactive>(); }
365  bool isUnconfirmed() const { return !isAbandoned() && !isBlockConflicted() && !isMempoolConflicted() && !isConfirmed(); }
366  bool isConfirmed() const { return state<TxStateConfirmed>(); }
367  const Txid& GetHash() const LIFETIMEBOUND { return tx->GetHash(); }
368  const Wtxid& GetWitnessHash() const LIFETIMEBOUND { return tx->GetWitnessHash(); }
369  bool IsCoinBase() const { return tx->IsCoinBase(); }
370 
371 private:
372  // Disable copying of CWalletTx objects to prevent bugs where instances get
373  // copied in and out of the mapWallet map, and fields are updated in the
374  // wrong copy.
375  CWalletTx(const CWalletTx&) = default;
376  CWalletTx& operator=(const CWalletTx&) = default;
377 public:
378  // Instead have an explicit copy function
379  void CopyFrom(const CWalletTx&);
380 };
381 
383  bool operator()(const CWalletTx* a, const CWalletTx* b) const
384  {
385  return a->nOrderPos < b->nOrderPos;
386  }
387 };
388 
390 {
391 private:
392  const CWalletTx& m_wtx;
393  const CTxOut& m_output;
394 
395 public:
396  WalletTXO(const CWalletTx& wtx, const CTxOut& output)
397  : m_wtx(wtx),
398  m_output(output)
399  {
400  Assume(std::ranges::find(wtx.tx->vout, output) != wtx.tx->vout.end());
401  }
402 
403  const CWalletTx& GetWalletTx() const { return m_wtx; }
404 
405  const CTxOut& GetTxOut() const { return m_output; }
406 };
407 } // namespace wallet
408 
409 #endif // BITCOIN_WALLET_TRANSACTION_H
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
State of transaction added to mempool.
Definition: transaction.h:42
static const uint256 ONE
Definition: uint256.h:204
void Serialize(Stream &s) const
Definition: transaction.h:285
mapValue_t mapValue
Key/value map with information about the transaction.
Definition: transaction.h:222
void MarkDirty()
make sure balances are recalculated
Definition: transaction.h:338
const T * state() const
Definition: transaction.h:354
CAmount Get(bool avoid_reuse)
Definition: transaction.h:150
const Wtxid & GetWitnessHash() const LIFETIMEBOUND
Definition: transaction.h:368
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
std::map< std::string, std::string > mapValue_t
Definition: transaction.h:167
std::vector< std::pair< std::string, std::string > > vOrderForm
Definition: transaction.h:223
CWalletTx(CTransactionRef tx, const TxState &state)
Definition: transaction.h:253
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
Definition: transaction.cpp:38
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Definition: transaction.h:249
std::string TxStateString(const T &state)
Return TxState or SyncTxState as a string for logging or debugging.
Definition: transaction.h:125
TxStateBlockConflicted(const uint256 &block_hash, int height)
Definition: transaction.h:51
State of transaction not confirmed or conflicting with a known block and not in the mempool...
Definition: transaction.h:59
Definition: common.h:29
TxStateConfirmed(const uint256 &block_hash, int height, int index)
Definition: transaction.h:37
std::string toString() const
Definition: transaction.h:43
std::variant< TxStateConfirmed, TxStateInMempool, TxStateInactive > SyncTxState
Subset of states transaction sync logic is implemented to handle.
Definition: transaction.h:82
State of transaction confirmed in a block.
Definition: transaction.h:32
bool IsEquivalentTo(const CWalletTx &tx) const
True if only scriptSigs are different.
Definition: transaction.cpp:12
std::string toString() const
Definition: transaction.h:63
bool isAbandoned() const
Definition: transaction.h:361
const CWalletTx & GetWalletTx() const
Definition: transaction.h:403
int64_t GetTxTime() const
Definition: transaction.cpp:32
State of transaction loaded in an unrecognized state with unexpected hash or index values...
Definition: transaction.h:70
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:194
TxStateUnrecognized(const uint256 &block_hash, int index)
Definition: transaction.h:74
#define LIFETIMEBOUND
Definition: attributes.h:16
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
Definition: transaction.h:238
static TxState TxStateInterpretSerialized(TxStateUnrecognized data)
Try to interpret deserialized TxStateUnrecognized data as a recognized state.
Definition: transaction.h:85
std::optional< Txid > truc_child_in_mempool
Definition: transaction.h:282
const CTxOut & GetTxOut() const
Definition: transaction.h:405
State of rejected transaction that conflicts with a confirmed block.
Definition: transaction.h:47
std::variant< TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized > TxState
All possible CWalletTx states.
Definition: transaction.h:79
static const uint256 ZERO
Definition: uint256.h:203
void Unserialize(Stream &s)
Definition: transaction.h:307
bool isMempoolConflicted() const
Definition: transaction.h:362
static int TxStateSerializedIndex(const TxState &state)
Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
Definition: transaction.h:112
std::set< Txid > mempool_conflicts
Definition: transaction.h:278
std::string toString() const
Definition: transaction.h:38
An output of a transaction.
Definition: transaction.h:139
std::string ToString() const
Definition: uint256.cpp:21
void CopyFrom(const CWalletTx &)
Definition: transaction.cpp:59
is a home for public enum and struct type definitions that are used by internally by wallet code...
bool isBlockConflicted() const
Definition: transaction.h:363
#define Assume(val)
Assume is the identity function.
Definition: check.h:125
static uint256 TxStateSerializedBlockHash(const TxState &state)
Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
Definition: transaction.h:100
Cachable amount subdivided into avoid reuse and all balances.
Definition: transaction.h:133
TxStateInactive(bool abandoned=false)
Definition: transaction.h:62
256-bit opaque blob.
Definition: uint256.h:195
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:367
std::optional< CAmount > m_all_value
Definition: transaction.h:136
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:117
const CWalletTx & m_wtx
Definition: transaction.h:392
void Set(bool avoid_reuse, CAmount value)
Definition: transaction.h:142
std::string toString() const
Definition: transaction.h:52
bool InMempool() const
Definition: transaction.cpp:27
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet...
Definition: transaction.h:234
void Unserialize(Stream &s)
Definition: transaction.h:179
std::string toString() const
Definition: transaction.h:75
WalletTXO(const CWalletTx &wtx, const CTxOut &output)
Definition: transaction.h:396
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
Definition: transaction.h:242
bool IsCoinBase() const
Definition: transaction.h:369
unsigned int nTimeReceived
time received by this node
Definition: transaction.h:224
int64_t nOrderPos
position in ordered transaction list
Definition: transaction.h:237
std::optional< CAmount > m_avoid_reuse_value
Definition: transaction.h:135
bool operator()(const CWalletTx *a, const CWalletTx *b) const
Definition: transaction.h:383
CAmount nChangeCached
Definition: transaction.h:251
CWalletTx & operator=(const CWalletTx &)=default
Overloaded helper for std::visit.
Definition: overloaded.h:16
bool isInactive() const
Definition: transaction.h:364
void SetTx(CTransactionRef arg)
Definition: transaction.h:332
#define T(expected, seed, data)
CTransactionRef tx
Definition: transaction.h:269
bool isConfirmed() const
Definition: transaction.h:366
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:246
bool IsCached(bool avoid_reuse)
Definition: transaction.h:159
#define Assert(val)
Identity function.
Definition: check.h:113
std::optional< bool > m_cached_from_me
Definition: transaction.h:236
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:180
bool isUnconfirmed() const
Definition: transaction.h:365
const CTxOut & m_output
Definition: transaction.h:393
Legacy class used for deserializing vtxPrev for backwards compatibility.
Definition: transaction.h:175