Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

addrman.h
Go to the documentation of this file.
1 // Copyright (c) 2012 Pieter Wuille
2 // Copyright (c) 2012-2015 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 #ifndef BITCOIN_ADDRMAN_H
7 #define BITCOIN_ADDRMAN_H
8 
9 #include <netaddress.h>
10 #include <protocol.h>
11 #include <random.h>
12 #include <sync.h>
13 #include <timedata.h>
14 #include <util.h>
15 
16 #include <map>
17 #include <set>
18 #include <stdint.h>
19 #include <vector>
20 
24 class CAddrInfo : public CAddress
25 {
26 
27 
28 public:
30  int64_t nLastTry;
31 
34 
35 private:
38 
40  int64_t nLastSuccess;
41 
43  int nAttempts;
44 
46  int nRefCount;
47 
49  bool fInTried;
50 
53 
54  friend class CAddrMan;
55 
56 public:
57 
59 
60  template <typename Stream, typename Operation>
61  inline void SerializationOp(Stream& s, Operation ser_action) {
62  READWRITE(*(CAddress*)this);
66  }
67 
68  void Init()
69  {
70  nLastSuccess = 0;
71  nLastTry = 0;
73  nAttempts = 0;
74  nRefCount = 0;
75  fInTried = false;
76  nRandomPos = -1;
77  }
78 
79  CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
80  {
81  Init();
82  }
83 
85  {
86  Init();
87  }
88 
90  int GetTriedBucket(const uint256 &nKey) const;
91 
93  int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const;
94 
96  int GetNewBucket(const uint256 &nKey) const
97  {
98  return GetNewBucket(nKey, source);
99  }
100 
102  int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
103 
105  bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
106 
108  double GetChance(int64_t nNow = GetAdjustedTime()) const;
109 
110 };
111 
138 #define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
140 
142 #define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
143 
145 #define ADDRMAN_BUCKET_SIZE_LOG2 6
146 
148 #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
149 
151 #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
152 
154 #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
155 
157 #define ADDRMAN_HORIZON_DAYS 30
158 
160 #define ADDRMAN_RETRIES 3
161 
163 #define ADDRMAN_MAX_FAILURES 10
164 
166 #define ADDRMAN_MIN_FAIL_DAYS 7
167 
169 #define ADDRMAN_GETADDR_MAX_PCT 23
170 
172 #define ADDRMAN_GETADDR_MAX 2500
173 
175 #define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
176 #define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
177 #define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
178 
182 class CAddrMan
183 {
184 private:
187 
189  int nIdCount;
190 
192  std::map<int, CAddrInfo> mapInfo;
193 
195  std::map<CService, int> mapAddr;
196 
198  std::vector<int> vRandom;
199 
200  // number of "tried" entries
201  int nTried;
202 
205 
207  int nNew;
208 
211 
213  int64_t nLastGood;
214 
215  // discriminate entries based on port. Should be false on mainnet/testnet and can be true on devnet/regtest
217 
218 protected:
221 
224 
226  CAddrInfo* Find(const CService& addr, int *pnId = nullptr);
227 
230  CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr);
231 
233  void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
234 
236  void MakeTried(CAddrInfo& info, int nId);
237 
239  void Delete(int nId);
240 
242  void ClearNew(int nUBucket, int nUBucketPos);
243 
245  void Good_(const CService &addr, int64_t nTime);
246 
248  bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
249 
251  void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);
252 
254  CAddrInfo Select_(bool newOnly);
255 
257  virtual int RandomInt(int nMax);
258 
259 #ifdef DEBUG_ADDRMAN
260  int Check_();
262 #endif
263 
265  void GetAddr_(std::vector<CAddress> &vAddr);
266 
268  void Connected_(const CService &addr, int64_t nTime);
269 
271  void SetServices_(const CService &addr, ServiceFlags nServices);
272 
274  CAddrInfo GetAddressInfo_(const CService& addr);
275 
276 public:
306  template<typename Stream>
307  void Serialize(Stream &s) const
308  {
309  LOCK(cs);
310 
311  unsigned char nVersion = 1;
312  s << nVersion;
313  s << ((unsigned char)32);
314  s << nKey;
315  s << nNew;
316  s << nTried;
317 
318  int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
319  s << nUBuckets;
320  std::map<int, int> mapUnkIds;
321  int nIds = 0;
322  for (const auto& entry : mapInfo) {
323  mapUnkIds[entry.first] = nIds;
324  const CAddrInfo &info = entry.second;
325  if (info.nRefCount) {
326  assert(nIds != nNew); // this means nNew was wrong, oh ow
327  s << info;
328  nIds++;
329  }
330  }
331  nIds = 0;
332  for (const auto& entry : mapInfo) {
333  const CAddrInfo &info = entry.second;
334  if (info.fInTried) {
335  assert(nIds != nTried); // this means nTried was wrong, oh ow
336  s << info;
337  nIds++;
338  }
339  }
340  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
341  int nSize = 0;
342  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
343  if (vvNew[bucket][i] != -1)
344  nSize++;
345  }
346  s << nSize;
347  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
348  if (vvNew[bucket][i] != -1) {
349  int nIndex = mapUnkIds[vvNew[bucket][i]];
350  s << nIndex;
351  }
352  }
353  }
354  }
355 
356  template<typename Stream>
357  void Unserialize(Stream& s)
358  {
359  LOCK(cs);
360 
361  Clear();
362 
363  unsigned char nVersion;
364  s >> nVersion;
365  unsigned char nKeySize;
366  s >> nKeySize;
367  if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
368  s >> nKey;
369  s >> nNew;
370  s >> nTried;
371  int nUBuckets = 0;
372  s >> nUBuckets;
373  if (nVersion != 0) {
374  nUBuckets ^= (1 << 30);
375  }
376 
378  throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
379  }
380 
382  throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
383  }
384 
385  // Deserialize entries from the new table.
386  for (int n = 0; n < nNew; n++) {
387  CAddrInfo &info = mapInfo[n];
388  s >> info;
389  mapAddr[info] = n;
390  info.nRandomPos = vRandom.size();
391  vRandom.push_back(n);
392  if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
393  // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
394  // immediately try to give them a reference based on their primary source address.
395  int nUBucket = info.GetNewBucket(nKey);
396  int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
397  if (vvNew[nUBucket][nUBucketPos] == -1) {
398  vvNew[nUBucket][nUBucketPos] = n;
399  info.nRefCount++;
400  }
401  }
402  }
403  nIdCount = nNew;
404 
405  // Deserialize entries from the tried table.
406  int nLost = 0;
407  for (int n = 0; n < nTried; n++) {
408  CAddrInfo info;
409  s >> info;
410  int nKBucket = info.GetTriedBucket(nKey);
411  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
412  if (vvTried[nKBucket][nKBucketPos] == -1) {
413  info.nRandomPos = vRandom.size();
414  info.fInTried = true;
415  vRandom.push_back(nIdCount);
416  mapInfo[nIdCount] = info;
417  mapAddr[info] = nIdCount;
418  vvTried[nKBucket][nKBucketPos] = nIdCount;
419  nIdCount++;
420  } else {
421  nLost++;
422  }
423  }
424  nTried -= nLost;
425 
426  // Deserialize positions in the new table (if possible).
427  for (int bucket = 0; bucket < nUBuckets; bucket++) {
428  int nSize = 0;
429  s >> nSize;
430  for (int n = 0; n < nSize; n++) {
431  int nIndex = 0;
432  s >> nIndex;
433  if (nIndex >= 0 && nIndex < nNew) {
434  CAddrInfo &info = mapInfo[nIndex];
435  int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
436  if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
437  info.nRefCount++;
438  vvNew[bucket][nUBucketPos] = nIndex;
439  }
440  }
441  }
442  }
443 
444  // Prune new entries with refcount 0 (as a result of collisions).
445  int nLostUnk = 0;
446  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
447  if (it->second.fInTried == false && it->second.nRefCount == 0) {
448  std::map<int, CAddrInfo>::const_iterator itCopy = it++;
449  Delete(itCopy->first);
450  nLostUnk++;
451  } else {
452  it++;
453  }
454  }
455  if (nLost + nLostUnk > 0) {
456  LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
457  }
458 
459  Check();
460  }
461 
462  void Clear()
463  {
464  LOCK(cs);
465  std::vector<int>().swap(vRandom);
466  nKey = GetRandHash();
467  for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
468  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
469  vvNew[bucket][entry] = -1;
470  }
471  }
472  for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
473  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
474  vvTried[bucket][entry] = -1;
475  }
476  }
477 
478  nIdCount = 0;
479  nTried = 0;
480  nNew = 0;
481  nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
482  mapInfo.clear();
483  mapAddr.clear();
484  }
485 
486  CAddrMan(bool _discriminatePorts = false) :
487  discriminatePorts(_discriminatePorts)
488  {
489  Clear();
490  }
491 
493  {
494  nKey.SetNull();
495  }
496 
498  size_t size() const
499  {
500  LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
501  return vRandom.size();
502  }
503 
505  void Check()
506  {
507 #ifdef DEBUG_ADDRMAN
508  {
509  LOCK(cs);
510  int err;
511  if ((err=Check_()))
512  LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
513  }
514 #endif
515  }
516 
518  bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
519  {
520  LOCK(cs);
521  bool fRet = false;
522  Check();
523  fRet |= Add_(addr, source, nTimePenalty);
524  Check();
525  if (fRet) {
526  LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
527  }
528  return fRet;
529  }
530 
532  bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
533  {
534  LOCK(cs);
535  int nAdd = 0;
536  Check();
537  for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
538  nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
539  Check();
540  if (nAdd) {
541  LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
542  }
543  return nAdd > 0;
544  }
545 
547  void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
548  {
549  LOCK(cs);
550  Check();
551  Good_(addr, nTime);
552  Check();
553  }
554 
556  void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
557  {
558  LOCK(cs);
559  Check();
560  Attempt_(addr, fCountFailure, nTime);
561  Check();
562  }
563 
567  CAddrInfo Select(bool newOnly = false)
568  {
569  CAddrInfo addrRet;
570  {
571  LOCK(cs);
572  Check();
573  addrRet = Select_(newOnly);
574  Check();
575  }
576  return addrRet;
577  }
578 
580  std::vector<CAddress> GetAddr()
581  {
582  Check();
583  std::vector<CAddress> vAddr;
584  {
585  LOCK(cs);
586  GetAddr_(vAddr);
587  }
588  Check();
589  return vAddr;
590  }
591 
593  void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
594  {
595  LOCK(cs);
596  Check();
597  Connected_(addr, nTime);
598  Check();
599  }
600 
601  void SetServices(const CService &addr, ServiceFlags nServices)
602  {
603  LOCK(cs);
604  Check();
605  SetServices_(addr, nServices);
606  Check();
607  }
608 
610  {
611  CAddrInfo addrRet;
612  {
613  LOCK(cs);
614  Check();
615  addrRet = GetAddressInfo_(addr);
616  Check();
617  }
618  return addrRet;
619  }
620 
621 };
622 
623 #endif // BITCOIN_ADDRMAN_H
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:46
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime)
Mark an entry as attempted to connect.
Definition: addrman.cpp:332
uint256 GetRandHash()
Definition: random.cpp:384
ServiceFlags
nServices flags
Definition: protocol.h:280
CAddrInfo Select(bool newOnly=false)
Choose an address to connect to.
Definition: addrman.h:567
CAddrInfo * Find(const CService &addr, int *pnId=nullptr)
Find an entry.
Definition: addrman.cpp:68
void SetNull()
Definition: uint256.h:41
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.h:556
#define READWRITE(obj)
Definition: serialize.h:165
CAddrInfo Select_(bool newOnly)
Select an address to connect to, if newOnly is set to true, only the new table is selected from...
Definition: addrman.cpp:354
~CAddrMan()
Definition: addrman.h:492
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]
list of "new" buckets
Definition: addrman.h:210
void SetServices_(const CService &addr, ServiceFlags nServices)
Update an entry&#39;s service bits.
Definition: addrman.cpp:520
int64_t nLastGood
last time Good was called (memory only)
Definition: addrman.h:213
int nAttempts
connection attempts since last successful attempt
Definition: addrman.h:43
virtual int RandomInt(int nMax)
Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
Definition: addrman.cpp:555
std::string ToString() const
Definition: netaddress.cpp:288
int nRandomPos
position in vRandom
Definition: addrman.h:52
bool Add(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty=0)
Add a single address.
Definition: addrman.h:518
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
Definition: addrman.h:175
bool fInTried
in tried set? (memory only)
Definition: addrman.h:49
Stochastical (IP) address manager.
Definition: addrman.h:182
std::vector< CAddress > GetAddr()
Return a bunch of addresses, selected at random.
Definition: addrman.h:580
Extended statistics about a CAddress.
Definition: addrman.h:24
std::vector< int > vRandom
randomly-ordered vector of all nIds
Definition: addrman.h:198
int GetNewBucket(const uint256 &nKey, const CNetAddr &src) const
Calculate in which "new" bucket this entry belongs, given a certain source.
Definition: addrman.cpp:19
int GetTriedBucket(const uint256 &nKey) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:12
#define LogPrintf(...)
Definition: util.h:203
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:223
void Unserialize(Stream &s)
Definition: addrman.h:357
#define LOCK(cs)
Definition: sync.h:178
CAddrInfo GetAddressInfo(const CService &addr)
Definition: addrman.h:609
void MakeTried(CAddrInfo &info, int nId)
Move an entry from the "new" table(s) to the "tried" table.
Definition: addrman.cpp:157
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:143
Fast randomness source.
Definition: random.h:48
void Check()
Consistency check.
Definition: addrman.h:505
A CService with information about it as peer.
Definition: protocol.h:358
int nTried
Definition: addrman.h:201
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2)
Swap two elements in vRandom.
Definition: addrman.cpp:103
CAddrInfo GetAddressInfo_(const CService &addr)
Get address info for address.
Definition: addrman.cpp:538
ADD_SERIALIZE_METHODS
Definition: addrman.h:58
#define ADDRMAN_BUCKET_SIZE
Definition: addrman.h:177
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr)
find an entry, creating it if necessary.
Definition: addrman.cpp:86
bool discriminatePorts
Definition: addrman.h:216
int nIdCount
last used nId
Definition: addrman.h:189
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:33
CAddrInfo()
Definition: addrman.h:84
#define LogPrint(category,...)
Definition: util.h:214
IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
Definition: netaddress.h:33
CAddrMan(bool _discriminatePorts=false)
Definition: addrman.h:486
void Good_(const CService &addr, int64_t nTime)
Mark an entry "good", possibly moving it from "new" to "tried".
Definition: addrman.cpp:205
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:498
256-bit opaque blob.
Definition: uint256.h:123
void Init()
Definition: addrman.h:68
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
Calculate in which position of a bucket to store this entry.
Definition: addrman.cpp:27
void Clear()
Definition: addrman.h:462
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource)
Definition: addrman.h:79
#define ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman.h:176
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
int GetNewBucket(const uint256 &nKey) const
Calculate in which "new" bucket this entry belongs, using its default source.
Definition: addrman.h:96
bool Add_(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty)
Add an entry to the "new" table.
Definition: addrman.cpp:259
void SerializationOp(Stream &s, Operation ser_action)
Definition: addrman.h:61
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:53
void Connected_(const CService &addr, int64_t nTime)
Mark an entry as currently-connected-to.
Definition: addrman.cpp:500
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:33
std::string ToStringIPPort(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:572
void GetAddr_(std::vector< CAddress > &vAddr)
Select several addresses at once.
Definition: addrman.cpp:479
std::map< int, CAddrInfo > mapInfo
table with information about all nIds
Definition: addrman.h:192
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty=0)
Add multiple addresses.
Definition: addrman.h:532
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]
list of "tried" buckets
Definition: addrman.h:204
void SetServices(const CService &addr, ServiceFlags nServices)
Definition: addrman.h:601
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:220
void Delete(int nId)
Delete an entry. It must not be in tried, and have refcount 0.
Definition: addrman.cpp:123
void Serialize(Stream &s) const
serialized format:
Definition: addrman.h:307
int nNew
number of (unique) "new" entries
Definition: addrman.h:207
void Connected(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as currently-connected-to.
Definition: addrman.h:593
int64_t nLastSuccess
last successful connection by us
Definition: addrman.h:40
CCriticalSection cs
critical section to protect the inner data structures
Definition: addrman.h:186
std::map< CService, int > mapAddr
find an nId based on its network address
Definition: addrman.h:195
void ClearNew(int nUBucket, int nUBucketPos)
Clear a position in a "new" table. This is the only place where entries are actually deleted...
Definition: addrman.cpp:142
Wrapped mutex: supports recursive locking, but no waiting TODO: We should move away from using the re...
Definition: sync.h:94
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman.h:30
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
Definition: addrman.h:154
CNetAddr source
where knowledge about this address first came from
Definition: addrman.h:37
void Good(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible.
Definition: addrman.h:547
Released under the MIT license