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.
251self.log.info('A transaction with too large output value')252tx = tx_from_hex(raw_tx_reference)253tx.vout[0].nValue = MAX_MONEY + 1254self.check_mempool_result(255result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],256rawtxs=[tx.serialize().hex()],257)259self.log.info('A transaction with too large sum of output values')260tx = tx_from_hex(raw_tx_reference)261tx.vout = [tx.vout[0]] * 2262tx.vout[0].nValue = MAX_MONEY263self.check_mempool_result(264result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],265rawtxs=[tx.serialize().hex()],266)268self.log.info('A transaction with duplicate inputs')269tx = tx_from_hex(raw_tx_reference)270tx.vin = [tx.vin[0]] * 2271self.check_mempool_result(272result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],273rawtxs=[tx.serialize().hex()],274)276self.log.info('A non-coinbase transaction with coinbase-like outpoint')277tx = tx_from_hex(raw_tx_reference)278tx.vin.append(CTxIn(COutPoint(hash=0, n=0xffffffff)))279self.check_mempool_result(280result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-prevout-null'}],281rawtxs=[tx.serialize().hex()],282)284self.log.info('A coinbase transaction')285# Pick the input of the first tx we created, so it has to be a coinbase tx286sync_txindex(self, node)287raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])288tx = tx_from_hex(raw_tx_coinbase_spent)289self.check_mempool_result(290result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'coinbase'}],291rawtxs=[tx.serialize().hex()],292)294self.log.info('Some nonstandard transactions')295tx = tx_from_hex(raw_tx_reference)296tx.version = 4 # A version currently non-standard297self.check_mempool_result(298result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'version'}],299rawtxs=[tx.serialize().hex()],300)301tx = tx_from_hex(raw_tx_reference)302tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script303self.check_mempool_result(304result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptpubkey'}],305rawtxs=[tx.serialize().hex()],306)307tx = tx_from_hex(raw_tx_reference)308_, pubkey = generate_keypair()309tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=2) # Some bare multisig script (2-of-3)310self.check_mempool_result(311result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bare-multisig'}],312rawtxs=[tx.serialize().hex()],313)314tx = tx_from_hex(raw_tx_reference)315tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig316self.check_mempool_result(317result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],318rawtxs=[tx.serialize().hex()],319)320tx = tx_from_hex(raw_tx_reference)321tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)322self.check_mempool_result(323result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptsig-size'}],324rawtxs=[tx.serialize().hex()],325)326tx = tx_from_hex(raw_tx_reference)327output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=script_to_p2sh_script(b'burn'))328num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy329tx.vout = [output_p2sh_burn] * num_scripts330self.check_mempool_result(331result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'tx-size'}],332rawtxs=[tx.serialize().hex()],333)334tx = tx_from_hex(raw_tx_reference)335tx.vout[0] = output_p2sh_burn336tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy337self.check_mempool_result(338result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'dust'}],339rawtxs=[tx.serialize().hex()],340)342# OP_RETURN followed by non-push343tx = tx_from_hex(raw_tx_reference)344tx.vout[0].scriptPubKey = CScript([OP_RETURN, OP_HASH160])345self.check_mempool_result(346result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptpubkey'}],347rawtxs=[tx.serialize().hex()],348)350# Multiple OP_RETURN and more than 83 bytes, even if over MAX_SCRIPT_ELEMENT_SIZE351# are standard since v30352tx = tx_from_hex(raw_tx_reference)353tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff'])))354tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff' * 50000])))356self.check_mempool_result(357result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize_adjusted': tx.get_vsize(), 'vsize': tx.get_vsize(), 'vsize_bip141': tx.get_vsize(), 'fees': {'base': Decimal('0.05')}}],358rawtxs=[tx.serialize().hex()],359maxfeerate=0360)362self.log.info("A transaction with several OP_RETURN outputs.")363tx = tx_from_hex(raw_tx_reference)364op_return_count = 42365tx.vout[0].nValue = int(tx.vout[0].nValue / op_return_count)366tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])367tx.vout = [tx.vout[0]] * op_return_count368self.check_mempool_result(369result_expected=[{"txid": tx.txid_hex, "allowed": True, "vsize_adjusted": tx.get_vsize(), "vsize": tx.get_vsize(), 'vsize_bip141': tx.get_vsize(), "fees": {"base": Decimal("0.05000026")}}],370rawtxs=[tx.serialize().hex()],371)373self.log.info("A transaction with an OP_RETURN output that bumps into the max standardness tx size.")374tx = tx_from_hex(raw_tx_reference)375tx.vout[0].scriptPubKey = CScript([OP_RETURN])376data_len = int(MAX_STANDARD_TX_WEIGHT / 4) - tx.get_vsize() - 5 - 4 # -5 for PUSHDATA4 and -4 for script size377tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len)])378assert_equal(tx.get_vsize(), int(MAX_STANDARD_TX_WEIGHT / 4))379self.check_mempool_result(380result_expected=[{"txid": tx.txid_hex, "allowed": True, "vsize_adjusted": tx.get_vsize(), "vsize": tx.get_vsize(), 'vsize_bip141': tx.get_vsize(), "fees": {"base": Decimal("0.1") - Decimal("0.05")}}],381rawtxs=[tx.serialize().hex()],382)383tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len + 1)])384assert_greater_than(tx.get_vsize(), int(MAX_STANDARD_TX_WEIGHT / 4))385self.check_mempool_result(386result_expected=[{"txid": tx.txid_hex, "allowed": False, "reject-reason": "tx-size"}],387rawtxs=[tx.serialize().hex()],388)390self.log.info('A timelocked transaction')391tx = tx_from_hex(raw_tx_reference)392tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored393tx.nLockTime = node.getblockcount() + 1394self.check_mempool_result(395result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'non-final'}],396rawtxs=[tx.serialize().hex()],397)399self.log.info('A transaction that is locked by BIP68 sequence logic')400tx = tx_from_hex(raw_tx_reference)401tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one402self.check_mempool_result(403result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'non-BIP68-final'}],404rawtxs=[tx.serialize().hex()],405maxfeerate=0,406)408# Prep for tiny-tx tests with wsh(OP_TRUE) output409seed_tx = self.wallet.send_to(from_node=node, scriptPubKey=script_to_p2wsh_script(CScript([OP_TRUE])), amount=COIN)410self.generate(node, 1)412self.log.info('A tiny transaction(in non-witness bytes) that is disallowed')413tx = CTransaction()414tx.vin.append(CTxIn(COutPoint(int(seed_tx["txid"], 16), seed_tx["sent_vout"]), b"", SEQUENCE_FINAL))415tx.wit.vtxinwit = [CTxInWitness()]416tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]417tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))418# Note it's only non-witness size that matters!419assert_equal(len(tx.serialize_without_witness()), 64)420assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64)421assert_greater_than(len(tx.serialize()), 64)423self.check_mempool_result(424result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'tx-size-small'}],425rawtxs=[tx.serialize().hex()],426maxfeerate=0,427)429self.log.info('Minimally-small transaction(in non-witness bytes) that is allowed')430tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT)431assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE)432self.check_mempool_result(433result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize_adjusted': tx.get_vsize(), 'vsize': tx.get_vsize(), 'vsize_bip141': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}],434rawtxs=[tx.serialize().hex()],435maxfeerate=0,436)438self.log.info('OP_1 <0x4e73> is able to be created and spent')439anchor_value = 10000440create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value)441self.generate(node, 1)443# First spend has non-empty witness, will be rejected to prevent third party wtxid malleability444anchor_nonempty_wit_spend = CTransaction()445anchor_nonempty_wit_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b""))446anchor_nonempty_wit_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))447anchor_nonempty_wit_spend.wit.vtxinwit.append(CTxInWitness())448anchor_nonempty_wit_spend.wit.vtxinwit[0].scriptWitness.stack.append(b"f")450self.check_mempool_result(451result_expected=[{'txid': anchor_nonempty_wit_spend.txid_hex, 'allowed': False, 'reject-reason': 'bad-witness-nonstandard'}],452rawtxs=[anchor_nonempty_wit_spend.serialize().hex()],453maxfeerate=0,454)456# but is consensus-legal457self.generateblock(node, self.wallet.get_address(), [anchor_nonempty_wit_spend.serialize().hex()])459# Without witness elements it is standard460create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value)461self.generate(node, 1)463anchor_spend = CTransaction()464anchor_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b""))465anchor_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))466anchor_spend.wit.vtxinwit.append(CTxInWitness())467# It's "segwit" but txid == wtxid since there is no witness data468assert_equal(anchor_spend.txid_hex, anchor_spend.wtxid_hex)470self.check_mempool_result(471result_expected=[{'txid': anchor_spend.txid_hex, 'allowed': True, 'vsize_adjusted': anchor_spend.get_vsize(), 'vsize': anchor_spend.get_vsize(), 'vsize_bip141': anchor_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}],472rawtxs=[anchor_spend.serialize().hex()],473maxfeerate=0,474)476self.log.info('But cannot be spent if nested sh()')477nested_anchor_tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx']478nested_anchor_tx.vout[0].scriptPubKey = script_to_p2sh_script(PAY_TO_ANCHOR)479self.generateblock(node, self.wallet.get_address(), [nested_anchor_tx.serialize().hex()])481nested_anchor_spend = CTransaction()482nested_anchor_spend.vin.append(CTxIn(COutPoint(nested_anchor_tx.txid_int, 0), b""))483nested_anchor_spend.vin[0].scriptSig = CScript([bytes(PAY_TO_ANCHOR)])484nested_anchor_spend.vout.append(CTxOut(nested_anchor_tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))486self.check_mempool_result(487result_expected=[{'txid': nested_anchor_spend.txid_hex, 'allowed': False, 'reject-reason': 'mempool-script-verify-flag-failed (Witness version reserved for soft-fork upgrades)'}],488rawtxs=[nested_anchor_spend.serialize().hex()],489maxfeerate=0,490)491# but is consensus-legal492self.generateblock(node, self.wallet.get_address(), [nested_anchor_spend.serialize().hex()])494self.log.info('Spending a confirmed bare multisig is okay')495address = self.wallet.get_address()496tx = tx_from_hex(raw_tx_reference)497privkey, pubkey = generate_keypair()498tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=1) # Some bare multisig script (1-of-3)499self.generateblock(node, address, [tx.serialize().hex()])500tx_spend = CTransaction()
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.