Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2017-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <consensus/tx_verify.h>7#include <chain.h>8#include <coins.h>9#include <consensus/amount.h>10#include <consensus/consensus.h>11#include <consensus/validation.h>12#include <primitives/transaction.h>13#include <script/interpreter.h>14#include <script/script.h>15#include <tinyformat.h>16#include <util/check.h>17#include <util/moneystr.h>19#include <algorithm>20#include <cstddef>21#include <string>23bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)24{25if (tx.nLockTime == 0)26return true;27if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))28return true;30// Even if tx.nLockTime isn't satisfied by nBlockHeight/nBlockTime, a31// transaction is still considered final if all inputs' nSequence ==32// SEQUENCE_FINAL (0xffffffff), in which case nLockTime is ignored.33//34// Because of this behavior OP_CHECKLOCKTIMEVERIFY/CheckLockTime() will35// also check that the spending input's nSequence != SEQUENCE_FINAL,36// ensuring that an unsatisfied nLockTime value will actually cause37// IsFinalTx() to return false here:38for (const auto& txin : tx.vin) {39if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))40return false;41}42return true;43}45std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block)46{47assert(prevHeights.size() == tx.vin.size());49// Will be set to the equivalent height- and time-based nLockTime50// values that would be necessary to satisfy all relative lock-51// time constraints given our view of block chain history.52// The semantics of nLockTime are the last invalid height/time, so53// use -1 to have the effect of any height or time being valid.54int nMinHeight = -1;55int64_t nMinTime = -1;57bool fEnforceBIP68 = tx.version >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE;59// Do not enforce sequence numbers as a relative lock time60// unless we have been instructed to61if (!fEnforceBIP68) {62return std::make_pair(nMinHeight, nMinTime);63}65for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {66const CTxIn& txin = tx.vin[txinIndex];68// Sequence numbers with the most significant bit set are not69// treated as relative lock-times, nor are they given any70// consensus-enforced meaning at this point.71if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {72// The height of this input is not relevant for sequence locks73prevHeights[txinIndex] = 0;74continue;75}77int nCoinHeight = prevHeights[txinIndex];79if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {80const int64_t nCoinTime{Assert(block.GetAncestor(std::max(nCoinHeight - 1, 0)))->GetMedianTimePast()};81// NOTE: Subtract 1 to maintain nLockTime semantics82// BIP 68 relative lock times have the semantics of calculating83// the first block or time at which the transaction would be84// valid. When calculating the effective block time or height85// for the entire transaction, we switch to using the86// semantics of nLockTime which is the last invalid block87// time or height. Thus we subtract 1 from the calculated88// time or height.90// Time-based relative lock-times are measured from the91// smallest allowed timestamp of the block containing the92// txout being spent, which is the median time past of the93// block prior.94nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);95} else {96nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);97}98}100return std::make_pair(nMinHeight, nMinTime);101}103bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)104{105assert(block.pprev);106int64_t nBlockTime = block.pprev->GetMedianTimePast();107if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)108return false;110return true;111}113bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block)114{115return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));116}118unsigned int GetLegacySigOpCount(const CTransaction& tx)119{120unsigned int nSigOps = 0;121for (const auto& txin : tx.vin)122{123nSigOps += txin.scriptSig.GetSigOpCount(false);124}125for (const auto& txout : tx.vout)126{127nSigOps += txout.scriptPubKey.GetSigOpCount(false);128}129return nSigOps;130}132unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)133{134if (tx.IsCoinBase())135return 0;137unsigned int nSigOps = 0;138for (unsigned int i = 0; i < tx.vin.size(); i++)139{140const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);141assert(!coin.IsSpent());142const CTxOut &prevout = coin.out;143if (prevout.scriptPubKey.IsPayToScriptHash())144nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);145}146return nSigOps;147}149int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)150{151int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;153if (tx.IsCoinBase())154return nSigOps;156if (flags & SCRIPT_VERIFY_P2SH) {157nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;158}160for (unsigned int i = 0; i < tx.vin.size(); i++)161{162const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);163assert(!coin.IsSpent());164const CTxOut &prevout = coin.out;165nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, tx.vin[i].scriptWitness, flags);166}167return nSigOps;168}170bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)171{172// are the actual inputs available?173if (!inputs.HaveInputs(tx)) {174return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",175strprintf("%s: inputs missing/spent", __func__));176}178CAmount nValueIn = 0;179for (unsigned int i = 0; i < tx.vin.size(); ++i) {180const COutPoint &prevout = tx.vin[i].prevout;181const Coin& coin = inputs.AccessCoin(prevout);182assert(!coin.IsSpent());184// If prev is coinbase, check that it's matured185if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {186return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",187strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));188}190// Check for negative or overflow input values191nValueIn += coin.out.nValue;192if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {193return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");194}195}197// `tx.GetValueOut()` won't throw in validation paths because output-range checks run first198// (`bad-txns-vout-negative`, `bad-txns-vout-toolarge`, `bad-txns-txouttotal-toolarge`):199// * `MemPoolAccept::PreChecks`: `CheckTransaction()` is called before this method;200// * `Chainstate::ConnectBlock`: `CheckTransaction()` is called via `CheckBlock()` before this method.201const CAmount value_out = tx.GetValueOut();202if (nValueIn < value_out) {203return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",204strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));205}207// Tally transaction fees208const CAmount txfee_aux = nValueIn - value_out;209if (!MoneyRange(txfee_aux)) {210// Unreachable, given the following preconditions:211// * `value_out` comes from `tx.GetValueOut()`, which throws unless `MoneyRange(value_out)` and asserts `MoneyRange(nValueOut)` on return.212// * `MoneyRange(nValueIn)` was enforced in the input loop.213// * `nValueIn < value_out` was handled above, so `nValueIn >= value_out` here (and `txfee_aux >= 0`).214// Therefore `0 <= txfee_aux = nValueIn - value_out <= nValueIn <= MAX_MONEY`.215return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");216}218txfee = txfee_aux;219return true;220}