LCOV - code coverage report
Current view: top level - src - addrman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 274 298 91.9 %
Date: 2025-02-23 09:33:43 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14