Dogecoin Core  1.14.2
P2P Digital Currency
addrman.h
Go to the documentation of this file.
1 // Copyright (c) 2012 Pieter Wuille
2 // Copyright (c) 2012-2016 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 
139 #define ADDRMAN_TRIED_BUCKET_COUNT 256
140 
142 #define ADDRMAN_NEW_BUCKET_COUNT 1024
143 
145 #define ADDRMAN_BUCKET_SIZE 64
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 
177 class CAddrMan
178 {
179 private:
182 
184  int nIdCount;
185 
187  std::map<int, CAddrInfo> mapInfo;
188 
190  std::map<CNetAddr, int> mapAddr;
191 
193  std::vector<int> vRandom;
194 
195  // number of "tried" entries
196  int nTried;
197 
200 
202  int nNew;
203 
206 
208  int64_t nLastGood;
209 
210 protected:
213 
216 
218  CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
219 
222  CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL);
223 
225  void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
226 
228  void MakeTried(CAddrInfo& info, int nId);
229 
231  void Delete(int nId);
232 
234  void ClearNew(int nUBucket, int nUBucketPos);
235 
237  void Good_(const CService &addr, int64_t nTime);
238 
240  bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
241 
243  void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);
244 
246  CAddrInfo Select_(bool newOnly);
247 
249  virtual int RandomInt(int nMax);
250 
251 #ifdef DEBUG_ADDRMAN
253  int Check_();
254 #endif
255 
257  void GetAddr_(std::vector<CAddress> &vAddr);
258 
260  void Connected_(const CService &addr, int64_t nTime);
261 
263  void SetServices_(const CService &addr, ServiceFlags nServices);
264 
265 public:
295  template<typename Stream>
296  void Serialize(Stream &s) const
297  {
298  LOCK(cs);
299 
300  unsigned char nVersion = 1;
301  s << nVersion;
302  s << ((unsigned char)32);
303  s << nKey;
304  s << nNew;
305  s << nTried;
306 
307  int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
308  s << nUBuckets;
309  std::map<int, int> mapUnkIds;
310  int nIds = 0;
311  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
312  mapUnkIds[(*it).first] = nIds;
313  const CAddrInfo &info = (*it).second;
314  if (info.nRefCount) {
315  assert(nIds != nNew); // this means nNew was wrong, oh ow
316  s << info;
317  nIds++;
318  }
319  }
320  nIds = 0;
321  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
322  const CAddrInfo &info = (*it).second;
323  if (info.fInTried) {
324  assert(nIds != nTried); // this means nTried was wrong, oh ow
325  s << info;
326  nIds++;
327  }
328  }
329  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
330  int nSize = 0;
331  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
332  if (vvNew[bucket][i] != -1)
333  nSize++;
334  }
335  s << nSize;
336  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
337  if (vvNew[bucket][i] != -1) {
338  int nIndex = mapUnkIds[vvNew[bucket][i]];
339  s << nIndex;
340  }
341  }
342  }
343  }
344 
345  template<typename Stream>
346  void Unserialize(Stream& s)
347  {
348  LOCK(cs);
349 
350  Clear();
351 
352  unsigned char nVersion;
353  s >> nVersion;
354  unsigned char nKeySize;
355  s >> nKeySize;
356  if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
357  s >> nKey;
358  s >> nNew;
359  s >> nTried;
360  int nUBuckets = 0;
361  s >> nUBuckets;
362  if (nVersion != 0) {
363  nUBuckets ^= (1 << 30);
364  }
365 
367  throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
368  }
369 
371  throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
372  }
373 
374  // Deserialize entries from the new table.
375  for (int n = 0; n < nNew; n++) {
376  CAddrInfo &info = mapInfo[n];
377  s >> info;
378  mapAddr[info] = n;
379  info.nRandomPos = vRandom.size();
380  vRandom.push_back(n);
381  if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
382  // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
383  // immediately try to give them a reference based on their primary source address.
384  int nUBucket = info.GetNewBucket(nKey);
385  int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
386  if (vvNew[nUBucket][nUBucketPos] == -1) {
387  vvNew[nUBucket][nUBucketPos] = n;
388  info.nRefCount++;
389  }
390  }
391  }
392  nIdCount = nNew;
393 
394  // Deserialize entries from the tried table.
395  int nLost = 0;
396  for (int n = 0; n < nTried; n++) {
397  CAddrInfo info;
398  s >> info;
399  int nKBucket = info.GetTriedBucket(nKey);
400  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
401  if (vvTried[nKBucket][nKBucketPos] == -1) {
402  info.nRandomPos = vRandom.size();
403  info.fInTried = true;
404  vRandom.push_back(nIdCount);
405  mapInfo[nIdCount] = info;
406  mapAddr[info] = nIdCount;
407  vvTried[nKBucket][nKBucketPos] = nIdCount;
408  nIdCount++;
409  } else {
410  nLost++;
411  }
412  }
413  nTried -= nLost;
414 
415  // Deserialize positions in the new table (if possible).
416  for (int bucket = 0; bucket < nUBuckets; bucket++) {
417  int nSize = 0;
418  s >> nSize;
419  for (int n = 0; n < nSize; n++) {
420  int nIndex = 0;
421  s >> nIndex;
422  if (nIndex >= 0 && nIndex < nNew) {
423  CAddrInfo &info = mapInfo[nIndex];
424  int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
425  if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
426  info.nRefCount++;
427  vvNew[bucket][nUBucketPos] = nIndex;
428  }
429  }
430  }
431  }
432 
433  // Prune new entries with refcount 0 (as a result of collisions).
434  int nLostUnk = 0;
435  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
436  if (it->second.fInTried == false && it->second.nRefCount == 0) {
437  std::map<int, CAddrInfo>::const_iterator itCopy = it++;
438  Delete(itCopy->first);
439  nLostUnk++;
440  } else {
441  it++;
442  }
443  }
444  if (nLost + nLostUnk > 0) {
445  LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
446  }
447 
448  Check();
449  }
450 
451  void Clear()
452  {
453  std::vector<int>().swap(vRandom);
454  nKey = GetRandHash();
455  for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
456  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
457  vvNew[bucket][entry] = -1;
458  }
459  }
460  for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
461  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
462  vvTried[bucket][entry] = -1;
463  }
464  }
465 
466  nIdCount = 0;
467  nTried = 0;
468  nNew = 0;
469  nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
470  }
471 
473  {
474  Clear();
475  }
476 
478  {
479  nKey.SetNull();
480  }
481 
483  size_t size() const
484  {
485  LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
486  return vRandom.size();
487  }
488 
490  void Check()
491  {
492 #ifdef DEBUG_ADDRMAN
493  {
494  LOCK(cs);
495  int err;
496  if ((err=Check_()))
497  LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
498  }
499 #endif
500  }
501 
503  bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
504  {
505  LOCK(cs);
506  bool fRet = false;
507  Check();
508  fRet |= Add_(addr, source, nTimePenalty);
509  Check();
510  if (fRet)
511  LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
512  return fRet;
513  }
514 
516  bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
517  {
518  LOCK(cs);
519  int nAdd = 0;
520  Check();
521  for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
522  nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
523  Check();
524  if (nAdd)
525  LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
526  return nAdd > 0;
527  }
528 
530  void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
531  {
532  LOCK(cs);
533  Check();
534  Good_(addr, nTime);
535  Check();
536  }
537 
539  void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
540  {
541  LOCK(cs);
542  Check();
543  Attempt_(addr, fCountFailure, nTime);
544  Check();
545  }
546 
550  CAddrInfo Select(bool newOnly = false)
551  {
552  CAddrInfo addrRet;
553  {
554  LOCK(cs);
555  Check();
556  addrRet = Select_(newOnly);
557  Check();
558  }
559  return addrRet;
560  }
561 
563  std::vector<CAddress> GetAddr()
564  {
565  Check();
566  std::vector<CAddress> vAddr;
567  {
568  LOCK(cs);
569  GetAddr_(vAddr);
570  }
571  Check();
572  return vAddr;
573  }
574 
576  void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
577  {
578  LOCK(cs);
579  Check();
580  Connected_(addr, nTime);
581  Check();
582  }
583 
584  void SetServices(const CService &addr, ServiceFlags nServices)
585  {
586  LOCK(cs);
587  Check();
588  SetServices_(addr, nServices);
589  Check();
590  }
591 
592 };
593 
594 #endif // BITCOIN_ADDRMAN_H
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS
in how many buckets for entries with new addresses a single address may occur
Definition: addrman.h:154
#define ADDRMAN_BUCKET_SIZE
maximum allowed number of entries in buckets for new and tried addresses
Definition: addrman.h:145
#define ADDRMAN_NEW_BUCKET_COUNT
total number of buckets for new addresses
Definition: addrman.h:142
#define ADDRMAN_TRIED_BUCKET_COUNT
Stochastic address manager.
Definition: addrman.h:139
Extended statistics about a CAddress.
Definition: addrman.h:25
int GetNewBucket(const uint256 &nKey) const
Calculate in which "new" bucket this entry belongs, using its default source.
Definition: addrman.h:96
int GetTriedBucket(const uint256 &nKey) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:12
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource)
Definition: addrman.h:79
int nAttempts
connection attempts since last successful attempt
Definition: addrman.h:43
int64_t nLastSuccess
last successful connection by us
Definition: addrman.h:40
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
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:33
int64_t nLastTry
last try whatsoever by us (memory only)
Definition: addrman.h:30
void SerializationOp(Stream &s, Operation ser_action)
Definition: addrman.h:61
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
int nRandomPos
position in vRandom
Definition: addrman.h:52
bool fInTried
in tried set? (memory only)
Definition: addrman.h:49
ADD_SERIALIZE_METHODS
Definition: addrman.h:58
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:46
CNetAddr source
where knowledge about this address first came from
Definition: addrman.h:37
CAddrInfo()
Definition: addrman.h:84
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
void Init()
Definition: addrman.h:68
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
Stochastical (IP) address manager.
Definition: addrman.h:178
int64_t nLastGood
last time Good was called (memory only)
Definition: addrman.h:208
bool Add(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty=0)
Add a single address.
Definition: addrman.h:503
void Check()
Consistency check.
Definition: addrman.h:490
std::map< int, CAddrInfo > mapInfo
table with information about all nIds
Definition: addrman.h:187
void Connected_(const CService &addr, int64_t nTime)
Mark an entry as currently-connected-to.
Definition: addrman.cpp:483
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:215
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:483
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:337
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2)
Swap two elements in vRandom.
Definition: addrman.cpp:93
void Good_(const CService &addr, int64_t nTime)
Mark an entry "good", possibly moving it from "new" to "tried".
Definition: addrman.cpp:190
void Serialize(Stream &s) const
serialized format:
Definition: addrman.h:296
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]
list of "tried" buckets
Definition: addrman.h:199
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.h:539
int nNew
number of (unique) "new" entries
Definition: addrman.h:202
virtual int RandomInt(int nMax)
Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
Definition: addrman.cpp:521
void Clear()
Definition: addrman.h:451
std::map< CNetAddr, int > mapAddr
find an nId based on its network address
Definition: addrman.h:190
CAddrInfo Select(bool newOnly=false)
Choose an address to connect to.
Definition: addrman.h:550
std::vector< CAddress > GetAddr()
Return a bunch of addresses, selected at random.
Definition: addrman.h:563
int nIdCount
last used nId
Definition: addrman.h:184
void Connected(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as currently-connected-to.
Definition: addrman.h:576
void Unserialize(Stream &s)
Definition: addrman.h:346
void MakeTried(CAddrInfo &info, int nId)
Move an entry from the "new" table(s) to the "tried" table.
Definition: addrman.cpp:142
void Good(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible.
Definition: addrman.h:530
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime)
Mark an entry as attempted to connect.
Definition: addrman.cpp:315
bool Add_(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty)
Add an entry to the "new" table.
Definition: addrman.cpp:242
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty=0)
Add multiple addresses.
Definition: addrman.h:516
CCriticalSection cs
critical section to protect the inner data structures
Definition: addrman.h:181
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=NULL)
find an entry, creating it if necessary.
Definition: addrman.cpp:81
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:127
void SetServices(const CService &addr, ServiceFlags nServices)
Definition: addrman.h:584
CAddrInfo * Find(const CNetAddr &addr, int *pnId=NULL)
Find an entry.
Definition: addrman.cpp:68
CAddrMan()
Definition: addrman.h:472
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:212
~CAddrMan()
Definition: addrman.h:477
int nTried
Definition: addrman.h:196
void Delete(int nId)
Delete an entry. It must not be in tried, and have refcount 0.
Definition: addrman.cpp:113
std::vector< int > vRandom
randomly-ordered vector of all nIds
Definition: addrman.h:193
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]
list of "new" buckets
Definition: addrman.h:205
void SetServices_(const CService &addr, ServiceFlags nServices)
Update an entry's service bits.
Definition: addrman.cpp:503
void GetAddr_(std::vector< CAddress > &vAddr)
Select several addresses at once.
Definition: addrman.cpp:462
A CService with information about it as peer.
Definition: protocol.h:289
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:93
IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
Definition: netaddress.h:31
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:134
std::string ToStringIPPort() const
Definition: netaddress.cpp:559
Fast randomness source.
Definition: random.h:35
void SetNull()
Definition: uint256.h:40
256-bit opaque blob.
Definition: uint256.h:123
ServiceFlags
nServices flags
Definition: protocol.h:256
uint256 GetRandHash()
Definition: random.cpp:173
const char * source
Definition: rpcconsole.cpp:58
#define READWRITE(obj)
Definition: serialize.h:151
#define LOCK(cs)
Definition: sync.h:177
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
#define LogPrint(category,...)
Definition: util.h:76
#define LogPrintf(...)
Definition: util.h:82