LCOV - code coverage report
Current view: top level - src/wallet - transaction.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 0 114 0.0 %
Date: 2023-09-26 12:08:55 Functions: 0 44 0.0 %

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

Generated by: LCOV version 1.14