6 #ifndef BITCOIN_ADDRMAN_H 7 #define BITCOIN_ADDRMAN_H 26 #include <unordered_map> 67 READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
126 #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8 130 #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10 133 #define ADDRMAN_BUCKET_SIZE_LOG2 6 136 #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8 139 #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64 142 #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8 145 #define ADDRMAN_HORIZON_DAYS 30 148 #define ADDRMAN_RETRIES 3 151 #define ADDRMAN_MAX_FAILURES 10 154 #define ADDRMAN_MIN_FAIL_DAYS 7 157 #define ADDRMAN_REPLACEMENT_HOURS 4 160 #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2) 161 #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2) 162 #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2) 165 #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10 193 static std::vector<bool>
DecodeAsmap(fs::path path);
232 template <
typename Stream>
246 static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
255 std::unordered_map<int, int> mapUnkIds;
257 for (
const auto& entry : mapInfo) {
258 mapUnkIds[entry.first] = nIds;
267 for (
const auto& entry : mapInfo) {
278 if (vvNew[bucket][i] != -1)
283 if (vvNew[bucket][i] != -1) {
284 int nIndex = mapUnkIds[vvNew[bucket][i]];
298 template <
typename Stream>
307 s_ >> Using<CustomUintFormatter<1>>(
format);
309 int stream_version = s_.GetVersion();
310 if (
format >= Format::V3_BIP155) {
323 "Unsupported format of addrman database: %u. It is compatible with formats >=%u, " 324 "but the maximum supported by this version of %s is %u.",
333 if (
format >= Format::V1_DETERMINISTIC) {
334 nUBuckets ^= (1 << 30);
338 throw std::ios_base::failure(
339 strprintf(
"Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
345 throw std::ios_base::failure(
346 strprintf(
"Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
352 for (
int n = 0; n < nNew; n++) {
357 vRandom.push_back(n);
363 for (
int n = 0; n < nTried; n++) {
367 int nKBucketPos = info.GetBucketPosition(
nKey,
false, nKBucket);
368 if (vvTried[nKBucket][nKBucketPos] == -1) {
369 info.nRandomPos = vRandom.size();
370 info.fInTried =
true;
371 vRandom.push_back(nIdCount);
372 mapInfo[nIdCount] = info;
373 mapAddr[info] = nIdCount;
374 vvTried[nKBucket][nKBucketPos] = nIdCount;
385 std::vector<std::pair<int, int>> bucket_entries;
387 for (
int bucket = 0; bucket < nUBuckets; ++bucket) {
390 for (
int n = 0; n < num_entries; ++n) {
393 if (entry_index >= 0 && entry_index < nNew) {
394 bucket_entries.emplace_back(bucket, entry_index);
402 uint256 supplied_asmap_checksum;
406 uint256 serialized_asmap_checksum;
407 if (
format >= Format::V2_ASMAP) {
408 s >> serialized_asmap_checksum;
411 serialized_asmap_checksum == supplied_asmap_checksum};
413 if (!restore_bucketing) {
417 for (
auto bucket_entry : bucket_entries) {
418 int bucket{bucket_entry.first};
419 const int entry_index{bucket_entry.second};
428 if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
430 vvNew[bucket][bucket_position] = entry_index;
437 if (vvNew[bucket][bucket_position] == -1) {
438 vvNew[bucket][bucket_position] = entry_index;
446 for (
auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
447 if (it->second.fInTried ==
false && it->second.nRefCount == 0) {
448 const auto itCopy = it++;
455 if (nLost + nLostUnk > 0) {
456 LogPrint(
BCLog::ADDRMAN,
"addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
468 std::vector<int>().swap(vRandom);
472 vvNew[bucket][entry] = -1;
477 vvTried[bucket][entry] = -1;
504 return vRandom.size();
529 for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
530 nAdd +=
Add_(*it,
source, nTimePenalty) ? 1 : 0;
544 Good_(addr, test_before_evict, nTime);
554 Attempt_(addr, fCountFailure, nTime);
599 std::vector<CAddress>
GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
604 std::vector<CAddress> vAddr;
605 GetAddr_(vAddr, max_addresses, max_pct, network);
666 std::unordered_map<int, CAddrInfo> mapInfo
GUARDED_BY(
cs);
669 std::unordered_map<CNetAddr, int, CNetAddrHash> mapAddr
GUARDED_BY(
cs);
735 const int err = Check_();
737 LogPrintf(
"ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
779 #endif // BITCOIN_ADDRMAN_H int nRefCount
reference count in new sets (memory only)
for files including asmap version
friend class CAddrManTest
ServiceFlags
nServices flags
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs)
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions...
#define LogPrint(category,...)
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct, std::optional< Network > network) EXCLUSIVE_LOCKS_REQUIRED(cs)
Return all or many randomly selected addresses, optionally by network.
CAddrInfo SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs)
Randomly select an address in tried that another address is attempting to evict.
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Mutex cs
A mutex to protect the inner data structures.
static constexpr uint8_t INCOMPATIBILITY_BASE
The initial value of a field that is incremented every time an incompatible format change is made (su...
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
find an entry, creating it if necessary.
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Update an entry's service bits.
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
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 Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as attempted to connect.
int nAttempts
connection attempts since last successful attempt
uint256 rand256() noexcept
generate a random uint256.
same as V2_ASMAP plus addresses are in BIP155 format
static const int64_t ADDRMAN_TEST_WINDOW
the maximum time we'll spend trying to resolve a tried table collision, in seconds ...
bool Add_(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Add an entry to the "new" table.
std::set< int > m_tried_collisions
Holds addrs inserted into tried table that collide with existing entries. Test-before-evict disciplin...
int nIdCount GUARDED_BY(cs)
last used nId
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs)
int nRandomPos
position in vRandom
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Return a random to-be-evicted tried table address.
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
#define READWRITEAS(type, obj)
bool fInTried
in tried set? (memory only)
Stochastical (IP) address manager.
static constexpr Format FILE_FORMAT
The maximum format this software knows it can unserialize.
static constexpr int ADDRV2_FORMAT
A flag that is ORed into the protocol version to designate that addresses should be serialized in (un...
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Return all or many randomly selected addresses, optionally by network.
Extended statistics about a CAddress.
CAddrInfo Select(bool newOnly=false) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Choose an address to connect to.
bool Add(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty=0) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Add a single address.
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
void MakeTried(CAddrInfo &info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Move an entry from the "new" table(s) to the "tried" table.
void Connected(const CService &addr, int64_t nTime=GetAdjustedTime()) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Outer function for Connected_()
void SetServices(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(!cs)
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs)
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions...
historic format, before commit e6b343d88
A combination of a network address (CNetAddr) and a (TCP) port.
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty=0) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Add multiple addresses.
int GetNewBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "new" bucket this entry belongs, using its default source.
A CService with information about it as peer.
void Check() EXCLUSIVE_LOCKS_REQUIRED(cs)
Consistency check.
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.
#define ADDRMAN_BUCKET_SIZE
Format
Serialization versions.
void Serialize(Stream &s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Serialized format.
bool IsTerrible(int64_t nNow=GetAdjustedTime()) const
Determine whether the statistics about this entry are bad enough so that it can just be deleted...
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...
#define EXCLUSIVE_LOCKS_REQUIRED(...)
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...
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
Calculate in which position of a bucket to store this entry.
SERIALIZE_METHODS(CAddrInfo, obj)
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
We have successfully connected to this peer.
void Unserialize(Stream &s_) EXCLUSIVE_LOCKS_REQUIRED(!cs)
void RemoveInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove invalid addresses.
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Return the number of (unique) addresses in all tables.
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource)
#define ADDRMAN_NEW_BUCKET_COUNT
int64_t GetAdjustedTime()
std::string ToStringIPPort() const
double GetChance(int64_t nNow=GetAdjustedTime()) const
Calculate the relative chance this entry should be given when selecting nodes to connect to...
int64_t nLastCountAttempt
last counted attempt (memory only)
static std::vector< bool > DecodeAsmap(fs::path path)
std::vector< bool > m_asmap
uint256 nKey
secret key to randomize bucket select with
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime()) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Mark an entry as connection attempted to.
void Good(const CService &addr, bool test_before_evict=true, int64_t nTime=GetAdjustedTime()) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Mark an entry as accessible.
int64_t nLastSuccess
last successful connection by us
int64_t nLastTry
last try whatsoever by us (memory only)
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
CNetAddr source
where knowledge about this address first came from
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.