Branch data Line data Source code
# 1 : : // Copyright (c) 2012 Pieter Wuille
# 2 : : // Copyright (c) 2012-2020 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #ifndef BITCOIN_ADDRMAN_H
# 7 : : #define BITCOIN_ADDRMAN_H
# 8 : :
# 9 : : #include <clientversion.h>
# 10 : : #include <netaddress.h>
# 11 : : #include <protocol.h>
# 12 : : #include <random.h>
# 13 : : #include <sync.h>
# 14 : : #include <timedata.h>
# 15 : : #include <util/system.h>
# 16 : :
# 17 : : #include <fs.h>
# 18 : : #include <hash.h>
# 19 : : #include <iostream>
# 20 : : #include <map>
# 21 : : #include <set>
# 22 : : #include <stdint.h>
# 23 : : #include <streams.h>
# 24 : : #include <vector>
# 25 : :
# 26 : : /**
# 27 : : * Extended statistics about a CAddress
# 28 : : */
# 29 : : class CAddrInfo : public CAddress
# 30 : : {
# 31 : : public:
# 32 : : //! last try whatsoever by us (memory only)
# 33 : : int64_t nLastTry{0};
# 34 : :
# 35 : : //! last counted attempt (memory only)
# 36 : : int64_t nLastCountAttempt{0};
# 37 : :
# 38 : : private:
# 39 : : //! where knowledge about this address first came from
# 40 : : CNetAddr source;
# 41 : :
# 42 : : //! last successful connection by us
# 43 : : int64_t nLastSuccess{0};
# 44 : :
# 45 : : //! connection attempts since last successful attempt
# 46 : : int nAttempts{0};
# 47 : :
# 48 : : //! reference count in new sets (memory only)
# 49 : : int nRefCount{0};
# 50 : :
# 51 : : //! in tried set? (memory only)
# 52 : : bool fInTried{false};
# 53 : :
# 54 : : //! position in vRandom
# 55 : : int nRandomPos{-1};
# 56 : :
# 57 : : friend class CAddrMan;
# 58 : :
# 59 : : public:
# 60 : :
# 61 : : SERIALIZE_METHODS(CAddrInfo, obj)
# 62 : 202 : {
# 63 : 202 : READWRITE(WithParams(AddrSerialization::DISK, AsBase<CAddress>(obj)), obj.source, obj.nLastSuccess, obj.nAttempts);
# 64 : 202 : }
# 65 : :
# 66 : : CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
# 67 : 13416 : {
# 68 : 13416 : }
# 69 : :
# 70 : : CAddrInfo() : CAddress(), source()
# 71 : 43684 : {
# 72 : 43684 : }
# 73 : :
# 74 : : //! Calculate in which "tried" bucket this entry belongs
# 75 : : int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
# 76 : :
# 77 : : //! Calculate in which "new" bucket this entry belongs, given a certain source
# 78 : : int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
# 79 : :
# 80 : : //! Calculate in which "new" bucket this entry belongs, using its default source
# 81 : : int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
# 82 : 6660 : {
# 83 : 6660 : return GetNewBucket(nKey, source, asmap);
# 84 : 6660 : }
# 85 : :
# 86 : : //! Calculate in which position of a bucket to store this entry.
# 87 : : int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
# 88 : :
# 89 : : //! Determine whether the statistics about this entry are bad enough so that it can just be deleted
# 90 : : bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
# 91 : :
# 92 : : //! Calculate the relative chance this entry should be given when selecting nodes to connect to
# 93 : : double GetChance(int64_t nNow = GetAdjustedTime()) const;
# 94 : : };
# 95 : :
# 96 : : /** Stochastic address manager
# 97 : : *
# 98 : : * Design goals:
# 99 : : * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
# 100 : : * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
# 101 : : *
# 102 : : * To that end:
# 103 : : * * Addresses are organized into buckets.
# 104 : : * * Addresses that have not yet been tried go into 1024 "new" buckets.
# 105 : : * * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.
# 106 : : * * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
# 107 : : * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
# 108 : : * are seen frequently. The chance for increasing this multiplicity decreases exponentially.
# 109 : : * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
# 110 : : * ones) is removed from it first.
# 111 : : * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
# 112 : : * * Each address range selects at random 8 of these buckets.
# 113 : : * * The actual bucket is chosen from one of these, based on the full address.
# 114 : : * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
# 115 : : * tried ones) is evicted from it, back to the "new" buckets.
# 116 : : * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
# 117 : : * be observable by adversaries.
# 118 : : * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
# 119 : : * consistency checks for the entire data structure.
# 120 : : */
# 121 : :
# 122 : : //! total number of buckets for tried addresses
# 123 : 3467230 : #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
# 124 : :
# 125 : : //! total number of buckets for new addresses
# 126 : 6717946 : #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
# 127 : :
# 128 : : //! maximum allowed number of entries in buckets for new and tried addresses
# 129 : 316810666 : #define ADDRMAN_BUCKET_SIZE_LOG2 6
# 130 : :
# 131 : : //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
# 132 : 3694 : #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
# 133 : :
# 134 : : //! over how many buckets entries with new addresses originating from a single group are spread
# 135 : 11386 : #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
# 136 : :
# 137 : : //! in how many buckets for entries with new addresses a single address may occur
# 138 : 44 : #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
# 139 : :
# 140 : : //! how old addresses can maximally be
# 141 : 1067 : #define ADDRMAN_HORIZON_DAYS 30
# 142 : :
# 143 : : //! after how many failed attempts we give up on a new node
# 144 : 1065 : #define ADDRMAN_RETRIES 3
# 145 : :
# 146 : : //! how many successive failures are allowed ...
# 147 : 1065 : #define ADDRMAN_MAX_FAILURES 10
# 148 : :
# 149 : : //! ... in at least this many days
# 150 : 1065 : #define ADDRMAN_MIN_FAIL_DAYS 7
# 151 : :
# 152 : : //! how recent a successful connection should be before we allow an address to be evicted from tried
# 153 : 12 : #define ADDRMAN_REPLACEMENT_HOURS 4
# 154 : :
# 155 : : //! the maximum percentage of nodes to return in a getaddr call
# 156 : 250 : #define ADDRMAN_GETADDR_MAX_PCT 23
# 157 : :
# 158 : : //! the maximum number of nodes to return in a getaddr call
# 159 : 250 : #define ADDRMAN_GETADDR_MAX 2500
# 160 : :
# 161 : : //! Convenience
# 162 : 1891880 : #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
# 163 : 5635778 : #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
# 164 : 314153126 : #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
# 165 : :
# 166 : : //! the maximum number of tried addr collisions to store
# 167 : 30 : #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
# 168 : :
# 169 : : //! the maximum time we'll spend trying to resolve a tried table collision, in seconds
# 170 : : static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
# 171 : :
# 172 : : /**
# 173 : : * Stochastical (IP) address manager
# 174 : : */
# 175 : : class CAddrMan
# 176 : : {
# 177 : : friend class CAddrManTest;
# 178 : : protected:
# 179 : : //! critical section to protect the inner data structures
# 180 : : mutable RecursiveMutex cs;
# 181 : :
# 182 : : private:
# 183 : : //! last used nId
# 184 : : int nIdCount GUARDED_BY(cs);
# 185 : :
# 186 : : //! table with information about all nIds
# 187 : : std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
# 188 : :
# 189 : : //! find an nId based on its network address
# 190 : : std::map<CNetAddr, int> mapAddr GUARDED_BY(cs);
# 191 : :
# 192 : : //! randomly-ordered vector of all nIds
# 193 : : std::vector<int> vRandom GUARDED_BY(cs);
# 194 : :
# 195 : : // number of "tried" entries
# 196 : : int nTried GUARDED_BY(cs);
# 197 : :
# 198 : : //! list of "tried" buckets
# 199 : : int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 200 : :
# 201 : : //! number of (unique) "new" entries
# 202 : : int nNew GUARDED_BY(cs);
# 203 : :
# 204 : : //! list of "new" buckets
# 205 : : int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 206 : :
# 207 : : //! last time Good was called (memory only)
# 208 : : int64_t nLastGood GUARDED_BY(cs);
# 209 : :
# 210 : : //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
# 211 : : std::set<int> m_tried_collisions;
# 212 : :
# 213 : : protected:
# 214 : : //! secret key to randomize bucket select with
# 215 : : uint256 nKey;
# 216 : :
# 217 : : //! Source of random numbers for randomization in inner loops
# 218 : : FastRandomContext insecure_rand;
# 219 : :
# 220 : : //! Find an entry.
# 221 : : CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 222 : :
# 223 : : //! find an entry, creating it if necessary.
# 224 : : //! nTime and nServices of the found node are updated, if necessary.
# 225 : : CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 226 : :
# 227 : : //! Swap two elements in vRandom.
# 228 : : void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 229 : :
# 230 : : //! Move an entry from the "new" table(s) to the "tried" table
# 231 : : void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 232 : :
# 233 : : //! Delete an entry. It must not be in tried, and have refcount 0.
# 234 : : void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 235 : :
# 236 : : //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
# 237 : : void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 238 : :
# 239 : : //! Mark an entry "good", possibly moving it from "new" to "tried".
# 240 : : void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 241 : :
# 242 : : //! Add an entry to the "new" table.
# 243 : : bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 244 : :
# 245 : : //! Mark an entry as attempted to connect.
# 246 : : void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 247 : :
# 248 : : //! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
# 249 : : CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 250 : :
# 251 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 252 : : void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 253 : :
# 254 : : //! Return a random to-be-evicted tried table address.
# 255 : : CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 256 : :
# 257 : : #ifdef DEBUG_ADDRMAN
# 258 : : //! Perform consistency check. Returns an error code or zero.
# 259 : : int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 260 : : #endif
# 261 : :
# 262 : : //! Select several addresses at once.
# 263 : : void GetAddr_(std::vector<CAddress> &vAddr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 264 : :
# 265 : : //! Mark an entry as currently-connected-to.
# 266 : : void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 267 : :
# 268 : : //! Update an entry's service bits.
# 269 : : void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 270 : :
# 271 : : public:
# 272 : : // Compressed IP->ASN mapping, loaded from a file when a node starts.
# 273 : : // Should be always empty if no file was provided.
# 274 : : // This mapping is then used for bucketing nodes in Addrman.
# 275 : : //
# 276 : : // If asmap is provided, nodes will be bucketed by
# 277 : : // AS they belong to, in order to make impossible for a node
# 278 : : // to connect to several nodes hosted in a single AS.
# 279 : : // This is done in response to Erebus attack, but also to generally
# 280 : : // diversify the connections every node creates,
# 281 : : // especially useful when a large fraction of nodes
# 282 : : // operate under a couple of cloud providers.
# 283 : : //
# 284 : : // If a new asmap was provided, the existing records
# 285 : : // would be re-bucketed accordingly.
# 286 : : std::vector<bool> m_asmap;
# 287 : :
# 288 : : // Read asmap from provided binary file
# 289 : : static std::vector<bool> DecodeAsmap(fs::path path);
# 290 : :
# 291 : :
# 292 : : /**
# 293 : : * serialized format:
# 294 : : * * version byte (1 for pre-asmap files, 2 for files including asmap version)
# 295 : : * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
# 296 : : * * nNew
# 297 : : * * nTried
# 298 : : * * number of "new" buckets XOR 2**30
# 299 : : * * all nNew addrinfos in vvNew
# 300 : : * * all nTried addrinfos in vvTried
# 301 : : * * for each bucket:
# 302 : : * * number of elements
# 303 : : * * for each element: index
# 304 : : *
# 305 : : * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
# 306 : : * as incompatible. This is necessary because it did not check the version number on
# 307 : : * deserialization.
# 308 : : *
# 309 : : * Notice that vvTried, mapAddr and vVector are never encoded explicitly;
# 310 : : * they are instead reconstructed from the other information.
# 311 : : *
# 312 : : * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change,
# 313 : : * otherwise it is reconstructed as well.
# 314 : : *
# 315 : : * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
# 316 : : * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
# 317 : : *
# 318 : : * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
# 319 : : * very little in common.
# 320 : : */
# 321 : : template<typename Stream>
# 322 : : void Serialize(Stream &s) const
# 323 : 1568 : {
# 324 : 1568 : LOCK(cs);
# 325 : 1568 :
# 326 : 1568 : unsigned char nVersion = 2;
# 327 : 1568 : s << nVersion;
# 328 : 1568 : s << ((unsigned char)32);
# 329 : 1568 : s << nKey;
# 330 : 1568 : s << nNew;
# 331 : 1568 : s << nTried;
# 332 : 1568 :
# 333 : 1568 : int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
# 334 : 1568 : s << nUBuckets;
# 335 : 1568 : std::map<int, int> mapUnkIds;
# 336 : 1568 : int nIds = 0;
# 337 : 1568 : for (const auto& entry : mapInfo) {
# 338 : 168 : mapUnkIds[entry.first] = nIds;
# 339 : 168 : const CAddrInfo &info = entry.second;
# 340 : 168 : if (info.nRefCount) {
# 341 : 168 : assert(nIds != nNew); // this means nNew was wrong, oh ow
# 342 : 168 : s << info;
# 343 : 168 : nIds++;
# 344 : 168 : }
# 345 : 168 : }
# 346 : 1568 : nIds = 0;
# 347 : 1568 : for (const auto& entry : mapInfo) {
# 348 : 168 : const CAddrInfo &info = entry.second;
# 349 : 168 : if (info.fInTried) {
# 350 : 0 : assert(nIds != nTried); // this means nTried was wrong, oh ow
# 351 : 0 : s << info;
# 352 : 0 : nIds++;
# 353 : 0 : }
# 354 : 168 : }
# 355 : 1607200 : for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# 356 : 1605632 : int nSize = 0;
# 357 : 104366080 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 358 : 102760448 : if (vvNew[bucket][i] != -1)
# 359 : 168 : nSize++;
# 360 : 102760448 : }
# 361 : 1605632 : s << nSize;
# 362 : 104366080 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 363 : 102760448 : if (vvNew[bucket][i] != -1) {
# 364 : 168 : int nIndex = mapUnkIds[vvNew[bucket][i]];
# 365 : 168 : s << nIndex;
# 366 : 168 : }
# 367 : 102760448 : }
# 368 : 1605632 : }
# 369 : 1568 : // Store asmap version after bucket entries so that it
# 370 : 1568 : // can be ignored by older clients for backward compatibility.
# 371 : 1568 : uint256 asmap_version;
# 372 : 1568 : if (m_asmap.size() != 0) {
# 373 : 12 : asmap_version = SerializeHash(m_asmap);
# 374 : 12 : }
# 375 : 1568 : s << asmap_version;
# 376 : 1568 : }
# 377 : :
# 378 : : template<typename Stream>
# 379 : : void Unserialize(Stream& s)
# 380 : 203 : {
# 381 : 203 : LOCK(cs);
# 382 : 203 :
# 383 : 203 : Clear();
# 384 : 203 : unsigned char nVersion;
# 385 : 203 : s >> nVersion;
# 386 : 203 : unsigned char nKeySize;
# 387 : 203 : s >> nKeySize;
# 388 : 203 : if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
# 389 : 203 : s >> nKey;
# 390 : 203 : s >> nNew;
# 391 : 203 : s >> nTried;
# 392 : 203 : int nUBuckets = 0;
# 393 : 203 : s >> nUBuckets;
# 394 : 203 : if (nVersion != 0) {
# 395 : 203 : nUBuckets ^= (1 << 30);
# 396 : 203 : }
# 397 : 203 :
# 398 : 203 : if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# 399 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
# 400 : 0 : }
# 401 : 203 :
# 402 : 203 : if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# 403 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
# 404 : 0 : }
# 405 : 203 :
# 406 : 203 : // Deserialize entries from the new table.
# 407 : 233 : for (int n = 0; n < nNew; n++) {
# 408 : 30 : CAddrInfo &info = mapInfo[n];
# 409 : 30 : s >> info;
# 410 : 30 : mapAddr[info] = n;
# 411 : 30 : info.nRandomPos = vRandom.size();
# 412 : 30 : vRandom.push_back(n);
# 413 : 30 : }
# 414 : 203 : nIdCount = nNew;
# 415 : 203 :
# 416 : 203 : // Deserialize entries from the tried table.
# 417 : 203 : int nLost = 0;
# 418 : 203 : for (int n = 0; n < nTried; n++) {
# 419 : 0 : CAddrInfo info;
# 420 : 0 : s >> info;
# 421 : 0 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
# 422 : 0 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
# 423 : 0 : if (vvTried[nKBucket][nKBucketPos] == -1) {
# 424 : 0 : info.nRandomPos = vRandom.size();
# 425 : 0 : info.fInTried = true;
# 426 : 0 : vRandom.push_back(nIdCount);
# 427 : 0 : mapInfo[nIdCount] = info;
# 428 : 0 : mapAddr[info] = nIdCount;
# 429 : 0 : vvTried[nKBucket][nKBucketPos] = nIdCount;
# 430 : 0 : nIdCount++;
# 431 : 0 : } else {
# 432 : 0 : nLost++;
# 433 : 0 : }
# 434 : 0 : }
# 435 : 203 : nTried -= nLost;
# 436 : 203 :
# 437 : 203 : // Store positions in the new table buckets to apply later (if possible).
# 438 : 203 : std::map<int, int> entryToBucket; // Represents which entry belonged to which bucket when serializing
# 439 : 203 :
# 440 : 203979 : for (int bucket = 0; bucket < nUBuckets; bucket++) {
# 441 : 203776 : int nSize = 0;
# 442 : 203776 : s >> nSize;
# 443 : 203798 : for (int n = 0; n < nSize; n++) {
# 444 : 22 : int nIndex = 0;
# 445 : 22 : s >> nIndex;
# 446 : 22 : if (nIndex >= 0 && nIndex < nNew) {
# 447 : 22 : entryToBucket[nIndex] = bucket;
# 448 : 22 : }
# 449 : 22 : }
# 450 : 203776 : }
# 451 : 203 :
# 452 : 203 : uint256 supplied_asmap_version;
# 453 : 203 : if (m_asmap.size() != 0) {
# 454 : 10 : supplied_asmap_version = SerializeHash(m_asmap);
# 455 : 10 : }
# 456 : 203 : uint256 serialized_asmap_version;
# 457 : 203 : if (nVersion > 1) {
# 458 : 199 : s >> serialized_asmap_version;
# 459 : 199 : }
# 460 : 203 :
# 461 : 225 : for (int n = 0; n < nNew; n++) {
# 462 : 22 : CAddrInfo &info = mapInfo[n];
# 463 : 22 : int bucket = entryToBucket[n];
# 464 : 22 : int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
# 465 : 22 : if (nVersion == 2 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 &&
# 466 : 22 : info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) {
# 467 : 14 : // Bucketing has not changed, using existing bucket positions for the new table
# 468 : 14 : vvNew[bucket][nUBucketPos] = n;
# 469 : 14 : info.nRefCount++;
# 470 : 14 : } else {
# 471 : 8 : // In case the new table data cannot be used (nVersion unknown, bucket count wrong or new asmap),
# 472 : 8 : // try to give them a reference based on their primary source address.
# 473 : 8 : LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
# 474 : 8 : bucket = info.GetNewBucket(nKey, m_asmap);
# 475 : 8 : nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
# 476 : 8 : if (vvNew[bucket][nUBucketPos] == -1) {
# 477 : 8 : vvNew[bucket][nUBucketPos] = n;
# 478 : 8 : info.nRefCount++;
# 479 : 8 : }
# 480 : 8 : }
# 481 : 22 : }
# 482 : 203 :
# 483 : 203 : // Prune new entries with refcount 0 (as a result of collisions).
# 484 : 203 : int nLostUnk = 0;
# 485 : 225 : for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
# 486 : 22 : if (it->second.fInTried == false && it->second.nRefCount == 0) {
# 487 : 0 : std::map<int, CAddrInfo>::const_iterator itCopy = it++;
# 488 : 0 : Delete(itCopy->first);
# 489 : 0 : nLostUnk++;
# 490 : 22 : } else {
# 491 : 22 : it++;
# 492 : 22 : }
# 493 : 22 : }
# 494 : 203 : if (nLost + nLostUnk > 0) {
# 495 : 0 : LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
# 496 : 0 : }
# 497 : 203 :
# 498 : 203 : Check();
# 499 : 203 : }
# 500 : :
# 501 : : void Clear()
# 502 : 1215 : {
# 503 : 1215 : LOCK(cs);
# 504 : 1215 : std::vector<int>().swap(vRandom);
# 505 : 1215 : nKey = insecure_rand.rand256();
# 506 : 1245375 : for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# 507 : 80870400 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 508 : 79626240 : vvNew[bucket][entry] = -1;
# 509 : 79626240 : }
# 510 : 1244160 : }
# 511 : 312255 : for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
# 512 : 20217600 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 513 : 19906560 : vvTried[bucket][entry] = -1;
# 514 : 19906560 : }
# 515 : 311040 : }
# 516 : 1215 :
# 517 : 1215 : nIdCount = 0;
# 518 : 1215 : nTried = 0;
# 519 : 1215 : nNew = 0;
# 520 : 1215 : nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
# 521 : 1215 : mapInfo.clear();
# 522 : 1215 : mapAddr.clear();
# 523 : 1215 : }
# 524 : :
# 525 : : CAddrMan()
# 526 : 706 : {
# 527 : 706 : Clear();
# 528 : 706 : }
# 529 : :
# 530 : : ~CAddrMan()
# 531 : 706 : {
# 532 : 706 : nKey.SetNull();
# 533 : 706 : }
# 534 : :
# 535 : : //! Return the number of (unique) addresses in all tables.
# 536 : : size_t size() const
# 537 : 20663 : {
# 538 : 20663 : LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
# 539 : 20663 : return vRandom.size();
# 540 : 20663 : }
# 541 : :
# 542 : : //! Consistency check
# 543 : : void Check()
# 544 : 71613 : {
# 545 : : #ifdef DEBUG_ADDRMAN
# 546 : : {
# 547 : : LOCK(cs);
# 548 : : int err;
# 549 : : if ((err=Check_()))
# 550 : : LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
# 551 : : }
# 552 : : #endif
# 553 : : }
# 554 : :
# 555 : : //! Add a single address.
# 556 : : bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 557 : 4510 : {
# 558 : 4510 : LOCK(cs);
# 559 : 4510 : bool fRet = false;
# 560 : 4510 : Check();
# 561 : 4510 : fRet |= Add_(addr, source, nTimePenalty);
# 562 : 4510 : Check();
# 563 : 4510 : if (fRet) {
# 564 : 4452 : LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
# 565 : 4452 : }
# 566 : 4510 : return fRet;
# 567 : 4510 : }
# 568 : :
# 569 : : //! Add multiple addresses.
# 570 : : bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 571 : 28 : {
# 572 : 28 : LOCK(cs);
# 573 : 28 : int nAdd = 0;
# 574 : 28 : Check();
# 575 : 301 : for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
# 576 : 273 : nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
# 577 : 28 : Check();
# 578 : 28 : if (nAdd) {
# 579 : 4 : LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
# 580 : 4 : }
# 581 : 28 : return nAdd > 0;
# 582 : 28 : }
# 583 : :
# 584 : : //! Mark an entry as accessible.
# 585 : : void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
# 586 : 1122 : {
# 587 : 1122 : LOCK(cs);
# 588 : 1122 : Check();
# 589 : 1122 : Good_(addr, test_before_evict, nTime);
# 590 : 1122 : Check();
# 591 : 1122 : }
# 592 : :
# 593 : : //! Mark an entry as connection attempted to.
# 594 : : void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
# 595 : 246 : {
# 596 : 246 : LOCK(cs);
# 597 : 246 : Check();
# 598 : 246 : Attempt_(addr, fCountFailure, nTime);
# 599 : 246 : Check();
# 600 : 246 : }
# 601 : :
# 602 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 603 : : void ResolveCollisions()
# 604 : 9545 : {
# 605 : 9545 : LOCK(cs);
# 606 : 9545 : Check();
# 607 : 9545 : ResolveCollisions_();
# 608 : 9545 : Check();
# 609 : 9545 : }
# 610 : :
# 611 : : //! Randomly select an address in tried that another address is attempting to evict.
# 612 : : CAddrInfo SelectTriedCollision()
# 613 : 9853 : {
# 614 : 9853 : CAddrInfo ret;
# 615 : 9853 : {
# 616 : 9853 : LOCK(cs);
# 617 : 9853 : Check();
# 618 : 9853 : ret = SelectTriedCollision_();
# 619 : 9853 : Check();
# 620 : 9853 : }
# 621 : 9853 : return ret;
# 622 : 9853 : }
# 623 : :
# 624 : : /**
# 625 : : * Choose an address to connect to.
# 626 : : */
# 627 : : CAddrInfo Select(bool newOnly = false)
# 628 : 9691 : {
# 629 : 9691 : CAddrInfo addrRet;
# 630 : 9691 : {
# 631 : 9691 : LOCK(cs);
# 632 : 9691 : Check();
# 633 : 9691 : addrRet = Select_(newOnly);
# 634 : 9691 : Check();
# 635 : 9691 : }
# 636 : 9691 : return addrRet;
# 637 : 9691 : }
# 638 : :
# 639 : : //! Return a bunch of addresses, selected at random.
# 640 : : std::vector<CAddress> GetAddr()
# 641 : 244 : {
# 642 : 244 : Check();
# 643 : 244 : std::vector<CAddress> vAddr;
# 644 : 244 : {
# 645 : 244 : LOCK(cs);
# 646 : 244 : GetAddr_(vAddr);
# 647 : 244 : }
# 648 : 244 : Check();
# 649 : 244 : return vAddr;
# 650 : 244 : }
# 651 : :
# 652 : : //! Mark an entry as currently-connected-to.
# 653 : : void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
# 654 : 234 : {
# 655 : 234 : LOCK(cs);
# 656 : 234 : Check();
# 657 : 234 : Connected_(addr, nTime);
# 658 : 234 : Check();
# 659 : 234 : }
# 660 : :
# 661 : : void SetServices(const CService &addr, ServiceFlags nServices)
# 662 : 234 : {
# 663 : 234 : LOCK(cs);
# 664 : 234 : Check();
# 665 : 234 : SetServices_(addr, nServices);
# 666 : 234 : Check();
# 667 : 234 : }
# 668 : :
# 669 : : };
# 670 : :
# 671 : : #endif // BITCOIN_ADDRMAN_H
|