Bitcoin Core 22.99.0
P2P Digital Currency
addrman.cpp
Go to the documentation of this file.
1// Copyright (c) 2012 Pieter Wuille
2// Copyright (c) 2012-2020 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <addrman.h>
7#include <addrman_impl.h>
8
9#include <hash.h>
10#include <netaddress.h>
11#include <protocol.h>
12#include <random.h>
13#include <serialize.h>
14#include <streams.h>
15#include <timedata.h>
16#include <tinyformat.h>
17#include <uint256.h>
18#include <util/check.h>
19
20#include <cmath>
21#include <optional>
22
24static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8};
26static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
28static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
30static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
32static constexpr int32_t ADDRMAN_RETRIES{3};
34static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
36static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7};
38static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4};
40static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
42static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
43
44int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const
45{
46 uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
47 uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
48 return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
49}
50
51int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
52{
53 std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
54 uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
55 uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
56 return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
57}
58
59int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
60{
61 uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
62 return hash1 % ADDRMAN_BUCKET_SIZE;
63}
64
65bool AddrInfo::IsTerrible(int64_t nNow) const
66{
67 if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
68 return false;
69
70 if (nTime > nNow + 10 * 60) // came in a flying DeLorean
71 return true;
72
73 if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
74 return true;
75
76 if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
77 return true;
78
79 if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
80 return true;
81
82 return false;
83}
84
85double AddrInfo::GetChance(int64_t nNow) const
86{
87 double fChance = 1.0;
88 int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
89
90 // deprioritize very recent attempts away
91 if (nSinceLastTry < 60 * 10)
92 fChance *= 0.01;
93
94 // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
95 fChance *= pow(0.66, std::min(nAttempts, 8));
96
97 return fChance;
98}
99
100AddrManImpl::AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio)
101 : insecure_rand{deterministic}
102 , nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
103 , m_consistency_check_ratio{consistency_check_ratio}
104 , m_asmap{std::move(asmap)}
105{
106 for (auto& bucket : vvNew) {
107 for (auto& entry : bucket) {
108 entry = -1;
109 }
110 }
111 for (auto& bucket : vvTried) {
112 for (auto& entry : bucket) {
113 entry = -1;
114 }
115 }
116}
117
119{
120 nKey.SetNull();
121}
122
123template <typename Stream>
124void AddrManImpl::Serialize(Stream& s_) const
125{
126 LOCK(cs);
127
166 // Always serialize in the latest version (FILE_FORMAT).
167
168 OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
169
170 s << static_cast<uint8_t>(FILE_FORMAT);
171
172 // Increment `lowest_compatible` iff a newly introduced format is incompatible with
173 // the previous one.
174 static constexpr uint8_t lowest_compatible = Format::V4_MULTIPORT;
175 s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
176
177 s << nKey;
178 s << nNew;
179 s << nTried;
180
181 int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
182 s << nUBuckets;
183 std::unordered_map<int, int> mapUnkIds;
184 int nIds = 0;
185 for (const auto& entry : mapInfo) {
186 mapUnkIds[entry.first] = nIds;
187 const AddrInfo& info = entry.second;
188 if (info.nRefCount) {
189 assert(nIds != nNew); // this means nNew was wrong, oh ow
190 s << info;
191 nIds++;
192 }
193 }
194 nIds = 0;
195 for (const auto& entry : mapInfo) {
196 const AddrInfo& info = entry.second;
197 if (info.fInTried) {
198 assert(nIds != nTried); // this means nTried was wrong, oh ow
199 s << info;
200 nIds++;
201 }
202 }
203 for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
204 int nSize = 0;
205 for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
206 if (vvNew[bucket][i] != -1)
207 nSize++;
208 }
209 s << nSize;
210 for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
211 if (vvNew[bucket][i] != -1) {
212 int nIndex = mapUnkIds[vvNew[bucket][i]];
213 s << nIndex;
214 }
215 }
216 }
217 // Store asmap checksum after bucket entries so that it
218 // can be ignored by older clients for backward compatibility.
219 uint256 asmap_checksum;
220 if (m_asmap.size() != 0) {
221 asmap_checksum = SerializeHash(m_asmap);
222 }
223 s << asmap_checksum;
224}
225
226template <typename Stream>
228{
229 LOCK(cs);
230
231 assert(vRandom.empty());
232
234 s_ >> Using<CustomUintFormatter<1>>(format);
235
236 int stream_version = s_.GetVersion();
237 if (format >= Format::V3_BIP155) {
238 // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
239 // unserialize methods know that an address in addrv2 format is coming.
240 stream_version |= ADDRV2_FORMAT;
241 }
242
243 OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
244
245 uint8_t compat;
246 s >> compat;
247 const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
248 if (lowest_compatible > FILE_FORMAT) {
249 throw std::ios_base::failure(strprintf(
250 "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
251 "but the maximum supported by this version of %s is %u.",
252 uint8_t{format}, uint8_t{lowest_compatible}, PACKAGE_NAME, uint8_t{FILE_FORMAT}));
253 }
254
255 s >> nKey;
256 s >> nNew;
257 s >> nTried;
258 int nUBuckets = 0;
259 s >> nUBuckets;
260 if (format >= Format::V1_DETERMINISTIC) {
261 nUBuckets ^= (1 << 30);
262 }
263
264 if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
265 throw std::ios_base::failure(
266 strprintf("Corrupt AddrMan serialization: nNew=%d, should be in [0, %d]",
267 nNew,
269 }
270
271 if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
272 throw std::ios_base::failure(
273 strprintf("Corrupt AddrMan serialization: nTried=%d, should be in [0, %d]",
274 nTried,
276 }
277
278 // Deserialize entries from the new table.
279 for (int n = 0; n < nNew; n++) {
280 AddrInfo& info = mapInfo[n];
281 s >> info;
282 mapAddr[info] = n;
283 info.nRandomPos = vRandom.size();
284 vRandom.push_back(n);
285 }
286 nIdCount = nNew;
287
288 // Deserialize entries from the tried table.
289 int nLost = 0;
290 for (int n = 0; n < nTried; n++) {
291 AddrInfo info;
292 s >> info;
293 int nKBucket = info.GetTriedBucket(nKey, m_asmap);
294 int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
295 if (info.IsValid()
296 && vvTried[nKBucket][nKBucketPos] == -1) {
297 info.nRandomPos = vRandom.size();
298 info.fInTried = true;
299 vRandom.push_back(nIdCount);
300 mapInfo[nIdCount] = info;
301 mapAddr[info] = nIdCount;
302 vvTried[nKBucket][nKBucketPos] = nIdCount;
303 nIdCount++;
304 } else {
305 nLost++;
306 }
307 }
308 nTried -= nLost;
309
310 // Store positions in the new table buckets to apply later (if possible).
311 // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
312 // so we store all bucket-entry_index pairs to iterate through later.
313 std::vector<std::pair<int, int>> bucket_entries;
314
315 for (int bucket = 0; bucket < nUBuckets; ++bucket) {
316 int num_entries{0};
317 s >> num_entries;
318 for (int n = 0; n < num_entries; ++n) {
319 int entry_index{0};
320 s >> entry_index;
321 if (entry_index >= 0 && entry_index < nNew) {
322 bucket_entries.emplace_back(bucket, entry_index);
323 }
324 }
325 }
326
327 // If the bucket count and asmap checksum haven't changed, then attempt
328 // to restore the entries to the buckets/positions they were in before
329 // serialization.
330 uint256 supplied_asmap_checksum;
331 if (m_asmap.size() != 0) {
332 supplied_asmap_checksum = SerializeHash(m_asmap);
333 }
334 uint256 serialized_asmap_checksum;
335 if (format >= Format::V2_ASMAP) {
336 s >> serialized_asmap_checksum;
337 }
338 const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
339 serialized_asmap_checksum == supplied_asmap_checksum};
340
341 if (!restore_bucketing) {
342 LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
343 }
344
345 for (auto bucket_entry : bucket_entries) {
346 int bucket{bucket_entry.first};
347 const int entry_index{bucket_entry.second};
348 AddrInfo& info = mapInfo[entry_index];
349
350 // Don't store the entry in the new bucket if it's not a valid address for our addrman
351 if (!info.IsValid()) continue;
352
353 // The entry shouldn't appear in more than
354 // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
355 // this bucket_entry.
356 if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
357
358 int bucket_position = info.GetBucketPosition(nKey, true, bucket);
359 if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
360 // Bucketing has not changed, using existing bucket positions for the new table
361 vvNew[bucket][bucket_position] = entry_index;
362 ++info.nRefCount;
363 } else {
364 // In case the new table data cannot be used (bucket count wrong or new asmap),
365 // try to give them a reference based on their primary source address.
366 bucket = info.GetNewBucket(nKey, m_asmap);
367 bucket_position = info.GetBucketPosition(nKey, true, bucket);
368 if (vvNew[bucket][bucket_position] == -1) {
369 vvNew[bucket][bucket_position] = entry_index;
370 ++info.nRefCount;
371 }
372 }
373 }
374
375 // Prune new entries with refcount 0 (as a result of collisions or invalid address).
376 int nLostUnk = 0;
377 for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
378 if (it->second.fInTried == false && it->second.nRefCount == 0) {
379 const auto itCopy = it++;
380 Delete(itCopy->first);
381 ++nLostUnk;
382 } else {
383 ++it;
384 }
385 }
386 if (nLost + nLostUnk > 0) {
387 LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
388 }
389
390 const int check_code{ForceCheckAddrman()};
391 if (check_code != 0) {
392 throw std::ios_base::failure(strprintf(
393 "Corrupt data. Consistency check failed with code %s",
394 check_code));
395 }
396}
397
398AddrInfo* AddrManImpl::Find(const CService& addr, int* pnId)
399{
401
402 const auto it = mapAddr.find(addr);
403 if (it == mapAddr.end())
404 return nullptr;
405 if (pnId)
406 *pnId = (*it).second;
407 const auto it2 = mapInfo.find((*it).second);
408 if (it2 != mapInfo.end())
409 return &(*it2).second;
410 return nullptr;
411}
412
413AddrInfo* AddrManImpl::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
414{
416
417 int nId = nIdCount++;
418 mapInfo[nId] = AddrInfo(addr, addrSource);
419 mapAddr[addr] = nId;
420 mapInfo[nId].nRandomPos = vRandom.size();
421 vRandom.push_back(nId);
422 if (pnId)
423 *pnId = nId;
424 return &mapInfo[nId];
425}
426
427void AddrManImpl::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) const
428{
430
431 if (nRndPos1 == nRndPos2)
432 return;
433
434 assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
435
436 int nId1 = vRandom[nRndPos1];
437 int nId2 = vRandom[nRndPos2];
438
439 const auto it_1{mapInfo.find(nId1)};
440 const auto it_2{mapInfo.find(nId2)};
441 assert(it_1 != mapInfo.end());
442 assert(it_2 != mapInfo.end());
443
444 it_1->second.nRandomPos = nRndPos2;
445 it_2->second.nRandomPos = nRndPos1;
446
447 vRandom[nRndPos1] = nId2;
448 vRandom[nRndPos2] = nId1;
449}
450
452{
454
455 assert(mapInfo.count(nId) != 0);
456 AddrInfo& info = mapInfo[nId];
457 assert(!info.fInTried);
458 assert(info.nRefCount == 0);
459
460 SwapRandom(info.nRandomPos, vRandom.size() - 1);
461 vRandom.pop_back();
462 mapAddr.erase(info);
463 mapInfo.erase(nId);
464 nNew--;
465}
466
467void AddrManImpl::ClearNew(int nUBucket, int nUBucketPos)
468{
470
471 // if there is an entry in the specified bucket, delete it.
472 if (vvNew[nUBucket][nUBucketPos] != -1) {
473 int nIdDelete = vvNew[nUBucket][nUBucketPos];
474 AddrInfo& infoDelete = mapInfo[nIdDelete];
475 assert(infoDelete.nRefCount > 0);
476 infoDelete.nRefCount--;
477 vvNew[nUBucket][nUBucketPos] = -1;
478 LogPrint(BCLog::ADDRMAN, "Removed %s from new[%i][%i]\n", infoDelete.ToString(), nUBucket, nUBucketPos);
479 if (infoDelete.nRefCount == 0) {
480 Delete(nIdDelete);
481 }
482 }
483}
484
486{
488
489 // remove the entry from all new buckets
490 const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
491 for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
492 const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
493 const int pos{info.GetBucketPosition(nKey, true, bucket)};
494 if (vvNew[bucket][pos] == nId) {
495 vvNew[bucket][pos] = -1;
496 info.nRefCount--;
497 if (info.nRefCount == 0) break;
498 }
499 }
500 nNew--;
501
502 assert(info.nRefCount == 0);
503
504 // which tried bucket to move the entry to
505 int nKBucket = info.GetTriedBucket(nKey, m_asmap);
506 int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
507
508 // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
509 if (vvTried[nKBucket][nKBucketPos] != -1) {
510 // find an item to evict
511 int nIdEvict = vvTried[nKBucket][nKBucketPos];
512 assert(mapInfo.count(nIdEvict) == 1);
513 AddrInfo& infoOld = mapInfo[nIdEvict];
514
515 // Remove the to-be-evicted item from the tried set.
516 infoOld.fInTried = false;
517 vvTried[nKBucket][nKBucketPos] = -1;
518 nTried--;
519
520 // find which new bucket it belongs to
521 int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
522 int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
523 ClearNew(nUBucket, nUBucketPos);
524 assert(vvNew[nUBucket][nUBucketPos] == -1);
525
526 // Enter it into the new set again.
527 infoOld.nRefCount = 1;
528 vvNew[nUBucket][nUBucketPos] = nIdEvict;
529 nNew++;
530 LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
531 infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
532 }
533 assert(vvTried[nKBucket][nKBucketPos] == -1);
534
535 vvTried[nKBucket][nKBucketPos] = nId;
536 nTried++;
537 info.fInTried = true;
538}
539
540bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
541{
543
544 if (!addr.IsRoutable())
545 return false;
546
547 int nId;
548 AddrInfo* pinfo = Find(addr, &nId);
549
550 // Do not set a penalty for a source's self-announcement
551 if (addr == source) {
552 nTimePenalty = 0;
553 }
554
555 if (pinfo) {
556 // periodically update nTime
557 bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
558 int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
559 if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
560 pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
561
562 // add services
563 pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
564
565 // do not update if no new information is present
566 if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
567 return false;
568
569 // do not update if the entry was already in the "tried" table
570 if (pinfo->fInTried)
571 return false;
572
573 // do not update if the max reference count is reached
575 return false;
576
577 // stochastic test: previous nRefCount == N: 2^N times harder to increase it
578 int nFactor = 1;
579 for (int n = 0; n < pinfo->nRefCount; n++)
580 nFactor *= 2;
581 if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
582 return false;
583 } else {
584 pinfo = Create(addr, source, &nId);
585 pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
586 nNew++;
587 }
588
589 int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
590 int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
591 bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
592 if (vvNew[nUBucket][nUBucketPos] != nId) {
593 if (!fInsert) {
594 AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
595 if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
596 // Overwrite the existing new table entry.
597 fInsert = true;
598 }
599 }
600 if (fInsert) {
601 ClearNew(nUBucket, nUBucketPos);
602 pinfo->nRefCount++;
603 vvNew[nUBucket][nUBucketPos] = nId;
604 LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
605 addr.ToString(), addr.GetMappedAS(m_asmap), nUBucket, nUBucketPos);
606 } else {
607 if (pinfo->nRefCount == 0) {
608 Delete(nId);
609 }
610 }
611 }
612 return fInsert;
613}
614
615void AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
616{
618
619 int nId;
620
621 nLastGood = nTime;
622
623 AddrInfo* pinfo = Find(addr, &nId);
624
625 // if not found, bail out
626 if (!pinfo)
627 return;
628
629 AddrInfo& info = *pinfo;
630
631 // update info
632 info.nLastSuccess = nTime;
633 info.nLastTry = nTime;
634 info.nAttempts = 0;
635 // nTime is not updated here, to avoid leaking information about
636 // currently-connected peers.
637
638 // if it is already in the tried set, don't do anything else
639 if (info.fInTried)
640 return;
641
642 // if it is not in new, something bad happened
643 if (!Assume(info.nRefCount > 0)) {
644 return;
645 }
646
647 // which tried bucket to move the entry to
648 int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
649 int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
650
651 // Will moving this address into tried evict another entry?
652 if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
654 m_tried_collisions.insert(nId);
655 }
656 // Output the entry we'd be colliding with, for debugging purposes
657 auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
658 LogPrint(BCLog::ADDRMAN, "Collision with %s while attempting to move %s to tried table. Collisions=%d\n",
659 colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "",
660 addr.ToString(),
661 m_tried_collisions.size());
662 } else {
663 // move nId to the tried tables
664 MakeTried(info, nId);
665 LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
666 addr.ToString(), addr.GetMappedAS(m_asmap), tried_bucket, tried_bucket_pos);
667 }
668}
669
670bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty)
671{
672 int added{0};
673 for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
674 added += AddSingle(*it, source, nTimePenalty) ? 1 : 0;
675 }
676 if (added > 0) {
677 LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToString(), nTried, nNew);
678 }
679 return added > 0;
680}
681
682void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
683{
685
686 AddrInfo* pinfo = Find(addr);
687
688 // if not found, bail out
689 if (!pinfo)
690 return;
691
692 AddrInfo& info = *pinfo;
693
694 // update info
695 info.nLastTry = nTime;
696 if (fCountFailure && info.nLastCountAttempt < nLastGood) {
697 info.nLastCountAttempt = nTime;
698 info.nAttempts++;
699 }
700}
701
702std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
703{
705
706 if (vRandom.empty()) return {};
707
708 if (newOnly && nNew == 0) return {};
709
710 // Use a 50% chance for choosing between tried and new table entries.
711 if (!newOnly &&
712 (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
713 // use a tried node
714 double fChanceFactor = 1.0;
715 while (1) {
716 // Pick a tried bucket, and an initial position in that bucket.
717 int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
718 int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
719 // Iterate over the positions of that bucket, starting at the initial one,
720 // and looping around.
721 int i;
722 for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
723 if (vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
724 }
725 // If the bucket is entirely empty, start over with a (likely) different one.
726 if (i == ADDRMAN_BUCKET_SIZE) continue;
727 // Find the entry to return.
728 int nId = vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE];
729 const auto it_found{mapInfo.find(nId)};
730 assert(it_found != mapInfo.end());
731 const AddrInfo& info{it_found->second};
732 // With probability GetChance() * fChanceFactor, return the entry.
733 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
734 LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
735 return {info, info.nLastTry};
736 }
737 // Otherwise start over with a (likely) different bucket, and increased chance factor.
738 fChanceFactor *= 1.2;
739 }
740 } else {
741 // use a new node
742 double fChanceFactor = 1.0;
743 while (1) {
744 // Pick a new bucket, and an initial position in that bucket.
745 int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
746 int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
747 // Iterate over the positions of that bucket, starting at the initial one,
748 // and looping around.
749 int i;
750 for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
751 if (vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
752 }
753 // If the bucket is entirely empty, start over with a (likely) different one.
754 if (i == ADDRMAN_BUCKET_SIZE) continue;
755 // Find the entry to return.
756 int nId = vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE];
757 const auto it_found{mapInfo.find(nId)};
758 assert(it_found != mapInfo.end());
759 const AddrInfo& info{it_found->second};
760 // With probability GetChance() * fChanceFactor, return the entry.
761 if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
762 LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
763 return {info, info.nLastTry};
764 }
765 // Otherwise start over with a (likely) different bucket, and increased chance factor.
766 fChanceFactor *= 1.2;
767 }
768 }
769}
770
771std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
772{
774
775 size_t nNodes = vRandom.size();
776 if (max_pct != 0) {
777 nNodes = max_pct * nNodes / 100;
778 }
779 if (max_addresses != 0) {
780 nNodes = std::min(nNodes, max_addresses);
781 }
782
783 // gather a list of random nodes, skipping those of low quality
784 const int64_t now{GetAdjustedTime()};
785 std::vector<CAddress> addresses;
786 for (unsigned int n = 0; n < vRandom.size(); n++) {
787 if (addresses.size() >= nNodes)
788 break;
789
790 int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
791 SwapRandom(n, nRndPos);
792 const auto it{mapInfo.find(vRandom[n])};
793 assert(it != mapInfo.end());
794
795 const AddrInfo& ai{it->second};
796
797 // Filter by network (optional)
798 if (network != std::nullopt && ai.GetNetClass() != network) continue;
799
800 // Filter for quality
801 if (ai.IsTerrible(now)) continue;
802
803 addresses.push_back(ai);
804 }
805 LogPrint(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size());
806 return addresses;
807}
808
809void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
810{
812
813 AddrInfo* pinfo = Find(addr);
814
815 // if not found, bail out
816 if (!pinfo)
817 return;
818
819 AddrInfo& info = *pinfo;
820
821 // update info
822 int64_t nUpdateInterval = 20 * 60;
823 if (nTime - info.nTime > nUpdateInterval)
824 info.nTime = nTime;
825}
826
828{
830
831 AddrInfo* pinfo = Find(addr);
832
833 // if not found, bail out
834 if (!pinfo)
835 return;
836
837 AddrInfo& info = *pinfo;
838
839 // update info
840 info.nServices = nServices;
841}
842
844{
846
847 for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
848 int id_new = *it;
849
850 bool erase_collision = false;
851
852 // If id_new not found in mapInfo remove it from m_tried_collisions
853 if (mapInfo.count(id_new) != 1) {
854 erase_collision = true;
855 } else {
856 AddrInfo& info_new = mapInfo[id_new];
857
858 // Which tried bucket to move the entry to.
859 int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
860 int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
861 if (!info_new.IsValid()) { // id_new may no longer map to a valid address
862 erase_collision = true;
863 } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
864
865 // Get the to-be-evicted address that is being tested
866 int id_old = vvTried[tried_bucket][tried_bucket_pos];
867 AddrInfo& info_old = mapInfo[id_old];
868
869 // Has successfully connected in last X hours
870 if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
871 erase_collision = true;
872 } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
873
874 // Give address at least 60 seconds to successfully connect
875 if (GetAdjustedTime() - info_old.nLastTry > 60) {
876 LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
877
878 // Replaces an existing address already in the tried table with the new address
879 Good_(info_new, false, GetAdjustedTime());
880 erase_collision = true;
881 }
882 } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
883 // If the collision hasn't resolved in some reasonable amount of time,
884 // just evict the old entry -- we must not be able to
885 // connect to it for some reason.
886 LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
887 Good_(info_new, false, GetAdjustedTime());
888 erase_collision = true;
889 }
890 } else { // Collision is not actually a collision anymore
891 Good_(info_new, false, GetAdjustedTime());
892 erase_collision = true;
893 }
894 }
895
896 if (erase_collision) {
897 m_tried_collisions.erase(it++);
898 } else {
899 it++;
900 }
901 }
902}
903
904std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
905{
907
908 if (m_tried_collisions.size() == 0) return {};
909
910 std::set<int>::iterator it = m_tried_collisions.begin();
911
912 // Selects a random element from m_tried_collisions
913 std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
914 int id_new = *it;
915
916 // If id_new not found in mapInfo remove it from m_tried_collisions
917 if (mapInfo.count(id_new) != 1) {
918 m_tried_collisions.erase(it);
919 return {};
920 }
921
922 const AddrInfo& newInfo = mapInfo[id_new];
923
924 // which tried bucket to move the entry to
925 int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
926 int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
927
928 const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
929 return {info_old, info_old.nLastTry};
930}
931
933{
935
936 // Run consistency checks 1 in m_consistency_check_ratio times if enabled
937 if (m_consistency_check_ratio == 0) return;
938 if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return;
939
940 const int err{ForceCheckAddrman()};
941 if (err) {
942 LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
943 assert(false);
944 }
945}
946
948{
950
951 LogPrint(BCLog::ADDRMAN, "Addrman checks started: new %i, tried %i, total %u\n", nNew, nTried, vRandom.size());
952
953 std::unordered_set<int> setTried;
954 std::unordered_map<int, int> mapNew;
955
956 if (vRandom.size() != (size_t)(nTried + nNew))
957 return -7;
958
959 for (const auto& entry : mapInfo) {
960 int n = entry.first;
961 const AddrInfo& info = entry.second;
962 if (info.fInTried) {
963 if (!info.nLastSuccess)
964 return -1;
965 if (info.nRefCount)
966 return -2;
967 setTried.insert(n);
968 } else {
970 return -3;
971 if (!info.nRefCount)
972 return -4;
973 mapNew[n] = info.nRefCount;
974 }
975 const auto it{mapAddr.find(info)};
976 if (it == mapAddr.end() || it->second != n) {
977 return -5;
978 }
979 if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
980 return -14;
981 if (info.nLastTry < 0)
982 return -6;
983 if (info.nLastSuccess < 0)
984 return -8;
985 }
986
987 if (setTried.size() != (size_t)nTried)
988 return -9;
989 if (mapNew.size() != (size_t)nNew)
990 return -10;
991
992 for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
993 for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
994 if (vvTried[n][i] != -1) {
995 if (!setTried.count(vvTried[n][i]))
996 return -11;
997 const auto it{mapInfo.find(vvTried[n][i])};
998 if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
999 return -17;
1000 }
1001 if (it->second.GetBucketPosition(nKey, false, n) != i) {
1002 return -18;
1003 }
1004 setTried.erase(vvTried[n][i]);
1005 }
1006 }
1007 }
1008
1009 for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
1010 for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
1011 if (vvNew[n][i] != -1) {
1012 if (!mapNew.count(vvNew[n][i]))
1013 return -12;
1014 const auto it{mapInfo.find(vvNew[n][i])};
1015 if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) {
1016 return -19;
1017 }
1018 if (--mapNew[vvNew[n][i]] == 0)
1019 mapNew.erase(vvNew[n][i]);
1020 }
1021 }
1022 }
1023
1024 if (setTried.size())
1025 return -13;
1026 if (mapNew.size())
1027 return -15;
1028 if (nKey.IsNull())
1029 return -16;
1030
1031 LogPrint(BCLog::ADDRMAN, "Addrman checks completed successfully\n");
1032 return 0;
1033}
1034
1035size_t AddrManImpl::size() const
1036{
1037 LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
1038 return vRandom.size();
1039}
1040
1041bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
1042{
1043 LOCK(cs);
1044 Check();
1045 auto ret = Add_(vAddr, source, nTimePenalty);
1046 Check();
1047 return ret;
1048}
1049
1050void AddrManImpl::Good(const CService& addr, int64_t nTime)
1051{
1052 LOCK(cs);
1053 Check();
1054 Good_(addr, /* test_before_evict */ true, nTime);
1055 Check();
1056}
1057
1058void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
1059{
1060 LOCK(cs);
1061 Check();
1062 Attempt_(addr, fCountFailure, nTime);
1063 Check();
1064}
1065
1067{
1068 LOCK(cs);
1069 Check();
1071 Check();
1072}
1073
1074std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
1075{
1076 LOCK(cs);
1077 Check();
1078 const auto ret = SelectTriedCollision_();
1079 Check();
1080 return ret;
1081}
1082
1083std::pair<CAddress, int64_t> AddrManImpl::Select(bool newOnly) const
1084{
1085 LOCK(cs);
1086 Check();
1087 const auto addrRet = Select_(newOnly);
1088 Check();
1089 return addrRet;
1090}
1091
1092std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
1093{
1094 LOCK(cs);
1095 Check();
1096 const auto addresses = GetAddr_(max_addresses, max_pct, network);
1097 Check();
1098 return addresses;
1099}
1100
1101void AddrManImpl::Connected(const CService& addr, int64_t nTime)
1102{
1103 LOCK(cs);
1104 Check();
1105 Connected_(addr, nTime);
1106 Check();
1107}
1108
1110{
1111 LOCK(cs);
1112 Check();
1113 SetServices_(addr, nServices);
1114 Check();
1115}
1116
1117const std::vector<bool>& AddrManImpl::GetAsmap() const
1118{
1119 return m_asmap;
1120}
1121
1122AddrMan::AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
1123 : m_impl(std::make_unique<AddrManImpl>(std::move(asmap), deterministic, consistency_check_ratio)) {}
1124
1125AddrMan::~AddrMan() = default;
1126
1127template <typename Stream>
1128void AddrMan::Serialize(Stream& s_) const
1129{
1130 m_impl->Serialize<Stream>(s_);
1131}
1132
1133template <typename Stream>
1134void AddrMan::Unserialize(Stream& s_)
1135{
1136 m_impl->Unserialize<Stream>(s_);
1137}
1138
1139// explicit instantiation
1140template void AddrMan::Serialize(CHashWriter& s) const;
1141template void AddrMan::Serialize(CAutoFile& s) const;
1142template void AddrMan::Serialize(CDataStream& s) const;
1143template void AddrMan::Unserialize(CAutoFile& s);
1145template void AddrMan::Unserialize(CDataStream& s);
1147
1148size_t AddrMan::size() const
1149{
1150 return m_impl->size();
1151}
1152
1153bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
1154{
1155 return m_impl->Add(vAddr, source, nTimePenalty);
1156}
1157
1158void AddrMan::Good(const CService& addr, int64_t nTime)
1159{
1160 m_impl->Good(addr, nTime);
1161}
1162
1163void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
1164{
1165 m_impl->Attempt(addr, fCountFailure, nTime);
1166}
1167
1169{
1170 m_impl->ResolveCollisions();
1171}
1172
1173std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision()
1174{
1175 return m_impl->SelectTriedCollision();
1176}
1177
1178std::pair<CAddress, int64_t> AddrMan::Select(bool newOnly) const
1179{
1180 return m_impl->Select(newOnly);
1181}
1182
1183std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
1184{
1185 return m_impl->GetAddr(max_addresses, max_pct, network);
1186}
1187
1188void AddrMan::Connected(const CService& addr, int64_t nTime)
1189{
1190 m_impl->Connected(addr, nTime);
1191}
1192
1193void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
1194{
1195 m_impl->SetServices(addr, nServices);
1196}
1197
1198const std::vector<bool>& AddrMan::GetAsmap() const
1199{
1200 return m_impl->GetAsmap();
1201}
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.
Definition: addrman.cpp:26
static constexpr int64_t ADDRMAN_HORIZON_DAYS
How old addresses can maximally be.
Definition: addrman.cpp:30
static constexpr int32_t ADDRMAN_MAX_FAILURES
How many successive failures are allowed ...
Definition: addrman.cpp:34
static constexpr int32_t ADDRMAN_RETRIES
After how many failed attempts we give up on a new node.
Definition: addrman.cpp:32
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE
The maximum number of tried addr collisions to store.
Definition: addrman.cpp:40
static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS
How recent a successful connection should be before we allow an address to be evicted from tried.
Definition: addrman.cpp:38
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.
Definition: addrman.cpp:24
static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS
... in at least this many days
Definition: addrman.cpp:36
static constexpr int64_t ADDRMAN_TEST_WINDOW
The maximum time we'll spend trying to resolve a tried table collision, in seconds.
Definition: addrman.cpp:42
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS
Maximum number of times an address can occur in the new table.
Definition: addrman.cpp:28
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT
Definition: addrman_impl.h:25
static constexpr int ADDRMAN_BUCKET_SIZE
Definition: addrman_impl.h:31
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman_impl.h:28
#define PACKAGE_NAME
#define Assume(val)
Assume is the identity function.
Definition: check.h:72
Extended statistics about a CAddress.
Definition: addrman_impl.h:37
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:44
bool IsTerrible(int64_t nNow=GetAdjustedTime()) const
Determine whether the statistics about this entry are bad enough so that it can just be deleted.
Definition: addrman.cpp:65
int nRandomPos
position in vRandom
Definition: addrman_impl.h:61
double GetChance(int64_t nNow=GetAdjustedTime()) const
Calculate the relative chance this entry should be given when selecting nodes to connect to.
Definition: addrman.cpp:85
bool fInTried
in tried set? (memory only)
Definition: addrman_impl.h:58
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.
Definition: addrman.cpp:51
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman_impl.h:43
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman_impl.h:40
int64_t nLastSuccess
last successful connection by us
Definition: addrman_impl.h:49
int nRefCount
reference count in new sets (memory only)
Definition: addrman_impl.h:55
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
Calculate in which position of a bucket to store this entry.
Definition: addrman.cpp:59
int nAttempts
connection attempts since last successful attempt
Definition: addrman_impl.h:52
std::pair< CAddress, int64_t > SelectTriedCollision()
Randomly select an address in the tried table that another address is attempting to evict.
Definition: addrman.cpp:1173
const std::unique_ptr< AddrManImpl > m_impl
Definition: addrman.h:56
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network) const
Return all or many randomly selected addresses, optionally by network.
Definition: addrman.cpp:1183
const std::vector< bool > & GetAsmap() const
Definition: addrman.cpp:1198
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty=0)
Attempt to add one or more addresses to addrman's new table.
Definition: addrman.cpp:1153
void Good(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible, possibly moving it from "new" to "tried".
Definition: addrman.cpp:1158
void ResolveCollisions()
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
Definition: addrman.cpp:1168
void Connected(const CService &addr, int64_t nTime=GetAdjustedTime())
We have successfully connected to this peer.
Definition: addrman.cpp:1188
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.cpp:1163
void Serialize(Stream &s_) const
Definition: addrman.cpp:1128
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.cpp:1148
void Unserialize(Stream &s_)
Definition: addrman.cpp:1134
AddrMan(std::vector< bool > asmap, bool deterministic, int32_t consistency_check_ratio)
Definition: addrman.cpp:1122
std::pair< CAddress, int64_t > Select(bool newOnly=false) const
Choose an address to connect to.
Definition: addrman.cpp:1178
void SetServices(const CService &addr, ServiceFlags nServices)
Update an entry's service bits.
Definition: addrman.cpp:1193
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.
Definition: addrman.cpp:467
int ForceCheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Perform consistency check, regardless of m_consistency_check_ratio.
Definition: addrman.cpp:947
void Good(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1050
static constexpr Format FILE_FORMAT
The maximum format this software knows it can unserialize.
Definition: addrman_impl.h:168
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:843
Format
Serialization versions.
Definition: addrman_impl.h:155
void Serialize(Stream &s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:124
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1092
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1035
void MakeTried(AddrInfo &info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Move an entry from the "new" table(s) to the "tried" table.
Definition: addrman.cpp:485
void SetServices(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1109
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1041
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1058
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:827
void Connected(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1101
const int32_t m_consistency_check_ratio
Perform consistency checks every m_consistency_check_ratio operations (if non-zero).
Definition: addrman_impl.h:210
const std::vector< bool > & GetAsmap() const
Definition: addrman.cpp:1117
std::pair< CAddress, int64_t > Select(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1083
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Consistency check, taking into account m_consistency_check_ratio. Will std::abort if an inconsistency...
Definition: addrman.cpp:932
AddrInfo * Find(const CService &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
Definition: addrman.cpp:398
std::pair< CAddress, int64_t > SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:904
Mutex cs
A mutex to protect the inner data structures.
Definition: addrman_impl.h:146
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:615
std::pair< CAddress, int64_t > Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:702
AddrManImpl(std::vector< bool > &&asmap, bool deterministic, int32_t consistency_check_ratio)
Definition: addrman.cpp:100
static constexpr uint8_t INCOMPATIBILITY_BASE
The initial value of a field that is incremented every time an incompatible format change is made (su...
Definition: addrman_impl.h:175
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
Definition: addrman.cpp:451
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
Definition: addrman.cpp:427
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:809
bool AddSingle(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Attempt to add a single address to addrman's new table.
Definition: addrman.cpp:540
void Unserialize(Stream &s_) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:227
std::set< int > m_tried_collisions
Holds addrs inserted into tried table that collide with existing entries. Test-before-evict disciplin...
Definition: addrman_impl.h:204
const std::vector< bool > m_asmap
Definition: addrman_impl.h:226
uint256 nKey
secret key to randomize bucket select with
Definition: addrman_impl.h:152
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1066
AddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Create a new entry and add it to the internal data structures mapInfo, mapAddr and vRandom.
Definition: addrman.cpp:413
std::pair< CAddress, int64_t > SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:1074
bool Add_(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:670
std::vector< CAddress > GetAddr_(size_t max_addresses, size_t max_pct, std::optional< Network > network) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:771
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: addrman.cpp:682
A CService with information about it as peer.
Definition: protocol.h:359
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
Definition: protocol.h:442
uint32_t nTime
Always included in serialization.
Definition: protocol.h:440
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:565
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:205
Reads data from an underlying stream, while hashing the read data.
Definition: hash.h:158
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:101
Network address.
Definition: netaddress.h:119
bool IsRoutable() const
Definition: netaddress.cpp:490
bool IsValid() const
Definition: netaddress.cpp:451
std::vector< unsigned char > GetGroup(const std::vector< bool > &asmap) const
Get the canonical identifier of our network group.
Definition: netaddress.cpp:766
uint32_t GetMappedAS(const std::vector< bool > &asmap) const
Definition: netaddress.cpp:725
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:523
std::string ToString() const
std::vector< unsigned char > GetKey() const
void SetNull()
Definition: uint256.h:39
bool IsNull() const
Definition: uint256.h:31
256-bit opaque blob.
Definition: uint256.h:124
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:192
#define LogPrint(category,...)
Definition: logging.h:191
#define LogPrintf(...)
Definition: logging.h:187
@ ADDRMAN
Definition: logging.h:47
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1062
static constexpr int ADDRV2_FORMAT
A flag that is ORed into the protocol version to designate that addresses should be serialized in (un...
Definition: netaddress.h:34
ServiceFlags
nServices flags
Definition: protocol.h:271
const char * source
Definition: rpcconsole.cpp:63
@ SER_GETHASH
Definition: serialize.h:140
#define LOCK(cs)
Definition: sync.h:226
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
AssertLockHeld(pool.cs)
assert(!tx.IsCoinBase())