Line data Source code
1 : // Copyright (c) 2021 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 <serialize.h>
12 : #include <wallet/ismine.h>
13 : #include <threadsafety.h>
14 : #include <tinyformat.h>
15 : #include <uint256.h>
16 : #include <util/overloaded.h>
17 : #include <util/strencodings.h>
18 : #include <util/string.h>
19 :
20 : #include <variant>
21 : #include <vector>
22 :
23 : namespace wallet {
24 : //! State of transaction confirmed in a block.
25 : struct TxStateConfirmed {
26 : uint256 confirmed_block_hash;
27 : int confirmed_block_height;
28 : int position_in_block;
29 :
30 739544 : explicit TxStateConfirmed(const uint256& block_hash, int height, int index) : confirmed_block_hash(block_hash), confirmed_block_height(height), position_in_block(index) {}
31 93091 : std::string toString() const { return strprintf("Confirmed (block=%s, height=%i, index=%i)", confirmed_block_hash.ToString(), confirmed_block_height, position_in_block); }
32 : };
33 :
34 : //! State of transaction added to mempool.
35 : struct TxStateInMempool {
36 8459 : std::string toString() const { return strprintf("InMempool"); }
37 : };
38 :
39 : //! State of rejected transaction that conflicts with a confirmed block.
40 : struct TxStateConflicted {
41 : uint256 conflicting_block_hash;
42 : int conflicting_block_height;
43 :
44 272 : explicit TxStateConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
45 0 : std::string toString() const { return strprintf("Conflicted (block=%s, height=%i)", conflicting_block_hash.ToString(), conflicting_block_height); }
46 : };
47 :
48 : //! State of transaction not confirmed or conflicting with a known block and
49 : //! not in the mempool. May conflict with the mempool, or with an unknown block,
50 : //! or be abandoned, never broadcast, or rejected from the mempool for another
51 : //! reason.
52 : struct TxStateInactive {
53 : bool abandoned;
54 :
55 349010 : explicit TxStateInactive(bool abandoned = false) : abandoned(abandoned) {}
56 7932 : std::string toString() const { return strprintf("Inactive (abandoned=%i)", abandoned); }
57 : };
58 :
59 : //! State of transaction loaded in an unrecognized state with unexpected hash or
60 : //! index values. Treated as inactive (with serialized hash and index values
61 : //! preserved) by default, but may enter another state if transaction is added
62 : //! to the mempool, or confirmed, or abandoned, or found conflicting.
63 : struct TxStateUnrecognized {
64 : uint256 block_hash;
65 : int index;
66 :
67 92790 : TxStateUnrecognized(const uint256& block_hash, int index) : block_hash(block_hash), index(index) {}
68 0 : std::string toString() const { return strprintf("Unrecognized (block=%s, index=%i)", block_hash.ToString(), index); }
69 : };
70 :
71 : //! All possible CWalletTx states
72 : using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateConflicted, TxStateInactive, TxStateUnrecognized>;
73 :
74 : //! Subset of states transaction sync logic is implemented to handle.
75 : using SyncTxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateInactive>;
76 :
77 : //! Try to interpret deserialized TxStateUnrecognized data as a recognized state.
78 46395 : static inline TxState TxStateInterpretSerialized(TxStateUnrecognized data)
79 : {
80 46395 : if (data.block_hash == uint256::ZERO) {
81 504 : if (data.index == 0) return TxStateInactive{};
82 45895 : } else if (data.block_hash == uint256::ONE) {
83 27 : if (data.index == -1) return TxStateInactive{/*abandoned=*/true};
84 45868 : } else if (data.index >= 0) {
85 45848 : return TxStateConfirmed{data.block_hash, /*height=*/-1, data.index};
86 16 : } else if (data.index == -1) {
87 13 : return TxStateConflicted{data.block_hash, /*height=*/-1};
88 : }
89 11 : return data;
90 46395 : }
91 :
92 : //! Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
93 138608 : static inline uint256 TxStateSerializedBlockHash(const TxState& state)
94 : {
95 138608 : return std::visit(util::Overloaded{
96 7997 : [](const TxStateInactive& inactive) { return inactive.abandoned ? uint256::ONE : uint256::ZERO; },
97 14001 : [](const TxStateInMempool& in_mempool) { return uint256::ZERO; },
98 116473 : [](const TxStateConfirmed& confirmed) { return confirmed.confirmed_block_hash; },
99 126 : [](const TxStateConflicted& conflicted) { return conflicted.conflicting_block_hash; },
100 11 : [](const TxStateUnrecognized& unrecognized) { return unrecognized.block_hash; }
101 138608 : }, state);
102 : }
103 :
104 : //! Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
105 138608 : static inline int TxStateSerializedIndex(const TxState& state)
106 : {
107 138608 : return std::visit(util::Overloaded{
108 7997 : [](const TxStateInactive& inactive) { return inactive.abandoned ? -1 : 0; },
109 14001 : [](const TxStateInMempool& in_mempool) { return 0; },
110 116473 : [](const TxStateConfirmed& confirmed) { return confirmed.position_in_block; },
111 126 : [](const TxStateConflicted& conflicted) { return -1; },
112 11 : [](const TxStateUnrecognized& unrecognized) { return unrecognized.index; }
113 138608 : }, state);
114 : }
115 :
116 : //! Return TxState or SyncTxState as a string for logging or debugging.
117 : template<typename T>
118 109482 : std::string TxStateString(const T& state)
119 : {
120 218964 : return std::visit([](const auto& s) { return s.toString(); }, state);
121 : }
122 :
123 : typedef std::map<std::string, std::string> mapValue_t;
124 :
125 : /** Legacy class used for deserializing vtxPrev for backwards compatibility.
126 : * vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3,
127 : * but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs.
128 : * These need to get deserialized for field alignment when deserializing
129 : * a CWalletTx, but the deserialized values are discarded.**/
130 : class CMerkleTx
131 : {
132 : public:
133 : template<typename Stream>
134 0 : void Unserialize(Stream& s)
135 : {
136 0 : CTransactionRef tx;
137 0 : uint256 hashBlock;
138 0 : std::vector<uint256> vMerkleBranch;
139 : int nIndex;
140 :
141 0 : s >> tx >> hashBlock >> vMerkleBranch >> nIndex;
142 0 : }
143 : };
144 :
145 : /**
146 : * A transaction with a bunch of additional info that only the owner cares about.
147 : * It includes any unrecorded transactions needed to link it back to the block chain.
148 : */
149 : class CWalletTx
150 : {
151 : public:
152 : /**
153 : * Key/value map with information about the transaction.
154 : *
155 : * The following keys can be read and written through the map and are
156 : * serialized in the wallet database:
157 : *
158 : * "comment", "to" - comment strings provided to sendtoaddress,
159 : * and sendmany wallet RPCs
160 : * "replaces_txid" - txid (as HexStr) of transaction replaced by
161 : * bumpfee on transaction created by bumpfee
162 : * "replaced_by_txid" - txid (as HexStr) of transaction created by
163 : * bumpfee on transaction replaced by bumpfee
164 : * "from", "message" - obsolete fields that could be set in UI prior to
165 : * 2011 (removed in commit 4d9b223)
166 : *
167 : * The following keys are serialized in the wallet database, but shouldn't
168 : * be read or written through the map (they will be temporarily added and
169 : * removed from the map during serialization):
170 : *
171 : * "fromaccount" - serialized strFromAccount value
172 : * "n" - serialized nOrderPos value
173 : * "timesmart" - serialized nTimeSmart value
174 : * "spent" - serialized vfSpent value that existed prior to
175 : * 2014 (removed in commit 93a18a3)
176 : */
177 : mapValue_t mapValue;
178 : std::vector<std::pair<std::string, std::string> > vOrderForm;
179 : unsigned int fTimeReceivedIsTxTime;
180 : unsigned int nTimeReceived; //!< time received by this node
181 : /**
182 : * Stable timestamp that never changes, and reflects the order a transaction
183 : * was added to the wallet. Timestamp is based on the block time for a
184 : * transaction added as part of a block, or else the time when the
185 : * transaction was received if it wasn't part of a block, with the timestamp
186 : * adjusted in both cases so timestamp order matches the order transactions
187 : * were added to the wallet. More details can be found in
188 : * CWallet::ComputeTimeSmart().
189 : */
190 : unsigned int nTimeSmart;
191 : /**
192 : * From me flag is set to 1 for transactions that were created by the wallet
193 : * on this bitcoin node, and set to 0 for transactions that were created
194 : * externally and came in through the network or sendrawtransaction RPC.
195 : */
196 : bool fFromMe;
197 : int64_t nOrderPos; //!< position in ordered transaction list
198 : std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
199 :
200 : // memory only
201 : enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, ANON_CREDIT, DENOM_UCREDIT, DENOM_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
202 : mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
203 : /**
204 : * This flag is true if all m_amounts caches are empty. This is particularly
205 : * useful in places where MarkDirty is conditionally called and the
206 : * condition can be expensive and thus can be skipped if the flag is true.
207 : * See MarkDestinationsDirty.
208 : */
209 271399 : mutable bool m_is_cache_empty{true};
210 : mutable bool fChangeCached;
211 : mutable bool fIsChainlocked;
212 : mutable bool fIsInstantSendLocked;
213 : mutable CAmount nChangeCached;
214 :
215 542798 : CWalletTx(CTransactionRef tx, const TxState& state) : tx(std::move(tx)), m_state(state)
216 271399 : {
217 271399 : Init();
218 542798 : }
219 :
220 317769 : void Init()
221 : {
222 317769 : mapValue.clear();
223 317769 : vOrderForm.clear();
224 317769 : fTimeReceivedIsTxTime = false;
225 317769 : nTimeReceived = 0;
226 317769 : nTimeSmart = 0;
227 317769 : fFromMe = false;
228 317769 : fChangeCached = false;
229 317769 : fIsChainlocked = false;
230 317769 : fIsInstantSendLocked = false;
231 317769 : nChangeCached = 0;
232 317769 : nOrderPos = -1;
233 317769 : }
234 :
235 : CTransactionRef tx;
236 : TxState m_state;
237 :
238 : template<typename Stream>
239 80991 : void Serialize(Stream& s) const
240 : {
241 80991 : mapValue_t mapValueCopy = mapValue;
242 :
243 80991 : mapValueCopy["fromaccount"] = "";
244 80991 : if (nOrderPos != -1) {
245 80991 : mapValueCopy["n"] = ToString(nOrderPos);
246 80991 : }
247 80991 : if (nTimeSmart) {
248 80991 : mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
249 80991 : }
250 :
251 80991 : std::vector<uint8_t> dummy_vector1; //!< Used to be vMerkleBranch
252 80991 : std::vector<uint8_t> dummy_vector2; //!< Used to be vtxPrev
253 80991 : bool dummy_bool = false; //!< Used to be fSpent
254 80991 : uint256 serializedHash = TxStateSerializedBlockHash(m_state);
255 80991 : int serializedIndex = TxStateSerializedIndex(m_state);
256 80991 : s << tx << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool;
257 80991 : }
258 :
259 : template<typename Stream>
260 46370 : void Unserialize(Stream& s)
261 : {
262 46370 : Init();
263 :
264 46370 : std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
265 46370 : std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
266 : bool dummy_bool; //! Used to be fSpent
267 46370 : uint256 serialized_block_hash;
268 : int serializedIndex;
269 46370 : s >> tx >> serialized_block_hash >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool;
270 :
271 46370 : m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});
272 :
273 46370 : const auto it_op = mapValue.find("n");
274 46370 : nOrderPos = (it_op != mapValue.end()) ? LocaleIndependentAtoi<int64_t>(it_op->second) : -1;
275 46370 : nTimeSmart = mapValue.count("timesmart") ? (unsigned int)LocaleIndependentAtoi<int64_t>(mapValue["timesmart"]) : 0;
276 :
277 46370 : mapValue.erase("fromaccount");
278 46370 : mapValue.erase("spent");
279 46370 : mapValue.erase("n");
280 46370 : mapValue.erase("timesmart");
281 46370 : }
282 :
283 : void SetTx(CTransactionRef arg)
284 : {
285 : tx = std::move(arg);
286 : }
287 :
288 : //! make sure balances are recalculated
289 198352 : void MarkDirty()
290 : {
291 198352 : m_amounts[DEBIT].Reset();
292 198352 : m_amounts[CREDIT].Reset();
293 198352 : m_amounts[ANON_CREDIT].Reset();
294 198352 : m_amounts[DENOM_CREDIT].Reset();
295 198352 : m_amounts[DENOM_UCREDIT].Reset();
296 198352 : m_amounts[IMMATURE_CREDIT].Reset();
297 198352 : m_amounts[AVAILABLE_CREDIT].Reset();
298 198352 : fChangeCached = false;
299 198352 : m_is_cache_empty = true;
300 198352 : }
301 :
302 : /** True if only scriptSigs are different */
303 : bool IsEquivalentTo(const CWalletTx& tx) const;
304 :
305 : bool InMempool() const;
306 :
307 : int64_t GetTxTime() const;
308 :
309 5901377 : template<typename T> const T* state() const { return std::get_if<T>(&m_state); }
310 109915 : template<typename T> T* state() { return std::get_if<T>(&m_state); }
311 :
312 65522 : bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
313 403 : bool isConflicted() const { return state<TxStateConflicted>(); }
314 : bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
315 4142 : bool isConfirmed() const { return state<TxStateConfirmed>(); }
316 4956957 : const uint256& GetHash() const LIFETIMEBOUND { return tx->GetHash(); }
317 3040488 : bool IsCoinBase() const { return tx->IsCoinBase(); }
318 6636 : bool IsPlatformTransfer() const { return tx->IsPlatformTransfer(); }
319 :
320 : // Disable copying of CWalletTx objects to prevent bugs where instances get
321 : // copied in and out of the mapWallet map, and fields are updated in the
322 : // wrong copy.
323 : CWalletTx(CWalletTx const &) = delete;
324 : void operator=(CWalletTx const &x) = delete;
325 : };
326 : } // namespace wallet
327 :
328 : #endif // BITCOIN_WALLET_TRANSACTION_H
|