55 std::vector<unsigned char> vchSourceGroupKey = netgroupman.
GetGroup(src);
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_netgroupman{netgroupman}
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]];
224 template <
typename Stream>
232 s_ >> Using<CustomUintFormatter<1>>(
format);
234 int stream_version = s_.GetVersion();
235 if (
format >= Format::V3_BIP155) {
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);
294 for (
int n = 0; n < nTried; n++) {
298 int nKBucketPos = info.GetBucketPosition(
nKey,
false, nKBucket);
300 && vvTried[nKBucket][nKBucketPos] == -1) {
301 info.nRandomPos = vRandom.size();
302 info.fInTried =
true;
303 vRandom.push_back(nIdCount);
304 mapInfo[nIdCount] = info;
305 mapAddr[info] = nIdCount;
306 vvTried[nKBucket][nKBucketPos] = nIdCount;
317 std::vector<std::pair<int, int>> bucket_entries;
319 for (
int bucket = 0; bucket < nUBuckets; ++bucket) {
322 for (
int n = 0; n < num_entries; ++n) {
325 if (entry_index >= 0 && entry_index < nNew) {
326 bucket_entries.emplace_back(bucket, entry_index);
335 uint256 serialized_asmap_checksum;
336 if (
format >= Format::V2_ASMAP) {
337 s >> serialized_asmap_checksum;
340 serialized_asmap_checksum == supplied_asmap_checksum};
342 if (!restore_bucketing) {
346 for (
auto bucket_entry : bucket_entries) {
347 int bucket{bucket_entry.first};
348 const int entry_index{bucket_entry.second};
349 AddrInfo& info = mapInfo[entry_index];
360 if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
362 vvNew[bucket][bucket_position] = entry_index;
369 if (vvNew[bucket][bucket_position] == -1) {
370 vvNew[bucket][bucket_position] = entry_index;
378 for (
auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
379 if (it->second.fInTried ==
false && it->second.nRefCount == 0) {
380 const auto itCopy = it++;
387 if (nLost + nLostUnk > 0) {
388 LogPrint(
BCLog::ADDRMAN,
"addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
392 if (check_code != 0) {
394 "Corrupt data. Consistency check failed with code %s",
403 const auto it = mapAddr.find(addr);
404 if (it == mapAddr.end())
407 *pnId = (*it).second;
408 const auto it2 = mapInfo.find((*it).second);
409 if (it2 != mapInfo.end())
410 return &(*it2).second;
418 int nId = nIdCount++;
419 mapInfo[nId] =
AddrInfo(addr, addrSource);
421 mapInfo[nId].nRandomPos = vRandom.size();
422 vRandom.push_back(nId);
425 return &mapInfo[nId];
432 if (nRndPos1 == nRndPos2)
435 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
437 int nId1 = vRandom[nRndPos1];
438 int nId2 = vRandom[nRndPos2];
440 const auto it_1{mapInfo.find(nId1)};
441 const auto it_2{mapInfo.find(nId2)};
442 assert(it_1 != mapInfo.end());
443 assert(it_2 != mapInfo.end());
445 it_1->second.nRandomPos = nRndPos2;
446 it_2->second.nRandomPos = nRndPos1;
448 vRandom[nRndPos1] = nId2;
449 vRandom[nRndPos2] = nId1;
456 assert(mapInfo.count(nId) != 0);
473 if (vvNew[nUBucket][nUBucketPos] != -1) {
474 int nIdDelete = vvNew[nUBucket][nUBucketPos];
475 AddrInfo& infoDelete = mapInfo[nIdDelete];
478 vvNew[nUBucket][nUBucketPos] = -1;
495 if (vvNew[bucket][pos] == nId) {
496 vvNew[bucket][pos] = -1;
510 if (vvTried[nKBucket][nKBucketPos] != -1) {
512 int nIdEvict = vvTried[nKBucket][nKBucketPos];
513 assert(mapInfo.count(nIdEvict) == 1);
514 AddrInfo& infoOld = mapInfo[nIdEvict];
518 vvTried[nKBucket][nKBucketPos] = -1;
525 assert(vvNew[nUBucket][nUBucketPos] == -1);
529 vvNew[nUBucket][nUBucketPos] = nIdEvict;
532 infoOld.
ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
534 assert(vvTried[nKBucket][nKBucketPos] == -1);
536 vvTried[nKBucket][nKBucketPos] = nId;
559 int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
560 if (addr.
nTime && (!pinfo->
nTime || pinfo->
nTime < addr.
nTime - nUpdateInterval - nTimePenalty))
561 pinfo->
nTime = std::max((int64_t)0, addr.
nTime - nTimePenalty);
580 for (
int n = 0; n < pinfo->
nRefCount; n++)
582 if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
586 pinfo->
nTime = std::max((int64_t)0, (int64_t)pinfo->
nTime - nTimePenalty);
592 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
593 if (vvNew[nUBucket][nUBucketPos] != nId) {
595 AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
604 vvNew[nUBucket][nUBucketPos] = nId;
627 if (!pinfo)
return false;
650 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
655 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
657 colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() :
"",
673 for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
677 LogPrint(
BCLog::ADDRMAN,
"Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(),
source.ToString(), nTried, nNew);
706 if (vRandom.empty())
return {};
708 if (newOnly && nNew == 0)
return {};
712 (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
714 double fChanceFactor = 1.0;
729 const auto it_found{mapInfo.find(nId)};
730 assert(it_found != mapInfo.end());
731 const AddrInfo& info{it_found->second};
733 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
735 return {info, info.nLastTry};
738 fChanceFactor *= 1.2;
742 double fChanceFactor = 1.0;
757 const auto it_found{mapInfo.find(nId)};
758 assert(it_found != mapInfo.end());
759 const AddrInfo& info{it_found->second};
761 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
763 return {info, info.nLastTry};
766 fChanceFactor *= 1.2;
771 std::vector<CAddress>
AddrManImpl::GetAddr_(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
775 size_t nNodes = vRandom.size();
777 nNodes = max_pct * nNodes / 100;
779 if (max_addresses != 0) {
780 nNodes = std::min(nNodes, max_addresses);
785 std::vector<CAddress> addresses;
786 for (
unsigned int n = 0; n < vRandom.size(); n++) {
787 if (addresses.size() >= nNodes)
790 int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
792 const auto it{mapInfo.find(vRandom[n])};
793 assert(it != mapInfo.end());
798 if (network != std::nullopt && ai.GetNetClass() != network)
continue;
801 if (ai.IsTerrible(now))
continue;
803 addresses.push_back(ai);
822 int64_t nUpdateInterval = 20 * 60;
823 if (nTime - info.
nTime > nUpdateInterval)
850 bool erase_collision =
false;
853 if (mapInfo.count(id_new) != 1) {
854 erase_collision =
true;
856 AddrInfo& info_new = mapInfo[id_new];
862 erase_collision =
true;
863 }
else if (vvTried[tried_bucket][tried_bucket_pos] != -1) {
866 int id_old = vvTried[tried_bucket][tried_bucket_pos];
867 AddrInfo& info_old = mapInfo[id_old];
871 erase_collision =
true;
880 erase_collision =
true;
888 erase_collision =
true;
892 erase_collision =
true;
896 if (erase_collision) {
917 if (mapInfo.count(id_new) != 1) {
922 const AddrInfo& newInfo = mapInfo[id_new];
928 const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
929 return {info_old, info_old.
nLastTry};
938 if (!addr_info)
return std::nullopt;
965 LogPrintf(
"ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
977 std::unordered_set<int> setTried;
978 std::unordered_map<int, int> mapNew;
980 if (vRandom.size() != (
size_t)(nTried + nNew))
983 for (
const auto& entry : mapInfo) {
985 const AddrInfo& info = entry.second;
999 const auto it{mapAddr.find(info)};
1000 if (it == mapAddr.end() || it->second != n) {
1011 if (setTried.size() != (
size_t)nTried)
1013 if (mapNew.size() != (
size_t)nNew)
1018 if (vvTried[n][i] != -1) {
1019 if (!setTried.count(vvTried[n][i]))
1021 const auto it{mapInfo.find(vvTried[n][i])};
1022 if (it == mapInfo.end() || it->second.GetTriedBucket(
nKey,
m_netgroupman) != n) {
1025 if (it->second.GetBucketPosition(
nKey,
false, n) != i) {
1028 setTried.erase(vvTried[n][i]);
1035 if (vvNew[n][i] != -1) {
1036 if (!mapNew.count(vvNew[n][i]))
1038 const auto it{mapInfo.find(vvNew[n][i])};
1039 if (it == mapInfo.end() || it->second.GetBucketPosition(
nKey,
true, n) != i) {
1042 if (--mapNew[vvNew[n][i]] == 0)
1043 mapNew.erase(vvNew[n][i]);
1048 if (setTried.size())
1061 return vRandom.size();
1068 auto ret =
Add_(vAddr,
source, nTimePenalty);
1077 auto ret =
Good_(addr,
true, nTime);
1086 Attempt_(addr, fCountFailure, nTime);
1111 const auto addrRet =
Select_(newOnly);
1116 std::vector<CAddress>
AddrManImpl::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
1120 const auto addresses =
GetAddr_(max_addresses, max_pct, network);
1151 : m_impl(
std::make_unique<
AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {}
1155 template <
typename Stream>
1158 m_impl->Serialize<Stream>(s_);
1161 template <
typename Stream>
1164 m_impl->Unserialize<Stream>(s_);
1188 return m_impl->Good(addr, nTime);
1193 m_impl->Attempt(addr, fCountFailure, nTime);
1198 m_impl->ResolveCollisions();
1203 return m_impl->SelectTriedCollision();
1208 return m_impl->Select(newOnly);
1211 std::vector<CAddress>
AddrMan::GetAddr(
size_t max_addresses,
size_t max_pct, std::optional<Network> network)
const
1213 return m_impl->GetAddr(max_addresses, max_pct, network);
1218 m_impl->Connected(addr, nTime);
1223 m_impl->SetServices(addr, nServices);
1228 return m_impl->FindAddressEntry(addr);