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// Copyright (c) 2012-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <addrdb.h>6#include <addrman.h>7#include <addrman_impl.h>8#include <chainparams.h>9#include <clientversion.h>10#include <hash.h>11#include <netbase.h>12#include <netgroup.h>13#include <random.h>14#include <test/data/asmap.raw.h>15#include <test/util/common.h>16#include <test/util/setup_common.h>17#include <test/util/time.h>18#include <util/asmap.h>19#include <util/string.h>21#include <boost/test/unit_test.hpp>23#include <cstdint>24#include <optional>25#include <string>27using namespace std::literals;28using node::NodeContext;29using util::ToString;31static auto EMPTY_NETGROUPMAN{NetGroupManager::NoAsmap()};32static const bool DETERMINISTIC{true};34static int32_t GetCheckRatio(const NodeContext& node_ctx)35{36return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);37}39static CNetAddr ResolveIP(const std::string& ip)40{41const std::optional<CNetAddr> addr{LookupHost(ip, false)};42BOOST_CHECK_MESSAGE(addr.has_value(), strprintf("failed to resolve: %s", ip));43return addr.value_or(CNetAddr{});44}46static CService ResolveService(const std::string& ip, uint16_t port = 0)47{48const std::optional<CService> serv{Lookup(ip, port, false)};49BOOST_CHECK_MESSAGE(serv.has_value(), strprintf("failed to resolve: %s:%i", ip, port));50return serv.value_or(CService{});51}53BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)55BOOST_AUTO_TEST_CASE(addrman_simple)56{57auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));59CNetAddr source = ResolveIP("252.2.2.2");61// Test: Does Addrman respond correctly when empty.62BOOST_CHECK_EQUAL(addrman->Size(), 0U);63auto addr_null = addrman->Select().first;64BOOST_CHECK_EQUAL(addr_null.ToStringAddrPort(), "[::]:0");66// Test: Does Addrman::Add work as expected.67CService addr1 = ResolveService("250.1.1.1", 8333);68BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));69BOOST_CHECK_EQUAL(addrman->Size(), 1U);70auto addr_ret1 = addrman->Select().first;71BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");73// Test: Does IP address deduplication work correctly.74// Expected dup IP should not be added.75CService addr1_dup = ResolveService("250.1.1.1", 8333);76BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));77BOOST_CHECK_EQUAL(addrman->Size(), 1U);80// Test: New table has one addr and we add a diff addr we should81// have at least one addr.82// Note that addrman's size cannot be tested reliably after insertion, as83// hash collisions may occur. But we can always be sure of at least one84// success.86CService addr2 = ResolveService("250.1.1.2", 8333);87BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));88BOOST_CHECK(addrman->Size() >= 1);90// Test: reset addrman and test AddrMan::Add multiple addresses works as expected91addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));92std::vector<CAddress> vAddr;93vAddr.emplace_back(ResolveService("250.1.1.3", 8333), NODE_NONE);94vAddr.emplace_back(ResolveService("250.1.1.4", 8333), NODE_NONE);95BOOST_CHECK(addrman->Add(vAddr, source));96BOOST_CHECK(addrman->Size() >= 1);97}100BOOST_AUTO_TEST_CASE(addrman_terrible_many_failures)101{102FakeNodeClock clock{};104auto addrman{std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node))};106CNetAddr source{ResolveIP("250.1.2.1")};107CAddress addr{CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE)};108addr.nTime = Now<NodeSeconds>();110BOOST_CHECK(addrman->Add({addr}, source));111BOOST_CHECK(addrman->Good(addr));113clock += ADDRMAN_MIN_FAIL + 24h;115CAddress addr_helper{CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE)};116addr_helper.nTime = Now<NodeSeconds>();117BOOST_CHECK(addrman->Add({addr_helper}, source));118BOOST_CHECK(addrman->Good(addr_helper));120for (int i = 0; i < ADDRMAN_MAX_FAILURES; ++i) {121// Use a time > 60s ago so IsTerrible doesn't bail out at the "tried in the last minute" check122addrman->Attempt(addr, /*fCountFailure=*/true, Now<NodeSeconds>() - 61s);123}125std::vector<CAddress> filtered{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};126BOOST_CHECK_EQUAL(filtered.size(), 1U);127BOOST_CHECK_EQUAL(filtered[0].ToStringAddrPort(), "251.252.2.3:8333");129std::vector<CAddress> unfiltered{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false)};130BOOST_CHECK_EQUAL(unfiltered.size(), 2U);131}134BOOST_AUTO_TEST_CASE(addrman_penalty_self_announcement)135{136FakeNodeClock clock{};137auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));139const auto base_time{Now<NodeSeconds>() - 10000s};140CService addr1 = ResolveService("250.1.1.1", 8333);141CNetAddr source1 = ResolveIP("250.1.1.1"); // Same as addr1 - self announcement143CAddress caddr1(addr1, NODE_NONE);144caddr1.nTime = base_time;146const auto time_penalty{3600s};148BOOST_CHECK(addrman->Add({caddr1}, source1, time_penalty));150auto addr_pos1{addrman->FindAddressEntry(caddr1)};151BOOST_REQUIRE(addr_pos1.has_value());153std::vector<CAddress> addresses{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};154BOOST_REQUIRE_EQUAL(addresses.size(), 1U);156BOOST_CHECK(addresses[0].nTime == base_time);158CService addr2{ResolveService("250.1.1.2", 8333)};159CNetAddr source2{ResolveIP("250.1.1.3")}; // Different from addr2 - not self announcement161CAddress caddr2(addr2, NODE_NONE);162caddr2.nTime = base_time;164BOOST_CHECK(addrman->Add({caddr2}, source2, time_penalty));166addresses = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);167BOOST_REQUIRE_EQUAL(addresses.size(), 2U);169CAddress retrieved_addr2{addresses[0]};170BOOST_CHECK(retrieved_addr2.nTime == base_time - time_penalty);171}173BOOST_AUTO_TEST_CASE(addrman_ports)174{175auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));177CNetAddr source = ResolveIP("252.2.2.2");179BOOST_CHECK_EQUAL(addrman->Size(), 0U);181// Test 7; Addr with same IP but diff port does not replace existing addr.182CService addr1 = ResolveService("250.1.1.1", 8333);183BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));184BOOST_CHECK_EQUAL(addrman->Size(), 1U);186CService addr1_port = ResolveService("250.1.1.1", 8334);187BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));188BOOST_CHECK_EQUAL(addrman->Size(), 2U);189auto addr_ret2 = addrman->Select().first;190BOOST_CHECK(addr_ret2.ToStringAddrPort() == "250.1.1.1:8333" || addr_ret2.ToStringAddrPort() == "250.1.1.1:8334");192// Test: Add same IP but diff port to tried table; this converts the entry with193// the specified port to tried, but not the other.194addrman->Good(CAddress(addr1_port, NODE_NONE));195BOOST_CHECK_EQUAL(addrman->Size(), 2U);196bool new_only = true;197auto addr_ret3 = addrman->Select(new_only).first;198BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");199}201BOOST_AUTO_TEST_CASE(addrman_select)202{203auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));204BOOST_CHECK(!addrman->Select(false).first.IsValid());205BOOST_CHECK(!addrman->Select(true).first.IsValid());207CNetAddr source = ResolveIP("252.2.2.2");209// Add 1 address to the new table210CService addr1 = ResolveService("250.1.1.1", 8333);211BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));212BOOST_CHECK_EQUAL(addrman->Size(), 1U);214BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr1);215BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);217// Move address to the tried table218BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));220BOOST_CHECK_EQUAL(addrman->Size(), 1U);221BOOST_CHECK(!addrman->Select(/*new_only=*/true).first.IsValid());222BOOST_CHECK(addrman->Select().first == addr1);223BOOST_CHECK_EQUAL(addrman->Size(), 1U);225// Add one address to the new table226CService addr2 = ResolveService("250.3.1.1", 8333);227BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, addr2));228BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr2);230// Add two more addresses to the new table231CService addr3 = ResolveService("250.3.2.2", 9999);232CService addr4 = ResolveService("250.3.3.3", 9999);234BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, addr2));235BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));237// Add three addresses to tried table.238CService addr5 = ResolveService("250.4.4.4", 8333);239CService addr6 = ResolveService("250.4.5.5", 7777);240CService addr7 = ResolveService("250.4.6.6", 8333);242BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, addr3));243BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));244BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, addr3));245BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE)));246BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));247BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));249// 6 addrs + 1 addr from last test = 7.250BOOST_CHECK_EQUAL(addrman->Size(), 7U);
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.