Bitcoin Core  21.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 <hash.h>
9 #include <logging.h>
10 #include <serialize.h>
11 
12 #include <cmath>
13 
14 int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
15 {
16  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
17  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
18  int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
19  uint32_t mapped_as = GetMappedAS(asmap);
20  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
21  return tried_bucket;
22 }
23 
24 int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
25 {
26  std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
27  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
28  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
29  int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
30  uint32_t mapped_as = GetMappedAS(asmap);
31  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
32  return new_bucket;
33 }
34 
35 int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
36 {
37  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetCheapHash();
38  return hash1 % ADDRMAN_BUCKET_SIZE;
39 }
40 
41 bool CAddrInfo::IsTerrible(int64_t nNow) const
42 {
43  if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
44  return false;
45 
46  if (nTime > nNow + 10 * 60) // came in a flying DeLorean
47  return true;
48 
49  if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
50  return true;
51 
52  if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
53  return true;
54 
55  if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
56  return true;
57 
58  return false;
59 }
60 
61 double CAddrInfo::GetChance(int64_t nNow) const
62 {
63  double fChance = 1.0;
64  int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
65 
66  // deprioritize very recent attempts away
67  if (nSinceLastTry < 60 * 10)
68  fChance *= 0.01;
69 
70  // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
71  fChance *= pow(0.66, std::min(nAttempts, 8));
72 
73  return fChance;
74 }
75 
76 CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
77 {
78  std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
79  if (it == mapAddr.end())
80  return nullptr;
81  if (pnId)
82  *pnId = (*it).second;
83  std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
84  if (it2 != mapInfo.end())
85  return &(*it2).second;
86  return nullptr;
87 }
88 
89 CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
90 {
91  int nId = nIdCount++;
92  mapInfo[nId] = CAddrInfo(addr, addrSource);
93  mapAddr[addr] = nId;
94  mapInfo[nId].nRandomPos = vRandom.size();
95  vRandom.push_back(nId);
96  if (pnId)
97  *pnId = nId;
98  return &mapInfo[nId];
99 }
100 
101 void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
102 {
103  if (nRndPos1 == nRndPos2)
104  return;
105 
106  assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
107 
108  int nId1 = vRandom[nRndPos1];
109  int nId2 = vRandom[nRndPos2];
110 
111  assert(mapInfo.count(nId1) == 1);
112  assert(mapInfo.count(nId2) == 1);
113 
114  mapInfo[nId1].nRandomPos = nRndPos2;
115  mapInfo[nId2].nRandomPos = nRndPos1;
116 
117  vRandom[nRndPos1] = nId2;
118  vRandom[nRndPos2] = nId1;
119 }
120 
121 void CAddrMan::Delete(int nId)
122 {
123  assert(mapInfo.count(nId) != 0);
124  CAddrInfo& info = mapInfo[nId];
125  assert(!info.fInTried);
126  assert(info.nRefCount == 0);
127 
128  SwapRandom(info.nRandomPos, vRandom.size() - 1);
129  vRandom.pop_back();
130  mapAddr.erase(info);
131  mapInfo.erase(nId);
132  nNew--;
133 }
134 
135 void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
136 {
137  // if there is an entry in the specified bucket, delete it.
138  if (vvNew[nUBucket][nUBucketPos] != -1) {
139  int nIdDelete = vvNew[nUBucket][nUBucketPos];
140  CAddrInfo& infoDelete = mapInfo[nIdDelete];
141  assert(infoDelete.nRefCount > 0);
142  infoDelete.nRefCount--;
143  vvNew[nUBucket][nUBucketPos] = -1;
144  if (infoDelete.nRefCount == 0) {
145  Delete(nIdDelete);
146  }
147  }
148 }
149 
150 void CAddrMan::MakeTried(CAddrInfo& info, int nId)
151 {
152  // remove the entry from all new buckets
153  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
154  int pos = info.GetBucketPosition(nKey, true, bucket);
155  if (vvNew[bucket][pos] == nId) {
156  vvNew[bucket][pos] = -1;
157  info.nRefCount--;
158  }
159  }
160  nNew--;
161 
162  assert(info.nRefCount == 0);
163 
164  // which tried bucket to move the entry to
165  int nKBucket = info.GetTriedBucket(nKey, m_asmap);
166  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
167 
168  // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
169  if (vvTried[nKBucket][nKBucketPos] != -1) {
170  // find an item to evict
171  int nIdEvict = vvTried[nKBucket][nKBucketPos];
172  assert(mapInfo.count(nIdEvict) == 1);
173  CAddrInfo& infoOld = mapInfo[nIdEvict];
174 
175  // Remove the to-be-evicted item from the tried set.
176  infoOld.fInTried = false;
177  vvTried[nKBucket][nKBucketPos] = -1;
178  nTried--;
179 
180  // find which new bucket it belongs to
181  int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
182  int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
183  ClearNew(nUBucket, nUBucketPos);
184  assert(vvNew[nUBucket][nUBucketPos] == -1);
185 
186  // Enter it into the new set again.
187  infoOld.nRefCount = 1;
188  vvNew[nUBucket][nUBucketPos] = nIdEvict;
189  nNew++;
190  }
191  assert(vvTried[nKBucket][nKBucketPos] == -1);
192 
193  vvTried[nKBucket][nKBucketPos] = nId;
194  nTried++;
195  info.fInTried = true;
196 }
197 
198 void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
199 {
200  int nId;
201 
202  nLastGood = nTime;
203 
204  CAddrInfo* pinfo = Find(addr, &nId);
205 
206  // if not found, bail out
207  if (!pinfo)
208  return;
209 
210  CAddrInfo& info = *pinfo;
211 
212  // check whether we are talking about the exact same CService (including same port)
213  if (info != addr)
214  return;
215 
216  // update info
217  info.nLastSuccess = nTime;
218  info.nLastTry = nTime;
219  info.nAttempts = 0;
220  // nTime is not updated here, to avoid leaking information about
221  // currently-connected peers.
222 
223  // if it is already in the tried set, don't do anything else
224  if (info.fInTried)
225  return;
226 
227  // find a bucket it is in now
229  int nUBucket = -1;
230  for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
231  int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
232  int nBpos = info.GetBucketPosition(nKey, true, nB);
233  if (vvNew[nB][nBpos] == nId) {
234  nUBucket = nB;
235  break;
236  }
237  }
238 
239  // if no bucket is found, something bad happened;
240  // TODO: maybe re-add the node, but for now, just bail out
241  if (nUBucket == -1)
242  return;
243 
244  // which tried bucket to move the entry to
245  int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
246  int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
247 
248  // Will moving this address into tried evict another entry?
249  if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
250  // Output the entry we'd be colliding with, for debugging purposes
251  auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
252  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());
254  m_tried_collisions.insert(nId);
255  }
256  } else {
257  LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
258 
259  // move nId to the tried tables
260  MakeTried(info, nId);
261  }
262 }
263 
264 bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
265 {
266  if (!addr.IsRoutable())
267  return false;
268 
269  bool fNew = false;
270  int nId;
271  CAddrInfo* pinfo = Find(addr, &nId);
272 
273  // Do not set a penalty for a source's self-announcement
274  if (addr == source) {
275  nTimePenalty = 0;
276  }
277 
278  if (pinfo) {
279  // periodically update nTime
280  bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
281  int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
282  if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
283  pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
284 
285  // add services
286  pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
287 
288  // do not update if no new information is present
289  if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
290  return false;
291 
292  // do not update if the entry was already in the "tried" table
293  if (pinfo->fInTried)
294  return false;
295 
296  // do not update if the max reference count is reached
298  return false;
299 
300  // stochastic test: previous nRefCount == N: 2^N times harder to increase it
301  int nFactor = 1;
302  for (int n = 0; n < pinfo->nRefCount; n++)
303  nFactor *= 2;
304  if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
305  return false;
306  } else {
307  pinfo = Create(addr, source, &nId);
308  pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
309  nNew++;
310  fNew = true;
311  }
312 
313  int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
314  int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
315  if (vvNew[nUBucket][nUBucketPos] != nId) {
316  bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
317  if (!fInsert) {
318  CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
319  if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
320  // Overwrite the existing new table entry.
321  fInsert = true;
322  }
323  }
324  if (fInsert) {
325  ClearNew(nUBucket, nUBucketPos);
326  pinfo->nRefCount++;
327  vvNew[nUBucket][nUBucketPos] = nId;
328  } else {
329  if (pinfo->nRefCount == 0) {
330  Delete(nId);
331  }
332  }
333  }
334  return fNew;
335 }
336 
337 void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
338 {
339  CAddrInfo* pinfo = Find(addr);
340 
341  // if not found, bail out
342  if (!pinfo)
343  return;
344 
345  CAddrInfo& info = *pinfo;
346 
347  // check whether we are talking about the exact same CService (including same port)
348  if (info != addr)
349  return;
350 
351  // update info
352  info.nLastTry = nTime;
353  if (fCountFailure && info.nLastCountAttempt < nLastGood) {
354  info.nLastCountAttempt = nTime;
355  info.nAttempts++;
356  }
357 }
358 
360 {
361  if (size() == 0)
362  return CAddrInfo();
363 
364  if (newOnly && nNew == 0)
365  return CAddrInfo();
366 
367  // Use a 50% chance for choosing between tried and new table entries.
368  if (!newOnly &&
369  (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
370  // use a tried node
371  double fChanceFactor = 1.0;
372  while (1) {
374  int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
375  while (vvTried[nKBucket][nKBucketPos] == -1) {
377  nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
378  }
379  int nId = vvTried[nKBucket][nKBucketPos];
380  assert(mapInfo.count(nId) == 1);
381  CAddrInfo& info = mapInfo[nId];
382  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
383  return info;
384  fChanceFactor *= 1.2;
385  }
386  } else {
387  // use a new node
388  double fChanceFactor = 1.0;
389  while (1) {
391  int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
392  while (vvNew[nUBucket][nUBucketPos] == -1) {
394  nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
395  }
396  int nId = vvNew[nUBucket][nUBucketPos];
397  assert(mapInfo.count(nId) == 1);
398  CAddrInfo& info = mapInfo[nId];
399  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
400  return info;
401  fChanceFactor *= 1.2;
402  }
403  }
404 }
405 
406 #ifdef DEBUG_ADDRMAN
407 int CAddrMan::Check_()
408 {
409  std::set<int> setTried;
410  std::map<int, int> mapNew;
411 
412  if (vRandom.size() != (size_t)(nTried + nNew))
413  return -7;
414 
415  for (const auto& entry : mapInfo) {
416  int n = entry.first;
417  const CAddrInfo& info = entry.second;
418  if (info.fInTried) {
419  if (!info.nLastSuccess)
420  return -1;
421  if (info.nRefCount)
422  return -2;
423  setTried.insert(n);
424  } else {
425  if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
426  return -3;
427  if (!info.nRefCount)
428  return -4;
429  mapNew[n] = info.nRefCount;
430  }
431  if (mapAddr[info] != n)
432  return -5;
433  if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
434  return -14;
435  if (info.nLastTry < 0)
436  return -6;
437  if (info.nLastSuccess < 0)
438  return -8;
439  }
440 
441  if (setTried.size() != (size_t)nTried)
442  return -9;
443  if (mapNew.size() != (size_t)nNew)
444  return -10;
445 
446  for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
447  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
448  if (vvTried[n][i] != -1) {
449  if (!setTried.count(vvTried[n][i]))
450  return -11;
451  if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n)
452  return -17;
453  if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
454  return -18;
455  setTried.erase(vvTried[n][i]);
456  }
457  }
458  }
459 
460  for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
461  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
462  if (vvNew[n][i] != -1) {
463  if (!mapNew.count(vvNew[n][i]))
464  return -12;
465  if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
466  return -19;
467  if (--mapNew[vvNew[n][i]] == 0)
468  mapNew.erase(vvNew[n][i]);
469  }
470  }
471  }
472 
473  if (setTried.size())
474  return -13;
475  if (mapNew.size())
476  return -15;
477  if (nKey.IsNull())
478  return -16;
479 
480  return 0;
481 }
482 #endif
483 
484 void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct)
485 {
486  size_t nNodes = vRandom.size();
487  if (max_pct != 0) {
488  nNodes = max_pct * nNodes / 100;
489  }
490  if (max_addresses != 0) {
491  nNodes = std::min(nNodes, max_addresses);
492  }
493 
494  // gather a list of random nodes, skipping those of low quality
495  for (unsigned int n = 0; n < vRandom.size(); n++) {
496  if (vAddr.size() >= nNodes)
497  break;
498 
499  int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
500  SwapRandom(n, nRndPos);
501  assert(mapInfo.count(vRandom[n]) == 1);
502 
503  const CAddrInfo& ai = mapInfo[vRandom[n]];
504  if (!ai.IsTerrible())
505  vAddr.push_back(ai);
506  }
507 }
508 
509 void CAddrMan::Connected_(const CService& addr, int64_t nTime)
510 {
511  CAddrInfo* pinfo = Find(addr);
512 
513  // if not found, bail out
514  if (!pinfo)
515  return;
516 
517  CAddrInfo& info = *pinfo;
518 
519  // check whether we are talking about the exact same CService (including same port)
520  if (info != addr)
521  return;
522 
523  // update info
524  int64_t nUpdateInterval = 20 * 60;
525  if (nTime - info.nTime > nUpdateInterval)
526  info.nTime = nTime;
527 }
528 
529 void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
530 {
531  CAddrInfo* pinfo = Find(addr);
532 
533  // if not found, bail out
534  if (!pinfo)
535  return;
536 
537  CAddrInfo& info = *pinfo;
538 
539  // check whether we are talking about the exact same CService (including same port)
540  if (info != addr)
541  return;
542 
543  // update info
544  info.nServices = nServices;
545 }
546 
548 {
549  for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
550  int id_new = *it;
551 
552  bool erase_collision = false;
553 
554  // If id_new not found in mapInfo remove it from m_tried_collisions
555  if (mapInfo.count(id_new) != 1) {
556  erase_collision = true;
557  } else {
558  CAddrInfo& info_new = mapInfo[id_new];
559 
560  // Which tried bucket to move the entry to.
561  int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
562  int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
563  if (!info_new.IsValid()) { // id_new may no longer map to a valid address
564  erase_collision = true;
565  } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
566 
567  // Get the to-be-evicted address that is being tested
568  int id_old = vvTried[tried_bucket][tried_bucket_pos];
569  CAddrInfo& info_old = mapInfo[id_old];
570 
571  // Has successfully connected in last X hours
572  if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
573  erase_collision = true;
574  } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
575 
576  // Give address at least 60 seconds to successfully connect
577  if (GetAdjustedTime() - info_old.nLastTry > 60) {
578  LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
579 
580  // Replaces an existing address already in the tried table with the new address
581  Good_(info_new, false, GetAdjustedTime());
582  erase_collision = true;
583  }
584  } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
585  // If the collision hasn't resolved in some reasonable amount of time,
586  // just evict the old entry -- we must not be able to
587  // connect to it for some reason.
588  LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
589  Good_(info_new, false, GetAdjustedTime());
590  erase_collision = true;
591  }
592  } else { // Collision is not actually a collision anymore
593  Good_(info_new, false, GetAdjustedTime());
594  erase_collision = true;
595  }
596  }
597 
598  if (erase_collision) {
599  m_tried_collisions.erase(it++);
600  } else {
601  it++;
602  }
603  }
604 }
605 
607 {
608  if (m_tried_collisions.size() == 0) return CAddrInfo();
609 
610  std::set<int>::iterator it = m_tried_collisions.begin();
611 
612  // Selects a random element from m_tried_collisions
613  std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
614  int id_new = *it;
615 
616  // If id_new not found in mapInfo remove it from m_tried_collisions
617  if (mapInfo.count(id_new) != 1) {
618  m_tried_collisions.erase(it);
619  return CAddrInfo();
620  }
621 
622  const CAddrInfo& newInfo = mapInfo[id_new];
623 
624  // which tried bucket to move the entry to
625  int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
626  int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
627 
628  int id_old = vvTried[tried_bucket][tried_bucket_pos];
629 
630  return mapInfo[id_old];
631 }
632 
633 std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
634 {
635  std::vector<bool> bits;
636  FILE *filestr = fsbridge::fopen(path, "rb");
637  CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
638  if (file.IsNull()) {
639  LogPrintf("Failed to open asmap file from disk\n");
640  return bits;
641  }
642  fseek(filestr, 0, SEEK_END);
643  int length = ftell(filestr);
644  LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
645  fseek(filestr, 0, SEEK_SET);
646  char cur_byte;
647  for (int i = 0; i < length; ++i) {
648  file >> cur_byte;
649  for (int bit = 0; bit < 8; ++bit) {
650  bits.push_back((cur_byte >> bit) & 1);
651  }
652  }
653  if (!SanityCheckASMap(bits)) {
654  LogPrintf("Sanity check of asmap file %s failed\n", path);
655  return {};
656  }
657  return bits;
658 }
CAddrMan::Create
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
find an entry, creating it if necessary.
Definition: addrman.cpp:89
CService
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:551
CAddrMan::nKey
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:234
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:24
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:198
ADDRMAN_MIN_FAIL_DAYS
#define ADDRMAN_MIN_FAIL_DAYS
... in at least this many days
Definition: addrman.h:153
ADDRMAN_REPLACEMENT_HOURS
#define ADDRMAN_REPLACEMENT_HOURS
how recent a successful connection should be before we allow an address to be evicted from tried
Definition: addrman.h:156
CNetAddr::GetGroup
std::vector< unsigned char > GetGroup(const std::vector< bool > &asmap) const
Get the canonical identifier of our network group.
Definition: netaddress.cpp:757
SER_DISK
@ SER_DISK
Definition: serialize.h:167
ADDRMAN_MAX_FAILURES
#define ADDRMAN_MAX_FAILURES
how many successive failures are allowed ...
Definition: addrman.h:150
ADDRMAN_TEST_WINDOW
static const int64_t ADDRMAN_TEST_WINDOW
the maximum time we'll spend trying to resolve a tried table collision, in seconds
Definition: addrman.h:167
ADDRMAN_TRIED_BUCKET_COUNT_LOG2
#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2
Stochastic address manager.
Definition: addrman.h:126
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:264
ADDRMAN_TRIED_BUCKETS_PER_GROUP
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP
over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
Definition: addrman.h:135
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:230
CAddrMan::SwapRandom
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
Definition: addrman.cpp:101
fsbridge::fopen
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:24
ADDRMAN_NEW_BUCKETS_PER_ADDRESS
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
Definition: addrman.h:141
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:121
ADDRMAN_SET_TRIED_COLLISION_SIZE
#define ADDRMAN_SET_TRIED_COLLISION_SIZE
the maximum number of tried addr collisions to store
Definition: addrman.h:164
FastRandomContext::randbool
bool randbool() noexcept
Generate a random boolean.
Definition: random.h:211
CNetAddr
Network address.
Definition: netaddress.h:119
source
const char * source
Definition: rpcconsole.cpp:57
CAddrInfo::nLastSuccess
int64_t nLastSuccess
last successful connection by us
Definition: addrman.h:45
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:61
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:547
ServiceFlags
ServiceFlags
nServices flags
Definition: protocol.h:269
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:41
CAddress::nServices
ServiceFlags nServices
Definition: protocol.h:396
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:337
CAddress::nTime
uint32_t nTime
Definition: protocol.h:394
ADDRMAN_NEW_BUCKET_COUNT_LOG2
#define ADDRMAN_NEW_BUCKET_COUNT_LOG2
total number of buckets for new addresses
Definition: addrman.h:129
ADDRMAN_RETRIES
#define ADDRMAN_RETRIES
after how many failed attempts we give up on a new node
Definition: addrman.h:147
SanityCheckASMap
bool SanityCheckASMap(const std::vector< bool > &asmap)
Definition: netaddress.cpp:1237
CAddrMan::SetServices_
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Update an entry's service bits.
Definition: addrman.cpp:529
FastRandomContext::randbits
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:172
CNetAddr::ToStringIP
std::string ToStringIP() const
Definition: netaddress.cpp:570
CAutoFile
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:564
CAddrInfo
Extended statistics about a CAddress.
Definition: addrman.h:31
CAddrInfo::nLastCountAttempt
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:38
CService::ToString
std::string ToString() const
Definition: netaddress.cpp:1028
CAddrMan::SelectTriedCollision_
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Return a random to-be-evicted tried table address.
Definition: addrman.cpp:606
ADDRMAN_BUCKET_SIZE
#define ADDRMAN_BUCKET_SIZE
Definition: addrman.h:161
ADDRMAN_TRIED_BUCKET_COUNT
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
Definition: addrman.h:159
CNetAddr::IsRoutable
bool IsRoutable() const
Definition: netaddress.cpp:508
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:135
CAddrInfo::nRefCount
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:51
CNetAddr::GetMappedAS
uint32_t GetMappedAS(const std::vector< bool > &asmap) const
Definition: netaddress.cpp:716
LogPrintf
#define LogPrintf(...)
Definition: logging.h:183
CAddrMan::insecure_rand
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:237
CNetAddr::IsValid
bool IsValid() const
Definition: netaddress.cpp:469
CAddrInfo::nRandomPos
int nRandomPos
position in vRandom
Definition: addrman.h:57
CAddrInfo::nLastTry
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman.h:35
CAutoFile::IsNull
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:609
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:35
uint256
256-bit opaque blob.
Definition: uint256.h:124
LogPrint
#define LogPrint(category,...)
Definition: logging.h:187
ADDRMAN_NEW_BUCKET_COUNT
#define ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman.h:160
ADDRMAN_BUCKET_SIZE_LOG2
#define ADDRMAN_BUCKET_SIZE_LOG2
maximum allowed number of entries in buckets for new and tried addresses
Definition: addrman.h:132
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:150
CAddrInfo::GetTriedBucket
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:14
CAddrMan::Connected_
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
We have successfully connected to this peer.
Definition: addrman.cpp:509
CAddrMan::Select_
CAddrInfo Select_(bool newOnly) 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:359
CAddrMan::m_asmap
std::vector< bool > m_asmap
Definition: addrman.h:315
GetAdjustedTime
int64_t GetAdjustedTime()
Definition: timedata.cpp:34
base_blob::IsNull
bool IsNull() const
Definition: uint256.h:31
CAddress
A CService with information about it as peer.
Definition: protocol.h:356
CAddrInfo::nAttempts
int nAttempts
connection attempts since last successful attempt
Definition: addrman.h:48
CLIENT_VERSION
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
CHashWriter
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
logging.h
FastRandomContext::randrange
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
Definition: random.h:190
hash.h
serialize.h
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:76
CAddrInfo::fInTried
bool fInTried
in tried set? (memory only)
Definition: addrman.h:54
CAddrMan::size
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:615
ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
over how many buckets entries with new addresses originating from a single group are spread
Definition: addrman.h:138
ADDRMAN_HORIZON_DAYS
#define ADDRMAN_HORIZON_DAYS
how old addresses can maximally be
Definition: addrman.h:144
BCLog::NET
@ NET
Definition: logging.h:38
CAddrMan::DecodeAsmap
static std::vector< bool > DecodeAsmap(fs::path path)
Definition: addrman.cpp:633
assert
assert(std::addressof(::ChainstateActive().CoinsTip())==std::addressof(coins_cache))
CAddrMan::GetAddr_
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs)
Select several addresses at once.
Definition: addrman.cpp:484
SER_GETHASH
@ SER_GETHASH
Definition: serialize.h:168
it
auto it
Definition: validation.cpp:398
CService::GetKey
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:1006