LCOV - code coverage report
Current view: top level - src/primitives - transaction.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 133 135 98.5 %
Date: 2025-04-02 01:23:23 Functions: 55 56 98.2 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2015-2021 The PIVX Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #ifndef PIVX_PRIMITIVES_TRANSACTION_H
       8             : #define PIVX_PRIMITIVES_TRANSACTION_H
       9             : 
      10             : #include "amount.h"
      11             : #include "memusage.h"
      12             : #include "netaddress.h"
      13             : #include "optional.h"
      14             : #include "script/script.h"
      15             : #include "serialize.h"
      16             : #include "uint256.h"
      17             : 
      18             : #include "sapling/sapling_transaction.h"
      19             : 
      20             : #include <atomic>
      21             : #include <list>
      22             : 
      23             : class CTransaction;
      24             : 
      25             : enum SigVersion
      26             : {
      27             :     SIGVERSION_BASE = 0,
      28             :     SIGVERSION_SAPLING = 1,
      29             : };
      30             : 
      31             : /** An outpoint - a combination of a transaction hash and an index n into its vout */
      32             : class BaseOutPoint
      33             : {
      34             : public:
      35             :     uint256 hash;
      36             :     uint32_t n;
      37             :     bool isTransparent{true};
      38             : 
      39    12787632 :     BaseOutPoint() { SetNull(); }
      40    22242544 :     BaseOutPoint(const uint256& hashIn, const uint32_t nIn, bool isTransparentIn = true) :
      41    22242544 :         hash(hashIn), n(nIn), isTransparent(isTransparentIn) { }
      42             : 
      43    61760196 :     SERIALIZE_METHODS(BaseOutPoint, obj) { READWRITE(obj.hash, obj.n); }
      44             : 
      45    12749409 :     void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
      46    41741725 :     bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
      47             : 
      48   474299598 :     friend bool operator<(const BaseOutPoint& a, const BaseOutPoint& b)
      49             :     {
      50   474299598 :         return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
      51             :     }
      52             : 
      53    23183357 :     friend bool operator==(const BaseOutPoint& a, const BaseOutPoint& b)
      54             :     {
      55    23182237 :         return (a.hash == b.hash && a.n == b.n);
      56             :     }
      57             : 
      58        1120 :     friend bool operator!=(const BaseOutPoint& a, const BaseOutPoint& b)
      59             :     {
      60        2023 :         return !(a == b);
      61             :     }
      62             : 
      63             :     std::string ToString() const;
      64             :     std::string ToStringShort() const;
      65             : 
      66             :     size_t DynamicMemoryUsage() const { return 0; }
      67             : 
      68             : };
      69             : 
      70             : /** An outpoint - a combination of a transaction hash and an index n into its vout */
      71             : class COutPoint : public BaseOutPoint
      72             : {
      73             : public:
      74     8280912 :     COutPoint() : BaseOutPoint() {};
      75    19678945 :     COutPoint(const uint256& hashIn, const uint32_t nIn) : BaseOutPoint(hashIn, nIn, true) {};
      76             :     std::string ToString() const;
      77             : };
      78             : 
      79             : /** An outpoint - a combination of a transaction hash and an index n into its sapling
      80             :  * output description (vShieldedOutput) */
      81             : class SaplingOutPoint : public BaseOutPoint
      82             : {
      83             : public:
      84         902 :     SaplingOutPoint() : BaseOutPoint() {};
      85        5130 :     SaplingOutPoint(const uint256& hashIn, const uint32_t nIn) : BaseOutPoint(hashIn, nIn, false) {};
      86             :     std::string ToString() const;
      87             : };
      88             : 
      89             : /** An input of a transaction.  It contains the location of the previous
      90             :  * transaction's output that it claims and a signature that matches the
      91             :  * output's public key.
      92             :  */
      93    69524990 : class CTxIn
      94             : {
      95             : public:
      96             :     COutPoint prevout;
      97             :     CScript scriptSig;
      98             :     uint32_t nSequence;
      99             : 
     100             :     /* Setting nSequence to this value for every input in a transaction
     101             :      * disables nLockTime. */
     102             :     static const uint32_t SEQUENCE_FINAL = 0xffffffff;
     103             : 
     104     9406238 :     CTxIn() { nSequence = SEQUENCE_FINAL; }
     105             :     explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
     106             :     CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
     107             : 
     108    34316426 :     SERIALIZE_METHODS(CTxIn, obj) { READWRITE(obj.prevout, obj.scriptSig, obj.nSequence); }
     109             : 
     110         870 :     bool IsFinal() const { return nSequence == SEQUENCE_FINAL; }
     111        1702 :     bool IsNull() const { return prevout.IsNull() && scriptSig.empty() && IsFinal(); }
     112             : 
     113             :     bool IsZerocoinSpend() const;
     114             :     bool IsZerocoinPublicSpend() const;
     115             : 
     116             :     friend bool operator==(const CTxIn& a, const CTxIn& b)
     117             :     {
     118             :         return (a.prevout   == b.prevout &&
     119             :                 a.scriptSig == b.scriptSig &&
     120             :                 a.nSequence == b.nSequence);
     121             :     }
     122             : 
     123             :     friend bool operator!=(const CTxIn& a, const CTxIn& b)
     124             :     {
     125             :         return !(a == b);
     126             :     }
     127             : 
     128             :     std::string ToString() const;
     129             : 
     130      385542 :     size_t DynamicMemoryUsage() const { return scriptSig.DynamicMemoryUsage(); }
     131             : };
     132             : 
     133             : /** An output of a transaction.  It contains the public key that the next input
     134             :  * must be able to sign with to claim it.
     135             :  */
     136   150132947 : class CTxOut
     137             : {
     138             : public:
     139             :     CAmount nValue;
     140             :     CScript scriptPubKey;
     141             :     int nRounds;
     142             : 
     143    68391457 :     CTxOut()
     144    68391457 :     {
     145   136782906 :         SetNull();
     146             :     }
     147             : 
     148             :     CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
     149             : 
     150    66738963 :     SERIALIZE_METHODS(CTxOut, obj) { READWRITE(obj.nValue, obj.scriptPubKey); }
     151             : 
     152    72607348 :     void SetNull()
     153             :     {
     154    72607348 :         nValue = -1;
     155    72607348 :         scriptPubKey.clear();
     156    63382929 :         nRounds = -10; // an initial value, should be no way to get this by calculations
     157             :     }
     158             : 
     159    53128349 :     bool IsNull() const
     160             :     {
     161    52398664 :         return (nValue == -1);
     162             :     }
     163             : 
     164       16125 :     void SetEmpty()
     165             :     {
     166       16125 :         nValue = 0;
     167       16125 :         scriptPubKey.clear();
     168             :     }
     169             : 
     170    12523874 :     bool IsEmpty() const
     171             :     {
     172    12523884 :         return (nValue == 0 && scriptPubKey.empty());
     173             :     }
     174             : 
     175             :     uint256 GetHash() const;
     176             : 
     177             :     bool IsZerocoinMint() const;
     178             : 
     179      390321 :     friend bool operator==(const CTxOut& a, const CTxOut& b)
     180             :     {
     181      385456 :         return (a.nValue       == b.nValue &&
     182      390321 :                 a.scriptPubKey == b.scriptPubKey &&
     183      385455 :                 a.nRounds      == b.nRounds);
     184             :     }
     185             : 
     186      167066 :     friend bool operator!=(const CTxOut& a, const CTxOut& b)
     187             :     {
     188      167066 :         return !(a == b);
     189             :     }
     190             : 
     191             :     std::string ToString() const;
     192             : 
     193      555344 :     size_t DynamicMemoryUsage() const { return scriptPubKey.DynamicMemoryUsage(); }
     194             : };
     195             : 
     196             : struct CMutableTransaction;
     197             : 
     198             : /**
     199             :  * Transaction serialization format:
     200             :  * - int32_t nVersion
     201             :  * - std::vector<CTxIn> vin
     202             :  * - std::vector<CTxOut> vout
     203             :  * - uint32_t nLockTime
     204             :  * - Optional<SaplingTxData> sapData
     205             :  * - Optional<std::vector<uint8_t>> extraPayload
     206             :  */
     207             : template<typename Stream, typename TxType>
     208     1018789 : inline void UnserializeTransaction(TxType& tx, Stream& s) {
     209     1018789 :     tx.vin.clear();
     210     1018789 :     tx.vout.clear();
     211             : 
     212     1018789 :     s >> tx.nVersion;
     213     1018789 :     s >> tx.nType;
     214     1018788 :     s >> tx.vin;
     215     1018786 :     s >> tx.vout;
     216     1018786 :     s >> tx.nLockTime;
     217     1018786 :     if (tx.isSaplingVersion()) {
     218       13555 :         s >> tx.sapData;
     219       13555 :         if (!tx.IsNormalType()) {
     220        9933 :             s >> tx.extraPayload;
     221             :         }
     222             :     }
     223     1018786 : }
     224             : 
     225             : template<typename Stream, typename TxType>
     226     6304961 : inline void SerializeTransaction(const TxType& tx, Stream& s) {
     227     6304961 :     s << tx.nVersion;
     228     6304961 :     s << tx.nType;
     229     6304961 :     s << tx.vin;
     230     6304961 :     s << tx.vout;
     231     6304961 :     s << tx.nLockTime;
     232     6304961 :     if (tx.isSaplingVersion()) {
     233      123272 :         s << tx.sapData;
     234      123272 :         if (!tx.IsNormalType()) {
     235       39065 :             s << tx.extraPayload;
     236             :         }
     237             :     }
     238     6304961 : }
     239             : 
     240             : /** The basic transaction that is broadcasted on the network and contained in
     241             :  * blocks. A transaction can contain multiple inputs and outputs.
     242             :  */
     243             : class CTransaction
     244             : {
     245             : public:
     246             :     /** Transaction Versions */
     247             :     enum TxVersion: int16_t {
     248             :         LEGACY      = 1,
     249             :         SAPLING     = 3,
     250             :         TOOHIGH
     251             :     };
     252             : 
     253             :     /** Transaction types */
     254             :     enum TxType: int16_t {
     255             :         NORMAL = 0,
     256             :         PROREG = 1,
     257             :         PROUPSERV = 2,
     258             :         PROUPREG = 3,
     259             :         PROUPREV = 4,
     260             :         LLMQCOMM = 5,
     261             :     };
     262             : 
     263             :     static const int16_t CURRENT_VERSION = TxVersion::LEGACY;
     264             : 
     265             :     // The local variables are made const to prevent unintended modification
     266             :     // without updating the cached hash value. However, CTransaction is not
     267             :     // actually immutable; deserialization and assignment are implemented,
     268             :     // and bypass the constness. This is safe, as they update the entire
     269             :     // structure, including the hash.
     270             :     std::vector<CTxIn> vin;
     271             :     std::vector<CTxOut> vout;
     272             :     const int16_t nVersion;
     273             :     const int16_t nType;
     274             :     const uint32_t nLockTime;
     275             :     Optional<SaplingTxData> sapData{SaplingTxData()}; // Future: Don't initialize it by default
     276             :     Optional<std::vector<uint8_t>> extraPayload{nullopt};     // only available for special transaction types
     277             : 
     278             :     /** Construct a CTransaction that qualifies as IsNull() */
     279             :     CTransaction();
     280             : 
     281             :     /** Convert a CMutableTransaction into a CTransaction. */
     282             :     CTransaction(const CMutableTransaction &tx);
     283             :     CTransaction(CMutableTransaction &&tx);
     284             : 
     285      721008 :     CTransaction(const CTransaction& tx) = default;
     286             : 
     287             :     template <typename Stream>
     288     5973001 :     inline void Serialize(Stream& s) const {
     289     5973001 :         SerializeTransaction(*this, s);
     290             :     }
     291             : 
     292             :     /** This deserializing constructor is provided instead of an Unserialize method.
     293             :       *  Unserialize is not possible, since it would require overwriting const fields. */
     294             :     template <typename Stream>
     295      807302 :     CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
     296             : 
     297             :     bool IsNull() const {
     298             :         return vin.empty() && vout.empty();
     299             :     }
     300             : 
     301   380906095 :     const uint256& GetHash() const {
     302   371045595 :         return hash;
     303             :     }
     304             : 
     305    12974656 :     bool hasSaplingData() const
     306             :     {
     307    25949212 :         return sapData != nullopt &&
     308    12974550 :             (!sapData->vShieldedOutput.empty() ||
     309    10363433 :             !sapData->vShieldedSpend.empty() ||
     310    10363307 :             sapData->valueBalance != 0 ||
     311    10363307 :             sapData->hasBindingSig());
     312             :     };
     313             : 
     314    24602518 :     bool isSaplingVersion() const
     315             :     {
     316    16212211 :         return nVersion >= TxVersion::SAPLING;
     317             :     }
     318             : 
     319    11561775 :     bool IsShieldedTx() const
     320             :     {
     321    11561775 :         return isSaplingVersion() && hasSaplingData();
     322             :     }
     323             : 
     324     1197818 :     bool hasExtraPayload() const
     325             :     {
     326     1197818 :         return extraPayload != nullopt && !extraPayload->empty();
     327             :     }
     328             : 
     329     1641768 :     bool IsSpecialTx() const
     330             :     {
     331     1369449 :         return isSaplingVersion() && nType != TxType::NORMAL && hasExtraPayload();
     332             :     }
     333             : 
     334     1837847 :     bool IsNormalType() const { return nType == TxType::NORMAL; }
     335             : 
     336       39876 :     bool IsProRegTx() const
     337             :     {
     338       39889 :         return IsSpecialTx() && nType == TxType::PROREG;
     339             :     }
     340             : 
     341      244017 :     bool IsQuorumCommitmentTx() const
     342             :     {
     343      253345 :         return IsSpecialTx() && nType == TxType::LLMQCOMM;
     344             :     }
     345             : 
     346             :     // Ensure that special and sapling fields are signed
     347     1325380 :     SigVersion GetRequiredSigVersion() const
     348             :     {
     349     1325380 :         return isSaplingVersion() ? SIGVERSION_SAPLING : SIGVERSION_BASE;
     350             :     }
     351             : 
     352             :     /*
     353             :      * Context for the two methods below:
     354             :      * We can think of the Sapling shielded part of the transaction as an input
     355             :      * or output according to whether valueBalance - the sum of shielded input
     356             :      * values minus the sum of shielded output values - is positive or negative.
     357             :      */
     358             : 
     359             :     // Return sum of txouts.
     360             :     CAmount GetValueOut() const;
     361             :     // GetValueIn() is a method on CCoinsViewCache, because
     362             :     // inputs must be known to compute value in.
     363             : 
     364             :     // Return sum of (positive valueBalance or zero) and JoinSplit vpub_new
     365             :     CAmount GetShieldedValueIn() const;
     366             : 
     367             :     bool HasZerocoinSpendInputs() const;
     368             : 
     369             :     bool HasZerocoinMintOutputs() const;
     370             : 
     371      240646 :     bool ContainsZerocoins() const
     372             :     {
     373      240646 :         return HasZerocoinSpendInputs() || HasZerocoinMintOutputs();
     374             :     }
     375             : 
     376    23798325 :     bool IsCoinBase() const
     377             :     {
     378    96112126 :         return (vin.size() == 1 && vin[0].prevout.IsNull() && !vin[0].scriptSig.IsZerocoinSpend());
     379             :     }
     380             : 
     381             :     bool IsCoinStake() const;
     382             :     bool HasP2CSOutputs() const;
     383             :     bool HasExchangeAddr() const;
     384             : 
     385     3448485 :     friend bool operator==(const CTransaction& a, const CTransaction& b)
     386             :     {
     387     3448485 :         return a.hash == b.hash;
     388             :     }
     389             : 
     390           0 :     friend bool operator!=(const CTransaction& a, const CTransaction& b)
     391             :     {
     392           0 :         return a.hash != b.hash;
     393             :     }
     394             : 
     395             :     unsigned int GetTotalSize() const;
     396             : 
     397             :     std::string ToString() const;
     398             : 
     399             :     size_t DynamicMemoryUsage() const;
     400             : 
     401             : private:
     402             :     /** Memory only. */
     403             :     const uint256 hash;
     404             :     uint256 ComputeHash() const;
     405             : };
     406             : 
     407             : /** A mutable version of CTransaction. */
     408             : struct CMutableTransaction
     409             : {
     410             :     std::vector<CTxIn> vin;
     411             :     std::vector<CTxOut> vout;
     412             :     int16_t nVersion;
     413             :     int16_t nType;
     414             :     uint32_t nLockTime;
     415             :     Optional<SaplingTxData> sapData{SaplingTxData()}; // Future: Don't initialize it by default
     416             :     Optional<std::vector<uint8_t>> extraPayload{nullopt};
     417             : 
     418             :     CMutableTransaction();
     419             :     CMutableTransaction(const CTransaction& tx);
     420             : 
     421             :     template <typename Stream>
     422      331960 :     inline void Serialize(Stream& s) const {
     423      331960 :         SerializeTransaction(*this, s);
     424             :     }
     425             : 
     426             :     template <typename Stream>
     427     1018789 :     inline void Unserialize(Stream& s) {
     428     1018789 :         UnserializeTransaction(*this, s);
     429      807302 :     }
     430             : 
     431             :     template <typename Stream>
     432      807302 :     CMutableTransaction(deserialize_type, Stream& s) {
     433      807302 :         Unserialize(s);
     434      807302 :     }
     435             : 
     436     1352147 :     bool isSaplingVersion() const { return nVersion >= CTransaction::TxVersion::SAPLING; }
     437       20924 :     bool IsNormalType() const { return nType == CTransaction::TxType::NORMAL; }
     438             : 
     439             :     /** Compute the hash of this CMutableTransaction. This is computed on the
     440             :      * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
     441             :      */
     442             :     uint256 GetHash() const;
     443             : 
     444          88 :     bool hasExtraPayload() const
     445             :     {
     446          88 :         return extraPayload != nullopt && !extraPayload->empty();
     447             :     }
     448             : 
     449             :     // Ensure that special and sapling fields are signed
     450      255632 :     SigVersion GetRequiredSigVersion() const
     451             :     {
     452      255632 :         return isSaplingVersion() ? SIGVERSION_SAPLING : SIGVERSION_BASE;
     453             :     }
     454             : };
     455             : 
     456             : typedef std::shared_ptr<const CTransaction> CTransactionRef;
     457        6775 : static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
     458      856039 : template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
     459      170052 : static inline CTransactionRef MakeTransactionRef(const CTransactionRef& txIn) { return txIn; }
     460             : static inline CTransactionRef MakeTransactionRef(CTransactionRef&& txIn) { return std::move(txIn); }
     461             : 
     462             : /* Special tx payload handling */
     463             : template <typename T>
     464       15329 : inline bool GetTxPayload(const std::vector<unsigned char>& payload, T& obj)
     465             : {
     466       30658 :     CDataStream ds(payload, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
     467             :     try {
     468       15327 :         ds >> obj;
     469           2 :     } catch (std::exception& e) {
     470             :         return false;
     471             :     }
     472       15327 :     return ds.empty();
     473             : }
     474             : template <typename T>
     475          88 : inline bool GetTxPayload(const CMutableTransaction& tx, T& obj)
     476             : {
     477          88 :     return tx.hasExtraPayload() && GetTxPayload(*tx.extraPayload, obj);
     478             : }
     479             : template <typename T>
     480       15241 : inline bool GetTxPayload(const CTransaction& tx, T& obj)
     481             : {
     482       15241 :     return tx.hasExtraPayload() && GetTxPayload(*tx.extraPayload, obj);
     483             : }
     484             : 
     485             : template <typename T>
     486         639 : void SetTxPayload(CMutableTransaction& tx, const T& payload)
     487             : {
     488         639 :     CDataStream ds(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
     489         639 :     ds << payload;
     490        1278 :     tx.extraPayload.emplace(ds.begin(), ds.end());
     491         639 : }
     492             : 
     493             : #endif // PIVX_PRIMITIVES_TRANSACTION_H

Generated by: LCOV version 1.14