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) 2021-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 that a node in blocksonly mode does not request compact blocks."""7from test_framework.messages import (8MSG_BLOCK,9MSG_CMPCT_BLOCK,10MSG_WITNESS_FLAG,11CBlock,12CBlockHeader,13CInv,14from_hex,15HeaderAndShortIDs,16msg_block,17msg_cmpctblock,18msg_getdata,19msg_headers,20msg_sendcmpct,21)22from test_framework.p2p import P2PInterface23from test_framework.test_framework import BitcoinTestFramework24from test_framework.util import assert_equal27class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):28def set_test_params(self):29self.extra_args = [["-blocksonly"], [], [], []]30self.num_nodes = 432def setup_network(self):33self.setup_nodes()34# Start network with everyone disconnected35self.sync_all()37def build_block_on_tip(self):38blockhash = self.generate(self.nodes[2], 1, sync_fun=self.no_op)[0]39block_hex = self.nodes[2].getblock(blockhash=blockhash, verbosity=0)40block = from_hex(CBlock(), block_hex)41return block43def ignores_cmpctblock(self, node_id, conn, solicited=False):44# Briefly connect to mining node, sync, and disconnect, just to make45# sure the node is on the same tip as the miner so that compact block46# reconstruction works.47self.connect_nodes(2, node_id)48self.sync_blocks([self.nodes[2], self.nodes[node_id]], timeout=10)49self.disconnect_nodes(2, node_id)51block = self.build_block_on_tip()52if solicited:53conn.send_without_ping(msg_headers([block]))54conn.wait_for_getdata([block.hash_int], timeout=10)55cmpct_block = HeaderAndShortIDs()56cmpct_block.initialize_from_block(block, use_witness=True)57msg = msg_cmpctblock(cmpct_block.to_p2p())58conn.send_and_ping(msg)60cmpct_block_received = self.nodes[node_id].getbestblockhash() == cmpct_block.header.hash_hex61if not cmpct_block_received:62# Compact block was ignored, send the full block to keep in sync.63conn.send_and_ping(msg_block(block))65return not cmpct_block_received67def run_test(self):68# Nodes will only request hb compact blocks mode when they're out of IBD69for node in self.nodes:70assert not node.getblockchaininfo()['initialblockdownload']72p2p_conn_blocksonly = self.nodes[0].add_p2p_connection(P2PInterface())73p2p_conn_high_bw = self.nodes[1].add_p2p_connection(P2PInterface())74p2p_conn_low_bw = self.nodes[3].add_p2p_connection(P2PInterface())75for conn in [p2p_conn_blocksonly, p2p_conn_high_bw, p2p_conn_low_bw]:76assert_equal(conn.message_count['sendcmpct'], 1)77conn.send_and_ping(msg_sendcmpct(announce=False, version=2))79# Nodes:80# 0 -> blocksonly81# 1 -> high bandwidth82# 2 -> miner83# 3 -> low bandwidth84#85# Topology:86# p2p_conn_blocksonly ---> node087# p2p_conn_high_bw ---> node188# p2p_conn_low_bw ---> node389# node2 (no connections)90#91# node2 produces blocks that are passed to the rest of the nodes92# through the respective p2p connections.94self.log.info("Test that -blocksonly nodes do not select peers for BIP152 high bandwidth mode")96block0 = self.build_block_on_tip()98# A -blocksonly node should not request BIP152 high bandwidth mode upon99# receiving a new valid block at the tip.100p2p_conn_blocksonly.send_and_ping(msg_block(block0))101assert_equal(self.nodes[0].getbestblockhash(), block0.hash_hex)102assert_equal(p2p_conn_blocksonly.message_count['sendcmpct'], 1)103assert_equal(p2p_conn_blocksonly.last_message['sendcmpct'].announce, False)105# A normal node participating in transaction relay should request BIP152106# high bandwidth mode upon receiving a new valid block at the tip.107p2p_conn_high_bw.send_and_ping(msg_block(block0))108assert_equal(self.nodes[1].getbestblockhash(), block0.hash_hex)109p2p_conn_high_bw.wait_until(lambda: p2p_conn_high_bw.message_count['sendcmpct'] == 2)110assert_equal(p2p_conn_high_bw.last_message['sendcmpct'].announce, True)112# Don't send a block from the p2p_conn_low_bw so the low bandwidth node113# doesn't select it for BIP152 high bandwidth relay.114self.nodes[3].submitblock(block0.serialize().hex())116self.log.info("Test that -blocksonly nodes send getdata(BLOCK) instead"117" of getdata(CMPCT) in BIP152 low bandwidth mode")119block1 = self.build_block_on_tip()121p2p_conn_blocksonly.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))122assert_equal(p2p_conn_blocksonly.last_message['getdata'].inv, [CInv(MSG_BLOCK | MSG_WITNESS_FLAG, block1.hash_int)])124p2p_conn_high_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))125assert_equal(p2p_conn_high_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.hash_int)])127# Send the block to avoid stalling the peer later in the test.128comp_block = HeaderAndShortIDs()129comp_block.initialize_from_block(block1, use_witness=True)130block1_cb_msg = msg_cmpctblock(comp_block.to_p2p())131p2p_conn_high_bw.send_and_ping(block1_cb_msg)133self.log.info("Test that getdata(CMPCT) is still sent on BIP152 low bandwidth connections"134" when no -blocksonly nodes are involved")136p2p_conn_low_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))137assert_equal(p2p_conn_low_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.hash_int)])138# Send the block to avoid stalling the peer later in the test.139p2p_conn_low_bw.send_and_ping(block1_cb_msg)141self.log.info("Test that -blocksonly nodes still serve compact blocks")143def test_for_cmpctblock(block):144if 'cmpctblock' not in p2p_conn_blocksonly.last_message:145return False146return p2p_conn_blocksonly.last_message['cmpctblock'].header_and_shortids.header.hash_int == block.hash_int148p2p_conn_blocksonly.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, block0.hash_int)]))149p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block0))151# Request BIP152 high bandwidth mode from the -blocksonly node.152p2p_conn_blocksonly.send_and_ping(msg_sendcmpct(announce=True, version=2))154block2 = self.build_block_on_tip()155self.nodes[0].submitblock(block1.serialize().hex())156self.nodes[0].submitblock(block2.serialize().hex())157p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2))159# This is redundant with other tests, and is here as a test-of-the-test160self.log.info("Test that normal nodes don't ignore CMPCTBLOCK messages from HB peers")161assert not self.ignores_cmpctblock(1, p2p_conn_high_bw, solicited=False)163self.log.info("Test that -blocksonly nodes ignore CMPCTBLOCK messages")164assert self.ignores_cmpctblock(0, p2p_conn_blocksonly, solicited=False)166self.log.info("Test that low bandwidth nodes listen to CMPCTBLOCK messages when the block is requested")167assert not self.ignores_cmpctblock(3, p2p_conn_low_bw, solicited=True)169self.log.info("Test that -blocksonly nodes ignore CMPCTBLOCK messages even when the block is requested")170assert self.ignores_cmpctblock(0, p2p_conn_blocksonly, solicited=True)172if __name__ == '__main__':173P2PCompactBlocksBlocksOnly(__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.