55 std::vector<unsigned char> vchSourceGroupKey = src.
GetGroup(asmap);
72 if (
nTime > nNow + 10 * 60)
90 int64_t nSinceLastTry = std::max<int64_t>(nNow -
nLastTry, 0);
93 if (nSinceLastTry < 60 * 10)
97 fChance *= pow(0.66, std::min(
nAttempts, 8));
103 : insecure_rand{deterministic}
104 , nKey{deterministic ?
uint256{1} : insecure_rand.rand256()}
105 , m_consistency_check_ratio{consistency_check_ratio}
106 , m_asmap{std::move(asmap)}
108 for (
auto& bucket : vvNew) {
109 for (
auto& entry : bucket) {
113 for (
auto& bucket : vvTried) {
114 for (
auto& entry : bucket) {
125 template <
typename Stream>
176 static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;
185 std::unordered_map<int, int> mapUnkIds;
187 for (
const auto& entry : mapInfo) {
188 mapUnkIds[entry.first] = nIds;
189 const AddrInfo& info = entry.second;
197 for (
const auto& entry : mapInfo) {
198 const AddrInfo& info = entry.second;
208 if (vvNew[bucket][i] != -1)
213 if (vvNew[bucket][i] != -1) {
214 int nIndex = mapUnkIds[vvNew[bucket][i]];
228 template <
typename Stream>
236 s_ >> Using<CustomUintFormatter<1>>(
format);
238 int stream_version = s_.GetVersion();
239 if (
format >= Format::V3_BIP155) {
252 "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
253 "but the maximum supported by this version of %s is %u.",
262 if (
format >= Format::V1_DETERMINISTIC) {
263 nUBuckets ^= (1 << 30);
267 throw std::ios_base::failure(
268 strprintf(
"Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
274 throw std::ios_base::failure(
275 strprintf(
"Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
281 for (
int n = 0; n < nNew; n++) {
286 vRandom.push_back(n);
292 for (
int n = 0; n < nTried; n++) {
296 int nKBucketPos = info.GetBucketPosition(
nKey,
false, nKBucket);
298 && vvTried[nKBucket][nKBucketPos] == -1) {
299 info.nRandomPos = vRandom.size();
300 info.fInTried =
true;
301 vRandom.push_back(nIdCount);
302 mapInfo[nIdCount] = info;
303 mapAddr[info] = nIdCount;
304 vvTried[nKBucket][nKBucketPos] = nIdCount;
315 std::vector<std::pair<int, int>> bucket_entries;
317 for (
int bucket = 0; bucket < nUBuckets; ++bucket) {
320 for (
int n = 0; n < num_entries; ++n) {
323 if (entry_index >= 0 && entry_index < nNew) {
324 bucket_entries.emplace_back(bucket, entry_index);
332 uint256 supplied_asmap_checksum;
336 uint256 serialized_asmap_checksum;
337 if (
format >= Format::V2_ASMAP) {
338 s >> serialized_asmap_checksum;
341 serialized_asmap_checksum == supplied_asmap_checksum};
343 if (!restore_bucketing) {
347 for (
auto bucket_entry : bucket_entries) {
348 int bucket{bucket_entry.first};
349 const int entry_index{bucket_entry.second};
350 AddrInfo& info = mapInfo[entry_index];
361 if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
363 vvNew[bucket][bucket_position] = entry_index;
370 if (vvNew[bucket][bucket_position] == -1) {
371 vvNew[bucket][bucket_position] = entry_index;
379 for (
auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
380 if (it->second.fInTried ==
false && it->second.nRefCount == 0) {
381 const auto itCopy = it++;
388 if (nLost + nLostUnk > 0) {
389 LogPrint(
BCLog::ADDRMAN,
"addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
393 if (check_code != 0) {
395 "Corrupt data. Consistency check failed with code %s",
404 const auto it = mapAddr.find(addr);
405 if (it == mapAddr.end())
408 *pnId = (*it).second;
409 const auto it2 = mapInfo.find((*it).second);
410 if (it2 != mapInfo.end())
411 return &(*it2).second;
419 int nId = nIdCount++;
420 mapInfo[nId] =
AddrInfo(addr, addrSource);
422 mapInfo[nId].nRandomPos = vRandom.size();
423 vRandom.push_back(nId);
426 return &mapInfo[nId];
433 if (nRndPos1 == nRndPos2)
436 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
438 int nId1 = vRandom[nRndPos1];
439 int nId2 = vRandom[nRndPos2];
441 const auto it_1{mapInfo.find(nId1)};
442 const auto it_2{mapInfo.find(nId2)};
443 assert(it_1 != mapInfo.end());
444 assert(it_2 != mapInfo.end());
446 it_1->second.nRandomPos = nRndPos2;
447 it_2->second.nRandomPos = nRndPos1;
449 vRandom[nRndPos1] = nId2;
450 vRandom[nRndPos2] = nId1;
457 assert(mapInfo.count(nId) != 0);
474 if (vvNew[nUBucket][nUBucketPos] != -1) {
475 int nIdDelete = vvNew[nUBucket][nUBucketPos];
476 AddrInfo& infoDelete = mapInfo[nIdDelete];
479 vvNew[nUBucket][nUBucketPos] = -1;
496 if (vvNew[bucket][pos] == nId) {
497 vvNew[bucket][pos] = -1;
511 if (vvTried[nKBucket][nKBucketPos] != -1) {
513 int nIdEvict = vvTried[nKBucket][nKBucketPos];
514 assert(mapInfo.count(nIdEvict) == 1);
515 AddrInfo& infoOld = mapInfo[nIdEvict];
519 vvTried[nKBucket][nKBucketPos] = -1;
526 assert(vvNew[nUBucket][nUBucketPos] == -1);
530 vvNew[nUBucket][nUBucketPos] = nIdEvict;
533 infoOld.
ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
535 assert(vvTried[nKBucket][nKBucketPos] == -1);
537 vvTried[nKBucket][nKBucketPos] = nId;
560 int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
561 if (addr.
nTime && (!pinfo->
nTime || pinfo->
nTime < addr.
nTime - nUpdateInterval - nTimePenalty))
562 pinfo->
nTime = std::max((int64_t)0, addr.
nTime - nTimePenalty);
581 for (
int n = 0; n < pinfo->
nRefCount; n++)
583 if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
587 pinfo->
nTime = std::max((int64_t)0, (int64_t)pinfo->
nTime - nTimePenalty);
593 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
594 if (vvNew[nUBucket][nUBucketPos] != nId) {
596 AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
605 vvNew[nUBucket][nUBucketPos] = nId;
628 if (!pinfo)
return false;
651 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
656 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
658 colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() :
"",
674 for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
678 LogPrint(
BCLog::ADDRMAN,
"Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(),
source.ToString(), nTried, nNew);
707 if (vRandom.empty())
return {};
709 if (newOnly && nNew == 0)
return {};
713 (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
715 double fChanceFactor = 1.0;
730 const auto it_found{mapInfo.find(nId)};
731 assert(it_found != mapInfo.end());
732 const AddrInfo& info{it_found->second};
734 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
736 return {info, info.nLastTry};
739 fChanceFactor *= 1.2;
743 double fChanceFactor = 1.0;
758 const auto it_found{mapInfo.find(nId)};
759 assert(it_found != mapInfo.end());
760 const AddrInfo& info{it_found->second};
762 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
764 return {info, info.nLastTry};
767 fChanceFactor *= 1.2;
772 std::vector<CAddress>
AddrManImpl::GetAddr_(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
776 size_t nNodes = vRandom.size();
778 nNodes = max_pct * nNodes / 100;
780 if (max_addresses != 0) {
781 nNodes = std::min(nNodes, max_addresses);
786 std::vector<CAddress> addresses;
787 for (
unsigned int n = 0; n < vRandom.size(); n++) {
788 if (addresses.size() >= nNodes)
791 int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
793 const auto it{mapInfo.find(vRandom[n])};
794 assert(it != mapInfo.end());
799 if (network != std::nullopt && ai.GetNetClass() != network)
continue;
802 if (ai.IsTerrible(now))
continue;
804 addresses.push_back(ai);
823 int64_t nUpdateInterval = 20 * 60;
824 if (nTime - info.
nTime > nUpdateInterval)
851 bool erase_collision =
false;
854 if (mapInfo.count(id_new) != 1) {
855 erase_collision =
true;
857 AddrInfo& info_new = mapInfo[id_new];
863 erase_collision =
true;
864 }
else if (vvTried[tried_bucket][tried_bucket_pos] != -1) {
867 int id_old = vvTried[tried_bucket][tried_bucket_pos];
868 AddrInfo& info_old = mapInfo[id_old];
872 erase_collision =
true;
881 erase_collision =
true;
889 erase_collision =
true;
893 erase_collision =
true;
897 if (erase_collision) {
918 if (mapInfo.count(id_new) != 1) {
923 const AddrInfo& newInfo = mapInfo[id_new];
929 const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
930 return {info_old, info_old.
nLastTry};
939 if (!addr_info)
return std::nullopt;
966 LogPrintf(
"ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
978 std::unordered_set<int> setTried;
979 std::unordered_map<int, int> mapNew;
981 if (vRandom.size() != (
size_t)(nTried + nNew))
984 for (
const auto& entry : mapInfo) {
986 const AddrInfo& info = entry.second;
1000 const auto it{mapAddr.find(info)};
1001 if (it == mapAddr.end() || it->second != n) {
1012 if (setTried.size() != (
size_t)nTried)
1014 if (mapNew.size() != (
size_t)nNew)
1019 if (vvTried[n][i] != -1) {
1020 if (!setTried.count(vvTried[n][i]))
1022 const auto it{mapInfo.find(vvTried[n][i])};
1023 if (it == mapInfo.end() || it->second.GetTriedBucket(
nKey,
m_asmap) != n) {
1026 if (it->second.GetBucketPosition(
nKey,
false, n) != i) {
1029 setTried.erase(vvTried[n][i]);
1036 if (vvNew[n][i] != -1) {
1037 if (!mapNew.count(vvNew[n][i]))
1039 const auto it{mapInfo.find(vvNew[n][i])};
1040 if (it == mapInfo.end() || it->second.GetBucketPosition(
nKey,
true, n) != i) {
1043 if (--mapNew[vvNew[n][i]] == 0)
1044 mapNew.erase(vvNew[n][i]);
1049 if (setTried.size())
1062 return vRandom.size();
1069 auto ret =
Add_(vAddr,
source, nTimePenalty);
1078 auto ret =
Good_(addr,
true, nTime);
1087 Attempt_(addr, fCountFailure, nTime);
1112 const auto addrRet =
Select_(newOnly);
1117 std::vector<CAddress>
AddrManImpl::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
1121 const auto addresses =
GetAddr_(max_addresses, max_pct, network);
1157 : m_impl(
std::make_unique<
AddrManImpl>(
std::move(asmap), deterministic, consistency_check_ratio)) {}
1161 template <
typename Stream>
1164 m_impl->Serialize<Stream>(s_);
1167 template <
typename Stream>
1170 m_impl->Unserialize<Stream>(s_);
1194 return m_impl->Good(addr, nTime);
1199 m_impl->Attempt(addr, fCountFailure, nTime);
1204 m_impl->ResolveCollisions();
1209 return m_impl->SelectTriedCollision();
1214 return m_impl->Select(newOnly);
1217 std::vector<CAddress>
AddrMan::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
1219 return m_impl->GetAddr(max_addresses, max_pct, network);
1224 m_impl->Connected(addr, nTime);
1229 m_impl->SetServices(addr, nServices);
1234 return m_impl->GetAsmap();
1239 return m_impl->FindAddressEntry(addr);