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) 2021-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#ifndef BITCOIN_ADDRMAN_IMPL_H6#define BITCOIN_ADDRMAN_IMPL_H8#include <logging/timer.h>9#include <netaddress.h>10#include <protocol.h>11#include <serialize.h>12#include <sync.h>13#include <uint256.h>14#include <util/log.h>15#include <util/time.h>17#include <cstdint>18#include <optional>19#include <set>20#include <unordered_map>21#include <unordered_set>22#include <utility>23#include <vector>25/** Total number of buckets for tried addresses */26inline constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2{8};27inline constexpr int ADDRMAN_TRIED_BUCKET_COUNT{1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2};28/** Total number of buckets for new addresses */29inline constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2{10};30inline constexpr int ADDRMAN_NEW_BUCKET_COUNT{1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2};31/** Maximum allowed number of entries in buckets for new and tried addresses */32inline constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6};33inline constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2};35/**36* User-defined type for the internally used nIds37* This used to be int, making it feasible for attackers to cause an overflow,38* see https://bitcoincore.org/en/2024/07/31/disclose-addrman-int-overflow/39*/40using nid_type = int64_t;42/**43* Extended statistics about a CAddress44*/45class AddrInfo : public CAddress46{47public:48//! last try whatsoever by us (memory only)49NodeSeconds m_last_try{0s};51//! last counted attempt (memory only)52NodeSeconds m_last_count_attempt{0s};54//! where knowledge about this address first came from55CNetAddr source;57//! last successful connection by us58NodeSeconds m_last_success{0s};60//! connection attempts since last successful attempt61int nAttempts{0};63//! reference count in new sets (memory only)64int nRefCount{0};66//! in tried set? (memory only)67bool fInTried{false};69//! position in vRandom70mutable int nRandomPos{-1};72SERIALIZE_METHODS(AddrInfo, obj)73{74READWRITE(AsBase<CAddress>(obj), obj.source, Using<ChronoFormatter<int64_t>>(obj.m_last_success), obj.nAttempts);75}77AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)78{79}81AddrInfo() : CAddress(), source()82{83}85//! Calculate in which "tried" bucket this entry belongs86int GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const;88//! Calculate in which "new" bucket this entry belongs, given a certain source89int GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const;91//! Calculate in which "new" bucket this entry belongs, using its default source92int GetNewBucket(const uint256& nKey, const NetGroupManager& netgroupman) const93{94return GetNewBucket(nKey, source, netgroupman);95}97//! Calculate in which position of a bucket to store this entry.98int GetBucketPosition(const uint256 &nKey, bool fNew, int bucket) const;100//! Determine whether the statistics about this entry are bad enough so that it can just be deleted101bool IsTerrible(NodeSeconds now = Now<NodeSeconds>()) const;103//! Calculate the relative chance this entry should be given when selecting nodes to connect to104double GetChance(NodeSeconds now = Now<NodeSeconds>()) const;105};107class AddrManImpl108{109public:110AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio);112~AddrManImpl();114template <typename Stream>115void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);117template <typename Stream>118void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);120size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs);122bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)123EXCLUSIVE_LOCKS_REQUIRED(!cs);125bool Good(const CService& addr, NodeSeconds time)126EXCLUSIVE_LOCKS_REQUIRED(!cs);128void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)129EXCLUSIVE_LOCKS_REQUIRED(!cs);131void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);133std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);135std::pair<CAddress, NodeSeconds> Select(bool new_only, const std::unordered_set<Network>& networks) const136EXCLUSIVE_LOCKS_REQUIRED(!cs);138std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, bool filtered = true) const139EXCLUSIVE_LOCKS_REQUIRED(!cs);141std::vector<std::pair<AddrInfo, AddressPosition>> GetEntries(bool from_tried) const142EXCLUSIVE_LOCKS_REQUIRED(!cs);144void Connected(const CService& addr, NodeSeconds time)145EXCLUSIVE_LOCKS_REQUIRED(!cs);147void SetServices(const CService& addr, ServiceFlags nServices)148EXCLUSIVE_LOCKS_REQUIRED(!cs);150std::optional<AddressPosition> FindAddressEntry(const CAddress& addr)151EXCLUSIVE_LOCKS_REQUIRED(!cs);153friend class AddrManDeterministic;155private:156//! A mutex to protect the inner data structures.157mutable Mutex cs;159//! Source of random numbers for randomization in inner loops160mutable FastRandomContext insecure_rand GUARDED_BY(cs);162//! secret key to randomize bucket select with163uint256 nKey;165//! Serialization versions.166enum Format : uint8_t {167V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88168V1_DETERMINISTIC = 1, //!< for pre-asmap files169V2_ASMAP = 2, //!< for files including asmap version170V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format171V4_MULTIPORT = 4, //!< adds support for multiple ports per IP172};174//! The maximum format this software knows it can unserialize. Also, we always serialize175//! in this format.176//! The format (first byte in the serialized stream) can be higher than this and177//! still this software may be able to unserialize the file - if the second byte178//! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.179static constexpr Format FILE_FORMAT = Format::V4_MULTIPORT;181//! The initial value of a field that is incremented every time an incompatible format182//! change is made (such that old software versions would not be able to parse and183//! understand the new file format). This is 32 because we overtook the "key size"184//! field which was 32 historically.185//! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.186static constexpr uint8_t INCOMPATIBILITY_BASE = 32;188//! last used nId189nid_type nIdCount GUARDED_BY(cs){0};191//! table with information about all nIds192std::unordered_map<nid_type, AddrInfo> mapInfo GUARDED_BY(cs);194//! find an nId based on its network address and port.195std::unordered_map<CService, nid_type, CServiceHash> mapAddr GUARDED_BY(cs);197//! randomly-ordered vector of all nIds198//! This is mutable because it is unobservable outside the class, so any199//! changes to it (even in const methods) are also unobservable.200mutable std::vector<nid_type> vRandom GUARDED_BY(cs);202// number of "tried" entries203int nTried GUARDED_BY(cs){0};205//! list of "tried" buckets206nid_type vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);208//! number of (unique) "new" entries209int nNew GUARDED_BY(cs){0};211//! list of "new" buckets212nid_type vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);214//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.215NodeSeconds m_last_good GUARDED_BY(cs){1s};217//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.218std::set<nid_type> m_tried_collisions;220/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */221const int32_t m_consistency_check_ratio;223/** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */224const NetGroupManager& m_netgroupman;226struct NewTriedCount {227size_t n_new;228size_t n_tried;229};231/** Number of entries in addrman per network and new/tried table. */232std::unordered_map<Network, NewTriedCount> m_network_counts GUARDED_BY(cs);234//! Find an entry.235AddrInfo* Find(const CService& addr, nid_type* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);237//! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.238AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, nid_type* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);240//! Swap two elements in vRandom.241void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs);243//! Delete an entry. It must not be in tried, and have refcount 0.244void Delete(nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs);246//! Clear a position in a "new" table. This is the only place where entries are actually deleted.247void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);249//! Move an entry from the "new" table(s) to the "tried" table250void MakeTried(AddrInfo& info, nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
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.