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) 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 that the correct active block is chosen in complex reorgs."""7from test_framework.blocktools import create_block8from test_framework.messages import CBlockHeader9from test_framework.p2p import P2PDataStore10from test_framework.test_framework import BitcoinTestFramework11from test_framework.util import assert_equal13class ChainTiebreaksTest(BitcoinTestFramework):14def set_test_params(self):15self.num_nodes = 216self.setup_clean_chain = True18def setup_network(self):19self.setup_nodes()21@staticmethod22def send_headers(node, blocks):23"""Submit headers for blocks to node."""24for block in blocks:25# Use RPC rather than P2P, to prevent the message from being interpreted as a block26# announcement.27node.submitheader(hexdata=CBlockHeader(block).serialize().hex())29def test_chain_split_in_memory(self):30node = self.nodes[0]31# Add P2P connection to bitcoind32peer = node.add_p2p_connection(P2PDataStore())34self.log.info('Precomputing blocks')35#36# /- B3 -- B737# B1 \- B838# / \39# / \ B4 -- B940# B0 \- B1041# \42# \ /- B543# B244# \- B645#46blocks = []48# Construct B0, building off genesis.49start_height = node.getblockcount()50blocks.append(create_block(51hashprev=int(node.getbestblockhash(), 16),52tmpl={"height": start_height + 1}53))54blocks[-1].solve()56# Construct B1-B10.57for i in range(1, 11):58blocks.append(create_block(59hashprev=blocks[(i - 1) >> 1].hash_int,60tmpl={61"height": start_height + (i + 1).bit_length(),62# Make sure each block has a different hash.63"curtime": blocks[-1].nTime + 1,64}65))66blocks[-1].solve()68self.log.info('Make sure B0 is accepted normally')69peer.send_blocks_and_test([blocks[0]], node, success=True)70# B0 must be active chain now.71assert_equal(node.getbestblockhash(), blocks[0].hash_hex)73self.log.info('Send B1 and B2 headers, and then blocks in opposite order')74self.send_headers(node, blocks[1:3])75peer.send_blocks_and_test([blocks[2]], node, success=True)76peer.send_blocks_and_test([blocks[1]], node, success=False)77# B2 must be active chain now, as full data for B2 was received first.78assert_equal(node.getbestblockhash(), blocks[2].hash_hex)80self.log.info('Send all further headers in order')81self.send_headers(node, blocks[3:])82# B2 is still the active chain, headers don't change this.83assert_equal(node.getbestblockhash(), blocks[2].hash_hex)85self.log.info('Send blocks B7-B10')86peer.send_blocks_and_test([blocks[7]], node, success=False)87peer.send_blocks_and_test([blocks[8]], node, success=False)88peer.send_blocks_and_test([blocks[9]], node, success=False)89peer.send_blocks_and_test([blocks[10]], node, success=False)90# B2 is still the active chain, as B7-B10 have missing parents.91assert_equal(node.getbestblockhash(), blocks[2].hash_hex)93self.log.info('Send parents B3-B4 of B8-B10 in reverse order')94peer.send_blocks_and_test([blocks[4]], node, success=False, force_send=True)95peer.send_blocks_and_test([blocks[3]], node, success=False, force_send=True)96# B9 is now active. Despite B7 being received earlier, the missing parent.97assert_equal(node.getbestblockhash(), blocks[9].hash_hex)99self.log.info('Invalidate B9-B10')100node.invalidateblock(blocks[9].hash_hex)101node.invalidateblock(blocks[10].hash_hex)102# B7 is now active.103assert_equal(node.getbestblockhash(), blocks[7].hash_hex)105# Invalidate blocks to start fresh on the next test106node.invalidateblock(blocks[0].hash_hex)108def test_chain_split_from_disk(self):109node = self.nodes[1]110peer = node.add_p2p_connection(P2PDataStore())112self.generate(node, 1, sync_fun=self.no_op)114self.log.info('Precomputing blocks')115#116# /- A1117# /118# G -- B1 --- A2119# \120# \- A3121#122blocks = []124# Construct three equal-work blocks building from the tip.125start_height = node.getblockcount()126tip_block = node.getblock(node.getbestblockhash())127prev_time = tip_block["time"]129for i in range(0, 3):130blocks.append(create_block(131hashprev=int(tip_block["hash"], 16),132tmpl={"height": start_height + 1,133# Make sure each block has a different hash.134"curtime": prev_time + i + 1,135}136))137blocks[-1].solve()139# Send blocks and test that only the first one connects140self.log.info('Send A1, A2, and A3. Make sure that only the former connects')141peer.send_blocks_and_test([blocks[0]], node, success=True)142peer.send_blocks_and_test([blocks[1]], node, success=False)143peer.send_blocks_and_test([blocks[2]], node, success=False)145# Restart and send a new block146self.restart_node(1)147assert_equal(blocks[0].hash_hex, node.getbestblockhash())148peer = node.add_p2p_connection(P2PDataStore())149next_block = create_block(150hashprev=blocks[0].hash_int,151tmpl={"height": start_height + 2,152"curtime": prev_time + 10,153}154)155next_block.solve()156peer.send_blocks_and_test([next_block], node, success=True)158def run_test(self):159self.test_chain_split_in_memory()160self.test_chain_split_from_disk()163if __name__ == '__main__':164ChainTiebreaksTest(__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.