Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#ifndef BITCOIN_CONSENSUS_VALIDATION_H7#define BITCOIN_CONSENSUS_VALIDATION_H9#include <consensus/consensus.h>10#include <primitives/block.h>11#include <primitives/transaction.h>12#include <script/script.h>13#include <serialize.h>15#include <cstddef>16#include <cstdint>17#include <string>18#include <vector>21/** Index marker for when no witness commitment is present in a coinbase transaction. */22inline constexpr int NO_WITNESS_COMMITMENT{-1};24/** Minimum size of a witness commitment structure. Defined in BIP 141. **/25inline constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};27/** A "reason" why a transaction was invalid, suitable for determining whether the28* provider of the transaction should be banned/ignored/disconnected/etc.29*/30enum class TxValidationResult {31TX_RESULT_UNSET = 0, //!< initial value. Tx has not yet been rejected32TX_CONSENSUS, //!< invalid by consensus rules33TX_INPUTS_NOT_STANDARD, //!< inputs (covered by txid) failed policy rules34TX_NOT_STANDARD, //!< otherwise didn't meet our local policy rules35TX_MISSING_INPUTS, //!< transaction was missing some of its inputs36TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks37/**38* Transaction might have a witness prior to SegWit39* activation, or witness may have been malleated (which includes40* non-standard witnesses).41*/42TX_WITNESS_MUTATED,43/**44* Transaction is missing a witness.45*/46TX_WITNESS_STRIPPED,47/**48* Tx already in mempool or conflicts with a tx in the chain49* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)50* Currently this is only used if the transaction already exists in the mempool or on chain.51*/52TX_CONFLICT,53TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits54TX_NO_MEMPOOL, //!< this node does not have a mempool so can't validate the transaction55TX_RECONSIDERABLE, //!< fails some policy, but might be acceptable if submitted in a (different) package56TX_UNKNOWN, //!< transaction was not validated because package failed57};59/** A "reason" why a block was invalid, suitable for determining whether the60* provider of the block should be banned/ignored/disconnected/etc.61* These are much more granular than the rejection codes, which may be more62* useful for some other use-cases.63*/64enum class BlockValidationResult {65BLOCK_RESULT_UNSET = 0, //!< initial value. Block has not yet been rejected66BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)67BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why68BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old69BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW70BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on71BLOCK_INVALID_PREV, //!< A block this one builds on is invalid72BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)73BLOCK_HEADER_LOW_WORK //!< the block header may be on a too-little-work chain74};78/** Template for capturing information about block/transaction validation. This is instantiated79* by TxValidationState and BlockValidationState for validation information on transactions80* and blocks respectively. */81template <typename Result>82class ValidationState83{84private:85enum class ModeState {86M_VALID, //!< everything ok87M_INVALID, //!< network rule violation (DoS value may be set)88M_ERROR, //!< run-time error89} m_mode{ModeState::M_VALID};90Result m_result{};91std::string m_reject_reason;92std::string m_debug_message;94public:95bool Invalid(Result result,96const std::string& reject_reason = "",97const std::string& debug_message = "")98{99m_result = result;100m_reject_reason = reject_reason;101m_debug_message = debug_message;102if (m_mode != ModeState::M_ERROR) m_mode = ModeState::M_INVALID;103return false;104}105bool Error(const std::string& reject_reason)106{107if (m_mode == ModeState::M_VALID)108m_reject_reason = reject_reason;109m_mode = ModeState::M_ERROR;110return false;111}112bool IsValid() const { return m_mode == ModeState::M_VALID; }113bool IsInvalid() const { return m_mode == ModeState::M_INVALID; }114bool IsError() const { return m_mode == ModeState::M_ERROR; }115Result GetResult() const { return m_result; }116std::string GetRejectReason() const { return m_reject_reason; }117std::string GetDebugMessage() const { return m_debug_message; }118std::string ToString() const119{120if (IsValid()) {121return "Valid";122}124if (!m_debug_message.empty()) {125return m_reject_reason + ", " + m_debug_message;126}128return m_reject_reason;129}130};132class TxValidationState : public ValidationState<TxValidationResult> {};133class BlockValidationState : public ValidationState<BlockValidationResult> {};135// These implement the weight = (stripped_size * 4) + witness_size formula,136// using only serialization with and without witness data. As witness_size137// is equal to total_size - stripped_size, this formula is identical to:138// weight = (stripped_size * 3) + total_size.139static inline int32_t GetTransactionWeight(const CTransaction& tx)140{141return ::GetSerializeSize(TX_NO_WITNESS(tx)) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(TX_WITH_WITNESS(tx));142}143static inline int64_t GetBlockWeight(const CBlock& block)144{145return ::GetSerializeSize(TX_NO_WITNESS(block)) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(TX_WITH_WITNESS(block));146}147static inline int64_t GetTransactionInputWeight(const CTxIn& txin)148{149// scriptWitness size is added here because witnesses and txins are split up in segwit serialization.150return ::GetSerializeSize(TX_NO_WITNESS(txin)) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(TX_WITH_WITNESS(txin)) + ::GetSerializeSize(txin.scriptWitness.stack);151}153/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */154inline int GetWitnessCommitmentIndex(const CBlock& block)155{156int commitpos = NO_WITNESS_COMMITMENT;157if (!block.vtx.empty()) {158for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {159const CTxOut& vout = block.vtx[0]->vout[o];160if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&161vout.scriptPubKey[0] == OP_RETURN &&162vout.scriptPubKey[1] == 0x24 &&163vout.scriptPubKey[2] == 0xaa &&164vout.scriptPubKey[3] == 0x21 &&165vout.scriptPubKey[4] == 0xa9 &&166vout.scriptPubKey[5] == 0xed) {167commitpos = o;168}169}170}171return commitpos;172}174#endif // BITCOIN_CONSENSUS_VALIDATION_H