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) 2020-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 <addrman.h>6#include <bench/bench.h>7#include <compat/compat.h>8#include <netaddress.h>9#include <netbase.h>10#include <netgroup.h>11#include <protocol.h>12#include <random.h>13#include <uint256.h>14#include <util/check.h>15#include <util/time.h>17#include <cstring>18#include <optional>19#include <span>20#include <vector>22/* A "source" is a source address from which we have received a bunch of other addresses. */24static constexpr size_t NUM_SOURCES = 64;25static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;27static auto EMPTY_NETGROUPMAN{NetGroupManager::NoAsmap()};28static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};30static std::vector<CAddress> g_sources;31static std::vector<std::vector<CAddress>> g_addresses;33static void CreateAddresses()34{35if (g_sources.size() > 0) { // already created36return;37}39FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));41auto randAddr = [&rng]() {42in6_addr addr;43memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));45uint16_t port;46memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));47if (port == 0) {48port = 1;49}51CAddress ret(CService(addr, port), NODE_NETWORK);53ret.nTime = Now<NodeSeconds>();55return ret;56};58for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {59g_sources.emplace_back(randAddr());60g_addresses.emplace_back();61for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {62g_addresses[source_i].emplace_back(randAddr());63}64}65}67static void AddAddressesToAddrMan(AddrMan& addrman)68{69for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {70addrman.Add(g_addresses[source_i], g_sources[source_i]);71}72}74static void FillAddrMan(AddrMan& addrman)75{76CreateAddresses();78AddAddressesToAddrMan(addrman);79}81/* Benchmarks */83static void AddrManAdd(benchmark::Bench& bench)84{85CreateAddresses();87bench.run([&] {88AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};89AddAddressesToAddrMan(addrman);90});91}93static void AddrManSelect(benchmark::Bench& bench)94{95AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};97FillAddrMan(addrman);99bench.run([&] {100const auto& address = addrman.Select();101assert(address.first.GetPort() > 0);102});103}105// The worst case performance of the Select() function is when there is only106// one address on the table, because it linearly searches every position of107// several buckets before identifying the correct bucket108static void AddrManSelectFromAlmostEmpty(benchmark::Bench& bench)109{110AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};112// Add one address to the new table113CService addr = Lookup("250.3.1.1", 8333, false).value();114addrman.Add({CAddress(addr, NODE_NONE)}, addr);116bench.run([&] {117(void)addrman.Select();118});119}121static void AddrManSelectByNetwork(benchmark::Bench& bench)122{123AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};125// add single I2P address to new table126CService i2p_service;127i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");128CAddress i2p_address(i2p_service, NODE_NONE);129i2p_address.nTime = Now<NodeSeconds>();130const CNetAddr source{LookupHost("252.2.2.2", false).value()};131addrman.Add({i2p_address}, source);133FillAddrMan(addrman);135bench.run([&] {136(void)addrman.Select(/*new_only=*/false, {NET_I2P});137});138}140static void AddrManGetAddr(benchmark::Bench& bench)141{142AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};144FillAddrMan(addrman);146bench.run([&] {147const auto& addresses = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);148assert(addresses.size() > 0);149});150}152static void AddrManAddThenGood(benchmark::Bench& bench)153{154auto markSomeAsGood = [](AddrMan& addrman) {155for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {156for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {157addrman.Good(g_addresses[source_i][addr_i]);158}159}160};162CreateAddresses();164std::optional<AddrMan> addrman;165bench.setup([&] {166addrman.emplace(EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO);167AddAddressesToAddrMan(*addrman);168})169.run([&] { markSomeAsGood(*addrman); });170}172BENCHMARK(AddrManAdd);173BENCHMARK(AddrManSelect);174BENCHMARK(AddrManSelectFromAlmostEmpty);175BENCHMARK(AddrManSelectByNetwork);176BENCHMARK(AddrManGetAddr);177BENCHMARK(AddrManAddThenGood);
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.