24 std::vector<unsigned char> vchSourceGroupKey = src.
GetGroup(asmap);
44 if (
nTime > nNow + 10 * 60)
62 int64_t nSinceLastTry = std::max<int64_t>(nNow -
nLastTry, 0);
65 if (nSinceLastTry < 60 * 10)
69 fChance *= pow(0.66, std::min(
nAttempts, 8));
76 std::map<CNetAddr, int>::iterator
it = mapAddr.find(addr);
77 if (
it == mapAddr.end())
81 std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
82 if (it2 != mapInfo.end())
83 return &(*it2).second;
90 mapInfo[nId] =
CAddrInfo(addr, addrSource);
92 mapInfo[nId].nRandomPos = vRandom.size();
93 vRandom.push_back(nId);
101 if (nRndPos1 == nRndPos2)
104 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
106 int nId1 = vRandom[nRndPos1];
107 int nId2 = vRandom[nRndPos2];
109 assert(mapInfo.count(nId1) == 1);
110 assert(mapInfo.count(nId2) == 1);
112 mapInfo[nId1].nRandomPos = nRndPos2;
113 mapInfo[nId2].nRandomPos = nRndPos1;
115 vRandom[nRndPos1] = nId2;
116 vRandom[nRndPos2] = nId1;
121 assert(mapInfo.count(nId) != 0);
136 if (vvNew[nUBucket][nUBucketPos] != -1) {
137 int nIdDelete = vvNew[nUBucket][nUBucketPos];
138 CAddrInfo& infoDelete = mapInfo[nIdDelete];
141 vvNew[nUBucket][nUBucketPos] = -1;
153 if (vvNew[bucket][pos] == nId) {
154 vvNew[bucket][pos] = -1;
167 if (vvTried[nKBucket][nKBucketPos] != -1) {
169 int nIdEvict = vvTried[nKBucket][nKBucketPos];
170 assert(mapInfo.count(nIdEvict) == 1);
175 vvTried[nKBucket][nKBucketPos] = -1;
182 assert(vvNew[nUBucket][nUBucketPos] == -1);
186 vvNew[nUBucket][nUBucketPos] = nIdEvict;
189 assert(vvTried[nKBucket][nKBucketPos] == -1);
191 vvTried[nKBucket][nKBucketPos] = nId;
231 if (vvNew[nB][nBpos] == nId) {
247 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
249 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
250 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());
279 int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
280 if (addr.
nTime && (!pinfo->
nTime || pinfo->
nTime < addr.
nTime - nUpdateInterval - nTimePenalty))
281 pinfo->
nTime = std::max((int64_t)0, addr.
nTime - nTimePenalty);
300 for (
int n = 0; n < pinfo->
nRefCount; n++)
306 pinfo->
nTime = std::max((int64_t)0, (int64_t)pinfo->
nTime - nTimePenalty);
313 if (vvNew[nUBucket][nUBucketPos] != nId) {
314 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
316 CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
325 vvNew[nUBucket][nUBucketPos] = nId;
362 if (newOnly && nNew == 0)
369 double fChanceFactor = 1.0;
373 while (vvTried[nKBucket][nKBucketPos] == -1) {
377 int nId = vvTried[nKBucket][nKBucketPos];
378 assert(mapInfo.count(nId) == 1);
382 fChanceFactor *= 1.2;
386 double fChanceFactor = 1.0;
390 while (vvNew[nUBucket][nUBucketPos] == -1) {
394 int nId = vvNew[nUBucket][nUBucketPos];
395 assert(mapInfo.count(nId) == 1);
399 fChanceFactor *= 1.2;
405 int CAddrMan::Check_()
407 std::set<int> setTried;
408 std::map<int, int> mapNew;
410 if (vRandom.size() != (
size_t)(nTried + nNew))
413 for (
const auto& entry : mapInfo) {
429 if (mapAddr[info] != n)
439 if (setTried.size() != (
size_t)nTried)
441 if (mapNew.size() != (
size_t)nNew)
446 if (vvTried[n][i] != -1) {
447 if (!setTried.count(vvTried[n][i]))
449 if (mapInfo[vvTried[n][i]].GetTriedBucket(
nKey,
m_asmap) != n)
451 if (mapInfo[vvTried[n][i]].GetBucketPosition(
nKey,
false, n) != i)
453 setTried.erase(vvTried[n][i]);
460 if (vvNew[n][i] != -1) {
461 if (!mapNew.count(vvNew[n][i]))
463 if (mapInfo[vvNew[n][i]].GetBucketPosition(
nKey,
true, n) != i)
465 if (--mapNew[vvNew[n][i]] == 0)
466 mapNew.erase(vvNew[n][i]);
484 size_t nNodes = vRandom.size();
486 nNodes = max_pct * nNodes / 100;
488 if (max_addresses != 0) {
489 nNodes = std::min(nNodes, max_addresses);
493 for (
unsigned int n = 0; n < vRandom.size(); n++) {
494 if (vAddr.size() >= nNodes)
499 assert(mapInfo.count(vRandom[n]) == 1);
501 const CAddrInfo& ai = mapInfo[vRandom[n]];
522 int64_t nUpdateInterval = 20 * 60;
523 if (nTime - info.
nTime > nUpdateInterval)
550 bool erase_collision =
false;
553 if (mapInfo.count(id_new) != 1) {
554 erase_collision =
true;
562 erase_collision =
true;
563 }
else if (vvTried[tried_bucket][tried_bucket_pos] != -1) {
566 int id_old = vvTried[tried_bucket][tried_bucket_pos];
571 erase_collision =
true;
580 erase_collision =
true;
588 erase_collision =
true;
592 erase_collision =
true;
596 if (erase_collision) {
615 if (mapInfo.count(id_new) != 1) {
626 int id_old = vvTried[tried_bucket][tried_bucket_pos];
628 return mapInfo[id_old];
633 std::vector<bool> bits;
637 LogPrintf(
"Failed to open asmap file from disk\n");
640 fseek(filestr, 0, SEEK_END);
641 int length = ftell(filestr);
642 LogPrintf(
"Opened asmap file %s (%d bytes) from disk\n", path, length);
643 fseek(filestr, 0, SEEK_SET);
645 for (
int i = 0; i < length; ++i) {
647 for (
int bit = 0; bit < 8; ++bit) {
648 bits.push_back((cur_byte >> bit) & 1);
652 LogPrintf(
"Sanity check of asmap file %s failed\n", path);
#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
static const int64_t ADDRMAN_TEST_WINDOW
the maximum time we'll spend trying to resolve a tried table collision, in seconds
#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 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".
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs)
Select several addresses at once.
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.
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.
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).
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
static void LogPrintf(const char *fmt, const Args &... args)
#define LogPrint(category,...)
FILE * fopen(const fs::path &p, const char *mode)
std::deque< CInv >::iterator it
bool SanityCheckASMap(const std::vector< bool > &asmap)
ServiceFlags
nServices flags
int64_t GetAdjustedTime()