mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-11 01:26:10 +01:00
Merge bitcoin/bitcoin#22950: [p2p] Pimpl AddrMan to abstract implementation details
021f86953e
[style] Run changed files through clang formatter. (Amiti Uttarwar)375750387e
scripted-diff: Rename CAddrInfo to AddrInfo (Amiti Uttarwar)dd8f7f2500
scripted-diff: Rename CAddrMan to AddrMan (Amiti Uttarwar)3c263d3f63
[includes] Fix up included files (Amiti Uttarwar)29727c2aa1
[doc] Update comments (Amiti Uttarwar)14f9e000d0
[refactor] Update GetAddr_() function signature (Amiti Uttarwar)40acd6fc9a
[move-only] Move constants to test-only header (Amiti Uttarwar)7cf41bbb38
[addrman] Change CAddrInfo access (Amiti Uttarwar)e3f1ea659c
[move-only] Move CAddrInfo to test-only header file (Amiti Uttarwar)7cba9d5618
[net, addrman] Remove external dependencies on CAddrInfo objects (Amiti Uttarwar)8af5b54f97
[addrman] Introduce CAddrMan::Impl to encapsulate addrman implementation. (Amiti Uttarwar)f2e5f38f09
[move-only] Match ordering of CAddrMan declarations and definitions (Amiti Uttarwar)5faa7dd6d8
[move-only] Move CAddrMan function definitions to cpp (Amiti Uttarwar) Pull request description: Introduce the pimpl pattern for AddrMan to separate the implementation details from the externally used object representation. This reduces compile-time dependencies and conceptually clarifies AddrMan's interface from the implementation specifics. Since the unit & fuzz tests currently rely on accessing AddrMan internals, this PR introduces addrman_impl.h, which is exclusively imported by addrman.cpp and test files. ACKs for top commit: jnewbery: ACK021f86953e
GeneFerneau: utACK [021f869
](021f86953e
) mzumsande: ACK021f86953e
rajarshimaitra: Concept + Code Review ACK021f86953e
theuni: ACK021f86953e
Tree-SHA512: aa70cb77927a35c85230163c0cf6d3872382d79048b0fb79341493caa46f8e91498cb787d8b06aba4da17b2f921f2230e73f3d66385519794fff86a831b3a71d
This commit is contained in:
commit
c4fc899442
20 changed files with 897 additions and 744 deletions
|
@ -117,6 +117,7 @@ endif
|
|||
BITCOIN_CORE_H = \
|
||||
addrdb.h \
|
||||
addrman.h \
|
||||
addrman_impl.h \
|
||||
attributes.h \
|
||||
banman.h \
|
||||
base58.h \
|
||||
|
|
|
@ -170,21 +170,21 @@ bool CBanDB::Read(banmap_t& banSet)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DumpPeerAddresses(const ArgsManager& args, const CAddrMan& addr)
|
||||
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
|
||||
{
|
||||
const auto pathAddr = args.GetDataDirNet() / "peers.dat";
|
||||
return SerializeFileDB("peers", pathAddr, addr, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
void ReadFromStream(CAddrMan& addr, CDataStream& ssPeers)
|
||||
void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
|
||||
{
|
||||
DeserializeDB(ssPeers, addr, false);
|
||||
}
|
||||
|
||||
std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<CAddrMan>& addrman)
|
||||
std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
|
||||
{
|
||||
auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
|
||||
addrman = std::make_unique<CAddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
|
||||
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
|
||||
|
||||
int64_t nStart = GetTimeMillis();
|
||||
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
|
||||
|
@ -193,7 +193,7 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
|
|||
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart);
|
||||
} catch (const DbNotFoundError&) {
|
||||
// Addrman can be in an inconsistent state after failure, reset it
|
||||
addrman = std::make_unique<CAddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
|
||||
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
|
||||
LogPrintf("Creating peers.dat because the file was not found (%s)\n", path_addr);
|
||||
DumpPeerAddresses(args, *addrman);
|
||||
} catch (const std::exception& e) {
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
#include <vector>
|
||||
|
||||
class ArgsManager;
|
||||
class CAddrMan;
|
||||
class AddrMan;
|
||||
class CAddress;
|
||||
class CDataStream;
|
||||
struct bilingual_str;
|
||||
|
||||
bool DumpPeerAddresses(const ArgsManager& args, const CAddrMan& addr);
|
||||
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
|
||||
/** Only used by tests. */
|
||||
void ReadFromStream(CAddrMan& addr, CDataStream& ssPeers);
|
||||
void ReadFromStream(AddrMan& addr, CDataStream& ssPeers);
|
||||
|
||||
/** Access to the banlist database (banlist.json) */
|
||||
class CBanDB
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
};
|
||||
|
||||
/** Returns an error string on failure */
|
||||
std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<CAddrMan>& addrman);
|
||||
std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
|
||||
|
||||
/**
|
||||
* Dump the anchor IP address database (anchors.dat)
|
||||
|
|
611
src/addrman.cpp
611
src/addrman.cpp
|
@ -4,25 +4,27 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <addrman.h>
|
||||
#include <addrman_impl.h>
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <hash.h>
|
||||
#include <logging.h>
|
||||
#include <netaddress.h>
|
||||
#include <protocol.h>
|
||||
#include <random.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <timedata.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
#include <util/check.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/** Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread */
|
||||
static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8};
|
||||
/** Over how many buckets entries with new addresses originating from a single group are spread */
|
||||
static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
|
||||
/** Maximum number of times an address can be added to the new table */
|
||||
/** Maximum number of times an address can occur in the new table */
|
||||
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
|
||||
/** How old addresses can maximally be */
|
||||
static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
|
||||
|
@ -39,7 +41,7 @@ static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
|
|||
/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
|
||||
static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
|
||||
|
||||
int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
|
||||
int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const
|
||||
{
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
|
||||
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
|
||||
|
@ -49,7 +51,7 @@ int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asma
|
|||
return tried_bucket;
|
||||
}
|
||||
|
||||
int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
|
||||
int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
|
||||
{
|
||||
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
|
||||
|
@ -60,13 +62,13 @@ int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std:
|
|||
return new_bucket;
|
||||
}
|
||||
|
||||
int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
|
||||
int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
|
||||
{
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
|
||||
return hash1 % ADDRMAN_BUCKET_SIZE;
|
||||
}
|
||||
|
||||
bool CAddrInfo::IsTerrible(int64_t nNow) const
|
||||
bool AddrInfo::IsTerrible(int64_t nNow) const
|
||||
{
|
||||
if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
|
||||
return false;
|
||||
|
@ -86,7 +88,7 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const
|
|||
return false;
|
||||
}
|
||||
|
||||
double CAddrInfo::GetChance(int64_t nNow) const
|
||||
double AddrInfo::GetChance(int64_t nNow) const
|
||||
{
|
||||
double fChance = 1.0;
|
||||
int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
|
||||
|
@ -101,7 +103,7 @@ double CAddrInfo::GetChance(int64_t nNow) const
|
|||
return fChance;
|
||||
}
|
||||
|
||||
CAddrMan::CAddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
|
||||
AddrManImpl::AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio)
|
||||
: insecure_rand{deterministic}
|
||||
, nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
|
||||
, m_consistency_check_ratio{consistency_check_ratio}
|
||||
|
@ -119,8 +121,13 @@ CAddrMan::CAddrMan(std::vector<bool> asmap, bool deterministic, int32_t consiste
|
|||
}
|
||||
}
|
||||
|
||||
AddrManImpl::~AddrManImpl()
|
||||
{
|
||||
nKey.SetNull();
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void CAddrMan::Serialize(Stream& s_) const
|
||||
void AddrManImpl::Serialize(Stream& s_) const
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
|
@ -183,7 +190,7 @@ void CAddrMan::Serialize(Stream& s_) const
|
|||
int nIds = 0;
|
||||
for (const auto& entry : mapInfo) {
|
||||
mapUnkIds[entry.first] = nIds;
|
||||
const CAddrInfo &info = entry.second;
|
||||
const AddrInfo& info = entry.second;
|
||||
if (info.nRefCount) {
|
||||
assert(nIds != nNew); // this means nNew was wrong, oh ow
|
||||
s << info;
|
||||
|
@ -192,7 +199,7 @@ void CAddrMan::Serialize(Stream& s_) const
|
|||
}
|
||||
nIds = 0;
|
||||
for (const auto& entry : mapInfo) {
|
||||
const CAddrInfo &info = entry.second;
|
||||
const AddrInfo& info = entry.second;
|
||||
if (info.fInTried) {
|
||||
assert(nIds != nTried); // this means nTried was wrong, oh ow
|
||||
s << info;
|
||||
|
@ -223,7 +230,7 @@ void CAddrMan::Serialize(Stream& s_) const
|
|||
}
|
||||
|
||||
template <typename Stream>
|
||||
void CAddrMan::Unserialize(Stream& s_)
|
||||
void AddrManImpl::Unserialize(Stream& s_)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
|
@ -262,21 +269,21 @@ void CAddrMan::Unserialize(Stream& s_)
|
|||
|
||||
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %d]",
|
||||
strprintf("Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
|
||||
nNew,
|
||||
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %d]",
|
||||
strprintf("Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
|
||||
nTried,
|
||||
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
// Deserialize entries from the new table.
|
||||
for (int n = 0; n < nNew; n++) {
|
||||
CAddrInfo &info = mapInfo[n];
|
||||
AddrInfo& info = mapInfo[n];
|
||||
s >> info;
|
||||
mapAddr[info] = n;
|
||||
info.nRandomPos = vRandom.size();
|
||||
|
@ -287,7 +294,7 @@ void CAddrMan::Unserialize(Stream& s_)
|
|||
// Deserialize entries from the tried table.
|
||||
int nLost = 0;
|
||||
for (int n = 0; n < nTried; n++) {
|
||||
CAddrInfo info;
|
||||
AddrInfo info;
|
||||
s >> info;
|
||||
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
||||
|
@ -344,7 +351,7 @@ void CAddrMan::Unserialize(Stream& s_)
|
|||
for (auto bucket_entry : bucket_entries) {
|
||||
int bucket{bucket_entry.first};
|
||||
const int entry_index{bucket_entry.second};
|
||||
CAddrInfo& info = mapInfo[entry_index];
|
||||
AddrInfo& info = mapInfo[entry_index];
|
||||
|
||||
// Don't store the entry in the new bucket if it's not a valid address for our addrman
|
||||
if (!info.IsValid()) continue;
|
||||
|
@ -394,16 +401,7 @@ void CAddrMan::Unserialize(Stream& s_)
|
|||
}
|
||||
}
|
||||
|
||||
// explicit instantiation
|
||||
template void CAddrMan::Serialize(CHashWriter& s) const;
|
||||
template void CAddrMan::Serialize(CAutoFile& s) const;
|
||||
template void CAddrMan::Serialize(CDataStream& s) const;
|
||||
template void CAddrMan::Unserialize(CAutoFile& s);
|
||||
template void CAddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
|
||||
template void CAddrMan::Unserialize(CDataStream& s);
|
||||
template void CAddrMan::Unserialize(CHashVerifier<CDataStream>& s);
|
||||
|
||||
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
|
||||
AddrInfo* AddrManImpl::Find(const CNetAddr& addr, int* pnId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -418,12 +416,12 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
|
||||
AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
int nId = nIdCount++;
|
||||
mapInfo[nId] = CAddrInfo(addr, addrSource);
|
||||
mapInfo[nId] = AddrInfo(addr, addrSource);
|
||||
mapAddr[addr] = nId;
|
||||
mapInfo[nId].nRandomPos = vRandom.size();
|
||||
vRandom.push_back(nId);
|
||||
|
@ -432,7 +430,7 @@ CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, in
|
|||
return &mapInfo[nId];
|
||||
}
|
||||
|
||||
void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
|
||||
void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -456,12 +454,12 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
|
|||
vRandom[nRndPos2] = nId1;
|
||||
}
|
||||
|
||||
void CAddrMan::Delete(int nId)
|
||||
void AddrManImpl::Delete(int nId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
assert(mapInfo.count(nId) != 0);
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
AddrInfo& info = mapInfo[nId];
|
||||
assert(!info.fInTried);
|
||||
assert(info.nRefCount == 0);
|
||||
|
||||
|
@ -472,14 +470,14 @@ void CAddrMan::Delete(int nId)
|
|||
nNew--;
|
||||
}
|
||||
|
||||
void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
|
||||
void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
// if there is an entry in the specified bucket, delete it.
|
||||
if (vvNew[nUBucket][nUBucketPos] != -1) {
|
||||
int nIdDelete = vvNew[nUBucket][nUBucketPos];
|
||||
CAddrInfo& infoDelete = mapInfo[nIdDelete];
|
||||
AddrInfo& infoDelete = mapInfo[nIdDelete];
|
||||
assert(infoDelete.nRefCount > 0);
|
||||
infoDelete.nRefCount--;
|
||||
vvNew[nUBucket][nUBucketPos] = -1;
|
||||
|
@ -489,7 +487,7 @@ void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
|
|||
}
|
||||
}
|
||||
|
||||
void CAddrMan::MakeTried(CAddrInfo& info, int nId)
|
||||
void AddrManImpl::MakeTried(AddrInfo& info, int nId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -517,7 +515,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId)
|
|||
// find an item to evict
|
||||
int nIdEvict = vvTried[nKBucket][nKBucketPos];
|
||||
assert(mapInfo.count(nIdEvict) == 1);
|
||||
CAddrInfo& infoOld = mapInfo[nIdEvict];
|
||||
AddrInfo& infoOld = mapInfo[nIdEvict];
|
||||
|
||||
// Remove the to-be-evicted item from the tried set.
|
||||
infoOld.fInTried = false;
|
||||
|
@ -542,7 +540,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId)
|
|||
info.fInTried = true;
|
||||
}
|
||||
|
||||
void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
|
||||
void AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -550,13 +548,13 @@ void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime
|
|||
|
||||
nLastGood = nTime;
|
||||
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
AddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
AddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
|
@ -598,7 +596,7 @@ void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime
|
|||
}
|
||||
}
|
||||
|
||||
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
bool AddrManImpl::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -607,7 +605,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
|
|||
|
||||
bool fNew = false;
|
||||
int nId;
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
AddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
// Do not set a penalty for a source's self-announcement
|
||||
if (addr == source) {
|
||||
|
@ -654,7 +652,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
|
|||
if (vvNew[nUBucket][nUBucketPos] != nId) {
|
||||
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
|
||||
if (!fInsert) {
|
||||
CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
|
||||
AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
|
||||
if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
|
||||
// Overwrite the existing new table entry.
|
||||
fInsert = true;
|
||||
|
@ -673,17 +671,17 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
|
|||
return fNew;
|
||||
}
|
||||
|
||||
void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
AddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
AddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
|
@ -697,15 +695,13 @@ void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
|
|||
}
|
||||
}
|
||||
|
||||
CAddrInfo CAddrMan::Select_(bool newOnly) const
|
||||
std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (vRandom.empty())
|
||||
return CAddrInfo();
|
||||
if (vRandom.empty()) return {};
|
||||
|
||||
if (newOnly && nNew == 0)
|
||||
return CAddrInfo();
|
||||
if (newOnly && nNew == 0) return {};
|
||||
|
||||
// Use a 50% chance for choosing between tried and new table entries.
|
||||
if (!newOnly &&
|
||||
|
@ -722,9 +718,10 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const
|
|||
int nId = vvTried[nKBucket][nKBucketPos];
|
||||
const auto it_found{mapInfo.find(nId)};
|
||||
assert(it_found != mapInfo.end());
|
||||
const CAddrInfo& info{it_found->second};
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
const AddrInfo& info{it_found->second};
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
|
||||
return {info, info.nLastTry};
|
||||
}
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
} else {
|
||||
|
@ -740,15 +737,185 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const
|
|||
int nId = vvNew[nUBucket][nUBucketPos];
|
||||
const auto it_found{mapInfo.find(nId)};
|
||||
assert(it_found != mapInfo.end());
|
||||
const CAddrInfo& info{it_found->second};
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
const AddrInfo& info{it_found->second};
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
|
||||
return {info, info.nLastTry};
|
||||
}
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAddrMan::Check() const
|
||||
std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
size_t nNodes = vRandom.size();
|
||||
if (max_pct != 0) {
|
||||
nNodes = max_pct * nNodes / 100;
|
||||
}
|
||||
if (max_addresses != 0) {
|
||||
nNodes = std::min(nNodes, max_addresses);
|
||||
}
|
||||
|
||||
// gather a list of random nodes, skipping those of low quality
|
||||
const int64_t now{GetAdjustedTime()};
|
||||
std::vector<CAddress> addresses;
|
||||
for (unsigned int n = 0; n < vRandom.size(); n++) {
|
||||
if (addresses.size() >= nNodes)
|
||||
break;
|
||||
|
||||
int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
|
||||
SwapRandom(n, nRndPos);
|
||||
const auto it{mapInfo.find(vRandom[n])};
|
||||
assert(it != mapInfo.end());
|
||||
|
||||
const AddrInfo& ai{it->second};
|
||||
|
||||
// Filter by network (optional)
|
||||
if (network != std::nullopt && ai.GetNetClass() != network) continue;
|
||||
|
||||
// Filter for quality
|
||||
if (ai.IsTerrible(now)) continue;
|
||||
|
||||
addresses.push_back(ai);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
AddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
AddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
int64_t nUpdateInterval = 20 * 60;
|
||||
if (nTime - info.nTime > nUpdateInterval)
|
||||
info.nTime = nTime;
|
||||
}
|
||||
|
||||
void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
AddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
AddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
info.nServices = nServices;
|
||||
}
|
||||
|
||||
void AddrManImpl::ResolveCollisions_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
|
||||
int id_new = *it;
|
||||
|
||||
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 {
|
||||
AddrInfo& info_new = mapInfo[id_new];
|
||||
|
||||
// Which tried bucket to move the entry to.
|
||||
int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
|
||||
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
|
||||
int id_old = vvTried[tried_bucket][tried_bucket_pos];
|
||||
AddrInfo& info_old = mapInfo[id_old];
|
||||
|
||||
// Has successfully connected in last X hours
|
||||
if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
|
||||
erase_collision = true;
|
||||
} else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
|
||||
|
||||
// Give address at least 60 seconds to successfully connect
|
||||
if (GetAdjustedTime() - info_old.nLastTry > 60) {
|
||||
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
|
||||
|
||||
// Replaces an existing address already in the tried table with the new address
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
|
||||
// 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.
|
||||
LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else { // Collision is not actually a collision anymore
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (erase_collision) {
|
||||
m_tried_collisions.erase(it++);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (m_tried_collisions.size() == 0) return {};
|
||||
|
||||
std::set<int>::iterator it = m_tried_collisions.begin();
|
||||
|
||||
// Selects a random element from m_tried_collisions
|
||||
std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
|
||||
int id_new = *it;
|
||||
|
||||
// If id_new not found in mapInfo remove it from m_tried_collisions
|
||||
if (mapInfo.count(id_new) != 1) {
|
||||
m_tried_collisions.erase(it);
|
||||
return {};
|
||||
}
|
||||
|
||||
const AddrInfo& newInfo = mapInfo[id_new];
|
||||
|
||||
// which tried bucket to move the entry to
|
||||
int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
|
||||
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
|
||||
|
||||
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
|
||||
return {info_old, info_old.nLastTry};
|
||||
}
|
||||
|
||||
void AddrManImpl::Check() const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -763,7 +930,7 @@ void CAddrMan::Check() const
|
|||
}
|
||||
}
|
||||
|
||||
int CAddrMan::ForceCheckAddrman() const
|
||||
int AddrManImpl::ForceCheckAddrman() const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
|
@ -777,7 +944,7 @@ int CAddrMan::ForceCheckAddrman() const
|
|||
|
||||
for (const auto& entry : mapInfo) {
|
||||
int n = entry.first;
|
||||
const CAddrInfo& info = entry.second;
|
||||
const AddrInfo& info = entry.second;
|
||||
if (info.fInTried) {
|
||||
if (!info.nLastSuccess)
|
||||
return -1;
|
||||
|
@ -851,169 +1018,175 @@ int CAddrMan::ForceCheckAddrman() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
size_t AddrManImpl::size() const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
size_t nNodes = vRandom.size();
|
||||
if (max_pct != 0) {
|
||||
nNodes = max_pct * nNodes / 100;
|
||||
}
|
||||
if (max_addresses != 0) {
|
||||
nNodes = std::min(nNodes, max_addresses);
|
||||
}
|
||||
|
||||
// gather a list of random nodes, skipping those of low quality
|
||||
const int64_t now{GetAdjustedTime()};
|
||||
for (unsigned int n = 0; n < vRandom.size(); n++) {
|
||||
if (vAddr.size() >= nNodes)
|
||||
break;
|
||||
|
||||
int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
|
||||
SwapRandom(n, nRndPos);
|
||||
const auto it{mapInfo.find(vRandom[n])};
|
||||
assert(it != mapInfo.end());
|
||||
|
||||
const CAddrInfo& ai{it->second};
|
||||
|
||||
// Filter by network (optional)
|
||||
if (network != std::nullopt && ai.GetNetClass() != network) continue;
|
||||
|
||||
// Filter for quality
|
||||
if (ai.IsTerrible(now)) continue;
|
||||
|
||||
vAddr.push_back(ai);
|
||||
}
|
||||
LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
|
||||
return vRandom.size();
|
||||
}
|
||||
|
||||
void CAddrMan::Connected_(const CService& addr, int64_t nTime)
|
||||
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
int64_t nUpdateInterval = 20 * 60;
|
||||
if (nTime - info.nTime > nUpdateInterval)
|
||||
info.nTime = nTime;
|
||||
}
|
||||
|
||||
void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
info.nServices = nServices;
|
||||
}
|
||||
|
||||
void CAddrMan::ResolveCollisions_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
|
||||
int id_new = *it;
|
||||
|
||||
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 {
|
||||
CAddrInfo& info_new = mapInfo[id_new];
|
||||
|
||||
// Which tried bucket to move the entry to.
|
||||
int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
|
||||
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
|
||||
int id_old = vvTried[tried_bucket][tried_bucket_pos];
|
||||
CAddrInfo& info_old = mapInfo[id_old];
|
||||
|
||||
// Has successfully connected in last X hours
|
||||
if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
|
||||
erase_collision = true;
|
||||
} else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
|
||||
|
||||
// Give address at least 60 seconds to successfully connect
|
||||
if (GetAdjustedTime() - info_old.nLastTry > 60) {
|
||||
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
|
||||
|
||||
// Replaces an existing address already in the tried table with the new address
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
|
||||
// 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.
|
||||
LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else { // Collision is not actually a collision anymore
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (erase_collision) {
|
||||
m_tried_collisions.erase(it++);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
LOCK(cs);
|
||||
int nAdd = 0;
|
||||
Check();
|
||||
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
|
||||
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
|
||||
Check();
|
||||
if (nAdd) {
|
||||
LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
|
||||
}
|
||||
return nAdd > 0;
|
||||
}
|
||||
|
||||
CAddrInfo CAddrMan::SelectTriedCollision_()
|
||||
void AddrManImpl::Good(const CService& addr, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (m_tried_collisions.size() == 0) return CAddrInfo();
|
||||
|
||||
std::set<int>::iterator it = m_tried_collisions.begin();
|
||||
|
||||
// Selects a random element from m_tried_collisions
|
||||
std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
|
||||
int id_new = *it;
|
||||
|
||||
// If id_new not found in mapInfo remove it from m_tried_collisions
|
||||
if (mapInfo.count(id_new) != 1) {
|
||||
m_tried_collisions.erase(it);
|
||||
return CAddrInfo();
|
||||
}
|
||||
|
||||
const CAddrInfo& newInfo = mapInfo[id_new];
|
||||
|
||||
// which tried bucket to move the entry to
|
||||
int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
|
||||
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
|
||||
|
||||
int id_old = vvTried[tried_bucket][tried_bucket_pos];
|
||||
|
||||
return mapInfo[id_old];
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Good_(addr, /* test_before_evict */ true, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Attempt_(addr, fCountFailure, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
void AddrManImpl::ResolveCollisions()
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
ResolveCollisions_();
|
||||
Check();
|
||||
}
|
||||
|
||||
std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const auto ret = SelectTriedCollision_();
|
||||
Check();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::pair<CAddress, int64_t> AddrManImpl::Select(bool newOnly) const
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const auto addrRet = Select_(newOnly);
|
||||
Check();
|
||||
return addrRet;
|
||||
}
|
||||
|
||||
std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const auto addresses = GetAddr_(max_addresses, max_pct, network);
|
||||
Check();
|
||||
return addresses;
|
||||
}
|
||||
|
||||
void AddrManImpl::Connected(const CService& addr, int64_t nTime)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Connected_(addr, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
SetServices_(addr, nServices);
|
||||
Check();
|
||||
}
|
||||
|
||||
const std::vector<bool>& AddrManImpl::GetAsmap() const
|
||||
{
|
||||
return m_asmap;
|
||||
}
|
||||
|
||||
AddrMan::AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
|
||||
: m_impl(std::make_unique<AddrManImpl>(std::move(asmap), deterministic, consistency_check_ratio)) {}
|
||||
|
||||
AddrMan::~AddrMan() = default;
|
||||
|
||||
template <typename Stream>
|
||||
void AddrMan::Serialize(Stream& s_) const
|
||||
{
|
||||
m_impl->Serialize<Stream>(s_);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void AddrMan::Unserialize(Stream& s_)
|
||||
{
|
||||
m_impl->Unserialize<Stream>(s_);
|
||||
}
|
||||
|
||||
// explicit instantiation
|
||||
template void AddrMan::Serialize(CHashWriter& s) const;
|
||||
template void AddrMan::Serialize(CAutoFile& s) const;
|
||||
template void AddrMan::Serialize(CDataStream& s) const;
|
||||
template void AddrMan::Unserialize(CAutoFile& s);
|
||||
template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
|
||||
template void AddrMan::Unserialize(CDataStream& s);
|
||||
template void AddrMan::Unserialize(CHashVerifier<CDataStream>& s);
|
||||
|
||||
size_t AddrMan::size() const
|
||||
{
|
||||
return m_impl->size();
|
||||
}
|
||||
|
||||
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
{
|
||||
return m_impl->Add(vAddr, source, nTimePenalty);
|
||||
}
|
||||
|
||||
void AddrMan::Good(const CService& addr, int64_t nTime)
|
||||
{
|
||||
m_impl->Good(addr, nTime);
|
||||
}
|
||||
|
||||
void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
{
|
||||
m_impl->Attempt(addr, fCountFailure, nTime);
|
||||
}
|
||||
|
||||
void AddrMan::ResolveCollisions()
|
||||
{
|
||||
m_impl->ResolveCollisions();
|
||||
}
|
||||
|
||||
std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision()
|
||||
{
|
||||
return m_impl->SelectTriedCollision();
|
||||
}
|
||||
|
||||
std::pair<CAddress, int64_t> AddrMan::Select(bool newOnly) const
|
||||
{
|
||||
return m_impl->Select(newOnly);
|
||||
}
|
||||
|
||||
std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
{
|
||||
return m_impl->GetAddr(max_addresses, max_pct, network);
|
||||
}
|
||||
|
||||
void AddrMan::Connected(const CService& addr, int64_t nTime)
|
||||
{
|
||||
m_impl->Connected(addr, nTime);
|
||||
}
|
||||
|
||||
void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
|
||||
{
|
||||
m_impl->SetServices(addr, nServices);
|
||||
}
|
||||
|
||||
const std::vector<bool>& AddrMan::GetAsmap() const
|
||||
{
|
||||
return m_impl->GetAsmap();
|
||||
}
|
||||
|
|
378
src/addrman.h
378
src/addrman.h
|
@ -6,94 +6,22 @@
|
|||
#ifndef BITCOIN_ADDRMAN_H
|
||||
#define BITCOIN_ADDRMAN_H
|
||||
|
||||
#include <fs.h>
|
||||
#include <logging.h>
|
||||
#include <netaddress.h>
|
||||
#include <protocol.h>
|
||||
#include <sync.h>
|
||||
#include <streams.h>
|
||||
#include <timedata.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class AddrManImpl;
|
||||
|
||||
/** Default for -checkaddrman */
|
||||
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
|
||||
|
||||
/**
|
||||
* Extended statistics about a CAddress
|
||||
*/
|
||||
class CAddrInfo : public CAddress
|
||||
{
|
||||
public:
|
||||
//! last try whatsoever by us (memory only)
|
||||
int64_t nLastTry{0};
|
||||
|
||||
//! last counted attempt (memory only)
|
||||
int64_t nLastCountAttempt{0};
|
||||
|
||||
private:
|
||||
//! where knowledge about this address first came from
|
||||
CNetAddr source;
|
||||
|
||||
//! last successful connection by us
|
||||
int64_t nLastSuccess{0};
|
||||
|
||||
//! connection attempts since last successful attempt
|
||||
int nAttempts{0};
|
||||
|
||||
//! reference count in new sets (memory only)
|
||||
int nRefCount{0};
|
||||
|
||||
//! in tried set? (memory only)
|
||||
bool fInTried{false};
|
||||
|
||||
//! position in vRandom
|
||||
mutable int nRandomPos{-1};
|
||||
|
||||
friend class CAddrMan;
|
||||
friend class CAddrManDeterministic;
|
||||
|
||||
public:
|
||||
|
||||
SERIALIZE_METHODS(CAddrInfo, obj)
|
||||
{
|
||||
READWRITEAS(CAddress, obj);
|
||||
READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
|
||||
}
|
||||
|
||||
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
|
||||
{
|
||||
}
|
||||
|
||||
CAddrInfo() : CAddress(), source()
|
||||
{
|
||||
}
|
||||
|
||||
//! Calculate in which "tried" bucket this entry belongs
|
||||
int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, given a certain source
|
||||
int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, using its default source
|
||||
int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
|
||||
{
|
||||
return GetNewBucket(nKey, source, asmap);
|
||||
}
|
||||
|
||||
//! Calculate in which position of a bucket to store this entry.
|
||||
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
|
||||
|
||||
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
|
||||
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
|
||||
|
||||
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
|
||||
double GetChance(int64_t nNow = GetAdjustedTime()) const;
|
||||
};
|
||||
|
||||
/** Stochastic address manager
|
||||
*
|
||||
* Design goals:
|
||||
|
@ -123,115 +51,53 @@ public:
|
|||
* * 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.
|
||||
*/
|
||||
|
||||
/** Total number of buckets for tried addresses */
|
||||
static constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2{8};
|
||||
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT{1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2};
|
||||
|
||||
/** Total number of buckets for new addresses */
|
||||
static constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2{10};
|
||||
static constexpr int ADDRMAN_NEW_BUCKET_COUNT{1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2};
|
||||
|
||||
/** Maximum allowed number of entries in buckets for new and tried addresses */
|
||||
static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6};
|
||||
static constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2};
|
||||
|
||||
/**
|
||||
* Stochastical (IP) address manager
|
||||
*/
|
||||
class CAddrMan
|
||||
class AddrMan
|
||||
{
|
||||
const std::unique_ptr<AddrManImpl> m_impl;
|
||||
|
||||
public:
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
explicit AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
|
||||
|
||||
~AddrMan();
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
void Serialize(Stream& s_) const;
|
||||
|
||||
explicit CAddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
|
||||
|
||||
~CAddrMan()
|
||||
{
|
||||
nKey.SetNull();
|
||||
}
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s_);
|
||||
|
||||
//! Return the number of (unique) addresses in all tables.
|
||||
size_t size() const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
|
||||
return vRandom.size();
|
||||
}
|
||||
size_t size() const;
|
||||
|
||||
//! Add addresses to addrman's new table.
|
||||
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
int nAdd = 0;
|
||||
Check();
|
||||
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
|
||||
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
|
||||
Check();
|
||||
if (nAdd) {
|
||||
LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
|
||||
}
|
||||
return nAdd > 0;
|
||||
}
|
||||
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0);
|
||||
|
||||
//! Mark an entry as accessible.
|
||||
void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Good_(addr, /* test_before_evict */ true, nTime);
|
||||
Check();
|
||||
}
|
||||
//! Mark an entry as accessible, possibly moving it from "new" to "tried".
|
||||
void Good(const CService& addr, int64_t nTime = GetAdjustedTime());
|
||||
|
||||
//! Mark an entry as connection attempted to.
|
||||
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Attempt_(addr, fCountFailure, nTime);
|
||||
Check();
|
||||
}
|
||||
void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime());
|
||||
|
||||
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
|
||||
void ResolveCollisions()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
ResolveCollisions_();
|
||||
Check();
|
||||
}
|
||||
void ResolveCollisions();
|
||||
|
||||
//! Randomly select an address in tried that another address is attempting to evict.
|
||||
CAddrInfo SelectTriedCollision()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const CAddrInfo ret = SelectTriedCollision_();
|
||||
Check();
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Randomly select an address in the tried table that another address is
|
||||
* attempting to evict.
|
||||
*
|
||||
* @return CAddress The record for the selected tried peer.
|
||||
* int64_t The last time we attempted to connect to that peer.
|
||||
*/
|
||||
std::pair<CAddress, int64_t> SelectTriedCollision();
|
||||
|
||||
/**
|
||||
* Choose an address to connect to.
|
||||
*
|
||||
* @param[in] newOnly Whether to only select addresses from the new table.
|
||||
* @return CAddress The record for the selected peer.
|
||||
* int64_t The last time we attempted to connect to that peer.
|
||||
*/
|
||||
CAddrInfo Select(bool newOnly = false) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const CAddrInfo addrRet = Select_(newOnly);
|
||||
Check();
|
||||
return addrRet;
|
||||
}
|
||||
std::pair<CAddress, int64_t> Select(bool newOnly = false) const;
|
||||
|
||||
/**
|
||||
* Return all or many randomly selected addresses, optionally by network.
|
||||
|
@ -239,174 +105,10 @@ public:
|
|||
* @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).
|
||||
*/
|
||||
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
std::vector<CAddress> vAddr;
|
||||
GetAddr_(vAddr, max_addresses, max_pct, network);
|
||||
Check();
|
||||
return vAddr;
|
||||
}
|
||||
|
||||
//! Outer function for Connected_()
|
||||
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Connected_(addr, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
void SetServices(const CService &addr, ServiceFlags nServices)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
SetServices_(addr, nServices);
|
||||
Check();
|
||||
}
|
||||
|
||||
const std::vector<bool>& GetAsmap() const { return m_asmap; }
|
||||
|
||||
private:
|
||||
//! A mutex to protect the inner data structures.
|
||||
mutable Mutex cs;
|
||||
|
||||
//! Source of random numbers for randomization in inner loops
|
||||
mutable FastRandomContext insecure_rand GUARDED_BY(cs);
|
||||
|
||||
//! secret key to randomize bucket select with
|
||||
uint256 nKey;
|
||||
|
||||
//! 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
|
||||
int nIdCount GUARDED_BY(cs){0};
|
||||
|
||||
//! table with information about all nIds
|
||||
std::unordered_map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
|
||||
|
||||
//! find an nId based on its network address
|
||||
std::unordered_map<CNetAddr, int, CNetAddrHash> mapAddr GUARDED_BY(cs);
|
||||
|
||||
//! randomly-ordered vector of all nIds
|
||||
//! 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);
|
||||
|
||||
// number of "tried" entries
|
||||
int nTried GUARDED_BY(cs){0};
|
||||
|
||||
//! list of "tried" buckets
|
||||
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! number of (unique) "new" entries
|
||||
int nNew GUARDED_BY(cs){0};
|
||||
|
||||
//! list of "new" buckets
|
||||
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
|
||||
int64_t nLastGood GUARDED_BY(cs){1};
|
||||
|
||||
//! 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;
|
||||
|
||||
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
|
||||
const int32_t m_consistency_check_ratio;
|
||||
|
||||
// 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;
|
||||
|
||||
//! Find an entry.
|
||||
CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.
|
||||
CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Swap two elements in vRandom.
|
||||
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! 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.
|
||||
CAddrInfo Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Consistency check, taking into account m_consistency_check_ratio. Will std::abort if an inconsistency is detected.
|
||||
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Perform consistency check, regardless of m_consistency_check_ratio.
|
||||
//! @returns an error code or zero.
|
||||
int ForceCheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* @return A vector of randomly selected addresses from vRandom.
|
||||
*/
|
||||
void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
|
||||
|
||||
/** We have successfully connected to this peer. Calling this function
|
||||
* updates the CAddress's nTime, which is used in our IsTerrible()
|
||||
|
@ -419,13 +121,15 @@ private:
|
|||
* @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);
|
||||
void Connected(const CService& addr, int64_t nTime = GetAdjustedTime());
|
||||
|
||||
//! Update an entry's service bits.
|
||||
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void SetServices(const CService& addr, ServiceFlags nServices);
|
||||
|
||||
friend class CAddrManTest;
|
||||
friend class CAddrManDeterministic;
|
||||
const std::vector<bool>& GetAsmap() const;
|
||||
|
||||
friend class AddrManTest;
|
||||
friend class AddrManDeterministic;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_ADDRMAN_H
|
||||
|
|
271
src/addrman_impl.h
Normal file
271
src/addrman_impl.h
Normal file
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) 2021 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_ADDRMAN_IMPL_H
|
||||
#define BITCOIN_ADDRMAN_IMPL_H
|
||||
|
||||
#include <logging.h>
|
||||
#include <netaddress.h>
|
||||
#include <protocol.h>
|
||||
#include <serialize.h>
|
||||
#include <sync.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/** Total number of buckets for tried addresses */
|
||||
static constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2{8};
|
||||
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT{1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2};
|
||||
/** Total number of buckets for new addresses */
|
||||
static constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2{10};
|
||||
static constexpr int ADDRMAN_NEW_BUCKET_COUNT{1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2};
|
||||
/** Maximum allowed number of entries in buckets for new and tried addresses */
|
||||
static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2{6};
|
||||
static constexpr int ADDRMAN_BUCKET_SIZE{1 << ADDRMAN_BUCKET_SIZE_LOG2};
|
||||
|
||||
/**
|
||||
* Extended statistics about a CAddress
|
||||
*/
|
||||
class AddrInfo : public CAddress
|
||||
{
|
||||
public:
|
||||
//! last try whatsoever by us (memory only)
|
||||
int64_t nLastTry{0};
|
||||
|
||||
//! last counted attempt (memory only)
|
||||
int64_t nLastCountAttempt{0};
|
||||
|
||||
//! where knowledge about this address first came from
|
||||
CNetAddr source;
|
||||
|
||||
//! last successful connection by us
|
||||
int64_t nLastSuccess{0};
|
||||
|
||||
//! connection attempts since last successful attempt
|
||||
int nAttempts{0};
|
||||
|
||||
//! reference count in new sets (memory only)
|
||||
int nRefCount{0};
|
||||
|
||||
//! in tried set? (memory only)
|
||||
bool fInTried{false};
|
||||
|
||||
//! position in vRandom
|
||||
mutable int nRandomPos{-1};
|
||||
|
||||
SERIALIZE_METHODS(AddrInfo, obj)
|
||||
{
|
||||
READWRITEAS(CAddress, obj);
|
||||
READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
|
||||
}
|
||||
|
||||
AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
|
||||
{
|
||||
}
|
||||
|
||||
AddrInfo() : CAddress(), source()
|
||||
{
|
||||
}
|
||||
|
||||
//! Calculate in which "tried" bucket this entry belongs
|
||||
int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, given a certain source
|
||||
int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, using its default source
|
||||
int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
|
||||
{
|
||||
return GetNewBucket(nKey, source, asmap);
|
||||
}
|
||||
|
||||
//! Calculate in which position of a bucket to store this entry.
|
||||
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
|
||||
|
||||
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
|
||||
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
|
||||
|
||||
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
|
||||
double GetChance(int64_t nNow = GetAdjustedTime()) const;
|
||||
};
|
||||
|
||||
class AddrManImpl
|
||||
{
|
||||
public:
|
||||
AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio);
|
||||
|
||||
~AddrManImpl();
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
void Good(const CService& addr, int64_t nTime)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
void Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
std::pair<CAddress, int64_t> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
std::pair<CAddress, int64_t> Select(bool newOnly) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
void Connected(const CService& addr, int64_t nTime)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
void SetServices(const CService& addr, ServiceFlags nServices)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
const std::vector<bool>& GetAsmap() const;
|
||||
|
||||
friend class AddrManTest;
|
||||
friend class AddrManDeterministic;
|
||||
|
||||
private:
|
||||
//! A mutex to protect the inner data structures.
|
||||
mutable Mutex cs;
|
||||
|
||||
//! Source of random numbers for randomization in inner loops
|
||||
mutable FastRandomContext insecure_rand GUARDED_BY(cs);
|
||||
|
||||
//! secret key to randomize bucket select with
|
||||
uint256 nKey;
|
||||
|
||||
//! 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
|
||||
int nIdCount GUARDED_BY(cs){0};
|
||||
|
||||
//! table with information about all nIds
|
||||
std::unordered_map<int, AddrInfo> mapInfo GUARDED_BY(cs);
|
||||
|
||||
//! find an nId based on its network address
|
||||
std::unordered_map<CNetAddr, int, CNetAddrHash> mapAddr GUARDED_BY(cs);
|
||||
|
||||
//! randomly-ordered vector of all nIds
|
||||
//! 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);
|
||||
|
||||
// number of "tried" entries
|
||||
int nTried GUARDED_BY(cs){0};
|
||||
|
||||
//! list of "tried" buckets
|
||||
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! number of (unique) "new" entries
|
||||
int nNew GUARDED_BY(cs){0};
|
||||
|
||||
//! list of "new" buckets
|
||||
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
|
||||
int64_t nLastGood GUARDED_BY(cs){1};
|
||||
|
||||
//! 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;
|
||||
|
||||
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
|
||||
const int32_t m_consistency_check_ratio;
|
||||
|
||||
// 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;
|
||||
|
||||
//! Find an entry.
|
||||
AddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.
|
||||
AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Swap two elements in vRandom.
|
||||
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const 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);
|
||||
|
||||
//! Move an entry from the "new" table(s) to the "tried" table
|
||||
void MakeTried(AddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
void Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
bool Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
std::pair<CAddress, int64_t> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Consistency check, taking into account m_consistency_check_ratio. Will std::abort if an inconsistency is detected.
|
||||
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Perform consistency check, regardless of m_consistency_check_ratio.
|
||||
//! @returns an error code or zero.
|
||||
int ForceCheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_ADDRMAN_IMPL_H
|
|
@ -53,14 +53,14 @@ static void CreateAddresses()
|
|||
}
|
||||
}
|
||||
|
||||
static void AddAddressesToAddrMan(CAddrMan& addrman)
|
||||
static void AddAddressesToAddrMan(AddrMan& addrman)
|
||||
{
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
addrman.Add(g_addresses[source_i], g_sources[source_i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillAddrMan(CAddrMan& addrman)
|
||||
static void FillAddrMan(AddrMan& addrman)
|
||||
{
|
||||
CreateAddresses();
|
||||
|
||||
|
@ -74,26 +74,26 @@ static void AddrManAdd(benchmark::Bench& bench)
|
|||
CreateAddresses();
|
||||
|
||||
bench.run([&] {
|
||||
CAddrMan addrman{/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0};
|
||||
AddrMan addrman{/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0};
|
||||
AddAddressesToAddrMan(addrman);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManSelect(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
bench.run([&] {
|
||||
const auto& address = addrman.Select();
|
||||
assert(address.GetPort() > 0);
|
||||
assert(address.first.GetPort() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManGetAddr(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
|
@ -105,7 +105,7 @@ static void AddrManGetAddr(benchmark::Bench& bench)
|
|||
|
||||
static void AddrManAddThenGood(benchmark::Bench& bench)
|
||||
{
|
||||
auto markSomeAsGood = [](CAddrMan& addrman) {
|
||||
auto markSomeAsGood = [](AddrMan& addrman) {
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
|
||||
addrman.Good(g_addresses[source_i][addr_i]);
|
||||
|
@ -117,12 +117,12 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
|
|||
|
||||
bench.run([&] {
|
||||
// To make the benchmark independent of the number of evaluations, we always prepare a new addrman.
|
||||
// This is necessary because CAddrMan::Good() method modifies the object, affecting the timing of subsequent calls
|
||||
// This is necessary because AddrMan::Good() method modifies the object, affecting the timing of subsequent calls
|
||||
// to the same method and we want to do the same amount of work in every loop iteration.
|
||||
//
|
||||
// This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
|
||||
// CAddrMan::Good() will still be noticeable.
|
||||
CAddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
// AddrMan::Good() will still be noticeable.
|
||||
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddAddressesToAddrMan(addrman);
|
||||
|
||||
markSomeAsGood(addrman);
|
||||
|
|
15
src/net.cpp
15
src/net.cpp
|
@ -2010,17 +2010,18 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
|||
if (nTries > 100)
|
||||
break;
|
||||
|
||||
CAddrInfo addr;
|
||||
CAddress addr;
|
||||
int64_t addr_last_try{0};
|
||||
|
||||
if (fFeeler) {
|
||||
// First, try to get a tried table collision address. This returns
|
||||
// an empty (invalid) address if there are no collisions to try.
|
||||
addr = addrman.SelectTriedCollision();
|
||||
std::tie(addr, addr_last_try) = addrman.SelectTriedCollision();
|
||||
|
||||
if (!addr.IsValid()) {
|
||||
// No tried table collisions. Select a new table address
|
||||
// for our feeler.
|
||||
addr = addrman.Select(true);
|
||||
std::tie(addr, addr_last_try) = addrman.Select(true);
|
||||
} else if (AlreadyConnectedToAddress(addr)) {
|
||||
// If test-before-evict logic would have us connect to a
|
||||
// peer that we're already connected to, just mark that
|
||||
|
@ -2029,11 +2030,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
|||
// a currently-connected peer.
|
||||
addrman.Good(addr);
|
||||
// Select a new table address for our feeler instead.
|
||||
addr = addrman.Select(true);
|
||||
std::tie(addr, addr_last_try) = addrman.Select(true);
|
||||
}
|
||||
} else {
|
||||
// Not a feeler
|
||||
addr = addrman.Select();
|
||||
std::tie(addr, addr_last_try) = addrman.Select();
|
||||
}
|
||||
|
||||
// Require outbound connections, other than feelers, to be to distinct network groups
|
||||
|
@ -2050,7 +2051,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
|||
continue;
|
||||
|
||||
// only consider very recently tried nodes after 30 failed attempts
|
||||
if (nANow - addr.nLastTry < 600 && nTries < 30)
|
||||
if (nANow - addr_last_try < 600 && nTries < 30)
|
||||
continue;
|
||||
|
||||
// for non-feelers, require all the services we'll want,
|
||||
|
@ -2443,7 +2444,7 @@ void CConnman::SetNetworkActive(bool active)
|
|||
}
|
||||
}
|
||||
|
||||
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, CAddrMan& addrman_in, bool network_active)
|
||||
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in, bool network_active)
|
||||
: addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
|
||||
{
|
||||
SetTryNewOutboundPeer(false);
|
||||
|
|
|
@ -797,7 +797,7 @@ public:
|
|||
m_onion_binds = connOptions.onion_binds;
|
||||
}
|
||||
|
||||
CConnman(uint64_t seed0, uint64_t seed1, CAddrMan& addrman, bool network_active = true);
|
||||
CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, bool network_active = true);
|
||||
~CConnman();
|
||||
bool Start(CScheduler& scheduler, const Options& options);
|
||||
|
||||
|
@ -1049,7 +1049,7 @@ private:
|
|||
std::vector<ListenSocket> vhListenSocket;
|
||||
std::atomic<bool> fNetworkActive{true};
|
||||
bool fAddressesInitialized{false};
|
||||
CAddrMan& addrman;
|
||||
AddrMan& addrman;
|
||||
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
|
||||
RecursiveMutex m_addr_fetches_mutex;
|
||||
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
|
||||
|
|
|
@ -292,7 +292,7 @@ using PeerRef = std::shared_ptr<Peer>;
|
|||
class PeerManagerImpl final : public PeerManager
|
||||
{
|
||||
public:
|
||||
PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
|
||||
PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman,
|
||||
BanMan* banman, ChainstateManager& chainman,
|
||||
CTxMemPool& pool, bool ignore_incoming_txs);
|
||||
|
||||
|
@ -410,7 +410,7 @@ private:
|
|||
|
||||
const CChainParams& m_chainparams;
|
||||
CConnman& m_connman;
|
||||
CAddrMan& m_addrman;
|
||||
AddrMan& m_addrman;
|
||||
/** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
|
||||
BanMan* const m_banman;
|
||||
ChainstateManager& m_chainman;
|
||||
|
@ -1426,14 +1426,14 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
|
|||
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
|
||||
std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman,
|
||||
BanMan* banman, ChainstateManager& chainman,
|
||||
CTxMemPool& pool, bool ignore_incoming_txs)
|
||||
{
|
||||
return std::make_unique<PeerManagerImpl>(chainparams, connman, addrman, banman, chainman, pool, ignore_incoming_txs);
|
||||
}
|
||||
|
||||
PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
|
||||
PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman,
|
||||
BanMan* banman, ChainstateManager& chainman,
|
||||
CTxMemPool& pool, bool ignore_incoming_txs)
|
||||
: m_chainparams(chainparams),
|
||||
|
@ -2664,7 +2664,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
// table is also potentially detrimental because new-table entries
|
||||
// are subject to eviction in the event of addrman collisions. We
|
||||
// mitigate the information-leak by never calling
|
||||
// CAddrMan::Connected() on block-relay-only peers; see
|
||||
// AddrMan::Connected() on block-relay-only peers; see
|
||||
// FinalizeNode().
|
||||
//
|
||||
// This moves an address from New to Tried table in Addrman,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <net.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
class CAddrMan;
|
||||
class AddrMan;
|
||||
class CChainParams;
|
||||
class CTxMemPool;
|
||||
class ChainstateManager;
|
||||
|
@ -37,7 +37,7 @@ struct CNodeStateStats {
|
|||
class PeerManager : public CValidationInterface, public NetEventsInterface
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
|
||||
static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman,
|
||||
BanMan* banman, ChainstateManager& chainman,
|
||||
CTxMemPool& pool, bool ignore_incoming_txs);
|
||||
virtual ~PeerManager() { }
|
||||
|
|
|
@ -165,7 +165,7 @@ void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6)
|
|||
}
|
||||
|
||||
/**
|
||||
* Create an "internal" address that represents a name or FQDN. CAddrMan uses
|
||||
* Create an "internal" address that represents a name or FQDN. AddrMan uses
|
||||
* these fake addresses to keep track of which DNS seeds were used.
|
||||
* @returns Whether or not the operation was successful.
|
||||
* @see NET_INTERNAL, INTERNAL_IN_IPV6_PREFIX, CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
|
||||
|
|
|
@ -62,7 +62,7 @@ enum Network {
|
|||
NET_CJDNS,
|
||||
|
||||
/// A set of addresses that represent the hash of a string or FQDN. We use
|
||||
/// them in CAddrMan to keep track of which DNS seeds were used.
|
||||
/// them in AddrMan to keep track of which DNS seeds were used.
|
||||
NET_INTERNAL,
|
||||
|
||||
/// Dummy value to indicate the number of NET_* constants.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
class ArgsManager;
|
||||
class BanMan;
|
||||
class CAddrMan;
|
||||
class AddrMan;
|
||||
class CBlockPolicyEstimator;
|
||||
class CConnman;
|
||||
class CScheduler;
|
||||
|
@ -39,7 +39,7 @@ class WalletClient;
|
|||
struct NodeContext {
|
||||
//! Init interface for initializing current process and connecting to other processes.
|
||||
interfaces::Init* init{nullptr};
|
||||
std::unique_ptr<CAddrMan> addrman;
|
||||
std::unique_ptr<AddrMan> addrman;
|
||||
std::unique_ptr<CConnman> connman;
|
||||
std::unique_ptr<CTxMemPool> mempool;
|
||||
std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <addrdb.h>
|
||||
#include <addrman.h>
|
||||
#include <addrman_impl.h>
|
||||
#include <chainparams.h>
|
||||
#include <clientversion.h>
|
||||
#include <hash.h>
|
||||
|
@ -21,26 +22,26 @@
|
|||
|
||||
using namespace std::literals;
|
||||
|
||||
class CAddrManSerializationMock : public CAddrMan
|
||||
class AddrManSerializationMock : public AddrMan
|
||||
{
|
||||
public:
|
||||
virtual void Serialize(CDataStream& s) const = 0;
|
||||
|
||||
CAddrManSerializationMock()
|
||||
: CAddrMan(/* asmap */ std::vector<bool>(), /* deterministic */ true, /* consistency_check_ratio */ 100)
|
||||
AddrManSerializationMock()
|
||||
: AddrMan(/* asmap */ std::vector<bool>(), /* deterministic */ true, /* consistency_check_ratio */ 100)
|
||||
{}
|
||||
};
|
||||
|
||||
class CAddrManUncorrupted : public CAddrManSerializationMock
|
||||
class AddrManUncorrupted : public AddrManSerializationMock
|
||||
{
|
||||
public:
|
||||
void Serialize(CDataStream& s) const override
|
||||
{
|
||||
CAddrMan::Serialize(s);
|
||||
AddrMan::Serialize(s);
|
||||
}
|
||||
};
|
||||
|
||||
class CAddrManCorrupted : public CAddrManSerializationMock
|
||||
class AddrManCorrupted : public AddrManSerializationMock
|
||||
{
|
||||
public:
|
||||
void Serialize(CDataStream& s) const override
|
||||
|
@ -61,12 +62,12 @@ public:
|
|||
CAddress addr = CAddress(serv, NODE_NONE);
|
||||
CNetAddr resolved;
|
||||
BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
|
||||
CAddrInfo info = CAddrInfo(addr, resolved);
|
||||
AddrInfo info = AddrInfo(addr, resolved);
|
||||
s << info;
|
||||
}
|
||||
};
|
||||
|
||||
static CDataStream AddrmanToStream(const CAddrManSerializationMock& _addrman)
|
||||
static CDataStream AddrmanToStream(const AddrManSerializationMock& _addrman)
|
||||
{
|
||||
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
|
||||
ssPeersIn << Params().MessageStart();
|
||||
|
@ -76,44 +77,44 @@ static CDataStream AddrmanToStream(const CAddrManSerializationMock& _addrman)
|
|||
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
class CAddrManTest : public CAddrMan
|
||||
class AddrManTest : public AddrMan
|
||||
{
|
||||
private:
|
||||
bool deterministic;
|
||||
public:
|
||||
explicit CAddrManTest(bool makeDeterministic = true,
|
||||
std::vector<bool> asmap = std::vector<bool>())
|
||||
: CAddrMan(asmap, makeDeterministic, /* consistency_check_ratio */ 100)
|
||||
explicit AddrManTest(bool makeDeterministic = true,
|
||||
std::vector<bool> asmap = std::vector<bool>())
|
||||
: AddrMan(asmap, makeDeterministic, /* consistency_check_ratio */ 100)
|
||||
{
|
||||
deterministic = makeDeterministic;
|
||||
}
|
||||
|
||||
CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
|
||||
AddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
|
||||
{
|
||||
LOCK(cs);
|
||||
return CAddrMan::Find(addr, pnId);
|
||||
LOCK(m_impl->cs);
|
||||
return m_impl->Find(addr, pnId);
|
||||
}
|
||||
|
||||
CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
|
||||
AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
|
||||
{
|
||||
LOCK(cs);
|
||||
return CAddrMan::Create(addr, addrSource, pnId);
|
||||
LOCK(m_impl->cs);
|
||||
return m_impl->Create(addr, addrSource, pnId);
|
||||
}
|
||||
|
||||
void Delete(int nId)
|
||||
{
|
||||
LOCK(cs);
|
||||
CAddrMan::Delete(nId);
|
||||
LOCK(m_impl->cs);
|
||||
m_impl->Delete(nId);
|
||||
}
|
||||
|
||||
// Used to test deserialization
|
||||
std::pair<int, int> GetBucketAndEntry(const CAddress& addr)
|
||||
{
|
||||
LOCK(cs);
|
||||
int nId = mapAddr[addr];
|
||||
LOCK(m_impl->cs);
|
||||
int nId = m_impl->mapAddr[addr];
|
||||
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
|
||||
for (int entry = 0; entry < ADDRMAN_BUCKET_SIZE; ++entry) {
|
||||
if (nId == vvNew[bucket][entry]) {
|
||||
if (nId == m_impl->vvNew[bucket][entry]) {
|
||||
return std::pair<int, int>(bucket, entry);
|
||||
}
|
||||
}
|
||||
|
@ -165,20 +166,20 @@ BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(addrman_simple)
|
||||
{
|
||||
auto addrman = std::make_unique<CAddrManTest>();
|
||||
auto addrman = std::make_unique<AddrManTest>();
|
||||
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
||||
// Test: Does Addrman respond correctly when empty.
|
||||
BOOST_CHECK_EQUAL(addrman->size(), 0U);
|
||||
CAddrInfo addr_null = addrman->Select();
|
||||
auto addr_null = addrman->Select().first;
|
||||
BOOST_CHECK_EQUAL(addr_null.ToString(), "[::]:0");
|
||||
|
||||
// Test: Does Addrman::Add work as expected.
|
||||
CService addr1 = ResolveService("250.1.1.1", 8333);
|
||||
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
|
||||
BOOST_CHECK_EQUAL(addrman->size(), 1U);
|
||||
CAddrInfo addr_ret1 = addrman->Select();
|
||||
auto addr_ret1 = addrman->Select().first;
|
||||
BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
|
||||
|
||||
// Test: Does IP address deduplication work correctly.
|
||||
|
@ -199,7 +200,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
|
|||
BOOST_CHECK(addrman->size() >= 1);
|
||||
|
||||
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected
|
||||
addrman = std::make_unique<CAddrManTest>();
|
||||
addrman = std::make_unique<AddrManTest>();
|
||||
std::vector<CAddress> vAddr;
|
||||
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
|
||||
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
|
||||
|
@ -209,7 +210,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(addrman_ports)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
||||
|
@ -223,7 +224,7 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
|
|||
CService addr1_port = ResolveService("250.1.1.1", 8334);
|
||||
BOOST_CHECK(!addrman.Add({CAddress(addr1_port, NODE_NONE)}, source));
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
CAddrInfo addr_ret2 = addrman.Select();
|
||||
auto addr_ret2 = addrman.Select().first;
|
||||
BOOST_CHECK_EQUAL(addr_ret2.ToString(), "250.1.1.1:8333");
|
||||
|
||||
// Test: Add same IP but diff port to tried table, it doesn't get added.
|
||||
|
@ -231,14 +232,14 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
|
|||
addrman.Good(CAddress(addr1_port, NODE_NONE));
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
bool newOnly = true;
|
||||
CAddrInfo addr_ret3 = addrman.Select(newOnly);
|
||||
auto addr_ret3 = addrman.Select(newOnly).first;
|
||||
BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_select)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
||||
|
@ -248,16 +249,16 @@ BOOST_AUTO_TEST_CASE(addrman_select)
|
|||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
|
||||
bool newOnly = true;
|
||||
CAddrInfo addr_ret1 = addrman.Select(newOnly);
|
||||
auto addr_ret1 = addrman.Select(newOnly).first;
|
||||
BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
|
||||
|
||||
// Test: move addr to tried, select from new expected nothing returned.
|
||||
addrman.Good(CAddress(addr1, NODE_NONE));
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
CAddrInfo addr_ret2 = addrman.Select(newOnly);
|
||||
auto addr_ret2 = addrman.Select(newOnly).first;
|
||||
BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0");
|
||||
|
||||
CAddrInfo addr_ret3 = addrman.Select();
|
||||
auto addr_ret3 = addrman.Select().first;
|
||||
BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
|
@ -290,14 +291,14 @@ BOOST_AUTO_TEST_CASE(addrman_select)
|
|||
// Test: Select pulls from new and tried regardless of port number.
|
||||
std::set<uint16_t> ports;
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
ports.insert(addrman.Select().GetPort());
|
||||
ports.insert(addrman.Select().first.GetPort());
|
||||
}
|
||||
BOOST_CHECK_EQUAL(ports.size(), 3U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
||||
|
@ -326,7 +327,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
||||
|
@ -356,7 +357,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(addrman_find)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 0U);
|
||||
|
||||
|
@ -372,24 +373,24 @@ BOOST_AUTO_TEST_CASE(addrman_find)
|
|||
BOOST_CHECK(addrman.Add({addr3}, source1));
|
||||
|
||||
// Test: ensure Find returns an IP matching what we searched on.
|
||||
CAddrInfo* info1 = addrman.Find(addr1);
|
||||
AddrInfo* info1 = addrman.Find(addr1);
|
||||
BOOST_REQUIRE(info1);
|
||||
BOOST_CHECK_EQUAL(info1->ToString(), "250.1.2.1:8333");
|
||||
|
||||
// Test 18; Find does not discriminate by port number.
|
||||
CAddrInfo* info2 = addrman.Find(addr2);
|
||||
AddrInfo* info2 = addrman.Find(addr2);
|
||||
BOOST_REQUIRE(info2);
|
||||
BOOST_CHECK_EQUAL(info2->ToString(), info1->ToString());
|
||||
|
||||
// Test: Find returns another IP matching what we searched on.
|
||||
CAddrInfo* info3 = addrman.Find(addr3);
|
||||
AddrInfo* info3 = addrman.Find(addr3);
|
||||
BOOST_REQUIRE(info3);
|
||||
BOOST_CHECK_EQUAL(info3->ToString(), "251.255.2.1:8333");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_create)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 0U);
|
||||
|
||||
|
@ -397,19 +398,19 @@ BOOST_AUTO_TEST_CASE(addrman_create)
|
|||
CNetAddr source1 = ResolveIP("250.1.2.1");
|
||||
|
||||
int nId;
|
||||
CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId);
|
||||
AddrInfo* pinfo = addrman.Create(addr1, source1, &nId);
|
||||
|
||||
// Test: The result should be the same as the input addr.
|
||||
BOOST_CHECK_EQUAL(pinfo->ToString(), "250.1.2.1:8333");
|
||||
|
||||
CAddrInfo* info2 = addrman.Find(addr1);
|
||||
AddrInfo* info2 = addrman.Find(addr1);
|
||||
BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:8333");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_delete)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 0U);
|
||||
|
||||
|
@ -423,13 +424,13 @@ BOOST_AUTO_TEST_CASE(addrman_delete)
|
|||
BOOST_CHECK_EQUAL(addrman.size(), 1U);
|
||||
addrman.Delete(nId);
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 0U);
|
||||
CAddrInfo* info2 = addrman.Find(addr1);
|
||||
AddrInfo* info2 = addrman.Find(addr1);
|
||||
BOOST_CHECK(info2 == nullptr);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_getaddr)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
// Test: Sanity check, GetAddr should never return anything if addrman
|
||||
// is empty.
|
||||
|
@ -489,7 +490,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
|
||||
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
|
||||
|
@ -497,7 +498,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
|||
CNetAddr source1 = ResolveIP("250.1.1.1");
|
||||
|
||||
|
||||
CAddrInfo info1 = CAddrInfo(addr1, source1);
|
||||
AddrInfo info1 = AddrInfo(addr1, source1);
|
||||
|
||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
|
||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
|
||||
|
@ -512,14 +513,14 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
|||
|
||||
// Test: Two addresses with same IP but different ports can map to
|
||||
// different buckets because they have different keys.
|
||||
CAddrInfo info2 = CAddrInfo(addr2, source1);
|
||||
AddrInfo info2 = AddrInfo(addr2, source1);
|
||||
|
||||
BOOST_CHECK(info1.GetKey() != info2.GetKey());
|
||||
BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
|
||||
|
||||
std::set<int> buckets;
|
||||
for (int i = 0; i < 255; i++) {
|
||||
CAddrInfo infoi = CAddrInfo(
|
||||
AddrInfo infoi = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
|
||||
ResolveIP("250.1.1." + ToString(i)));
|
||||
int bucket = infoi.GetTriedBucket(nKey1, asmap);
|
||||
|
@ -531,7 +532,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
|||
|
||||
buckets.clear();
|
||||
for (int j = 0; j < 255; j++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
|
||||
ResolveIP("250." + ToString(j) + ".1.1"));
|
||||
int bucket = infoj.GetTriedBucket(nKey1, asmap);
|
||||
|
@ -544,14 +545,14 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
|
||||
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
|
||||
|
||||
CNetAddr source1 = ResolveIP("250.1.2.1");
|
||||
|
||||
CAddrInfo info1 = CAddrInfo(addr1, source1);
|
||||
AddrInfo info1 = AddrInfo(addr1, source1);
|
||||
|
||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
|
||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
|
||||
|
@ -567,13 +568,13 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
|
|||
BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
|
||||
|
||||
// Test: Ports should not affect bucket placement in the addr
|
||||
CAddrInfo info2 = CAddrInfo(addr2, source1);
|
||||
AddrInfo info2 = AddrInfo(addr2, source1);
|
||||
BOOST_CHECK(info1.GetKey() != info2.GetKey());
|
||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
|
||||
|
||||
std::set<int> buckets;
|
||||
for (int i = 0; i < 255; i++) {
|
||||
CAddrInfo infoi = CAddrInfo(
|
||||
AddrInfo infoi = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
|
||||
ResolveIP("250.1.1." + ToString(i)));
|
||||
int bucket = infoi.GetNewBucket(nKey1, asmap);
|
||||
|
@ -585,7 +586,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
|
|||
|
||||
buckets.clear();
|
||||
for (int j = 0; j < 4 * 255; j++) {
|
||||
CAddrInfo infoj = CAddrInfo(CAddress(
|
||||
AddrInfo infoj = AddrInfo(CAddress(
|
||||
ResolveService(
|
||||
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
|
||||
ResolveIP("251.4.1.1"));
|
||||
|
@ -598,7 +599,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
|
|||
|
||||
buckets.clear();
|
||||
for (int p = 0; p < 255; p++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
|
||||
ResolveIP("250." + ToString(p) + ".1.1"));
|
||||
int bucket = infoj.GetNewBucket(nKey1, asmap);
|
||||
|
@ -622,7 +623,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
|
|||
// 101.8.0.0/16 AS8
|
||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
|
||||
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
|
||||
|
@ -630,7 +631,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
|
|||
CNetAddr source1 = ResolveIP("250.1.1.1");
|
||||
|
||||
|
||||
CAddrInfo info1 = CAddrInfo(addr1, source1);
|
||||
AddrInfo info1 = AddrInfo(addr1, source1);
|
||||
|
||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
|
||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
|
||||
|
@ -645,14 +646,14 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
|
|||
|
||||
// Test: Two addresses with same IP but different ports can map to
|
||||
// different buckets because they have different keys.
|
||||
CAddrInfo info2 = CAddrInfo(addr2, source1);
|
||||
AddrInfo info2 = AddrInfo(addr2, source1);
|
||||
|
||||
BOOST_CHECK(info1.GetKey() != info2.GetKey());
|
||||
BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
|
||||
|
||||
std::set<int> buckets;
|
||||
for (int j = 0; j < 255; j++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
|
||||
ResolveIP("101." + ToString(j) + ".1.1"));
|
||||
int bucket = infoj.GetTriedBucket(nKey1, asmap);
|
||||
|
@ -664,7 +665,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
|
|||
|
||||
buckets.clear();
|
||||
for (int j = 0; j < 255; j++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
|
||||
ResolveIP("250." + ToString(j) + ".1.1"));
|
||||
int bucket = infoj.GetTriedBucket(nKey1, asmap);
|
||||
|
@ -677,14 +678,14 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
|
||||
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
|
||||
|
||||
CNetAddr source1 = ResolveIP("250.1.2.1");
|
||||
|
||||
CAddrInfo info1 = CAddrInfo(addr1, source1);
|
||||
AddrInfo info1 = AddrInfo(addr1, source1);
|
||||
|
||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
|
||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
|
||||
|
@ -700,13 +701,13 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
|
|||
BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
|
||||
|
||||
// Test: Ports should not affect bucket placement in the addr
|
||||
CAddrInfo info2 = CAddrInfo(addr2, source1);
|
||||
AddrInfo info2 = AddrInfo(addr2, source1);
|
||||
BOOST_CHECK(info1.GetKey() != info2.GetKey());
|
||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
|
||||
|
||||
std::set<int> buckets;
|
||||
for (int i = 0; i < 255; i++) {
|
||||
CAddrInfo infoi = CAddrInfo(
|
||||
AddrInfo infoi = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
|
||||
ResolveIP("250.1.1." + ToString(i)));
|
||||
int bucket = infoi.GetNewBucket(nKey1, asmap);
|
||||
|
@ -718,7 +719,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
|
|||
|
||||
buckets.clear();
|
||||
for (int j = 0; j < 4 * 255; j++) {
|
||||
CAddrInfo infoj = CAddrInfo(CAddress(
|
||||
AddrInfo infoj = AddrInfo(CAddress(
|
||||
ResolveService(
|
||||
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
|
||||
ResolveIP("251.4.1.1"));
|
||||
|
@ -731,7 +732,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
|
|||
|
||||
buckets.clear();
|
||||
for (int p = 0; p < 255; p++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
|
||||
ResolveIP("101." + ToString(p) + ".1.1"));
|
||||
int bucket = infoj.GetNewBucket(nKey1, asmap);
|
||||
|
@ -743,7 +744,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
|
|||
|
||||
buckets.clear();
|
||||
for (int p = 0; p < 255; p++) {
|
||||
CAddrInfo infoj = CAddrInfo(
|
||||
AddrInfo infoj = AddrInfo(
|
||||
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
|
||||
ResolveIP("250." + ToString(p) + ".1.1"));
|
||||
int bucket = infoj.GetNewBucket(nKey1, asmap);
|
||||
|
@ -759,9 +760,9 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
|
|||
{
|
||||
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
|
||||
|
||||
auto addrman_asmap1 = std::make_unique<CAddrManTest>(true, asmap1);
|
||||
auto addrman_asmap1_dup = std::make_unique<CAddrManTest>(true, asmap1);
|
||||
auto addrman_noasmap = std::make_unique<CAddrManTest>();
|
||||
auto addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
|
||||
auto addrman_asmap1_dup = std::make_unique<AddrManTest>(true, asmap1);
|
||||
auto addrman_noasmap = std::make_unique<AddrManTest>();
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
|
||||
|
@ -791,8 +792,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
|
|||
BOOST_CHECK(bucketAndEntry_asmap1.second != bucketAndEntry_noasmap.second);
|
||||
|
||||
// deserializing non-asmaped peers.dat to asmaped addrman
|
||||
addrman_asmap1 = std::make_unique<CAddrManTest>(true, asmap1);
|
||||
addrman_noasmap = std::make_unique<CAddrManTest>();
|
||||
addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
|
||||
addrman_noasmap = std::make_unique<AddrManTest>();
|
||||
addrman_noasmap->Add({addr}, default_source);
|
||||
stream << *addrman_noasmap;
|
||||
stream >> *addrman_asmap1;
|
||||
|
@ -803,8 +804,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
|
|||
BOOST_CHECK(bucketAndEntry_asmap1_deser.second == bucketAndEntry_asmap1_dup.second);
|
||||
|
||||
// used to map to different buckets, now maps to the same bucket.
|
||||
addrman_asmap1 = std::make_unique<CAddrManTest>(true, asmap1);
|
||||
addrman_noasmap = std::make_unique<CAddrManTest>();
|
||||
addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
|
||||
addrman_noasmap = std::make_unique<AddrManTest>();
|
||||
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
|
||||
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
|
||||
addrman_noasmap->Add({addr, addr2}, default_source);
|
||||
|
@ -824,7 +825,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
|
|||
{
|
||||
// Confirm that invalid addresses are ignored in unserialization.
|
||||
|
||||
auto addrman = std::make_unique<CAddrManTest>();
|
||||
auto addrman = std::make_unique<AddrManTest>();
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
|
||||
|
@ -856,19 +857,19 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
|
|||
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
|
||||
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
|
||||
|
||||
addrman = std::make_unique<CAddrManTest>();
|
||||
addrman = std::make_unique<AddrManTest>();
|
||||
stream >> *addrman;
|
||||
BOOST_CHECK_EQUAL(addrman->size(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
BOOST_CHECK(addrman.size() == 0);
|
||||
|
||||
// Empty addrman should return blank addrman info.
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
|
||||
// Add twenty two addresses.
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
@ -879,7 +880,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
|
|||
|
||||
// No collisions yet.
|
||||
BOOST_CHECK(addrman.size() == i);
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
// Ensure Good handles duplicates well.
|
||||
|
@ -888,14 +889,14 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
|
|||
addrman.Good(addr);
|
||||
|
||||
BOOST_CHECK(addrman.size() == 22);
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_noevict)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
// Add 35 addresses.
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
@ -906,7 +907,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
|
|||
|
||||
// No collision yet.
|
||||
BOOST_CHECK(addrman.size() == i);
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
// Collision between 36 and 19.
|
||||
|
@ -915,11 +916,11 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
|
|||
addrman.Good(addr36);
|
||||
|
||||
BOOST_CHECK(addrman.size() == 36);
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.19:0");
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.19:0");
|
||||
|
||||
// 36 should be discarded and 19 not evicted.
|
||||
addrman.ResolveCollisions();
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
|
||||
// Lets create two collisions.
|
||||
for (unsigned int i = 37; i < 59; i++) {
|
||||
|
@ -928,7 +929,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
|
|||
addrman.Good(addr);
|
||||
|
||||
BOOST_CHECK(addrman.size() == i);
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
// Cause a collision.
|
||||
|
@ -937,26 +938,26 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
|
|||
addrman.Good(addr59);
|
||||
BOOST_CHECK(addrman.size() == 59);
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.10:0");
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.10:0");
|
||||
|
||||
// Cause a second collision.
|
||||
BOOST_CHECK(!addrman.Add({CAddress(addr36, NODE_NONE)}, source));
|
||||
addrman.Good(addr36);
|
||||
BOOST_CHECK(addrman.size() == 59);
|
||||
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() != "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() != "[::]:0");
|
||||
addrman.ResolveCollisions();
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
|
||||
{
|
||||
CAddrManTest addrman;
|
||||
AddrManTest addrman;
|
||||
|
||||
BOOST_CHECK(addrman.size() == 0);
|
||||
|
||||
// Empty addrman should return blank addrman info.
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
|
||||
// Add 35 addresses
|
||||
CNetAddr source = ResolveIP("252.2.2.2");
|
||||
|
@ -967,7 +968,7 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
|
|||
|
||||
// No collision yet.
|
||||
BOOST_CHECK(addrman.size() == i);
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
// Collision between 36 and 19.
|
||||
|
@ -976,7 +977,7 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
|
|||
addrman.Good(addr);
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.size(), 36);
|
||||
CAddrInfo info = addrman.SelectTriedCollision();
|
||||
auto info = addrman.SelectTriedCollision().first;
|
||||
BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0");
|
||||
|
||||
// Ensure test of address fails, so that it is evicted.
|
||||
|
@ -984,28 +985,28 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
|
|||
|
||||
// Should swap 36 for 19.
|
||||
addrman.ResolveCollisions();
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
|
||||
// If 36 was swapped for 19, then this should cause no collisions.
|
||||
BOOST_CHECK(!addrman.Add({CAddress(addr, NODE_NONE)}, source));
|
||||
addrman.Good(addr);
|
||||
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
|
||||
// If we insert 19 it should collide with 36
|
||||
CService addr19 = ResolveService("250.1.1.19");
|
||||
BOOST_CHECK(!addrman.Add({CAddress(addr19, NODE_NONE)}, source));
|
||||
addrman.Good(addr19);
|
||||
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().ToString(), "250.1.1.36:0");
|
||||
BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.36:0");
|
||||
|
||||
addrman.ResolveCollisions();
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
|
||||
BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(load_addrman)
|
||||
{
|
||||
CAddrManUncorrupted addrmanUncorrupted;
|
||||
AddrManUncorrupted addrmanUncorrupted;
|
||||
|
||||
CService addr1, addr2, addr3;
|
||||
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
|
||||
|
@ -1024,7 +1025,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
|
|||
// Test that the de-serialization does not throw an exception.
|
||||
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
|
||||
bool exceptionThrown = false;
|
||||
CAddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
|
||||
BOOST_CHECK(addrman1.size() == 0);
|
||||
try {
|
||||
|
@ -1041,7 +1042,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
|
|||
// Test that ReadFromStream creates an addrman with the correct number of addrs.
|
||||
CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
|
||||
|
||||
CAddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
BOOST_CHECK(addrman2.size() == 0);
|
||||
ReadFromStream(addrman2, ssPeers2);
|
||||
BOOST_CHECK(addrman2.size() == 3);
|
||||
|
@ -1050,12 +1051,12 @@ BOOST_AUTO_TEST_CASE(load_addrman)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
|
||||
{
|
||||
CAddrManCorrupted addrmanCorrupted;
|
||||
AddrManCorrupted addrmanCorrupted;
|
||||
|
||||
// Test that the de-serialization of corrupted addrman throws an exception.
|
||||
CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
|
||||
bool exceptionThrown = false;
|
||||
CAddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
BOOST_CHECK(addrman1.size() == 0);
|
||||
try {
|
||||
unsigned char pchMsgTmp[4];
|
||||
|
@ -1071,7 +1072,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
|
|||
// Test that ReadFromStream fails if peers.dat is corrupt
|
||||
CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
|
||||
|
||||
CAddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
|
||||
BOOST_CHECK(addrman2.size() == 0);
|
||||
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <addrdb.h>
|
||||
#include <addrman.h>
|
||||
#include <addrman_impl.h>
|
||||
#include <chainparams.h>
|
||||
#include <merkleblock.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
|
@ -27,29 +28,29 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
|
|||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
|
||||
CAddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
try {
|
||||
ReadFromStream(addr_man, data_stream);
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
}
|
||||
|
||||
class CAddrManDeterministic : public CAddrMan
|
||||
class AddrManDeterministic : public AddrMan
|
||||
{
|
||||
public:
|
||||
FuzzedDataProvider& m_fuzzed_data_provider;
|
||||
|
||||
explicit CAddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
|
||||
: CAddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
|
||||
explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
|
||||
: AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
|
||||
, m_fuzzed_data_provider(fuzzed_data_provider)
|
||||
{
|
||||
WITH_LOCK(cs, insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
|
||||
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random address. Always returns a valid address.
|
||||
*/
|
||||
CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(cs)
|
||||
CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs)
|
||||
{
|
||||
CNetAddr addr;
|
||||
if (m_fuzzed_data_provider.remaining_bytes() > 1 && m_fuzzed_data_provider.ConsumeBool()) {
|
||||
|
@ -61,7 +62,7 @@ public:
|
|||
{4, ADDR_TORV3_SIZE},
|
||||
{5, ADDR_I2P_SIZE},
|
||||
{6, ADDR_CJDNS_SIZE}};
|
||||
uint8_t net = insecure_rand.randrange(5) + 1; // [1..5]
|
||||
uint8_t net = m_impl->insecure_rand.randrange(5) + 1; // [1..5]
|
||||
if (net == 3) {
|
||||
net = 6;
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ public:
|
|||
CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
|
||||
|
||||
s << net;
|
||||
s << insecure_rand.randbytes(net_len_map.at(net));
|
||||
s << m_impl->insecure_rand.randbytes(net_len_map.at(net));
|
||||
|
||||
s >> addr;
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ public:
|
|||
*/
|
||||
void Fill()
|
||||
{
|
||||
LOCK(cs);
|
||||
LOCK(m_impl->cs);
|
||||
|
||||
// Add some of the addresses directly to the "tried" table.
|
||||
|
||||
|
@ -102,20 +103,20 @@ public:
|
|||
// the latter is exhausted it just returns 0.
|
||||
for (size_t i = 0; i < num_sources; ++i) {
|
||||
const auto source = RandAddr();
|
||||
const size_t num_addresses = insecure_rand.randrange(500) + 1; // [1..500]
|
||||
const size_t num_addresses = m_impl->insecure_rand.randrange(500) + 1; // [1..500]
|
||||
|
||||
for (size_t j = 0; j < num_addresses; ++j) {
|
||||
const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK};
|
||||
const auto time_penalty = insecure_rand.randrange(100000001);
|
||||
Add_(addr, source, time_penalty);
|
||||
const auto time_penalty = m_impl->insecure_rand.randrange(100000001);
|
||||
m_impl->Add_(addr, source, time_penalty);
|
||||
|
||||
if (n > 0 && mapInfo.size() % n == 0) {
|
||||
Good_(addr, false, GetTime());
|
||||
if (n > 0 && m_impl->mapInfo.size() % n == 0) {
|
||||
m_impl->Good_(addr, false, GetTime());
|
||||
}
|
||||
|
||||
// Add 10% of the addresses from more than one source.
|
||||
if (insecure_rand.randrange(10) == 0 && prev_source.IsValid()) {
|
||||
Add_(addr, prev_source, time_penalty);
|
||||
if (m_impl->insecure_rand.randrange(10) == 0 && prev_source.IsValid()) {
|
||||
m_impl->Add_({addr}, prev_source, time_penalty);
|
||||
}
|
||||
}
|
||||
prev_source = source;
|
||||
|
@ -129,46 +130,46 @@ public:
|
|||
* - vvNew entries refer to the same addresses
|
||||
* - vvTried entries refer to the same addresses
|
||||
*/
|
||||
bool operator==(const CAddrManDeterministic& other)
|
||||
bool operator==(const AddrManDeterministic& other)
|
||||
{
|
||||
LOCK2(cs, other.cs);
|
||||
LOCK2(m_impl->cs, other.m_impl->cs);
|
||||
|
||||
if (mapInfo.size() != other.mapInfo.size() || nNew != other.nNew ||
|
||||
nTried != other.nTried) {
|
||||
if (m_impl->mapInfo.size() != other.m_impl->mapInfo.size() || m_impl->nNew != other.m_impl->nNew ||
|
||||
m_impl->nTried != other.m_impl->nTried) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that all values in `mapInfo` are equal to all values in `other.mapInfo`.
|
||||
// Keys may be different.
|
||||
|
||||
using CAddrInfoHasher = std::function<size_t(const CAddrInfo&)>;
|
||||
using CAddrInfoEq = std::function<bool(const CAddrInfo&, const CAddrInfo&)>;
|
||||
using AddrInfoHasher = std::function<size_t(const AddrInfo&)>;
|
||||
using AddrInfoEq = std::function<bool(const AddrInfo&, const AddrInfo&)>;
|
||||
|
||||
CNetAddrHash netaddr_hasher;
|
||||
|
||||
CAddrInfoHasher addrinfo_hasher = [&netaddr_hasher](const CAddrInfo& a) {
|
||||
AddrInfoHasher addrinfo_hasher = [&netaddr_hasher](const AddrInfo& a) {
|
||||
return netaddr_hasher(static_cast<CNetAddr>(a)) ^ netaddr_hasher(a.source) ^
|
||||
a.nLastSuccess ^ a.nAttempts ^ a.nRefCount ^ a.fInTried;
|
||||
};
|
||||
|
||||
CAddrInfoEq addrinfo_eq = [](const CAddrInfo& lhs, const CAddrInfo& rhs) {
|
||||
AddrInfoEq addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
|
||||
return static_cast<CNetAddr>(lhs) == static_cast<CNetAddr>(rhs) &&
|
||||
lhs.source == rhs.source && lhs.nLastSuccess == rhs.nLastSuccess &&
|
||||
lhs.nAttempts == rhs.nAttempts && lhs.nRefCount == rhs.nRefCount &&
|
||||
lhs.fInTried == rhs.fInTried;
|
||||
};
|
||||
|
||||
using Addresses = std::unordered_set<CAddrInfo, CAddrInfoHasher, CAddrInfoEq>;
|
||||
using Addresses = std::unordered_set<AddrInfo, AddrInfoHasher, AddrInfoEq>;
|
||||
|
||||
const size_t num_addresses{mapInfo.size()};
|
||||
const size_t num_addresses{m_impl->mapInfo.size()};
|
||||
|
||||
Addresses addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
|
||||
for (const auto& [id, addr] : mapInfo) {
|
||||
for (const auto& [id, addr] : m_impl->mapInfo) {
|
||||
addresses.insert(addr);
|
||||
}
|
||||
|
||||
Addresses other_addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
|
||||
for (const auto& [id, addr] : other.mapInfo) {
|
||||
for (const auto& [id, addr] : other.m_impl->mapInfo) {
|
||||
other_addresses.insert(addr);
|
||||
}
|
||||
|
||||
|
@ -176,14 +177,14 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(cs, other.cs) {
|
||||
auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) {
|
||||
if (id == -1 && other_id == -1) {
|
||||
return true;
|
||||
}
|
||||
if ((id == -1 && other_id != -1) || (id != -1 && other_id == -1)) {
|
||||
return false;
|
||||
}
|
||||
return mapInfo.at(id) == other.mapInfo.at(other_id);
|
||||
return m_impl->mapInfo.at(id) == other.m_impl->mapInfo.at(other_id);
|
||||
};
|
||||
|
||||
// Check that `vvNew` contains the same addresses as `other.vvNew`. Notice - `vvNew[i][j]`
|
||||
|
@ -191,7 +192,7 @@ public:
|
|||
// themselves may differ between `vvNew` and `other.vvNew`.
|
||||
for (size_t i = 0; i < ADDRMAN_NEW_BUCKET_COUNT; ++i) {
|
||||
for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
|
||||
if (!IdsReferToSameAddress(vvNew[i][j], other.vvNew[i][j])) {
|
||||
if (!IdsReferToSameAddress(m_impl->vvNew[i][j], other.m_impl->vvNew[i][j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +201,7 @@ public:
|
|||
// Same for `vvTried`.
|
||||
for (size_t i = 0; i < ADDRMAN_TRIED_BUCKET_COUNT; ++i) {
|
||||
for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
|
||||
if (!IdsReferToSameAddress(vvTried[i][j], other.vvTried[i][j])) {
|
||||
if (!IdsReferToSameAddress(m_impl->vvTried[i][j], other.m_impl->vvTried[i][j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +223,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
|
|||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
|
||||
auto addr_man_ptr = std::make_unique<CAddrManDeterministic>(asmap, fuzzed_data_provider);
|
||||
auto addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
|
||||
CDataStream ds(serialized_data, SER_DISK, INIT_PROTO_VERSION);
|
||||
|
@ -231,10 +232,10 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
|
|||
try {
|
||||
ds >> *addr_man_ptr;
|
||||
} catch (const std::ios_base::failure&) {
|
||||
addr_man_ptr = std::make_unique<CAddrManDeterministic>(asmap, fuzzed_data_provider);
|
||||
addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
|
||||
}
|
||||
}
|
||||
CAddrManDeterministic& addr_man = *addr_man_ptr;
|
||||
AddrManDeterministic& addr_man = *addr_man_ptr;
|
||||
while (fuzzed_data_provider.ConsumeBool()) {
|
||||
CallOneOf(
|
||||
fuzzed_data_provider,
|
||||
|
@ -283,7 +284,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
|
|||
}
|
||||
});
|
||||
}
|
||||
const CAddrMan& const_addr_man{addr_man};
|
||||
const AddrMan& const_addr_man{addr_man};
|
||||
(void)const_addr_man.GetAddr(
|
||||
/* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
|
||||
/* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
|
||||
|
@ -301,8 +302,8 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman)
|
|||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
|
||||
std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
|
||||
CAddrManDeterministic addr_man1{asmap, fuzzed_data_provider};
|
||||
CAddrManDeterministic addr_man2{asmap, fuzzed_data_provider};
|
||||
AddrManDeterministic addr_man1{asmap, fuzzed_data_provider};
|
||||
AddrManDeterministic addr_man2{asmap, fuzzed_data_provider};
|
||||
|
||||
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
|
|||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
CAddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
|
||||
CNetAddr random_netaddr;
|
||||
CNode random_node = ConsumeNode(fuzzed_data_provider);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <addrdb.h>
|
||||
#include <addrman.h>
|
||||
#include <addrman_impl.h>
|
||||
#include <blockencodings.h>
|
||||
#include <blockfilter.h>
|
||||
#include <chain.h>
|
||||
|
@ -104,7 +105,7 @@ FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
|
|||
DeserializeFromFuzzingInput(buffer, block_filter);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(addr_info_deserialize, {
|
||||
CAddrInfo addr_info;
|
||||
AddrInfo addr_info;
|
||||
DeserializeFromFuzzingInput(buffer, addr_info);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
|
||||
|
@ -188,7 +189,7 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
|
|||
BlockMerkleRoot(block, &mutated);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
|
||||
CAddrMan am(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
AddrMan am(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
DeserializeFromFuzzingInput(buffer, am);
|
||||
})
|
||||
FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
|
||||
|
|
|
@ -192,7 +192,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
|
|||
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
|
||||
}
|
||||
|
||||
m_node.addrman = std::make_unique<CAddrMan>(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
m_node.addrman = std::make_unique<AddrMan>(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
|
||||
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
||||
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
|
||||
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
|
||||
|
|
|
@ -109,7 +109,7 @@ class AddrmanTest(BitcoinTestFramework):
|
|||
self.stop_node(0)
|
||||
write_addrman(peers_dat, len_tried=-1)
|
||||
self.nodes[0].assert_start_raises_init_error(
|
||||
expected_msg=init_error("Corrupt CAddrMan serialization: nTried=-1, should be in \\[0, 16384\\]:.*"),
|
||||
expected_msg=init_error("Corrupt AddrMan serialization: nTried=-1, should be in \\[0, 16384\\]:.*"),
|
||||
match=ErrorMatch.FULL_REGEX,
|
||||
)
|
||||
|
||||
|
@ -117,7 +117,7 @@ class AddrmanTest(BitcoinTestFramework):
|
|||
self.stop_node(0)
|
||||
write_addrman(peers_dat, len_new=-1)
|
||||
self.nodes[0].assert_start_raises_init_error(
|
||||
expected_msg=init_error("Corrupt CAddrMan serialization: nNew=-1, should be in \\[0, 65536\\]:.*"),
|
||||
expected_msg=init_error("Corrupt AddrMan serialization: nNew=-1, should be in \\[0, 65536\\]:.*"),
|
||||
match=ErrorMatch.FULL_REGEX,
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue