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.
502BOOST_AUTO_TEST_CASE(getaddr_unfiltered)503{504auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));506// Set time on this addr so isTerrible = false507CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);508addr1.nTime = Now<NodeSeconds>();509// Not setting time so this addr should be isTerrible = true510CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);512CNetAddr source = ResolveIP("250.1.2.1");513BOOST_CHECK(addrman->Add({addr1, addr2}, source));515// Set time on this addr so isTerrible = false516CAddress addr3 = CAddress(ResolveService("250.251.2.3", 9998), NODE_NONE);517addr3.nTime = Now<NodeSeconds>();518addrman->Good(addr3, /*time=*/Now<NodeSeconds>());519BOOST_CHECK(addrman->Add({addr3}, source));520// The time is set, but after ADDRMAN_RETRIES unsuccessful attempts not521// retried in the last minute, this addr should be isTerrible = true522for (size_t i = 0; i < 3; ++i) {523addrman->Attempt(addr3, /*fCountFailure=*/true, /*time=*/Now<NodeSeconds>() - 61s);524}526// Set time more than 10 minutes in the future (flying DeLorean), so this527// addr should be isTerrible = true528CAddress addr4 = CAddress(ResolveService("250.252.2.4", 9997), NODE_NONE);529addr4.nTime = Now<NodeSeconds>() + 11min;530BOOST_CHECK(addrman->Add({addr4}, source));532// GetAddr filtered by quality (i.e. not IsTerrible) should only return addr1533BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);534// Unfiltered GetAddr should return all addrs535BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 4U);536}538BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)539{540CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);541CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);543CNetAddr source1 = ResolveIP("250.1.1.1");546AddrInfo info1 = AddrInfo(addr1, source1);548uint256 nKey1 = (HashWriter{} << 1).GetHash();549uint256 nKey2 = (HashWriter{} << 2).GetHash();551BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN), 40);553// Test: Make sure key actually randomizes bucket placement. A fail on554// this test could be a security issue.555BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetTriedBucket(nKey2, EMPTY_NETGROUPMAN));557// Test: Two addresses with same IP but different ports can map to558// different buckets because they have different keys.559AddrInfo info2 = AddrInfo(addr2, source1);561BOOST_CHECK(info1.GetKey() != info2.GetKey());562BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));564std::set<int> buckets;565for (int i = 0; i < 255; i++) {566AddrInfo infoi = AddrInfo(567CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),568ResolveIP("250.1.1." + ToString(i)));569int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);570buckets.insert(bucket);571}572// Test: IP addresses in the same /16 prefix should573// never get more than 8 buckets with legacy grouping574BOOST_CHECK_EQUAL(buckets.size(), 8U);576buckets.clear();577for (int j = 0; j < 255; j++) {578AddrInfo infoj = AddrInfo(579CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),580ResolveIP("250." + ToString(j) + ".1.1"));581int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);582buckets.insert(bucket);583}584// Test: IP addresses in the different /16 prefix should map to more than585// 8 buckets with legacy grouping586BOOST_CHECK_EQUAL(buckets.size(), 160U);587}589BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)590{591CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);592CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);594CNetAddr source1 = ResolveIP("250.1.2.1");596AddrInfo info1 = AddrInfo(addr1, source1);598uint256 nKey1 = (HashWriter{} << 1).GetHash();599uint256 nKey2 = (HashWriter{} << 2).GetHash();601// Test: Make sure the buckets are what we expect602BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), 786);603BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);605// Test: Make sure key actually randomizes bucket placement. A fail on606// this test could be a security issue.607BOOST_CHECK(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetNewBucket(nKey2, EMPTY_NETGROUPMAN));609// Test: Ports should not affect bucket placement in the addr610AddrInfo info2 = AddrInfo(addr2, source1);611BOOST_CHECK(info1.GetKey() != info2.GetKey());612BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));614std::set<int> buckets;615for (int i = 0; i < 255; i++) {616AddrInfo infoi = AddrInfo(617CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),618ResolveIP("250.1.1." + ToString(i)));619int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);620buckets.insert(bucket);621}622// Test: IP addresses in the same group (\16 prefix for IPv4) should623// always map to the same bucket.624BOOST_CHECK_EQUAL(buckets.size(), 1U);626buckets.clear();627for (int j = 0; j < 4 * 255; j++) {628AddrInfo infoj = AddrInfo(CAddress(629ResolveService(630ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),631ResolveIP("251.4.1.1"));632int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);633buckets.insert(bucket);634}635// Test: IP addresses in the same source groups should map to NO MORE636// than 64 buckets.637BOOST_CHECK(buckets.size() <= 64);639buckets.clear();640for (int p = 0; p < 255; p++) {641AddrInfo infoj = AddrInfo(642CAddress(ResolveService("250.1.1.1"), NODE_NONE),643ResolveIP("250." + ToString(p) + ".1.1"));644int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);645buckets.insert(bucket);646}647// Test: IP addresses in the different source groups should map to MORE648// than 64 buckets.649BOOST_CHECK(buckets.size() > 64);650}652// The following three test cases use asmap.raw653// We use an artificial minimal mock mapping654// 250.0.0.0/8 AS1000655// 101.1.0.0/16 AS1656// 101.2.0.0/16 AS2657// 101.3.0.0/16 AS3658// 101.4.0.0/16 AS4659// 101.5.0.0/16 AS5660// 101.6.0.0/16 AS6661// 101.7.0.0/16 AS7662// 101.8.0.0/16 AS8663BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)664{665auto ngm_asmap{NetGroupManager::WithEmbeddedAsmap(test::data::asmap)};667CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);668CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);670CNetAddr source1 = ResolveIP("250.1.1.1");673AddrInfo info1 = AddrInfo(addr1, source1);675uint256 nKey1 = (HashWriter{} << 1).GetHash();676uint256 nKey2 = (HashWriter{} << 2).GetHash();678BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);680// Test: Make sure key actually randomizes bucket placement. A fail on681// this test could be a security issue.682BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));684// Test: Two addresses with same IP but different ports can map to685// different buckets because they have different keys.686AddrInfo info2 = AddrInfo(addr2, source1);688BOOST_CHECK(info1.GetKey() != info2.GetKey());689BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));691std::set<int> buckets;692for (int j = 0; j < 255; j++) {693AddrInfo infoj = AddrInfo(694CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),695ResolveIP("101." + ToString(j) + ".1.1"));696int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);697buckets.insert(bucket);698}699// Test: IP addresses in the different /16 prefix MAY map to more than700// 8 buckets.701BOOST_CHECK(buckets.size() > 8);703buckets.clear();704for (int j = 0; j < 255; j++) {705AddrInfo infoj = AddrInfo(706CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),707ResolveIP("250." + ToString(j) + ".1.1"));708int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);709buckets.insert(bucket);710}711// Test: IP addresses in the different /16 prefix MAY NOT map to more than712// 8 buckets.713BOOST_CHECK(buckets.size() == 8);714}716BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)717{718auto ngm_asmap{NetGroupManager::WithEmbeddedAsmap(test::data::asmap)};720CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);721CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);723CNetAddr source1 = ResolveIP("250.1.2.1");725AddrInfo info1 = AddrInfo(addr1, source1);727uint256 nKey1 = (HashWriter{} << 1).GetHash();728uint256 nKey2 = (HashWriter{} << 2).GetHash();730// Test: Make sure the buckets are what we expect731BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);732BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);734// Test: Make sure key actually randomizes bucket placement. A fail on735// this test could be a security issue.736BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));738// Test: Ports should not affect bucket placement in the addr739AddrInfo info2 = AddrInfo(addr2, source1);740BOOST_CHECK(info1.GetKey() != info2.GetKey());741BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));743std::set<int> buckets;744for (int i = 0; i < 255; i++) {745AddrInfo infoi = AddrInfo(746CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),747ResolveIP("250.1.1." + ToString(i)));748int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);749buckets.insert(bucket);750}
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.