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-02-23 09:33:43 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     9942925 : bool IsFinalTx(const CTransactionRef& tx, int nBlockHeight, int64_t nBlockTime)
      13             : {
      14             :     // Time based nLockTime implemented in 0.1.6
      15     9942925 :     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     1384332 : unsigned int GetLegacySigOpCount(const CTransaction& tx)
      28             : {
      29     1384332 :     unsigned int nSigOps = 0;
      30     3855756 :     for (const CTxIn& txin : tx.vin) {
      31     2471424 :         nSigOps += txin.scriptSig.GetSigOpCount(false);
      32             :     }
      33     5022511 :     for (const CTxOut& txout : tx.vout) {
      34     3638189 :         nSigOps += txout.scriptPubKey.GetSigOpCount(false);
      35             :     }
      36     1384332 :     return nSigOps;
      37             : }
      38             : 
      39      600054 : unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
      40             : {
      41      600054 :     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     1723716 :     for (unsigned int i = 0; i < tx.vin.size(); i++) {
      47     1123667 :         const CTxOut& prevout = inputs.AccessCoin(tx.vin[i].prevout).out;
      48     1123667 :         if (prevout.scriptPubKey.IsPayToScriptHash())
      49       62401 :             nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
      50             :     }
      51             :     return nSigOps;
      52             : }
      53             : 
      54      891273 : 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      891273 :     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      891271 :     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      891269 :     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      891269 :     static_assert(MAX_BLOCK_SIZE_CURRENT >= MAX_TX_SIZE_AFTER_SAPLING, "Max block size must be bigger than max TX size");    // sanity
      75      891269 :     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      891269 :     const unsigned int nMaxSize = tx.IsShieldedTx() ? MAX_TX_SIZE_AFTER_SAPLING : MAX_ZEROCOIN_TX_SIZE;
      77      891269 :     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      891269 :     CAmount nValueOut = 0;
      83      891269 :     if (!SaplingValidation::CheckTransaction(tx, state, nValueOut)) {
      84             :         return false;
      85             :     }
      86             : 
      87             :     // Check for negative or overflow output values
      88      891267 :     const Consensus::Params& consensus = Params().GetConsensus();
      89     3272544 :     for (const CTxOut& txout : tx.vout) {
      90     2398441 :         if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake())
      91          54 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-empty");
      92     2381278 :         if (txout.nValue < 0)
      93           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
      94     2381277 :         if (txout.nValue > consensus.nMaxMoneyOut)
      95           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
      96     2381276 :         nValueOut += txout.nValue;
      97     2381276 :         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     2381275 :         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     1782523 :     std::set<COutPoint> vInOutPoints;
     109     2510476 :     for (const CTxIn& txin : tx.vin) {
     110             :         // Check for duplicate inputs
     111     1619230 :         if (vInOutPoints.count(txin.prevout))
     112          12 :             return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
     113     1619228 :         if (!txin.IsZerocoinSpend()) {
     114     3238454 :             vInOutPoints.insert(txin.prevout);
     115             :         }
     116             :     }
     117             : 
     118      891241 :     bool hasExchangeUTXOs = tx.HasExchangeAddr();
     119             : 
     120      891241 :     if (tx.IsCoinBase()) {
     121       73445 :         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       73122 :         if (hasExchangeUTXOs)
     124           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-exchange-address-in-cb");
     125             :     } else {
     126     2364218 :         for (const CTxIn& txin : tx.vin)
     127     3099108 :             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      663440 : bool ContextualCheckTransaction(const CTransactionRef& tx, CValidationState& state, const CChainParams& chainparams, int nHeight, bool isMined, bool fIBD)
     135             : {
     136             :     // Dispatch to Sapling validator
     137      663440 :     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      663439 :     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