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.
501}502},503/*protected_peer_ids=*/{0, 1, 6},504/*unprotected_peer_ids=*/{2, 3, 4, 5},505random_context));507// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer508// out of 8 to protect 1 CJDNS, 1 I2P, 0 localhost, 0 onion and 2 other509// peers (4 total) sorted by longest uptime; stable sort breaks tie with510// array order of CJDNS first.511BOOST_CHECK(IsProtected(5128, [](NodeEvictionCandidate& c) {513c.m_connected = NodeSeconds{std::chrono::seconds{c.id}};514c.m_is_local = (c.id == 3);515if (c.id == 5) {516c.m_network = NET_CJDNS;517} else if (c.id == 6) {518c.m_network = NET_I2P;519} else if (c.id == 3) {520c.m_network = NET_ONION;521} else {522c.m_network = NET_IPV6;523}524},525/*protected_peer_ids=*/{0, 1, 5, 6},526/*unprotected_peer_ids=*/{2, 3, 4, 7},527random_context));529// Combined test: expect having 2 CJDNS, 2 I2P, 4 localhost, and 2 onion530// peers out of 16 to protect 1 CJDNS, 1 I2P, 1 localhost, 1 onion (4/16531// total), plus 4 others for 8 total, sorted by longest uptime.532BOOST_CHECK(IsProtected(53316, [](NodeEvictionCandidate& c) {534c.m_connected = NodeSeconds{std::chrono::seconds{c.id}};535c.m_is_local = (c.id > 5);536if (c.id == 11 || c.id == 15) {537c.m_network = NET_CJDNS;538} else if (c.id == 10 || c.id == 14) {539c.m_network = NET_I2P;540} else if (c.id == 8 || c.id == 9) {541c.m_network = NET_ONION;542} else {543c.m_network = NET_IPV4;544}545},546/*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 10, 11},547/*unprotected_peer_ids=*/{4, 5, 7, 9, 12, 13, 14, 15},548random_context));550// Combined test: expect having 6 CJDNS, 1 I2P, 1 localhost, and 4 onion551// peers out of 24 to protect 2 CJDNS, 1 I2P, 1 localhost, and 2 onions (6552// total), plus 6 others for 12/24 total, sorted by longest uptime.553BOOST_CHECK(IsProtected(55424, [](NodeEvictionCandidate& c) {555c.m_connected = NodeSeconds{std::chrono::seconds{c.id}};556c.m_is_local = (c.id == 13);557if (c.id > 17) {558c.m_network = NET_CJDNS;559} else if (c.id == 17) {560c.m_network = NET_I2P;561} else if (c.id == 12 || c.id == 14 || c.id == 15 || c.id == 16) {562c.m_network = NET_ONION;563} else {564c.m_network = NET_IPV6;565}566},567/*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19},568/*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23},569random_context));570}572// Returns true if any of the node ids in node_ids are selected for eviction.573bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::unordered_set<NodeId>& node_ids, FastRandomContext& random_context)574{575std::shuffle(candidates.begin(), candidates.end(), random_context);576const std::optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));577if (!evicted_node_id) {578return false;579}580return node_ids.contains(*evicted_node_id);581}583// Create number_of_nodes random nodes, apply setup function candidate_setup_fn,584// apply eviction logic and then return true if any of the node ids in node_ids585// are selected for eviction.586bool IsEvicted(const int number_of_nodes, std::function<void(NodeEvictionCandidate&)> candidate_setup_fn, const std::unordered_set<NodeId>& node_ids, FastRandomContext& random_context)587{588std::vector<NodeEvictionCandidate> candidates = GetRandomNodeEvictionCandidates(number_of_nodes, random_context);589for (NodeEvictionCandidate& candidate : candidates) {590candidate_setup_fn(candidate);591}592return IsEvicted(candidates, node_ids, random_context);593}595BOOST_AUTO_TEST_CASE(peer_eviction_test)596{597FastRandomContext random_context{true};599for (int number_of_nodes = 0; number_of_nodes < 200; ++number_of_nodes) {600// Four nodes with the highest keyed netgroup values should be601// protected from eviction.602BOOST_CHECK(!IsEvicted(603number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {604candidate.nKeyedNetGroup = number_of_nodes - candidate.id;605},606{0, 1, 2, 3}, random_context));608// Eight nodes with the lowest minimum ping time should be protected609// from eviction.610BOOST_CHECK(!IsEvicted(611number_of_nodes, [](NodeEvictionCandidate& candidate) {612candidate.m_min_ping_time = std::chrono::microseconds{candidate.id};613},614{0, 1, 2, 3, 4, 5, 6, 7}, random_context));616// Four nodes that most recently sent us novel transactions accepted617// into our mempool should be protected from eviction.618BOOST_CHECK(!IsEvicted(619number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {620candidate.m_last_tx_time = std::chrono::seconds{number_of_nodes - candidate.id};621},622{0, 1, 2, 3}, random_context));624// Up to eight non-tx-relay peers that most recently sent us novel625// blocks should be protected from eviction.626BOOST_CHECK(!IsEvicted(627number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {628candidate.m_last_block_time = std::chrono::seconds{number_of_nodes - candidate.id};629if (candidate.id <= 7) {630candidate.m_relay_txs = false;631candidate.fRelevantServices = true;632}633},634{0, 1, 2, 3, 4, 5, 6, 7}, random_context));636// Four peers that most recently sent us novel blocks should be637// protected from eviction.638BOOST_CHECK(!IsEvicted(639number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {640candidate.m_last_block_time = std::chrono::seconds{number_of_nodes - candidate.id};641},642{0, 1, 2, 3}, random_context));644// Combination of the previous two tests.645BOOST_CHECK(!IsEvicted(646number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {647candidate.m_last_block_time = std::chrono::seconds{number_of_nodes - candidate.id};648if (candidate.id <= 7) {649candidate.m_relay_txs = false;650candidate.fRelevantServices = true;651}652},653{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, random_context));655// Combination of all tests above.656BOOST_CHECK(!IsEvicted(657number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {658candidate.nKeyedNetGroup = number_of_nodes - candidate.id; // 4 protected659candidate.m_min_ping_time = std::chrono::microseconds{candidate.id}; // 8 protected660candidate.m_last_tx_time = std::chrono::seconds{number_of_nodes - candidate.id}; // 4 protected661candidate.m_last_block_time = std::chrono::seconds{number_of_nodes - candidate.id}; // 4 protected662},663{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, random_context));665// An eviction is expected given >= 29 random eviction candidates. The eviction logic protects at most666// four peers by net group, eight by lowest ping time, four by last time of novel tx, up to eight non-tx-relay667// peers by last novel block time, and four more peers by last novel block time.668if (number_of_nodes >= 29) {669BOOST_CHECK(SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));670}672// No eviction is expected given <= 20 random eviction candidates. The eviction logic protects at least673// four peers by net group, eight by lowest ping time, four by last time of novel tx and four peers by last674// novel block time.675if (number_of_nodes <= 20) {676BOOST_CHECK(!SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));677}679// Cases left to test:680// * "If any remaining peers are preferred for eviction consider only them. [...]"681// * "Identify the network group with the most connections and youngest member. [...]"682}683}685BOOST_AUTO_TEST_SUITE_END()
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.