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) 2019-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.6""" Test node eviction logic8When the number of peers has reached the limit of maximum connections,9the next connecting inbound peer will trigger the eviction mechanism.10We cannot currently test the parts of the eviction logic that are based on11address/netgroup since in the current framework, all peers are connecting from12the same local address. See Issue #14210 for more info.13Therefore, this test is limited to the remaining protection criteria.14"""15import time17from test_framework.blocktools import (18create_block,19)20from test_framework.messages import (21msg_pong,22msg_tx,23)24from test_framework.p2p import (25P2PDataStore,26P2PInterface,27)28from test_framework.test_framework import BitcoinTestFramework29from test_framework.util import assert_equal30from test_framework.wallet import MiniWallet33class SlowP2PDataStore(P2PDataStore):34def on_ping(self, message):35time.sleep(0.1)36self.send_without_ping(msg_pong(message.nonce))39class SlowP2PInterface(P2PInterface):40def on_ping(self, message):41time.sleep(0.1)42self.send_without_ping(msg_pong(message.nonce))45class P2PEvict(BitcoinTestFramework):46def set_test_params(self):47self.num_nodes = 148# The choice of maxconnections=53 results in a maximum of 21 tx-relaying inbound connections49# (53 - 10 outbound - 1 feeler) * 0.5 = 21. The other inbound slots are reserved for block-relay-only50# peers that don't play a role in this test.51# 20 inbound peers are protected from eviction:52# 4 by netgroup, 4 that sent us blocks, 4 that sent us transactions and 8 via lowest ping time53self.extra_args = [['-maxconnections=53']]55def run_test(self):56protected_peers = set() # peers that we expect to be protected from eviction57current_peer = -158node = self.nodes[0]59self.wallet = MiniWallet(node)61self.log.info("Create 4 peers and protect them from eviction by sending us a block")62for _ in range(4):63block_peer = node.add_p2p_connection(SlowP2PDataStore())64current_peer += 165block_peer.sync_with_ping()66best_block = node.getbestblockhash()67tip = int(best_block, 16)68best_block_time = node.getblock(best_block)['time']69block = create_block(tip, height=node.getblockcount() + 1, ntime=best_block_time + 1)70block.solve()71block_peer.send_blocks_and_test([block], node, success=True)72protected_peers.add(current_peer)74self.log.info("Create 5 slow-pinging peers, making them eviction candidates")75for _ in range(5):76node.add_p2p_connection(SlowP2PInterface())77current_peer += 179self.log.info("Create 4 peers and protect them from eviction by sending us a tx")80for i in range(4):81txpeer = node.add_p2p_connection(SlowP2PInterface())82current_peer += 183txpeer.sync_with_ping()85tx = self.wallet.create_self_transfer()['tx']86txpeer.send_without_ping(msg_tx(tx))87protected_peers.add(current_peer)89self.log.info("Create 8 peers and protect them from eviction by having faster pings")90for _ in range(8):91fastpeer = node.add_p2p_connection(P2PInterface())92current_peer += 193self.wait_until(lambda: "ping" in fastpeer.last_message, timeout=10)95# Make sure by asking the node what the actual min pings are96peerinfo = node.getpeerinfo()97pings = {}98for i in range(len(peerinfo)):99pings[i] = peerinfo[i]['minping'] if 'minping' in peerinfo[i] else 1000000100sorted_pings = sorted(pings.items(), key=lambda x: x[1])102# Usually the 8 fast peers are protected. In rare case of unreliable pings,103# one of the slower peers might have a faster min ping though.104for i in range(8):105protected_peers.add(sorted_pings[i][0])107self.log.info("Create peer that triggers the eviction mechanism")108node.add_p2p_connection(SlowP2PInterface())110# One of the non-protected peers must be evicted. We can't be sure which one because111# 4 peers are protected via netgroup, which is identical for all peers,112# and the eviction mechanism doesn't preserve the order of identical elements.113evicted_peers = []114for i in range(len(node.p2ps)):115if not node.p2ps[i].is_connected:116evicted_peers.append(i)118self.log.info("Test that one peer was evicted")119self.log.debug("{} evicted peer: {}".format(len(evicted_peers), set(evicted_peers)))120assert_equal(len(evicted_peers), 1)122self.log.info("Test that no peer expected to be protected was evicted")123self.log.debug("{} protected peers: {}".format(len(protected_peers), protected_peers))124assert evicted_peers[0] not in protected_peers127if __name__ == '__main__':128P2PEvict(__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.