Branch data Line data Source code
# 1 : : // Copyright (c) 2012 Pieter Wuille
# 2 : : // Copyright (c) 2012-2021 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 : : #include <addrman.h>
# 7 : : #include <addrman_impl.h>
# 8 : :
# 9 : : #include <hash.h>
# 10 : : #include <logging.h>
# 11 : : #include <logging/timer.h>
# 12 : : #include <netaddress.h>
# 13 : : #include <protocol.h>
# 14 : : #include <random.h>
# 15 : : #include <serialize.h>
# 16 : : #include <streams.h>
# 17 : : #include <timedata.h>
# 18 : : #include <tinyformat.h>
# 19 : : #include <uint256.h>
# 20 : : #include <util/check.h>
# 21 : :
# 22 : : #include <cmath>
# 23 : : #include <optional>
# 24 : :
# 25 : : /** Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread */
# 26 : : static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8};
# 27 : : /** Over how many buckets entries with new addresses originating from a single group are spread */
# 28 : : static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
# 29 : : /** Maximum number of times an address can occur in the new table */
# 30 : : static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
# 31 : : /** How old addresses can maximally be */
# 32 : : static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
# 33 : : /** After how many failed attempts we give up on a new node */
# 34 : : static constexpr int32_t ADDRMAN_RETRIES{3};
# 35 : : /** How many successive failures are allowed ... */
# 36 : : static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
# 37 : : /** ... in at least this many days */
# 38 : : static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7};
# 39 : : /** How recent a successful connection should be before we allow an address to be evicted from tried */
# 40 : : static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4};
# 41 : : /** The maximum number of tried addr collisions to store */
# 42 : : static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
# 43 : : /** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
# 44 : : static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
# 45 : :
# 46 : : int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const
# 47 : 13810 : {
# 48 : 13810 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
# 49 : 13810 : uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
# 50 : 13810 : return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
# 51 : 13810 : }
# 52 : :
# 53 : : int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
# 54 : 34066 : {
# 55 : 34066 : std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
# 56 : 34066 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
# 57 : 34066 : uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
# 58 : 34066 : return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
# 59 : 34066 : }
# 60 : :
# 61 : : int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
# 62 : 112646 : {
# 63 [ + + ]: 112646 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
# 64 : 112646 : return hash1 % ADDRMAN_BUCKET_SIZE;
# 65 : 112646 : }
# 66 : :
# 67 : : bool AddrInfo::IsTerrible(int64_t nNow) const
# 68 : 24061 : {
# 69 [ + + ][ + - ]: 24061 : if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
# 70 : 141 : return false;
# 71 : :
# 72 [ - + ]: 23920 : if (nTime > nNow + 10 * 60) // came in a flying DeLorean
# 73 : 0 : return true;
# 74 : :
# 75 [ - + ][ + + ]: 23920 : if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
# 76 : 2 : return true;
# 77 : :
# 78 [ + - ][ - + ]: 23918 : if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
# 79 : 0 : return true;
# 80 : :
# 81 [ + - ][ - + ]: 23918 : if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
# 82 : 0 : return true;
# 83 : :
# 84 : 23918 : return false;
# 85 : 23918 : }
# 86 : :
# 87 : : double AddrInfo::GetChance(int64_t nNow) const
# 88 : 264 : {
# 89 : 264 : double fChance = 1.0;
# 90 : 264 : int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
# 91 : :
# 92 : : // deprioritize very recent attempts away
# 93 [ + + ]: 264 : if (nSinceLastTry < 60 * 10)
# 94 : 230 : fChance *= 0.01;
# 95 : :
# 96 : : // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
# 97 : 264 : fChance *= pow(0.66, std::min(nAttempts, 8));
# 98 : :
# 99 : 264 : return fChance;
# 100 : 264 : }
# 101 : :
# 102 : : AddrManImpl::AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio)
# 103 : : : insecure_rand{deterministic}
# 104 : : , nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
# 105 : : , m_consistency_check_ratio{consistency_check_ratio}
# 106 : : , m_asmap{std::move(asmap)}
# 107 : 1441 : {
# 108 [ + + ]: 1475584 : for (auto& bucket : vvNew) {
# 109 [ + + ]: 94437376 : for (auto& entry : bucket) {
# 110 : 94437376 : entry = -1;
# 111 : 94437376 : }
# 112 : 1475584 : }
# 113 [ + + ]: 368896 : for (auto& bucket : vvTried) {
# 114 [ + + ]: 23609344 : for (auto& entry : bucket) {
# 115 : 23609344 : entry = -1;
# 116 : 23609344 : }
# 117 : 368896 : }
# 118 : 1441 : }
# 119 : :
# 120 : : AddrManImpl::~AddrManImpl()
# 121 : 1441 : {
# 122 : 1441 : nKey.SetNull();
# 123 : 1441 : }
# 124 : :
# 125 : : template <typename Stream>
# 126 : : void AddrManImpl::Serialize(Stream& s_) const
# 127 : 2306 : {
# 128 : 2306 : LOCK(cs);
# 129 : :
# 130 : : /**
# 131 : : * Serialized format.
# 132 : : * * format version byte (@see `Format`)
# 133 : : * * lowest compatible format version byte. This is used to help old software decide
# 134 : : * whether to parse the file. For example:
# 135 : : * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
# 136 : : * introduced in version N+1 that is compatible with format=3 and it is known that
# 137 : : * version N will be able to parse it, then version N+1 will write
# 138 : : * (format=4, lowest_compatible=3) in the first two bytes of the file, and so
# 139 : : * version N will still try to parse it.
# 140 : : * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
# 141 : : * (format=5, lowest_compatible=5) and so any versions that do not know how to parse
# 142 : : * format=5 will not try to read the file.
# 143 : : * * nKey
# 144 : : * * nNew
# 145 : : * * nTried
# 146 : : * * number of "new" buckets XOR 2**30
# 147 : : * * all new addresses (total count: nNew)
# 148 : : * * all tried addresses (total count: nTried)
# 149 : : * * for each new bucket:
# 150 : : * * number of elements
# 151 : : * * for each element: index in the serialized "all new addresses"
# 152 : : * * asmap checksum
# 153 : : *
# 154 : : * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
# 155 : : * as incompatible. This is necessary because it did not check the version number on
# 156 : : * deserialization.
# 157 : : *
# 158 : : * vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
# 159 : : * they are instead reconstructed from the other information.
# 160 : : *
# 161 : : * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
# 162 : : * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
# 163 : : *
# 164 : : * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
# 165 : : * very little in common.
# 166 : : */
# 167 : :
# 168 : : // Always serialize in the latest version (FILE_FORMAT).
# 169 : :
# 170 : 2306 : OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
# 171 : :
# 172 : 2306 : s << static_cast<uint8_t>(FILE_FORMAT);
# 173 : :
# 174 : : // Increment `lowest_compatible` iff a newly introduced format is incompatible with
# 175 : : // the previous one.
# 176 : 2306 : static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;
# 177 : 2306 : s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
# 178 : :
# 179 : 2306 : s << nKey;
# 180 : 2306 : s << nNew;
# 181 : 2306 : s << nTried;
# 182 : :
# 183 : 2306 : int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
# 184 : 2306 : s << nUBuckets;
# 185 : 2306 : std::unordered_map<int, int> mapUnkIds;
# 186 : 2306 : int nIds = 0;
# 187 [ + + ][ + + ]: 46328 : for (const auto& entry : mapInfo) {
# [ + + ]
# 188 : 46328 : mapUnkIds[entry.first] = nIds;
# 189 : 46328 : const AddrInfo& info = entry.second;
# 190 [ + + ][ + + ]: 46328 : if (info.nRefCount) {
# [ + + ]
# 191 : 46318 : assert(nIds != nNew); // this means nNew was wrong, oh ow
# 192 : 0 : s << info;
# 193 : 46318 : nIds++;
# 194 : 46318 : }
# 195 : 46328 : }
# 196 : 2306 : nIds = 0;
# 197 [ + + ][ + + ]: 46328 : for (const auto& entry : mapInfo) {
# [ + + ]
# 198 : 46328 : const AddrInfo& info = entry.second;
# 199 [ + + ][ + + ]: 46328 : if (info.fInTried) {
# [ + + ]
# 200 : 10 : assert(nIds != nTried); // this means nTried was wrong, oh ow
# 201 : 0 : s << info;
# 202 : 10 : nIds++;
# 203 : 10 : }
# 204 : 46328 : }
# 205 [ + + ][ + + ]: 2363650 : for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
# [ + + ]
# 206 : 2361344 : int nSize = 0;
# 207 [ + + ][ + + ]: 153487360 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# [ + + ]
# 208 [ + + ][ + + ]: 151126016 : if (vvNew[bucket][i] != -1)
# [ + + ]
# 209 : 46318 : nSize++;
# 210 : 151126016 : }
# 211 : 2361344 : s << nSize;
# 212 [ + + ][ + + ]: 153487360 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# [ + + ]
# 213 [ + + ][ + + ]: 151126016 : if (vvNew[bucket][i] != -1) {
# [ + + ]
# 214 : 46318 : int nIndex = mapUnkIds[vvNew[bucket][i]];
# 215 : 46318 : s << nIndex;
# 216 : 46318 : }
# 217 : 151126016 : }
# 218 : 2361344 : }
# 219 : : // Store asmap checksum after bucket entries so that it
# 220 : : // can be ignored by older clients for backward compatibility.
# 221 : 2306 : uint256 asmap_checksum;
# 222 [ + + ][ + + ]: 2306 : if (m_asmap.size() != 0) {
# [ + + ]
# 223 : 16 : asmap_checksum = SerializeHash(m_asmap);
# 224 : 16 : }
# 225 : 2306 : s << asmap_checksum;
# 226 : 2306 : }
# 227 : :
# 228 : : template <typename Stream>
# 229 : : void AddrManImpl::Unserialize(Stream& s_)
# 230 : 358 : {
# 231 : 358 : LOCK(cs);
# 232 : :
# 233 : 358 : assert(vRandom.empty());
# 234 : :
# 235 : 0 : Format format;
# 236 : 358 : s_ >> Using<CustomUintFormatter<1>>(format);
# 237 : :
# 238 : 358 : int stream_version = s_.GetVersion();
# 239 [ + + ][ # # ]: 358 : if (format >= Format::V3_BIP155) {
# [ + + ][ + + ]
# 240 : : // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
# 241 : : // unserialize methods know that an address in addrv2 format is coming.
# 242 : 346 : stream_version |= ADDRV2_FORMAT;
# 243 : 346 : }
# 244 : :
# 245 : 358 : OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
# 246 : :
# 247 : 358 : uint8_t compat;
# 248 : 358 : s >> compat;
# 249 [ - + ][ # # ]: 358 : if (compat < INCOMPATIBILITY_BASE) {
# [ + + ][ - + ]
# 250 : 1 : throw std::ios_base::failure(strprintf(
# 251 : 1 : "Corrupted addrman database: The compat value (%u) "
# 252 : 1 : "is lower than the expected minimum value %u.",
# 253 : 1 : compat, INCOMPATIBILITY_BASE));
# 254 : 1 : }
# 255 : 357 : const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
# 256 [ - + ][ - + ]: 357 : if (lowest_compatible > FILE_FORMAT) {
# [ # # ][ + + ]
# 257 : 1 : throw InvalidAddrManVersionError(strprintf(
# 258 : 1 : "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
# 259 : 1 : "but the maximum supported by this version of %s is %u.",
# 260 : 1 : uint8_t{format}, lowest_compatible, PACKAGE_NAME, uint8_t{FILE_FORMAT}));
# 261 : 1 : }
# 262 : :
# 263 : 356 : s >> nKey;
# 264 : 356 : s >> nNew;
# 265 : 356 : s >> nTried;
# 266 : 356 : int nUBuckets = 0;
# 267 : 356 : s >> nUBuckets;
# 268 [ + - ][ + - ]: 356 : if (format >= Format::V1_DETERMINISTIC) {
# [ # # ][ + - ]
# 269 : 356 : nUBuckets ^= (1 << 30);
# 270 : 356 : }
# 271 : :
# 272 [ - + ][ - + ]: 356 : if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
# [ # # ][ - + ]
# [ # # ][ - + ]
# [ - + ][ + + ]
# 273 : 1 : throw std::ios_base::failure(
# 274 : 1 : strprintf("Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
# 275 : 1 : nNew,
# 276 : 1 : ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
# 277 : 1 : }
# 278 : :
# 279 [ - + ][ - + ]: 355 : if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
# [ # # ][ - + ]
# [ + + ][ - + ]
# [ # # ][ - + ]
# 280 : 1 : throw std::ios_base::failure(
# 281 : 1 : strprintf("Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
# 282 : 1 : nTried,
# 283 : 1 : ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
# 284 : 1 : }
# 285 : :
# 286 : : // Deserialize entries from the new table.
# 287 [ + + ][ + + ]: 2988 : for (int n = 0; n < nNew; n++) {
# [ # # ][ + + ]
# 288 : 2634 : AddrInfo& info = mapInfo[n];
# 289 : 2634 : s >> info;
# 290 : 2634 : mapAddr[info] = n;
# 291 : 2634 : info.nRandomPos = vRandom.size();
# 292 : 2634 : vRandom.push_back(n);
# 293 : 2634 : }
# 294 : 354 : nIdCount = nNew;
# 295 : :
# 296 : : // Deserialize entries from the tried table.
# 297 : 354 : int nLost = 0;
# 298 [ - + ][ + + ]: 359 : for (int n = 0; n < nTried; n++) {
# [ # # ][ + + ]
# 299 : 5 : AddrInfo info;
# 300 : 5 : s >> info;
# 301 : 5 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
# 302 : 5 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
# 303 [ # # ][ # # ]: 5 : if (info.IsValid()
# [ + - ][ + + ]
# 304 [ # # ][ # # ]: 5 : && vvTried[nKBucket][nKBucketPos] == -1) {
# [ + - ][ + - ]
# 305 : 3 : info.nRandomPos = vRandom.size();
# 306 : 3 : info.fInTried = true;
# 307 : 3 : vRandom.push_back(nIdCount);
# 308 : 3 : mapInfo[nIdCount] = info;
# 309 : 3 : mapAddr[info] = nIdCount;
# 310 : 3 : vvTried[nKBucket][nKBucketPos] = nIdCount;
# 311 : 3 : nIdCount++;
# 312 : 3 : } else {
# 313 : 2 : nLost++;
# 314 : 2 : }
# 315 : 5 : }
# 316 : 354 : nTried -= nLost;
# 317 : :
# 318 : : // Store positions in the new table buckets to apply later (if possible).
# 319 : : // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
# 320 : : // so we store all bucket-entry_index pairs to iterate through later.
# 321 : 354 : std::vector<std::pair<int, int>> bucket_entries;
# 322 : :
# 323 [ # # ][ + + ]: 358754 : for (int bucket = 0; bucket < nUBuckets; ++bucket) {
# [ + + ][ + + ]
# 324 : 358400 : int num_entries{0};
# 325 : 358400 : s >> num_entries;
# 326 [ # # ][ + + ]: 361026 : for (int n = 0; n < num_entries; ++n) {
# [ + + ][ + + ]
# 327 : 2626 : int entry_index{0};
# 328 : 2626 : s >> entry_index;
# 329 [ + - ][ # # ]: 2626 : if (entry_index >= 0 && entry_index < nNew) {
# [ + - ][ + - ]
# [ + - ][ # # ]
# [ + - ][ + - ]
# 330 : 2626 : bucket_entries.emplace_back(bucket, entry_index);
# 331 : 2626 : }
# 332 : 2626 : }
# 333 : 358400 : }
# 334 : :
# 335 : : // If the bucket count and asmap checksum haven't changed, then attempt
# 336 : : // to restore the entries to the buckets/positions they were in before
# 337 : : // serialization.
# 338 : 354 : uint256 supplied_asmap_checksum;
# 339 [ + + ][ # # ]: 354 : if (m_asmap.size() != 0) {
# [ - + ][ + + ]
# 340 : 12 : supplied_asmap_checksum = SerializeHash(m_asmap);
# 341 : 12 : }
# 342 : 354 : uint256 serialized_asmap_checksum;
# 343 [ + + ][ # # ]: 354 : if (format >= Format::V2_ASMAP) {
# [ + + ][ + + ]
# 344 : 346 : s >> serialized_asmap_checksum;
# 345 : 346 : }
# 346 [ # # ][ + - ]: 354 : const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
# [ + + ][ + + ]
# 347 [ # # ][ + + ]: 354 : serialized_asmap_checksum == supplied_asmap_checksum};
# [ + - ][ + + ]
# 348 : :
# 349 [ # # ][ + + ]: 354 : if (!restore_bucketing) {
# [ + + ][ - + ]
# 350 [ # # ][ # # ]: 7 : LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
# [ + - ][ + - ]
# 351 : 7 : }
# 352 : :
# 353 [ # # ][ + + ]: 2626 : for (auto bucket_entry : bucket_entries) {
# [ + + ][ + + ]
# 354 : 2626 : int bucket{bucket_entry.first};
# 355 : 2626 : const int entry_index{bucket_entry.second};
# 356 : 2626 : AddrInfo& info = mapInfo[entry_index];
# 357 : :
# 358 : : // Don't store the entry in the new bucket if it's not a valid address for our addrman
# 359 [ - + ][ + + ]: 2626 : if (!info.IsValid()) continue;
# [ - + ][ # # ]
# 360 : :
# 361 : : // The entry shouldn't appear in more than
# 362 : : // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
# 363 : : // this bucket_entry.
# 364 [ - + ][ - + ]: 2624 : if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
# [ - + ][ # # ]
# 365 : :
# 366 : 2624 : int bucket_position = info.GetBucketPosition(nKey, true, bucket);
# 367 [ + + ][ # # ]: 2624 : if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
# [ + - ][ + - ]
# [ + - ][ + - ]
# [ # # ][ + - ]
# 368 : : // Bucketing has not changed, using existing bucket positions for the new table
# 369 : 2616 : vvNew[bucket][bucket_position] = entry_index;
# 370 : 2616 : ++info.nRefCount;
# 371 : 2616 : } else {
# 372 : : // In case the new table data cannot be used (bucket count wrong or new asmap),
# 373 : : // try to give them a reference based on their primary source address.
# 374 : 8 : bucket = info.GetNewBucket(nKey, m_asmap);
# 375 : 8 : bucket_position = info.GetBucketPosition(nKey, true, bucket);
# 376 [ # # ][ + - ]: 8 : if (vvNew[bucket][bucket_position] == -1) {
# [ # # ][ # # ]
# 377 : 8 : vvNew[bucket][bucket_position] = entry_index;
# 378 : 8 : ++info.nRefCount;
# 379 : 8 : }
# 380 : 8 : }
# 381 : 2624 : }
# 382 : :
# 383 : : // Prune new entries with refcount 0 (as a result of collisions or invalid address).
# 384 : 354 : int nLostUnk = 0;
# 385 [ # # ][ + + ]: 2983 : for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
# [ + + ][ + + ]
# 386 [ # # ][ + + ]: 2629 : if (it->second.fInTried == false && it->second.nRefCount == 0) {
# [ + - ][ + + ]
# [ # # ][ + + ]
# [ - + ][ - + ]
# 387 : 2 : const auto itCopy = it++;
# 388 : 2 : Delete(itCopy->first);
# 389 : 2 : ++nLostUnk;
# 390 : 2627 : } else {
# 391 : 2627 : ++it;
# 392 : 2627 : }
# 393 : 2629 : }
# 394 [ - + ][ + + ]: 354 : if (nLost + nLostUnk > 0) {
# [ # # ][ - + ]
# 395 [ # # ][ # # ]: 2 : LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
# [ + - ][ # # ]
# 396 : 2 : }
# 397 : :
# 398 : 354 : const int check_code{CheckAddrman()};
# 399 [ + + ][ - + ]: 354 : if (check_code != 0) {
# [ - + ][ # # ]
# 400 : 1 : throw std::ios_base::failure(strprintf(
# 401 : 1 : "Corrupt data. Consistency check failed with code %s",
# 402 : 1 : check_code));
# 403 : 1 : }
# 404 : 354 : }
# 405 : :
# 406 : : AddrInfo* AddrManImpl::Find(const CService& addr, int* pnId)
# 407 : 29974 : {
# 408 : 29974 : AssertLockHeld(cs);
# 409 : :
# 410 : 29974 : const auto it = mapAddr.find(addr);
# 411 [ + + ]: 29974 : if (it == mapAddr.end())
# 412 : 28221 : return nullptr;
# 413 [ + + ]: 1753 : if (pnId)
# 414 : 1721 : *pnId = (*it).second;
# 415 : 1753 : const auto it2 = mapInfo.find((*it).second);
# 416 [ + - ]: 1753 : if (it2 != mapInfo.end())
# 417 : 1753 : return &(*it2).second;
# 418 : 0 : return nullptr;
# 419 : 1753 : }
# 420 : :
# 421 : : AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
# 422 : 26553 : {
# 423 : 26553 : AssertLockHeld(cs);
# 424 : :
# 425 : 26553 : int nId = nIdCount++;
# 426 : 26553 : mapInfo[nId] = AddrInfo(addr, addrSource);
# 427 : 26553 : mapAddr[addr] = nId;
# 428 : 26553 : mapInfo[nId].nRandomPos = vRandom.size();
# 429 : 26553 : vRandom.push_back(nId);
# 430 [ + - ]: 26553 : if (pnId)
# 431 : 26553 : *pnId = nId;
# 432 : 26553 : return &mapInfo[nId];
# 433 : 26553 : }
# 434 : :
# 435 : : void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
# 436 : 59520 : {
# 437 : 59520 : AssertLockHeld(cs);
# 438 : :
# 439 [ + + ]: 59520 : if (nRndPos1 == nRndPos2)
# 440 : 1678 : return;
# 441 : :
# 442 : 57842 : assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
# 443 : :
# 444 : 0 : int nId1 = vRandom[nRndPos1];
# 445 : 57842 : int nId2 = vRandom[nRndPos2];
# 446 : :
# 447 : 57842 : const auto it_1{mapInfo.find(nId1)};
# 448 : 57842 : const auto it_2{mapInfo.find(nId2)};
# 449 : 57842 : assert(it_1 != mapInfo.end());
# 450 : 0 : assert(it_2 != mapInfo.end());
# 451 : :
# 452 : 0 : it_1->second.nRandomPos = nRndPos2;
# 453 : 57842 : it_2->second.nRandomPos = nRndPos1;
# 454 : :
# 455 : 57842 : vRandom[nRndPos1] = nId2;
# 456 : 57842 : vRandom[nRndPos2] = nId1;
# 457 : 57842 : }
# 458 : :
# 459 : : void AddrManImpl::Delete(int nId)
# 460 : 1589 : {
# 461 : 1589 : AssertLockHeld(cs);
# 462 : :
# 463 : 1589 : assert(mapInfo.count(nId) != 0);
# 464 : 0 : AddrInfo& info = mapInfo[nId];
# 465 : 1589 : assert(!info.fInTried);
# 466 : 0 : assert(info.nRefCount == 0);
# 467 : :
# 468 : 0 : SwapRandom(info.nRandomPos, vRandom.size() - 1);
# 469 : 1589 : vRandom.pop_back();
# 470 : 1589 : mapAddr.erase(info);
# 471 : 1589 : mapInfo.erase(nId);
# 472 : 1589 : nNew--;
# 473 : 1589 : }
# 474 : :
# 475 : : void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
# 476 : 24986 : {
# 477 : 24986 : AssertLockHeld(cs);
# 478 : :
# 479 : : // if there is an entry in the specified bucket, delete it.
# 480 [ + + ]: 24986 : if (vvNew[nUBucket][nUBucketPos] != -1) {
# 481 : 2 : int nIdDelete = vvNew[nUBucket][nUBucketPos];
# 482 : 2 : AddrInfo& infoDelete = mapInfo[nIdDelete];
# 483 : 2 : assert(infoDelete.nRefCount > 0);
# 484 : 0 : infoDelete.nRefCount--;
# 485 : 2 : vvNew[nUBucket][nUBucketPos] = -1;
# 486 [ + - ]: 2 : LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToString(), nUBucket, nUBucketPos);
# 487 [ + - ]: 2 : if (infoDelete.nRefCount == 0) {
# 488 : 2 : Delete(nIdDelete);
# 489 : 2 : }
# 490 : 2 : }
# 491 : 24986 : }
# 492 : :
# 493 : : void AddrManImpl::MakeTried(AddrInfo& info, int nId)
# 494 : 808 : {
# 495 : 808 : AssertLockHeld(cs);
# 496 : :
# 497 : : // remove the entry from all new buckets
# 498 : 808 : const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
# 499 [ + - ]: 808 : for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
# 500 : 808 : const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
# 501 : 808 : const int pos{info.GetBucketPosition(nKey, true, bucket)};
# 502 [ + - ]: 808 : if (vvNew[bucket][pos] == nId) {
# 503 : 808 : vvNew[bucket][pos] = -1;
# 504 : 808 : info.nRefCount--;
# 505 [ + - ]: 808 : if (info.nRefCount == 0) break;
# 506 : 808 : }
# 507 : 808 : }
# 508 : 808 : nNew--;
# 509 : :
# 510 : 808 : assert(info.nRefCount == 0);
# 511 : :
# 512 : : // which tried bucket to move the entry to
# 513 : 0 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
# 514 : 808 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
# 515 : :
# 516 : : // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
# 517 [ + + ]: 808 : if (vvTried[nKBucket][nKBucketPos] != -1) {
# 518 : : // find an item to evict
# 519 : 4 : int nIdEvict = vvTried[nKBucket][nKBucketPos];
# 520 : 4 : assert(mapInfo.count(nIdEvict) == 1);
# 521 : 0 : AddrInfo& infoOld = mapInfo[nIdEvict];
# 522 : :
# 523 : : // Remove the to-be-evicted item from the tried set.
# 524 : 4 : infoOld.fInTried = false;
# 525 : 4 : vvTried[nKBucket][nKBucketPos] = -1;
# 526 : 4 : nTried--;
# 527 : :
# 528 : : // find which new bucket it belongs to
# 529 : 4 : int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
# 530 : 4 : int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
# 531 : 4 : ClearNew(nUBucket, nUBucketPos);
# 532 : 4 : assert(vvNew[nUBucket][nUBucketPos] == -1);
# 533 : :
# 534 : : // Enter it into the new set again.
# 535 : 0 : infoOld.nRefCount = 1;
# 536 : 4 : vvNew[nUBucket][nUBucketPos] = nIdEvict;
# 537 : 4 : nNew++;
# 538 [ + - ]: 4 : LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
# 539 : 4 : infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
# 540 : 4 : }
# 541 : 0 : assert(vvTried[nKBucket][nKBucketPos] == -1);
# 542 : :
# 543 : 0 : vvTried[nKBucket][nKBucketPos] = nId;
# 544 : 808 : nTried++;
# 545 : 808 : info.fInTried = true;
# 546 : 808 : }
# 547 : :
# 548 : : bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
# 549 : 28725 : {
# 550 : 28725 : AssertLockHeld(cs);
# 551 : :
# 552 [ + + ]: 28725 : if (!addr.IsRoutable())
# 553 : 1329 : return false;
# 554 : :
# 555 : 27396 : int nId;
# 556 : 27396 : AddrInfo* pinfo = Find(addr, &nId);
# 557 : :
# 558 : : // Do not set a penalty for a source's self-announcement
# 559 [ + + ]: 27396 : if (addr == source) {
# 560 : 24885 : nTimePenalty = 0;
# 561 : 24885 : }
# 562 : :
# 563 [ + + ]: 27396 : if (pinfo) {
# 564 : : // periodically update nTime
# 565 : 843 : bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
# 566 [ + + ]: 843 : int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
# 567 [ + - ][ - + ]: 843 : if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
# [ - + ]
# 568 : 0 : pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
# 569 : :
# 570 : : // add services
# 571 : 843 : pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
# 572 : :
# 573 : : // do not update if no new information is present
# 574 [ - + ][ + - ]: 843 : if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
# [ + + ]
# 575 : 42 : return false;
# 576 : :
# 577 : : // do not update if the entry was already in the "tried" table
# 578 [ - + ]: 801 : if (pinfo->fInTried)
# 579 : 0 : return false;
# 580 : :
# 581 : : // do not update if the max reference count is reached
# 582 [ + + ]: 801 : if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
# 583 : 262 : return false;
# 584 : :
# 585 : : // stochastic test: previous nRefCount == N: 2^N times harder to increase it
# 586 : 539 : int nFactor = 1;
# 587 [ + + ]: 3776 : for (int n = 0; n < pinfo->nRefCount; n++)
# 588 : 3237 : nFactor *= 2;
# 589 [ + - ][ + + ]: 539 : if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
# 590 : 522 : return false;
# 591 : 26553 : } else {
# 592 : 26553 : pinfo = Create(addr, source, &nId);
# 593 : 26553 : pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
# 594 : 26553 : nNew++;
# 595 : 26553 : }
# 596 : :
# 597 : 26570 : int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
# 598 : 26570 : int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
# 599 : 26570 : bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
# 600 [ + + ]: 26570 : if (vvNew[nUBucket][nUBucketPos] != nId) {
# 601 [ + + ]: 26567 : if (!fInsert) {
# 602 : 1587 : AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
# 603 [ + + ][ - + ]: 1587 : if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
# [ # # ]
# 604 : : // Overwrite the existing new table entry.
# 605 : 2 : fInsert = true;
# 606 : 2 : }
# 607 : 1587 : }
# 608 [ + + ]: 26567 : if (fInsert) {
# 609 : 24982 : ClearNew(nUBucket, nUBucketPos);
# 610 : 24982 : pinfo->nRefCount++;
# 611 : 24982 : vvNew[nUBucket][nUBucketPos] = nId;
# 612 [ + - ]: 24982 : LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
# 613 : 24982 : addr.ToString(), addr.GetMappedAS(m_asmap), nUBucket, nUBucketPos);
# 614 : 24982 : } else {
# 615 [ + - ]: 1585 : if (pinfo->nRefCount == 0) {
# 616 : 1585 : Delete(nId);
# 617 : 1585 : }
# 618 : 1585 : }
# 619 : 26567 : }
# 620 : 26570 : return fInsert;
# 621 : 27396 : }
# 622 : :
# 623 : : bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
# 624 : 1302 : {
# 625 : 1302 : AssertLockHeld(cs);
# 626 : :
# 627 : 1302 : int nId;
# 628 : :
# 629 : 1302 : nLastGood = nTime;
# 630 : :
# 631 : 1302 : AddrInfo* pinfo = Find(addr, &nId);
# 632 : :
# 633 : : // if not found, bail out
# 634 [ + + ]: 1302 : if (!pinfo) return false;
# 635 : :
# 636 : 878 : AddrInfo& info = *pinfo;
# 637 : :
# 638 : : // update info
# 639 : 878 : info.nLastSuccess = nTime;
# 640 : 878 : info.nLastTry = nTime;
# 641 : 878 : info.nAttempts = 0;
# 642 : : // nTime is not updated here, to avoid leaking information about
# 643 : : // currently-connected peers.
# 644 : :
# 645 : : // if it is already in the tried set, don't do anything else
# 646 [ + + ]: 878 : if (info.fInTried) return false;
# 647 : :
# 648 : : // if it is not in new, something bad happened
# 649 [ - + ]: 830 : if (!Assume(info.nRefCount > 0)) return false;
# 650 : :
# 651 : :
# 652 : : // which tried bucket to move the entry to
# 653 : 830 : int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
# 654 : 830 : int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
# 655 : :
# 656 : : // Will moving this address into tried evict another entry?
# 657 [ + + ][ + + ]: 830 : if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
# 658 [ + - ]: 22 : if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
# 659 : 22 : m_tried_collisions.insert(nId);
# 660 : 22 : }
# 661 : : // Output the entry we'd be colliding with, for debugging purposes
# 662 : 22 : auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
# 663 [ + - ][ + - ]: 22 : LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n",
# 664 : 22 : colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "",
# 665 : 22 : addr.ToString(),
# 666 : 22 : m_tried_collisions.size());
# 667 : 22 : return false;
# 668 : 808 : } else {
# 669 : : // move nId to the tried tables
# 670 : 808 : MakeTried(info, nId);
# 671 [ + - ]: 808 : LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
# 672 : 808 : addr.ToString(), addr.GetMappedAS(m_asmap), tried_bucket, tried_bucket_pos);
# 673 : 808 : return true;
# 674 : 808 : }
# 675 : 830 : }
# 676 : :
# 677 : : bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty)
# 678 : 27474 : {
# 679 : 27474 : int added{0};
# 680 [ + + ]: 56199 : for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
# 681 [ + + ]: 28725 : added += AddSingle(*it, source, nTimePenalty) ? 1 : 0;
# 682 : 28725 : }
# 683 [ + + ]: 27474 : if (added > 0) {
# 684 [ + - ]: 23943 : LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToString(), nTried, nNew);
# 685 : 23943 : }
# 686 : 27474 : return added > 0;
# 687 : 27474 : }
# 688 : :
# 689 : : void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
# 690 : 428 : {
# 691 : 428 : AssertLockHeld(cs);
# 692 : :
# 693 : 428 : AddrInfo* pinfo = Find(addr);
# 694 : :
# 695 : : // if not found, bail out
# 696 [ + + ]: 428 : if (!pinfo)
# 697 : 426 : return;
# 698 : :
# 699 : 2 : AddrInfo& info = *pinfo;
# 700 : :
# 701 : : // update info
# 702 : 2 : info.nLastTry = nTime;
# 703 [ - + ][ # # ]: 2 : if (fCountFailure && info.nLastCountAttempt < nLastGood) {
# 704 : 0 : info.nLastCountAttempt = nTime;
# 705 : 0 : info.nAttempts++;
# 706 : 0 : }
# 707 : 2 : }
# 708 : :
# 709 : : std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
# 710 : 58 : {
# 711 : 58 : AssertLockHeld(cs);
# 712 : :
# 713 [ + + ]: 58 : if (vRandom.empty()) return {};
# 714 : :
# 715 [ + + ][ + + ]: 52 : if (newOnly && nNew == 0) return {};
# 716 : :
# 717 : : // Use a 50% chance for choosing between tried and new table entries.
# 718 [ + + ]: 50 : if (!newOnly &&
# 719 [ + + ][ + + ]: 50 : (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
# [ + + ]
# 720 : : // use a tried node
# 721 : 16 : double fChanceFactor = 1.0;
# 722 : 21082 : while (1) {
# 723 : : // Pick a tried bucket, and an initial position in that bucket.
# 724 : 21082 : int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
# 725 : 21082 : int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
# 726 : : // Iterate over the positions of that bucket, starting at the initial one,
# 727 : : // and looping around.
# 728 : 21082 : int i;
# 729 [ + + ]: 1362950 : for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
# 730 [ + + ]: 1342098 : if (vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
# 731 : 1342098 : }
# 732 : : // If the bucket is entirely empty, start over with a (likely) different one.
# 733 [ + + ]: 21082 : if (i == ADDRMAN_BUCKET_SIZE) continue;
# 734 : : // Find the entry to return.
# 735 : 230 : int nId = vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE];
# 736 : 230 : const auto it_found{mapInfo.find(nId)};
# 737 : 230 : assert(it_found != mapInfo.end());
# 738 : 0 : const AddrInfo& info{it_found->second};
# 739 : : // With probability GetChance() * fChanceFactor, return the entry.
# 740 [ + + ]: 230 : if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
# 741 [ + - ]: 16 : LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
# 742 : 16 : return {info, info.nLastTry};
# 743 : 16 : }
# 744 : : // Otherwise start over with a (likely) different bucket, and increased chance factor.
# 745 : 214 : fChanceFactor *= 1.2;
# 746 : 214 : }
# 747 : 34 : } else {
# 748 : : // use a new node
# 749 : 34 : double fChanceFactor = 1.0;
# 750 : 21924 : while (1) {
# 751 : : // Pick a new bucket, and an initial position in that bucket.
# 752 : 21924 : int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
# 753 : 21924 : int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
# 754 : : // Iterate over the positions of that bucket, starting at the initial one,
# 755 : : // and looping around.
# 756 : 21924 : int i;
# 757 [ + + ]: 1424156 : for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
# 758 [ + + ]: 1402266 : if (vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
# 759 : 1402266 : }
# 760 : : // If the bucket is entirely empty, start over with a (likely) different one.
# 761 [ + + ]: 21924 : if (i == ADDRMAN_BUCKET_SIZE) continue;
# 762 : : // Find the entry to return.
# 763 : 34 : int nId = vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE];
# 764 : 34 : const auto it_found{mapInfo.find(nId)};
# 765 : 34 : assert(it_found != mapInfo.end());
# 766 : 0 : const AddrInfo& info{it_found->second};
# 767 : : // With probability GetChance() * fChanceFactor, return the entry.
# 768 [ + - ]: 34 : if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
# 769 [ + - ]: 34 : LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
# 770 : 34 : return {info, info.nLastTry};
# 771 : 34 : }
# 772 : : // Otherwise start over with a (likely) different bucket, and increased chance factor.
# 773 : 0 : fChanceFactor *= 1.2;
# 774 : 0 : }
# 775 : 34 : }
# 776 : 50 : }
# 777 : :
# 778 : : std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
# 779 : 377 : {
# 780 : 377 : AssertLockHeld(cs);
# 781 : :
# 782 : 377 : size_t nNodes = vRandom.size();
# 783 [ + + ]: 377 : if (max_pct != 0) {
# 784 : 348 : nNodes = max_pct * nNodes / 100;
# 785 : 348 : }
# 786 [ + + ]: 377 : if (max_addresses != 0) {
# 787 : 355 : nNodes = std::min(nNodes, max_addresses);
# 788 : 355 : }
# 789 : :
# 790 : : // gather a list of random nodes, skipping those of low quality
# 791 : 377 : const int64_t now{GetAdjustedTime()};
# 792 : 377 : std::vector<CAddress> addresses;
# 793 [ + + ]: 58308 : for (unsigned int n = 0; n < vRandom.size(); n++) {
# 794 [ + + ]: 57953 : if (addresses.size() >= nNodes)
# 795 : 22 : break;
# 796 : :
# 797 : 57931 : int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
# 798 : 57931 : SwapRandom(n, nRndPos);
# 799 : 57931 : const auto it{mapInfo.find(vRandom[n])};
# 800 : 57931 : assert(it != mapInfo.end());
# 801 : :
# 802 : 0 : const AddrInfo& ai{it->second};
# 803 : :
# 804 : : // Filter by network (optional)
# 805 [ + + ][ + + ]: 57931 : if (network != std::nullopt && ai.GetNetClass() != network) continue;
# [ + + ]
# 806 : :
# 807 : : // Filter for quality
# 808 [ - + ]: 22474 : if (ai.IsTerrible(now)) continue;
# 809 : :
# 810 : 22474 : addresses.push_back(ai);
# 811 : 22474 : }
# 812 [ + - ]: 377 : LogPrint(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size());
# 813 : 377 : return addresses;
# 814 : 377 : }
# 815 : :
# 816 : : void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
# 817 : 410 : {
# 818 : 410 : AssertLockHeld(cs);
# 819 : :
# 820 : 410 : AddrInfo* pinfo = Find(addr);
# 821 : :
# 822 : : // if not found, bail out
# 823 [ + + ]: 410 : if (!pinfo)
# 824 : 408 : return;
# 825 : :
# 826 : 2 : AddrInfo& info = *pinfo;
# 827 : :
# 828 : : // update info
# 829 : 2 : int64_t nUpdateInterval = 20 * 60;
# 830 [ + - ]: 2 : if (nTime - info.nTime > nUpdateInterval)
# 831 : 2 : info.nTime = nTime;
# 832 : 2 : }
# 833 : :
# 834 : : void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
# 835 : 412 : {
# 836 : 412 : AssertLockHeld(cs);
# 837 : :
# 838 : 412 : AddrInfo* pinfo = Find(addr);
# 839 : :
# 840 : : // if not found, bail out
# 841 [ + + ]: 412 : if (!pinfo)
# 842 : 410 : return;
# 843 : :
# 844 : 2 : AddrInfo& info = *pinfo;
# 845 : :
# 846 : : // update info
# 847 : 2 : info.nServices = nServices;
# 848 : 2 : }
# 849 : :
# 850 : : void AddrManImpl::ResolveCollisions_()
# 851 : 12 : {
# 852 : 12 : AssertLockHeld(cs);
# 853 : :
# 854 [ + + ]: 22 : for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
# 855 : 10 : int id_new = *it;
# 856 : :
# 857 : 10 : bool erase_collision = false;
# 858 : :
# 859 : : // If id_new not found in mapInfo remove it from m_tried_collisions
# 860 [ - + ]: 10 : if (mapInfo.count(id_new) != 1) {
# 861 : 0 : erase_collision = true;
# 862 : 10 : } else {
# 863 : 10 : AddrInfo& info_new = mapInfo[id_new];
# 864 : :
# 865 : : // Which tried bucket to move the entry to.
# 866 : 10 : int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
# 867 : 10 : int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
# 868 [ - + ]: 10 : if (!info_new.IsValid()) { // id_new may no longer map to a valid address
# 869 : 0 : erase_collision = true;
# 870 [ + - ]: 10 : } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
# 871 : :
# 872 : : // Get the to-be-evicted address that is being tested
# 873 : 10 : int id_old = vvTried[tried_bucket][tried_bucket_pos];
# 874 : 10 : AddrInfo& info_old = mapInfo[id_old];
# 875 : :
# 876 : : // Has successfully connected in last X hours
# 877 [ + + ]: 10 : if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
# 878 : 6 : erase_collision = true;
# 879 [ + + ]: 6 : } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
# 880 : :
# 881 : : // Give address at least 60 seconds to successfully connect
# 882 [ + - ]: 2 : if (GetAdjustedTime() - info_old.nLastTry > 60) {
# 883 [ + - ]: 2 : LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
# 884 : :
# 885 : : // Replaces an existing address already in the tried table with the new address
# 886 : 2 : Good_(info_new, false, GetAdjustedTime());
# 887 : 2 : erase_collision = true;
# 888 : 2 : }
# 889 [ + - ]: 2 : } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
# 890 : : // If the collision hasn't resolved in some reasonable amount of time,
# 891 : : // just evict the old entry -- we must not be able to
# 892 : : // connect to it for some reason.
# 893 [ + - ]: 2 : LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
# 894 : 2 : Good_(info_new, false, GetAdjustedTime());
# 895 : 2 : erase_collision = true;
# 896 : 2 : }
# 897 : 10 : } else { // Collision is not actually a collision anymore
# 898 : 0 : Good_(info_new, false, GetAdjustedTime());
# 899 : 0 : erase_collision = true;
# 900 : 0 : }
# 901 : 10 : }
# 902 : :
# 903 [ + - ]: 10 : if (erase_collision) {
# 904 : 10 : m_tried_collisions.erase(it++);
# 905 : 10 : } else {
# 906 : 0 : it++;
# 907 : 0 : }
# 908 : 10 : }
# 909 : 12 : }
# 910 : :
# 911 : : std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
# 912 : 112 : {
# 913 : 112 : AssertLockHeld(cs);
# 914 : :
# 915 [ + + ]: 112 : if (m_tried_collisions.size() == 0) return {};
# 916 : :
# 917 : 10 : std::set<int>::iterator it = m_tried_collisions.begin();
# 918 : :
# 919 : : // Selects a random element from m_tried_collisions
# 920 : 10 : std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
# 921 : 10 : int id_new = *it;
# 922 : :
# 923 : : // If id_new not found in mapInfo remove it from m_tried_collisions
# 924 [ - + ]: 10 : if (mapInfo.count(id_new) != 1) {
# 925 : 0 : m_tried_collisions.erase(it);
# 926 : 0 : return {};
# 927 : 0 : }
# 928 : :
# 929 : 10 : const AddrInfo& newInfo = mapInfo[id_new];
# 930 : :
# 931 : : // which tried bucket to move the entry to
# 932 : 10 : int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
# 933 : 10 : int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
# 934 : :
# 935 : 10 : const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
# 936 : 10 : return {info_old, info_old.nLastTry};
# 937 : 10 : }
# 938 : :
# 939 : : std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
# 940 : 26 : {
# 941 : 26 : AssertLockHeld(cs);
# 942 : :
# 943 : 26 : AddrInfo* addr_info = Find(addr);
# 944 : :
# 945 [ - + ]: 26 : if (!addr_info) return std::nullopt;
# 946 : :
# 947 [ + + ]: 26 : if(addr_info->fInTried) {
# 948 : 4 : int bucket{addr_info->GetTriedBucket(nKey, m_asmap)};
# 949 : 4 : return AddressPosition(/*tried_in=*/true,
# 950 : 4 : /*multiplicity_in=*/1,
# 951 : 4 : /*bucket_in=*/bucket,
# 952 : 4 : /*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket));
# 953 : 22 : } else {
# 954 : 22 : int bucket{addr_info->GetNewBucket(nKey, m_asmap)};
# 955 : 22 : return AddressPosition(/*tried_in=*/false,
# 956 : 22 : /*multiplicity_in=*/addr_info->nRefCount,
# 957 : 22 : /*bucket_in=*/bucket,
# 958 : 22 : /*position_in=*/addr_info->GetBucketPosition(nKey, true, bucket));
# 959 : 22 : }
# 960 : 26 : }
# 961 : :
# 962 : : void AddrManImpl::Check() const
# 963 : 61214 : {
# 964 : 61214 : AssertLockHeld(cs);
# 965 : :
# 966 : : // Run consistency checks 1 in m_consistency_check_ratio times if enabled
# 967 [ + + ]: 61214 : if (m_consistency_check_ratio == 0) return;
# 968 [ + + ]: 12916 : if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return;
# 969 : :
# 970 : 174 : const int err{CheckAddrman()};
# 971 [ - + ]: 174 : if (err) {
# 972 : 0 : LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
# 973 : 0 : assert(false);
# 974 : 0 : }
# 975 : 174 : }
# 976 : :
# 977 : : int AddrManImpl::CheckAddrman() const
# 978 : 524 : {
# 979 : 524 : AssertLockHeld(cs);
# 980 : :
# 981 : 524 : LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE(
# 982 : 524 : strprintf("new %i, tried %i, total %u", nNew, nTried, vRandom.size()), BCLog::ADDRMAN);
# 983 : :
# 984 : 524 : std::unordered_set<int> setTried;
# 985 : 524 : std::unordered_map<int, int> mapNew;
# 986 : :
# 987 [ - + ]: 524 : if (vRandom.size() != (size_t)(nTried + nNew))
# 988 : 0 : return -7;
# 989 : :
# 990 [ + + ]: 80779 : for (const auto& entry : mapInfo) {
# 991 : 80779 : int n = entry.first;
# 992 : 80779 : const AddrInfo& info = entry.second;
# 993 [ + + ]: 80779 : if (info.fInTried) {
# 994 [ - + ]: 10083 : if (!info.nLastSuccess)
# 995 : 0 : return -1;
# 996 [ - + ]: 10083 : if (info.nRefCount)
# 997 : 0 : return -2;
# 998 : 10083 : setTried.insert(n);
# 999 : 70696 : } else {
# 1000 [ - + ][ - + ]: 70696 : if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
# 1001 : 0 : return -3;
# 1002 [ - + ]: 70696 : if (!info.nRefCount)
# 1003 : 0 : return -4;
# 1004 : 70696 : mapNew[n] = info.nRefCount;
# 1005 : 70696 : }
# 1006 : 80779 : const auto it{mapAddr.find(info)};
# 1007 [ - + ][ - + ]: 80779 : if (it == mapAddr.end() || it->second != n) {
# [ - + ]
# 1008 : 0 : return -5;
# 1009 : 0 : }
# 1010 [ - + ][ - + ]: 80779 : if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
# [ - + ]
# 1011 : 0 : return -14;
# 1012 [ - + ]: 80779 : if (info.nLastTry < 0)
# 1013 : 0 : return -6;
# 1014 [ - + ]: 80779 : if (info.nLastSuccess < 0)
# 1015 : 0 : return -8;
# 1016 : 80779 : }
# 1017 : :
# 1018 [ - + ]: 524 : if (setTried.size() != (size_t)nTried)
# 1019 : 0 : return -9;
# 1020 [ - + ]: 524 : if (mapNew.size() != (size_t)nNew)
# 1021 : 0 : return -10;
# 1022 : :
# 1023 [ + + ]: 134668 : for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
# 1024 [ + + ]: 8719360 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 1025 [ + + ]: 8585216 : if (vvTried[n][i] != -1) {
# 1026 [ - + ]: 10083 : if (!setTried.count(vvTried[n][i]))
# 1027 : 0 : return -11;
# 1028 : 10083 : const auto it{mapInfo.find(vvTried[n][i])};
# 1029 [ - + ][ - + ]: 10083 : if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
# [ - + ]
# 1030 : 0 : return -17;
# 1031 : 0 : }
# 1032 [ - + ]: 10083 : if (it->second.GetBucketPosition(nKey, false, n) != i) {
# 1033 : 0 : return -18;
# 1034 : 0 : }
# 1035 : 10083 : setTried.erase(vvTried[n][i]);
# 1036 : 10083 : }
# 1037 : 8585216 : }
# 1038 : 134144 : }
# 1039 : :
# 1040 [ + + ]: 537100 : for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
# 1041 [ + + ]: 34877440 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
# 1042 [ + + ]: 34340864 : if (vvNew[n][i] != -1) {
# 1043 [ - + ]: 70860 : if (!mapNew.count(vvNew[n][i]))
# 1044 : 0 : return -12;
# 1045 : 70860 : const auto it{mapInfo.find(vvNew[n][i])};
# 1046 [ - + ][ - + ]: 70860 : if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) {
# [ - + ]
# 1047 : 0 : return -19;
# 1048 : 0 : }
# 1049 [ + + ]: 70860 : if (--mapNew[vvNew[n][i]] == 0)
# 1050 : 70696 : mapNew.erase(vvNew[n][i]);
# 1051 : 70860 : }
# 1052 : 34340864 : }
# 1053 : 536576 : }
# 1054 : :
# 1055 [ - + ]: 524 : if (setTried.size())
# 1056 : 0 : return -13;
# 1057 [ - + ]: 524 : if (mapNew.size())
# 1058 : 0 : return -15;
# 1059 [ + + ]: 524 : if (nKey.IsNull())
# 1060 : 1 : return -16;
# 1061 : :
# 1062 : 523 : return 0;
# 1063 : 524 : }
# 1064 : :
# 1065 : : size_t AddrManImpl::size() const
# 1066 : 1196 : {
# 1067 : 1196 : LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
# 1068 : 1196 : return vRandom.size();
# 1069 : 1196 : }
# 1070 : :
# 1071 : : bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
# 1072 : 27474 : {
# 1073 : 27474 : LOCK(cs);
# 1074 : 27474 : Check();
# 1075 : 27474 : auto ret = Add_(vAddr, source, nTimePenalty);
# 1076 : 27474 : Check();
# 1077 : 27474 : return ret;
# 1078 : 27474 : }
# 1079 : :
# 1080 : : bool AddrManImpl::Good(const CService& addr, int64_t nTime)
# 1081 : 1298 : {
# 1082 : 1298 : LOCK(cs);
# 1083 : 1298 : Check();
# 1084 : 1298 : auto ret = Good_(addr, /*test_before_evict=*/true, nTime);
# 1085 : 1298 : Check();
# 1086 : 1298 : return ret;
# 1087 : 1298 : }
# 1088 : :
# 1089 : : void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
# 1090 : 428 : {
# 1091 : 428 : LOCK(cs);
# 1092 : 428 : Check();
# 1093 : 428 : Attempt_(addr, fCountFailure, nTime);
# 1094 : 428 : Check();
# 1095 : 428 : }
# 1096 : :
# 1097 : : void AddrManImpl::ResolveCollisions()
# 1098 : 12 : {
# 1099 : 12 : LOCK(cs);
# 1100 : 12 : Check();
# 1101 : 12 : ResolveCollisions_();
# 1102 : 12 : Check();
# 1103 : 12 : }
# 1104 : :
# 1105 : : std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
# 1106 : 112 : {
# 1107 : 112 : LOCK(cs);
# 1108 : 112 : Check();
# 1109 : 112 : const auto ret = SelectTriedCollision_();
# 1110 : 112 : Check();
# 1111 : 112 : return ret;
# 1112 : 112 : }
# 1113 : :
# 1114 : : std::pair<CAddress, int64_t> AddrManImpl::Select(bool newOnly) const
# 1115 : 58 : {
# 1116 : 58 : LOCK(cs);
# 1117 : 58 : Check();
# 1118 : 58 : const auto addrRet = Select_(newOnly);
# 1119 : 58 : Check();
# 1120 : 58 : return addrRet;
# 1121 : 58 : }
# 1122 : :
# 1123 : : std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
# 1124 : 377 : {
# 1125 : 377 : LOCK(cs);
# 1126 : 377 : Check();
# 1127 : 377 : const auto addresses = GetAddr_(max_addresses, max_pct, network);
# 1128 : 377 : Check();
# 1129 : 377 : return addresses;
# 1130 : 377 : }
# 1131 : :
# 1132 : : void AddrManImpl::Connected(const CService& addr, int64_t nTime)
# 1133 : 410 : {
# 1134 : 410 : LOCK(cs);
# 1135 : 410 : Check();
# 1136 : 410 : Connected_(addr, nTime);
# 1137 : 410 : Check();
# 1138 : 410 : }
# 1139 : :
# 1140 : : void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices)
# 1141 : 412 : {
# 1142 : 412 : LOCK(cs);
# 1143 : 412 : Check();
# 1144 : 412 : SetServices_(addr, nServices);
# 1145 : 412 : Check();
# 1146 : 412 : }
# 1147 : :
# 1148 : : std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& addr)
# 1149 : 26 : {
# 1150 : 26 : LOCK(cs);
# 1151 : 26 : Check();
# 1152 : 26 : auto entry = FindAddressEntry_(addr);
# 1153 : 26 : Check();
# 1154 : 26 : return entry;
# 1155 : 26 : }
# 1156 : :
# 1157 : : const std::vector<bool>& AddrManImpl::GetAsmap() const
# 1158 : 15988 : {
# 1159 : 15988 : return m_asmap;
# 1160 : 15988 : }
# 1161 : :
# 1162 : : AddrMan::AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
# 1163 : 1441 : : m_impl(std::make_unique<AddrManImpl>(std::move(asmap), deterministic, consistency_check_ratio)) {}
# 1164 : :
# 1165 : 1441 : AddrMan::~AddrMan() = default;
# 1166 : :
# 1167 : : template <typename Stream>
# 1168 : : void AddrMan::Serialize(Stream& s_) const
# 1169 : 2306 : {
# 1170 : 2306 : m_impl->Serialize<Stream>(s_);
# 1171 : 2306 : }
# 1172 : :
# 1173 : : template <typename Stream>
# 1174 : : void AddrMan::Unserialize(Stream& s_)
# 1175 : 358 : {
# 1176 : 358 : m_impl->Unserialize<Stream>(s_);
# 1177 : 358 : }
# 1178 : :
# 1179 : : // explicit instantiation
# 1180 : : template void AddrMan::Serialize(CHashWriter& s) const;
# 1181 : : template void AddrMan::Serialize(CAutoFile& s) const;
# 1182 : : template void AddrMan::Serialize(CDataStream& s) const;
# 1183 : : template void AddrMan::Unserialize(CAutoFile& s);
# 1184 : : template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
# 1185 : : template void AddrMan::Unserialize(CDataStream& s);
# 1186 : : template void AddrMan::Unserialize(CHashVerifier<CDataStream>& s);
# 1187 : :
# 1188 : : size_t AddrMan::size() const
# 1189 : 1196 : {
# 1190 : 1196 : return m_impl->size();
# 1191 : 1196 : }
# 1192 : :
# 1193 : : bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
# 1194 : 27474 : {
# 1195 : 27474 : return m_impl->Add(vAddr, source, nTimePenalty);
# 1196 : 27474 : }
# 1197 : :
# 1198 : : bool AddrMan::Good(const CService& addr, int64_t nTime)
# 1199 : 1298 : {
# 1200 : 1298 : return m_impl->Good(addr, nTime);
# 1201 : 1298 : }
# 1202 : :
# 1203 : : void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
# 1204 : 428 : {
# 1205 : 428 : m_impl->Attempt(addr, fCountFailure, nTime);
# 1206 : 428 : }
# 1207 : :
# 1208 : : void AddrMan::ResolveCollisions()
# 1209 : 12 : {
# 1210 : 12 : m_impl->ResolveCollisions();
# 1211 : 12 : }
# 1212 : :
# 1213 : : std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision()
# 1214 : 112 : {
# 1215 : 112 : return m_impl->SelectTriedCollision();
# 1216 : 112 : }
# 1217 : :
# 1218 : : std::pair<CAddress, int64_t> AddrMan::Select(bool newOnly) const
# 1219 : 58 : {
# 1220 : 58 : return m_impl->Select(newOnly);
# 1221 : 58 : }
# 1222 : :
# 1223 : : std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
# 1224 : 377 : {
# 1225 : 377 : return m_impl->GetAddr(max_addresses, max_pct, network);
# 1226 : 377 : }
# 1227 : :
# 1228 : : void AddrMan::Connected(const CService& addr, int64_t nTime)
# 1229 : 410 : {
# 1230 : 410 : m_impl->Connected(addr, nTime);
# 1231 : 410 : }
# 1232 : :
# 1233 : : void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
# 1234 : 412 : {
# 1235 : 412 : m_impl->SetServices(addr, nServices);
# 1236 : 412 : }
# 1237 : :
# 1238 : : const std::vector<bool>& AddrMan::GetAsmap() const
# 1239 : 15988 : {
# 1240 : 15988 : return m_impl->GetAsmap();
# 1241 : 15988 : }
# 1242 : :
# 1243 : : std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr)
# 1244 : 26 : {
# 1245 : 26 : return m_impl->FindAddressEntry(addr);
# 1246 : 26 : }
|