Fabcoin Core  0.16.2
P2P Digital Currency
addrman.h
Go to the documentation of this file.
1 // Copyright (c) 2012 Pieter Wuille
2 // Copyright (c) 2012-2017 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 FABCOIN_ADDRMAN_H
7 #define FABCOIN_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);
63  READWRITE(source);
64  READWRITE(nLastSuccess);
65  READWRITE(nAttempts);
66  }
67 
68  void Init()
69  {
70  nLastSuccess = 0;
71  nLastTry = 0;
72  nLastCountAttempt = 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 
84  CAddrInfo() : CAddress(), source()
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<CNetAddr, 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 protected:
218 
221 
223  CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr);
224 
227  CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr);
228 
230  void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
231 
233  void MakeTried(CAddrInfo& info, int nId);
234 
236  void Delete(int nId);
237 
239  void ClearNew(int nUBucket, int nUBucketPos);
240 
242  void Good_(const CService &addr, int64_t nTime);
243 
245  bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
246 
248  void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);
249 
251  CAddrInfo Select_(bool newOnly);
252 
254  virtual int RandomInt(int nMax);
255 
256 #ifdef DEBUG_ADDRMAN
257  int Check_();
259 #endif
260 
262  void GetAddr_(std::vector<CAddress> &vAddr);
263 
265  void Connected_(const CService &addr, int64_t nTime);
266 
268  void SetServices_(const CService &addr, ServiceFlags nServices);
269 
270 public:
300  template<typename Stream>
301  void Serialize(Stream &s) const
302  {
303  LOCK(cs);
304 
305  unsigned char nVersion = 1;
306  s << nVersion;
307  s << ((unsigned char)32);
308  s << nKey;
309  s << nNew;
310  s << nTried;
311 
312  int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
313  s << nUBuckets;
314  std::map<int, int> mapUnkIds;
315  int nIds = 0;
316  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
317  mapUnkIds[(*it).first] = nIds;
318  const CAddrInfo &info = (*it).second;
319  if (info.nRefCount) {
320  assert(nIds != nNew); // this means nNew was wrong, oh ow
321  s << info;
322  nIds++;
323  }
324  }
325  nIds = 0;
326  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
327  const CAddrInfo &info = (*it).second;
328  if (info.fInTried) {
329  assert(nIds != nTried); // this means nTried was wrong, oh ow
330  s << info;
331  nIds++;
332  }
333  }
334  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
335  int nSize = 0;
336  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
337  if (vvNew[bucket][i] != -1)
338  nSize++;
339  }
340  s << nSize;
341  for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
342  if (vvNew[bucket][i] != -1) {
343  int nIndex = mapUnkIds[vvNew[bucket][i]];
344  s << nIndex;
345  }
346  }
347  }
348  }
349 
350  template<typename Stream>
351  void Unserialize(Stream& s)
352  {
353  LOCK(cs);
354 
355  Clear();
356 
357  unsigned char nVersion;
358  s >> nVersion;
359  unsigned char nKeySize;
360  s >> nKeySize;
361  if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
362  s >> nKey;
363  s >> nNew;
364  s >> nTried;
365  int nUBuckets = 0;
366  s >> nUBuckets;
367  if (nVersion != 0) {
368  nUBuckets ^= (1 << 30);
369  }
370 
372  throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
373  }
374 
375  if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
376  throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
377  }
378 
379  // Deserialize entries from the new table.
380  for (int n = 0; n < nNew; n++) {
381  CAddrInfo &info = mapInfo[n];
382  s >> info;
383  mapAddr[info] = n;
384  info.nRandomPos = vRandom.size();
385  vRandom.push_back(n);
386  if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
387  // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
388  // immediately try to give them a reference based on their primary source address.
389  int nUBucket = info.GetNewBucket(nKey);
390  int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
391  if (vvNew[nUBucket][nUBucketPos] == -1) {
392  vvNew[nUBucket][nUBucketPos] = n;
393  info.nRefCount++;
394  }
395  }
396  }
397  nIdCount = nNew;
398 
399  // Deserialize entries from the tried table.
400  int nLost = 0;
401  for (int n = 0; n < nTried; n++) {
402  CAddrInfo info;
403  s >> info;
404  int nKBucket = info.GetTriedBucket(nKey);
405  int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
406  if (vvTried[nKBucket][nKBucketPos] == -1) {
407  info.nRandomPos = vRandom.size();
408  info.fInTried = true;
409  vRandom.push_back(nIdCount);
410  mapInfo[nIdCount] = info;
411  mapAddr[info] = nIdCount;
412  vvTried[nKBucket][nKBucketPos] = nIdCount;
413  nIdCount++;
414  } else {
415  nLost++;
416  }
417  }
418  nTried -= nLost;
419 
420  // Deserialize positions in the new table (if possible).
421  for (int bucket = 0; bucket < nUBuckets; bucket++) {
422  int nSize = 0;
423  s >> nSize;
424  for (int n = 0; n < nSize; n++) {
425  int nIndex = 0;
426  s >> nIndex;
427  if (nIndex >= 0 && nIndex < nNew) {
428  CAddrInfo &info = mapInfo[nIndex];
429  int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
430  if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
431  info.nRefCount++;
432  vvNew[bucket][nUBucketPos] = nIndex;
433  }
434  }
435  }
436  }
437 
438  // Prune new entries with refcount 0 (as a result of collisions).
439  int nLostUnk = 0;
440  for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
441  if (it->second.fInTried == false && it->second.nRefCount == 0) {
442  std::map<int, CAddrInfo>::const_iterator itCopy = it++;
443  Delete(itCopy->first);
444  nLostUnk++;
445  } else {
446  it++;
447  }
448  }
449  if (nLost + nLostUnk > 0) {
450  LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
451  }
452 
453  Check();
454  }
455 
456  void Clear()
457  {
458  std::vector<int>().swap(vRandom);
459  nKey = GetRandHash();
460  for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
461  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
462  vvNew[bucket][entry] = -1;
463  }
464  }
465  for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
466  for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
467  vvTried[bucket][entry] = -1;
468  }
469  }
470 
471  nIdCount = 0;
472  nTried = 0;
473  nNew = 0;
474  nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
475  mapInfo.clear();
476  mapAddr.clear();
477  }
478 
480  {
481  Clear();
482  }
483 
485  {
486  nKey.SetNull();
487  }
488 
490  size_t size() const
491  {
492  LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
493  return vRandom.size();
494  }
495 
497  void Check()
498  {
499 #ifdef DEBUG_ADDRMAN
500  {
501  LOCK(cs);
502  int err;
503  if ((err=Check_()))
504  LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
505  }
506 #endif
507  }
508 
510  bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
511  {
512  LOCK(cs);
513  bool fRet = false;
514  Check();
515  fRet |= Add_(addr, source, nTimePenalty);
516  Check();
517  if (fRet) {
518  LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
519  }
520  return fRet;
521  }
522 
524  bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
525  {
526  LOCK(cs);
527  int nAdd = 0;
528  Check();
529  for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
530  nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
531  Check();
532  if (nAdd) {
533  LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
534  }
535  return nAdd > 0;
536  }
537 
539  void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
540  {
541  LOCK(cs);
542  Check();
543  Good_(addr, nTime);
544  Check();
545  }
546 
548  void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
549  {
550  LOCK(cs);
551  Check();
552  Attempt_(addr, fCountFailure, nTime);
553  Check();
554  }
555 
559  CAddrInfo Select(bool newOnly = false)
560  {
561  CAddrInfo addrRet;
562  {
563  LOCK(cs);
564  Check();
565  addrRet = Select_(newOnly);
566  Check();
567  }
568  return addrRet;
569  }
570 
572  std::vector<CAddress> GetAddr()
573  {
574  Check();
575  std::vector<CAddress> vAddr;
576  {
577  LOCK(cs);
578  GetAddr_(vAddr);
579  }
580  Check();
581  return vAddr;
582  }
583 
585  void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
586  {
587  LOCK(cs);
588  Check();
589  Connected_(addr, nTime);
590  Check();
591  }
592 
594  {
595  LOCK(cs);
596  Check();
597  SetServices_(addr, nServices);
598  Check();
599  }
600 
601 };
602 
603 #endif // FABCOIN_ADDRMAN_H
void Serialize(Stream &s) const
serialized format:
Definition: addrman.h:301
int nRefCount
reference count in new sets (memory only)
Definition: addrman.h:46
uint256 GetRandHash()
Definition: random.cpp:372
int GetTriedBucket(const uint256 &nKey) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:12
ServiceFlags
nServices flags
Definition: protocol.h:249
CAddrInfo Select(bool newOnly=false)
Choose an address to connect to.
Definition: addrman.h:559
void SetNull()
Definition: uint256.h:46
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.h:548
#define READWRITE(obj)
Definition: serialize.h:179
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
Definition: Interface.h:284
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
~CAddrMan()
Definition: addrman.h:484
std::string ToStringIPPort() const
Definition: netaddress.cpp:587
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
assert(len-trim+(2 *lenIndices)<=WIDTH)
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:510
#define ADDRMAN_TRIED_BUCKET_COUNT
Convenience.
Definition: addrman.h:175
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
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:572
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:490
Extended statistics about a CAddress.
Definition: addrman.h:24
std::vector< int > vRandom
randomly-ordered vector of all nIds
Definition: addrman.h:198
#define LogPrintf(...)
Definition: util.h:153
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:220
void Unserialize(Stream &s)
Definition: addrman.h:351
#define LOCK(cs)
Definition: sync.h:175
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:140
Fast randomness source.
Definition: random.h:44
void Check()
Consistency check.
Definition: addrman.h:497
A CService with information about it as peer.
Definition: protocol.h:281
int nTried
Definition: addrman.h:201
ADD_SERIALIZE_METHODS
Definition: addrman.h:58
#define ADDRMAN_BUCKET_SIZE
Definition: addrman.h:177
int nIdCount
last used nId
Definition: addrman.h:189
std::map< CNetAddr, int > mapAddr
find an nId based on its network address
Definition: addrman.h:195
CAddrInfo()
Definition: addrman.h:84
#define LogPrint(category,...)
Definition: util.h:164
IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
Definition: netaddress.h:31
256-bit opaque blob.
Definition: uint256.h:132
unsigned int nTime
Definition: protocol.h:313
ServiceFlags nServices
Definition: protocol.h:310
void Init()
Definition: addrman.h:68
void Clear()
Definition: addrman.h:456
CAddrMan()
Definition: addrman.h:479
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
void SerializationOp(Stream &s, Operation ser_action)
Definition: addrman.h:61
int64_t nLastCountAttempt
last counted attempt (memory only)
Definition: addrman.h:33
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:524
std::string ToString() const
Definition: netaddress.cpp:287
void SetServices(const CService &addr, ServiceFlags nServices)
Definition: addrman.h:593
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:217
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:585
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
int64_t nLastSuccess
last successful connection by us
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:33
CCriticalSection cs
critical section to protect the inner data structures
Definition: addrman.h:186
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:91
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
int GetNewBucket(const uint256 &nKey) const
Calculate in which "new" bucket this entry belongs, using its default source.
Definition: addrman.h:96
void Good(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible.
Definition: addrman.h:539