6 #include <bitcoin-build-config.h> 57 std::vector<unsigned char> vchSourceGroupKey = netgroupman.
GetGroup(src);
58 uint64_t hash1 = (
HashWriter{} << nKey << netgroupman.
GetGroup(*
this) << vchSourceGroupKey).GetCheapHash();
65 uint64_t hash1 = (
HashWriter{} << nKey << (fNew ? uint8_t{
'N'} : uint8_t{
'K'}) << bucket <<
GetKey()).GetCheapHash();
75 if (
nTime > now + 10min) {
104 fChance *= pow(0.66, std::min(
nAttempts, 8));
110 : insecure_rand{deterministic}
111 , nKey{deterministic ?
uint256{1} : insecure_rand.rand256()}
112 , m_consistency_check_ratio{consistency_check_ratio}
113 , m_netgroupman{netgroupman}
115 for (
auto& bucket : vvNew) {
116 for (
auto& entry : bucket) {
120 for (
auto& bucket : vvTried) {
121 for (
auto& entry : bucket) {
132 template <
typename Stream>
182 static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;
191 std::unordered_map<nid_type, int> mapUnkIds;
193 for (
const auto& entry : mapInfo) {
194 mapUnkIds[entry.first] = nIds;
195 const AddrInfo& info = entry.second;
203 for (
const auto& entry : mapInfo) {
204 const AddrInfo& info = entry.second;
214 if (vvNew[bucket][i] != -1)
219 if (vvNew[bucket][i] != -1) {
220 int nIndex = mapUnkIds[vvNew[bucket][i]];
230 template <
typename Stream>
238 s_ >> Using<CustomUintFormatter<1>>(
format);
247 "Corrupted addrman database: The compat value (%u) " 248 "is lower than the expected minimum value %u.",
254 "Unsupported format of addrman database: %u. It is compatible with formats >=%u, " 255 "but the maximum supported by this version of %s is %u.",
264 if (
format >= Format::V1_DETERMINISTIC) {
265 nUBuckets ^= (1 << 30);
269 throw std::ios_base::failure(
270 strprintf(
"Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
276 throw std::ios_base::failure(
277 strprintf(
"Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
283 for (
int n = 0; n < nNew; n++) {
288 vRandom.push_back(n);
289 m_network_counts[info.GetNetwork()].n_new++;
295 for (
int n = 0; n < nTried; n++) {
299 int nKBucketPos = info.GetBucketPosition(
nKey,
false, nKBucket);
301 && vvTried[nKBucket][nKBucketPos] == -1) {
302 info.nRandomPos = vRandom.size();
303 info.fInTried =
true;
304 vRandom.push_back(nIdCount);
305 mapInfo[nIdCount] = info;
306 mapAddr[info] = nIdCount;
307 vvTried[nKBucket][nKBucketPos] = nIdCount;
309 m_network_counts[info.GetNetwork()].n_tried++;
319 std::vector<std::pair<int, int>> bucket_entries;
321 for (
int bucket = 0; bucket < nUBuckets; ++bucket) {
324 for (
int n = 0; n < num_entries; ++n) {
327 if (entry_index >= 0 && entry_index < nNew) {
328 bucket_entries.emplace_back(bucket, entry_index);
337 uint256 serialized_asmap_checksum;
338 if (
format >= Format::V2_ASMAP) {
339 s >> serialized_asmap_checksum;
342 serialized_asmap_checksum == supplied_asmap_checksum};
344 if (!restore_bucketing) {
348 for (
auto bucket_entry : bucket_entries) {
349 int bucket{bucket_entry.first};
350 const int entry_index{bucket_entry.second};
351 AddrInfo& info = mapInfo[entry_index];
362 if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
364 vvNew[bucket][bucket_position] = entry_index;
371 if (vvNew[bucket][bucket_position] == -1) {
372 vvNew[bucket][bucket_position] = entry_index;
380 for (
auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
381 if (it->second.fInTried ==
false && it->second.nRefCount == 0) {
382 const auto itCopy = it++;
389 if (nLost + nLostUnk > 0) {
390 LogDebug(
BCLog::ADDRMAN,
"addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
394 if (check_code != 0) {
396 "Corrupt data. Consistency check failed with code %s",
405 const auto it = mapAddr.find(addr);
406 if (it == mapAddr.end())
409 *pnId = (*it).second;
410 const auto it2 = mapInfo.find((*it).second);
411 if (it2 != mapInfo.end())
412 return &(*it2).second;
421 mapInfo[nId] =
AddrInfo(addr, addrSource);
423 mapInfo[nId].nRandomPos = vRandom.size();
424 vRandom.push_back(nId);
429 return &mapInfo[nId];
436 if (nRndPos1 == nRndPos2)
439 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
444 const auto it_1{mapInfo.find(nId1)};
445 const auto it_2{mapInfo.find(nId2)};
446 assert(it_1 != mapInfo.end());
447 assert(it_2 != mapInfo.end());
449 it_1->second.nRandomPos = nRndPos2;
450 it_2->second.nRandomPos = nRndPos1;
452 vRandom[nRndPos1] = nId2;
453 vRandom[nRndPos2] = nId1;
460 assert(mapInfo.count(nId) != 0);
463 assert(info.nRefCount == 0);
465 SwapRandom(info.nRandomPos, vRandom.size() - 1);
466 m_network_counts[info.GetNetwork()].n_new--;
478 if (vvNew[nUBucket][nUBucketPos] != -1) {
479 nid_type nIdDelete = vvNew[nUBucket][nUBucketPos];
480 AddrInfo& infoDelete = mapInfo[nIdDelete];
483 vvNew[nUBucket][nUBucketPos] = -1;
500 if (vvNew[bucket][pos] == nId) {
501 vvNew[bucket][pos] = -1;
516 if (vvTried[nKBucket][nKBucketPos] != -1) {
518 nid_type nIdEvict = vvTried[nKBucket][nKBucketPos];
519 assert(mapInfo.count(nIdEvict) == 1);
520 AddrInfo& infoOld = mapInfo[nIdEvict];
524 vvTried[nKBucket][nKBucketPos] = -1;
526 m_network_counts[infoOld.GetNetwork()].n_tried--;
530 int nUBucketPos = infoOld.GetBucketPosition(
nKey,
true, nUBucket);
532 assert(vvNew[nUBucket][nUBucketPos] == -1);
535 infoOld.nRefCount = 1;
536 vvNew[nUBucket][nUBucketPos] = nIdEvict;
538 m_network_counts[infoOld.GetNetwork()].n_new++;
540 infoOld.ToStringAddrPort(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
542 assert(vvTried[nKBucket][nKBucketPos] == -1);
544 vvTried[nKBucket][nKBucketPos] = nId;
547 m_network_counts[info.
GetNetwork()].n_tried++;
568 const auto update_interval{currently_online ? 1h : 24h};
569 if (pinfo->
nTime < addr.
nTime - update_interval - time_penalty) {
591 const int nFactor{1 << pinfo->
nRefCount};
592 if (insecure_rand.randrange(nFactor) != 0)
return false;
601 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
602 if (vvNew[nUBucket][nUBucketPos] != nId) {
604 AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
613 vvNew[nUBucket][nUBucketPos] = nId;
637 if (!pinfo)
return false;
660 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
665 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
667 colliding_entry != mapInfo.end() ? colliding_entry->second.ToStringAddrPort() :
"",
684 for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
688 LogDebug(
BCLog::ADDRMAN,
"Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(),
source.ToStringAddr(), nTried, nNew);
713 std::pair<CAddress, NodeSeconds>
AddrManImpl::Select_(
bool new_only,
const std::unordered_set<Network>& networks)
const 717 if (vRandom.empty())
return {};
719 size_t new_count = nNew;
720 size_t tried_count = nTried;
722 if (!networks.empty()) {
725 for (
auto& network : networks) {
726 auto it = m_network_counts.find(network);
727 if (it == m_network_counts.end()) {
730 auto counts = it->second;
731 new_count += counts.n_new;
732 tried_count += counts.n_tried;
736 if (new_only && new_count == 0)
return {};
737 if (new_count + tried_count == 0)
return {};
742 if (new_only || tried_count == 0) {
743 search_tried =
false;
744 }
else if (new_count == 0) {
747 search_tried = insecure_rand.randbool();
753 double chance_factor = 1.0;
756 int bucket = insecure_rand.randrange(bucket_count);
765 node_id =
GetEntry(search_tried, bucket, position);
767 if (!networks.empty()) {
768 const auto it{mapInfo.find(node_id)};
769 if (
Assume(it != mapInfo.end()) && networks.contains(it->second.GetNetwork()))
break;
780 const auto it_found{mapInfo.find(node_id)};
781 assert(it_found != mapInfo.end());
782 const AddrInfo& info{it_found->second};
785 if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {
786 LogDebug(
BCLog::ADDRMAN,
"Selected %s from %s\n", info.ToStringAddrPort(), search_tried ?
"tried" :
"new");
787 return {info, info.m_last_try};
791 chance_factor *= 1.2;
801 return vvTried[bucket][position];
805 return vvNew[bucket][position];
812 std::vector<CAddress>
AddrManImpl::GetAddr_(
size_t max_addresses,
size_t max_pct, std::optional<Network> network,
const bool filtered)
const 817 size_t nNodes = vRandom.size();
819 max_pct = std::min(max_pct,
size_t{100});
820 nNodes = max_pct * nNodes / 100;
822 if (max_addresses != 0) {
823 nNodes = std::min(nNodes, max_addresses);
827 const auto now{Now<NodeSeconds>()};
828 std::vector<CAddress> addresses;
829 addresses.reserve(nNodes);
830 for (
unsigned int n = 0; n < vRandom.size(); n++) {
831 if (addresses.size() >= nNodes)
834 int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
836 const auto it{mapInfo.find(vRandom[n])};
837 assert(it != mapInfo.end());
842 if (network != std::nullopt && ai.GetNetClass() != network)
continue;
845 if (ai.IsTerrible(now) && filtered)
continue;
847 addresses.push_back(ai);
858 std::vector<std::pair<AddrInfo, AddressPosition>> infos;
859 for (
int bucket = 0; bucket < bucket_count; ++bucket) {
869 infos.emplace_back(info, location);
890 const auto update_interval{20min};
891 if (time - info.
nTime > update_interval) {
919 bool erase_collision =
false;
922 if (mapInfo.count(id_new) != 1) {
923 erase_collision =
true;
925 AddrInfo& info_new = mapInfo[id_new];
931 erase_collision =
true;
932 }
else if (vvTried[tried_bucket][tried_bucket_pos] != -1) {
935 nid_type id_old = vvTried[tried_bucket][tried_bucket_pos];
936 AddrInfo& info_old = mapInfo[id_old];
938 const auto current_time{Now<NodeSeconds>()};
942 erase_collision =
true;
950 Good_(info_new,
false, current_time);
951 erase_collision =
true;
958 Good_(info_new,
false, current_time);
959 erase_collision =
true;
962 Good_(info_new,
false, Now<NodeSeconds>());
963 erase_collision =
true;
967 if (erase_collision) {
988 if (mapInfo.count(id_new) != 1) {
993 const AddrInfo& newInfo = mapInfo[id_new];
999 const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
1009 if (!addr_info)
return std::nullopt;
1030 if (!net.has_value()) {
1031 if (in_new.has_value()) {
1032 return *in_new ? nNew : nTried;
1034 return vRandom.size();
1037 if (
auto it = m_network_counts.find(*net); it != m_network_counts.end()) {
1038 auto net_count = it->second;
1039 if (in_new.has_value()) {
1040 return *in_new ? net_count.n_new : net_count.n_tried;
1042 return net_count.n_new + net_count.n_tried;
1058 LogPrintf(
"ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
1070 std::unordered_set<nid_type> setTried;
1071 std::unordered_map<nid_type, int> mapNew;
1072 std::unordered_map<Network, NewTriedCount> local_counts;
1074 if (vRandom.size() != (size_t)(nTried + nNew))
1077 for (
const auto& entry : mapInfo) {
1079 const AddrInfo& info = entry.second;
1081 if (!TicksSinceEpoch<std::chrono::seconds>(info.
m_last_success)) {
1096 const auto it{mapAddr.find(info)};
1097 if (it == mapAddr.end() || it->second != n) {
1110 if (setTried.size() != (size_t)nTried)
1112 if (mapNew.size() != (size_t)nNew)
1117 if (vvTried[n][i] != -1) {
1118 if (!setTried.count(vvTried[n][i]))
1120 const auto it{mapInfo.find(vvTried[n][i])};
1121 if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_netgroupman) != n) {
1124 if (it->second.GetBucketPosition(nKey,
false, n) != i) {
1127 setTried.erase(vvTried[n][i]);
1134 if (vvNew[n][i] != -1) {
1135 if (!mapNew.count(vvNew[n][i]))
1137 const auto it{mapInfo.find(vvNew[n][i])};
1138 if (it == mapInfo.end() || it->second.GetBucketPosition(nKey,
true, n) != i) {
1141 if (--mapNew[vvNew[n][i]] == 0)
1142 mapNew.erase(vvNew[n][i]);
1147 if (setTried.size())
1156 if (m_network_counts.size() < local_counts.size()) {
1159 for (
const auto& [net,
count] : m_network_counts) {
1160 if (local_counts[net].n_new !=
count.n_new || local_counts[net].n_tried !=
count.n_tried) {
1190 auto ret =
Good_(addr,
true, time);
1199 Attempt_(addr, fCountFailure, time);
1220 std::pair<CAddress, NodeSeconds>
AddrManImpl::Select(
bool new_only,
const std::unordered_set<Network>& networks)
const 1224 auto addrRet =
Select_(new_only, networks);
1229 std::vector<CAddress>
AddrManImpl::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network,
const bool filtered)
const 1233 auto addresses =
GetAddr_(max_addresses, max_pct, network, filtered);
1273 : m_impl(
std::make_unique<
AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {}
1277 template <
typename Stream>
1280 m_impl->Serialize<Stream>(s_);
1283 template <
typename Stream>
1286 m_impl->Unserialize<Stream>(s_);
1297 size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new)
const 1299 return m_impl->Size(net, in_new);
1309 return m_impl->Good(addr, time);
1314 m_impl->Attempt(addr, fCountFailure, time);
1319 m_impl->ResolveCollisions();
1324 return m_impl->SelectTriedCollision();
1327 std::pair<CAddress, NodeSeconds>
AddrMan::Select(
bool new_only,
const std::unordered_set<Network>& networks)
const 1329 return m_impl->Select(new_only, networks);
1332 std::vector<CAddress>
AddrMan::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network,
const bool filtered)
const 1334 return m_impl->GetAddr(max_addresses, max_pct, network, filtered);
1339 return m_impl->GetEntries(use_tried);
1344 m_impl->Connected(addr, time);
1349 m_impl->SetServices(addr, nServices);
1354 return m_impl->FindAddressEntry(addr);
Wrapper that overrides the GetParams() function of a stream.
const std::unique_ptr< AddrManImpl > m_impl
void Connected(const CService &addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(!cs)
std::vector< unsigned char > GetGroup(const CNetAddr &address) const
Get the canonical identifier of the network group for address.
size_t Size(std::optional< Network > net=std::nullopt, std::optional< bool > in_new=std::nullopt) const
Return size information about addrman.
static constexpr uint8_t INCOMPATIBILITY_BASE
The initial value of a field that is incremented every time an incompatible format change is made (su...
void Connected_(const CService &addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs)
ServiceFlags
nServices flags
const NetGroupManager & m_netgroupman
Reference to the netgroup manager.
uint256 GetAsmapChecksum() const
Get a checksum identifying the asmap being used.
bool Good_(const CService &addr, bool test_before_evict, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs)
void Unserialize(Stream &s_)
static constexpr int ADDRMAN_BUCKET_SIZE
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
std::optional< AddressPosition > FindAddressEntry(const CAddress &addr)
Test-only function Find the address record in AddrMan and return information about its position...
std::vector< std::pair< AddrInfo, AddressPosition > > GetEntries_(bool from_tried) const EXCLUSIVE_LOCKS_REQUIRED(cs)
int64_t nid_type
User-defined type for the internally used nIds This used to be int, making it feasible for attackers ...
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network, const bool filtered=true) const
Return all or many randomly selected addresses, optionally by network.
void Attempt_(const CService &addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs)
static constexpr int32_t ADDRMAN_MAX_FAILURES
How many successive failures are allowed ...
bool Add_(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
size_t Size_(std::optional< Network > net, std::optional< bool > in_new) const EXCLUSIVE_LOCKS_REQUIRED(cs)
static constexpr SerParams V1_DISK
int nRandomPos
position in vRandom
int CheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Perform consistency check, regardless of m_consistency_check_ratio.
size_t Size(std::optional< Network > net, std::optional< bool > in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE
The maximum number of tried addr collisions to store.
int GetBucketPosition(const uint256 &nKey, bool fNew, int bucket) const
Calculate in which position of a bucket to store this entry.
Non-refcounted RAII wrapper for FILE*.
enum Network GetNetwork() const
void ResolveCollisions()
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions...
std::string ToStringAddrPort() const
uint256 nKey
secret key to randomize bucket select with
std::pair< CAddress, NodeSeconds > SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs)
static constexpr int32_t ADDRMAN_RETRIES
After how many failed attempts we give up on a new node.
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
static constexpr SerParams V2_DISK
int nAttempts
connection attempts since last successful attempt
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs)
std::pair< CAddress, NodeSeconds > SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs)
NodeSeconds m_last_try
last try whatsoever by us (memory only)
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty=0s)
Attempt to add one or more addresses to addrman's new table.
int nRefCount
reference count in new sets (memory only)
static constexpr auto ADDRMAN_MIN_FAIL
...
Double ended buffer combining vector and stream-like interfaces.
void Attempt(const CService &addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(!cs)
A combination of a network address (CNetAddr) and a (TCP) port.
A writer stream (for serialization) that computes a 256-bit hash.
Extended statistics about a CAddress.
void Attempt(const CService &addr, bool fCountFailure, NodeSeconds time=Now< NodeSeconds >())
Mark an entry as connection attempted to.
std::pair< CAddress, NodeSeconds > Select_(bool new_only, const std::unordered_set< Network > &networks) const EXCLUSIVE_LOCKS_REQUIRED(cs)
NodeSeconds m_last_count_attempt
last counted attempt (memory only)
A CService with information about it as peer.
void Connected(const CService &addr, NodeSeconds time=Now< NodeSeconds >())
We have successfully connected to this peer.
std::vector< unsigned char > GetKey() const
nid_type GetEntry(bool use_tried, size_t bucket, size_t position) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Helper to generalize looking up an addrman entry from either table.
void Serialize(Stream &s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
uint32_t GetMappedAS(const CNetAddr &address) const
Get the autonomous system on the BGP path to address.
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(!cs)
NodeSeconds nTime
Always included in serialization. The behavior is unspecified if the value is not representable as ui...
int GetNewBucket(const uint256 &nKey, const CNetAddr &src, const NetGroupManager &netgroupman) const
Calculate in which "new" bucket this entry belongs, given a certain source.
void Serialize(Stream &s_) const
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 Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Consistency check, taking into account m_consistency_check_ratio.
#define Assume(val)
Assume is the identity function.
static constexpr Format FILE_FORMAT
The maximum format this software knows it can unserialize.
Format
Serialization versions.
bool IsTerrible(NodeSeconds now=Now< NodeSeconds >()) const
Determine whether the statistics about this entry are bad enough so that it can just be deleted...
std::vector< CAddress > GetAddr_(size_t max_addresses, size_t max_pct, std::optional< Network > network, const bool filtered=true) const EXCLUSIVE_LOCKS_REQUIRED(cs)
void Unserialize(Stream &s_) EXCLUSIVE_LOCKS_REQUIRED(!cs)
static time_point now() noexcept
Return current system time or mocked time, if set.
std::pair< CAddress, NodeSeconds > SelectTriedCollision()
Randomly select an address in the tried table that another address is attempting to evict...
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
bool Good(const CService &addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(!cs)
AddrManImpl(const NetGroupManager &netgroupman, bool deterministic, int32_t consistency_check_ratio)
double GetChance(NodeSeconds now=Now< NodeSeconds >()) const
Calculate the relative chance this entry should be given when selecting nodes to connect to...
std::vector< std::pair< AddrInfo, AddressPosition > > GetEntries(bool from_tried) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
#define LogDebug(category,...)
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP
Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread...
void SetServices(const CService &addr, ServiceFlags nServices)
Update an entry's service bits.
std::pair< CAddress, NodeSeconds > Select(bool new_only=false, const std::unordered_set< Network > &networks={}) const
Choose an address to connect to.
void Delete(nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
std::pair< CAddress, NodeSeconds > Select(bool new_only, const std::unordered_set< Network > &networks) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
AddrInfo * Find(const CService &addr, nid_type *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
Writes data to an underlying source stream, while hashing the written data.
bool fInTried
in tried set? (memory only)
std::optional< AddressPosition > FindAddressEntry_(const CAddress &addr) EXCLUSIVE_LOCKS_REQUIRED(cs)
void MakeTried(AddrInfo &info, nid_type nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Move an entry from the "new" table(s) to the "tried" table.
Reads data from an underlying stream, while hashing the read data.
bool AddSingle(const CAddress &addr, const CNetAddr &source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Attempt to add a single address to addrman's new table.
static constexpr auto ADDRMAN_REPLACEMENT
How recent a successful connection should be before we allow an address to be evicted from tried...
AddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, nid_type *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom...
Location information for an address in AddrMan.
Mutex cs
A mutex to protect the inner data structures.
std::set< nid_type > m_tried_collisions
Holds addrs inserted into tried table that collide with existing entries. Test-before-evict disciplin...
static constexpr auto ADDRMAN_TEST_WINDOW
The maximum time we'll spend trying to resolve a tried table collision.
const int32_t m_consistency_check_ratio
Perform consistency checks every m_consistency_check_ratio operations (if non-zero).
bool Good(const CService &addr, NodeSeconds time=Now< NodeSeconds >())
Mark an address record as accessible and attempt to move it to addrman's tried table.
int GetTriedBucket(const uint256 &nKey, const NetGroupManager &netgroupman) const
Calculate in which "tried" bucket this entry belongs.
std::optional< AddressPosition > FindAddressEntry(const CAddress &addr) EXCLUSIVE_LOCKS_REQUIRED(!cs)
void SetServices(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(!cs)
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network, const bool filtered=true) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
NodeSeconds m_last_success
last successful connection by us
static constexpr auto ADDRMAN_HORIZON
How old addresses can maximally be.
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS
Maximum number of times an address can occur in the new table.
std::vector< std::pair< AddrInfo, AddressPosition > > GetEntries(bool from_tried) const
Returns an information-location pair for all addresses in the selected addrman table.
#define LOG_TIME_MILLIS_WITH_CATEGORY_MSG_ONCE(end_msg, log_category)
AddrMan(const NetGroupManager &netgroupman, bool deterministic, int32_t consistency_check_ratio)
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
Over how many buckets entries with new addresses originating from a single group are spread...