Bitcoin Core  22.99.0
P2P Digital Currency
addrman.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012 Pieter Wuille
2 // Copyright (c) 2012-2020 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <addrman.h>
7 
8 #include <clientversion.h>
9 #include <hash.h>
10 #include <logging.h>
11 #include <netaddress.h>
12 #include <serialize.h>
13 #include <streams.h>
14 
15 #include <cmath>
16 #include <optional>
17 #include <unordered_map>
18 #include <unordered_set>
19 
21 static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP{8};
23 static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
25 static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
27 static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
29 static constexpr int32_t ADDRMAN_RETRIES{3};
31 static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
33 static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7};
35 static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4};
37 static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
39 static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
40 
41 int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
42 {
43  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
44  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
45  int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
46  uint32_t mapped_as = GetMappedAS(asmap);
47  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
48  return tried_bucket;
49 }
50 
51 int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
52 {
53  std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
54  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
55  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
56  int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
57  uint32_t mapped_as = GetMappedAS(asmap);
58  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
59  return new_bucket;
60 }
61 
62 int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
63 {
64  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
65  return hash1 % ADDRMAN_BUCKET_SIZE;
66 }
67 
68 bool CAddrInfo::IsTerrible(int64_t nNow) const
69 {
70  if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
71  return false;
72 
73  if (nTime > nNow + 10 * 60) // came in a flying DeLorean
74  return true;
75 
76  if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
77  return true;
78 
79  if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
80  return true;
81 
82  if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
83  return true;
84 
85  return false;
86 }
87 
88 double CAddrInfo::GetChance(int64_t nNow) const
89 {
90  double fChance = 1.0;
91  int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
92 
93  // deprioritize very recent attempts away
94  if (nSinceLastTry < 60 * 10)
95  fChance *= 0.01;
96 
97  // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
98  fChance *= pow(0.66, std::min(nAttempts, 8));
99 
100  return fChance;
101 }
102 
103 CAddrMan::CAddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
104  : insecure_rand{deterministic}
105  , nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
106  , m_consistency_check_ratio{consistency_check_ratio}
107  , m_asmap{std::move(asmap)}
108 {
109  for (auto& bucket : vvNew) {
110  for (auto& entry : bucket) {
111  entry = -1;
112  }
113  }
114  for (auto& bucket : vvTried) {
115  for (auto& entry : bucket) {
116  entry = -1;
117  }
118  }
119 }
120 
121 template <typename Stream>
122 void CAddrMan::Serialize(Stream& s_) const
123 {
124  LOCK(cs);
125 
164  // Always serialize in the latest version (FILE_FORMAT).
165 
166  OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
167 
168  s << static_cast<uint8_t>(FILE_FORMAT);
169 
170  // Increment `lowest_compatible` iff a newly introduced format is incompatible with
171  // the previous one.
172  static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
173  s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
174 
175  s << nKey;
176  s << nNew;
177  s << nTried;
178 
179  int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
180  s << nUBuckets;
181  std::unordered_map<int, int> mapUnkIds;
182  int nIds = 0;
183  for (const auto& entry : mapInfo) {
184  mapUnkIds[entry.first] = nIds;
185  const CAddrInfo &info = entry.second;
186  if (info.nRefCount) {
187  assert(nIds != nNew); // this means nNew was wrong, oh ow
188  s << info;
189  nIds++;
190  }
191  }
192  nIds = 0;
193  for (const auto& entry : mapInfo) {
194  const CAddrInfo &info = entry.second;
195  if (info.fInTried) {
196  assert(nIds != nTried); // this means nTried was wrong, oh ow
197  s << info;
198  nIds++;
199  }
200  }
201  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
202  int nSize = 0;
203  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
204  if (vvNew[bucket][i] != -1)
205  nSize++;
206  }
207  s << nSize;
208  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
209  if (vvNew[bucket][i] != -1) {
210  int nIndex = mapUnkIds[vvNew[bucket][i]];
211  s << nIndex;
212  }
213  }
214  }
215  // Store asmap checksum after bucket entries so that it
216  // can be ignored by older clients for backward compatibility.
217  uint256 asmap_checksum;
218  if (m_asmap.size() != 0) {
219  asmap_checksum = SerializeHash(m_asmap);
220  }
221  s << asmap_checksum;
222 }
223 
224 template <typename Stream>
225 void CAddrMan::Unserialize(Stream& s_)
226 {
227  LOCK(cs);
228 
229  assert(vRandom.empty());
230 
231  Format format;
232  s_ >> Using<CustomUintFormatter<1>>(format);
233 
234  int stream_version = s_.GetVersion();
235  if (format >= Format::V3_BIP155) {
236  // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
237  // unserialize methods know that an address in addrv2 format is coming.
238  stream_version |= ADDRV2_FORMAT;
239  }
240 
241  OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
242 
243  uint8_t compat;
244  s >> compat;
245  const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
246  if (lowest_compatible > FILE_FORMAT) {
247  throw std::ios_base::failure(strprintf(
248  "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
249  "but the maximum supported by this version of %s is %u.",
250  uint8_t{format}, uint8_t{lowest_compatible}, PACKAGE_NAME, uint8_t{FILE_FORMAT}));
251  }
252 
253  s >> nKey;
254  s >> nNew;
255  s >> nTried;
256  int nUBuckets = 0;
257  s >> nUBuckets;
258  if (format >= Format::V1_DETERMINISTIC) {
259  nUBuckets ^= (1 << 30);
260  }
261 
262  if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
263  throw std::ios_base::failure(
264  strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %d]",
265  nNew,
267  }
268 
269  if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
270  throw std::ios_base::failure(
271  strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %d]",
272  nTried,
274  }
275 
276  // Deserialize entries from the new table.
277  for (int n = 0; n < nNew; n++) {
278  CAddrInfo &info = mapInfo[n];
279  s >> info;
280  mapAddr[info] = n;
281  info.nRandomPos = vRandom.size();
282  vRandom.push_back(n);
283  }
284  nIdCount = nNew;
285 
286  // Deserialize entries from the tried table.
287  int nLost = 0;
288  for (int n = 0; n < nTried; n++) {
289  CAddrInfo info;
290  s >> info;
291  int nKBucket = info.GetTriedBucket(nKey, m_asmap);
292  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
293  if (info.IsValid()
294  && vvTried[nKBucket][nKBucketPos] == -1) {
295  info.nRandomPos = vRandom.size();
296  info.fInTried = true;
297  vRandom.push_back(nIdCount);
298  mapInfo[nIdCount] = info;
299  mapAddr[info] = nIdCount;
300  vvTried[nKBucket][nKBucketPos] = nIdCount;
301  nIdCount++;
302  } else {
303  nLost++;
304  }
305  }
306  nTried -= nLost;
307 
308  // Store positions in the new table buckets to apply later (if possible).
309  // An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
310  // so we store all bucket-entry_index pairs to iterate through later.
311  std::vector<std::pair<int, int>> bucket_entries;
312 
313  for (int bucket = 0; bucket < nUBuckets; ++bucket) {
314  int num_entries{0};
315  s >> num_entries;
316  for (int n = 0; n < num_entries; ++n) {
317  int entry_index{0};
318  s >> entry_index;
319  if (entry_index >= 0 && entry_index < nNew) {
320  bucket_entries.emplace_back(bucket, entry_index);
321  }
322  }
323  }
324 
325  // If the bucket count and asmap checksum haven't changed, then attempt
326  // to restore the entries to the buckets/positions they were in before
327  // serialization.
328  uint256 supplied_asmap_checksum;
329  if (m_asmap.size() != 0) {
330  supplied_asmap_checksum = SerializeHash(m_asmap);
331  }
332  uint256 serialized_asmap_checksum;
333  if (format >= Format::V2_ASMAP) {
334  s >> serialized_asmap_checksum;
335  }
336  const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
337  serialized_asmap_checksum == supplied_asmap_checksum};
338 
339  if (!restore_bucketing) {
340  LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
341  }
342 
343  for (auto bucket_entry : bucket_entries) {
344  int bucket{bucket_entry.first};
345  const int entry_index{bucket_entry.second};
346  CAddrInfo& info = mapInfo[entry_index];
347 
348  // Don't store the entry in the new bucket if it's not a valid address for our addrman
349  if (!info.IsValid()) continue;
350 
351  // The entry shouldn't appear in more than
352  // ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
353  // this bucket_entry.
354  if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
355 
356  int bucket_position = info.GetBucketPosition(nKey, true, bucket);
357  if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
358  // Bucketing has not changed, using existing bucket positions for the new table
359  vvNew[bucket][bucket_position] = entry_index;
360  ++info.nRefCount;
361  } else {
362  // In case the new table data cannot be used (bucket count wrong or new asmap),
363  // try to give them a reference based on their primary source address.
364  bucket = info.GetNewBucket(nKey, m_asmap);
365  bucket_position = info.GetBucketPosition(nKey, true, bucket);
366  if (vvNew[bucket][bucket_position] == -1) {
367  vvNew[bucket][bucket_position] = entry_index;
368  ++info.nRefCount;
369  }
370  }
371  }
372 
373  // Prune new entries with refcount 0 (as a result of collisions or invalid address).
374  int nLostUnk = 0;
375  for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
376  if (it->second.fInTried == false && it->second.nRefCount == 0) {
377  const auto itCopy = it++;
378  Delete(itCopy->first);
379  ++nLostUnk;
380  } else {
381  ++it;
382  }
383  }
384  if (nLost + nLostUnk > 0) {
385  LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
386  }
387 
388  Check();
389 }
390 
391 // explicit instantiation
392 template void CAddrMan::Serialize(CHashWriter& s) const;
393 template void CAddrMan::Serialize(CAutoFile& s) const;
394 template void CAddrMan::Serialize(CDataStream& s) const;
395 template void CAddrMan::Unserialize(CAutoFile& s);
397 template void CAddrMan::Unserialize(CDataStream& s);
399 
400 CAddrInfo* CAddrMan::Find(const CNetAddr& 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 CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
416 {
418 
419  int nId = nIdCount++;
420  mapInfo[nId] = CAddrInfo(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 CAddrMan::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 CAddrMan::Delete(int nId)
454 {
456 
457  assert(mapInfo.count(nId) != 0);
458  CAddrInfo& 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 CAddrMan::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  CAddrInfo& infoDelete = mapInfo[nIdDelete];
477  assert(infoDelete.nRefCount > 0);
478  infoDelete.nRefCount--;
479  vvNew[nUBucket][nUBucketPos] = -1;
480  if (infoDelete.nRefCount == 0) {
481  Delete(nIdDelete);
482  }
483  }
484 }
485 
486 void CAddrMan::MakeTried(CAddrInfo& info, int nId)
487 {
489 
490  // remove the entry from all new buckets
491  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
492  int pos = info.GetBucketPosition(nKey, true, bucket);
493  if (vvNew[bucket][pos] == nId) {
494  vvNew[bucket][pos] = -1;
495  info.nRefCount--;
496  }
497  }
498  nNew--;
499 
500  assert(info.nRefCount == 0);
501 
502  // which tried bucket to move the entry to
503  int nKBucket = info.GetTriedBucket(nKey, m_asmap);
504  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
505 
506  // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
507  if (vvTried[nKBucket][nKBucketPos] != -1) {
508  // find an item to evict
509  int nIdEvict = vvTried[nKBucket][nKBucketPos];
510  assert(mapInfo.count(nIdEvict) == 1);
511  CAddrInfo& infoOld = mapInfo[nIdEvict];
512 
513  // Remove the to-be-evicted item from the tried set.
514  infoOld.fInTried = false;
515  vvTried[nKBucket][nKBucketPos] = -1;
516  nTried--;
517 
518  // find which new bucket it belongs to
519  int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
520  int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
521  ClearNew(nUBucket, nUBucketPos);
522  assert(vvNew[nUBucket][nUBucketPos] == -1);
523 
524  // Enter it into the new set again.
525  infoOld.nRefCount = 1;
526  vvNew[nUBucket][nUBucketPos] = nIdEvict;
527  nNew++;
528  }
529  assert(vvTried[nKBucket][nKBucketPos] == -1);
530 
531  vvTried[nKBucket][nKBucketPos] = nId;
532  nTried++;
533  info.fInTried = true;
534 }
535 
536 void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
537 {
539 
540  int nId;
541 
542  nLastGood = nTime;
543 
544  CAddrInfo* pinfo = Find(addr, &nId);
545 
546  // if not found, bail out
547  if (!pinfo)
548  return;
549 
550  CAddrInfo& info = *pinfo;
551 
552  // check whether we are talking about the exact same CService (including same port)
553  if (info != addr)
554  return;
555 
556  // update info
557  info.nLastSuccess = nTime;
558  info.nLastTry = nTime;
559  info.nAttempts = 0;
560  // nTime is not updated here, to avoid leaking information about
561  // currently-connected peers.
562 
563  // if it is already in the tried set, don't do anything else
564  if (info.fInTried)
565  return;
566 
567  // find a bucket it is in now
568  int nRnd = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
569  int nUBucket = -1;
570  for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
571  int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
572  int nBpos = info.GetBucketPosition(nKey, true, nB);
573  if (vvNew[nB][nBpos] == nId) {
574  nUBucket = nB;
575  break;
576  }
577  }
578 
579  // if no bucket is found, something bad happened;
580  // TODO: maybe re-add the node, but for now, just bail out
581  if (nUBucket == -1)
582  return;
583 
584  // which tried bucket to move the entry to
585  int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
586  int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
587 
588  // Will moving this address into tried evict another entry?
589  if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
590  // Output the entry we'd be colliding with, for debugging purposes
591  auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
592  LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
594  m_tried_collisions.insert(nId);
595  }
596  } else {
597  LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
598 
599  // move nId to the tried tables
600  MakeTried(info, nId);
601  }
602 }
603 
604 bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
605 {
607 
608  if (!addr.IsRoutable())
609  return false;
610 
611  bool fNew = false;
612  int nId;
613  CAddrInfo* pinfo = Find(addr, &nId);
614 
615  // Do not set a penalty for a source's self-announcement
616  if (addr == source) {
617  nTimePenalty = 0;
618  }
619 
620  if (pinfo) {
621  // periodically update nTime
622  bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
623  int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
624  if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
625  pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
626 
627  // add services
628  pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
629 
630  // do not update if no new information is present
631  if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
632  return false;
633 
634  // do not update if the entry was already in the "tried" table
635  if (pinfo->fInTried)
636  return false;
637 
638  // do not update if the max reference count is reached
640  return false;
641 
642  // stochastic test: previous nRefCount == N: 2^N times harder to increase it
643  int nFactor = 1;
644  for (int n = 0; n < pinfo->nRefCount; n++)
645  nFactor *= 2;
646  if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
647  return false;
648  } else {
649  pinfo = Create(addr, source, &nId);
650  pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
651  nNew++;
652  fNew = true;
653  }
654 
655  int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
656  int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
657  if (vvNew[nUBucket][nUBucketPos] != nId) {
658  bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
659  if (!fInsert) {
660  CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
661  if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
662  // Overwrite the existing new table entry.
663  fInsert = true;
664  }
665  }
666  if (fInsert) {
667  ClearNew(nUBucket, nUBucketPos);
668  pinfo->nRefCount++;
669  vvNew[nUBucket][nUBucketPos] = nId;
670  } else {
671  if (pinfo->nRefCount == 0) {
672  Delete(nId);
673  }
674  }
675  }
676  return fNew;
677 }
678 
679 void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
680 {
682 
683  CAddrInfo* pinfo = Find(addr);
684 
685  // if not found, bail out
686  if (!pinfo)
687  return;
688 
689  CAddrInfo& info = *pinfo;
690 
691  // check whether we are talking about the exact same CService (including same port)
692  if (info != addr)
693  return;
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 CAddrInfo CAddrMan::Select_(bool newOnly) const
704 {
706 
707  if (vRandom.empty())
708  return CAddrInfo();
709 
710  if (newOnly && nNew == 0)
711  return CAddrInfo();
712 
713  // Use a 50% chance for choosing between tried and new table entries.
714  if (!newOnly &&
715  (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
716  // use a tried node
717  double fChanceFactor = 1.0;
718  while (1) {
719  int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
720  int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
721  while (vvTried[nKBucket][nKBucketPos] == -1) {
722  nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
723  nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
724  }
725  int nId = vvTried[nKBucket][nKBucketPos];
726  const auto it_found{mapInfo.find(nId)};
727  assert(it_found != mapInfo.end());
728  const CAddrInfo& info{it_found->second};
729  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
730  return info;
731  fChanceFactor *= 1.2;
732  }
733  } else {
734  // use a new node
735  double fChanceFactor = 1.0;
736  while (1) {
737  int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
738  int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
739  while (vvNew[nUBucket][nUBucketPos] == -1) {
740  nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
741  nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
742  }
743  int nId = vvNew[nUBucket][nUBucketPos];
744  const auto it_found{mapInfo.find(nId)};
745  assert(it_found != mapInfo.end());
746  const CAddrInfo& info{it_found->second};
747  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
748  return info;
749  fChanceFactor *= 1.2;
750  }
751  }
752 }
753 
754 int CAddrMan::Check_() const
755 {
757 
758  // Run consistency checks 1 in m_consistency_check_ratio times if enabled
759  if (m_consistency_check_ratio == 0) return 0;
760  if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return 0;
761 
762  LogPrint(BCLog::ADDRMAN, "Addrman checks started: new %i, tried %i, total %u\n", nNew, nTried, vRandom.size());
763 
764  std::unordered_set<int> setTried;
765  std::unordered_map<int, int> mapNew;
766 
767  if (vRandom.size() != (size_t)(nTried + nNew))
768  return -7;
769 
770  for (const auto& entry : mapInfo) {
771  int n = entry.first;
772  const CAddrInfo& info = entry.second;
773  if (info.fInTried) {
774  if (!info.nLastSuccess)
775  return -1;
776  if (info.nRefCount)
777  return -2;
778  setTried.insert(n);
779  } else {
780  if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
781  return -3;
782  if (!info.nRefCount)
783  return -4;
784  mapNew[n] = info.nRefCount;
785  }
786  const auto it{mapAddr.find(info)};
787  if (it == mapAddr.end() || it->second != n) {
788  return -5;
789  }
790  if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
791  return -14;
792  if (info.nLastTry < 0)
793  return -6;
794  if (info.nLastSuccess < 0)
795  return -8;
796  }
797 
798  if (setTried.size() != (size_t)nTried)
799  return -9;
800  if (mapNew.size() != (size_t)nNew)
801  return -10;
802 
803  for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
804  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
805  if (vvTried[n][i] != -1) {
806  if (!setTried.count(vvTried[n][i]))
807  return -11;
808  const auto it{mapInfo.find(vvTried[n][i])};
809  if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
810  return -17;
811  }
812  if (it->second.GetBucketPosition(nKey, false, n) != i) {
813  return -18;
814  }
815  setTried.erase(vvTried[n][i]);
816  }
817  }
818  }
819 
820  for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
821  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
822  if (vvNew[n][i] != -1) {
823  if (!mapNew.count(vvNew[n][i]))
824  return -12;
825  const auto it{mapInfo.find(vvNew[n][i])};
826  if (it == mapInfo.end() || it->second.GetBucketPosition(nKey, true, n) != i) {
827  return -19;
828  }
829  if (--mapNew[vvNew[n][i]] == 0)
830  mapNew.erase(vvNew[n][i]);
831  }
832  }
833  }
834 
835  if (setTried.size())
836  return -13;
837  if (mapNew.size())
838  return -15;
839  if (nKey.IsNull())
840  return -16;
841 
842  LogPrint(BCLog::ADDRMAN, "Addrman checks completed successfully\n");
843  return 0;
844 }
845 
846 void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) const
847 {
849 
850  size_t nNodes = vRandom.size();
851  if (max_pct != 0) {
852  nNodes = max_pct * nNodes / 100;
853  }
854  if (max_addresses != 0) {
855  nNodes = std::min(nNodes, max_addresses);
856  }
857 
858  // gather a list of random nodes, skipping those of low quality
859  const int64_t now{GetAdjustedTime()};
860  for (unsigned int n = 0; n < vRandom.size(); n++) {
861  if (vAddr.size() >= nNodes)
862  break;
863 
864  int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
865  SwapRandom(n, nRndPos);
866  const auto it{mapInfo.find(vRandom[n])};
867  assert(it != mapInfo.end());
868 
869  const CAddrInfo& ai{it->second};
870 
871  // Filter by network (optional)
872  if (network != std::nullopt && ai.GetNetClass() != network) continue;
873 
874  // Filter for quality
875  if (ai.IsTerrible(now)) continue;
876 
877  vAddr.push_back(ai);
878  }
879 }
880 
881 void CAddrMan::Connected_(const CService& addr, int64_t nTime)
882 {
884 
885  CAddrInfo* pinfo = Find(addr);
886 
887  // if not found, bail out
888  if (!pinfo)
889  return;
890 
891  CAddrInfo& info = *pinfo;
892 
893  // check whether we are talking about the exact same CService (including same port)
894  if (info != addr)
895  return;
896 
897  // update info
898  int64_t nUpdateInterval = 20 * 60;
899  if (nTime - info.nTime > nUpdateInterval)
900  info.nTime = nTime;
901 }
902 
903 void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
904 {
906 
907  CAddrInfo* pinfo = Find(addr);
908 
909  // if not found, bail out
910  if (!pinfo)
911  return;
912 
913  CAddrInfo& info = *pinfo;
914 
915  // check whether we are talking about the exact same CService (including same port)
916  if (info != addr)
917  return;
918 
919  // update info
920  info.nServices = nServices;
921 }
922 
924 {
926 
927  for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
928  int id_new = *it;
929 
930  bool erase_collision = false;
931 
932  // If id_new not found in mapInfo remove it from m_tried_collisions
933  if (mapInfo.count(id_new) != 1) {
934  erase_collision = true;
935  } else {
936  CAddrInfo& info_new = mapInfo[id_new];
937 
938  // Which tried bucket to move the entry to.
939  int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
940  int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
941  if (!info_new.IsValid()) { // id_new may no longer map to a valid address
942  erase_collision = true;
943  } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
944 
945  // Get the to-be-evicted address that is being tested
946  int id_old = vvTried[tried_bucket][tried_bucket_pos];
947  CAddrInfo& info_old = mapInfo[id_old];
948 
949  // Has successfully connected in last X hours
950  if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
951  erase_collision = true;
952  } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
953 
954  // Give address at least 60 seconds to successfully connect
955  if (GetAdjustedTime() - info_old.nLastTry > 60) {
956  LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
957 
958  // Replaces an existing address already in the tried table with the new address
959  Good_(info_new, false, GetAdjustedTime());
960  erase_collision = true;
961  }
962  } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
963  // If the collision hasn't resolved in some reasonable amount of time,
964  // just evict the old entry -- we must not be able to
965  // connect to it for some reason.
966  LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
967  Good_(info_new, false, GetAdjustedTime());
968  erase_collision = true;
969  }
970  } else { // Collision is not actually a collision anymore
971  Good_(info_new, false, GetAdjustedTime());
972  erase_collision = true;
973  }
974  }
975 
976  if (erase_collision) {
977  m_tried_collisions.erase(it++);
978  } else {
979  it++;
980  }
981  }
982 }
983 
985 {
987 
988  if (m_tried_collisions.size() == 0) return CAddrInfo();
989 
990  std::set<int>::iterator it = m_tried_collisions.begin();
991 
992  // Selects a random element from m_tried_collisions
993  std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
994  int id_new = *it;
995 
996  // If id_new not found in mapInfo remove it from m_tried_collisions
997  if (mapInfo.count(id_new) != 1) {
998  m_tried_collisions.erase(it);
999  return CAddrInfo();
1000  }
1001 
1002  const CAddrInfo& newInfo = mapInfo[id_new];
1003 
1004  // which tried bucket to move the entry to
1005  int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
1006  int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
1007 
1008  int id_old = vvTried[tried_bucket][tried_bucket_pos];
1009 
1010  return mapInfo[id_old];
1011 }
CAddrMan::Create
CAddrInfo * 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
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
CService
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:539
CAddrMan::nKey
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:283
CAddrInfo::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:51
CAddrMan::Good_
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry "good", possibly moving it from "new" to "tried".
Definition: addrman.cpp:536
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
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
ADDRMAN_HORIZON_DAYS
static constexpr int64_t ADDRMAN_HORIZON_DAYS
How old addresses can maximally be.
Definition: addrman.cpp:27
CAddrMan::Add_
bool Add_(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs)
Add an entry to the "new" table.
Definition: addrman.cpp:604
CAddrMan::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.h:334
CHashVerifier
Reads data from an underlying stream, while hashing the read data.
Definition: hash.h:157
streams.h
CAddrMan::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
CNetAddr
Network address.
Definition: netaddress.h:118
source
const char * source
Definition: rpcconsole.cpp:63
CAddrInfo::nLastSuccess
int64_t nLastSuccess
last successful connection by us
Definition: addrman.h:42
CAddrMan::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.h:305
CAddrInfo::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:88
CAddrMan::ResolveCollisions_
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs)
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
Definition: addrman.cpp:923
clientversion.h
ServiceFlags
ServiceFlags
nServices flags
Definition: protocol.h:271
CAddrInfo::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:68
CAddress::nServices
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
Definition: protocol.h:442
CAddrMan::Attempt_
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as attempted to connect.
Definition: addrman.cpp:679
ADDRMAN_MAX_FAILURES
static constexpr int32_t ADDRMAN_MAX_FAILURES
How many successive failures are allowed ...
Definition: addrman.cpp:31
CAddress::nTime
uint32_t nTime
Always included in serialization.
Definition: protocol.h:440
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:21
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:23
ADDRMAN_TRIED_BUCKET_COUNT
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT
Definition: addrman.h:129
CAddrMan::SetServices_
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Update an entry's service bits.
Definition: addrman.cpp:903
CNetAddr::ToStringIP
std::string ToStringIP() const
Definition: netaddress.cpp:608
CAutoFile
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:564
CAddrInfo
Extended statistics about a CAddress.
Definition: addrman.h:28
CAddrMan::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.h:340
CAddrInfo::nLastCountAttempt
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:35
CService::ToString
std::string ToString() const
Definition: netaddress.cpp:1037
CAddrMan::GetAddr_
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct, std::optional< Network > network) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Return all or many randomly selected addresses, optionally by network.
Definition: addrman.cpp:846
ADDRMAN_RETRIES
static constexpr int32_t ADDRMAN_RETRIES
After how many failed attempts we give up on a new node.
Definition: addrman.cpp:29
ADDRMAN_NEW_BUCKET_COUNT_LOG2
static constexpr int32_t ADDRMAN_NEW_BUCKET_COUNT_LOG2
Total number of buckets for new addresses.
Definition: addrman.h:132
CAddrMan::SelectTriedCollision_
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Return a random to-be-evicted tried table address.
Definition: addrman.cpp:984
PACKAGE_NAME
#define PACKAGE_NAME
Definition: bitcoin-config.h:368
CNetAddr::IsRoutable
bool IsRoutable() const
Definition: netaddress.cpp:490
ADDRMAN_BUCKET_SIZE_LOG2
static constexpr int32_t ADDRMAN_BUCKET_SIZE_LOG2
Maximum allowed number of entries in buckets for new and tried addresses.
Definition: addrman.h:136
netaddress.h
CAddrMan::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
CAddrMan::CAddrMan
CAddrMan(std::vector< bool > asmap, bool deterministic, int32_t consistency_check_ratio)
Definition: addrman.cpp:103
CAddrInfo::nRefCount
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:48
CNetAddr::GetMappedAS
uint32_t GetMappedAS(const std::vector< bool > &asmap) const
Definition: netaddress.cpp:725
CNetAddr::IsValid
bool IsValid() const
Definition: netaddress.cpp:451
CAddrInfo::nRandomPos
int nRandomPos
position in vRandom
Definition: addrman.h:54
CAddrMan::FILE_FORMAT
static constexpr Format FILE_FORMAT
The maximum format this software knows it can unserialize.
Definition: addrman.h:298
ADDRMAN_NEW_BUCKETS_PER_ADDRESS
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS
Maximum number of times an address can be added to the new table.
Definition: addrman.cpp:25
CAddrInfo::nLastTry
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman.h:32
CAddrInfo::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:62
uint256
256-bit opaque blob.
Definition: uint256.h:124
CAddrMan::Format
Format
Serialization versions.
Definition: addrman.h:286
CAddrMan::Select_
CAddrInfo Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Select an address to connect to, if newOnly is set to true, only the new table is selected from.
Definition: addrman.cpp:703
CAddrMan::Check
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Consistency check.
Definition: addrman.h:395
LogPrint
#define LogPrint(category,...)
Definition: logging.h:189
CAddrMan::MakeTried
void MakeTried(CAddrInfo &info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Move an entry from the "new" table(s) to the "tried" table.
Definition: addrman.cpp:486
CAddrInfo::GetTriedBucket
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:41
CAddrMan::m_asmap
const std::vector< bool > m_asmap
Definition: addrman.h:356
OverrideStream
Definition: streams.h:26
CAddrMan::Connected_
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
We have successfully connected to this peer.
Definition: addrman.cpp:881
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
ADDRMAN_MIN_FAIL_DAYS
static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS
...
Definition: addrman.cpp:33
GetAdjustedTime
int64_t GetAdjustedTime()
Definition: timedata.cpp:34
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:37
base_blob::IsNull
bool IsNull() const
Definition: uint256.h:31
CAddress
A CService with information about it as peer.
Definition: protocol.h:358
CAddrInfo::nAttempts
int nAttempts
connection attempts since last successful attempt
Definition: addrman.h:45
ADDRMAN_TRIED_BUCKET_COUNT_LOG2
static constexpr int32_t ADDRMAN_TRIED_BUCKET_COUNT_LOG2
Stochastic address manager.
Definition: addrman.h:128
LOCK
#define LOCK(cs)
Definition: sync.h:226
ADDRMAN_BUCKET_SIZE
static constexpr int ADDRMAN_BUCKET_SIZE
Definition: addrman.h:137
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.h:133
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:39
serialize.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:204
addrman.h
BCLog::ADDRMAN
@ ADDRMAN
Definition: logging.h:47
CAddrMan::Find
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
Definition: addrman.cpp:400
CAddrInfo::fInTried
bool fInTried
in tried set? (memory only)
Definition: addrman.h:51
BCLog::NET
@ NET
Definition: logging.h:38
CAddrMan::Serialize
void Serialize(Stream &s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:122
CAddrMan::Unserialize
void Unserialize(Stream &s_) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: addrman.cpp:225
CAddrMan::Check_
int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Perform consistency check. Returns an error code or zero.
Definition: addrman.cpp:754
CAddrMan::SwapRandom
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
Definition: addrman.cpp:429
SER_GETHASH
@ SER_GETHASH
Definition: serialize.h:140
CAddrMan::cs
Mutex cs
A mutex to protect the inner data structures.
Definition: addrman.h:277
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:35
CService::GetKey
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:1015