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) 2024-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"""6Test P2P behaviour during the handshake phase (VERSION, VERACK messages).7"""8import itertools9import time11from test_framework.test_framework import BitcoinTestFramework12from test_framework.util import assert_equal, assert_not_equal13from test_framework.messages import (14NODE_NETWORK,15NODE_NETWORK_LIMITED,16NODE_NONE,17NODE_P2P_V2,18NODE_WITNESS,19msg_verack,20)21from test_framework.p2p import P2PInterface22from test_framework.util import p2p_port25# Desirable service flags for outbound non-pruned and pruned peers. Note that26# the desirable service flags for pruned peers are dynamic and only apply if27# 1. the peer's service flag NODE_NETWORK_LIMITED is set *and*28# 2. the local chain is close to the tip (<24h)29DESIRABLE_SERVICE_FLAGS_FULL = NODE_NETWORK | NODE_WITNESS30DESIRABLE_SERVICE_FLAGS_PRUNED = NODE_NETWORK_LIMITED | NODE_WITNESS33class P2PHandshakeTest(BitcoinTestFramework):34def set_test_params(self):35self.num_nodes = 137def add_outbound_connection(self, node, connection_type, services, wait_for_disconnect):38peer = node.add_outbound_p2p_connection(39P2PInterface(), p2p_idx=0, wait_for_disconnect=wait_for_disconnect,40connection_type=connection_type, services=services,41supports_v2_p2p=self.options.v2transport, advertise_v2_p2p=self.options.v2transport)42if not wait_for_disconnect:43# check that connection is alive past the version handshake and disconnect manually44peer.sync_with_ping()45peer.peer_disconnect()46peer.wait_for_disconnect()47self.wait_until(lambda: len(node.getpeerinfo()) == 0)49def test_desirable_service_flags(self, node, service_flag_tests, desirable_service_flags, expect_disconnect):50"""Check that connecting to a peer either fails or succeeds depending on its offered51service flags in the VERSION message. The test is exercised for all relevant52outbound connection types where the desirable service flags check is done."""53CONNECTION_TYPES = ["outbound-full-relay", "block-relay-only", "addr-fetch"]54for conn_type, services in itertools.product(CONNECTION_TYPES, service_flag_tests):55if self.options.v2transport:56services |= NODE_P2P_V257expected_result = "disconnect" if expect_disconnect else "connect"58self.log.info(f' - services 0x{services:08x}, type "{conn_type}" [{expected_result}]')59if expect_disconnect:60assert_not_equal((services & desirable_service_flags), desirable_service_flags)61expected_debug_log = f'does not offer the expected services ' \62f'({services:08x} offered, {desirable_service_flags:08x} expected)'63with node.assert_debug_log([expected_debug_log]):64self.add_outbound_connection(node, conn_type, services, wait_for_disconnect=True)65else:66assert_equal((services & desirable_service_flags), desirable_service_flags)67self.add_outbound_connection(node, conn_type, services, wait_for_disconnect=False)69def generate_at_mocktime(self, time):70self.nodes[0].setmocktime(time)71self.generate(self.nodes[0], 1)72self.nodes[0].setmocktime(0)74def run_test(self):75node = self.nodes[0]77self.log.info("Check that redundant verack message is ignored")78verack_conn = node.add_p2p_connection(P2PInterface())79with node.assert_debug_log(["ignoring redundant verack message"]):80verack_conn.send_and_ping(msg_verack())81node.disconnect_p2ps()83self.log.info("Check that lacking desired service flags leads to disconnect (non-pruned peers)")84self.test_desirable_service_flags(node, [NODE_NONE, NODE_NETWORK, NODE_WITNESS],85DESIRABLE_SERVICE_FLAGS_FULL, expect_disconnect=True)86self.test_desirable_service_flags(node, [NODE_NETWORK | NODE_WITNESS],87DESIRABLE_SERVICE_FLAGS_FULL, expect_disconnect=False)89self.log.info("Check that limited peers are only desired if the local chain is close to the tip (<24h)")90self.generate_at_mocktime(int(time.time()) - 25 * 3600) # tip outside the 24h window, should fail91self.test_desirable_service_flags(node, [NODE_NETWORK_LIMITED | NODE_WITNESS],92DESIRABLE_SERVICE_FLAGS_FULL, expect_disconnect=True)93self.generate_at_mocktime(int(time.time()) - 23 * 3600) # tip inside the 24h window, should succeed94self.test_desirable_service_flags(node, [NODE_NETWORK_LIMITED | NODE_WITNESS],95DESIRABLE_SERVICE_FLAGS_PRUNED, expect_disconnect=False)97self.log.info("Check that feeler connections get disconnected immediately")98with node.assert_debug_log(["feeler connection completed"]):99self.add_outbound_connection(node, "feeler", NODE_NONE, wait_for_disconnect=True)101self.log.info("Check that connecting to ourself leads to immediate disconnect")102with node.assert_debug_log(["connected to self", "disconnecting"]):103node_listen_addr = f"127.0.0.1:{p2p_port(0)}"104node.addconnection(node_listen_addr, "outbound-full-relay", self.options.v2transport)105self.wait_until(lambda: len(node.getpeerinfo()) == 0)108if __name__ == '__main__':109P2PHandshakeTest(__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.