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"""6Test addr relay7"""9import random10import time12from test_framework.messages import (13CAddress,14CBlockHeader,15msg_addr,16msg_getaddr,17msg_headers,18msg_verack,19from_hex,20)21from test_framework.p2p import (22P2PInterface,23p2p_lock,24P2P_SERVICES,25)26from test_framework.test_framework import BitcoinTestFramework27from test_framework.util import (28assert_equal,29assert_greater_than,30assert_greater_than_or_equal31)33ONE_MINUTE = 6034TEN_MINUTES = 10 * ONE_MINUTE35ONE_HOUR = 60 * ONE_MINUTE36TWO_HOURS = 2 * ONE_HOUR37ONE_DAY = 24 * ONE_HOUR39ADDR_DESTINATIONS_THRESHOLD = 441class AddrReceiver(P2PInterface):42num_ipv4_received = 043test_addr_contents = False44_tokens = 145send_getaddr = True47def __init__(self, test_addr_contents=False, send_getaddr=True):48super().__init__()49self.test_addr_contents = test_addr_contents50self.send_getaddr = send_getaddr52def on_addr(self, message):53for addr in message.addrs:54self.num_ipv4_received += 155if self.test_addr_contents:56# relay_tests checks the content of the addr messages match57# expectations based on the message creation in setup_addr_msg58assert_equal(addr.nServices, 9)59if not 8333 <= addr.port < 8343:60raise AssertionError("Invalid addr.port of {} (8333-8342 expected)".format(addr.port))61assert addr.ip.startswith('123.123.')63def on_getaddr(self, message):64# When the node sends us a getaddr, it increments the addr relay tokens for the connection by 100065self._tokens += 100067@property68def tokens(self):69with p2p_lock:70return self._tokens72def increment_tokens(self, n):73# When we move mocktime forward, the node increments the addr relay tokens for its peers74with p2p_lock:75self._tokens += n77def addr_received(self):78return self.num_ipv4_received != 080def on_version(self, message):81self.send_version()82self.send_without_ping(msg_verack())83if (self.send_getaddr):84self.send_without_ping(msg_getaddr())86def getaddr_received(self):87return self.message_count['getaddr'] > 090class AddrTest(BitcoinTestFramework):91counter = 092mocktime = int(time.time())94def set_test_params(self):95self.num_nodes = 196self.extra_args = [["[email protected]"]]98def run_test(self):99self.oversized_addr_test()100self.relay_tests()101self.inbound_blackhole_tests()103self.destination_rotates_once_in_24_hours_test()104self.destination_rotates_more_than_once_over_several_days_test()106# This test populates the addrman, which can impact the node's behavior107# in subsequent tests108self.getaddr_tests()109self.blocksonly_mode_tests()110self.rate_limit_tests()112def setup_addr_msg(self, num, sequential_ips=True):113addrs = []114for i in range(num):115addr = CAddress()116addr.time = self.mocktime + random.randrange(-100, 100)117addr.nServices = P2P_SERVICES118if sequential_ips:119assert self.counter < 256 ** 2 # Don't allow the returned ip addresses to wrap.120addr.ip = f"123.123.{self.counter // 256}.{self.counter % 256}"121self.counter += 1122else:123addr.ip = f"{random.randrange(128,169)}.{random.randrange(1,255)}.{random.randrange(1,255)}.{random.randrange(1,255)}"124addr.port = 8333 + i125addrs.append(addr)127msg = msg_addr()128msg.addrs = addrs129return msg131def send_addr_msg(self, source, msg, receivers):132source.send_and_ping(msg)133# invoke m_next_addr_send timer:134# `addr` messages are sent on an exponential distribution with mean interval of 30s.135# Setting the mocktime 600s forward gives a probability of (1 - e^-(600/30)) that136# the event will occur (i.e. this fails once in ~500 million repeats).137self.mocktime += 10 * 60138self.nodes[0].setmocktime(self.mocktime)139for peer in receivers:140peer.sync_with_ping()142def oversized_addr_test(self):143self.log.info('Send an addr message that is too large')144addr_source = self.nodes[0].add_p2p_connection(P2PInterface())146msg = self.setup_addr_msg(1010)147with self.nodes[0].assert_debug_log(['addr message size = 1010']):148addr_source.send_without_ping(msg)149addr_source.wait_for_disconnect()151self.nodes[0].disconnect_p2ps()153def relay_tests(self):154self.log.info('Test address relay')155self.log.info('Check that addr message content is relayed and added to addrman')156addr_source = self.nodes[0].add_p2p_connection(P2PInterface())157num_receivers = 7158receivers = []159for _ in range(num_receivers):160receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver(test_addr_contents=True)))162# Keep this with length <= 10. Addresses from larger messages are not163# relayed.164num_ipv4_addrs = 10165msg = self.setup_addr_msg(num_ipv4_addrs)166with self.nodes[0].assert_debug_log(167[168'received: addr (301 bytes) peer=1',169]170):171self.send_addr_msg(addr_source, msg, receivers)173total_ipv4_received = sum(r.num_ipv4_received for r in receivers)175# Every IPv4 address must be relayed to two peers, other than the176# originating node (addr_source).177ipv4_branching_factor = 2178assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor)180self.nodes[0].disconnect_p2ps()182self.log.info('Check relay of addresses received from outbound peers')183inbound_peer = self.nodes[0].add_p2p_connection(AddrReceiver(test_addr_contents=True, send_getaddr=False))184# Send an empty ADDR message to initialize address relay on this connection.185inbound_peer.send_and_ping(msg_addr())187full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(AddrReceiver(), p2p_idx=0, connection_type="outbound-full-relay")188msg = self.setup_addr_msg(2)189self.send_addr_msg(full_outbound_peer, msg, [inbound_peer])190self.log.info('Check that the first addr message received from an outbound peer is not relayed')191# Currently, there is a flag that prevents the first addr message received192# from a new outbound peer to be relayed to others. Originally meant to prevent193# large GETADDR responses from being relayed, it now typically affects the self-announcement194# of the outbound peer which is often sent before the GETADDR response.195assert_equal(inbound_peer.num_ipv4_received, 0)197self.log.info('Check that subsequent addr messages sent from an outbound peer are relayed')198msg2 = self.setup_addr_msg(2)199self.send_addr_msg(full_outbound_peer, msg2, [inbound_peer])200assert_equal(inbound_peer.num_ipv4_received, 2)202self.log.info('Check address relay to outbound peers')203block_relay_peer = self.nodes[0].add_outbound_p2p_connection(AddrReceiver(), p2p_idx=1, connection_type="block-relay-only")204msg3 = self.setup_addr_msg(2)205self.send_addr_msg(inbound_peer, msg3, [full_outbound_peer, block_relay_peer])207self.log.info('Check that addresses are relayed to full outbound peers')208assert_equal(full_outbound_peer.num_ipv4_received, 2)209self.log.info('Check that addresses are not relayed to block-relay-only outbound peers')210assert_equal(block_relay_peer.num_ipv4_received, 0)212self.nodes[0].disconnect_p2ps()214def sum_addr_messages(self, msgs_dict):215return sum(bytes_received for (msg, bytes_received) in msgs_dict.items() if msg in ['addr', 'addrv2', 'getaddr'])217def inbound_blackhole_tests(self):218self.log.info('Check that we only relay addresses to inbound peers who have previously sent us addr related messages')220addr_source = self.nodes[0].add_p2p_connection(P2PInterface())221receiver_peer = self.nodes[0].add_p2p_connection(AddrReceiver())222blackhole_peer = self.nodes[0].add_p2p_connection(AddrReceiver(send_getaddr=False))223initial_addrs_received = receiver_peer.num_ipv4_received225peerinfo = self.nodes[0].getpeerinfo()226assert_equal(peerinfo[0]['addr_relay_enabled'], True) # addr_source227assert_equal(peerinfo[1]['addr_relay_enabled'], True) # receiver_peer228assert_equal(peerinfo[2]['addr_relay_enabled'], False) # blackhole_peer230# addr_source sends 2 addresses to node0231msg = self.setup_addr_msg(2)232addr_source.send_and_ping(msg)233self.mocktime += 30 * 60234self.nodes[0].setmocktime(self.mocktime)235receiver_peer.sync_with_ping()236blackhole_peer.sync_with_ping()238peerinfo = self.nodes[0].getpeerinfo()240# Confirm node received addr-related messages from receiver peer241assert_greater_than(self.sum_addr_messages(peerinfo[1]['bytesrecv_per_msg']), 0)242# And that peer received addresses243assert_equal(receiver_peer.num_ipv4_received - initial_addrs_received, 2)245# Confirm node has not received addr-related messages from blackhole peer246assert_equal(self.sum_addr_messages(peerinfo[2]['bytesrecv_per_msg']), 0)247# And that peer did not receive addresses248assert_equal(blackhole_peer.num_ipv4_received, 0)250self.log.info("After blackhole peer sends addr message, it becomes eligible for addr gossip")
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.