LCOV - code coverage report
Current view: top level - src - addrman.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 215 238 90.3 %
Date: 2025-02-23 09:33:43 Functions: 28 29 96.6 %

          Line data    Source code
       1             : // Copyright (c) 2012 Pieter Wuille
       2             : // Copyright (c) 2012-2015 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             : #ifndef PIVX_ADDRMAN_H
       8             : #define PIVX_ADDRMAN_H
       9             : 
      10             : #if defined(HAVE_CONFIG_H)
      11             : #include "config/pivx-config.h"
      12             : #endif //HAVE_CONFIG_H
      13             : 
      14             : #include "clientversion.h"
      15             : #include "netaddress.h"
      16             : #include "optional.h"
      17             : #include "protocol.h"
      18             : #include "random.h"
      19             : #include "sync.h"
      20             : #include "timedata.h"
      21             : #include "tinyformat.h"
      22             : #include "util/system.h"
      23             : 
      24             : #include <fs.h>
      25             : #include <hash.h>
      26             : #include <iostream>
      27             : #include <map>
      28             : #include <set>
      29             : #include <stdint.h>
      30             : #include <streams.h>
      31             : #include <vector>
      32             : 
      33             : /**
      34             :  * Extended statistics about a CAddress
      35             :  */
      36             : class CAddrInfo : public CAddress
      37             : {
      38             : public:
      39             :     //! last try whatsoever by us (memory only)
      40             :     int64_t nLastTry{0};
      41             : 
      42             :     //! last counted attempt (memory only)
      43             :     int64_t nLastCountAttempt{0};
      44             : 
      45             : private:
      46             :     //! where knowledge about this address first came from
      47             :     CNetAddr source;
      48             : 
      49             :     //! last successful connection by us
      50             :     int64_t nLastSuccess{0};
      51             : 
      52             :     //! connection attempts since last successful attempt
      53             :     int nAttempts{0};
      54             : 
      55             :     //! reference count in new sets (memory only)
      56             :     int nRefCount{0};
      57             : 
      58             :     //! in tried set? (memory only)
      59             :     bool fInTried{false};
      60             : 
      61             :     //! position in vRandom
      62             :     int nRandomPos{-1};
      63             : 
      64             :     friend class CAddrMan;
      65             : 
      66             : public:
      67             : 
      68       35972 :     SERIALIZE_METHODS(CAddrInfo, obj)
      69             :     {
      70       17986 :         READWRITEAS(CAddress, obj);
      71       17984 :         READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
      72       17984 :     }
      73             : 
      74       16203 :     CAddrInfo(const CAddress& addrIn, const CNetAddr& addrSource) : CAddress(addrIn), source(addrSource)
      75             :     {
      76       16203 :     }
      77             : 
      78      164977 :     CAddrInfo() : CAddress(), source()
      79             :     {
      80      164977 :     }
      81             : 
      82             :     //! Calculate in which "tried" bucket this entry belongs
      83             :     int GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const;
      84             : 
      85             :     //! Calculate in which "new" bucket this entry belongs, given a certain source
      86             :     int GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const;
      87             : 
      88             :     //! Calculate in which "new" bucket this entry belongs, using its default source
      89        3724 :     int GetNewBucket(const uint256& nKey, const std::vector<bool>& asmap) const
      90             :     {
      91        3716 :         return GetNewBucket(nKey, source, asmap);
      92             :     }
      93             : 
      94             :     //! Calculate in which position of a bucket to store this entry.
      95             :     int GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const;
      96             : 
      97             :     //! Determine whether the statistics about this entry are bad enough so that it can just be deleted
      98             :     bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
      99             : 
     100             :     //! Calculate the relative chance this entry should be given when selecting nodes to connect to
     101             :     double GetChance(int64_t nNow = GetAdjustedTime()) const;
     102             : };
     103             : 
     104             : /** Stochastic address manager
     105             :  *
     106             :  * Design goals:
     107             :  *  * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
     108             :  *  * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
     109             :  *
     110             :  * To that end:
     111             :  *  * Addresses are organized into buckets.
     112             :  *    * Addresses that have not yet been tried go into 1024 "new" buckets.
     113             :  *      * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.
     114             :  *      * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
     115             :  *      * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
     116             :  *        are seen frequently. The chance for increasing this multiplicity decreases exponentially.
     117             :  *      * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
     118             :  *        ones) is removed from it first.
     119             :  *    * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
     120             :  *      * Each address range selects at random 8 of these buckets.
     121             :  *      * The actual bucket is chosen from one of these, based on the full address.
     122             :  *      * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
     123             :  *        tried ones) is evicted from it, back to the "new" buckets.
     124             :  *    * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
     125             :  *      be observable by adversaries.
     126             :  *    * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
     127             :  *      consistency checks for the entire data structure.
     128             :  */
     129             : 
     130             : //! total number of buckets for tried addresses
     131             : #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
     132             : 
     133             : //! total number of buckets for new addresses
     134             : #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
     135             : 
     136             : //! maximum allowed number of entries in buckets for new and tried addresses
     137             : #define ADDRMAN_BUCKET_SIZE_LOG2 6
     138             : 
     139             : //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
     140             : #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
     141             : 
     142             : //! over how many buckets entries with new addresses originating from a single group are spread
     143             : #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
     144             : 
     145             : //! in how many buckets for entries with new addresses a single address may occur
     146             : #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
     147             : 
     148             : //! how old addresses can maximally be
     149             : #define ADDRMAN_HORIZON_DAYS 30
     150             : 
     151             : //! after how many failed attempts we give up on a new node
     152             : #define ADDRMAN_RETRIES 3
     153             : 
     154             : //! how many successive failures are allowed ...
     155             : #define ADDRMAN_MAX_FAILURES 10
     156             : 
     157             : //! ... in at least this many days
     158             : #define ADDRMAN_MIN_FAIL_DAYS 7
     159             : 
     160             : //! how recent a successful connection should be before we allow an address to be evicted from tried
     161             : #define ADDRMAN_REPLACEMENT_HOURS 4
     162             : 
     163             : //! Convenience
     164             : #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
     165             : #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
     166             : #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
     167             : 
     168             : //! the maximum number of tried addr collisions to store
     169             : #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
     170             : 
     171             : //! the maximum time we'll spend trying to resolve a tried table collision, in seconds
     172             : static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
     173             : 
     174             : /**
     175             :  * Stochastical (IP) address manager
     176             :  */
     177             : class CAddrMan
     178             : {
     179             : friend class CAddrManTest;
     180             : protected:
     181             :     //! critical section to protect the inner data structures
     182             :     mutable RecursiveMutex cs;
     183             : 
     184             : private:
     185             :     //! Serialization versions.
     186             :     enum Format : uint8_t {
     187             :         V0_HISTORICAL = 0,    //!< historic format, before commit e6b343d88
     188             :         V1_DETERMINISTIC = 1, //!< for pre-asmap files
     189             :         V2_ASMAP = 2,         //!< for files including asmap version
     190             :         V3_BIP155 = 3,        //!< same as V2_ASMAP plus addresses are in BIP155 format
     191             :     };
     192             : 
     193             :     //! The maximum format this software knows it can unserialize. Also, we always serialize
     194             :     //! in this format.
     195             :     //! The format (first byte in the serialized stream) can be higher than this and
     196             :     //! still this software may be able to unserialize the file - if the second byte
     197             :     //! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
     198             :     static constexpr Format FILE_FORMAT = Format::V3_BIP155;
     199             : 
     200             :     //! The initial value of a field that is incremented every time an incompatible format
     201             :     //! change is made (such that old software versions would not be able to parse and
     202             :     //! understand the new file format). This is 32 because we overtook the "key size"
     203             :     //! field which was 32 historically.
     204             :     //! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
     205             :     static constexpr uint8_t INCOMPATIBILITY_BASE = 32;
     206             : 
     207             :     //! last used nId
     208             :     int nIdCount GUARDED_BY(cs);
     209             : 
     210             :     //! table with information about all nIds
     211             :     std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
     212             : 
     213             :     //! find an nId based on its network address
     214             :     std::map<CNetAddr, int> mapAddr GUARDED_BY(cs);
     215             : 
     216             :     //! randomly-ordered vector of all nIds
     217             :     std::vector<int> vRandom GUARDED_BY(cs);
     218             : 
     219             :     // number of "tried" entries
     220             :     int nTried GUARDED_BY(cs);
     221             : 
     222             :     //! list of "tried" buckets
     223             :     int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
     224             : 
     225             :     //! number of (unique) "new" entries
     226             :     int nNew GUARDED_BY(cs);
     227             : 
     228             :     //! list of "new" buckets
     229             :     int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
     230             : 
     231             :     //! last time Good was called (memory only)
     232             :     int64_t nLastGood GUARDED_BY(cs);
     233             : 
     234             :     //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
     235             :     std::set<int> m_tried_collisions;
     236             : 
     237             : protected:
     238             :     //! secret key to randomize bucket select with
     239             :     uint256 nKey;
     240             : 
     241             :     //! Source of random numbers for randomization in inner loops
     242             :     FastRandomContext insecure_rand;
     243             : 
     244             :     //! Find an entry.
     245             :     CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
     246             : 
     247             :     //! find an entry, creating it if necessary.
     248             :     //! nTime and nServices of the found node are updated, if necessary.
     249             :     CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
     250             : 
     251             :     //! Swap two elements in vRandom.
     252             :     void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
     253             : 
     254             :     //! Move an entry from the "new" table(s) to the "tried" table
     255             :     void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
     256             : 
     257             :     //! Delete an entry. It must not be in tried, and have refcount 0.
     258             :     void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
     259             : 
     260             :     //! Clear a position in a "new" table. This is the only place where entries are actually deleted.
     261             :     void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
     262             : 
     263             :     //! Mark an entry "good", possibly moving it from "new" to "tried".
     264             :     void Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
     265             : 
     266             :     //! Add an entry to the "new" table.
     267             :     bool Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
     268             : 
     269             :     //! Mark an entry as attempted to connect.
     270             :     void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
     271             : 
     272             :     //! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
     273             :     CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
     274             : 
     275             :     //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
     276             :     void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
     277             : 
     278             :     //! Return a random to-be-evicted tried table address.
     279             :     CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
     280             : 
     281             : #ifdef DEBUG_ADDRMAN
     282             :     //! Perform consistency check. Returns an error code or zero.
     283             :     int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
     284             : #endif
     285             : 
     286             :     /**
     287             :      * Return all or many randomly selected addresses, optionally by network.
     288             :      *
     289             :      * @param[out] vAddr         Vector of randomly selected addresses from vRandom.
     290             :      * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
     291             :      * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
     292             :      * @param[in] network        Select only addresses of this network (nullopt = all).
     293             :      */
     294             :     void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, Optional<Network> network) EXCLUSIVE_LOCKS_REQUIRED(cs);
     295             : 
     296             :     //! Mark an entry as currently-connected-to.
     297             :     void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
     298             : 
     299             :     //! Update an entry's service bits.
     300             :     void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
     301             : 
     302             : public:
     303             :     // Compressed IP->ASN mapping, loaded from a file when a node starts.
     304             :     // Should be always empty if no file was provided.
     305             :     // This mapping is then used for bucketing nodes in Addrman.
     306             :     //
     307             :     // If asmap is provided, nodes will be bucketed by
     308             :     // AS they belong to, in order to make impossible for a node
     309             :     // to connect to several nodes hosted in a single AS.
     310             :     // This is done in response to Erebus attack, but also to generally
     311             :     // diversify the connections every node creates,
     312             :     // especially useful when a large fraction of nodes
     313             :     // operate under a couple of cloud providers.
     314             :     //
     315             :     // If a new asmap was provided, the existing records
     316             :     // would be re-bucketed accordingly.
     317             :     std::vector<bool> m_asmap;
     318             : 
     319             :     // Read asmap from provided binary file
     320             :     static std::vector<bool> DecodeAsmap(fs::path path);
     321             : 
     322             : 
     323             :     /**
     324             :      * Serialized format.
     325             :      * * format version byte (@see `Format`)
     326             :      * * lowest compatible format version byte. This is used to help old software decide
     327             :      *   whether to parse the file. For example:
     328             :      *   * PIVX Core version N knows how to parse up to format=3. If a new format=4 is
     329             :      *     introduced in version N+1 that is compatible with format=3 and it is known that
     330             :      *     version N will be able to parse it, then version N+1 will write
     331             :      *     (format=4, lowest_compatible=3) in the first two bytes of the file, and so
     332             :      *     version N will still try to parse it.
     333             :      *   * PIVX Core version N+2 introduces a new incompatible format=5. It will write
     334             :      *     (format=5, lowest_compatible=5) and so any versions that do not know how to parse
     335             :      *     format=5 will not try to read the file.
     336             :      * * nKey
     337             :      * * nNew
     338             :      * * nTried
     339             :      * * number of "new" buckets XOR 2**30
     340             :      * * all nNew addrinfos in vvNew
     341             :      * * all nTried addrinfos in vvTried
     342             :      * * for each bucket:
     343             :      *   * number of elements
     344             :      *   * for each element: index
     345             :      *
     346             :      * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
     347             :      * as incompatible. This is necessary because it did not check the version number on
     348             :      * deserialization.
     349             :      *
     350             :      * Notice that vvTried, mapAddr and vVector are never encoded explicitly;
     351             :      * they are instead reconstructed from the other information.
     352             :      *
     353             :      * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change,
     354             :      * otherwise it is reconstructed as well.
     355             :      *
     356             :      * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
     357             :      * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
     358             :      *
     359             :      * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
     360             :      * very little in common.
     361             :      */
     362             :     template <typename Stream>
     363        1258 :     void Serialize(Stream& s_) const
     364             :     {
     365        1258 :         LOCK(cs);
     366             : 
     367             :         // Always serialize in the latest version (FILE_FORMAT).
     368             : 
     369        1258 :         OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
     370             : 
     371        1258 :         s << static_cast<uint8_t>(FILE_FORMAT);
     372             : 
     373             :         // Increment `lowest_compatible` if a newly introduced format is incompatible with
     374             :         // the previous one.
     375             :         static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
     376        1258 :         s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
     377             : 
     378        1258 :         s << nKey;
     379        1258 :         s << nNew;
     380        1258 :         s << nTried;
     381             : 
     382        1258 :         int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
     383        1258 :         s << nUBuckets;
     384        1258 :         std::map<int, int> mapUnkIds;
     385        1258 :         int nIds = 0;
     386       19227 :         for (const auto& entry : mapInfo) {
     387       17969 :             mapUnkIds[entry.first] = nIds;
     388       17969 :             const CAddrInfo& info = entry.second;
     389       17969 :             if (info.nRefCount) {
     390       17969 :                 assert(nIds != nNew); // this means nNew was wrong, oh ow
     391       17969 :                 s << info;
     392       17969 :                 nIds++;
     393             :             }
     394             :         }
     395        1258 :         nIds = 0;
     396       19227 :         for (const auto& entry : mapInfo) {
     397       17969 :             const CAddrInfo& info = entry.second;
     398       17969 :             if (info.fInTried) {
     399           0 :                 assert(nIds != nTried); // this means nTried was wrong, oh ow
     400           0 :                 s << info;
     401           0 :                 nIds++;
     402             :             }
     403             :         }
     404     1289450 :         for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
     405             :             int nSize = 0;
     406    83732560 :             for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
     407    82444216 :                 if (vvNew[bucket][i] != -1)
     408       17969 :                     nSize++;
     409             :             }
     410     1288192 :             s << nSize;
     411    83732560 :             for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
     412    82444216 :                 if (vvNew[bucket][i] != -1) {
     413       17969 :                     int nIndex = mapUnkIds[vvNew[bucket][i]];
     414       17969 :                     s << nIndex;
     415             :                 }
     416             :             }
     417             :         }
     418             :         // Store asmap version after bucket entries so that it
     419             :         // can be ignored by older clients for backward compatibility.
     420        1258 :         uint256 asmap_version;
     421        1258 :         if (m_asmap.size() != 0) {
     422          10 :             asmap_version = SerializeHash(m_asmap);
     423             :         }
     424        1258 :         s << asmap_version;
     425        1258 :     }
     426             : 
     427             :     template <typename Stream>
     428          93 :     void Unserialize(Stream& s_)
     429             :     {
     430          93 :         LOCK(cs);
     431             : 
     432          93 :         Clear();
     433             : 
     434             :         Format format;
     435          93 :         s_ >> Using<CustomUintFormatter<1>>(format);
     436             : 
     437          93 :         int stream_version = s_.GetVersion();
     438          93 :         if (format >= Format::V3_BIP155) {
     439             :             // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
     440             :             // unserialize methods know that an address in addrv2 format is coming.
     441          91 :             stream_version |= ADDRV2_FORMAT;
     442             :         }
     443             : 
     444          93 :         OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
     445             : 
     446             :         uint8_t compat;
     447          93 :         s >> compat;
     448          93 :         const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
     449          93 :         if (lowest_compatible > FILE_FORMAT) {
     450             :             throw std::ios_base::failure(strprintf(
     451             :                 "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
     452             :                 "but the maximum supported by this version of %s is %u.",
     453           0 :                 format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
     454             :         }
     455             : 
     456          93 :         s >> nKey;
     457          93 :         s >> nNew;
     458          93 :         s >> nTried;
     459          93 :         int nUBuckets = 0;
     460          93 :         s >> nUBuckets;
     461          93 :         if (format >= Format::V1_DETERMINISTIC) {
     462          93 :             nUBuckets ^= (1 << 30);
     463             :         }
     464             : 
     465          93 :         if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
     466           0 :             throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
     467             :         }
     468             : 
     469          93 :         if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
     470           0 :             throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
     471             :         }
     472             : 
     473             :         // Deserialize entries from the new table.
     474         106 :         for (int n = 0; n < nNew; n++) {
     475          15 :             CAddrInfo& info = mapInfo[n];
     476          13 :             s >> info;
     477          13 :             mapAddr[info] = n;
     478          13 :             info.nRandomPos = vRandom.size();
     479          13 :             vRandom.push_back(n);
     480             :         }
     481          91 :         nIdCount = nNew;
     482             : 
     483             :         // Deserialize entries from the tried table.
     484          91 :         int nLost = 0;
     485          91 :         for (int n = 0; n < nTried; n++) {
     486           0 :             CAddrInfo info;
     487           0 :             s >> info;
     488           0 :             int nKBucket = info.GetTriedBucket(nKey, m_asmap);
     489           0 :             int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
     490           0 :             if (vvTried[nKBucket][nKBucketPos] == -1) {
     491           0 :                 info.nRandomPos = vRandom.size();
     492           0 :                 info.fInTried = true;
     493           0 :                 vRandom.push_back(nIdCount);
     494           0 :                 mapInfo[nIdCount] = info;
     495           0 :                 mapAddr[info] = nIdCount;
     496           0 :                 vvTried[nKBucket][nKBucketPos] = nIdCount;
     497           0 :                 nIdCount++;
     498             :             } else {
     499           0 :                 nLost++;
     500             :             }
     501             :         }
     502          91 :         nTried -= nLost;
     503             : 
     504             :         // Store positions in the new table buckets to apply later (if possible).
     505          91 :         std::map<int, int> entryToBucket; // Represents which entry belonged to which bucket when serializing
     506             : 
     507       93275 :         for (int bucket = 0; bucket < nUBuckets; bucket++) {
     508       93184 :             int nSize = 0;
     509       93184 :             s >> nSize;
     510       93195 :             for (int n = 0; n < nSize; n++) {
     511          11 :                 int nIndex = 0;
     512          11 :                 s >> nIndex;
     513          11 :                 if (nIndex >= 0 && nIndex < nNew) {
     514          11 :                     entryToBucket[nIndex] = bucket;
     515             :                 }
     516             :             }
     517             :         }
     518             : 
     519          91 :         uint256 supplied_asmap_version;
     520          91 :         if (m_asmap.size() != 0) {
     521           7 :             supplied_asmap_version = SerializeHash(m_asmap);
     522             :         }
     523          91 :         uint256 serialized_asmap_version;
     524          91 :         if (format >= Format::V2_ASMAP) {
     525          91 :             s >> serialized_asmap_version;
     526             :         }
     527             : 
     528         102 :         for (int n = 0; n < nNew; n++) {
     529          11 :             CAddrInfo &info = mapInfo[n];
     530          11 :             int bucket = entryToBucket[n];
     531          11 :             int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
     532          11 :             if (format >= Format::V2_ASMAP && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 &&
     533          22 :                 info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) {
     534             :                 // Bucketing has not changed, using existing bucket positions for the new table
     535           7 :                 vvNew[bucket][nUBucketPos] = n;
     536           7 :                 info.nRefCount++;
     537             :             } else {
     538             :                 // In case the new table data cannot be used (format unknown, bucket count wrong or new asmap),
     539             :                 // try to give them a reference based on their primary source address.
     540           4 :                 LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
     541           4 :                 bucket = info.GetNewBucket(nKey, m_asmap);
     542           4 :                 nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
     543           4 :                 if (vvNew[bucket][nUBucketPos] == -1) {
     544           4 :                     vvNew[bucket][nUBucketPos] = n;
     545           4 :                     info.nRefCount++;
     546             :                 }
     547             :             }
     548             :         }
     549             : 
     550             :         // Prune new entries with refcount 0 (as a result of collisions).
     551          91 :         int nLostUnk = 0;
     552          91 :         for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end();) {
     553          11 :             if (it->second.fInTried == false && it->second.nRefCount == 0) {
     554           0 :                 std::map<int, CAddrInfo>::const_iterator itCopy = it++;
     555           0 :                 Delete(itCopy->first);
     556           0 :                 nLostUnk++;
     557             :             } else {
     558         102 :                 it++;
     559             :             }
     560             :         }
     561          91 :         if (nLost + nLostUnk > 0) {
     562           0 :             LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
     563             :         }
     564             : 
     565          91 :         Check();
     566          91 :     }
     567             : 
     568         878 :     void Clear()
     569             :     {
     570         878 :         LOCK(cs);
     571         878 :         std::vector<int>().swap(vRandom);
     572         878 :         nKey = insecure_rand.rand256();
     573      899950 :         for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
     574    58439720 :             for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
     575    57540614 :                 vvNew[bucket][entry] = -1;
     576             :             }
     577             :         }
     578      225646 :         for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
     579    14609880 :             for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
     580    14385126 :                 vvTried[bucket][entry] = -1;
     581             :             }
     582             :         }
     583             : 
     584         878 :         nIdCount = 0;
     585         878 :         nTried = 0;
     586         878 :         nNew = 0;
     587         878 :         nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
     588         878 :         mapInfo.clear();
     589         878 :         mapAddr.clear();
     590         878 :     }
     591             : 
     592         509 :     CAddrMan()
     593        1018 :     {
     594         509 :         Clear();
     595         509 :     }
     596             : 
     597         509 :     ~CAddrMan()
     598         531 :     {
     599         509 :         nKey.SetNull();
     600         509 :     }
     601             : 
     602             :     //! Return the number of (unique) addresses in all tables.
     603       77541 :     size_t size() const
     604             :     {
     605       77541 :         LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
     606       77541 :         return vRandom.size();
     607             :     }
     608             : 
     609             :     //! Consistency check
     610      256087 :     void Check()
     611             :     {
     612             : #ifdef DEBUG_ADDRMAN
     613             :         {
     614             :             LOCK(cs);
     615             :             int err;
     616             :             if ((err = Check_()))
     617             :                 LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
     618             :         }
     619             : #endif
     620             :     }
     621             : 
     622             :     //! Add a single address.
     623        2321 :     bool Add(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty = 0)
     624             :     {
     625        2321 :         LOCK(cs);
     626        2321 :         bool fRet = false;
     627        2321 :         Check();
     628        2321 :         fRet |= Add_(addr, source, nTimePenalty);
     629        2321 :         Check();
     630        2321 :         if (fRet) {
     631        2226 :             LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
     632             :         }
     633        4642 :         return fRet;
     634             :     }
     635             : 
     636             :     //! Add multiple addresses.
     637       10131 :     bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
     638             :     {
     639       10131 :         LOCK(cs);
     640       10131 :         int nAdd = 0;
     641       10131 :         Check();
     642       20274 :         for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
     643       10656 :             nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
     644       10131 :         Check();
     645       10131 :         if (nAdd) {
     646       18990 :             LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
     647             :         }
     648       20262 :         return nAdd > 0;
     649             :     }
     650             : 
     651             :     //! Mark an entry as accessible.
     652        1092 :     void Good(const CService& addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
     653             :     {
     654        1092 :         LOCK(cs);
     655        1092 :         Check();
     656        1092 :         Good_(addr, test_before_evict, nTime);
     657        1092 :         Check();
     658        1092 :     }
     659             : 
     660             :     //! Mark an entry as connection attempted to.
     661         703 :     void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
     662             :     {
     663         703 :         LOCK(cs);
     664         703 :         Check();
     665         703 :         Attempt_(addr, fCountFailure, nTime);
     666         703 :         Check();
     667         703 :     }
     668             : 
     669             :     //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
     670       37781 :     void ResolveCollisions()
     671             :     {
     672       37781 :         LOCK(cs);
     673       37781 :         Check();
     674       37781 :         ResolveCollisions_();
     675       37781 :         Check();
     676       37781 :     }
     677             : 
     678             :     //! Randomly select an address in tried that another address is attempting to evict.
     679       38474 :     CAddrInfo SelectTriedCollision()
     680             :     {
     681       38474 :         CAddrInfo ret;
     682       38474 :         {
     683       38474 :             LOCK(cs);
     684       38474 :             Check();
     685       38474 :             ret = SelectTriedCollision_();
     686       38474 :             Check();
     687             :         }
     688       38474 :         return ret;
     689             :     }
     690             : 
     691             :     /**
     692             :      * Choose an address to connect to.
     693             :      * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
     694             :      */
     695       38393 :     CAddrInfo Select(bool newOnly = false)
     696             :     {
     697       38393 :         CAddrInfo addrRet;
     698       38393 :         {
     699       38393 :             LOCK(cs);
     700       38393 :             Check();
     701       38393 :             addrRet = Select_(newOnly);
     702       38393 :             Check();
     703             :         }
     704       38393 :         return addrRet;
     705             :     }
     706             : 
     707             :     /**
     708             :      * Return all or many randomly selected addresses, optionally by network.
     709             :      *
     710             :      * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
     711             :      * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
     712             :      * @param[in] network        Select only addresses of this network (nullopt = all).
     713             :      */
     714         660 :     std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, Optional<Network> network)
     715             :     {
     716         660 :         Check();
     717         660 :         std::vector<CAddress> vAddr;
     718         660 :         {
     719         660 :             LOCK(cs);
     720         660 :             GetAddr_(vAddr, max_addresses, max_pct, network);
     721             :         }
     722         660 :         Check();
     723         660 :         return vAddr;
     724             :     }
     725             : 
     726             :     //! Mark an entry as currently-connected-to.
     727         642 :     void Connected(const CService& addr, int64_t nTime = GetAdjustedTime())
     728             :     {
     729         642 :         LOCK(cs);
     730         642 :         Check();
     731         642 :         Connected_(addr, nTime);
     732         642 :         Check();
     733         642 :     }
     734             : 
     735         648 :     void SetServices(const CService& addr, ServiceFlags nServices)
     736             :     {
     737         648 :         LOCK(cs);
     738         648 :         Check();
     739         648 :         SetServices_(addr, nServices);
     740         648 :         Check();
     741         648 :     }
     742             : 
     743             : };
     744             : 
     745             : #endif // PIVX_ADDRMAN_H

Generated by: LCOV version 1.14