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"""Test node responses to invalid blocks.7In this test we connect to one node over p2p, and test block requests:81) Valid blocks should be requested and become chain tip.92) Invalid block with duplicated transaction should be re-requested.103) Invalid block with bad coinbase value should be rejected and not11re-requested.124) Invalid block due to future timestamp is later accepted when that timestamp13becomes valid.14"""15import copy16import time18from test_framework.blocktools import (19MAX_FUTURE_BLOCK_TIME,20create_block,21create_coinbase,22create_tx_with_script,23)24from test_framework.messages import COIN25from test_framework.p2p import P2PDataStore26from test_framework.script import OP_TRUE27from test_framework.test_framework import BitcoinTestFramework28from test_framework.util import (29assert_equal,30assert_not_equal,31)34class InvalidBlockRequestTest(BitcoinTestFramework):35def set_test_params(self):36self.num_nodes = 137self.setup_clean_chain = True38# whitelist peers to speed up tx relay / mempool sync39self.noban_tx_relay = True41def run_test(self):42# Add p2p connection to node043node = self.nodes[0] # convenience reference to the node44peer = node.add_p2p_connection(P2PDataStore())46best_block = node.getblock(node.getbestblockhash())47tip = int(node.getbestblockhash(), 16)48height = best_block["height"] + 149block_time = best_block["time"] + 151self.log.info("Create a new block with an anyone-can-spend coinbase")53block = create_block(tip, height=height, ntime=block_time)54block.solve()55# Save the coinbase for later56block1 = block57peer.send_blocks_and_test([block1], node, success=True)59self.log.info("Mature the block.")60self.generatetoaddress(node, 100, node.get_deterministic_priv_key().address)62best_block = node.getblock(node.getbestblockhash())63tip = int(node.getbestblockhash(), 16)64height = best_block["height"] + 165block_time = best_block["time"] + 167# Use merkle-root malleability to generate an invalid block with68# same blockheader (CVE-2012-2459).69# Manufacture a block with 3 transactions (coinbase, spend of prior70# coinbase, spend of that spend). Duplicate the 3rd transaction to71# leave merkle root and blockheader unchanged but invalidate the block.72# For more information on merkle-root malleability see src/consensus/merkle.cpp.73self.log.info("Test merkle root malleability.")75tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)76tx2 = create_tx_with_script(tx1, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)77block2 = create_block(tip, height=height, ntime=block_time, txlist=[tx1, tx2])78block_time += 179block2.solve()80orig_hash = block2.hash_int81block2_orig = copy.deepcopy(block2)83# Mutate block 284block2.vtx.append(tx2)85assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root())86assert_equal(orig_hash, block2.hash_int)87assert_not_equal(block2_orig.vtx, block2.vtx)89peer.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate')91# Check transactions for duplicate inputs (CVE-2018-17144)92self.log.info("Test duplicate input block.")94block2_dup = copy.deepcopy(block2_orig)95block2_dup.vtx[2].vin.append(block2_dup.vtx[2].vin[0])96block2_dup.hashMerkleRoot = block2_dup.calc_merkle_root()97block2_dup.solve()98peer.send_blocks_and_test([block2_dup], node, success=False, reject_reason='bad-txns-inputs-duplicate')100self.log.info("Test very broken block.")102block3 = create_block(tip, create_coinbase(height, nValue=100), ntime=block_time)103block_time += 1104block3.solve()106peer.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')109# Complete testing of CVE-2012-2459 by sending the original block.110# It should be accepted even though it has the same hash as the mutated one.112self.log.info("Test accepting original block after rejecting its mutated version.")113peer.send_blocks_and_test([block2_orig], node, success=True, timeout=5)115# Update tip info116height += 1117block_time += 1118tip = block2_orig.hash_int120# Complete testing of CVE-2018-17144, by checking for the inflation bug.121# Create a block that spends the output of a tx in a previous block.122tx3 = create_tx_with_script(tx2, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)123tx3.vin.append(tx3.vin[0]) # Duplicates input124block4 = create_block(tip, height=height, ntime=block_time, txlist=[tx3])125block4.solve()126self.log.info("Test inflation by duplicating input")127peer.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate')129self.log.info("Test accepting identical block after rejecting it due to a future timestamp.")130t = int(time.time())131node.setmocktime(t)132# Set block time +1 second past max future validity133block = create_block(tip, height=height, ntime=t + MAX_FUTURE_BLOCK_TIME + 1)134block.solve()135# Need force_send because the block will get rejected without a getdata otherwise136peer.send_blocks_and_test([block], node, force_send=True, success=False, reject_reason='time-too-new')137node.setmocktime(t + 1)138peer.send_blocks_and_test([block], node, success=True)141if __name__ == '__main__':142InvalidBlockRequestTest(__file__).main()
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.