2012-01-04 19:39:45 -03:00
|
|
|
// Copyright (c) 2012 Pieter Wuille
|
2020-01-14 16:17:38 -03:00
|
|
|
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
2014-10-24 01:04:27 -03:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-05-18 10:02:28 -04:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2013-04-13 02:13:08 -03:00
|
|
|
|
2014-11-03 12:16:40 -03:00
|
|
|
#ifndef BITCOIN_ADDRMAN_H
|
|
|
|
#define BITCOIN_ADDRMAN_H
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2020-04-20 11:11:08 -04:00
|
|
|
#include <fs.h>
|
2021-09-07 05:48:45 -03:00
|
|
|
#include <logging.h>
|
2017-11-09 21:57:53 -03:00
|
|
|
#include <netaddress.h>
|
|
|
|
#include <protocol.h>
|
|
|
|
#include <sync.h>
|
|
|
|
#include <timedata.h>
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2021-09-07 05:48:45 -03:00
|
|
|
#include <cstdint>
|
2021-05-02 12:44:17 -04:00
|
|
|
#include <optional>
|
2013-04-13 02:13:08 -03:00
|
|
|
#include <set>
|
2020-04-20 11:11:08 -04:00
|
|
|
#include <unordered_map>
|
2019-12-29 14:54:33 -03:00
|
|
|
#include <vector>
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2020-10-23 18:03:24 -03:00
|
|
|
/** Default for -checkaddrman */
|
|
|
|
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
|
|
|
|
|
2015-04-28 11:48:28 -03:00
|
|
|
/**
|
|
|
|
* Extended statistics about a CAddress
|
2014-10-24 01:04:27 -03:00
|
|
|
*/
|
2012-01-04 19:39:45 -03:00
|
|
|
class CAddrInfo : public CAddress
|
|
|
|
{
|
2015-04-19 15:10:13 -03:00
|
|
|
public:
|
|
|
|
//! last try whatsoever by us (memory only)
|
2019-01-05 08:02:12 -03:00
|
|
|
int64_t nLastTry{0};
|
2015-04-19 15:10:13 -03:00
|
|
|
|
2015-04-19 17:39:38 -03:00
|
|
|
//! last counted attempt (memory only)
|
2019-01-05 08:02:12 -03:00
|
|
|
int64_t nLastCountAttempt{0};
|
2015-04-19 17:39:38 -03:00
|
|
|
|
2012-01-04 19:39:45 -03:00
|
|
|
private:
|
2014-10-24 01:04:27 -03:00
|
|
|
//! where knowledge about this address first came from
|
2012-01-04 19:39:45 -03:00
|
|
|
CNetAddr source;
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! last successful connection by us
|
2019-01-05 08:02:12 -03:00
|
|
|
int64_t nLastSuccess{0};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! connection attempts since last successful attempt
|
2019-01-05 08:02:12 -03:00
|
|
|
int nAttempts{0};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! reference count in new sets (memory only)
|
2019-01-05 08:02:12 -03:00
|
|
|
int nRefCount{0};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! in tried set? (memory only)
|
2019-01-05 08:02:12 -03:00
|
|
|
bool fInTried{false};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! position in vRandom
|
2021-05-13 07:43:36 -04:00
|
|
|
mutable int nRandomPos{-1};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
|
|
|
friend class CAddrMan;
|
2021-02-08 10:14:12 -03:00
|
|
|
friend class CAddrManDeterministic;
|
2012-01-04 19:39:45 -03:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-07-07 19:08:51 -04:00
|
|
|
SERIALIZE_METHODS(CAddrInfo, obj)
|
|
|
|
{
|
|
|
|
READWRITEAS(CAddress, obj);
|
|
|
|
READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
|
overhaul serialization code
The implementation of each class' serialization/deserialization is no longer
passed within a macro. The implementation now lies within a template of form:
template <typename T, typename Stream, typename Operation>
inline static size_t SerializationOp(T thisPtr, Stream& s, Operation ser_action, int nType, int nVersion) {
size_t nSerSize = 0;
/* CODE */
return nSerSize;
}
In cases when codepath should depend on whether or not we are just deserializing
(old fGetSize, fWrite, fRead flags) an additional clause can be used:
bool fRead = boost::is_same<Operation, CSerActionUnserialize>();
The IMPLEMENT_SERIALIZE macro will now be a freestanding clause added within
class' body (similiar to Qt's Q_OBJECT) to implement GetSerializeSize,
Serialize and Unserialize. These are now wrappers around
the "SerializationOp" template.
2014-08-20 02:42:31 -04:00
|
|
|
}
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2012-05-05 15:27:52 -04:00
|
|
|
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CAddrInfo() : CAddress(), source()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Calculate in which "tried" bucket this entry belongs
|
2019-12-24 15:18:44 -03:00
|
|
|
int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Calculate in which "new" bucket this entry belongs, given a certain source
|
2019-12-24 15:18:44 -03:00
|
|
|
int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Calculate in which "new" bucket this entry belongs, using its default source
|
2019-12-24 15:18:44 -03:00
|
|
|
int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2019-12-24 15:18:44 -03:00
|
|
|
return GetNewBucket(nKey, source, asmap);
|
2012-01-04 19:39:45 -03:00
|
|
|
}
|
|
|
|
|
2015-03-18 13:31:49 -03:00
|
|
|
//! Calculate in which position of a bucket to store this entry.
|
|
|
|
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
|
2013-04-13 02:13:08 -03:00
|
|
|
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
|
2013-04-13 02:13:08 -03:00
|
|
|
double GetChance(int64_t nNow = GetAdjustedTime()) const;
|
2012-01-04 19:39:45 -03:00
|
|
|
};
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
/** Stochastic address manager
|
|
|
|
*
|
|
|
|
* Design goals:
|
2015-04-28 11:47:17 -03:00
|
|
|
* * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
|
2014-10-24 01:04:27 -03:00
|
|
|
* * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
|
|
|
|
*
|
|
|
|
* To that end:
|
2021-07-28 17:48:34 -04:00
|
|
|
* * Addresses are organized into buckets that can each store up to 64 entries.
|
|
|
|
* * Addresses to which our node has not successfully connected go into 1024 "new" buckets.
|
|
|
|
* * Based on the address range (/16 for IPv4) of the source of information, or if an asmap is provided,
|
|
|
|
* the AS it belongs to (for IPv4/IPv6), 64 buckets are selected at random.
|
2015-04-28 11:48:28 -03:00
|
|
|
* * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
|
2021-07-28 17:48:34 -04:00
|
|
|
* * The position in the bucket is chosen based on the full address.
|
2015-04-22 10:02:01 -03:00
|
|
|
* * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
|
2014-10-24 01:04:27 -03:00
|
|
|
* are seen frequently. The chance for increasing this multiplicity decreases exponentially.
|
2021-07-28 17:48:34 -04:00
|
|
|
* * When adding a new address to an occupied position of a bucket, it will not replace the existing entry
|
|
|
|
* unless that address is also stored in another bucket or it doesn't meet one of several quality criteria
|
|
|
|
* (see IsTerrible for exact criteria).
|
2015-03-19 14:01:57 -03:00
|
|
|
* * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
|
|
|
|
* * Each address range selects at random 8 of these buckets.
|
2014-10-24 01:04:27 -03:00
|
|
|
* * The actual bucket is chosen from one of these, based on the full address.
|
2021-07-28 17:48:34 -04:00
|
|
|
* * When adding a new good address to an occupied position of a bucket, a FEELER connection to the
|
|
|
|
* old address is attempted. The old entry is only replaced and moved back to the "new" buckets if this
|
|
|
|
* attempt was unsuccessful.
|
2014-10-24 01:04:27 -03:00
|
|
|
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
|
|
|
|
* be observable by adversaries.
|
2020-10-23 18:03:24 -03:00
|
|
|
* * Several indexes are kept for high performance. Setting m_consistency_check_ratio with the -checkaddrman
|
|
|
|
* configuration option will introduce (expensive) consistency checks for the entire data structure.
|
2014-10-24 01:04:27 -03:00
|
|
|
*/
|
|
|
|
|
2021-08-18 04:45:54 -04:00
|
|
|
/** Total number of buckets for tried addresses */
|
2021-08-17 12:31:23 -04:00
|
|
|
static constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2{8};
|
2021-08-17 16:55:11 -04:00
|
|
|
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT{1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2021-08-18 04:45:54 -04:00
|
|
|
/** Total number of buckets for new addresses */
|
2021-08-17 12:31:23 -04:00
|
|
|
static constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2{10};
|
2021-08-17 16:55:11 -04:00
|
|
|
static constexpr int ADDRMAN_NEW_BUCKET_COUNT{1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2};
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2021-08-18 04:45:54 -04:00
|
|
|
/** Maximum allowed number of entries in buckets for new and tried addresses */
|
2021-08-17 12:31:23 -04:00
|
|
|
static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6};
|
|
|
|
static constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2};
|
2017-02-15 22:45:22 -03:00
|
|
|
|
2018-07-24 11:59:49 -04:00
|
|
|
/**
|
|
|
|
* Stochastical (IP) address manager
|
2014-10-24 01:04:27 -03:00
|
|
|
*/
|
2012-01-04 19:39:45 -03:00
|
|
|
class CAddrMan
|
|
|
|
{
|
|
|
|
public:
|
2020-05-19 11:39:05 -04:00
|
|
|
template <typename Stream>
|
2021-08-17 12:31:23 -04:00
|
|
|
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2020-05-19 11:39:05 -04:00
|
|
|
template <typename Stream>
|
2021-08-17 12:31:23 -04:00
|
|
|
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
2014-07-10 14:16:58 -04:00
|
|
|
|
2021-08-24 06:27:05 -04:00
|
|
|
explicit CAddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
|
2012-01-04 19:39:45 -03:00
|
|
|
|
2015-03-08 10:30:05 -03:00
|
|
|
~CAddrMan()
|
|
|
|
{
|
2015-03-18 13:31:49 -03:00
|
|
|
nKey.SetNull();
|
2015-03-08 10:30:05 -03:00
|
|
|
}
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Return the number of (unique) addresses in all tables.
|
2015-06-15 09:43:31 -03:00
|
|
|
size_t size() const
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2016-11-25 23:11:25 -03:00
|
|
|
LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
|
2012-01-04 19:39:45 -03:00
|
|
|
return vRandom.size();
|
|
|
|
}
|
|
|
|
|
2021-07-22 20:00:36 -04:00
|
|
|
//! Add addresses to addrman's new table.
|
2013-04-13 02:13:08 -03:00
|
|
|
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2016-11-25 23:11:25 -03:00
|
|
|
LOCK(cs);
|
2012-01-04 19:39:45 -03:00
|
|
|
int nAdd = 0;
|
2016-11-25 23:11:25 -03:00
|
|
|
Check();
|
|
|
|
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
|
|
|
|
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
|
|
|
|
Check();
|
2016-12-25 17:19:40 -03:00
|
|
|
if (nAdd) {
|
|
|
|
LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
|
|
|
|
}
|
2012-01-04 19:39:45 -03:00
|
|
|
return nAdd > 0;
|
|
|
|
}
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Mark an entry as accessible.
|
2021-07-20 08:59:12 -04:00
|
|
|
void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2016-11-25 23:13:48 -03:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2021-07-20 08:59:12 -04:00
|
|
|
Good_(addr, /* test_before_evict */ true, nTime);
|
2016-11-25 23:13:48 -03:00
|
|
|
Check();
|
2012-01-04 19:39:45 -03:00
|
|
|
}
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
//! Mark an entry as connection attempted to.
|
2015-04-19 16:34:43 -03:00
|
|
|
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2016-11-25 23:13:48 -03:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
Attempt_(addr, fCountFailure, nTime);
|
|
|
|
Check();
|
2012-01-04 19:39:45 -03:00
|
|
|
}
|
|
|
|
|
2016-10-27 14:55:39 -03:00
|
|
|
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
|
|
|
|
void ResolveCollisions()
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2016-10-27 14:55:39 -03:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
ResolveCollisions_();
|
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Randomly select an address in tried that another address is attempting to evict.
|
|
|
|
CAddrInfo SelectTriedCollision()
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2016-10-27 14:55:39 -03:00
|
|
|
{
|
2021-05-23 12:40:21 -04:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
const CAddrInfo ret = SelectTriedCollision_();
|
|
|
|
Check();
|
2016-10-27 14:55:39 -03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-24 01:04:27 -03:00
|
|
|
/**
|
|
|
|
* Choose an address to connect to.
|
|
|
|
*/
|
2021-05-13 06:13:27 -04:00
|
|
|
CAddrInfo Select(bool newOnly = false) const
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2021-05-23 12:40:21 -04:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
const CAddrInfo addrRet = Select_(newOnly);
|
|
|
|
Check();
|
2012-01-04 19:39:45 -03:00
|
|
|
return addrRet;
|
|
|
|
}
|
|
|
|
|
2021-05-02 13:03:49 -04:00
|
|
|
/**
|
|
|
|
* Return all or many randomly selected addresses, optionally by network.
|
|
|
|
*
|
|
|
|
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
|
|
|
|
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
|
|
|
|
* @param[in] network Select only addresses of this network (nullopt = all).
|
|
|
|
*/
|
2021-05-13 07:43:36 -04:00
|
|
|
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2021-05-23 12:32:03 -04:00
|
|
|
LOCK(cs);
|
2012-01-04 19:39:45 -03:00
|
|
|
Check();
|
|
|
|
std::vector<CAddress> vAddr;
|
2021-05-23 12:32:03 -04:00
|
|
|
GetAddr_(vAddr, max_addresses, max_pct, network);
|
2012-01-04 19:39:45 -03:00
|
|
|
Check();
|
|
|
|
return vAddr;
|
|
|
|
}
|
|
|
|
|
2020-11-04 08:41:17 -03:00
|
|
|
//! Outer function for Connected_()
|
2013-04-13 02:13:08 -03:00
|
|
|
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2012-01-04 19:39:45 -03:00
|
|
|
{
|
2016-11-25 23:13:48 -03:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
Connected_(addr, nTime);
|
|
|
|
Check();
|
2012-01-04 19:39:45 -03:00
|
|
|
}
|
2015-09-22 16:24:16 -03:00
|
|
|
|
2016-06-08 13:12:22 -04:00
|
|
|
void SetServices(const CService &addr, ServiceFlags nServices)
|
2021-05-23 13:53:25 -04:00
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
2016-03-26 14:58:00 -03:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
SetServices_(addr, nServices);
|
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
2021-08-24 06:47:17 -04:00
|
|
|
const std::vector<bool>& GetAsmap() const { return m_asmap; }
|
|
|
|
|
2021-08-05 09:10:02 -04:00
|
|
|
private:
|
2021-05-23 14:11:00 -04:00
|
|
|
//! A mutex to protect the inner data structures.
|
|
|
|
mutable Mutex cs;
|
2021-05-24 12:26:49 -04:00
|
|
|
|
2021-07-23 05:48:34 -04:00
|
|
|
//! Source of random numbers for randomization in inner loops
|
|
|
|
mutable FastRandomContext insecure_rand GUARDED_BY(cs);
|
|
|
|
|
2021-08-05 09:10:02 -04:00
|
|
|
//! secret key to randomize bucket select with
|
|
|
|
uint256 nKey;
|
|
|
|
|
2021-05-24 12:26:49 -04:00
|
|
|
//! Serialization versions.
|
|
|
|
enum Format : uint8_t {
|
|
|
|
V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
|
|
|
|
V1_DETERMINISTIC = 1, //!< for pre-asmap files
|
|
|
|
V2_ASMAP = 2, //!< for files including asmap version
|
|
|
|
V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
|
|
|
|
};
|
|
|
|
|
|
|
|
//! The maximum format this software knows it can unserialize. Also, we always serialize
|
|
|
|
//! in this format.
|
|
|
|
//! The format (first byte in the serialized stream) can be higher than this and
|
|
|
|
//! still this software may be able to unserialize the file - if the second byte
|
|
|
|
//! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
|
|
|
|
static constexpr Format FILE_FORMAT = Format::V3_BIP155;
|
|
|
|
|
|
|
|
//! The initial value of a field that is incremented every time an incompatible format
|
|
|
|
//! change is made (such that old software versions would not be able to parse and
|
|
|
|
//! understand the new file format). This is 32 because we overtook the "key size"
|
|
|
|
//! field which was 32 historically.
|
|
|
|
//! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
|
|
|
|
static constexpr uint8_t INCOMPATIBILITY_BASE = 32;
|
|
|
|
|
|
|
|
//! last used nId
|
2021-08-05 09:14:21 -04:00
|
|
|
int nIdCount GUARDED_BY(cs){0};
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! table with information about all nIds
|
2020-04-20 11:11:08 -04:00
|
|
|
std::unordered_map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! find an nId based on its network address
|
2020-04-20 11:11:08 -04:00
|
|
|
std::unordered_map<CNetAddr, int, CNetAddrHash> mapAddr GUARDED_BY(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! randomly-ordered vector of all nIds
|
2021-05-13 07:43:36 -04:00
|
|
|
//! This is mutable because it is unobservable outside the class, so any
|
|
|
|
//! changes to it (even in const methods) are also unobservable.
|
|
|
|
mutable std::vector<int> vRandom GUARDED_BY(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
// number of "tried" entries
|
2021-08-05 09:14:21 -04:00
|
|
|
int nTried GUARDED_BY(cs){0};
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! list of "tried" buckets
|
|
|
|
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
|
|
|
|
|
|
|
//! number of (unique) "new" entries
|
2021-08-05 09:14:21 -04:00
|
|
|
int nNew GUARDED_BY(cs){0};
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! list of "new" buckets
|
|
|
|
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
|
|
|
|
2021-08-05 09:14:21 -04:00
|
|
|
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
|
|
|
|
int64_t nLastGood GUARDED_BY(cs){1};
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
|
|
|
|
std::set<int> m_tried_collisions;
|
|
|
|
|
2020-10-23 18:03:24 -03:00
|
|
|
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
|
|
|
|
const int32_t m_consistency_check_ratio;
|
|
|
|
|
2021-08-24 06:47:17 -04:00
|
|
|
// Compressed IP->ASN mapping, loaded from a file when a node starts.
|
|
|
|
// Should be always empty if no file was provided.
|
|
|
|
// This mapping is then used for bucketing nodes in Addrman.
|
|
|
|
//
|
|
|
|
// If asmap is provided, nodes will be bucketed by
|
|
|
|
// AS they belong to, in order to make impossible for a node
|
|
|
|
// to connect to several nodes hosted in a single AS.
|
|
|
|
// This is done in response to Erebus attack, but also to generally
|
|
|
|
// diversify the connections every node creates,
|
|
|
|
// especially useful when a large fraction of nodes
|
|
|
|
// operate under a couple of cloud providers.
|
|
|
|
//
|
|
|
|
// If a new asmap was provided, the existing records
|
|
|
|
// would be re-bucketed accordingly.
|
|
|
|
const std::vector<bool> m_asmap;
|
|
|
|
|
2021-05-24 12:26:49 -04:00
|
|
|
//! Find an entry.
|
|
|
|
CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
2021-08-02 16:22:18 -04:00
|
|
|
//! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.
|
2021-05-24 12:26:49 -04:00
|
|
|
CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Swap two elements in vRandom.
|
2021-05-13 07:43:36 -04:00
|
|
|
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! Move an entry from the "new" table(s) to the "tried" table
|
|
|
|
void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Delete an entry. It must not be in tried, and have refcount 0.
|
|
|
|
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Clear a position in a "new" table. This is the only place where entries are actually deleted.
|
|
|
|
void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Mark an entry "good", possibly moving it from "new" to "tried".
|
|
|
|
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Add an entry to the "new" table.
|
|
|
|
bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Mark an entry as attempted to connect.
|
|
|
|
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
|
2021-05-13 06:13:27 -04:00
|
|
|
CAddrInfo Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
|
|
|
|
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Return a random to-be-evicted tried table address.
|
|
|
|
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
2021-05-23 12:17:23 -04:00
|
|
|
//! Consistency check
|
2020-10-23 18:03:24 -03:00
|
|
|
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
|
2021-05-23 12:17:23 -04:00
|
|
|
{
|
2021-05-23 12:32:03 -04:00
|
|
|
AssertLockHeld(cs);
|
2020-10-23 18:03:24 -03:00
|
|
|
|
2021-05-23 12:23:28 -04:00
|
|
|
const int err = Check_();
|
|
|
|
if (err) {
|
|
|
|
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
|
2020-10-23 18:03:24 -03:00
|
|
|
assert(false);
|
2021-05-23 12:17:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-24 12:26:49 -04:00
|
|
|
//! Perform consistency check. Returns an error code or zero.
|
2021-05-13 06:13:27 -04:00
|
|
|
int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return all or many randomly selected addresses, optionally by network.
|
|
|
|
*
|
|
|
|
* @param[out] vAddr Vector of randomly selected addresses from vRandom.
|
|
|
|
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
|
|
|
|
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
|
|
|
|
* @param[in] network Select only addresses of this network (nullopt = all).
|
|
|
|
*/
|
2021-05-13 07:43:36 -04:00
|
|
|
void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
2021-05-24 12:26:49 -04:00
|
|
|
|
|
|
|
/** We have successfully connected to this peer. Calling this function
|
|
|
|
* updates the CAddress's nTime, which is used in our IsTerrible()
|
|
|
|
* decisions and gossiped to peers. Callers should be careful that updating
|
|
|
|
* this information doesn't leak topology information to network spies.
|
|
|
|
*
|
|
|
|
* net_processing calls this function when it *disconnects* from a peer to
|
|
|
|
* not leak information about currently connected peers.
|
|
|
|
*
|
|
|
|
* @param[in] addr The address of the peer we were connected to
|
|
|
|
* @param[in] nTime The time that we were last connected to this peer
|
|
|
|
*/
|
|
|
|
void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
//! Update an entry's service bits.
|
|
|
|
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
|
|
|
|
|
|
|
friend class CAddrManTest;
|
2021-02-08 10:14:12 -03:00
|
|
|
friend class CAddrManDeterministic;
|
2012-01-04 19:39:45 -03:00
|
|
|
};
|
|
|
|
|
2014-11-03 12:16:40 -03:00
|
|
|
#endif // BITCOIN_ADDRMAN_H
|