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