PIVX Core  5.6.99
P2P Digital Currency
addrman.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012 Pieter Wuille
2 // Copyright (c) 2012-2014 The Bitcoin developers
3 // Copyright (c) 2017-2021 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "addrman.h"
8 
9 #include "hash.h"
10 #include "logging.h"
11 #include "netaddress.h"
12 #include "optional.h"
13 #include "streams.h"
14 #include "serialize.h"
15 
16 
17 int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
18 {
19  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash();
20  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash();
21  int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
22  uint32_t mapped_as = GetMappedAS(asmap);
23  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
24  return tried_bucket;
25 }
26 
27 int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
28 {
29  std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
30  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetHash().GetCheapHash();
31  uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash();
32  int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
33  uint32_t mapped_as = GetMappedAS(asmap);
34  LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
35  return new_bucket;
36 }
37 
38 int CAddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
39 {
40  uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash();
41  return hash1 % ADDRMAN_BUCKET_SIZE;
42 }
43 
44 bool CAddrInfo::IsTerrible(int64_t nNow) const
45 {
46  if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
47  return false;
48 
49  if (nTime > nNow + 10 * 60) // came in a flying DeLorean
50  return true;
51 
52  if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
53  return true;
54 
55  if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
56  return true;
57 
58  if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
59  return true;
60 
61  return false;
62 }
63 
64 double CAddrInfo::GetChance(int64_t nNow) const
65 {
66  double fChance = 1.0;
67  int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
68 
69  // deprioritize very recent attempts away
70  if (nSinceLastTry < 60 * 10)
71  fChance *= 0.01;
72 
73  // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
74  fChance *= pow(0.66, std::min(nAttempts, 8));
75 
76  return fChance;
77 }
78 
79 CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
80 {
81  std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
82  if (it == mapAddr.end())
83  return nullptr;
84  if (pnId)
85  *pnId = (*it).second;
86  std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
87  if (it2 != mapInfo.end())
88  return &(*it2).second;
89  return nullptr;
90 }
91 
92 CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
93 {
94  int nId = nIdCount++;
95  mapInfo[nId] = CAddrInfo(addr, addrSource);
96  mapAddr[addr] = nId;
97  mapInfo[nId].nRandomPos = vRandom.size();
98  vRandom.push_back(nId);
99  if (pnId)
100  *pnId = nId;
101  return &mapInfo[nId];
102 }
103 
104 void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
105 {
106  if (nRndPos1 == nRndPos2)
107  return;
108 
109  assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
110 
111  int nId1 = vRandom[nRndPos1];
112  int nId2 = vRandom[nRndPos2];
113 
114  assert(mapInfo.count(nId1) == 1);
115  assert(mapInfo.count(nId2) == 1);
116 
117  mapInfo[nId1].nRandomPos = nRndPos2;
118  mapInfo[nId2].nRandomPos = nRndPos1;
119 
120  vRandom[nRndPos1] = nId2;
121  vRandom[nRndPos2] = nId1;
122 }
123 
124 void CAddrMan::Delete(int nId)
125 {
126  assert(mapInfo.count(nId) != 0);
127  CAddrInfo& info = mapInfo[nId];
128  assert(!info.fInTried);
129  assert(info.nRefCount == 0);
130 
131  SwapRandom(info.nRandomPos, vRandom.size() - 1);
132  vRandom.pop_back();
133  mapAddr.erase(info);
134  mapInfo.erase(nId);
135  nNew--;
136 }
137 
138 void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
139 {
140  // if there is an entry in the specified bucket, delete it.
141  if (vvNew[nUBucket][nUBucketPos] != -1) {
142  int nIdDelete = vvNew[nUBucket][nUBucketPos];
143  CAddrInfo& infoDelete = mapInfo[nIdDelete];
144  assert(infoDelete.nRefCount > 0);
145  infoDelete.nRefCount--;
146  vvNew[nUBucket][nUBucketPos] = -1;
147  if (infoDelete.nRefCount == 0) {
148  Delete(nIdDelete);
149  }
150  }
151 }
152 
153 void CAddrMan::MakeTried(CAddrInfo& info, int nId)
154 {
155  // remove the entry from all new buckets
156  const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
157  for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
158  const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
159  const int pos{info.GetBucketPosition(nKey, true, bucket)};
160  if (vvNew[bucket][pos] == nId) {
161  vvNew[bucket][pos] = -1;
162  info.nRefCount--;
163  if (info.nRefCount == 0) break;
164  }
165  }
166  nNew--;
167 
168  assert(info.nRefCount == 0);
169 
170  // which tried bucket to move the entry to
171  int nKBucket = info.GetTriedBucket(nKey, m_asmap);
172  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
173 
174  // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
175  if (vvTried[nKBucket][nKBucketPos] != -1) {
176  // find an item to evict
177  int nIdEvict = vvTried[nKBucket][nKBucketPos];
178  assert(mapInfo.count(nIdEvict) == 1);
179  CAddrInfo& infoOld = mapInfo[nIdEvict];
180 
181  // Remove the to-be-evicted item from the tried set.
182  infoOld.fInTried = false;
183  vvTried[nKBucket][nKBucketPos] = -1;
184  nTried--;
185 
186  // find which new bucket it belongs to
187  int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
188  int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
189  ClearNew(nUBucket, nUBucketPos);
190  assert(vvNew[nUBucket][nUBucketPos] == -1);
191 
192  // Enter it into the new set again.
193  infoOld.nRefCount = 1;
194  vvNew[nUBucket][nUBucketPos] = nIdEvict;
195  nNew++;
196  }
197  assert(vvTried[nKBucket][nKBucketPos] == -1);
198 
199  vvTried[nKBucket][nKBucketPos] = nId;
200  nTried++;
201  info.fInTried = true;
202 }
203 
204 void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
205 {
206  int nId;
207 
208  nLastGood = nTime;
209 
210  CAddrInfo* pinfo = Find(addr, &nId);
211 
212  // if not found, bail out
213  if (!pinfo)
214  return;
215 
216  CAddrInfo& info = *pinfo;
217 
218  // check whether we are talking about the exact same CService (including same port)
219  if (info != addr)
220  return;
221 
222  // update info
223  info.nLastSuccess = nTime;
224  info.nLastTry = nTime;
225  info.nAttempts = 0;
226  // nTime is not updated here, to avoid leaking information about
227  // currently-connected peers.
228 
229  // if it is already in the tried set, don't do anything else
230  if (info.fInTried)
231  return;
232 
233  // if it is not in new, something bad happened
234  if (info.nRefCount <= 0) {
235  return;
236  }
237 
238  // which tried bucket to move the entry to
239  int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
240  int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
241 
242  // Will moving this address into tried evict another entry?
243  if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
244  // Output the entry we'd be colliding with, for debugging purposes
245  auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
246  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());
248  m_tried_collisions.insert(nId);
249  }
250  } else {
251  LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
252 
253  // move nId to the tried tables
254  MakeTried(info, nId);
255  }
256 }
257 
258 bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
259 {
260  if (!addr.IsRoutable())
261  return false;
262 
263  bool fNew = false;
264  int nId;
265  CAddrInfo* pinfo = Find(addr, &nId);
266 
267  // Do not set a penalty for a source's self-announcement
268  if (addr == source) {
269  nTimePenalty = 0;
270  }
271 
272  if (pinfo) {
273  // periodically update nTime
274  bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
275  int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
276  if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
277  pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
278 
279  // add services
280  pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
281 
282  // do not update if no new information is present
283  if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
284  return false;
285 
286  // do not update if the entry was already in the "tried" table
287  if (pinfo->fInTried)
288  return false;
289 
290  // do not update if the max reference count is reached
292  return false;
293 
294  // stochastic test: previous nRefCount == N: 2^N times harder to increase it
295  int nFactor = 1;
296  for (int n = 0; n < pinfo->nRefCount; n++)
297  nFactor *= 2;
298  if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
299  return false;
300  } else {
301  pinfo = Create(addr, source, &nId);
302  pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
303  nNew++;
304  fNew = true;
305  }
306 
307  int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
308  int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
309  if (vvNew[nUBucket][nUBucketPos] != nId) {
310  bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
311  if (!fInsert) {
312  CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
313  if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
314  // Overwrite the existing new table entry.
315  fInsert = true;
316  }
317  }
318  if (fInsert) {
319  ClearNew(nUBucket, nUBucketPos);
320  pinfo->nRefCount++;
321  vvNew[nUBucket][nUBucketPos] = nId;
322  } else {
323  if (pinfo->nRefCount == 0) {
324  Delete(nId);
325  }
326  }
327  }
328  return fNew;
329 }
330 
331 void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
332 {
333  CAddrInfo* pinfo = Find(addr);
334 
335  // if not found, bail out
336  if (!pinfo)
337  return;
338 
339  CAddrInfo& info = *pinfo;
340 
341  // check whether we are talking about the exact same CService (including same port)
342  if (info != addr)
343  return;
344 
345  // update info
346  info.nLastTry = nTime;
347  if (fCountFailure && info.nLastCountAttempt < nLastGood) {
348  info.nLastCountAttempt = nTime;
349  info.nAttempts++;
350  }
351 }
352 
354 {
355  if (size() == 0)
356  return CAddrInfo();
357 
358  if (newOnly && nNew == 0)
359  return CAddrInfo();
360 
361  // Use a 50% chance for choosing between tried and new table entries.
362  if (!newOnly && (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
363  // use a tried node
364  double fChanceFactor = 1.0;
365  while (1) {
367  int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
368  while (vvTried[nKBucket][nKBucketPos] == -1) {
370  nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
371  }
372  int nId = vvTried[nKBucket][nKBucketPos];
373  assert(mapInfo.count(nId) == 1);
374  CAddrInfo& info = mapInfo[nId];
375  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
376  return info;
377  fChanceFactor *= 1.2;
378  }
379  } else {
380  // use a new node
381  double fChanceFactor = 1.0;
382  while (1) {
384  int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
385  while (vvNew[nUBucket][nUBucketPos] == -1) {
387  nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
388  }
389  int nId = vvNew[nUBucket][nUBucketPos];
390  assert(mapInfo.count(nId) == 1);
391  CAddrInfo& info = mapInfo[nId];
392  if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
393  return info;
394  fChanceFactor *= 1.2;
395  }
396  }
397 }
398 
399 #ifdef DEBUG_ADDRMAN
400 int CAddrMan::Check_()
401 {
402  std::set<int> setTried;
403  std::map<int, int> mapNew;
404 
405  if (vRandom.size() != nTried + nNew)
406  return -7;
407 
408  for (const auto& entry : mapInfo) {
409  int n = entry.first;
410  const CAddrInfo& info = entry.second;
411  if (info.fInTried) {
412  if (!info.nLastSuccess)
413  return -1;
414  if (info.nRefCount)
415  return -2;
416  setTried.insert(n);
417  } else {
418  if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
419  return -3;
420  if (!info.nRefCount)
421  return -4;
422  mapNew[n] = info.nRefCount;
423  }
424  if (mapAddr[info] != n)
425  return -5;
426  if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
427  return -14;
428  if (info.nLastTry < 0)
429  return -6;
430  if (info.nLastSuccess < 0)
431  return -8;
432  }
433 
434  if (setTried.size() != nTried)
435  return -9;
436  if (mapNew.size() != nNew)
437  return -10;
438 
439  for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
440  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
441  if (vvTried[n][i] != -1) {
442  if (!setTried.count(vvTried[n][i]))
443  return -11;
444  if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n)
445  return -17;
446  if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
447  return -18;
448  setTried.erase(vvTried[n][i]);
449  }
450  }
451  }
452 
453  for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
454  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
455  if (vvNew[n][i] != -1) {
456  if (!mapNew.count(vvNew[n][i]))
457  return -12;
458  if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
459  return -19;
460  if (--mapNew[vvNew[n][i]] == 0)
461  mapNew.erase(vvNew[n][i]);
462  }
463  }
464  }
465 
466  if (setTried.size())
467  return -13;
468  if (mapNew.size())
469  return -15;
470  if (nKey.IsNull())
471  return -16;
472 
473  return 0;
474 }
475 #endif
476 
477 void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, Optional<Network> network)
478 {
479  size_t nNodes = vRandom.size();
480  if (max_pct != 0) {
481  nNodes = max_pct * nNodes / 100;
482  }
483  if (max_addresses != 0) {
484  nNodes = std::min(nNodes, max_addresses);
485  }
486 
487  // gather a list of random nodes, skipping those of low quality
488  const int64_t now{GetAdjustedTime()};
489  for (unsigned int n = 0; n < vRandom.size(); n++) {
490  if (vAddr.size() >= nNodes)
491  break;
492 
493  int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
494  SwapRandom(n, nRndPos);
495  assert(mapInfo.count(vRandom[n]) == 1);
496 
497  const CAddrInfo& ai = mapInfo[vRandom[n]];
498 
499  // Filter by network (optional)
500  if (network != nullopt && ai.GetNetClass() != network) continue;
501 
502  // Filter for quality
503  if (ai.IsTerrible(now)) continue;
504 
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  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  return bits;
654 }
#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:143
#define ADDRMAN_SET_TRIED_COLLISION_SIZE
the maximum number of tried addr collisions to store
Definition: addrman.h:169
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
Definition: addrman.h:146
#define ADDRMAN_MAX_FAILURES
how many successive failures are allowed ...
Definition: addrman.h:155
#define ADDRMAN_BUCKET_SIZE
Definition: addrman.h:166
#define ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman.h:165
#define ADDRMAN_RETRIES
after how many failed attempts we give up on a new node
Definition: addrman.h:152
#define ADDRMAN_MIN_FAIL_DAYS
... in at least this many days
Definition: addrman.h:158
#define ADDRMAN_HORIZON_DAYS
how old addresses can maximally be
Definition: addrman.h:149
#define ADDRMAN_BUCKET_SIZE_LOG2
maximum allowed number of entries in buckets for new and tried addresses
Definition: addrman.h:137
#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:140
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
Definition: addrman.h:164
#define ADDRMAN_REPLACEMENT_HOURS
how recent a successful connection should be before we allow an address to be evicted from tried
Definition: addrman.h:161
#define ADDRMAN_NEW_BUCKET_COUNT_LOG2
total number of buckets for new addresses
Definition: addrman.h:134
#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2
Stochastic address manager.
Definition: addrman.h:131
Extended statistics about a CAddress.
Definition: addrman.h:37
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:17
int nAttempts
connection attempts since last successful attempt
Definition: addrman.h:53
int64_t nLastSuccess
last successful connection by us
Definition: addrman.h:50
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
Calculate in which position of a bucket to store this entry.
Definition: addrman.cpp:38
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:43
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman.h:40
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:44
int nRandomPos
position in vRandom
Definition: addrman.h:62
bool fInTried
in tried set? (memory only)
Definition: addrman.h:59
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:27
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:56
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:64
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
Definition: addrman.cpp:124
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:258
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:242
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:92
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:603
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs)
Return a random to-be-evicted tried table address.
Definition: addrman.cpp:606
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs)
Swap two elements in vRandom.
Definition: addrman.cpp:104
std::set< int > m_tried_collisions
Holds addrs inserted into tried table that collide with existing entries. Test-before-evict disciplin...
Definition: addrman.h:235
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
Definition: addrman.cpp:79
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:138
void GetAddr_(std::vector< CAddress > &vAddr, size_t max_addresses, size_t max_pct, Optional< Network > network) EXCLUSIVE_LOCKS_REQUIRED(cs)
Return all or many randomly selected addresses, optionally by network.
Definition: addrman.cpp:477
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as attempted to connect.
Definition: addrman.cpp:331
std::vector< bool > m_asmap
Definition: addrman.h:317
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:204
static std::vector< bool > DecodeAsmap(fs::path path)
Definition: addrman.cpp:633
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs)
Update an entry's service bits.
Definition: addrman.cpp:529
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:239
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry as currently-connected-to.
Definition: addrman.cpp:509
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:353
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:153
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
A CService with information about it as peer.
Definition: protocol.h:338
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
Definition: protocol.h:430
uint32_t nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
Definition: protocol.h:428
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:452
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:501
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:216
Network address.
Definition: netaddress.h:120
Network GetNetClass() const
Definition: netaddress.cpp:639
std::string ToStringIP() const
Definition: netaddress.cpp:516
bool IsRoutable() const
Definition: netaddress.cpp:454
bool IsValid() const
Definition: netaddress.cpp:418
uint64_t GetHash() const
Definition: netaddress.cpp:762
std::vector< unsigned char > GetGroup(const std::vector< bool > &asmap) const
Get the canonical identifier of our network group.
Definition: netaddress.cpp:698
uint32_t GetMappedAS(const std::vector< bool > &asmap) const
Definition: netaddress.cpp:657
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:484
std::string ToString() const
Definition: netaddress.cpp:954
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:932
bool randbool() noexcept
Generate a random boolean.
Definition: random.h:197
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:159
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
Definition: random.h:174
bool IsNull() const
Definition: uint256.h:36
256-bit opaque blob.
Definition: uint256.h:138
#define LogPrint(category,...)
Definition: logging.h:163
@ ADDRMAN
Definition: logging.h:50
@ NET
Definition: logging.h:41
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:23
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
ServiceFlags
nServices flags
Definition: protocol.h:312
const char * source
Definition: rpcconsole.cpp:52
@ SER_DISK
Definition: serialize.h:175
@ SER_GETHASH
Definition: serialize.h:176
int64_t GetAdjustedTime()
Definition: timedata.cpp:36