LCOV - code coverage report
Current view: top level - src/consensus - tx_verify.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 65 73 89.0 %
Date: 2025-04-02 01:23:23 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2017-2017 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             : #include "tx_verify.h"
       6             : 
       7             : #include "consensus/consensus.h"
       8             : #include "consensus/zerocoin_verify.h"
       9             : #include "sapling/sapling_validation.h"
      10             : #include "../validation.h"
      11             : 
      12     9756738 : bool IsFinalTx(const CTransactionRef& tx, int nBlockHeight, int64_t nBlockTime)
      13             : {
      14             :     // Time based nLockTime implemented in 0.1.6
      15     9756738 :     if (tx->nLockTime == 0)
      16             :         return true;
      17          12 :     if (nBlockTime == 0)
      18           4 :         nBlockTime = GetAdjustedTime();
      19          12 :     if ((int64_t)tx->nLockTime < ((int64_t)tx->nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
      20             :         return true;
      21           8 :     for (const CTxIn& txin : tx->vin)
      22           8 :         if (!txin.IsFinal())
      23           8 :             return false;
      24           0 :     return true;
      25             : }
      26             : 
      27     1168707 : unsigned int GetLegacySigOpCount(const CTransaction& tx)
      28             : {
      29     1168707 :     unsigned int nSigOps = 0;
      30     3210856 :     for (const CTxIn& txin : tx.vin) {
      31     2042149 :         nSigOps += txin.scriptSig.GetSigOpCount(false);
      32             :     }
      33     4163769 :     for (const CTxOut& txout : tx.vout) {
      34     2995062 :         nSigOps += txout.scriptPubKey.GetSigOpCount(false);
      35             :     }
      36     1168707 :     return nSigOps;
      37             : }
      38             : 
      39      490447 : unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
      40             : {
      41      490447 :     if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs())
      42             :         // a tx containing a zc spend can have only zc inputs
      43           0 :         return 0;
      44             : 
      45             :     unsigned int nSigOps = 0;
      46     1395166 :     for (unsigned int i = 0; i < tx.vin.size(); i++) {
      47      904721 :         const CTxOut& prevout = inputs.AccessCoin(tx.vin[i].prevout).out;
      48      904721 :         if (prevout.scriptPubKey.IsPayToScriptHash())
      49       61904 :             nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
      50             :     }
      51             :     return nSigOps;
      52             : }
      53             : 
      54      766980 : bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fColdStakingActive)
      55             : {
      56             :     // Basic checks that don't depend on any context
      57             :     // Transactions containing empty `vin` must have non-empty `vShieldedSpend`,
      58             :     // or they must be quorum commitments (only one per-type allowed in a block)
      59      766980 :     if (tx.vin.empty() && (tx.sapData && tx.sapData->vShieldedSpend.empty()) && !tx.IsQuorumCommitmentTx())
      60           6 :         return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
      61             :     // Transactions containing empty `vout` must have non-empty `vShieldedOutput`,
      62             :     // or they must be quorum commitments (only one per-type allowed in a block)
      63      766978 :     if (tx.vout.empty() && (tx.sapData && tx.sapData->vShieldedOutput.empty()) && !tx.IsQuorumCommitmentTx())
      64           6 :         return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
      65             : 
      66             :     // Version check
      67      766976 :     if (tx.nVersion < 1 || tx.nVersion >= CTransaction::TxVersion::TOOHIGH) {
      68           0 :         return state.DoS(10,
      69           0 :                 error("%s: Transaction version (%d) too high. Max: %d", __func__, tx.nVersion, int(CTransaction::TxVersion::TOOHIGH) - 1),
      70             :                 REJECT_INVALID, "bad-tx-version-too-high");
      71             :     }
      72             : 
      73             :     // Size limits
      74      766976 :     static_assert(MAX_BLOCK_SIZE_CURRENT >= MAX_TX_SIZE_AFTER_SAPLING, "Max block size must be bigger than max TX size");    // sanity
      75      766976 :     static_assert(MAX_TX_SIZE_AFTER_SAPLING > MAX_ZEROCOIN_TX_SIZE, "New max TX size must be bigger than old max TX size");  // sanity
      76      766976 :     const unsigned int nMaxSize = tx.IsShieldedTx() ? MAX_TX_SIZE_AFTER_SAPLING : MAX_ZEROCOIN_TX_SIZE;
      77      766976 :     if (tx.GetTotalSize() > nMaxSize) {
      78           0 :         return state.DoS(10, error("tx oversize: %d > %d", tx.GetTotalSize(), nMaxSize), REJECT_INVALID, "bad-txns-oversize");
      79             :     }
      80             : 
      81             :     // Dispatch to Sapling validator
      82      766976 :     CAmount nValueOut = 0;
      83      766976 :     if (!SaplingValidation::CheckTransaction(tx, state, nValueOut)) {
      84             :         return false;
      85             :     }
      86             : 
      87             :     // Check for negative or overflow output values
      88      766974 :     const Consensus::Params& consensus = Params().GetConsensus();
      89     2777477 :     for (const CTxOut& txout : tx.vout) {
      90     2027482 :         if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake())
      91          54 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-empty");
      92     2010509 :         if (txout.nValue < 0)
      93           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
      94     2010508 :         if (txout.nValue > consensus.nMaxMoneyOut)
      95           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
      96     2010507 :         nValueOut += txout.nValue;
      97     2010507 :         if (!consensus.MoneyRange(nValueOut))
      98           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
      99             :         // check cold staking enforcement (for delegations) and value out
     100     2010506 :         if (txout.scriptPubKey.IsPayToColdStaking()) {
     101         209 :             if (!fColdStakingActive)
     102           3 :                 return state.DoS(10, false, REJECT_INVALID, "cold-stake-inactive");
     103         208 :             if (txout.nValue < MIN_COLDSTAKING_AMOUNT)
     104           0 :                 return state.DoS(100, false, REJECT_INVALID, "cold-stake-vout-toosmall");
     105             :         }
     106             :     }
     107             : 
     108     1533927 :     std::set<COutPoint> vInOutPoints;
     109     2138630 :     for (const CTxIn& txin : tx.vin) {
     110             :         // Check for duplicate inputs
     111     1371682 :         if (vInOutPoints.count(txin.prevout))
     112          12 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
     113     1371680 :         if (!txin.IsZerocoinSpend()) {
     114     2743358 :             vInOutPoints.insert(txin.prevout);
     115             :         }
     116             :     }
     117             : 
     118      766948 :     bool hasExchangeUTXOs = tx.HasExchangeAddr();
     119             : 
     120      766948 :     if (tx.IsCoinBase()) {
     121       72712 :         if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 150)
     122           4 :             return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
     123       72389 :         if (hasExchangeUTXOs)
     124           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-exchange-address-in-cb");
     125             :     } else {
     126     1993836 :         for (const CTxIn& txin : tx.vin)
     127     2604209 :             if (txin.prevout.IsNull() && !txin.IsZerocoinSpend())
     128           0 :                 return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
     129             :     }
     130             : 
     131             :     return true;
     132             : }
     133             : 
     134      555806 : bool ContextualCheckTransaction(const CTransactionRef& tx, CValidationState& state, const CChainParams& chainparams, int nHeight, bool isMined, bool fIBD)
     135             : {
     136             :     // Dispatch to Sapling validator
     137      555806 :     if (!SaplingValidation::ContextualCheckTransaction(*tx, state, chainparams, nHeight, isMined, fIBD)) {
     138             :         return false; // Failure reason has been set in validation state object
     139             :     }
     140             : 
     141             :     // Dispatch to ZerocoinTx validator
     142      555805 :     if (!ContextualCheckZerocoinTx(tx, state, chainparams.GetConsensus(), nHeight, isMined)) {
     143           6 :         return false; // Failure reason has been set in validation state object
     144             :     }
     145             : 
     146             :     return true;
     147             : }

Generated by: LCOV version 1.14