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