LCOV - code coverage report
Current view: top level - src - addrman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 317 356 89.0 %
Date: 2020-09-26 01:30:44 Functions: 21 21 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2012 Pieter Wuille
       2             : // Copyright (c) 2012-2020 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <addrman.h>
       7             : 
       8             : #include <hash.h>
       9             : #include <logging.h>
      10             : #include <serialize.h>
      11             : 
      12        6239 : int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
      13             : {
      14        6239 :     uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
      15        6239 :     uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
      16        6239 :     int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
      17        6239 :     uint32_t mapped_as = GetMappedAS(asmap);
      18        6239 :     LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
      19       12478 :     return tried_bucket;
      20        6239 : }
      21             : 
      22      317064 : int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
      23             : {
      24      317064 :     std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
      25      317064 :     uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
      26      317064 :     uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
      27      317064 :     int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
      28      317064 :     uint32_t mapped_as = GetMappedAS(asmap);
      29      317064 :     LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
      30      317064 :     return new_bucket;
      31      317064 : }
      32             : 
      33     4318488 : int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
      34             : {
      35     4318488 :     uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetCheapHash();
      36     4318488 :     return hash1 % ADDRMAN_BUCKET_SIZE;
      37           0 : }
      38             : 
      39       93995 : bool CAddrInfo::IsTerrible(int64_t nNow) const
      40             : {
      41       93995 :     if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
      42          69 :         return false;
      43             : 
      44       93926 :     if (nTime > nNow + 10 * 60) // came in a flying DeLorean
      45           0 :         return true;
      46             : 
      47       93926 :     if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
      48           1 :         return true;
      49             : 
      50       93925 :     if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
      51           0 :         return true;
      52             : 
      53       93925 :     if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
      54           0 :         return true;
      55             : 
      56       93925 :     return false;
      57       93995 : }
      58             : 
      59         653 : double CAddrInfo::GetChance(int64_t nNow) const
      60             : {
      61             :     double fChance = 1.0;
      62         653 :     int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
      63             : 
      64             :     // deprioritize very recent attempts away
      65         653 :     if (nSinceLastTry < 60 * 10)
      66         189 :         fChance *= 0.01;
      67             : 
      68             :     // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
      69         653 :     fChance *= pow(0.66, std::min(nAttempts, 8));
      70             : 
      71         653 :     return fChance;
      72             : }
      73             : 
      74      317715 : CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
      75             : {
      76      317715 :     std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
      77      317715 :     if (it == mapAddr.end())
      78      315049 :         return nullptr;
      79        2666 :     if (pnId)
      80        2655 :         *pnId = (*it).second;
      81        2666 :     std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
      82        2666 :     if (it2 != mapInfo.end())
      83        2666 :         return &(*it2).second;
      84           0 :     return nullptr;
      85      317715 : }
      86             : 
      87      313734 : CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
      88             : {
      89      313734 :     int nId = nIdCount++;
      90      313734 :     mapInfo[nId] = CAddrInfo(addr, addrSource);
      91      313734 :     mapAddr[addr] = nId;
      92      313734 :     mapInfo[nId].nRandomPos = vRandom.size();
      93      313734 :     vRandom.push_back(nId);
      94      313734 :     if (pnId)
      95      313734 :         *pnId = nId;
      96      627468 :     return &mapInfo[nId];
      97      313734 : }
      98             : 
      99       93996 : void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
     100             : {
     101       93996 :     if (nRndPos1 == nRndPos2)
     102             :         return;
     103             : 
     104       47242 :     assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
     105             : 
     106       47242 :     int nId1 = vRandom[nRndPos1];
     107       47242 :     int nId2 = vRandom[nRndPos2];
     108             : 
     109       47242 :     assert(mapInfo.count(nId1) == 1);
     110       47242 :     assert(mapInfo.count(nId2) == 1);
     111             : 
     112       47242 :     mapInfo[nId1].nRandomPos = nRndPos2;
     113       47242 :     mapInfo[nId2].nRandomPos = nRndPos1;
     114             : 
     115       47242 :     vRandom[nRndPos1] = nId2;
     116       47242 :     vRandom[nRndPos2] = nId1;
     117       93996 : }
     118             : 
     119       46720 : void CAddrMan::Delete(int nId)
     120             : {
     121       46720 :     assert(mapInfo.count(nId) != 0);
     122       46720 :     CAddrInfo& info = mapInfo[nId];
     123       46720 :     assert(!info.fInTried);
     124       46720 :     assert(info.nRefCount == 0);
     125             : 
     126       46720 :     SwapRandom(info.nRandomPos, vRandom.size() - 1);
     127       46720 :     vRandom.pop_back();
     128       46720 :     mapAddr.erase(info);
     129       46720 :     mapInfo.erase(nId);
     130       46720 :     nNew--;
     131       46720 : }
     132             : 
     133      267015 : void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
     134             : {
     135             :     // if there is an entry in the specified bucket, delete it.
     136      267015 :     if (vvNew[nUBucket][nUBucketPos] != -1) {
     137           1 :         int nIdDelete = vvNew[nUBucket][nUBucketPos];
     138           1 :         CAddrInfo& infoDelete = mapInfo[nIdDelete];
     139           1 :         assert(infoDelete.nRefCount > 0);
     140           1 :         infoDelete.nRefCount--;
     141           1 :         vvNew[nUBucket][nUBucketPos] = -1;
     142           1 :         if (infoDelete.nRefCount == 0) {
     143           1 :             Delete(nIdDelete);
     144           1 :         }
     145           1 :     }
     146      267015 : }
     147             : 
     148        2575 : void CAddrMan::MakeTried(CAddrInfo& info, int nId)
     149             : {
     150             :     // remove the entry from all new buckets
     151     2639375 :     for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
     152     2636800 :         int pos = info.GetBucketPosition(nKey, true, bucket);
     153     2636800 :         if (vvNew[bucket][pos] == nId) {
     154        2575 :             vvNew[bucket][pos] = -1;
     155        2575 :             info.nRefCount--;
     156        2575 :         }
     157             :     }
     158        2575 :     nNew--;
     159             : 
     160        2575 :     assert(info.nRefCount == 0);
     161             : 
     162             :     // which tried bucket to move the entry to
     163        2575 :     int nKBucket = info.GetTriedBucket(nKey, m_asmap);
     164        2575 :     int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
     165             : 
     166             :     // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
     167        2575 :     if (vvTried[nKBucket][nKBucketPos] != -1) {
     168             :         // find an item to evict
     169           1 :         int nIdEvict = vvTried[nKBucket][nKBucketPos];
     170           1 :         assert(mapInfo.count(nIdEvict) == 1);
     171           1 :         CAddrInfo& infoOld = mapInfo[nIdEvict];
     172             : 
     173             :         // Remove the to-be-evicted item from the tried set.
     174           1 :         infoOld.fInTried = false;
     175           1 :         vvTried[nKBucket][nKBucketPos] = -1;
     176           1 :         nTried--;
     177             : 
     178             :         // find which new bucket it belongs to
     179           1 :         int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
     180           1 :         int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
     181           1 :         ClearNew(nUBucket, nUBucketPos);
     182           1 :         assert(vvNew[nUBucket][nUBucketPos] == -1);
     183             : 
     184             :         // Enter it into the new set again.
     185           1 :         infoOld.nRefCount = 1;
     186           1 :         vvNew[nUBucket][nUBucketPos] = nIdEvict;
     187           1 :         nNew++;
     188           1 :     }
     189        2575 :     assert(vvTried[nKBucket][nKBucketPos] == -1);
     190             : 
     191        2575 :     vvTried[nKBucket][nKBucketPos] = nId;
     192        2575 :     nTried++;
     193        2575 :     info.fInTried = true;
     194        2575 : }
     195             : 
     196        3244 : void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
     197             : {
     198        3244 :     int nId;
     199             : 
     200        3244 :     nLastGood = nTime;
     201             : 
     202        3244 :     CAddrInfo* pinfo = Find(addr, &nId);
     203             : 
     204             :     // if not found, bail out
     205        3244 :     if (!pinfo)
     206         595 :         return;
     207             : 
     208             :     CAddrInfo& info = *pinfo;
     209             : 
     210             :     // check whether we are talking about the exact same CService (including same port)
     211        2649 :     if (info != addr)
     212           1 :         return;
     213             : 
     214             :     // update info
     215        2648 :     info.nLastSuccess = nTime;
     216        2648 :     info.nLastTry = nTime;
     217        2648 :     info.nAttempts = 0;
     218             :     // nTime is not updated here, to avoid leaking information about
     219             :     // currently-connected peers.
     220             : 
     221             :     // if it is already in the tried set, don't do anything else
     222        2648 :     if (info.fInTried)
     223          24 :         return;
     224             : 
     225             :     // find a bucket it is in now
     226        2624 :     int nRnd = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
     227             :     int nUBucket = -1;
     228     1362731 :     for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
     229     1362731 :         int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
     230     1362731 :         int nBpos = info.GetBucketPosition(nKey, true, nB);
     231     1362731 :         if (vvNew[nB][nBpos] == nId) {
     232             :             nUBucket = nB;
     233        2624 :             break;
     234             :         }
     235     1360107 :     }
     236             : 
     237             :     // if no bucket is found, something bad happened;
     238             :     // TODO: maybe re-add the node, but for now, just bail out
     239        2624 :     if (nUBucket == -1)
     240           0 :         return;
     241             : 
     242             :     // which tried bucket to move the entry to
     243        2624 :     int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
     244        2624 :     int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
     245             : 
     246             :     // Will moving this address into tried evict another entry?
     247        2624 :     if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
     248             :         // Output the entry we'd be colliding with, for debugging purposes
     249          49 :         auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
     250          49 :         LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
     251          49 :         if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
     252          49 :             m_tried_collisions.insert(nId);
     253          49 :         }
     254          49 :     } else {
     255        2575 :         LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
     256             : 
     257             :         // move nId to the tried tables
     258        2575 :         MakeTried(info, nId);
     259             :     }
     260        5868 : }
     261             : 
     262      317182 : bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
     263             : {
     264      317182 :     if (!addr.IsRoutable())
     265        3444 :         return false;
     266             : 
     267             :     bool fNew = false;
     268      313738 :     int nId;
     269      313738 :     CAddrInfo* pinfo = Find(addr, &nId);
     270             : 
     271             :     // Do not set a penalty for a source's self-announcement
     272      313738 :     if (addr == source) {
     273             :         nTimePenalty = 0;
     274       11514 :     }
     275             : 
     276      313738 :     if (pinfo) {
     277             :         // periodically update nTime
     278           6 :         bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
     279           6 :         int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
     280           6 :         if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
     281           0 :             pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
     282             : 
     283             :         // add services
     284           6 :         pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
     285             : 
     286             :         // do not update if no new information is present
     287           6 :         if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
     288           6 :             return false;
     289             : 
     290             :         // do not update if the entry was already in the "tried" table
     291           0 :         if (pinfo->fInTried)
     292           0 :             return false;
     293             : 
     294             :         // do not update if the max reference count is reached
     295           0 :         if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
     296           0 :             return false;
     297             : 
     298             :         // stochastic test: previous nRefCount == N: 2^N times harder to increase it
     299             :         int nFactor = 1;
     300           0 :         for (int n = 0; n < pinfo->nRefCount; n++)
     301           0 :             nFactor *= 2;
     302           0 :         if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
     303           0 :             return false;
     304           0 :     } else {
     305      313732 :         pinfo = Create(addr, source, &nId);
     306      313732 :         pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
     307      313732 :         nNew++;
     308             :         fNew = true;
     309             :     }
     310             : 
     311      313732 :     int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
     312      313732 :     int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
     313      313732 :     if (vvNew[nUBucket][nUBucketPos] != nId) {
     314      313732 :         bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
     315      313732 :         if (!fInsert) {
     316       46719 :             CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
     317       46719 :             if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
     318             :                 // Overwrite the existing new table entry.
     319             :                 fInsert = true;
     320           1 :             }
     321       46719 :         }
     322      313732 :         if (fInsert) {
     323      267014 :             ClearNew(nUBucket, nUBucketPos);
     324      267014 :             pinfo->nRefCount++;
     325      267014 :             vvNew[nUBucket][nUBucketPos] = nId;
     326      267014 :         } else {
     327       46718 :             if (pinfo->nRefCount == 0) {
     328       46718 :                 Delete(nId);
     329       46718 :             }
     330             :         }
     331      313732 :     }
     332      313732 :     return fNew;
     333      317182 : }
     334             : 
     335         253 : void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
     336             : {
     337         253 :     CAddrInfo* pinfo = Find(addr);
     338             : 
     339             :     // if not found, bail out
     340         253 :     if (!pinfo)
     341         246 :         return;
     342             : 
     343             :     CAddrInfo& info = *pinfo;
     344             : 
     345             :     // check whether we are talking about the exact same CService (including same port)
     346           7 :     if (info != addr)
     347           0 :         return;
     348             : 
     349             :     // update info
     350           7 :     info.nLastTry = nTime;
     351           7 :     if (fCountFailure && info.nLastCountAttempt < nLastGood) {
     352           0 :         info.nLastCountAttempt = nTime;
     353           0 :         info.nAttempts++;
     354           0 :     }
     355         260 : }
     356             : 
     357       25935 : CAddrInfo CAddrMan::Select_(bool newOnly)
     358             : {
     359       25935 :     if (size() == 0)
     360       25458 :         return CAddrInfo();
     361             : 
     362         477 :     if (newOnly && nNew == 0)
     363           1 :         return CAddrInfo();
     364             : 
     365             :     // Use a 50% chance for choosing between tried and new table entries.
     366         496 :     if (!newOnly &&
     367         474 :        (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
     368             :         // use a tried node
     369         189 :         double fChanceFactor = 1.0;
     370          12 :         while (1) {
     371         189 :             int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
     372         189 :             int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
     373      787864 :             while (vvTried[nKBucket][nKBucketPos] == -1) {
     374      787675 :                 nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
     375      787675 :                 nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
     376             :             }
     377         189 :             int nId = vvTried[nKBucket][nKBucketPos];
     378         189 :             assert(mapInfo.count(nId) == 1);
     379         189 :             CAddrInfo& info = mapInfo[nId];
     380         189 :             if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
     381          12 :                 return info;
     382         177 :             fChanceFactor *= 1.2;
     383         189 :         }
     384             :     } else {
     385             :         // use a new node
     386         464 :         double fChanceFactor = 1.0;
     387         464 :         while (1) {
     388         464 :             int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
     389         464 :             int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
     390      496460 :             while (vvNew[nUBucket][nUBucketPos] == -1) {
     391      495996 :                 nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
     392      495996 :                 nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
     393             :             }
     394         464 :             int nId = vvNew[nUBucket][nUBucketPos];
     395         464 :             assert(mapInfo.count(nId) == 1);
     396         464 :             CAddrInfo& info = mapInfo[nId];
     397         464 :             if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
     398         464 :                 return info;
     399           0 :             fChanceFactor *= 1.2;
     400         464 :         }
     401             :     }
     402       25935 : }
     403             : 
     404             : #ifdef DEBUG_ADDRMAN
     405             : int CAddrMan::Check_()
     406             : {
     407             :     std::set<int> setTried;
     408             :     std::map<int, int> mapNew;
     409             : 
     410             :     if (vRandom.size() != (size_t)(nTried + nNew))
     411             :         return -7;
     412             : 
     413             :     for (const auto& entry : mapInfo) {
     414             :         int n = entry.first;
     415             :         const CAddrInfo& info = entry.second;
     416             :         if (info.fInTried) {
     417             :             if (!info.nLastSuccess)
     418             :                 return -1;
     419             :             if (info.nRefCount)
     420             :                 return -2;
     421             :             setTried.insert(n);
     422             :         } else {
     423             :             if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
     424             :                 return -3;
     425             :             if (!info.nRefCount)
     426             :                 return -4;
     427             :             mapNew[n] = info.nRefCount;
     428             :         }
     429             :         if (mapAddr[info] != n)
     430             :             return -5;
     431             :         if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
     432             :             return -14;
     433             :         if (info.nLastTry < 0)
     434             :             return -6;
     435             :         if (info.nLastSuccess < 0)
     436             :             return -8;
     437             :     }
     438             : 
     439             :     if (setTried.size() != (size_t)nTried)
     440             :         return -9;
     441             :     if (mapNew.size() != (size_t)nNew)
     442             :         return -10;
     443             : 
     444             :     for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
     445             :         for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
     446             :              if (vvTried[n][i] != -1) {
     447             :                  if (!setTried.count(vvTried[n][i]))
     448             :                      return -11;
     449             :                  if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n)
     450             :                      return -17;
     451             :                  if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
     452             :                      return -18;
     453             :                  setTried.erase(vvTried[n][i]);
     454             :              }
     455             :         }
     456             :     }
     457             : 
     458             :     for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
     459             :         for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
     460             :             if (vvNew[n][i] != -1) {
     461             :                 if (!mapNew.count(vvNew[n][i]))
     462             :                     return -12;
     463             :                 if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
     464             :                     return -19;
     465             :                 if (--mapNew[vvNew[n][i]] == 0)
     466             :                     mapNew.erase(vvNew[n][i]);
     467             :             }
     468             :         }
     469             :     }
     470             : 
     471             :     if (setTried.size())
     472             :         return -13;
     473             :     if (mapNew.size())
     474             :         return -15;
     475             :     if (nKey.IsNull())
     476             :         return -16;
     477             : 
     478             :     return 0;
     479             : }
     480             : #endif
     481             : 
     482         207 : void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct)
     483             : {
     484         207 :     size_t nNodes = vRandom.size();
     485         207 :     if (max_pct != 0) {
     486         201 :         nNodes = max_pct * nNodes / 100;
     487         201 :     }
     488         207 :     if (max_addresses != 0) {
     489         203 :         nNodes = std::min(nNodes, max_addresses);
     490         203 :     }
     491             : 
     492             :     // gather a list of random nodes, skipping those of low quality
     493       47483 :     for (unsigned int n = 0; n < vRandom.size(); n++) {
     494       47293 :         if (vAddr.size() >= nNodes)
     495          17 :             break;
     496             : 
     497       47276 :         int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
     498       47276 :         SwapRandom(n, nRndPos);
     499       47276 :         assert(mapInfo.count(vRandom[n]) == 1);
     500             : 
     501       47276 :         const CAddrInfo& ai = mapInfo[vRandom[n]];
     502       47276 :         if (!ai.IsTerrible())
     503       47276 :             vAddr.push_back(ai);
     504             :     }
     505         207 : }
     506             : 
     507         237 : void CAddrMan::Connected_(const CService& addr, int64_t nTime)
     508             : {
     509         237 :     CAddrInfo* pinfo = Find(addr);
     510             : 
     511             :     // if not found, bail out
     512         237 :     if (!pinfo)
     513         237 :         return;
     514             : 
     515             :     CAddrInfo& info = *pinfo;
     516             : 
     517             :     // check whether we are talking about the exact same CService (including same port)
     518           0 :     if (info != addr)
     519           0 :         return;
     520             : 
     521             :     // update info
     522             :     int64_t nUpdateInterval = 20 * 60;
     523           0 :     if (nTime - info.nTime > nUpdateInterval)
     524           0 :         info.nTime = nTime;
     525         237 : }
     526             : 
     527         238 : void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
     528             : {
     529         238 :     CAddrInfo* pinfo = Find(addr);
     530             : 
     531             :     // if not found, bail out
     532         238 :     if (!pinfo)
     533         238 :         return;
     534             : 
     535             :     CAddrInfo& info = *pinfo;
     536             : 
     537             :     // check whether we are talking about the exact same CService (including same port)
     538           0 :     if (info != addr)
     539           0 :         return;
     540             : 
     541             :     // update info
     542           0 :     info.nServices = nServices;
     543         238 : }
     544             : 
     545       25467 : void CAddrMan::ResolveCollisions_()
     546             : {
     547       25472 :     for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
     548           5 :         int id_new = *it;
     549             : 
     550             :         bool erase_collision = false;
     551             : 
     552             :         // If id_new not found in mapInfo remove it from m_tried_collisions
     553           5 :         if (mapInfo.count(id_new) != 1) {
     554             :             erase_collision = true;
     555           0 :         } else {
     556           5 :             CAddrInfo& info_new = mapInfo[id_new];
     557             : 
     558             :             // Which tried bucket to move the entry to.
     559           5 :             int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
     560           5 :             int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
     561           5 :             if (!info_new.IsValid()) { // id_new may no longer map to a valid address
     562             :                 erase_collision = true;
     563           5 :             } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
     564             : 
     565             :                 // Get the to-be-evicted address that is being tested
     566           5 :                 int id_old = vvTried[tried_bucket][tried_bucket_pos];
     567           5 :                 CAddrInfo& info_old = mapInfo[id_old];
     568             : 
     569             :                 // Has successfully connected in last X hours
     570           5 :                 if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
     571             :                     erase_collision = true;
     572           5 :                 } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
     573             : 
     574             :                     // Give address at least 60 seconds to successfully connect
     575           1 :                     if (GetAdjustedTime() - info_old.nLastTry > 60) {
     576           1 :                         LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
     577             : 
     578             :                         // Replaces an existing address already in the tried table with the new address
     579           1 :                         Good_(info_new, false, GetAdjustedTime());
     580             :                         erase_collision = true;
     581           1 :                     }
     582           0 :                 } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
     583             :                     // If the collision hasn't resolved in some reasonable amount of time,
     584             :                     // just evict the old entry -- we must not be able to
     585             :                     // connect to it for some reason.
     586           0 :                     LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
     587           0 :                     Good_(info_new, false, GetAdjustedTime());
     588             :                     erase_collision = true;
     589           0 :                 }
     590           5 :             } else { // Collision is not actually a collision anymore
     591           0 :                 Good_(info_new, false, GetAdjustedTime());
     592             :                 erase_collision = true;
     593             :             }
     594             :         }
     595             : 
     596           5 :         if (erase_collision) {
     597           5 :             m_tried_collisions.erase(it++);
     598           5 :         } else {
     599           0 :             it++;
     600             :         }
     601           5 :     }
     602       25467 : }
     603             : 
     604       25884 : CAddrInfo CAddrMan::SelectTriedCollision_()
     605             : {
     606       25884 :     if (m_tried_collisions.size() == 0) return CAddrInfo();
     607             : 
     608           5 :     std::set<int>::iterator it = m_tried_collisions.begin();
     609             : 
     610             :     // Selects a random element from m_tried_collisions
     611           5 :     std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
     612           5 :     int id_new = *it;
     613             : 
     614             :     // If id_new not found in mapInfo remove it from m_tried_collisions
     615           5 :     if (mapInfo.count(id_new) != 1) {
     616           0 :         m_tried_collisions.erase(it);
     617           0 :         return CAddrInfo();
     618             :     }
     619             : 
     620           5 :     CAddrInfo& newInfo = mapInfo[id_new];
     621             : 
     622             :     // which tried bucket to move the entry to
     623           5 :     int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
     624           5 :     int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
     625             : 
     626           5 :     int id_old = vvTried[tried_bucket][tried_bucket_pos];
     627             : 
     628           5 :     return mapInfo[id_old];
     629       25884 : }
     630             : 
     631           5 : std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
     632             : {
     633           5 :     std::vector<bool> bits;
     634           5 :     FILE *filestr = fsbridge::fopen(path, "rb");
     635           5 :     CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
     636           5 :     if (file.IsNull()) {
     637           0 :         LogPrintf("Failed to open asmap file from disk\n");
     638           0 :         return bits;
     639             :     }
     640           5 :     fseek(filestr, 0, SEEK_END);
     641           5 :     int length = ftell(filestr);
     642           5 :     LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
     643           5 :     fseek(filestr, 0, SEEK_SET);
     644           5 :     char cur_byte;
     645         241 :     for (int i = 0; i < length; ++i) {
     646         236 :         file >> cur_byte;
     647        2124 :         for (int bit = 0; bit < 8; ++bit) {
     648        1888 :             bits.push_back((cur_byte >> bit) & 1);
     649             :         }
     650             :     }
     651           5 :     if (!SanityCheckASMap(bits)) {
     652           1 :         LogPrintf("Sanity check of asmap file %s failed\n", path);
     653           1 :         return {};
     654             :     }
     655           4 :     return bits;
     656           5 : }

Generated by: LCOV version 1.15