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