29 std::vector<unsigned char> vchSourceGroupKey = src.
GetGroup(asmap);
49 if (
nTime > nNow + 10 * 60)
67 int64_t nSinceLastTry = std::max<int64_t>(nNow -
nLastTry, 0);
70 if (nSinceLastTry < 60 * 10)
74 fChance *= pow(0.66, std::min(
nAttempts, 8));
81 std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
82 if (it == mapAddr.end())
86 std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
87 if (it2 != mapInfo.end())
88 return &(*it2).second;
95 mapInfo[nId] =
CAddrInfo(addr, addrSource);
97 mapInfo[nId].nRandomPos = vRandom.size();
98 vRandom.push_back(nId);
101 return &mapInfo[nId];
106 if (nRndPos1 == nRndPos2)
109 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
111 int nId1 = vRandom[nRndPos1];
112 int nId2 = vRandom[nRndPos2];
114 assert(mapInfo.count(nId1) == 1);
115 assert(mapInfo.count(nId2) == 1);
117 mapInfo[nId1].nRandomPos = nRndPos2;
118 mapInfo[nId2].nRandomPos = nRndPos1;
120 vRandom[nRndPos1] = nId2;
121 vRandom[nRndPos2] = nId1;
126 assert(mapInfo.count(nId) != 0);
141 if (vvNew[nUBucket][nUBucketPos] != -1) {
142 int nIdDelete = vvNew[nUBucket][nUBucketPos];
143 CAddrInfo& infoDelete = mapInfo[nIdDelete];
146 vvNew[nUBucket][nUBucketPos] = -1;
160 if (vvNew[bucket][pos] == nId) {
161 vvNew[bucket][pos] = -1;
175 if (vvTried[nKBucket][nKBucketPos] != -1) {
177 int nIdEvict = vvTried[nKBucket][nKBucketPos];
178 assert(mapInfo.count(nIdEvict) == 1);
183 vvTried[nKBucket][nKBucketPos] = -1;
190 assert(vvNew[nUBucket][nUBucketPos] == -1);
194 vvNew[nUBucket][nUBucketPos] = nIdEvict;
197 assert(vvTried[nKBucket][nKBucketPos] == -1);
199 vvTried[nKBucket][nKBucketPos] = nId;
243 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
245 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
246 LogPrint(
BCLog::ADDRMAN,
"Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() :
"", addr.
ToString(),
m_tried_collisions.size());
275 int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
276 if (addr.
nTime && (!pinfo->
nTime || pinfo->
nTime < addr.
nTime - nUpdateInterval - nTimePenalty))
277 pinfo->
nTime = std::max((int64_t)0, addr.
nTime - nTimePenalty);
296 for (
int n = 0; n < pinfo->
nRefCount; n++)
302 pinfo->
nTime = std::max((int64_t)0, (int64_t)pinfo->
nTime - nTimePenalty);
309 if (vvNew[nUBucket][nUBucketPos] != nId) {
310 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
312 CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
321 vvNew[nUBucket][nUBucketPos] = nId;
358 if (newOnly && nNew == 0)
364 double fChanceFactor = 1.0;
368 while (vvTried[nKBucket][nKBucketPos] == -1) {
372 int nId = vvTried[nKBucket][nKBucketPos];
373 assert(mapInfo.count(nId) == 1);
377 fChanceFactor *= 1.2;
381 double fChanceFactor = 1.0;
385 while (vvNew[nUBucket][nUBucketPos] == -1) {
389 int nId = vvNew[nUBucket][nUBucketPos];
390 assert(mapInfo.count(nId) == 1);
394 fChanceFactor *= 1.2;
400 int CAddrMan::Check_()
402 std::set<int> setTried;
403 std::map<int, int> mapNew;
405 if (vRandom.size() != nTried + nNew)
408 for (
const auto& entry : mapInfo) {
424 if (mapAddr[info] != n)
434 if (setTried.size() != nTried)
436 if (mapNew.size() != nNew)
441 if (vvTried[n][i] != -1) {
442 if (!setTried.count(vvTried[n][i]))
444 if (mapInfo[vvTried[n][i]].GetTriedBucket(
nKey,
m_asmap) != n)
446 if (mapInfo[vvTried[n][i]].GetBucketPosition(
nKey,
false, n) != i)
448 setTried.erase(vvTried[n][i]);
455 if (vvNew[n][i] != -1) {
456 if (!mapNew.count(vvNew[n][i]))
458 if (mapInfo[vvNew[n][i]].GetBucketPosition(
nKey,
true, n) != i)
460 if (--mapNew[vvNew[n][i]] == 0)
461 mapNew.erase(vvNew[n][i]);
479 size_t nNodes = vRandom.size();
481 nNodes = max_pct * nNodes / 100;
483 if (max_addresses != 0) {
484 nNodes = std::min(nNodes, max_addresses);
489 for (
unsigned int n = 0; n < vRandom.size(); n++) {
490 if (vAddr.size() >= nNodes)
495 assert(mapInfo.count(vRandom[n]) == 1);
497 const CAddrInfo& ai = mapInfo[vRandom[n]];
500 if (network != nullopt && ai.
GetNetClass() != network)
continue;
524 int64_t nUpdateInterval = 20 * 60;
525 if (nTime - info.
nTime > nUpdateInterval)
552 bool erase_collision =
false;
555 if (mapInfo.count(id_new) != 1) {
556 erase_collision =
true;
564 erase_collision =
true;
565 }
else if (vvTried[tried_bucket][tried_bucket_pos] != -1) {
568 int id_old = vvTried[tried_bucket][tried_bucket_pos];
573 erase_collision =
true;
582 erase_collision =
true;
590 erase_collision =
true;
594 erase_collision =
true;
598 if (erase_collision) {
617 if (mapInfo.count(id_new) != 1) {
628 int id_old = vvTried[tried_bucket][tried_bucket_pos];
630 return mapInfo[id_old];
635 std::vector<bool> bits;
639 LogPrintf(
"Failed to open asmap file from disk\n");
642 fseek(filestr, 0, SEEK_END);
643 int length = ftell(filestr);
644 LogPrintf(
"Opened asmap file %s (%d bytes) from disk\n", path, length);
645 fseek(filestr, 0, SEEK_SET);
647 for (
int i = 0; i < length; ++i) {
649 for (
int bit = 0; bit < 8; ++bit) {
650 bits.push_back((cur_byte >> bit) & 1);
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
over how many buckets entries with new addresses originating from a single group are spread
#define ADDRMAN_SET_TRIED_COLLISION_SIZE
the maximum number of tried addr collisions to store
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
#define ADDRMAN_MAX_FAILURES
how many successive failures are allowed ...
#define ADDRMAN_BUCKET_SIZE
#define ADDRMAN_NEW_BUCKET_COUNT
#define ADDRMAN_RETRIES
after how many failed attempts we give up on a new node
#define ADDRMAN_MIN_FAIL_DAYS
... in at least this many days
#define ADDRMAN_HORIZON_DAYS
how old addresses can maximally be
#define ADDRMAN_BUCKET_SIZE_LOG2
maximum allowed number of entries in buckets for new and tried addresses
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP
over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
#define ADDRMAN_REPLACEMENT_HOURS
how recent a successful connection should be before we allow an address to be evicted from tried
#define ADDRMAN_NEW_BUCKET_COUNT_LOG2
total number of buckets for new addresses
#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2
Stochastic address manager.
Extended statistics about a CAddress.
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
int nAttempts
connection attempts since last successful attempt
int64_t nLastSuccess
last successful connection by us
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
Calculate in which position of a bucket to store this entry.
int64_t nLastCountAttempt
last counted attempt (memory only)
int64_t nLastTry
last try whatsoever by us (memory only)
bool IsTerrible(int64_t nNow=GetAdjustedTime()) const
Determine whether the statistics about this entry are bad enough so that it can just be deleted.
int nRandomPos
position in vRandom
bool fInTried
in tried set? (memory only)
int GetNewBucket(const uint256 &nKey, const CNetAddr &src, const std::vector< bool > &asmap) const
Calculate in which "new" bucket this entry belongs, given a certain source.
int nRefCount
reference count in new sets (memory only)
double GetChance(int64_t nNow=GetAdjustedTime()) const
Calculate the relative chance this entry should be given when selecting nodes to connect to.
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
bool Add_(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Add an entry to the "new" table.
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
find an entry, creating it if necessary.
size_t size() const
Return the number of (unique) addresses in all tables.
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Return a random to-be-evicted tried table address.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
std::set< int > m_tried_collisions
Holds addrs inserted into tried table that collide with existing entries. Test-before-evict disciplin...
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs)
Clear a position in a "new" table. This is the only place where entries are actually deleted.
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct, Optional< Network > network) EXCLUSIVE_LOCKS_REQUIRED(cs)
Return all or many randomly selected addresses, optionally by network.
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as attempted to connect.
std::vector< bool > m_asmap
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry "good", possibly moving it from "new" to "tried".
static std::vector< bool > DecodeAsmap(fs::path path)
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Update an entry's service bits.
uint256 nKey
secret key to randomize bucket select with
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as currently-connected-to.
CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs)
Select an address to connect to, if newOnly is set to true, only the new table is selected from.
void MakeTried(CAddrInfo &info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Move an entry from the "new" table(s) to the "tried" table.
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs)
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
A CService with information about it as peer.
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
uint32_t nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
Non-refcounted RAII wrapper for FILE*.
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
A writer stream (for serialization) that computes a 256-bit hash.
Network GetNetClass() const
std::string ToStringIP() const
std::vector< unsigned char > GetGroup(const std::vector< bool > &asmap) const
Get the canonical identifier of our network group.
uint32_t GetMappedAS(const std::vector< bool > &asmap) const
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToString() const
std::vector< unsigned char > GetKey() const
bool randbool() noexcept
Generate a random boolean.
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
#define LogPrint(category,...)
FILE * fopen(const fs::path &p, const char *mode)
boost::optional< T > Optional
Substitute for C++17 std::optional.
ServiceFlags
nServices flags
int64_t GetAdjustedTime()