Inside Bitcoin
Opening the selected file…
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 Pieter Wuille2// Copyright (c) 2012-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <bitcoin-build-config.h> // IWYU pragma: keep8#include <addrman.h>9#include <addrman_impl.h>11#include <hash.h>12#include <logging/timer.h>13#include <netaddress.h>14#include <netgroup.h>15#include <protocol.h>16#include <random.h>17#include <serialize.h>18#include <streams.h>19#include <tinyformat.h>20#include <uint256.h>21#include <util/check.h>22#include <util/log.h>23#include <util/time.h>25#include <cmath>26#include <optional>29int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const30{31uint64_t hash1 = (HashWriter{} << nKey << GetKey()).GetCheapHash();32uint64_t hash2 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();33return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;34}36int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const37{38std::vector<unsigned char> vchSourceGroupKey = netgroupman.GetGroup(src);39uint64_t hash1 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << vchSourceGroupKey).GetCheapHash();40uint64_t hash2 = (HashWriter{} << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();41return hash2 % ADDRMAN_NEW_BUCKET_COUNT;42}44int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int bucket) const45{46uint64_t hash1 = (HashWriter{} << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << bucket << GetKey()).GetCheapHash();47return hash1 % ADDRMAN_BUCKET_SIZE;48}50bool AddrInfo::IsTerrible(NodeSeconds now) const51{52if (now - m_last_try <= 1min) { // never remove things tried in the last minute53return false;54}56if (nTime > now + 10min) { // came in a flying DeLorean57return true;58}60if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history61return true;62}64if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success65return true;66}68if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week69return true;70}72return false;73}75double AddrInfo::GetChance(NodeSeconds now) const76{77double fChance = 1.0;79// deprioritize very recent attempts away80if (now - m_last_try < 10min) {81fChance *= 0.01;82}84// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.85fChance *= pow(0.66, std::min(nAttempts, 8));87return fChance;88}90AddrManImpl::AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)91: insecure_rand{deterministic}92, nKey{deterministic ? uint256{1} : insecure_rand.rand256()}93, m_consistency_check_ratio{consistency_check_ratio}94, m_netgroupman{netgroupman}95{96for (auto& bucket : vvNew) {97for (auto& entry : bucket) {98entry = -1;99}100}101for (auto& bucket : vvTried) {102for (auto& entry : bucket) {103entry = -1;104}105}106}108AddrManImpl::~AddrManImpl()109{110nKey.SetNull();111}113template <typename Stream>114void AddrManImpl::Serialize(Stream& s_) const115{116LOCK(cs);118/**119* Serialized format.120* * format version byte (@see `Format`)121* * lowest compatible format version byte. This is used to help old software decide122* whether to parse the file. For example:123* * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is124* introduced in version N+1 that is compatible with format=3 and it is known that125* version N will be able to parse it, then version N+1 will write126* (format=4, lowest_compatible=3) in the first two bytes of the file, and so127* version N will still try to parse it.128* * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write129* (format=5, lowest_compatible=5) and so any versions that do not know how to parse130* format=5 will not try to read the file.131* * nKey132* * nNew133* * nTried134* * number of "new" buckets XOR 2**30135* * all new addresses (total count: nNew)136* * all tried addresses (total count: nTried)137* * for each new bucket:138* * number of elements139* * for each element: index in the serialized "all new addresses"140* * asmap version141*142* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it143* as incompatible. This is necessary because it did not check the version number on144* deserialization.145*146* vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;147* they are instead reconstructed from the other information.148*149* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports150* changes to the ADDRMAN_ parameters without breaking the on-disk structure.151*152* We don't use SERIALIZE_METHODS since the serialization and deserialization code has153* very little in common.154*/156// Always serialize in the latest version (FILE_FORMAT).157ParamsStream s{s_, CAddress::V2_DISK};159s << static_cast<uint8_t>(FILE_FORMAT);161// Increment `lowest_compatible` iff a newly introduced format is incompatible with162// the previous one.163static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;164s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);166s << nKey;167s << nNew;168s << nTried;170int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);171s << nUBuckets;172std::unordered_map<nid_type, int> mapUnkIds;173int nIds = 0;174for (const auto& entry : mapInfo) {175mapUnkIds[entry.first] = nIds;176const AddrInfo& info = entry.second;177if (info.nRefCount) {178assert(nIds != nNew); // this means nNew was wrong, oh ow179s << info;180nIds++;181}182}183nIds = 0;184for (const auto& entry : mapInfo) {185const AddrInfo& info = entry.second;186if (info.fInTried) {187assert(nIds != nTried); // this means nTried was wrong, oh ow188s << info;189nIds++;190}191}192for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {193int nSize = 0;194for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {195if (vvNew[bucket][i] != -1)196nSize++;197}198s << nSize;199for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {200if (vvNew[bucket][i] != -1) {201int nIndex = mapUnkIds[vvNew[bucket][i]];202s << nIndex;203}204}205}206// Store asmap version after bucket entries so that it207// can be ignored by older clients for backward compatibility.208s << m_netgroupman.GetAsmapVersion();209}211template <typename Stream>212void AddrManImpl::Unserialize(Stream& s_)213{214LOCK(cs);216assert(vRandom.empty());218Format format;219s_ >> Using<CustomUintFormatter<1>>(format);221const auto ser_params = (format >= Format::V3_BIP155 ? CAddress::V2_DISK : CAddress::V1_DISK);222ParamsStream s{s_, ser_params};224uint8_t compat;225s >> compat;226if (compat < INCOMPATIBILITY_BASE) {227throw std::ios_base::failure(strprintf(228"Corrupted addrman database: The compat value (%u) "229"is lower than the expected minimum value %u.",230compat, INCOMPATIBILITY_BASE));231}232const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;233if (lowest_compatible > FILE_FORMAT) {234throw InvalidAddrManVersionError(strprintf(235"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "236"but the maximum supported by this version of %s is %u.",237uint8_t{format}, lowest_compatible, CLIENT_NAME, uint8_t{FILE_FORMAT}));238}240s >> nKey;241s >> nNew;242s >> nTried;243int nUBuckets = 0;244s >> nUBuckets;245if (format >= Format::V1_DETERMINISTIC) {246nUBuckets ^= (1 << 30);247}249if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {250throw std::ios_base::failure(