LCOV - code coverage report
Current view: top level - src - addrman.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 756 820 92.2 %
Date: 2022-04-21 14:51:19 Functions: 64 66 97.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 420 634 66.2 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a