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 <config/bitcoin-config.h>
# 11 : : #include <netaddress.h>
# 12 : : #include <protocol.h>
# 13 : : #include <random.h>
# 14 : : #include <sync.h>
# 15 : : #include <timedata.h>
# 16 : : #include <tinyformat.h>
# 17 : : #include <util/system.h>
# 18 : :
# 19 : : #include <fs.h>
# 20 : : #include <hash.h>
# 21 : : #include <iostream>
# 22 : : #include <map>
# 23 : : #include <optional>
# 24 : : #include <set>
# 25 : : #include <stdint.h>
# 26 : : #include <streams.h>
# 27 : : #include <vector>
# 28 : :
# 29 : : /**
# 30 : : * Extended statistics about a CAddress
# 31 : : */
# 32 : : class CAddrInfo : public CAddress
# 33 : : {
# 34 : : public:
# 35 : : //! last try whatsoever by us (memory only)
# 36 : : int64_t nLastTry{0};
# 37 : :
# 38 : : //! last counted attempt (memory only)
# 39 : : int64_t nLastCountAttempt{0};
# 40 : :
# 41 : : private:
# 42 : : //! where knowledge about this address first came from
# 43 : : CNetAddr source;
# 44 : :
# 45 : : //! last successful connection by us
# 46 : : int64_t nLastSuccess{0};
# 47 : :
# 48 : : //! connection attempts since last successful attempt
# 49 : : int nAttempts{0};
# 50 : :
# 51 : : //! reference count in new sets (memory only)
# 52 : : int nRefCount{0};
# 53 : :
# 54 : : //! in tried set? (memory only)
# 55 : : bool fInTried{false};
# 56 : :
# 57 : : //! position in vRandom
# 58 : : int nRandomPos{-1};
# 59 : :
# 60 : : friend class CAddrMan;
# 61 : :
# 62 : : public:
# 63 : :
# 64 : : SERIALIZE_METHODS(CAddrInfo, obj)
# 65 : 65373 : {
# 66 : 65373 : READWRITEAS(CAddress, obj);
# 67 : 65373 : READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
# 68 : 65373 : }
# 69 : :
# 70 : : CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
# 71 : 32921 : {
# 72 : 32921 : }
# 73 : :
# 74 : : CAddrInfo() : CAddress(), source()
# 75 : 106727 : {
# 76 : 106727 : }
# 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 : 6660 : {
# 87 : 6660 : return GetNewBucket(nKey, source, asmap);
# 88 : 6660 : }
# 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 : : /** Stochastic address manager
# 101 : : *
# 102 : : * Design goals:
# 103 : : * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
# 104 : : * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
# 105 : : *
# 106 : : * To that end:
# 107 : : * * Addresses are organized into buckets.
# 108 : : * * Addresses that have not yet been tried go into 1024 "new" buckets.
# 109 : : * * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.
# 110 : : * * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
# 111 : : * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
# 112 : : * are seen frequently. The chance for increasing this multiplicity decreases exponentially.
# 113 : : * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
# 114 : : * ones) is removed from it first.
# 115 : : * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
# 116 : : * * Each address range selects at random 8 of these buckets.
# 117 : : * * The actual bucket is chosen from one of these, based on the full address.
# 118 : : * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
# 119 : : * tried ones) is evicted from it, back to the "new" buckets.
# 120 : : * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
# 121 : : * be observable by adversaries.
# 122 : : * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
# 123 : : * consistency checks for the entire data structure.
# 124 : : */
# 125 : :
# 126 : : //! total number of buckets for tried addresses
# 127 : 45303497 : #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
# 128 : :
# 129 : : //! total number of buckets for new addresses
# 130 : 625829459 : #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
# 131 : :
# 132 : : //! maximum allowed number of entries in buckets for new and tried addresses
# 133 :14279565444 : #define ADDRMAN_BUCKET_SIZE_LOG2 6
# 134 : :
# 135 : : //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
# 136 : 1181214 : #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
# 137 : :
# 138 : : //! over how many buckets entries with new addresses originating from a single group are spread
# 139 : 30891 : #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
# 140 : :
# 141 : : //! in how many buckets for entries with new addresses a single address may occur
# 142 : 284376937 : #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
# 143 : :
# 144 : : //! how old addresses can maximally be
# 145 : 22081 : #define ADDRMAN_HORIZON_DAYS 30
# 146 : :
# 147 : : //! after how many failed attempts we give up on a new node
# 148 : 22037 : #define ADDRMAN_RETRIES 3
# 149 : :
# 150 : : //! how many successive failures are allowed ...
# 151 : 22037 : #define ADDRMAN_MAX_FAILURES 10
# 152 : :
# 153 : : //! ... in at least this many days
# 154 : 22079 : #define ADDRMAN_MIN_FAIL_DAYS 7
# 155 : :
# 156 : : //! how recent a successful connection should be before we allow an address to be evicted from tried
# 157 : 12 : #define ADDRMAN_REPLACEMENT_HOURS 4
# 158 : :
# 159 : : //! Convenience
# 160 : 43728147 : #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
# 161 : 396516682 : #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
# 162 :14048677052 : #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
# 163 : :
# 164 : : //! the maximum number of tried addr collisions to store
# 165 : 30 : #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
# 166 : :
# 167 : : //! the maximum time we'll spend trying to resolve a tried table collision, in seconds
# 168 : : static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
# 169 : :
# 170 : : /**
# 171 : : * Stochastical (IP) address manager
# 172 : : */
# 173 : : class CAddrMan
# 174 : : {
# 175 : : public:
# 176 : : // Compressed IP->ASN mapping, loaded from a file when a node starts.
# 177 : : // Should be always empty if no file was provided.
# 178 : : // This mapping is then used for bucketing nodes in Addrman.
# 179 : : //
# 180 : : // If asmap is provided, nodes will be bucketed by
# 181 : : // AS they belong to, in order to make impossible for a node
# 182 : : // to connect to several nodes hosted in a single AS.
# 183 : : // This is done in response to Erebus attack, but also to generally
# 184 : : // diversify the connections every node creates,
# 185 : : // especially useful when a large fraction of nodes
# 186 : : // operate under a couple of cloud providers.
# 187 : : //
# 188 : : // If a new asmap was provided, the existing records
# 189 : : // would be re-bucketed accordingly.
# 190 : : std::vector<bool> m_asmap;
# 191 : :
# 192 : : // Read asmap from provided binary file
# 193 : : static std::vector<bool> DecodeAsmap(fs::path path);
# 194 : :
# 195 : : /**
# 196 : : * Serialized format.
# 197 : : * * format version byte (@see `Format`)
# 198 : : * * lowest compatible format version byte. This is used to help old software decide
# 199 : : * whether to parse the file. For example:
# 200 : : * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
# 201 : : * introduced in version N+1 that is compatible with format=3 and it is known that
# 202 : : * version N will be able to parse it, then version N+1 will write
# 203 : : * (format=4, lowest_compatible=3) in the first two bytes of the file, and so
# 204 : : * version N will still try to parse it.
# 205 : : * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
# 206 : : * (format=5, lowest_compatible=5) and so any versions that do not know how to parse
# 207 : : * format=5 will not try to read the file.
# 208 : : * * nKey
# 209 : : * * nNew
# 210 : : * * nTried
# 211 : : * * number of "new" buckets XOR 2**30
# 212 : : * * all new addresses (total count: nNew)
# 213 : : * * all tried addresses (total count: nTried)
# 214 : : * * for each new bucket:
# 215 : : * * number of elements
# 216 : : * * for each element: index in the serialized "all new addresses"
# 217 : : * * asmap checksum
# 218 : : *
# 219 : : * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
# 220 : : * as incompatible. This is necessary because it did not check the version number on
# 221 : : * deserialization.
# 222 : : *
# 223 : : * vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
# 224 : : * they are instead reconstructed from the other information.
# 225 : : *
# 226 : : * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
# 227 : : * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
# 228 : : *
# 229 : : * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
# 230 : : * very little in common.
# 231 : : */
# 232 : : template <typename Stream>
# 233 : : void Serialize(Stream& s_) const
# 234 : 2004 : {
# 235 : 2004 : LOCK(cs);
# 236 : :
# 237 : : // Always serialize in the latest version (FILE_FORMAT).
# 238 : :
# 239 : 2004 : OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
# 240 : :
# 241 : 2004 : s << static_cast<uint8_t>(FILE_FORMAT);
# 242 : :
# 243 : : // Increment `lowest_compatible` iff a newly introduced format is incompatible with
# 244 : : // the previous one.
# 245 : 2004 : static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
# 246 : 2004 : s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
# 247 : :
# 248 : 2004 : s << nKey;
# 249 : 2004 : s << nNew;
# 250 : 2004 : s << nTried;
# 251 : :
# 252 : 2004 : int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
# 253 : 2004 : s << nUBuckets;
# 254 : 2004 : std::map<int, int> mapUnkIds;
# 255 : 2004 : int nIds = 0;
# 256 [ + + ][ + + ]: 64563 : for (const auto& entry : mapInfo) {
# [ + + ]
# 257 : 64563 : mapUnkIds[entry.first] = nIds;
# 258 : 64563 : const CAddrInfo &info = entry.second;
# 259 [ + - ][ + - ]: 64563 : if (info.nRefCount) {
# [ + + ]
# 260 : 64553 : assert(nIds != nNew); // this means nNew was wrong, oh ow
# 261 : 64553 : s << info;
# 262 : 64553 : nIds++;
# 263 : 64553 : }
# 264 : 64563 : }
# 265 : 2004 : nIds = 0;
# 266 [ + + ][ + + ]: 64563 : for (const auto& entry : mapInfo) {
# [ + + ]
# 267 : 64563 : const CAddrInfo &info = entry.second;
# 268 [ - + ][ + + ]: 64563 : if (info.fInTried) {
# [ - + ]
# 269 : 10 : assert(nIds != nTried); // this means nTried was wrong, oh ow
# 270 : 10 : s << info;
# 271 : 10 : nIds++;
# 272 : 10 : }
# 273 : 64563 : }
# 274 [ + + ][ + + ]: 2054100 : for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# [ + + ]
# 275 : 2052096 : int nSize = 0;
# 276 [ + + ][ + + ]: 133386240 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# [ + + ]
# 277 [ + + ][ + + ]: 131334144 : if (vvNew[bucket][i] != -1)
# [ + + ]
# 278 : 64553 : nSize++;
# 279 : 131334144 : }
# 280 : 2052096 : s << nSize;
# 281 [ + + ][ + + ]: 133386240 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# [ + + ]
# 282 [ + + ][ + + ]: 131334144 : if (vvNew[bucket][i] != -1) {
# [ + + ]
# 283 : 64553 : int nIndex = mapUnkIds[vvNew[bucket][i]];
# 284 : 64553 : s << nIndex;
# 285 : 64553 : }
# 286 : 131334144 : }
# 287 : 2052096 : }
# 288 : : // Store asmap checksum after bucket entries so that it
# 289 : : // can be ignored by older clients for backward compatibility.
# 290 : 2004 : uint256 asmap_checksum;
# 291 [ + + ][ + + ]: 2004 : if (m_asmap.size() != 0) {
# [ + + ]
# 292 : 12 : asmap_checksum = SerializeHash(m_asmap);
# 293 : 12 : }
# 294 : 2004 : s << asmap_checksum;
# 295 : 2004 : }
# 296 : :
# 297 : : template <typename Stream>
# 298 : : void Unserialize(Stream& s_)
# 299 : 265 : {
# 300 : 265 : LOCK(cs);
# 301 : :
# 302 : 265 : Clear();
# 303 : :
# 304 : 265 : Format format;
# 305 : 265 : s_ >> Using<CustomUintFormatter<1>>(format);
# 306 : :
# 307 : 265 : int stream_version = s_.GetVersion();
# 308 [ + + ][ + - ]: 265 : if (format >= Format::V3_BIP155) {
# [ + + ]
# 309 : : // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
# 310 : : // unserialize methods know that an address in addrv2 format is coming.
# 311 : 261 : stream_version |= ADDRV2_FORMAT;
# 312 : 261 : }
# 313 : :
# 314 : 265 : OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
# 315 : :
# 316 : 265 : uint8_t compat;
# 317 : 265 : s >> compat;
# 318 : 265 : const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
# 319 [ - + ][ - + ]: 265 : if (lowest_compatible > FILE_FORMAT) {
# [ - + ]
# 320 : 0 : throw std::ios_base::failure(strprintf(
# 321 : 0 : "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
# 322 : 0 : "but the maximum supported by this version of %s is %u.",
# 323 : 0 : format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
# 324 : 0 : }
# 325 : :
# 326 : 265 : s >> nKey;
# 327 : 265 : s >> nNew;
# 328 : 265 : s >> nTried;
# 329 : 265 : int nUBuckets = 0;
# 330 : 265 : s >> nUBuckets;
# 331 [ + - ][ + - ]: 265 : if (format >= Format::V1_DETERMINISTIC) {
# [ + - ]
# 332 : 265 : nUBuckets ^= (1 << 30);
# 333 : 265 : }
# 334 : :
# 335 [ - + ][ - + ]: 265 : if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# [ - + ]
# 336 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
# 337 : 0 : }
# 338 : :
# 339 [ - + ][ - + ]: 265 : if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
# [ - + ]
# 340 : 0 : throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
# 341 : 0 : }
# 342 : :
# 343 : : // Deserialize entries from the new table.
# 344 [ + + ][ + + ]: 1061 : for (int n = 0; n < nNew; n++) {
# [ + + ]
# 345 : 796 : CAddrInfo &info = mapInfo[n];
# 346 : 796 : s >> info;
# 347 : 796 : mapAddr[info] = n;
# 348 : 796 : info.nRandomPos = vRandom.size();
# 349 : 796 : vRandom.push_back(n);
# 350 : 796 : }
# 351 : 265 : nIdCount = nNew;
# 352 : :
# 353 : : // Deserialize entries from the tried table.
# 354 : 265 : int nLost = 0;
# 355 [ - + ][ - + ]: 275 : for (int n = 0; n < nTried; n++) {
# [ + + ]
# 356 : 10 : CAddrInfo info;
# 357 : 10 : s >> info;
# 358 : 10 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
# 359 : 10 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
# 360 [ # # ][ # # ]: 10 : if (vvTried[nKBucket][nKBucketPos] == -1) {
# [ + - ]
# 361 : 10 : info.nRandomPos = vRandom.size();
# 362 : 10 : info.fInTried = true;
# 363 : 10 : vRandom.push_back(nIdCount);
# 364 : 10 : mapInfo[nIdCount] = info;
# 365 : 10 : mapAddr[info] = nIdCount;
# 366 : 10 : vvTried[nKBucket][nKBucketPos] = nIdCount;
# 367 : 10 : nIdCount++;
# 368 : 10 : } else {
# 369 : 0 : nLost++;
# 370 : 0 : }
# 371 : 10 : }
# 372 : 265 : nTried -= nLost;
# 373 : :
# 374 : : // Store positions in the new table buckets to apply later (if possible).
# 375 : : // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
# 376 : : // so we store all bucket-entry_index pairs to iterate through later.
# 377 : 265 : std::vector<std::pair<int, int>> bucket_entries;
# 378 : :
# 379 [ + + ][ + + ]: 267529 : for (int bucket = 0; bucket < nUBuckets; ++bucket) {
# [ + + ]
# 380 : 267264 : int num_entries{0};
# 381 : 267264 : s >> num_entries;
# 382 [ + + ][ + + ]: 268052 : for (int n = 0; n < num_entries; ++n) {
# [ + + ]
# 383 : 788 : int entry_index{0};
# 384 : 788 : s >> entry_index;
# 385 [ + - ][ + - ]: 788 : if (entry_index >= 0 && entry_index < nNew) {
# [ + - ][ + - ]
# [ + - ][ + - ]
# 386 : 788 : bucket_entries.emplace_back(bucket, entry_index);
# 387 : 788 : }
# 388 : 788 : }
# 389 : 267264 : }
# 390 : :
# 391 : : // If the bucket count and asmap checksum haven't changed, then attempt
# 392 : : // to restore the entries to the buckets/positions they were in before
# 393 : : // serialization.
# 394 : 265 : uint256 supplied_asmap_checksum;
# 395 [ + + ][ + + ]: 265 : if (m_asmap.size() != 0) {
# [ - + ]
# 396 : 10 : supplied_asmap_checksum = SerializeHash(m_asmap);
# 397 : 10 : }
# 398 : 265 : uint256 serialized_asmap_checksum;
# 399 [ + - ][ + + ]: 265 : if (format >= Format::V2_ASMAP) {
# [ + + ]
# 400 : 261 : s >> serialized_asmap_checksum;
# 401 : 261 : }
# 402 [ + + ][ + - ]: 265 : const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
# [ + + ]
# 403 [ + + ][ + - ]: 265 : serialized_asmap_checksum == supplied_asmap_checksum};
# [ + + ]
# 404 : :
# 405 [ - + ][ + + ]: 265 : if (!restore_bucketing) {
# [ + + ]
# 406 [ + - ][ # # ]: 7 : LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
# [ + - ]
# 407 : 7 : }
# 408 : :
# 409 [ + + ][ + + ]: 788 : for (auto bucket_entry : bucket_entries) {
# [ + + ]
# 410 : 788 : int bucket{bucket_entry.first};
# 411 : 788 : const int entry_index{bucket_entry.second};
# 412 : 788 : CAddrInfo& info = mapInfo[entry_index];
# 413 : :
# 414 : : // The entry shouldn't appear in more than
# 415 : : // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
# 416 : : // this bucket_entry.
# 417 [ - + ][ - + ]: 788 : if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
# [ - + ]
# 418 : :
# 419 : 788 : int bucket_position = info.GetBucketPosition(nKey, true, bucket);
# 420 [ + - ][ + + ]: 788 : if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
# [ + - ][ + - ]
# [ + - ][ + - ]
# 421 : : // Bucketing has not changed, using existing bucket positions for the new table
# 422 : 780 : vvNew[bucket][bucket_position] = entry_index;
# 423 : 780 : ++info.nRefCount;
# 424 : 780 : } else {
# 425 : : // In case the new table data cannot be used (bucket count wrong or new asmap),
# 426 : : // try to give them a reference based on their primary source address.
# 427 : 8 : bucket = info.GetNewBucket(nKey, m_asmap);
# 428 : 8 : bucket_position = info.GetBucketPosition(nKey, true, bucket);
# 429 [ # # ][ # # ]: 8 : if (vvNew[bucket][bucket_position] == -1) {
# [ + - ]
# 430 : 8 : vvNew[bucket][bucket_position] = entry_index;
# 431 : 8 : ++info.nRefCount;
# 432 : 8 : }
# 433 : 8 : }
# 434 : 788 : }
# 435 : :
# 436 : : // Prune new entries with refcount 0 (as a result of collisions).
# 437 : 265 : int nLostUnk = 0;
# 438 [ + + ][ + + ]: 1063 : for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
# [ + + ]
# 439 [ + - ][ + - ]: 798 : if (it->second.fInTried == false && it->second.nRefCount == 0) {
# [ + + ][ - + ]
# [ - + ][ - + ]
# 440 : 0 : std::map<int, CAddrInfo>::const_iterator itCopy = it++;
# 441 : 0 : Delete(itCopy->first);
# 442 : 0 : nLostUnk++;
# 443 : 798 : } else {
# 444 : 798 : it++;
# 445 : 798 : }
# 446 : 798 : }
# 447 [ - + ][ - + ]: 265 : if (nLost + nLostUnk > 0) {
# [ - + ]
# 448 [ # # ][ # # ]: 0 : LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
# [ # # ]
# 449 : 0 : }
# 450 : :
# 451 : 265 : ResetI2PPorts();
# 452 : :
# 453 : 265 : Check();
# 454 : 265 : }
# 455 : :
# 456 : : void Clear()
# 457 : 1492 : {
# 458 : 1492 : LOCK(cs);
# 459 : 1492 : std::vector<int>().swap(vRandom);
# 460 : 1492 : nKey = insecure_rand.rand256();
# 461 [ + + ]: 1529300 : for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# 462 [ + + ]: 99307520 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 463 : 97779712 : vvNew[bucket][entry] = -1;
# 464 : 97779712 : }
# 465 : 1527808 : }
# 466 [ + + ]: 383444 : for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
# 467 [ + + ]: 24826880 : for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
# 468 : 24444928 : vvTried[bucket][entry] = -1;
# 469 : 24444928 : }
# 470 : 381952 : }
# 471 : :
# 472 : 1492 : nIdCount = 0;
# 473 : 1492 : nTried = 0;
# 474 : 1492 : nNew = 0;
# 475 : 1492 : nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
# 476 : 1492 : mapInfo.clear();
# 477 : 1492 : mapAddr.clear();
# 478 : 1492 : }
# 479 : :
# 480 : : CAddrMan()
# 481 : 844 : {
# 482 : 844 : Clear();
# 483 : 844 : }
# 484 : :
# 485 : : ~CAddrMan()
# 486 : 844 : {
# 487 : 844 : nKey.SetNull();
# 488 : 844 : }
# 489 : :
# 490 : : //! Return the number of (unique) addresses in all tables.
# 491 : : size_t size() const
# 492 : 33055 : {
# 493 : 33055 : LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
# 494 : 33055 : return vRandom.size();
# 495 : 33055 : }
# 496 : :
# 497 : : //! Consistency check
# 498 : : void Check()
# 499 : 157667 : {
# 500 : 157667 : #ifdef DEBUG_ADDRMAN
# 501 : 157667 : {
# 502 : 157667 : LOCK(cs);
# 503 : 157667 : int err;
# 504 [ + + ]: 157667 : if ((err=Check_()))
# 505 : 157667 : LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
# 506 : 157667 : }
# 507 : 157667 : #endif
# 508 : 157667 : }
# 509 : :
# 510 : : //! Add a single address.
# 511 : : bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 512 : 25533 : {
# 513 : 25533 : LOCK(cs);
# 514 : 25533 : bool fRet = false;
# 515 : 25533 : Check();
# 516 : 25533 : fRet |= Add_(addr, source, nTimePenalty);
# 517 : 25533 : Check();
# 518 [ + + ]: 25533 : if (fRet) {
# 519 [ + - ]: 24194 : LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
# 520 : 24194 : }
# 521 : 25533 : return fRet;
# 522 : 25533 : }
# 523 : :
# 524 : : //! Add multiple addresses.
# 525 : : bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
# 526 : 15 : {
# 527 : 15 : LOCK(cs);
# 528 : 15 : int nAdd = 0;
# 529 : 15 : Check();
# 530 [ + + ]: 51 : for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
# 531 [ + + ]: 36 : nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
# 532 : 15 : Check();
# 533 [ + + ]: 15 : if (nAdd) {
# 534 [ + - ]: 9 : LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
# 535 : 9 : }
# 536 : 15 : return nAdd > 0;
# 537 : 15 : }
# 538 : :
# 539 : : //! Mark an entry as accessible.
# 540 : : void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
# 541 : 1244 : {
# 542 : 1244 : LOCK(cs);
# 543 : 1244 : Check();
# 544 : 1244 : Good_(addr, test_before_evict, nTime);
# 545 : 1244 : Check();
# 546 : 1244 : }
# 547 : :
# 548 : : //! Mark an entry as connection attempted to.
# 549 : : void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
# 550 : 546 : {
# 551 : 546 : LOCK(cs);
# 552 : 546 : Check();
# 553 : 546 : Attempt_(addr, fCountFailure, nTime);
# 554 : 546 : Check();
# 555 : 546 : }
# 556 : :
# 557 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 558 : : void ResolveCollisions()
# 559 : 18856 : {
# 560 : 18856 : LOCK(cs);
# 561 : 18856 : Check();
# 562 : 18856 : ResolveCollisions_();
# 563 : 18856 : Check();
# 564 : 18856 : }
# 565 : :
# 566 : : //! Randomly select an address in tried that another address is attempting to evict.
# 567 : : CAddrInfo SelectTriedCollision()
# 568 : 218 : {
# 569 : 218 : CAddrInfo ret;
# 570 : 218 : {
# 571 : 218 : LOCK(cs);
# 572 : 218 : Check();
# 573 : 218 : ret = SelectTriedCollision_();
# 574 : 218 : Check();
# 575 : 218 : }
# 576 : 218 : return ret;
# 577 : 218 : }
# 578 : :
# 579 : : /**
# 580 : : * Choose an address to connect to.
# 581 : : */
# 582 : : CAddrInfo Select(bool newOnly = false)
# 583 : 31338 : {
# 584 : 31338 : CAddrInfo addrRet;
# 585 : 31338 : {
# 586 : 31338 : LOCK(cs);
# 587 : 31338 : Check();
# 588 : 31338 : addrRet = Select_(newOnly);
# 589 : 31338 : Check();
# 590 : 31338 : }
# 591 : 31338 : return addrRet;
# 592 : 31338 : }
# 593 : :
# 594 : : /**
# 595 : : * Return all or many randomly selected addresses, optionally by network.
# 596 : : *
# 597 : : * @param[in] max_addresses Maximum number of addresses to return (0 = all).
# 598 : : * @param[in] max_pct Maximum percentage of addresses to return (0 = all).
# 599 : : * @param[in] network Select only addresses of this network (nullopt = all).
# 600 : : */
# 601 : : std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
# 602 : 257 : {
# 603 : 257 : Check();
# 604 : 257 : std::vector<CAddress> vAddr;
# 605 : 257 : {
# 606 : 257 : LOCK(cs);
# 607 : 257 : GetAddr_(vAddr, max_addresses, max_pct, network);
# 608 : 257 : }
# 609 : 257 : Check();
# 610 : 257 : return vAddr;
# 611 : 257 : }
# 612 : :
# 613 : : //! Outer function for Connected_()
# 614 : : void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
# 615 : 350 : {
# 616 : 350 : LOCK(cs);
# 617 : 350 : Check();
# 618 : 350 : Connected_(addr, nTime);
# 619 : 350 : Check();
# 620 : 350 : }
# 621 : :
# 622 : : void SetServices(const CService &addr, ServiceFlags nServices)
# 623 : 346 : {
# 624 : 346 : LOCK(cs);
# 625 : 346 : Check();
# 626 : 346 : SetServices_(addr, nServices);
# 627 : 346 : Check();
# 628 : 346 : }
# 629 : :
# 630 : : protected:
# 631 : : //! secret key to randomize bucket select with
# 632 : : uint256 nKey;
# 633 : :
# 634 : : //! Source of random numbers for randomization in inner loops
# 635 : : FastRandomContext insecure_rand;
# 636 : :
# 637 : : private:
# 638 : : //! critical section to protect the inner data structures
# 639 : : mutable RecursiveMutex cs;
# 640 : :
# 641 : : //! Serialization versions.
# 642 : : enum Format : uint8_t {
# 643 : : V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
# 644 : : V1_DETERMINISTIC = 1, //!< for pre-asmap files
# 645 : : V2_ASMAP = 2, //!< for files including asmap version
# 646 : : V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
# 647 : : };
# 648 : :
# 649 : : //! The maximum format this software knows it can unserialize. Also, we always serialize
# 650 : : //! in this format.
# 651 : : //! The format (first byte in the serialized stream) can be higher than this and
# 652 : : //! still this software may be able to unserialize the file - if the second byte
# 653 : : //! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
# 654 : : static constexpr Format FILE_FORMAT = Format::V3_BIP155;
# 655 : :
# 656 : : //! The initial value of a field that is incremented every time an incompatible format
# 657 : : //! change is made (such that old software versions would not be able to parse and
# 658 : : //! understand the new file format). This is 32 because we overtook the "key size"
# 659 : : //! field which was 32 historically.
# 660 : : //! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
# 661 : : static constexpr uint8_t INCOMPATIBILITY_BASE = 32;
# 662 : :
# 663 : : //! last used nId
# 664 : : int nIdCount GUARDED_BY(cs);
# 665 : :
# 666 : : //! table with information about all nIds
# 667 : : std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
# 668 : :
# 669 : : //! find an nId based on its network address
# 670 : : std::map<CNetAddr, int> mapAddr GUARDED_BY(cs);
# 671 : :
# 672 : : //! randomly-ordered vector of all nIds
# 673 : : std::vector<int> vRandom GUARDED_BY(cs);
# 674 : :
# 675 : : // number of "tried" entries
# 676 : : int nTried GUARDED_BY(cs);
# 677 : :
# 678 : : //! list of "tried" buckets
# 679 : : int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 680 : :
# 681 : : //! number of (unique) "new" entries
# 682 : : int nNew GUARDED_BY(cs);
# 683 : :
# 684 : : //! list of "new" buckets
# 685 : : int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
# 686 : :
# 687 : : //! last time Good was called (memory only)
# 688 : : int64_t nLastGood GUARDED_BY(cs);
# 689 : :
# 690 : : //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
# 691 : : std::set<int> m_tried_collisions;
# 692 : :
# 693 : : //! Find an entry.
# 694 : : CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 695 : :
# 696 : : //! find an entry, creating it if necessary.
# 697 : : //! nTime and nServices of the found node are updated, if necessary.
# 698 : : CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 699 : :
# 700 : : //! Swap two elements in vRandom.
# 701 : : void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 702 : :
# 703 : : //! Move an entry from the "new" table(s) to the "tried" table
# 704 : : void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 705 : :
# 706 : : //! Delete an entry. It must not be in tried, and have refcount 0.
# 707 : : void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 708 : :
# 709 : : //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
# 710 : : void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 711 : :
# 712 : : //! Mark an entry "good", possibly moving it from "new" to "tried".
# 713 : : void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 714 : :
# 715 : : //! Add an entry to the "new" table.
# 716 : : bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 717 : :
# 718 : : //! Mark an entry as attempted to connect.
# 719 : : void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 720 : :
# 721 : : //! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
# 722 : : CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 723 : :
# 724 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 725 : : void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 726 : :
# 727 : : //! Return a random to-be-evicted tried table address.
# 728 : : CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 729 : :
# 730 : : #ifdef DEBUG_ADDRMAN
# 731 : : //! Perform consistency check. Returns an error code or zero.
# 732 : : int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 733 : : #endif
# 734 : :
# 735 : : /**
# 736 : : * Return all or many randomly selected addresses, optionally by network.
# 737 : : *
# 738 : : * @param[out] vAddr Vector of randomly selected addresses from vRandom.
# 739 : : * @param[in] max_addresses Maximum number of addresses to return (0 = all).
# 740 : : * @param[in] max_pct Maximum percentage of addresses to return (0 = all).
# 741 : : * @param[in] network Select only addresses of this network (nullopt = all).
# 742 : : */
# 743 : : void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 744 : :
# 745 : : /** We have successfully connected to this peer. Calling this function
# 746 : : * updates the CAddress's nTime, which is used in our IsTerrible()
# 747 : : * decisions and gossiped to peers. Callers should be careful that updating
# 748 : : * this information doesn't leak topology information to network spies.
# 749 : : *
# 750 : : * net_processing calls this function when it *disconnects* from a peer to
# 751 : : * not leak information about currently connected peers.
# 752 : : *
# 753 : : * @param[in] addr The address of the peer we were connected to
# 754 : : * @param[in] nTime The time that we were last connected to this peer
# 755 : : */
# 756 : : void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 757 : :
# 758 : : //! Update an entry's service bits.
# 759 : : void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
# 760 : :
# 761 : : /**
# 762 : : * Reset the ports of I2P peers to 0.
# 763 : : * This is needed as a temporary measure because now we enforce port 0 and only connect
# 764 : : * to I2P hosts if the port is 0, but in the early days some I2P addresses got spread
# 765 : : * around with port 8333.
# 766 : : */
# 767 : : void ResetI2PPorts() EXCLUSIVE_LOCKS_REQUIRED(cs);
# 768 : :
# 769 : : friend class CAddrManTest;
# 770 : : };
# 771 : :
# 772 : : #endif // BITCOIN_ADDRMAN_H
|