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) 2020-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 add_outbound_p2p_connection test framework functionality"""7from test_framework.p2p import P2PInterface8from test_framework.test_framework import BitcoinTestFramework9from test_framework.util import (10assert_equal,11check_node_connections,12)15class VersionSender(P2PInterface):16def on_open(self):17assert self.on_connection_send_msg is not None18self.send_version()19assert self.on_connection_send_msg is None22class P2PFeelerReceiver(P2PInterface):23def on_version(self, message):24# The bitcoind node closes feeler connections as soon as a version25# message is received from the test framework. Don't send any responses26# to the node's version message since the connection will already be27# closed.28self.send_version()30class P2PAddConnections(BitcoinTestFramework):31def set_test_params(self):32self.num_nodes = 234def setup_network(self):35self.setup_nodes()36# Don't connect the nodes38def run_test(self):39self.log.info("Add 8 outbounds to node 0")40for i in range(8):41self.log.info(f"outbound: {i}")42self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="outbound-full-relay")44self.log.info("Add 2 block-relay-only connections to node 0")45for i in range(2):46self.log.info(f"block-relay-only: {i}")47# set p2p_idx based on the outbound connections already open to the48# node, so add 8 to account for the previous full-relay connections49self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")51self.log.info("Add 2 block-relay-only connections to node 1")52for i in range(2):53self.log.info(f"block-relay-only: {i}")54self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="block-relay-only")56self.log.info("Add 5 inbound connections to node 1")57for i in range(5):58self.log.info(f"inbound: {i}")59self.nodes[1].add_p2p_connection(P2PInterface())61self.log.info("Add 8 outbounds to node 1")62for i in range(8):63self.log.info(f"outbound: {i}")64# bump p2p_idx to account for the 2 existing outbounds on node 165self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 2)67self.log.info("Check the connections opened as expected")68check_node_connections(node=self.nodes[0], num_in=0, num_out=10)69check_node_connections(node=self.nodes[1], num_in=5, num_out=10)71self.log.info("Disconnect p2p connections & try to re-open")72self.nodes[0].disconnect_p2ps()73check_node_connections(node=self.nodes[0], num_in=0, num_out=0)75self.log.info("Add 8 outbounds to node 0")76for i in range(8):77self.log.info(f"outbound: {i}")78self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)79check_node_connections(node=self.nodes[0], num_in=0, num_out=8)81self.log.info("Add 2 block-relay-only connections to node 0")82for i in range(2):83self.log.info(f"block-relay-only: {i}")84# bump p2p_idx to account for the 8 existing outbounds on node 085self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")86check_node_connections(node=self.nodes[0], num_in=0, num_out=10)88self.log.info("Restart node 0 and try to reconnect to p2ps")89self.restart_node(0)91self.log.info("Add 4 outbounds to node 0")92for i in range(4):93self.log.info(f"outbound: {i}")94self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)95check_node_connections(node=self.nodes[0], num_in=0, num_out=4)97self.log.info("Add 2 block-relay-only connections to node 0")98for i in range(2):99self.log.info(f"block-relay-only: {i}")100# bump p2p_idx to account for the 4 existing outbounds on node 0101self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 4, connection_type="block-relay-only")102check_node_connections(node=self.nodes[0], num_in=0, num_out=6)104check_node_connections(node=self.nodes[1], num_in=5, num_out=10)106self.log.info("Add 1 feeler connection to node 0")107feeler_conn = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=6, connection_type="feeler")109# Feeler connection is closed110assert not feeler_conn.is_connected112# Verify version message received113assert_equal(feeler_conn.message_count["version"], 1)114# Feeler connections do not request tx relay115assert_equal(feeler_conn.last_message["version"].relay, 0)117self.log.info("Send version message early to node")118# Normally the test framework would be shy and send the version message119# only after it received one. See the on_version method. Check that120# bitcoind behaves properly when a version is sent unexpectedly (but121# tolerably) early.122#123# This checks that bitcoind sends its own version prior to processing124# the remote version (and replying with a verack). Otherwise it would125# be violating its own rules, such as "non-version message before126# version handshake".127ver_conn = self.nodes[0].add_outbound_p2p_connection(VersionSender(), p2p_idx=6, connection_type="outbound-full-relay", supports_v2_p2p=False, advertise_v2_p2p=False)128ver_conn.sync_with_ping()131if __name__ == '__main__':132P2PAddConnections(__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.