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-02-23 09:33:43 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    14011020 :     BaseOutPoint() { SetNull(); }
      40    24749984 :     BaseOutPoint(const uint256& hashIn, const uint32_t nIn, bool isTransparentIn = true) :
      41    24749984 :         hash(hashIn), n(nIn), isTransparent(isTransparentIn) { }
      42             : 
      43    65246957 :     SERIALIZE_METHODS(BaseOutPoint, obj) { READWRITE(obj.hash, obj.n); }
      44             : 
      45    13972350 :     void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
      46    46560119 :     bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
      47             : 
      48   456991793 :     friend bool operator<(const BaseOutPoint& a, const BaseOutPoint& b)
      49             :     {
      50   456991793 :         return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
      51             :     }
      52             : 
      53    28742243 :     friend bool operator==(const BaseOutPoint& a, const BaseOutPoint& b)
      54             :     {
      55    28741111 :         return (a.hash == b.hash && a.n == b.n);
      56             :     }
      57             : 
      58        1132 :     friend bool operator!=(const BaseOutPoint& a, const BaseOutPoint& b)
      59             :     {
      60        2038 :         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     9064873 :     COutPoint() : BaseOutPoint() {};
      75    21616635 :     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         901 :     SaplingOutPoint() : BaseOutPoint() {};
      85        5127 :     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    71284233 : 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    10515609 :     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    36299879 :     SERIALIZE_METHODS(CTxIn, obj) { READWRITE(obj.prevout, obj.scriptSig, obj.nSequence); }
     109             : 
     110         863 :     bool IsFinal() const { return nSequence == SEQUENCE_FINAL; }
     111        1688 :     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      585511 :     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   159462677 : class CTxOut
     137             : {
     138             : public:
     139             :     CAmount nValue;
     140             :     CScript scriptPubKey;
     141             :     int nRounds;
     142             : 
     143    68907979 :     CTxOut()
     144    68907979 :     {
     145   137815982 :         SetNull();
     146             :     }
     147             : 
     148             :     CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
     149             : 
     150    72183363 :     SERIALIZE_METHODS(CTxOut, obj) { READWRITE(obj.nValue, obj.scriptPubKey); }
     151             : 
     152    74239263 :     void SetNull()
     153             :     {
     154    74239263 :         nValue = -1;
     155    74239263 :         scriptPubKey.clear();
     156    63270193 :         nRounds = -10; // an initial value, should be no way to get this by calculations
     157             :     }
     158             : 
     159    58501925 :     bool IsNull() const
     160             :     {
     161    57808178 :         return (nValue == -1);
     162             :     }
     163             : 
     164       16322 :     void SetEmpty()
     165             :     {
     166       16322 :         nValue = 0;
     167       16322 :         scriptPubKey.clear();
     168             :     }
     169             : 
     170    14425778 :     bool IsEmpty() const
     171             :     {
     172    14425788 :         return (nValue == 0 && scriptPubKey.empty());
     173             :     }
     174             : 
     175             :     uint256 GetHash() const;
     176             : 
     177             :     bool IsZerocoinMint() const;
     178             : 
     179      548383 :     friend bool operator==(const CTxOut& a, const CTxOut& b)
     180             :     {
     181      542026 :         return (a.nValue       == b.nValue &&
     182      548383 :                 a.scriptPubKey == b.scriptPubKey &&
     183      542023 :                 a.nRounds      == b.nRounds);
     184             :     }
     185             : 
     186      317467 :     friend bool operator!=(const CTxOut& a, const CTxOut& b)
     187             :     {
     188      317467 :         return !(a == b);
     189             :     }
     190             : 
     191             :     std::string ToString() const;
     192             : 
     193      855001 :     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     1121667 : inline void UnserializeTransaction(TxType& tx, Stream& s) {
     209     1121667 :     tx.vin.clear();
     210     1121667 :     tx.vout.clear();
     211             : 
     212     1121667 :     s >> tx.nVersion;
     213     1121667 :     s >> tx.nType;
     214     1121666 :     s >> tx.vin;
     215     1121664 :     s >> tx.vout;
     216     1121664 :     s >> tx.nLockTime;
     217     1121664 :     if (tx.isSaplingVersion()) {
     218       14393 :         s >> tx.sapData;
     219       14393 :         if (!tx.IsNormalType()) {
     220       10771 :             s >> tx.extraPayload;
     221             :         }
     222             :     }
     223     1121664 : }
     224             : 
     225             : template<typename Stream, typename TxType>
     226     7110164 : inline void SerializeTransaction(const TxType& tx, Stream& s) {
     227     7110164 :     s << tx.nVersion;
     228     7110164 :     s << tx.nType;
     229     7110164 :     s << tx.vin;
     230     7110164 :     s << tx.vout;
     231     7110164 :     s << tx.nLockTime;
     232     7110164 :     if (tx.isSaplingVersion()) {
     233      123329 :         s << tx.sapData;
     234      123329 :         if (!tx.IsNormalType()) {
     235       40328 :             s << tx.extraPayload;
     236             :         }
     237             :     }
     238     7110164 : }
     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      874381 :     CTransaction(const CTransaction& tx) = default;
     286             : 
     287             :     template <typename Stream>
     288     6778090 :     inline void Serialize(Stream& s) const {
     289     6778090 :         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      910135 :     CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
     296             : 
     297             :     bool IsNull() const {
     298             :         return vin.empty() && vout.empty();
     299             :     }
     300             : 
     301   414944252 :     const uint256& GetHash() const {
     302   405004752 :         return hash;
     303             :     }
     304             : 
     305    15509943 :     bool hasSaplingData() const
     306             :     {
     307    31019882 :         return sapData != nullopt &&
     308    15509937 :             (!sapData->vShieldedOutput.empty() ||
     309    12898802 :             !sapData->vShieldedSpend.empty() ||
     310    12898652 :             sapData->valueBalance != 0 ||
     311    12898652 :             sapData->hasBindingSig());
     312             :     };
     313             : 
     314    28866416 :     bool isSaplingVersion() const
     315             :     {
     316    18750518 :         return nVersion >= TxVersion::SAPLING;
     317             :     }
     318             : 
     319    13969618 :     bool IsShieldedTx() const
     320             :     {
     321    13969618 :         return isSaplingVersion() && hasSaplingData();
     322             :     }
     323             : 
     324     1419756 :     bool hasExtraPayload() const
     325             :     {
     326     1419756 :         return extraPayload != nullopt && !extraPayload->empty();
     327             :     }
     328             : 
     329     1973246 :     bool IsSpecialTx() const
     330             :     {
     331     1612388 :         return isSaplingVersion() && nType != TxType::NORMAL && hasExtraPayload();
     332             :     }
     333             : 
     334     2176427 :     bool IsNormalType() const { return nType == TxType::NORMAL; }
     335             : 
     336       58775 :     bool IsProRegTx() const
     337             :     {
     338       58788 :         return IsSpecialTx() && nType == TxType::PROREG;
     339             :     }
     340             : 
     341      313654 :     bool IsQuorumCommitmentTx() const
     342             :     {
     343      322979 :         return IsSpecialTx() && nType == TxType::LLMQCOMM;
     344             :     }
     345             : 
     346             :     // Ensure that special and sapling fields are signed
     347     1596945 :     SigVersion GetRequiredSigVersion() const
     348             :     {
     349     1596945 :         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      312393 :     bool ContainsZerocoins() const
     372             :     {
     373      312393 :         return HasZerocoinSpendInputs() || HasZerocoinMintOutputs();
     374             :     }
     375             : 
     376    27458424 :     bool IsCoinBase() const
     377             :     {
     378   101375067 :         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     4265555 :     friend bool operator==(const CTransaction& a, const CTransaction& b)
     386             :     {
     387     4265555 :         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      332074 :     inline void Serialize(Stream& s) const {
     423      332074 :         SerializeTransaction(*this, s);
     424             :     }
     425             : 
     426             :     template <typename Stream>
     427     1121667 :     inline void Unserialize(Stream& s) {
     428     1121667 :         UnserializeTransaction(*this, s);
     429      910135 :     }
     430             : 
     431             :     template <typename Stream>
     432      910135 :     CMutableTransaction(deserialize_type, Stream& s) {
     433      910135 :         Unserialize(s);
     434      910135 :     }
     435             : 
     436     1455139 :     bool isSaplingVersion() const { return nVersion >= CTransaction::TxVersion::SAPLING; }
     437       21693 :     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      255642 :     SigVersion GetRequiredSigVersion() const
     451             :     {
     452      255642 :         return isSaplingVersion() ? SIGVERSION_SAPLING : SIGVERSION_BASE;
     453             :     }
     454             : };
     455             : 
     456             : typedef std::shared_ptr<const CTransaction> CTransactionRef;
     457        6764 : static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
     458      933358 : template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
     459      191541 : 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       15355 : inline bool GetTxPayload(const std::vector<unsigned char>& payload, T& obj)
     465             : {
     466       30710 :     CDataStream ds(payload, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
     467             :     try {
     468       15353 :         ds >> obj;
     469           2 :     } catch (std::exception& e) {
     470             :         return false;
     471             :     }
     472       15353 :     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       15267 : inline bool GetTxPayload(const CTransaction& tx, T& obj)
     481             : {
     482       15267 :     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