Branch data Line data Source code
# 1 : : // Copyright (c) 2021 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #ifndef BITCOIN_ADDRMAN_IMPL_H
# 6 : : #define BITCOIN_ADDRMAN_IMPL_H
# 7 : :
# 8 : : #include <logging.h>
# 9 : : #include <logging/timer.h>
# 10 : : #include <netaddress.h>
# 11 : : #include <protocol.h>
# 12 : : #include <serialize.h>
# 13 : : #include <sync.h>
# 14 : : #include <uint256.h>
# 15 : :
# 16 : : #include <cstdint>
# 17 : : #include <optional>
# 18 : : #include <set>
# 19 : : #include <unordered_map>
# 20 : : #include <unordered_set>
# 21 : : #include <utility>
# 22 : : #include <vector>
# 23 : :
# 24 : : /** Total number of buckets for tried addresses */
# 25 : : static constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2{8};
# 26 : : static constexpr int ADDRMAN_TRIED_BUCKET_COUNT{1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2};
# 27 : : /** Total number of buckets for new addresses */
# 28 : : static constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2{10};
# 29 : : static constexpr int ADDRMAN_NEW_BUCKET_COUNT{1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2};
# 30 : : /** Maximum allowed number of entries in buckets for new and tried addresses */
# 31 : : static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6};
# 32 : : static constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2};
# 33 : :
# 34 : : /**
# 35 : : * Extended statistics about a CAddress
# 36 : : */
# 37 : : class AddrInfo : public CAddress
# 38 : : {
# 39 : : public:
# 40 : : //! last try whatsoever by us (memory only)
# 41 : : int64_t nLastTry{0};
# 42 : :
# 43 : : //! last counted attempt (memory only)
# 44 : : int64_t nLastCountAttempt{0};
# 45 : :
# 46 : : //! where knowledge about this address first came from
# 47 : : CNetAddr source;
# 48 : :
# 49 : : //! last successful connection by us
# 50 : : int64_t nLastSuccess{0};
# 51 : :
# 52 : : //! connection attempts since last successful attempt
# 53 : : int nAttempts{0};
# 54 : :
# 55 : : //! reference count in new sets (memory only)
# 56 : : int nRefCount{0};
# 57 : :
# 58 : : //! in tried set? (memory only)
# 59 : : bool fInTried{false};
# 60 : :
# 61 : : //! position in vRandom
# 62 : : mutable int nRandomPos{-1};
# 63 : :
# 64 : : SERIALIZE_METHODS(AddrInfo, obj)
# 65 : 48971 : {
# 66 : 48971 : READWRITEAS(CAddress, obj);
# 67 : 48971 : READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
# 68 : 48971 : }
# 69 : :
# 70 : : AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
# 71 : 35243 : {
# 72 : 35243 : }
# 73 : :
# 74 : : AddrInfo() : CAddress(), source()
# 75 : 29195 : {
# 76 : 29195 : }
# 77 : :
# 78 : : //! Calculate in which "tried" bucket this entry belongs
# 79 : : int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
# 80 : :
# 81 : : //! Calculate in which "new" bucket this entry belongs, given a certain source
# 82 : : int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
# 83 : :
# 84 : : //! Calculate in which "new" bucket this entry belongs, using its default source
# 85 : : int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
# 86 : 7492 : {
# 87 : 7492 : return GetNewBucket(nKey, source, asmap);
# 88 : 7492 : }
# 89 : :
# 90 : : //! Calculate in which position of a bucket to store this entry.
# 91 : : int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
# 92 : :
# 93 : : //! Determine whether the statistics about this entry are bad enough so that it can just be deleted
# 94 : : bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
# 95 : :
# 96 : : //! Calculate the relative chance this entry should be given when selecting nodes to connect to
# 97 : : double GetChance(int64_t nNow = GetAdjustedTime()) const;
# 98 : : };
# 99 : :
# 100 : : class AddrManImpl
# 101 : : {
# 102 : : public:
# 103 : : AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio);
# 104 : :
# 105 : : ~AddrManImpl();
# 106 : :
# 107 : : template <typename Stream>
# 108 : : void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 109 : :
# 110 : : template <typename Stream>
# 111 : : void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 112 : :
# 113 : : size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 114 : :
# 115 : : bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
# 116 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 117 : :
# 118 : : bool Good(const CService& addr, int64_t nTime)
# 119 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 120 : :
# 121 : : void Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
# 122 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 123 : :
# 124 : : void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 125 : :
# 126 : : std::pair<CAddress, int64_t> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 127 : :
# 128 : : std::pair<CAddress, int64_t> Select(bool newOnly) const
# 129 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 130 : :
# 131 : : std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
# 132 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 133 : :
# 134 : : void Connected(const CService& addr, int64_t nTime)
# 135 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 136 : :
# 137 : : void SetServices(const CService& addr, ServiceFlags nServices)
# 138 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 139 : :
# 140 : : std::optional<AddressPosition> FindAddressEntry(const CAddress& addr)
# 141 : : EXCLUSIVE_LOCKS_REQUIRED(!cs);
# 142 : :
# 143 : : const std::vector<bool>& GetAsmap() const;
# 144 : :
# 145 : : friend class AddrManDeterministic;
# 146 : :
# 147 : : private:
# 148 : : //! A mutex to protect the inner data structures.
# 149 : : mutable Mutex cs;
# 150 : :
# 151 : : //! Source of random numbers for randomization in inner loops
# 152 : : mutable FastRandomContext insecure_rand GUARDED_BY(cs);
# 153 : :
# 154 : : //! secret key to randomize bucket select with
# 155 : : uint256 nKey;
# 156 : :
# 157 : : //! Serialization versions.
# 158 : : enum Format : uint8_t {
# 159 : : V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
# 160 : : V1_DETERMINISTIC = 1, //!< for pre-asmap files
# 161 : : V2_ASMAP = 2, //!< for files including asmap version
# 162 : : V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
# 163 : : V4_MULTIPORT = 4, //!< adds support for multiple ports per IP
# 164 : : };
# 165 : :
# 166 : : //! The maximum format this software knows it can unserialize. Also, we always serialize
# 167 : : //! in this format.
# 168 : : //! The format (first byte in the serialized stream) can be higher than this and
# 169 : : //! still this software may be able to unserialize the file - if the second byte
# 170 : : //! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
# 171 : : static constexpr Format FILE_FORMAT = Format::V4_MULTIPORT;
# 172 : :
# 173 : : //! The initial value of a field that is incremented every time an incompatible format
# 174 : : //! change is made (such that old software versions would not be able to parse and
# 175 : : //! understand the new file format). This is 32 because we overtook the "key size"
# 176 : : //! field which was 32 historically.
# 177 : : //! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
# 178 : : static constexpr uint8_t INCOMPATIBILITY_BASE = 32;
# 179 : :
# 180 : : //! last used nId
# 181 : : int nIdCount GUARDED_BY(cs){0};
# 182 : :
# 183 : : //! table with information about all nIds
# 184 : : std::unordered_map<int, AddrInfo> mapInfo GUARDED_BY(cs);
# 185 : :
# 186 : : //! find an nId based on its network address and port.
# 187 : : std::unordered_map<CService, int, CServiceHash> mapAddr GUARDED_BY(cs);
# 188 : :
# 189 : : //! randomly-ordered vector of all nIds
# 190 : : //! This is mutable because it is unobservable outside the class, so any
# 191 : : //! changes to it (even in const methods) are also unobservable.
# 192 : : mutable std::vector<int> vRandom GUARDED_BY(cs);
# 193 : :
# 194 : : // number of "tried" entries
# 195 : : int nTried GUARDED_BY(cs){0};
# 196 : :
# 197 : : //! list of "tried" buckets
# 198 : : int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 199 : :
# 200 : : //! number of (unique) "new" entries
# 201 : : int nNew GUARDED_BY(cs){0};
# 202 : :
# 203 : : //! list of "new" buckets
# 204 : : int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 205 : :
# 206 : : //! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
# 207 : : int64_t nLastGood GUARDED_BY(cs){1};
# 208 : :
# 209 : : //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
# 210 : : std::set<int> m_tried_collisions;
# 211 : :
# 212 : : /** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
# 213 : : const int32_t m_consistency_check_ratio;
# 214 : :
# 215 : : // Compressed IP->ASN mapping, loaded from a file when a node starts.
# 216 : : // Should be always empty if no file was provided.
# 217 : : // This mapping is then used for bucketing nodes in Addrman.
# 218 : : //
# 219 : : // If asmap is provided, nodes will be bucketed by
# 220 : : // AS they belong to, in order to make impossible for a node
# 221 : : // to connect to several nodes hosted in a single AS.
# 222 : : // This is done in response to Erebus attack, but also to generally
# 223 : : // diversify the connections every node creates,
# 224 : : // especially useful when a large fraction of nodes
# 225 : : // operate under a couple of cloud providers.
# 226 : : //
# 227 : : // If a new asmap was provided, the existing records
# 228 : : // would be re-bucketed accordingly.
# 229 : : const std::vector<bool> m_asmap;
# 230 : :
# 231 : : //! Find an entry.
# 232 : : AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 233 : :
# 234 : : //! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.
# 235 : : AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 236 : :
# 237 : : //! Swap two elements in vRandom.
# 238 : : void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs);
# 239 : :
# 240 : : //! Delete an entry. It must not be in tried, and have refcount 0.
# 241 : : void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 242 : :
# 243 : : //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
# 244 : : void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 245 : :
# 246 : : //! Move an entry from the "new" table(s) to the "tried" table
# 247 : : void MakeTried(AddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 248 : :
# 249 : : /** Attempt to add a single address to addrman's new table.
# 250 : : * @see AddrMan::Add() for parameters. */
# 251 : : bool AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 252 : :
# 253 : : bool Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 254 : :
# 255 : : bool Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 256 : :
# 257 : : void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 258 : :
# 259 : : std::pair<CAddress, int64_t> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
# 260 : :
# 261 : : std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
# 262 : :
# 263 : : void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 264 : :
# 265 : : void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 266 : :
# 267 : : void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 268 : :
# 269 : : std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 270 : :
# 271 : : std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 272 : :
# 273 : : //! Consistency check, taking into account m_consistency_check_ratio.
# 274 : : //! Will std::abort if an inconsistency is detected.
# 275 : : void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
# 276 : :
# 277 : : //! Perform consistency check, regardless of m_consistency_check_ratio.
# 278 : : //! @returns an error code or zero.
# 279 : : int CheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs);
# 280 : : };
# 281 : :
# 282 : : #endif // BITCOIN_ADDRMAN_IMPL_H
|