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 <addrdb.h>6#include <addrman.h>7#include <addrman_impl.h>8#include <chainparams.h>9#include <common/args.h>10#include <merkleblock.h>11#include <random.h>12#include <test/fuzz/FuzzedDataProvider.h>13#include <test/fuzz/fuzz.h>14#include <test/fuzz/util.h>15#include <test/fuzz/util/net.h>16#include <test/util/setup_common.h>17#include <test/util/time.h>18#include <util/asmap.h>19#include <util/chaintype.h>21#include <cassert>22#include <cstdint>23#include <ctime>24#include <optional>25#include <string>26#include <vector>28namespace {29const BasicTestingSetup* g_setup;31int32_t GetCheckRatio()32{33return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000);34}35} // namespace37void initialize_addrman()38{39static const auto testing_setup = MakeNoLogFileContext<>(ChainType::REGTEST);40g_setup = testing_setup.get();41}43FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman)44{45SeedRandomStateForTest(SeedRand::ZEROS);46FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};47DataStream data_stream = ConsumeDataStream(fuzzed_data_provider);48NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};49AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());50try {51ReadFromStream(addr_man, data_stream);52} catch (const std::exception&) {53}54}56/**57* Generate a random address. Always returns a valid address.58*/59CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context)60{61CNetAddr addr;62assert(!addr.IsValid());63for (size_t i = 0; i < 8 && !addr.IsValid(); ++i) {64if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) {65addr = ConsumeNetAddr(fuzzed_data_provider);66} else {67addr = ConsumeNetAddr(fuzzed_data_provider, &fast_random_context);68}69}71// Return a dummy IPv4 5.5.5.5 if we generated an invalid address.72if (!addr.IsValid()) {73in_addr v4_addr = {};74v4_addr.s_addr = 0x05050505;75addr = CNetAddr{v4_addr};76}78return addr;79}81/** Fill addrman with lots of addresses from lots of sources. */82void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)83{84// Add a fraction of the addresses to the "tried" table.85// 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%86const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);88const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);89CNetAddr prev_source;90// Generate a FastRandomContext seed to use inside the loops instead of91// fuzzed_data_provider. When fuzzed_data_provider is exhausted it92// just returns 0.93FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};94for (size_t i = 0; i < num_sources; ++i) {95const auto source = RandAddr(fuzzed_data_provider, fast_random_context);96const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500]98for (size_t j = 0; j < num_addresses; ++j) {99const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};100const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};101addrman.Add({addr}, source, time_penalty);103if (n > 0 && addrman.Size() % n == 0) {104addrman.Good(addr, Now<NodeSeconds>());105}107// Add 10% of the addresses from more than one source.108if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) {109addrman.Add({addr}, prev_source, time_penalty);110}111}112prev_source = source;113}114}116FUZZ_TARGET(addrman, .init = initialize_addrman)117{118SeedRandomStateForTest(SeedRand::ZEROS);119FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());120FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)};121NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};122auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio());123if (fuzzed_data_provider.ConsumeBool()) {124const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};125DataStream ds{serialized_data};126try {127ds >> *addr_man_ptr;128} catch (const std::ios_base::failure&) {129addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio());130}131}132AddrManDeterministic& addr_man = *addr_man_ptr;133LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 10000) {134CallOneOf(135fuzzed_data_provider,136[&] {137addr_man.ResolveCollisions();138},139[&] {140(void)addr_man.SelectTriedCollision();141},142[&] {143std::vector<CAddress> addresses;144LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 10000) {145addresses.push_back(ConsumeAddress(fuzzed_data_provider));146}147auto net_addr = ConsumeNetAddr(fuzzed_data_provider);148auto time_penalty = ConsumeDuration<std::chrono::seconds>(fuzzed_data_provider, /*min=*/0s, /*max=*/100000000s);149addr_man.Add(addresses, net_addr, time_penalty);150},151[&] {152auto addr = ConsumeService(fuzzed_data_provider);153auto time = ConsumeTime(fuzzed_data_provider);154addr_man.Good(addr, time);155},156[&] {157auto addr = ConsumeService(fuzzed_data_provider);158auto count_failure = fuzzed_data_provider.ConsumeBool();159auto time = ConsumeTime(fuzzed_data_provider);160addr_man.Attempt(addr, count_failure, time);161},162[&] {163auto addr = ConsumeService(fuzzed_data_provider);164auto time = ConsumeTime(fuzzed_data_provider);165addr_man.Connected(addr, time);166},167[&] {168auto addr = ConsumeService(fuzzed_data_provider);169auto n_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);170addr_man.SetServices(addr, n_services);171});172}173const AddrMan& const_addr_man{addr_man};174std::optional<Network> network;175if (fuzzed_data_provider.ConsumeBool()) {176network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS);177}178auto max_addresses = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);179auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);180auto filtered = fuzzed_data_provider.ConsumeBool();181(void)const_addr_man.GetAddr(max_addresses, max_pct, network, filtered);183std::unordered_set<Network> nets;184for (const auto& net : ALL_NETWORKS) {185if (fuzzed_data_provider.ConsumeBool()) {186nets.insert(net);187}188}189(void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), nets);191std::optional<bool> in_new;192if (fuzzed_data_provider.ConsumeBool()) {193in_new = fuzzed_data_provider.ConsumeBool();194}195(void)const_addr_man.Size(network, in_new);196DataStream data_stream{};197data_stream << const_addr_man;198}200// Check that serialize followed by unserialize produces the same addrman.201FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)202{203SeedRandomStateForTest(SeedRand::ZEROS);204FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());205FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)};207NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};208AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider, GetCheckRatio()};209AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider, GetCheckRatio()};211DataStream data_stream{};213FillAddrman(addr_man1, fuzzed_data_provider);214data_stream << addr_man1;215data_stream >> addr_man2;216assert(addr_man1 == addr_man2);217}
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.