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 : 35438 : {
# 63 : 35438 : READWRITEAS(CAddress, obj);
# 64 : 35438 : READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
# 65 : 35438 : }
# 66 : :
# 67 : : CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
# 68 : 32147 : {
# 69 : 32147 : }
# 70 : :
# 71 : : CAddrInfo() : CAddress(), source()
# 72 : 84775 : {
# 73 : 84775 : }
# 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 : 3474428 : #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
# 125 : :
# 126 : : //! total number of buckets for new addresses
# 127 : 553861597 : #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
# 128 : :
# 129 : : //! maximum allowed number of entries in buckets for new and tried addresses
# 130 : 873658653 : #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 : 30117 : #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 : 44 : #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
# 140 : :
# 141 : : //! how old addresses can maximally be
# 142 : 30671 : #define ADDRMAN_HORIZON_DAYS 30
# 143 : :
# 144 : : //! after how many failed attempts we give up on a new node
# 145 : 30669 : #define ADDRMAN_RETRIES 3
# 146 : :
# 147 : : //! how many successive failures are allowed ...
# 148 : 30669 : #define ADDRMAN_MAX_FAILURES 10
# 149 : :
# 150 : : //! ... in at least this many days
# 151 : 30669 : #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 : : //! Convenience
# 157 : 1899078 : #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
# 158 : 279256010 : #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
# 159 : 597477694 : #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
# 160 : :
# 161 : : //! the maximum number of tried addr collisions to store
# 162 : 30 : #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
# 163 : :
# 164 : : //! the maximum time we'll spend trying to resolve a tried table collision, in seconds
# 165 : : static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
# 166 : :
# 167 : : /**
# 168 : : * Stochastical (IP) address manager
# 169 : : */
# 170 : : class CAddrMan
# 171 : : {
# 172 : : friend class CAddrManTest;
# 173 : : protected:
# 174 : : //! critical section to protect the inner data structures
# 175 : : mutable RecursiveMutex cs;
# 176 : :
# 177 : : private:
# 178 : : //! last used nId
# 179 : : int nIdCount GUARDED_BY(cs);
# 180 : :
# 181 : : //! table with information about all nIds
# 182 : : std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
# 183 : :
# 184 : : //! find an nId based on its network address
# 185 : : std::map<CNetAddr, int> mapAddr GUARDED_BY(cs);
# 186 : :
# 187 : : //! randomly-ordered vector of all nIds
# 188 : : std::vector<int> vRandom GUARDED_BY(cs);
# 189 : :
# 190 : : // number of "tried" entries
# 191 : : int nTried GUARDED_BY(cs);
# 192 : :
# 193 : : //! list of "tried" buckets
# 194 : : int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 195 : :
# 196 : : //! number of (unique) "new" entries
# 197 : : int nNew GUARDED_BY(cs);
# 198 : :
# 199 : : //! list of "new" buckets
# 200 : : int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 201 : :
# 202 : : //! last time Good was called (memory only)
# 203 : : int64_t nLastGood GUARDED_BY(cs);
# 204 : :
# 205 : : //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
# 206 : : std::set<int> m_tried_collisions;
# 207 : :
# 208 : : protected:
# 209 : : //! secret key to randomize bucket select with
# 210 : : uint256 nKey;
# 211 : :
# 212 : : //! Source of random numbers for randomization in inner loops
# 213 : : FastRandomContext insecure_rand;
# 214 : :
# 215 : : //! Find an entry.
# 216 : : CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 217 : :
# 218 : : //! find an entry, creating it if necessary.
# 219 : : //! nTime and nServices of the found node are updated, if necessary.
# 220 : : CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 221 : :
# 222 : : //! Swap two elements in vRandom.
# 223 : : void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 224 : :
# 225 : : //! Move an entry from the "new" table(s) to the "tried" table
# 226 : : void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 227 : :
# 228 : : //! Delete an entry. It must not be in tried, and have refcount 0.
# 229 : : void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 230 : :
# 231 : : //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
# 232 : : void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 233 : :
# 234 : : //! Mark an entry "good", possibly moving it from "new" to "tried".
# 235 : : void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 236 : :
# 237 : : //! Add an entry to the "new" table.
# 238 : : bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 239 : :
# 240 : : //! Mark an entry as attempted to connect.
# 241 : : void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 242 : :
# 243 : : //! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
# 244 : : CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 245 : :
# 246 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 247 : : void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 248 : :
# 249 : : //! Return a random to-be-evicted tried table address.
# 250 : : CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 251 : :
# 252 : : #ifdef DEBUG_ADDRMAN
# 253 : : //! Perform consistency check. Returns an error code or zero.
# 254 : : int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 255 : : #endif
# 256 : :
# 257 : : //! Select several addresses at once.
# 258 : : void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 259 : :
# 260 : : //! Mark an entry as currently-connected-to.
# 261 : : void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 262 : :
# 263 : : //! Update an entry's service bits.
# 264 : : void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 265 : :
# 266 : : public:
# 267 : : //! Serialization versions.
# 268 : : enum class Format : uint8_t {
# 269 : : V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
# 270 : : V1_DETERMINISTIC = 1, //!< for pre-asmap files
# 271 : : V2_ASMAP = 2, //!< for files including asmap version
# 272 : : V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
# 273 : : };
# 274 : :
# 275 : : // Compressed IP->ASN mapping, loaded from a file when a node starts.
# 276 : : // Should be always empty if no file was provided.
# 277 : : // This mapping is then used for bucketing nodes in Addrman.
# 278 : : //
# 279 : : // If asmap is provided, nodes will be bucketed by
# 280 : : // AS they belong to, in order to make impossible for a node
# 281 : : // to connect to several nodes hosted in a single AS.
# 282 : : // This is done in response to Erebus attack, but also to generally
# 283 : : // diversify the connections every node creates,
# 284 : : // especially useful when a large fraction of nodes
# 285 : : // operate under a couple of cloud providers.
# 286 : : //
# 287 : : // If a new asmap was provided, the existing records
# 288 : : // would be re-bucketed accordingly.
# 289 : : std::vector<bool> m_asmap;
# 290 : :
# 291 : : // Read asmap from provided binary file
# 292 : : static std::vector<bool> DecodeAsmap(fs::path path);
# 293 : :
# 294 : :
# 295 : : /**
# 296 : : * Serialized format.
# 297 : : * * version byte (@see `Format`)
# 298 : : * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
# 299 : : * * nNew
# 300 : : * * nTried
# 301 : : * * number of "new" buckets XOR 2**30
# 302 : : * * all nNew addrinfos in vvNew
# 303 : : * * all nTried addrinfos in vvTried
# 304 : : * * for each bucket:
# 305 : : * * number of elements
# 306 : : * * for each element: index
# 307 : : *
# 308 : : * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
# 309 : : * as incompatible. This is necessary because it did not check the version number on
# 310 : : * deserialization.
# 311 : : *
# 312 : : * Notice that vvTried, mapAddr and vVector are never encoded explicitly;
# 313 : : * they are instead reconstructed from the other information.
# 314 : : *
# 315 : : * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change,
# 316 : : * otherwise it is reconstructed as well.
# 317 : : *
# 318 : : * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
# 319 : : * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
# 320 : : *
# 321 : : * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
# 322 : : * very little in common.
# 323 : : */
# 324 : : template <typename Stream>
# 325 : : void Serialize(Stream& s_) const
# 326 : 1624 : {
# 327 : 1624 : LOCK(cs);
# 328 : :
# 329 : : // Always serialize in the latest version (currently Format::V3_BIP155).
# 330 : :
# 331 : 1624 : OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
# 332 : :
# 333 : 1624 : s << static_cast<uint8_t>(Format::V3_BIP155);
# 334 : 1624 : s << ((unsigned char)32);
# 335 : 1624 : s << nKey;
# 336 : 1624 : s << nNew;
# 337 : 1624 : s << nTried;
# 338 : :
# 339 : 1624 : int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
# 340 : 1624 : s << nUBuckets;
# 341 : 1624 : std::map<int, int> mapUnkIds;
# 342 : 1624 : int nIds = 0;
# 343 : 35404 : for (const auto& entry : mapInfo) {
# 344 : 35404 : mapUnkIds[entry.first] = nIds;
# 345 : 35404 : const CAddrInfo &info = entry.second;
# 346 : 35404 : if (info.nRefCount) {
# 347 : 35404 : assert(nIds != nNew); // this means nNew was wrong, oh ow
# 348 : 35404 : s << info;
# 349 : 35404 : nIds++;
# 350 : 35404 : }
# 351 : 35404 : }
# 352 : 1624 : nIds = 0;
# 353 : 35404 : for (const auto& entry : mapInfo) {
# 354 : 35404 : const CAddrInfo &info = entry.second;
# 355 : 35404 : if (info.fInTried) {
# 356 : 0 : assert(nIds != nTried); // this means nTried was wrong, oh ow
# 357 : 0 : s << info;
# 358 : 0 : nIds++;
# 359 : 0 : }
# 360 : 35404 : }
# 361 : 1664600 : for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# 362 : 1662976 : int nSize = 0;
# 363 : 108093440 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 364 : 106430464 : if (vvNew[bucket][i] != -1)
# 365 : 35404 : nSize++;
# 366 : 106430464 : }
# 367 : 1662976 : s << nSize;
# 368 : 108093440 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 369 : 106430464 : if (vvNew[bucket][i] != -1) {
# 370 : 35404 : int nIndex = mapUnkIds[vvNew[bucket][i]];
# 371 : 35404 : s << nIndex;
# 372 : 35404 : }
# 373 : 106430464 : }
# 374 : 1662976 : }
# 375 : : // Store asmap version after bucket entries so that it
# 376 : : // can be ignored by older clients for backward compatibility.
# 377 : 1624 : uint256 asmap_version;
# 378 : 1624 : if (m_asmap.size() != 0) {
# 379 : 12 : asmap_version = SerializeHash(m_asmap);
# 380 : 12 : }
# 381 : 1624 : s << asmap_version;
# 382 : 1624 : }
# 383 : :
# 384 : : template <typename Stream>
# 385 : : void Unserialize(Stream& s_)
# 386 : 205 : {
# 387 : 205 : LOCK(cs);
# 388 : :
# 389 : 205 : Clear();
# 390 : :
# 391 : 205 : Format format;
# 392 : 205 : s_ >> Using<CustomUintFormatter<1>>(format);
# 393 : :
# 394 : 205 : int stream_version = s_.GetVersion();
# 395 : 205 : if (format >= Format::V3_BIP155) {
# 396 : : // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
# 397 : : // unserialize methods know that an address in addrv2 format is coming.
# 398 : 201 : stream_version |= ADDRV2_FORMAT;
# 399 : 201 : }
# 400 : :
# 401 : 205 : OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
# 402 : :
# 403 : 205 : unsigned char nKeySize;
# 404 : 205 : s >> nKeySize;
# 405 : 205 : if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
# 406 : 205 : s >> nKey;
# 407 : 205 : s >> nNew;
# 408 : 205 : s >> nTried;
# 409 : 205 : int nUBuckets = 0;
# 410 : 205 : s >> nUBuckets;
# 411 : 205 : if (format >= Format::V1_DETERMINISTIC) {
# 412 : 205 : nUBuckets ^= (1 << 30);
# 413 : 205 : }
# 414 : :
# 415 : 205 : if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# 416 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
# 417 : 0 : }
# 418 : :
# 419 : 205 : if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# 420 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
# 421 : 0 : }
# 422 : :
# 423 : : // Deserialize entries from the new table.
# 424 : 235 : for (int n = 0; n < nNew; n++) {
# 425 : 30 : CAddrInfo &info = mapInfo[n];
# 426 : 30 : s >> info;
# 427 : 30 : mapAddr[info] = n;
# 428 : 30 : info.nRandomPos = vRandom.size();
# 429 : 30 : vRandom.push_back(n);
# 430 : 30 : }
# 431 : 205 : nIdCount = nNew;
# 432 : :
# 433 : : // Deserialize entries from the tried table.
# 434 : 205 : int nLost = 0;
# 435 : 205 : for (int n = 0; n < nTried; n++) {
# 436 : 0 : CAddrInfo info;
# 437 : 0 : s >> info;
# 438 : 0 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
# 439 : 0 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
# 440 : 0 : if (vvTried[nKBucket][nKBucketPos] == -1) {
# 441 : 0 : info.nRandomPos = vRandom.size();
# 442 : 0 : info.fInTried = true;
# 443 : 0 : vRandom.push_back(nIdCount);
# 444 : 0 : mapInfo[nIdCount] = info;
# 445 : 0 : mapAddr[info] = nIdCount;
# 446 : 0 : vvTried[nKBucket][nKBucketPos] = nIdCount;
# 447 : 0 : nIdCount++;
# 448 : 0 : } else {
# 449 : 0 : nLost++;
# 450 : 0 : }
# 451 : 0 : }
# 452 : 205 : nTried -= nLost;
# 453 : :
# 454 : : // Store positions in the new table buckets to apply later (if possible).
# 455 : 205 : std::map<int, int> entryToBucket; // Represents which entry belonged to which bucket when serializing
# 456 : :
# 457 : 206029 : for (int bucket = 0; bucket < nUBuckets; bucket++) {
# 458 : 205824 : int nSize = 0;
# 459 : 205824 : s >> nSize;
# 460 : 205846 : for (int n = 0; n < nSize; n++) {
# 461 : 22 : int nIndex = 0;
# 462 : 22 : s >> nIndex;
# 463 : 22 : if (nIndex >= 0 && nIndex < nNew) {
# 464 : 22 : entryToBucket[nIndex] = bucket;
# 465 : 22 : }
# 466 : 22 : }
# 467 : 205824 : }
# 468 : :
# 469 : 205 : uint256 supplied_asmap_version;
# 470 : 205 : if (m_asmap.size() != 0) {
# 471 : 10 : supplied_asmap_version = SerializeHash(m_asmap);
# 472 : 10 : }
# 473 : 205 : uint256 serialized_asmap_version;
# 474 : 205 : if (format >= Format::V2_ASMAP) {
# 475 : 201 : s >> serialized_asmap_version;
# 476 : 201 : }
# 477 : :
# 478 : 227 : for (int n = 0; n < nNew; n++) {
# 479 : 22 : CAddrInfo &info = mapInfo[n];
# 480 : 22 : int bucket = entryToBucket[n];
# 481 : 22 : int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
# 482 : 22 : if (format >= Format::V2_ASMAP && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 &&
# 483 : 22 : info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) {
# 484 : : // Bucketing has not changed, using existing bucket positions for the new table
# 485 : 14 : vvNew[bucket][nUBucketPos] = n;
# 486 : 14 : info.nRefCount++;
# 487 : 8 : } else {
# 488 : : // In case the new table data cannot be used (format unknown, bucket count wrong or new asmap),
# 489 : : // try to give them a reference based on their primary source address.
# 490 : 8 : LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
# 491 : 8 : bucket = info.GetNewBucket(nKey, m_asmap);
# 492 : 8 : nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
# 493 : 8 : if (vvNew[bucket][nUBucketPos] == -1) {
# 494 : 8 : vvNew[bucket][nUBucketPos] = n;
# 495 : 8 : info.nRefCount++;
# 496 : 8 : }
# 497 : 8 : }
# 498 : 22 : }
# 499 : :
# 500 : : // Prune new entries with refcount 0 (as a result of collisions).
# 501 : 205 : int nLostUnk = 0;
# 502 : 227 : for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
# 503 : 22 : if (it->second.fInTried == false && it->second.nRefCount == 0) {
# 504 : 0 : std::map<int, CAddrInfo>::const_iterator itCopy = it++;
# 505 : 0 : Delete(itCopy->first);
# 506 : 0 : nLostUnk++;
# 507 : 22 : } else {
# 508 : 22 : it++;
# 509 : 22 : }
# 510 : 22 : }
# 511 : 205 : if (nLost + nLostUnk > 0) {
# 512 : 0 : LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
# 513 : 0 : }
# 514 : :
# 515 : 205 : Check();
# 516 : 205 : }
# 517 : :
# 518 : : void Clear()
# 519 : 1243 : {
# 520 : 1243 : LOCK(cs);
# 521 : 1243 : std::vector<int>().swap(vRandom);
# 522 : 1243 : nKey = insecure_rand.rand256();
# 523 : 1274075 : for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# 524 : 82734080 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 525 : 81461248 : vvNew[bucket][entry] = -1;
# 526 : 81461248 : }
# 527 : 1272832 : }
# 528 : 319451 : for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
# 529 : 20683520 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 530 : 20365312 : vvTried[bucket][entry] = -1;
# 531 : 20365312 : }
# 532 : 318208 : }
# 533 : :
# 534 : 1243 : nIdCount = 0;
# 535 : 1243 : nTried = 0;
# 536 : 1243 : nNew = 0;
# 537 : 1243 : nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
# 538 : 1243 : mapInfo.clear();
# 539 : 1243 : mapAddr.clear();
# 540 : 1243 : }
# 541 : :
# 542 : : CAddrMan()
# 543 : 719 : {
# 544 : 719 : Clear();
# 545 : 719 : }
# 546 : :
# 547 : : ~CAddrMan()
# 548 : 719 : {
# 549 : 719 : nKey.SetNull();
# 550 : 719 : }
# 551 : :
# 552 : : //! Return the number of (unique) addresses in all tables.
# 553 : : size_t size() const
# 554 : 29786 : {
# 555 : 29786 : LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
# 556 : 29786 : return vRandom.size();
# 557 : 29786 : }
# 558 : :
# 559 : : //! Consistency check
# 560 : : void Check()
# 561 : 143123 : {
# 562 : : #ifdef DEBUG_ADDRMAN
# 563 : : {
# 564 : : LOCK(cs);
# 565 : : int err;
# 566 : : if ((err=Check_()))
# 567 : : LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
# 568 : : }
# 569 : : #endif
# 570 : 143123 : }
# 571 : :
# 572 : : //! Add a single address.
# 573 : : bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 574 : 4510 : {
# 575 : 4510 : LOCK(cs);
# 576 : 4510 : bool fRet = false;
# 577 : 4510 : Check();
# 578 : 4510 : fRet |= Add_(addr, source, nTimePenalty);
# 579 : 4510 : Check();
# 580 : 4510 : if (fRet) {
# 581 : 4452 : LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
# 582 : 4452 : }
# 583 : 4510 : return fRet;
# 584 : 4510 : }
# 585 : :
# 586 : : //! Add multiple addresses.
# 587 : : bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 588 : 20032 : {
# 589 : 20032 : LOCK(cs);
# 590 : 20032 : int nAdd = 0;
# 591 : 20032 : Check();
# 592 : 40060 : for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
# 593 : 20028 : nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
# 594 : 20032 : Check();
# 595 : 20032 : if (nAdd) {
# 596 : 18981 : LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
# 597 : 18981 : }
# 598 : 20032 : return nAdd > 0;
# 599 : 20032 : }
# 600 : :
# 601 : : //! Mark an entry as accessible.
# 602 : : void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
# 603 : 1131 : {
# 604 : 1131 : LOCK(cs);
# 605 : 1131 : Check();
# 606 : 1131 : Good_(addr, test_before_evict, nTime);
# 607 : 1131 : Check();
# 608 : 1131 : }
# 609 : :
# 610 : : //! Mark an entry as connection attempted to.
# 611 : : void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
# 612 : 260 : {
# 613 : 260 : LOCK(cs);
# 614 : 260 : Check();
# 615 : 260 : Attempt_(addr, fCountFailure, nTime);
# 616 : 260 : Check();
# 617 : 260 : }
# 618 : :
# 619 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 620 : : void ResolveCollisions()
# 621 : 11982 : {
# 622 : 11982 : LOCK(cs);
# 623 : 11982 : Check();
# 624 : 11982 : ResolveCollisions_();
# 625 : 11982 : Check();
# 626 : 11982 : }
# 627 : :
# 628 : : //! Randomly select an address in tried that another address is attempting to evict.
# 629 : : CAddrInfo SelectTriedCollision()
# 630 : 16509 : {
# 631 : 16509 : CAddrInfo ret;
# 632 : 16509 : {
# 633 : 16509 : LOCK(cs);
# 634 : 16509 : Check();
# 635 : 16509 : ret = SelectTriedCollision_();
# 636 : 16509 : Check();
# 637 : 16509 : }
# 638 : 16509 : return ret;
# 639 : 16509 : }
# 640 : :
# 641 : : /**
# 642 : : * Choose an address to connect to.
# 643 : : */
# 644 : : CAddrInfo Select(bool newOnly = false)
# 645 : 16347 : {
# 646 : 16347 : CAddrInfo addrRet;
# 647 : 16347 : {
# 648 : 16347 : LOCK(cs);
# 649 : 16347 : Check();
# 650 : 16347 : addrRet = Select_(newOnly);
# 651 : 16347 : Check();
# 652 : 16347 : }
# 653 : 16347 : return addrRet;
# 654 : 16347 : }
# 655 : :
# 656 : : //! Return a bunch of addresses, selected at random.
# 657 : : std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct)
# 658 : 205 : {
# 659 : 205 : Check();
# 660 : 205 : std::vector<CAddress> vAddr;
# 661 : 205 : {
# 662 : 205 : LOCK(cs);
# 663 : 205 : GetAddr_(vAddr, max_addresses, max_pct);
# 664 : 205 : }
# 665 : 205 : Check();
# 666 : 205 : return vAddr;
# 667 : 205 : }
# 668 : :
# 669 : : //! Mark an entry as currently-connected-to.
# 670 : : void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
# 671 : 242 : {
# 672 : 242 : LOCK(cs);
# 673 : 242 : Check();
# 674 : 242 : Connected_(addr, nTime);
# 675 : 242 : Check();
# 676 : 242 : }
# 677 : :
# 678 : : void SetServices(const CService &addr, ServiceFlags nServices)
# 679 : 243 : {
# 680 : 243 : LOCK(cs);
# 681 : 243 : Check();
# 682 : 243 : SetServices_(addr, nServices);
# 683 : 243 : Check();
# 684 : 243 : }
# 685 : :
# 686 : : };
# 687 : :
# 688 : : #endif // BITCOIN_ADDRMAN_H
|