LCOV - code coverage report
Current view: top level - src - addrman.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 22 820 2.7 %
Date: 2023-11-10 23:46:46 Functions: 4 67 6.0 %
Branches: 13 1530 0.8 %

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

Generated by: LCOV version 1.14