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#!/usr/bin/env python32# Copyright (c) 2015-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.5"""6Templates for constructing various sorts of invalid transactions.8These templates (or an iterator over all of them) can be reused in different9contexts to test using a number of invalid transaction types.11Hopefully this makes it easier to get coverage of a full variety of tx12validation checks through different interfaces (AcceptBlock, AcceptToMemPool,13etc.) without repeating ourselves.15Invalid tx cases not covered here can be found by running:17$ diff \18<(grep -IREho "bad-txns[a-zA-Z-]+" src | sort -u) \19<(grep -IEho "bad-txns[a-zA-Z-]+" test/functional/data/invalid_txs.py | sort -u)21"""22import abc24from typing import Optional25from test_framework.messages import (26COutPoint,27CTransaction,28CTxIn,29CTxInWitness,30CTxOut,31MAX_MONEY,32SEQUENCE_FINAL,33)34from test_framework.blocktools import (35create_tx_with_script,36MAX_BLOCK_SIGOPS,37MAX_STANDARD_TX_SIGOPS,38)39from test_framework.script import (40OP_TRUE,41CScript,42OP_0,43OP_2DIV,44OP_2MUL,45OP_AND,46OP_CAT,47OP_CHECKSIG,48OP_DIV,49OP_INVERT,50OP_LEFT,51OP_LSHIFT,52OP_MOD,53OP_MUL,54OP_OR,55OP_RETURN,56OP_RIGHT,57OP_RSHIFT,58OP_SUBSTR,59OP_XOR,60)61from test_framework.util import assert_equal62from test_framework.script_util import (63MIN_PADDING,64MIN_STANDARD_TX_NONWITNESS_SIZE,65script_to_p2sh_script,66)67basic_p2sh = script_to_p2sh_script(CScript([OP_0]))69class BadTxTemplate:70"""Allows simple construction of a certain kind of invalid tx. Base class to be subclassed."""71__metaclass__ = abc.ABCMeta73# The expected error code given by bitcoind upon submission of the tx.74reject_reason: Optional[str] = ""76# Only specified if it differs from mempool acceptance error.77block_reject_reason = ""79# Is this tx considered valid when included in a block, but not for acceptance into80# the mempool (i.e. does it violate policy but not consensus)?81valid_in_block = False83def __init__(self, *, spend_tx=None, spend_block=None):84self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx85self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)86self.valid_txin = CTxIn(COutPoint(self.spend_tx.txid_int, 0), b"", SEQUENCE_FINAL)88@abc.abstractmethod89def get_tx(self, *args, **kwargs):90"""Return a CTransaction that is invalid per the subclass."""91pass94class OutputMissing(BadTxTemplate):95reject_reason = "bad-txns-vout-empty"97def get_tx(self):98tx = CTransaction()99tx.vin.append(self.valid_txin)100return tx103class InputMissing(BadTxTemplate):104reject_reason = "bad-txns-vin-empty"106# We use a blank transaction here to make sure107# it is interpreted as a non-witness transaction.108# Otherwise the transaction will fail the109# "surpufluous witness" check during deserialization110# rather than the input count check.111def get_tx(self):112tx = CTransaction()113return tx116# The following check prevents exploit of lack of merkle117# tree depth commitment (CVE-2017-12842)118class SizeTooSmall(BadTxTemplate):119reject_reason = "tx-size-small"120valid_in_block = True122def get_tx(self):123tx = CTransaction()124tx.vin.append(self.valid_txin)125tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))126assert_equal(len(tx.serialize_without_witness()), 64)127assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64)128return tx130# reject a transaction that contains a witness131# but doesn't spend a segwit output132class ExtraWitness(BadTxTemplate):133reject_reason = "tx-size-small"134block_reject_reason = "block-script-verify-flag-failed (Witness provided for non-witness script)"136def get_tx(self):137tx = CTransaction()138tx.vin.append(self.valid_txin)139tx.vout.append(CTxOut(0, CScript()))140tx.wit.vtxinwit = [CTxInWitness()]141tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]142return tx145class BadInputOutpointIndex(BadTxTemplate):146# Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins147# database can't distinguish between spent outpoints and outpoints which never existed.148reject_reason = None149# But fails in block150block_reject_reason = "bad-txns-inputs-missingorspent"152def get_tx(self):153num_indices = len(self.spend_tx.vin)154bad_idx = num_indices + 100156tx = CTransaction()157tx.vin.append(CTxIn(COutPoint(self.spend_tx.txid_int, bad_idx), b"", SEQUENCE_FINAL))158tx.vout.append(CTxOut(0, basic_p2sh))159return tx162class DuplicateInput(BadTxTemplate):163reject_reason = 'bad-txns-inputs-duplicate'165def get_tx(self):166tx = CTransaction()167tx.vin.append(self.valid_txin)168tx.vin.append(self.valid_txin)169tx.vout.append(CTxOut(1, basic_p2sh))170return tx173class PrevoutNullInput(BadTxTemplate):174reject_reason = 'bad-txns-prevout-null'176def get_tx(self):177tx = CTransaction()178tx.vin.append(self.valid_txin)179tx.vin.append(CTxIn(COutPoint(hash=0, n=0xffffffff)))180tx.vout.append(CTxOut(1, basic_p2sh))181return tx184class NonexistentInput(BadTxTemplate):185reject_reason = None # Added as an orphan tx.186# But fails in block187block_reject_reason = "bad-txns-inputs-missingorspent"189def get_tx(self):190tx = CTransaction()191tx.vin.append(CTxIn(COutPoint(self.spend_tx.txid_int + 1, 0), b"", SEQUENCE_FINAL))192tx.vin.append(self.valid_txin)193tx.vout.append(CTxOut(1, basic_p2sh))194return tx197class SpendTooMuch(BadTxTemplate):198reject_reason = 'bad-txns-in-belowout'200def get_tx(self):201return create_tx_with_script(202self.spend_tx, 0, output_script=basic_p2sh, amount=(self.spend_avail + 1))205class CreateNegative(BadTxTemplate):206reject_reason = 'bad-txns-vout-negative'208def get_tx(self):209return create_tx_with_script(self.spend_tx, 0, amount=-1)212class CreateTooLarge(BadTxTemplate):213reject_reason = 'bad-txns-vout-toolarge'215def get_tx(self):216return create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY + 1)219class CreateSumTooLarge(BadTxTemplate):220reject_reason = 'bad-txns-txouttotal-toolarge'222def get_tx(self):223tx = create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY)224tx.vout = [tx.vout[0]] * 2225return tx228class InvalidOPIFConstruction(BadTxTemplate):229reject_reason = "mempool-script-verify-flag-failed (Invalid OP_IF construction)"231def get_tx(self):232return create_tx_with_script(233self.spend_tx, 0, script_sig=b'\x68' * 35,234amount=(self.spend_avail // 2))237class TooManySigopsPerBlock(BadTxTemplate):238reject_reason = "bad-txns-too-many-sigops"239block_reject_reason = "bad-blk-sigops, out-of-bounds SigOpCount"241def get_tx(self):242lotsa_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))243return create_tx_with_script(244self.spend_tx, 0,245output_script=lotsa_checksigs,246amount=1)249class TooManySigopsPerTransaction(BadTxTemplate):250reject_reason = "bad-txns-too-many-sigops"
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.