LCOV - code coverage report
Current view: top level - src/wallet - transaction.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 62 124 50.0 %
Date: 2023-11-10 23:46:46 Functions: 20 56 35.7 %
Branches: 26 146 17.8 %

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

Generated by: LCOV version 1.14