2012-01-04 23:39:45 +01:00
|
|
|
// Copyright (c) 2012 Pieter Wuille
|
2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2012-2022 The Bitcoin Core developers
|
2014-10-24 12:04:27 +08:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-05-18 22:02:28 +08:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2024-10-10 12:20:34 +02:00
|
|
|
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
2024-02-13 08:03:02 +01:00
|
|
|
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <addrman.h>
|
2021-09-01 11:21:29 -07:00
|
|
|
#include <addrman_impl.h>
|
2013-04-13 00:13:08 -05:00
|
|
|
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <hash.h>
|
2021-09-03 02:01:31 +02:00
|
|
|
#include <logging.h>
|
|
|
|
#include <logging/timer.h>
|
2021-05-02 18:44:17 +02:00
|
|
|
#include <netaddress.h>
|
2021-09-10 16:37:41 -06:00
|
|
|
#include <protocol.h>
|
|
|
|
#include <random.h>
|
2019-12-29 18:54:33 +01:00
|
|
|
#include <serialize.h>
|
2021-09-07 10:48:45 +02:00
|
|
|
#include <streams.h>
|
2021-09-10 16:37:41 -06:00
|
|
|
#include <tinyformat.h>
|
|
|
|
#include <uint256.h>
|
2021-09-09 21:41:51 +02:00
|
|
|
#include <util/check.h>
|
2022-03-24 19:56:00 +01:00
|
|
|
#include <util/time.h>
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2021-01-27 15:04:34 +08:00
|
|
|
#include <cmath>
|
2021-05-02 18:44:17 +02:00
|
|
|
#include <optional>
|
2021-01-27 15:04:34 +08:00
|
|
|
|
2021-08-18 09:45:54 +01:00
|
|
|
/** Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** Over how many buckets entries with new addresses originating from a single group are spread */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
|
2021-09-03 17:27:11 -07:00
|
|
|
/** Maximum number of times an address can occur in the new table */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** How old addresses can maximally be */
|
2022-03-28 14:20:04 +02:00
|
|
|
static constexpr auto ADDRMAN_HORIZON{30 * 24h};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** After how many failed attempts we give up on a new node */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr int32_t ADDRMAN_RETRIES{3};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** How many successive failures are allowed ... */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
|
2022-03-28 14:20:04 +02:00
|
|
|
/** ... in at least this duration */
|
|
|
|
static constexpr auto ADDRMAN_MIN_FAIL{7 * 24h};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** How recent a successful connection should be before we allow an address to be evicted from tried */
|
2022-03-28 14:20:04 +02:00
|
|
|
static constexpr auto ADDRMAN_REPLACEMENT{4h};
|
2021-08-18 09:45:54 +01:00
|
|
|
/** The maximum number of tried addr collisions to store */
|
2021-08-17 13:55:11 -07:00
|
|
|
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
|
2022-03-28 14:20:04 +02:00
|
|
|
/** The maximum time we'll spend trying to resolve a tried table collision */
|
|
|
|
static constexpr auto ADDRMAN_TEST_WINDOW{40min};
|
2021-08-17 13:55:11 -07:00
|
|
|
|
2021-09-01 12:12:52 +01:00
|
|
|
int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2023-08-25 16:57:52 +02:00
|
|
|
uint64_t hash1 = (HashWriter{} << nKey << GetKey()).GetCheapHash();
|
|
|
|
uint64_t hash2 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
|
2021-08-30 00:18:13 +02:00
|
|
|
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2021-09-01 12:12:52 +01:00
|
|
|
int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-09-01 12:12:52 +01:00
|
|
|
std::vector<unsigned char> vchSourceGroupKey = netgroupman.GetGroup(src);
|
2023-08-25 16:57:52 +02:00
|
|
|
uint64_t hash1 = (HashWriter{} << nKey << netgroupman.GetGroup(*this) << vchSourceGroupKey).GetCheapHash();
|
|
|
|
uint64_t hash2 = (HashWriter{} << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
|
2021-08-30 00:18:13 +02:00
|
|
|
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 10:09:28 -07:00
|
|
|
int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int bucket) const
|
2015-03-18 09:31:49 -07:00
|
|
|
{
|
2023-08-25 16:57:52 +02:00
|
|
|
uint64_t hash1 = (HashWriter{} << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << bucket << GetKey()).GetCheapHash();
|
2015-03-18 09:31:49 -07:00
|
|
|
return hash1 % ADDRMAN_BUCKET_SIZE;
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrInfo::IsTerrible(NodeSeconds now) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2022-03-28 14:20:04 +02:00
|
|
|
if (now - m_last_try <= 1min) { // never remove things tried in the last minute
|
2012-01-04 23:39:45 +01:00
|
|
|
return false;
|
2022-04-11 14:24:47 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
if (nTime > now + 10min) { // came in a flying DeLorean
|
2012-01-04 23:39:45 +01:00
|
|
|
return true;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history
|
2012-01-04 23:39:45 +01:00
|
|
|
return true;
|
2022-04-11 13:37:05 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success
|
2012-01-04 23:39:45 +01:00
|
|
|
return true;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week
|
2012-01-04 23:39:45 +01:00
|
|
|
return true;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
double AddrInfo::GetChance(NodeSeconds now) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
|
|
|
double fChance = 1.0;
|
|
|
|
|
|
|
|
// deprioritize very recent attempts away
|
2022-03-28 14:20:04 +02:00
|
|
|
if (now - m_last_try < 10min) {
|
2012-01-04 23:39:45 +01:00
|
|
|
fChance *= 0.01;
|
2022-07-26 11:10:03 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2015-04-19 11:47:56 -07:00
|
|
|
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
|
2015-06-15 14:45:19 +02:00
|
|
|
fChance *= pow(0.66, std::min(nAttempts, 8));
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
return fChance;
|
|
|
|
}
|
|
|
|
|
2021-08-31 18:40:18 +01:00
|
|
|
AddrManImpl::AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
|
2021-08-05 14:10:02 +01:00
|
|
|
: insecure_rand{deterministic}
|
2021-08-05 14:14:21 +01:00
|
|
|
, nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
|
2021-08-05 14:10:02 +01:00
|
|
|
, m_consistency_check_ratio{consistency_check_ratio}
|
2021-08-31 18:40:18 +01:00
|
|
|
, m_netgroupman{netgroupman}
|
2021-08-05 14:10:02 +01:00
|
|
|
{
|
2021-08-05 14:14:21 +01:00
|
|
|
for (auto& bucket : vvNew) {
|
|
|
|
for (auto& entry : bucket) {
|
|
|
|
entry = -1;
|
2021-08-05 14:10:02 +01:00
|
|
|
}
|
|
|
|
}
|
2021-08-05 14:14:21 +01:00
|
|
|
for (auto& bucket : vvTried) {
|
|
|
|
for (auto& entry : bucket) {
|
|
|
|
entry = -1;
|
2021-08-05 14:10:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
AddrManImpl::~AddrManImpl()
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
nKey.SetNull();
|
|
|
|
}
|
|
|
|
|
2021-08-17 17:31:23 +01:00
|
|
|
template <typename Stream>
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::Serialize(Stream& s_) const
|
2021-08-17 17:31:23 +01:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Serialized format.
|
|
|
|
* * format version byte (@see `Format`)
|
|
|
|
* * lowest compatible format version byte. This is used to help old software decide
|
|
|
|
* whether to parse the file. For example:
|
|
|
|
* * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
|
|
|
|
* introduced in version N+1 that is compatible with format=3 and it is known that
|
|
|
|
* version N will be able to parse it, then version N+1 will write
|
|
|
|
* (format=4, lowest_compatible=3) in the first two bytes of the file, and so
|
|
|
|
* version N will still try to parse it.
|
|
|
|
* * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
|
|
|
|
* (format=5, lowest_compatible=5) and so any versions that do not know how to parse
|
|
|
|
* format=5 will not try to read the file.
|
|
|
|
* * nKey
|
|
|
|
* * nNew
|
|
|
|
* * nTried
|
|
|
|
* * number of "new" buckets XOR 2**30
|
|
|
|
* * all new addresses (total count: nNew)
|
|
|
|
* * all tried addresses (total count: nTried)
|
|
|
|
* * for each new bucket:
|
|
|
|
* * number of elements
|
|
|
|
* * for each element: index in the serialized "all new addresses"
|
|
|
|
* * asmap checksum
|
|
|
|
*
|
|
|
|
* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
|
|
|
|
* as incompatible. This is necessary because it did not check the version number on
|
|
|
|
* deserialization.
|
|
|
|
*
|
|
|
|
* vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
|
|
|
|
* they are instead reconstructed from the other information.
|
|
|
|
*
|
|
|
|
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
|
|
|
|
* changes to the ADDRMAN_ parameters without breaking the on-disk structure.
|
|
|
|
*
|
|
|
|
* We don't use SERIALIZE_METHODS since the serialization and deserialization code has
|
|
|
|
* very little in common.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Always serialize in the latest version (FILE_FORMAT).
|
2023-11-22 16:39:32 -05:00
|
|
|
ParamsStream s{s_, CAddress::V2_DISK};
|
2021-08-17 17:31:23 +01:00
|
|
|
|
|
|
|
s << static_cast<uint8_t>(FILE_FORMAT);
|
|
|
|
|
|
|
|
// Increment `lowest_compatible` iff a newly introduced format is incompatible with
|
|
|
|
// the previous one.
|
2021-10-25 11:09:30 -04:00
|
|
|
static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;
|
2021-08-17 17:31:23 +01:00
|
|
|
s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
|
|
|
|
|
|
|
|
s << nKey;
|
|
|
|
s << nNew;
|
|
|
|
s << nTried;
|
|
|
|
|
|
|
|
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
|
|
|
|
s << nUBuckets;
|
2024-08-01 12:46:24 -04:00
|
|
|
std::unordered_map<nid_type, int> mapUnkIds;
|
2021-08-17 17:31:23 +01:00
|
|
|
int nIds = 0;
|
|
|
|
for (const auto& entry : mapInfo) {
|
|
|
|
mapUnkIds[entry.first] = nIds;
|
2021-09-10 18:53:57 -06:00
|
|
|
const AddrInfo& info = entry.second;
|
2021-08-17 17:31:23 +01:00
|
|
|
if (info.nRefCount) {
|
|
|
|
assert(nIds != nNew); // this means nNew was wrong, oh ow
|
|
|
|
s << info;
|
|
|
|
nIds++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nIds = 0;
|
|
|
|
for (const auto& entry : mapInfo) {
|
2021-09-10 18:53:57 -06:00
|
|
|
const AddrInfo& info = entry.second;
|
2021-08-17 17:31:23 +01:00
|
|
|
if (info.fInTried) {
|
|
|
|
assert(nIds != nTried); // this means nTried was wrong, oh ow
|
|
|
|
s << info;
|
|
|
|
nIds++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
|
|
|
|
int nSize = 0;
|
|
|
|
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
|
|
|
if (vvNew[bucket][i] != -1)
|
|
|
|
nSize++;
|
|
|
|
}
|
|
|
|
s << nSize;
|
|
|
|
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
|
|
|
if (vvNew[bucket][i] != -1) {
|
|
|
|
int nIndex = mapUnkIds[vvNew[bucket][i]];
|
|
|
|
s << nIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Store asmap checksum after bucket entries so that it
|
|
|
|
// can be ignored by older clients for backward compatibility.
|
2021-09-01 16:34:23 +01:00
|
|
|
s << m_netgroupman.GetAsmapChecksum();
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
|
2021-08-17 17:31:23 +01:00
|
|
|
template <typename Stream>
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::Unserialize(Stream& s_)
|
2021-08-17 17:31:23 +01:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
assert(vRandom.empty());
|
|
|
|
|
|
|
|
Format format;
|
|
|
|
s_ >> Using<CustomUintFormatter<1>>(format);
|
|
|
|
|
2023-01-31 18:04:44 +01:00
|
|
|
const auto ser_params = (format >= Format::V3_BIP155 ? CAddress::V2_DISK : CAddress::V1_DISK);
|
2023-11-22 16:39:32 -05:00
|
|
|
ParamsStream s{s_, ser_params};
|
2021-08-17 17:31:23 +01:00
|
|
|
|
|
|
|
uint8_t compat;
|
|
|
|
s >> compat;
|
2022-02-10 18:02:05 +01:00
|
|
|
if (compat < INCOMPATIBILITY_BASE) {
|
|
|
|
throw std::ios_base::failure(strprintf(
|
|
|
|
"Corrupted addrman database: The compat value (%u) "
|
|
|
|
"is lower than the expected minimum value %u.",
|
|
|
|
compat, INCOMPATIBILITY_BASE));
|
|
|
|
}
|
2021-08-17 17:31:23 +01:00
|
|
|
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
|
|
|
|
if (lowest_compatible > FILE_FORMAT) {
|
2022-01-29 21:58:59 +09:00
|
|
|
throw InvalidAddrManVersionError(strprintf(
|
2021-09-03 16:44:58 +02:00
|
|
|
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
|
|
|
|
"but the maximum supported by this version of %s is %u.",
|
2024-10-26 13:27:25 +01:00
|
|
|
uint8_t{format}, lowest_compatible, CLIENT_NAME, uint8_t{FILE_FORMAT}));
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
s >> nKey;
|
|
|
|
s >> nNew;
|
|
|
|
s >> nTried;
|
|
|
|
int nUBuckets = 0;
|
|
|
|
s >> nUBuckets;
|
|
|
|
if (format >= Format::V1_DETERMINISTIC) {
|
|
|
|
nUBuckets ^= (1 << 30);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
|
|
|
|
throw std::ios_base::failure(
|
2021-09-10 18:16:37 -06:00
|
|
|
strprintf("Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
|
2021-08-17 17:31:23 +01:00
|
|
|
nNew,
|
|
|
|
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
|
|
|
|
throw std::ios_base::failure(
|
2021-09-10 18:16:37 -06:00
|
|
|
strprintf("Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
|
2021-08-17 17:31:23 +01:00
|
|
|
nTried,
|
|
|
|
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deserialize entries from the new table.
|
|
|
|
for (int n = 0; n < nNew; n++) {
|
2021-09-10 18:53:57 -06:00
|
|
|
AddrInfo& info = mapInfo[n];
|
2021-08-17 17:31:23 +01:00
|
|
|
s >> info;
|
|
|
|
mapAddr[info] = n;
|
|
|
|
info.nRandomPos = vRandom.size();
|
|
|
|
vRandom.push_back(n);
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[info.GetNetwork()].n_new++;
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
nIdCount = nNew;
|
|
|
|
|
|
|
|
// Deserialize entries from the tried table.
|
|
|
|
int nLost = 0;
|
|
|
|
for (int n = 0; n < nTried; n++) {
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo info;
|
2021-08-17 17:31:23 +01:00
|
|
|
s >> info;
|
2021-09-01 12:12:52 +01:00
|
|
|
int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
|
2021-08-17 17:31:23 +01:00
|
|
|
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
|
|
|
if (info.IsValid()
|
|
|
|
&& vvTried[nKBucket][nKBucketPos] == -1) {
|
|
|
|
info.nRandomPos = vRandom.size();
|
|
|
|
info.fInTried = true;
|
|
|
|
vRandom.push_back(nIdCount);
|
|
|
|
mapInfo[nIdCount] = info;
|
|
|
|
mapAddr[info] = nIdCount;
|
|
|
|
vvTried[nKBucket][nKBucketPos] = nIdCount;
|
|
|
|
nIdCount++;
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[info.GetNetwork()].n_tried++;
|
2021-08-17 17:31:23 +01:00
|
|
|
} else {
|
|
|
|
nLost++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nTried -= nLost;
|
|
|
|
|
|
|
|
// Store positions in the new table buckets to apply later (if possible).
|
|
|
|
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
|
|
|
|
// so we store all bucket-entry_index pairs to iterate through later.
|
|
|
|
std::vector<std::pair<int, int>> bucket_entries;
|
|
|
|
|
|
|
|
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
|
|
|
|
int num_entries{0};
|
|
|
|
s >> num_entries;
|
|
|
|
for (int n = 0; n < num_entries; ++n) {
|
|
|
|
int entry_index{0};
|
|
|
|
s >> entry_index;
|
|
|
|
if (entry_index >= 0 && entry_index < nNew) {
|
|
|
|
bucket_entries.emplace_back(bucket, entry_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the bucket count and asmap checksum haven't changed, then attempt
|
|
|
|
// to restore the entries to the buckets/positions they were in before
|
|
|
|
// serialization.
|
2021-09-01 16:34:23 +01:00
|
|
|
uint256 supplied_asmap_checksum{m_netgroupman.GetAsmapChecksum()};
|
2021-08-17 17:31:23 +01:00
|
|
|
uint256 serialized_asmap_checksum;
|
|
|
|
if (format >= Format::V2_ASMAP) {
|
|
|
|
s >> serialized_asmap_checksum;
|
|
|
|
}
|
|
|
|
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
|
|
|
|
serialized_asmap_checksum == supplied_asmap_checksum};
|
|
|
|
|
|
|
|
if (!restore_bucketing) {
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto bucket_entry : bucket_entries) {
|
|
|
|
int bucket{bucket_entry.first};
|
|
|
|
const int entry_index{bucket_entry.second};
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info = mapInfo[entry_index];
|
2021-08-17 17:31:23 +01:00
|
|
|
|
|
|
|
// Don't store the entry in the new bucket if it's not a valid address for our addrman
|
|
|
|
if (!info.IsValid()) continue;
|
|
|
|
|
|
|
|
// The entry shouldn't appear in more than
|
|
|
|
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
|
|
|
|
// this bucket_entry.
|
|
|
|
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
|
|
|
|
|
|
|
|
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
|
|
|
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
|
|
|
|
// Bucketing has not changed, using existing bucket positions for the new table
|
|
|
|
vvNew[bucket][bucket_position] = entry_index;
|
|
|
|
++info.nRefCount;
|
|
|
|
} else {
|
|
|
|
// In case the new table data cannot be used (bucket count wrong or new asmap),
|
|
|
|
// try to give them a reference based on their primary source address.
|
2021-09-01 12:12:52 +01:00
|
|
|
bucket = info.GetNewBucket(nKey, m_netgroupman);
|
2021-08-17 17:31:23 +01:00
|
|
|
bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
|
|
|
if (vvNew[bucket][bucket_position] == -1) {
|
|
|
|
vvNew[bucket][bucket_position] = entry_index;
|
|
|
|
++info.nRefCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
|
|
|
|
int nLostUnk = 0;
|
|
|
|
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
|
|
|
|
if (it->second.fInTried == false && it->second.nRefCount == 0) {
|
|
|
|
const auto itCopy = it++;
|
|
|
|
Delete(itCopy->first);
|
|
|
|
++nLostUnk;
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nLost + nLostUnk > 0) {
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
|
2021-09-03 02:01:31 +02:00
|
|
|
const int check_code{CheckAddrman()};
|
2021-08-18 09:57:56 +02:00
|
|
|
if (check_code != 0) {
|
|
|
|
throw std::ios_base::failure(strprintf(
|
|
|
|
"Corrupt data. Consistency check failed with code %s",
|
|
|
|
check_code));
|
|
|
|
}
|
2021-08-17 17:31:23 +01:00
|
|
|
}
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
AddrInfo* AddrManImpl::Find(const CService& addr, nid_type* pnId)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2020-04-20 17:11:08 +02:00
|
|
|
const auto it = mapAddr.find(addr);
|
2012-01-04 23:39:45 +01:00
|
|
|
if (it == mapAddr.end())
|
2017-08-07 07:36:37 +02:00
|
|
|
return nullptr;
|
2012-01-04 23:39:45 +01:00
|
|
|
if (pnId)
|
|
|
|
*pnId = (*it).second;
|
2020-04-20 17:11:08 +02:00
|
|
|
const auto it2 = mapInfo.find((*it).second);
|
2012-01-04 23:39:45 +01:00
|
|
|
if (it2 != mapInfo.end())
|
|
|
|
return &(*it2).second;
|
2017-08-07 07:36:37 +02:00
|
|
|
return nullptr;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, nid_type* pnId)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nId = nIdCount++;
|
2021-09-10 18:33:25 -06:00
|
|
|
mapInfo[nId] = AddrInfo(addr, addrSource);
|
2012-01-04 23:39:45 +01:00
|
|
|
mapAddr[addr] = nId;
|
|
|
|
mapInfo[nId].nRandomPos = vRandom.size();
|
|
|
|
vRandom.push_back(nId);
|
2023-01-16 15:59:11 -05:00
|
|
|
nNew++;
|
|
|
|
m_network_counts[addr.GetNetwork()].n_new++;
|
2012-01-04 23:39:45 +01:00
|
|
|
if (pnId)
|
|
|
|
*pnId = nId;
|
|
|
|
return &mapInfo[nId];
|
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2012-01-04 23:39:45 +01:00
|
|
|
if (nRndPos1 == nRndPos2)
|
|
|
|
return;
|
|
|
|
|
2012-05-05 21:30:38 +02:00
|
|
|
assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nId1 = vRandom[nRndPos1];
|
|
|
|
nid_type nId2 = vRandom[nRndPos2];
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2021-05-13 13:43:36 +02:00
|
|
|
const auto it_1{mapInfo.find(nId1)};
|
|
|
|
const auto it_2{mapInfo.find(nId2)};
|
|
|
|
assert(it_1 != mapInfo.end());
|
|
|
|
assert(it_2 != mapInfo.end());
|
2012-05-05 21:30:38 +02:00
|
|
|
|
2021-05-13 13:43:36 +02:00
|
|
|
it_1->second.nRandomPos = nRndPos2;
|
|
|
|
it_2->second.nRandomPos = nRndPos1;
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
vRandom[nRndPos1] = nId2;
|
|
|
|
vRandom[nRndPos2] = nId1;
|
|
|
|
}
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
void AddrManImpl::Delete(nid_type nId)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2015-03-18 09:31:49 -07:00
|
|
|
assert(mapInfo.count(nId) != 0);
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info = mapInfo[nId];
|
2015-03-18 09:31:49 -07:00
|
|
|
assert(!info.fInTried);
|
|
|
|
assert(info.nRefCount == 0);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2015-03-18 09:31:49 -07:00
|
|
|
SwapRandom(info.nRandomPos, vRandom.size() - 1);
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[info.GetNetwork()].n_new--;
|
2015-03-18 09:31:49 -07:00
|
|
|
vRandom.pop_back();
|
|
|
|
mapAddr.erase(info);
|
|
|
|
mapInfo.erase(nId);
|
|
|
|
nNew--;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2015-03-18 09:31:49 -07:00
|
|
|
// if there is an entry in the specified bucket, delete it.
|
|
|
|
if (vvNew[nUBucket][nUBucketPos] != -1) {
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nIdDelete = vvNew[nUBucket][nUBucketPos];
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& infoDelete = mapInfo[nIdDelete];
|
2015-03-18 09:31:49 -07:00
|
|
|
assert(infoDelete.nRefCount > 0);
|
|
|
|
infoDelete.nRefCount--;
|
|
|
|
vvNew[nUBucket][nUBucketPos] = -1;
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToStringAddrPort(), nUBucket, nUBucketPos);
|
2015-03-18 09:31:49 -07:00
|
|
|
if (infoDelete.nRefCount == 0) {
|
|
|
|
Delete(nIdDelete);
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
void AddrManImpl::MakeTried(AddrInfo& info, nid_type nId)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2012-01-04 23:39:45 +01:00
|
|
|
// remove the entry from all new buckets
|
2021-09-01 12:12:52 +01:00
|
|
|
const int start_bucket{info.GetNewBucket(nKey, m_netgroupman)};
|
2021-09-09 21:41:51 +02:00
|
|
|
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
|
|
|
|
const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
|
|
|
|
const int pos{info.GetBucketPosition(nKey, true, bucket)};
|
2015-03-18 09:31:49 -07:00
|
|
|
if (vvNew[bucket][pos] == nId) {
|
|
|
|
vvNew[bucket][pos] = -1;
|
2012-01-04 23:39:45 +01:00
|
|
|
info.nRefCount--;
|
2021-09-09 21:41:51 +02:00
|
|
|
if (info.nRefCount == 0) break;
|
2015-03-18 09:31:49 -07:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
nNew--;
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[info.GetNetwork()].n_new--;
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2012-05-05 21:30:38 +02:00
|
|
|
assert(info.nRefCount == 0);
|
|
|
|
|
2014-10-24 12:04:27 +08:00
|
|
|
// which tried bucket to move the entry to
|
2021-09-01 12:12:52 +01:00
|
|
|
int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
|
2015-03-18 09:31:49 -07:00
|
|
|
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
|
|
|
|
|
|
|
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
|
|
|
|
if (vvTried[nKBucket][nKBucketPos] != -1) {
|
|
|
|
// find an item to evict
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nIdEvict = vvTried[nKBucket][nKBucketPos];
|
2015-03-18 09:31:49 -07:00
|
|
|
assert(mapInfo.count(nIdEvict) == 1);
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& infoOld = mapInfo[nIdEvict];
|
2015-03-18 09:31:49 -07:00
|
|
|
|
|
|
|
// Remove the to-be-evicted item from the tried set.
|
|
|
|
infoOld.fInTried = false;
|
|
|
|
vvTried[nKBucket][nKBucketPos] = -1;
|
|
|
|
nTried--;
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[infoOld.GetNetwork()].n_tried--;
|
2015-03-18 09:31:49 -07:00
|
|
|
|
|
|
|
// find which new bucket it belongs to
|
2021-09-01 12:12:52 +01:00
|
|
|
int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
|
2015-03-18 09:31:49 -07:00
|
|
|
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
|
|
|
|
ClearNew(nUBucket, nUBucketPos);
|
|
|
|
assert(vvNew[nUBucket][nUBucketPos] == -1);
|
|
|
|
|
|
|
|
// Enter it into the new set again.
|
|
|
|
infoOld.nRefCount = 1;
|
|
|
|
vvNew[nUBucket][nUBucketPos] = nIdEvict;
|
|
|
|
nNew++;
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[infoOld.GetNetwork()].n_new++;
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
|
2022-07-15 14:13:39 +02:00
|
|
|
infoOld.ToStringAddrPort(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2015-03-18 09:31:49 -07:00
|
|
|
assert(vvTried[nKBucket][nKBucketPos] == -1);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2015-03-18 09:31:49 -07:00
|
|
|
vvTried[nKBucket][nKBucketPos] = nId;
|
|
|
|
nTried++;
|
2012-01-04 23:39:45 +01:00
|
|
|
info.fInTried = true;
|
2022-11-29 17:16:26 -05:00
|
|
|
m_network_counts[info.GetNetwork()].n_tried++;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2012-01-04 23:39:45 +01:00
|
|
|
if (!addr.IsRoutable())
|
|
|
|
return false;
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nId;
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo* pinfo = Find(addr, &nId);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2017-01-18 16:15:37 +01:00
|
|
|
// Do not set a penalty for a source's self-announcement
|
2016-09-03 10:24:37 +00:00
|
|
|
if (addr == source) {
|
2022-03-28 14:20:04 +02:00
|
|
|
time_penalty = 0s;
|
2016-09-03 10:24:37 +00:00
|
|
|
}
|
|
|
|
|
2014-09-19 19:21:46 +02:00
|
|
|
if (pinfo) {
|
2012-01-04 23:39:45 +01:00
|
|
|
// periodically update nTime
|
2022-03-24 19:56:00 +01:00
|
|
|
const bool currently_online{NodeClock::now() - addr.nTime < 24h};
|
2022-03-28 14:20:04 +02:00
|
|
|
const auto update_interval{currently_online ? 1h : 24h};
|
2022-03-28 11:41:20 +02:00
|
|
|
if (pinfo->nTime < addr.nTime - update_interval - time_penalty) {
|
2022-03-28 14:20:04 +02:00
|
|
|
pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty);
|
2022-04-11 13:37:05 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// add services
|
2016-06-08 19:12:22 +02:00
|
|
|
pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// do not update if no new information is present
|
2022-04-11 13:37:05 +02:00
|
|
|
if (addr.nTime <= pinfo->nTime) {
|
2012-01-04 23:39:45 +01:00
|
|
|
return false;
|
2022-04-11 13:37:05 +02:00
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// do not update if the entry was already in the "tried" table
|
|
|
|
if (pinfo->fInTried)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// do not update if the max reference count is reached
|
|
|
|
if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// stochastic test: previous nRefCount == N: 2^N times harder to increase it
|
2023-03-23 15:45:56 -03:00
|
|
|
if (pinfo->nRefCount > 0) {
|
|
|
|
const int nFactor{1 << pinfo->nRefCount};
|
|
|
|
if (insecure_rand.randrange(nFactor) != 0) return false;
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
} else {
|
|
|
|
pinfo = Create(addr, source, &nId);
|
2022-03-28 14:20:04 +02:00
|
|
|
pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2021-09-01 12:12:52 +01:00
|
|
|
int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
|
2015-03-18 09:31:49 -07:00
|
|
|
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
|
2021-10-01 17:26:08 +01:00
|
|
|
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
|
2015-03-18 09:31:49 -07:00
|
|
|
if (vvNew[nUBucket][nUBucketPos] != nId) {
|
|
|
|
if (!fInsert) {
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
|
2015-03-18 09:31:49 -07:00
|
|
|
if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
|
|
|
|
// Overwrite the existing new table entry.
|
|
|
|
fInsert = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fInsert) {
|
|
|
|
ClearNew(nUBucket, nUBucketPos);
|
|
|
|
pinfo->nRefCount++;
|
|
|
|
vvNew[nUBucket][nUBucketPos] = nId;
|
2023-10-19 09:37:17 -03:00
|
|
|
const auto mapped_as{m_netgroupman.GetMappedAS(addr)};
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Added %s%s to new[%i][%i]\n",
|
2023-10-19 09:37:17 -03:00
|
|
|
addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), nUBucket, nUBucketPos);
|
2015-03-18 09:31:49 -07:00
|
|
|
} else {
|
|
|
|
if (pinfo->nRefCount == 0) {
|
|
|
|
Delete(nId);
|
|
|
|
}
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2021-10-01 17:26:08 +01:00
|
|
|
return fInsert;
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSeconds time)
|
2021-10-28 12:59:29 +01:00
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type nId;
|
2021-10-28 12:59:29 +01:00
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
m_last_good = time;
|
2021-10-28 12:59:29 +01:00
|
|
|
|
|
|
|
AddrInfo* pinfo = Find(addr, &nId);
|
|
|
|
|
|
|
|
// if not found, bail out
|
2021-12-10 15:37:04 +01:00
|
|
|
if (!pinfo) return false;
|
2021-10-28 12:59:29 +01:00
|
|
|
|
|
|
|
AddrInfo& info = *pinfo;
|
|
|
|
|
|
|
|
// update info
|
2022-03-28 14:20:04 +02:00
|
|
|
info.m_last_success = time;
|
|
|
|
info.m_last_try = time;
|
2021-10-28 12:59:29 +01:00
|
|
|
info.nAttempts = 0;
|
|
|
|
// nTime is not updated here, to avoid leaking information about
|
|
|
|
// currently-connected peers.
|
|
|
|
|
|
|
|
// if it is already in the tried set, don't do anything else
|
2021-12-10 15:37:04 +01:00
|
|
|
if (info.fInTried) return false;
|
2021-10-28 12:59:29 +01:00
|
|
|
|
|
|
|
// if it is not in new, something bad happened
|
2021-12-10 15:37:04 +01:00
|
|
|
if (!Assume(info.nRefCount > 0)) return false;
|
|
|
|
|
2021-10-28 12:59:29 +01:00
|
|
|
|
|
|
|
// which tried bucket to move the entry to
|
2021-09-01 12:12:52 +01:00
|
|
|
int tried_bucket = info.GetTriedBucket(nKey, m_netgroupman);
|
2021-10-28 12:59:29 +01:00
|
|
|
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
|
|
|
|
|
|
|
|
// Will moving this address into tried evict another entry?
|
|
|
|
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
|
|
|
|
if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
|
|
|
|
m_tried_collisions.insert(nId);
|
|
|
|
}
|
|
|
|
// Output the entry we'd be colliding with, for debugging purposes
|
|
|
|
auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n",
|
2022-07-15 14:13:39 +02:00
|
|
|
colliding_entry != mapInfo.end() ? colliding_entry->second.ToStringAddrPort() : "",
|
|
|
|
addr.ToStringAddrPort(),
|
2021-10-28 12:59:29 +01:00
|
|
|
m_tried_collisions.size());
|
2021-12-10 15:37:04 +01:00
|
|
|
return false;
|
2021-10-28 12:59:29 +01:00
|
|
|
} else {
|
|
|
|
// move nId to the tried tables
|
|
|
|
MakeTried(info, nId);
|
2023-10-19 09:37:17 -03:00
|
|
|
const auto mapped_as{m_netgroupman.GetMappedAS(addr)};
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Moved %s%s to tried[%i][%i]\n",
|
2023-10-19 09:37:17 -03:00
|
|
|
addr.ToStringAddrPort(), (mapped_as ? strprintf(" mapped to AS%i", mapped_as) : ""), tried_bucket, tried_bucket_pos);
|
2021-12-10 15:37:04 +01:00
|
|
|
return true;
|
2021-10-28 12:59:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
|
2021-10-01 17:26:08 +01:00
|
|
|
{
|
|
|
|
int added{0};
|
|
|
|
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
|
2022-03-28 11:41:20 +02:00
|
|
|
added += AddSingle(*it, source, time_penalty) ? 1 : 0;
|
2021-10-01 17:26:08 +01:00
|
|
|
}
|
|
|
|
if (added > 0) {
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew);
|
2021-10-01 17:26:08 +01:00
|
|
|
}
|
|
|
|
return added > 0;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo* pinfo = Find(addr);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// if not found, bail out
|
|
|
|
if (!pinfo)
|
|
|
|
return;
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info = *pinfo;
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// update info
|
2022-03-28 14:20:04 +02:00
|
|
|
info.m_last_try = time;
|
2022-03-28 11:41:20 +02:00
|
|
|
if (fCountFailure && info.m_last_count_attempt < m_last_good) {
|
2022-03-28 14:20:04 +02:00
|
|
|
info.m_last_count_attempt = time;
|
2015-04-19 13:39:38 -07:00
|
|
|
info.nAttempts++;
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
2024-02-12 18:10:33 -03:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, const std::unordered_set<Network>& networks) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-08-25 15:40:59 -07:00
|
|
|
if (vRandom.empty()) return {};
|
2023-02-18 18:29:45 -07:00
|
|
|
|
|
|
|
size_t new_count = nNew;
|
|
|
|
size_t tried_count = nTried;
|
|
|
|
|
2024-02-12 18:10:33 -03:00
|
|
|
if (!networks.empty()) {
|
|
|
|
new_count = 0;
|
|
|
|
tried_count = 0;
|
|
|
|
for (auto& network : networks) {
|
|
|
|
auto it = m_network_counts.find(network);
|
|
|
|
if (it == m_network_counts.end()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto counts = it->second;
|
|
|
|
new_count += counts.n_new;
|
|
|
|
tried_count += counts.n_tried;
|
|
|
|
}
|
2023-02-18 18:29:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (new_only && new_count == 0) return {};
|
|
|
|
if (new_count + tried_count == 0) return {};
|
2015-09-22 15:24:16 -04:00
|
|
|
|
2023-02-18 17:38:58 -07:00
|
|
|
// Decide if we are going to search the new or tried table
|
2023-02-18 18:29:45 -07:00
|
|
|
// If either option is viable, use a 50% chance to choose
|
2023-02-18 17:38:58 -07:00
|
|
|
bool search_tried;
|
2023-02-18 18:29:45 -07:00
|
|
|
if (new_only || tried_count == 0) {
|
|
|
|
search_tried = false;
|
|
|
|
} else if (new_count == 0) {
|
2023-02-18 17:38:58 -07:00
|
|
|
search_tried = true;
|
|
|
|
} else {
|
2023-02-18 18:29:45 -07:00
|
|
|
search_tried = insecure_rand.randbool();
|
2023-02-18 17:38:58 -07:00
|
|
|
}
|
|
|
|
|
2023-02-18 18:29:45 -07:00
|
|
|
const int bucket_count{search_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT};
|
|
|
|
|
|
|
|
// Loop through the addrman table until we find an appropriate entry
|
2023-02-19 10:09:28 -07:00
|
|
|
double chance_factor = 1.0;
|
2023-02-18 18:13:00 -07:00
|
|
|
while (1) {
|
|
|
|
// Pick a bucket, and an initial position in that bucket.
|
2023-02-19 10:09:28 -07:00
|
|
|
int bucket = insecure_rand.randrange(bucket_count);
|
|
|
|
int initial_position = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
|
2023-02-18 18:13:00 -07:00
|
|
|
|
|
|
|
// Iterate over the positions of that bucket, starting at the initial one,
|
|
|
|
// and looping around.
|
2024-08-01 12:46:24 -04:00
|
|
|
int i, position;
|
|
|
|
nid_type node_id;
|
2023-02-18 18:13:00 -07:00
|
|
|
for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
|
2023-04-25 16:29:29 +01:00
|
|
|
position = (initial_position + i) % ADDRMAN_BUCKET_SIZE;
|
|
|
|
node_id = GetEntry(search_tried, bucket, position);
|
2023-02-18 18:29:45 -07:00
|
|
|
if (node_id != -1) {
|
2024-02-12 18:10:33 -03:00
|
|
|
if (!networks.empty()) {
|
2023-02-18 18:29:45 -07:00
|
|
|
const auto it{mapInfo.find(node_id)};
|
2024-02-12 18:10:33 -03:00
|
|
|
if (Assume(it != mapInfo.end()) && networks.contains(it->second.GetNetwork())) break;
|
2023-02-18 18:29:45 -07:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2023-02-18 18:13:00 -07:00
|
|
|
|
|
|
|
// If the bucket is entirely empty, start over with a (likely) different one.
|
|
|
|
if (i == ADDRMAN_BUCKET_SIZE) continue;
|
|
|
|
|
|
|
|
// Find the entry to return.
|
2023-04-25 16:29:29 +01:00
|
|
|
const auto it_found{mapInfo.find(node_id)};
|
2023-02-18 18:13:00 -07:00
|
|
|
assert(it_found != mapInfo.end());
|
|
|
|
const AddrInfo& info{it_found->second};
|
|
|
|
|
2023-02-19 10:09:28 -07:00
|
|
|
// With probability GetChance() * chance_factor, return the entry.
|
2024-03-10 12:38:14 -04:00
|
|
|
if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
|
2023-02-18 18:13:00 -07:00
|
|
|
return {info, info.m_last_try};
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2023-02-18 18:13:00 -07:00
|
|
|
|
|
|
|
// Otherwise start over with a (likely) different bucket, and increased chance factor.
|
2023-02-19 10:09:28 -07:00
|
|
|
chance_factor *= 1.2;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const
|
2023-02-18 17:46:13 -07:00
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
|
|
|
if (use_tried) {
|
2023-04-25 17:04:11 +01:00
|
|
|
if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_TRIED_BUCKET_COUNT)) {
|
|
|
|
return vvTried[bucket][position];
|
|
|
|
}
|
2023-02-18 17:46:13 -07:00
|
|
|
} else {
|
2023-04-25 17:04:11 +01:00
|
|
|
if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_NEW_BUCKET_COUNT)) {
|
|
|
|
return vvNew[bucket][position];
|
|
|
|
}
|
2023-02-18 17:46:13 -07:00
|
|
|
}
|
2023-04-25 17:04:11 +01:00
|
|
|
|
|
|
|
return -1;
|
2023-02-18 17:46:13 -07:00
|
|
|
}
|
|
|
|
|
2023-09-29 23:23:36 +02:00
|
|
|
std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
2024-11-07 08:34:16 -03:00
|
|
|
Assume(max_pct <= 100);
|
2021-05-23 21:06:10 +03:00
|
|
|
|
2020-07-23 15:34:40 +01:00
|
|
|
size_t nNodes = vRandom.size();
|
|
|
|
if (max_pct != 0) {
|
2024-11-07 08:34:16 -03:00
|
|
|
max_pct = std::min(max_pct, size_t{100});
|
2020-07-23 15:34:40 +01:00
|
|
|
nNodes = max_pct * nNodes / 100;
|
|
|
|
}
|
|
|
|
if (max_addresses != 0) {
|
|
|
|
nNodes = std::min(nNodes, max_addresses);
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
|
2014-08-18 16:50:39 -04:00
|
|
|
// gather a list of random nodes, skipping those of low quality
|
2022-03-24 19:56:00 +01:00
|
|
|
const auto now{Now<NodeSeconds>()};
|
2021-09-22 15:47:49 -06:00
|
|
|
std::vector<CAddress> addresses;
|
Preallocate addresses in GetAddr based on nNodes
> make && ./src/bench/bench_bitcoin --filter=AddrManGetAddr --min-time=1000
Before:
```
| ns/op | op/s | err% | total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
| 76,852.79 | 13,011.89 | 0.4% | 1.07 | `AddrManGetAddr`
| 76,598.21 | 13,055.14 | 0.2% | 1.07 | `AddrManGetAddr`
| 76,296.32 | 13,106.79 | 0.1% | 1.07 | `AddrManGetAddr`
```
After:
```
| ns/op | op/s | err% | total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
| 65,966.97 | 15,159.10 | 0.3% | 1.07 | `AddrManGetAddr`
| 66,075.40 | 15,134.23 | 0.2% | 1.06 | `AddrManGetAddr`
| 66,306.34 | 15,081.51 | 0.3% | 1.06 | `AddrManGetAddr`
```
2024-03-09 20:56:19 +01:00
|
|
|
addresses.reserve(nNodes);
|
2014-09-19 19:21:46 +02:00
|
|
|
for (unsigned int n = 0; n < vRandom.size(); n++) {
|
2021-09-22 15:47:49 -06:00
|
|
|
if (addresses.size() >= nNodes)
|
2014-08-18 16:50:39 -04:00
|
|
|
break;
|
|
|
|
|
2018-10-31 13:56:19 -07:00
|
|
|
int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
|
2012-01-04 23:39:45 +01:00
|
|
|
SwapRandom(n, nRndPos);
|
2021-05-13 13:43:36 +02:00
|
|
|
const auto it{mapInfo.find(vRandom[n])};
|
|
|
|
assert(it != mapInfo.end());
|
2014-08-18 16:50:39 -04:00
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
const AddrInfo& ai{it->second};
|
2021-05-02 18:44:17 +02:00
|
|
|
|
|
|
|
// Filter by network (optional)
|
|
|
|
if (network != std::nullopt && ai.GetNetClass() != network) continue;
|
|
|
|
|
|
|
|
// Filter for quality
|
2023-09-29 23:23:36 +02:00
|
|
|
if (ai.IsTerrible(now) && filtered) continue;
|
2021-05-02 18:44:17 +02:00
|
|
|
|
2021-09-22 15:47:49 -06:00
|
|
|
addresses.push_back(ai);
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size());
|
2021-09-22 15:47:49 -06:00
|
|
|
return addresses;
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
|
|
|
|
rpc: getrawaddrman for addrman entries
Exposing address manager table entries in a hidden RPC allows to introspect
addrman tables in tests and during development.
As response JSON object the following FORMAT1 is choosen:
{
"table": {
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
...
}
}
An alternative would be FORMAT2
{
"table": {
"bucket": {
"position": { "address": "..", "port": .., ... },
"position": { "address": "..", "port": .., ... },
..
},
"bucket": {
"position": { "address": "..", "port": .., ... },
..
},
}
}
FORMAT1 and FORMAT2 have different encodings for the location of the
address in the address manager. While FORMAT2 might be easier to process
for downstream tools, it also mimics internal addrman mappings, which
might change at some point. Users not interested in the address location
can ignore the location key. They don't have to adapt to a new RPC
response format, when the internal addrman layout changes. Additionally,
FORMAT1 is also slightly easier to to iterate in downstream tools. The
RPC response-building implemenation complexcity is lower with FORMAT1
as we can more easily build a "<bucket>/<position>" key than a multiple
"bucket" objects with multiple "position" objects (FORMAT2).
2023-09-20 19:37:45 +02:00
|
|
|
std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries_(bool from_tried) const
|
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
|
|
|
const int bucket_count = from_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT;
|
|
|
|
std::vector<std::pair<AddrInfo, AddressPosition>> infos;
|
|
|
|
for (int bucket = 0; bucket < bucket_count; ++bucket) {
|
|
|
|
for (int position = 0; position < ADDRMAN_BUCKET_SIZE; ++position) {
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type id = GetEntry(from_tried, bucket, position);
|
rpc: getrawaddrman for addrman entries
Exposing address manager table entries in a hidden RPC allows to introspect
addrman tables in tests and during development.
As response JSON object the following FORMAT1 is choosen:
{
"table": {
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
...
}
}
An alternative would be FORMAT2
{
"table": {
"bucket": {
"position": { "address": "..", "port": .., ... },
"position": { "address": "..", "port": .., ... },
..
},
"bucket": {
"position": { "address": "..", "port": .., ... },
..
},
}
}
FORMAT1 and FORMAT2 have different encodings for the location of the
address in the address manager. While FORMAT2 might be easier to process
for downstream tools, it also mimics internal addrman mappings, which
might change at some point. Users not interested in the address location
can ignore the location key. They don't have to adapt to a new RPC
response format, when the internal addrman layout changes. Additionally,
FORMAT1 is also slightly easier to to iterate in downstream tools. The
RPC response-building implemenation complexcity is lower with FORMAT1
as we can more easily build a "<bucket>/<position>" key than a multiple
"bucket" objects with multiple "position" objects (FORMAT2).
2023-09-20 19:37:45 +02:00
|
|
|
if (id >= 0) {
|
|
|
|
AddrInfo info = mapInfo.at(id);
|
|
|
|
AddressPosition location = AddressPosition(
|
|
|
|
from_tried,
|
|
|
|
/*multiplicity_in=*/from_tried ? 1 : info.nRefCount,
|
|
|
|
bucket,
|
|
|
|
position);
|
2023-10-04 13:53:40 +02:00
|
|
|
infos.emplace_back(info, location);
|
rpc: getrawaddrman for addrman entries
Exposing address manager table entries in a hidden RPC allows to introspect
addrman tables in tests and during development.
As response JSON object the following FORMAT1 is choosen:
{
"table": {
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
...
}
}
An alternative would be FORMAT2
{
"table": {
"bucket": {
"position": { "address": "..", "port": .., ... },
"position": { "address": "..", "port": .., ... },
..
},
"bucket": {
"position": { "address": "..", "port": .., ... },
..
},
}
}
FORMAT1 and FORMAT2 have different encodings for the location of the
address in the address manager. While FORMAT2 might be easier to process
for downstream tools, it also mimics internal addrman mappings, which
might change at some point. Users not interested in the address location
can ignore the location key. They don't have to adapt to a new RPC
response format, when the internal addrman layout changes. Additionally,
FORMAT1 is also slightly easier to to iterate in downstream tools. The
RPC response-building implemenation complexcity is lower with FORMAT1
as we can more easily build a "<bucket>/<position>" key than a multiple
"bucket" objects with multiple "position" objects (FORMAT2).
2023-09-20 19:37:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return infos;
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)
|
2012-01-04 23:39:45 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo* pinfo = Find(addr);
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// if not found, bail out
|
|
|
|
if (!pinfo)
|
|
|
|
return;
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info = *pinfo;
|
2012-01-04 23:39:45 +01:00
|
|
|
|
|
|
|
// update info
|
2022-03-28 14:20:04 +02:00
|
|
|
const auto update_interval{20min};
|
|
|
|
if (time - info.nTime > update_interval) {
|
|
|
|
info.nTime = time;
|
|
|
|
}
|
2012-01-04 23:39:45 +01:00
|
|
|
}
|
2015-12-12 22:34:08 -05:00
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
|
2016-03-26 18:58:00 +01:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo* pinfo = Find(addr);
|
2016-03-26 18:58:00 +01:00
|
|
|
|
|
|
|
// if not found, bail out
|
|
|
|
if (!pinfo)
|
|
|
|
return;
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info = *pinfo;
|
2016-03-26 18:58:00 +01:00
|
|
|
|
|
|
|
// update info
|
|
|
|
info.nServices = nServices;
|
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::ResolveCollisions_()
|
2016-10-27 13:55:39 -04:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
for (std::set<nid_type>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
|
|
|
|
nid_type id_new = *it;
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
bool erase_collision = false;
|
|
|
|
|
|
|
|
// If id_new not found in mapInfo remove it from m_tried_collisions
|
|
|
|
if (mapInfo.count(id_new) != 1) {
|
|
|
|
erase_collision = true;
|
|
|
|
} else {
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info_new = mapInfo[id_new];
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// Which tried bucket to move the entry to.
|
2021-09-01 12:12:52 +01:00
|
|
|
int tried_bucket = info_new.GetTriedBucket(nKey, m_netgroupman);
|
2016-10-27 13:55:39 -04:00
|
|
|
int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
|
|
|
|
if (!info_new.IsValid()) { // id_new may no longer map to a valid address
|
|
|
|
erase_collision = true;
|
|
|
|
} else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
|
|
|
|
|
|
|
|
// Get the to-be-evicted address that is being tested
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type id_old = vvTried[tried_bucket][tried_bucket_pos];
|
2021-09-10 18:33:25 -06:00
|
|
|
AddrInfo& info_old = mapInfo[id_old];
|
2016-10-27 13:55:39 -04:00
|
|
|
|
2022-03-24 19:56:00 +01:00
|
|
|
const auto current_time{Now<NodeSeconds>()};
|
2022-03-28 17:29:20 +02:00
|
|
|
|
2016-10-27 13:55:39 -04:00
|
|
|
// Has successfully connected in last X hours
|
2022-03-28 14:20:04 +02:00
|
|
|
if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {
|
2016-10-27 13:55:39 -04:00
|
|
|
erase_collision = true;
|
2022-03-28 14:20:04 +02:00
|
|
|
} else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// Give address at least 60 seconds to successfully connect
|
2022-03-28 14:20:04 +02:00
|
|
|
if (current_time - info_old.m_last_try > 60s) {
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// Replaces an existing address already in the tried table with the new address
|
2022-03-28 17:29:20 +02:00
|
|
|
Good_(info_new, false, current_time);
|
2016-10-27 13:55:39 -04:00
|
|
|
erase_collision = true;
|
|
|
|
}
|
2022-03-28 11:41:20 +02:00
|
|
|
} else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) {
|
2019-02-26 16:34:26 -05:00
|
|
|
// If the collision hasn't resolved in some reasonable amount of time,
|
|
|
|
// just evict the old entry -- we must not be able to
|
|
|
|
// connect to it for some reason.
|
2024-08-08 10:49:13 +02:00
|
|
|
LogDebug(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());
|
2022-03-28 17:29:20 +02:00
|
|
|
Good_(info_new, false, current_time);
|
2019-02-26 16:34:26 -05:00
|
|
|
erase_collision = true;
|
2016-10-27 13:55:39 -04:00
|
|
|
}
|
|
|
|
} else { // Collision is not actually a collision anymore
|
2022-03-24 19:56:00 +01:00
|
|
|
Good_(info_new, false, Now<NodeSeconds>());
|
2016-10-27 13:55:39 -04:00
|
|
|
erase_collision = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (erase_collision) {
|
|
|
|
m_tried_collisions.erase(it++);
|
|
|
|
} else {
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_()
|
2016-10-27 13:55:39 -04:00
|
|
|
{
|
2021-05-23 21:06:10 +03:00
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-08-25 15:40:59 -07:00
|
|
|
if (m_tried_collisions.size() == 0) return {};
|
2016-10-27 13:55:39 -04:00
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
std::set<nid_type>::iterator it = m_tried_collisions.begin();
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// Selects a random element from m_tried_collisions
|
2018-10-31 13:56:19 -07:00
|
|
|
std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type id_new = *it;
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// If id_new not found in mapInfo remove it from m_tried_collisions
|
|
|
|
if (mapInfo.count(id_new) != 1) {
|
|
|
|
m_tried_collisions.erase(it);
|
2021-08-25 15:40:59 -07:00
|
|
|
return {};
|
2016-10-27 13:55:39 -04:00
|
|
|
}
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
const AddrInfo& newInfo = mapInfo[id_new];
|
2016-10-27 13:55:39 -04:00
|
|
|
|
|
|
|
// which tried bucket to move the entry to
|
2021-09-01 12:12:52 +01:00
|
|
|
int tried_bucket = newInfo.GetTriedBucket(nKey, m_netgroupman);
|
2016-10-27 13:55:39 -04:00
|
|
|
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
|
|
|
|
|
2021-09-10 18:33:25 -06:00
|
|
|
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
|
2022-03-28 11:41:20 +02:00
|
|
|
return {info_old, info_old.m_last_try};
|
2016-10-27 13:55:39 -04:00
|
|
|
}
|
2021-09-24 14:14:39 -06:00
|
|
|
|
2021-12-09 18:25:22 +00:00
|
|
|
std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
|
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
|
|
|
AddrInfo* addr_info = Find(addr);
|
|
|
|
|
|
|
|
if (!addr_info) return std::nullopt;
|
|
|
|
|
|
|
|
if(addr_info->fInTried) {
|
2021-09-01 12:12:52 +01:00
|
|
|
int bucket{addr_info->GetTriedBucket(nKey, m_netgroupman)};
|
2022-03-24 15:12:31 +00:00
|
|
|
return AddressPosition(/*tried_in=*/true,
|
|
|
|
/*multiplicity_in=*/1,
|
|
|
|
/*bucket_in=*/bucket,
|
|
|
|
/*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket));
|
2021-12-09 18:25:22 +00:00
|
|
|
} else {
|
2021-09-01 12:12:52 +01:00
|
|
|
int bucket{addr_info->GetNewBucket(nKey, m_netgroupman)};
|
2022-03-24 15:12:31 +00:00
|
|
|
return AddressPosition(/*tried_in=*/false,
|
|
|
|
/*multiplicity_in=*/addr_info->nRefCount,
|
|
|
|
/*bucket_in=*/bucket,
|
|
|
|
/*position_in=*/addr_info->GetBucketPosition(nKey, true, bucket));
|
2021-12-09 18:25:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-29 17:16:26 -05:00
|
|
|
size_t AddrManImpl::Size_(std::optional<Network> net, std::optional<bool> in_new) const
|
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
|
|
|
if (!net.has_value()) {
|
|
|
|
if (in_new.has_value()) {
|
|
|
|
return *in_new ? nNew : nTried;
|
|
|
|
} else {
|
|
|
|
return vRandom.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (auto it = m_network_counts.find(*net); it != m_network_counts.end()) {
|
|
|
|
auto net_count = it->second;
|
|
|
|
if (in_new.has_value()) {
|
|
|
|
return *in_new ? net_count.n_new : net_count.n_tried;
|
|
|
|
} else {
|
|
|
|
return net_count.n_new + net_count.n_tried;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::Check() const
|
2021-09-28 15:46:43 -04:00
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
|
|
|
// Run consistency checks 1 in m_consistency_check_ratio times if enabled
|
|
|
|
if (m_consistency_check_ratio == 0) return;
|
|
|
|
if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return;
|
|
|
|
|
2021-09-03 02:01:31 +02:00
|
|
|
const int err{CheckAddrman()};
|
2021-09-28 15:46:43 -04:00
|
|
|
if (err) {
|
|
|
|
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-03 02:01:31 +02:00
|
|
|
int AddrManImpl::CheckAddrman() const
|
2021-09-28 15:46:43 -04:00
|
|
|
{
|
|
|
|
AssertLockHeld(cs);
|
|
|
|
|
2021-09-03 02:01:31 +02:00
|
|
|
LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE(
|
|
|
|
strprintf("new %i, tried %i, total %u", nNew, nTried, vRandom.size()), BCLog::ADDRMAN);
|
2021-09-28 15:46:43 -04:00
|
|
|
|
2024-08-01 12:46:24 -04:00
|
|
|
std::unordered_set<nid_type> setTried;
|
|
|
|
std::unordered_map<nid_type, int> mapNew;
|
2022-11-29 17:16:26 -05:00
|
|
|
std::unordered_map<Network, NewTriedCount> local_counts;
|
2021-09-28 15:46:43 -04:00
|
|
|
|
|
|
|
if (vRandom.size() != (size_t)(nTried + nNew))
|
|
|
|
return -7;
|
|
|
|
|
|
|
|
for (const auto& entry : mapInfo) {
|
2024-08-01 12:46:24 -04:00
|
|
|
nid_type n = entry.first;
|
2021-09-10 18:33:25 -06:00
|
|
|
const AddrInfo& info = entry.second;
|
2021-09-28 15:46:43 -04:00
|
|
|
if (info.fInTried) {
|
2022-03-28 14:20:04 +02:00
|
|
|
if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) {
|
2021-09-28 15:46:43 -04:00
|
|
|
return -1;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
2021-09-28 15:46:43 -04:00
|
|
|
if (info.nRefCount)
|
|
|
|
return -2;
|
|
|
|
setTried.insert(n);
|
2022-11-29 17:16:26 -05:00
|
|
|
local_counts[info.GetNetwork()].n_tried++;
|
2021-09-28 15:46:43 -04:00
|
|
|
} else {
|
|
|
|
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
|
|
|
|
return -3;
|
|
|
|
if (!info.nRefCount)
|
|
|
|
return -4;
|
|
|
|
mapNew[n] = info.nRefCount;
|
2022-11-29 17:16:26 -05:00
|
|
|
local_counts[info.GetNetwork()].n_new++;
|
2021-09-28 15:46:43 -04:00
|
|
|
}
|
|
|
|
const auto it{mapAddr.find(info)};
|
|
|
|
if (it == mapAddr.end() || it->second != n) {
|
|
|
|
return -5;
|
|
|
|
}
|
|
|
|
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
|
|
|
|
return -14;
|
2022-03-28 14:20:04 +02:00
|
|
|
if (info.m_last_try < NodeSeconds{0s}) {
|
2021-09-28 15:46:43 -04:00
|
|
|
return -6;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
|
|
|
if (info.m_last_success < NodeSeconds{0s}) {
|
2021-09-28 15:46:43 -04:00
|
|
|
return -8;
|
2022-03-28 14:20:04 +02:00
|
|
|
}
|
2021-09-28 15:46:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (setTried.size() != (size_t)nTried)
|
|
|
|
return -9;
|
|
|
|
if (mapNew.size() != (size_t)nNew)
|
|
|
|
return -10;
|
|
|
|
|
|
|
|
for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
|
|
|
|
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
|
|
|
if (vvTried[n][i] != -1) {
|
|
|
|
if (!setTried.count(vvTried[n][i]))
|
|
|
|
return -11;
|
|
|
|
const auto it{mapInfo.find(vvTried[n][i])};
|
2021-09-01 12:12:52 +01:00
|
|
|
if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_netgroupman) != n) {
|
2021-09-28 15:46:43 -04:00
|
|
|
return -17;
|
|
|
|
}
|
|
|
|
if (it->second.GetBucketPosition(nKey, false, n) != i) {
|
|
|
|
return -18;
|
|
|
|
}
|
|
|
|
setTried.erase(vvTried[n][i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
|
|
|
|
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
|
|
|
if (vvNew[n][i] != -1) {
|
|
|
|
if (!mapNew.count(vvNew[n][i]))
|
|
|
|
return -12;
|
|
|
|
const auto it{mapInfo.find(vvNew[n][i])};
|
|
|
|
if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) {
|
|
|
|
return -19;
|
|
|
|
}
|
|
|
|
if (--mapNew[vvNew[n][i]] == 0)
|
|
|
|
mapNew.erase(vvNew[n][i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setTried.size())
|
|
|
|
return -13;
|
|
|
|
if (mapNew.size())
|
|
|
|
return -15;
|
|
|
|
if (nKey.IsNull())
|
|
|
|
return -16;
|
|
|
|
|
2022-11-29 17:16:26 -05:00
|
|
|
// It's possible that m_network_counts may have all-zero entries that local_counts
|
|
|
|
// doesn't have if addrs from a network were being added and then removed again in the past.
|
|
|
|
if (m_network_counts.size() < local_counts.size()) {
|
|
|
|
return -20;
|
|
|
|
}
|
|
|
|
for (const auto& [net, count] : m_network_counts) {
|
|
|
|
if (local_counts[net].n_new != count.n_new || local_counts[net].n_tried != count.n_tried) {
|
|
|
|
return -21;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-28 15:46:43 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-29 17:16:26 -05:00
|
|
|
size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new) const
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
2022-11-29 17:16:26 -05:00
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
auto ret = Size_(net, in_new);
|
|
|
|
Check();
|
|
|
|
return ret;
|
2021-09-24 14:14:39 -06:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2022-03-28 11:41:20 +02:00
|
|
|
auto ret = Add_(vAddr, source, time_penalty);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
2021-10-01 17:26:08 +01:00
|
|
|
return ret;
|
2021-09-24 14:14:39 -06:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrManImpl::Good(const CService& addr, NodeSeconds time)
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2022-03-28 14:20:04 +02:00
|
|
|
auto ret = Good_(addr, /*test_before_evict=*/true, time);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
2021-12-10 15:37:04 +01:00
|
|
|
return ret;
|
2021-09-24 14:14:39 -06:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2022-03-28 14:20:04 +02:00
|
|
|
Attempt_(addr, fCountFailure, time);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
2021-09-01 11:21:29 -07:00
|
|
|
void AddrManImpl::ResolveCollisions()
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
ResolveCollisions_();
|
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2022-12-27 15:25:51 +00:00
|
|
|
auto ret = SelectTriedCollision_();
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-02-12 18:10:33 -03:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, const std::unordered_set<Network>& networks) const
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2024-02-12 18:10:33 -03:00
|
|
|
auto addrRet = Select_(new_only, networks);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
|
|
|
return addrRet;
|
|
|
|
}
|
|
|
|
|
2023-09-29 23:23:36 +02:00
|
|
|
std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2023-09-29 23:23:36 +02:00
|
|
|
auto addresses = GetAddr_(max_addresses, max_pct, network, filtered);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
2021-09-22 15:47:49 -06:00
|
|
|
return addresses;
|
2021-09-24 14:14:39 -06:00
|
|
|
}
|
|
|
|
|
rpc: getrawaddrman for addrman entries
Exposing address manager table entries in a hidden RPC allows to introspect
addrman tables in tests and during development.
As response JSON object the following FORMAT1 is choosen:
{
"table": {
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
...
}
}
An alternative would be FORMAT2
{
"table": {
"bucket": {
"position": { "address": "..", "port": .., ... },
"position": { "address": "..", "port": .., ... },
..
},
"bucket": {
"position": { "address": "..", "port": .., ... },
..
},
}
}
FORMAT1 and FORMAT2 have different encodings for the location of the
address in the address manager. While FORMAT2 might be easier to process
for downstream tools, it also mimics internal addrman mappings, which
might change at some point. Users not interested in the address location
can ignore the location key. They don't have to adapt to a new RPC
response format, when the internal addrman layout changes. Additionally,
FORMAT1 is also slightly easier to to iterate in downstream tools. The
RPC response-building implemenation complexcity is lower with FORMAT1
as we can more easily build a "<bucket>/<position>" key than a multiple
"bucket" objects with multiple "position" objects (FORMAT2).
2023-09-20 19:37:45 +02:00
|
|
|
std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries(bool from_tried) const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
auto addrInfos = GetEntries_(from_tried);
|
|
|
|
Check();
|
|
|
|
return addrInfos;
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrManImpl::Connected(const CService& addr, NodeSeconds time)
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
2022-03-28 14:20:04 +02:00
|
|
|
Connected_(addr, time);
|
2021-09-24 14:14:39 -06:00
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
2021-09-10 18:53:57 -06:00
|
|
|
void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices)
|
2021-09-24 14:14:39 -06:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
SetServices_(addr, nServices);
|
|
|
|
Check();
|
|
|
|
}
|
|
|
|
|
2021-12-09 18:25:22 +00:00
|
|
|
std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& addr)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
Check();
|
|
|
|
auto entry = FindAddressEntry_(addr);
|
|
|
|
Check();
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2021-08-31 18:40:18 +01:00
|
|
|
AddrMan::AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
|
|
|
|
: m_impl(std::make_unique<AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {}
|
2021-09-01 11:21:29 -07:00
|
|
|
|
2021-09-10 18:16:37 -06:00
|
|
|
AddrMan::~AddrMan() = default;
|
2021-09-01 11:21:29 -07:00
|
|
|
|
|
|
|
template <typename Stream>
|
2021-09-10 18:16:37 -06:00
|
|
|
void AddrMan::Serialize(Stream& s_) const
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
|
|
|
m_impl->Serialize<Stream>(s_);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Stream>
|
2021-09-10 18:16:37 -06:00
|
|
|
void AddrMan::Unserialize(Stream& s_)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
|
|
|
m_impl->Unserialize<Stream>(s_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// explicit instantiation
|
2023-01-31 18:04:44 +01:00
|
|
|
template void AddrMan::Serialize(HashedSourceWriter<AutoFile>&) const;
|
|
|
|
template void AddrMan::Serialize(DataStream&) const;
|
|
|
|
template void AddrMan::Unserialize(AutoFile&);
|
|
|
|
template void AddrMan::Unserialize(HashVerifier<AutoFile>&);
|
|
|
|
template void AddrMan::Unserialize(DataStream&);
|
|
|
|
template void AddrMan::Unserialize(HashVerifier<DataStream>&);
|
2021-09-10 18:16:37 -06:00
|
|
|
|
2022-11-29 17:16:26 -05:00
|
|
|
size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2022-11-29 17:16:26 -05:00
|
|
|
return m_impl->Size(net, in_new);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2022-03-28 11:41:20 +02:00
|
|
|
return m_impl->Add(vAddr, source, time_penalty);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
bool AddrMan::Good(const CService& addr, NodeSeconds time)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2022-03-28 14:20:04 +02:00
|
|
|
return m_impl->Good(addr, time);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrMan::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2022-03-28 14:20:04 +02:00
|
|
|
m_impl->Attempt(addr, fCountFailure, time);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2021-09-10 18:16:37 -06:00
|
|
|
void AddrMan::ResolveCollisions()
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
|
|
|
m_impl->ResolveCollisions();
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision()
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
|
|
|
return m_impl->SelectTriedCollision();
|
|
|
|
}
|
|
|
|
|
2024-02-12 18:10:33 -03:00
|
|
|
std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, const std::unordered_set<Network>& networks) const
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2024-02-12 18:10:33 -03:00
|
|
|
return m_impl->Select(new_only, networks);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2023-09-29 23:23:36 +02:00
|
|
|
std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2023-09-29 23:23:36 +02:00
|
|
|
return m_impl->GetAddr(max_addresses, max_pct, network, filtered);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
rpc: getrawaddrman for addrman entries
Exposing address manager table entries in a hidden RPC allows to introspect
addrman tables in tests and during development.
As response JSON object the following FORMAT1 is choosen:
{
"table": {
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
"<bucket>/<position>": { "address": "..", "port": .., ... },
...
}
}
An alternative would be FORMAT2
{
"table": {
"bucket": {
"position": { "address": "..", "port": .., ... },
"position": { "address": "..", "port": .., ... },
..
},
"bucket": {
"position": { "address": "..", "port": .., ... },
..
},
}
}
FORMAT1 and FORMAT2 have different encodings for the location of the
address in the address manager. While FORMAT2 might be easier to process
for downstream tools, it also mimics internal addrman mappings, which
might change at some point. Users not interested in the address location
can ignore the location key. They don't have to adapt to a new RPC
response format, when the internal addrman layout changes. Additionally,
FORMAT1 is also slightly easier to to iterate in downstream tools. The
RPC response-building implemenation complexcity is lower with FORMAT1
as we can more easily build a "<bucket>/<position>" key than a multiple
"bucket" objects with multiple "position" objects (FORMAT2).
2023-09-20 19:37:45 +02:00
|
|
|
std::vector<std::pair<AddrInfo, AddressPosition>> AddrMan::GetEntries(bool use_tried) const
|
|
|
|
{
|
|
|
|
return m_impl->GetEntries(use_tried);
|
|
|
|
}
|
|
|
|
|
2022-03-28 14:20:04 +02:00
|
|
|
void AddrMan::Connected(const CService& addr, NodeSeconds time)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
2022-03-28 14:20:04 +02:00
|
|
|
m_impl->Connected(addr, time);
|
2021-09-01 11:21:29 -07:00
|
|
|
}
|
|
|
|
|
2021-09-10 18:53:57 -06:00
|
|
|
void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
|
2021-09-01 11:21:29 -07:00
|
|
|
{
|
|
|
|
m_impl->SetServices(addr, nServices);
|
|
|
|
}
|
|
|
|
|
2021-12-09 18:25:22 +00:00
|
|
|
std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr)
|
|
|
|
{
|
|
|
|
return m_impl->FindAddressEntry(addr);
|
|
|
|
}
|