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