Bitcoin ABC  0.29.2
P2P Digital Currency
db.h
Go to the documentation of this file.
1 // Copyright (c) 2017-2019 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_SEEDER_DB_H
6 #define BITCOIN_SEEDER_DB_H
7 
8 #include <chainparams.h>
9 #include <netbase.h>
10 #include <protocol.h>
11 #include <seeder/bitcoin.h>
12 #include <seeder/util.h>
13 #include <sync.h>
14 #include <util/time.h>
15 #include <version.h>
16 
17 #include <cmath>
18 #include <cstdint>
19 #include <deque>
20 #include <map>
21 #include <set>
22 #include <vector>
23 
24 #define MIN_RETRY 1000
25 
26 #define REQUIRE_VERSION 70001
27 
28 static inline int GetRequireHeight() {
29  return Params().Checkpoints().mapCheckpoints.rbegin()->first;
30 }
31 
32 static inline std::string ToString(const CService &ip) {
33  std::string str = ip.ToString();
34  while (str.size() < 22) {
35  str += ' ';
36  }
37  return str;
38 }
39 
40 class CAddrStat {
41 private:
42  float weight;
43  float count;
44  float reliability;
45 
46 public:
47  CAddrStat() : weight(0), count(0), reliability(0) {}
48 
49  void Update(bool good, int64_t age, double tau) {
50  double f = exp(-age / tau);
51  reliability = reliability * f + (good ? (1.0 - f) : 0);
52  count = count * f + 1;
53  weight = weight * f + (1.0 - f);
54  }
55 
57  READWRITE(obj.weight, obj.count, obj.reliability);
58  }
59 
60  friend class SeederAddrInfo;
61 };
62 
63 class CAddrReport {
64 public:
67  int blocks;
68  double uptime[5];
69  std::string clientSubVersion;
70  int64_t lastSuccess;
71  bool fGood;
72  uint64_t services;
73 };
74 
76 private:
78  uint64_t services;
79  int64_t lastTry;
80  int64_t ourLastTry;
81  int64_t ourLastSuccess;
82  int64_t ignoreTill;
89  int blocks;
90  int total;
91  int success;
92  std::string clientSubVersion;
93 
94 public:
96  : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0),
97  ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {}
98 
100  CAddrReport ret;
101  ret.ip = ip;
104  ret.blocks = blocks;
105  ret.uptime[0] = stat2H.reliability;
106  ret.uptime[1] = stat8H.reliability;
107  ret.uptime[2] = stat1D.reliability;
108  ret.uptime[3] = stat1W.reliability;
109  ret.uptime[4] = stat1M.reliability;
111  ret.fGood = IsReliable();
112  ret.services = services;
113  return ret;
114  }
115 
116  bool IsReliable() const {
117  if (ip.GetPort() != GetDefaultPort()) {
118  return false;
119  }
120  if (!(services & NODE_NETWORK)) {
121  return false;
122  }
123  if (!ip.IsRoutable()) {
124  return false;
125  }
127  return false;
128  }
129  if (blocks && blocks < GetRequireHeight()) {
130  return false;
131  }
132 
133  if (total <= 3 && success * 2 >= total) {
134  return true;
135  }
136 
137  if (stat2H.reliability > 0.85 && stat2H.count > 2) {
138  return true;
139  }
140  if (stat8H.reliability > 0.70 && stat8H.count > 4) {
141  return true;
142  }
143  if (stat1D.reliability > 0.55 && stat1D.count > 8) {
144  return true;
145  }
146  if (stat1W.reliability > 0.45 && stat1W.count > 16) {
147  return true;
148  }
149  if (stat1M.reliability > 0.35 && stat1M.count > 32) {
150  return true;
151  }
152 
153  return false;
154  }
155 
156  int64_t GetBanTime() const {
157  if (IsReliable()) {
158  return 0;
159  }
160  if (clientVersion && clientVersion < 31900) {
161  return 604800;
162  }
163  if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 &&
164  stat1M.count > 32) {
165  return 30 * 86400;
166  }
167  if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 &&
168  stat1W.count > 16) {
169  return 7 * 86400;
170  }
171  if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 &&
172  stat1D.count > 8) {
173  return 1 * 86400;
174  }
175  return 0;
176  }
177 
178  int64_t GetIgnoreTime() const {
179  if (IsReliable()) {
180  return 0;
181  }
182  if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 &&
183  stat1M.count > 2) {
184  return 10 * 86400;
185  }
186  if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 &&
187  stat1W.count > 2) {
188  return 3 * 86400;
189  }
190  if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 &&
191  stat1D.count > 2) {
192  return 8 * 3600;
193  }
194  if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 &&
195  stat8H.count > 2) {
196  return 2 * 3600;
197  }
198  return 0;
199  }
200 
201  void Update(bool good);
202 
203  friend class CAddrDb;
204 
206  uint8_t version = 4;
207  READWRITE(version, obj.ip, obj.services, obj.lastTry);
208  uint8_t tried = obj.ourLastTry != 0;
209  READWRITE(tried);
210  if (!tried) {
211  return;
212  }
213 
214  READWRITE(obj.ourLastTry, obj.ignoreTill, obj.stat2H, obj.stat8H,
215  obj.stat1D, obj.stat1W);
216  if (version >= 1) {
217  READWRITE(obj.stat1M);
218  } else {
219  SER_WRITE(obj, *((CAddrStat *)(&obj.stat1M)) = obj.stat1W);
220  }
221  READWRITE(obj.total, obj.success, obj.clientVersion);
222  if (version >= 2) {
223  READWRITE(obj.clientSubVersion);
224  }
225  if (version >= 3) {
226  READWRITE(obj.blocks);
227  }
228  if (version >= 4) {
229  READWRITE(obj.ourLastSuccess);
230  }
231  }
232 };
233 
235 public:
236  int nBanned;
237  int nAvail;
238  int nTracked;
239  int nNew;
240  int nGood;
241  int nAge;
242 };
243 
246  uint64_t services;
247  bool fGood;
248  int nBanTime;
249  int nHeight;
250  int nClientV;
251  std::string strClientV;
252  int64_t ourLastSuccess;
253 };
254 
264 class CAddrDb {
265 private:
267  // number of address id's
268  int nId;
269  // map address id to address info (b,c,d,e)
270  std::map<int, SeederAddrInfo> idToInfo;
271  // map ip to id (b,c,d,e)
272  std::map<CService, int> ipToId;
273  // sequence of tried nodes, in order we have tried connecting to them (c,d)
274  std::deque<int> ourId;
275  // set of nodes not yet tried (b)
276  std::set<int> unkId;
277  // set of good nodes (d, good e)
278  std::set<int> goodId;
279  int nDirty;
280 
281 protected:
282  // internal routines that assume proper locks are acquired
283  // add an address
284  void Add_(const CAddress &addr, bool force);
285  // get an IP to test (must call Good_ or Bad_ on result afterwards)
286  bool Get_(CServiceResult &ip, int &wait);
287  // mark an IP as good (must have been returned by Get_)
288  void Good_(const CService &ip, int clientV, std::string clientSV,
289  int blocks, uint64_t services);
290  // mark an IP as bad (and optionally ban it) (must have been returned by
291  // Get_)
292  void Bad_(const CService &ip, int ban);
293  // look up id of an IP
294  int Lookup_(const CService &ip);
295  // get a random set of IPs (shared lock only)
296  void GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
297  const bool *nets);
298 
299 public:
300  // nodes that are banned, with their unban time (a)
301  std::map<CService, int64_t> banned;
302 
303  void GetStats(CAddrDbStats &stats) const {
304  LOCK(cs);
305  stats.nBanned = banned.size();
306  stats.nAvail = idToInfo.size();
307  stats.nTracked = ourId.size();
308  stats.nGood = goodId.size();
309  stats.nNew = unkId.size();
310  if (ourId.size() > 0) {
311  stats.nAge = GetTime() - idToInfo.at(ourId.at(0)).ourLastTry;
312  } else {
313  stats.nAge = 0;
314  }
315  }
316 
317  void ResetIgnores() {
318  for (std::map<int, SeederAddrInfo>::iterator it = idToInfo.begin();
319  it != idToInfo.end(); it++) {
320  (*it).second.ignoreTill = 0;
321  }
322  }
323 
324  std::vector<CAddrReport> GetAll() {
325  std::vector<CAddrReport> ret;
326  LOCK(cs);
327  for (std::deque<int>::const_iterator it = ourId.begin();
328  it != ourId.end(); it++) {
329  const SeederAddrInfo &info = idToInfo[*it];
330  if (info.success > 0) {
331  ret.push_back(info.GetReport());
332  }
333  }
334  return ret;
335  }
336 
337  // serialization code
338  // format:
339  // nVersion (0 for now)
340  // n (number of ips in (b,c,d))
341  // SeederAddrInfo[n]
342  // banned
343  // acquires a shared lock (this does not suffice for read mode, but we
344  // assume that only happens at startup, single-threaded) this way, dumping
345  // does not interfere with GetIPs_, which is called from the DNS thread
346  template <typename Stream> void Serialize(Stream &s) const {
347  LOCK(cs);
348 
349  int nVersion = 0;
350  s << nVersion;
351 
352  CAddrDb *db = const_cast<CAddrDb *>(this);
353  int n = ourId.size() + unkId.size();
354  s << n;
355  for (std::deque<int>::const_iterator it = ourId.begin();
356  it != ourId.end(); it++) {
357  std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
358  s << (*ci).second;
359  }
360  for (std::set<int>::const_iterator it = unkId.begin();
361  it != unkId.end(); it++) {
362  std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
363  s << (*ci).second;
364  }
365  s << banned;
366  }
367 
368  template <typename Stream> void Unserialize(Stream &s) {
369  LOCK(cs);
370 
371  int nVersion;
372  s >> nVersion;
373 
374  CAddrDb *db = const_cast<CAddrDb *>(this);
375  db->nId = 0;
376  int n;
377  s >> n;
378  for (int i = 0; i < n; i++) {
379  SeederAddrInfo info;
380  s >> info;
381  if (!info.GetBanTime()) {
382  int id = db->nId++;
383  db->idToInfo[id] = info;
384  db->ipToId[info.ip] = id;
385  if (info.ourLastTry) {
386  db->ourId.push_back(id);
387  if (info.IsReliable()) {
388  db->goodId.insert(id);
389  }
390  } else {
391  db->unkId.insert(id);
392  }
393  }
394  }
395  db->nDirty++;
396 
397  s >> banned;
398  }
399 
400  void Add(const CAddress &addr, bool fForce = false) {
401  LOCK(cs);
402  Add_(addr, fForce);
403  }
404 
405  void Add(const std::vector<CAddress> &vAddr, bool fForce = false) {
406  LOCK(cs);
407  for (size_t i = 0; i < vAddr.size(); i++) {
408  Add_(vAddr[i], fForce);
409  }
410  }
411 
412  void GetMany(std::vector<CServiceResult> &ips, int max, int &wait) {
413  LOCK(cs);
414  while (max > 0) {
415  CServiceResult ip = {};
416  if (!Get_(ip, wait)) {
417  return;
418  }
419  ips.push_back(ip);
420  max--;
421  }
422  }
423 
424  void ResultMany(const std::vector<CServiceResult> &ips) {
425  LOCK(cs);
426  for (size_t i = 0; i < ips.size(); i++) {
427  if (ips[i].fGood) {
428  Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV,
429  ips[i].nHeight, ips[i].services);
430  } else {
431  Bad_(ips[i].service, ips[i].nBanTime);
432  }
433  }
434  }
435 
436  void GetIPs(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
437  const bool *nets) {
438  LOCK(cs);
439  GetIPs_(ips, requestedFlags, max, nets);
440  }
441 };
442 
443 #endif // BITCOIN_SEEDER_DB_H
const CChainParams & Params()
Return the currently selected parameters.
Definition: db.h:264
void Add(const CAddress &addr, bool fForce=false)
Definition: db.h:400
std::set< int > unkId
Definition: db.h:276
void Bad_(const CService &ip, int ban)
Definition: db.cpp:112
RecursiveMutex cs
Definition: db.h:266
void ResultMany(const std::vector< CServiceResult > &ips)
Definition: db.h:424
void Good_(const CService &ip, int clientV, std::string clientSV, int blocks, uint64_t services)
Definition: db.cpp:89
void GetStats(CAddrDbStats &stats) const
Definition: db.h:303
void GetIPs_(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.cpp:192
int nId
Definition: db.h:268
void GetIPs(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.h:436
std::set< int > goodId
Definition: db.h:278
void Unserialize(Stream &s)
Definition: db.h:368
int nDirty
Definition: db.h:279
std::map< CService, int > ipToId
Definition: db.h:272
std::map< CService, int64_t > banned
Definition: db.h:301
std::vector< CAddrReport > GetAll()
Definition: db.h:324
std::deque< int > ourId
Definition: db.h:274
std::map< int, SeederAddrInfo > idToInfo
Definition: db.h:270
void ResetIgnores()
Definition: db.h:317
void Add(const std::vector< CAddress > &vAddr, bool fForce=false)
Definition: db.h:405
void Serialize(Stream &s) const
Definition: db.h:346
void GetMany(std::vector< CServiceResult > &ips, int max, int &wait)
Definition: db.h:412
void Add_(const CAddress &addr, bool force)
Definition: db.cpp:146
bool Get_(CServiceResult &ip, int &wait)
Definition: db.cpp:44
int Lookup_(const CService &ip)
Definition: db.cpp:82
int nTracked
Definition: db.h:238
int nAvail
Definition: db.h:237
int nNew
Definition: db.h:239
int nGood
Definition: db.h:240
int nBanned
Definition: db.h:236
int nAge
Definition: db.h:241
Definition: db.h:63
double uptime[5]
Definition: db.h:68
uint64_t services
Definition: db.h:72
int blocks
Definition: db.h:67
CService ip
Definition: db.h:65
int clientVersion
Definition: db.h:66
bool fGood
Definition: db.h:71
std::string clientSubVersion
Definition: db.h:69
int64_t lastSuccess
Definition: db.h:70
Definition: db.h:40
SERIALIZE_METHODS(CAddrStat, obj)
Definition: db.h:56
CAddrStat()
Definition: db.h:47
float count
Definition: db.h:43
float weight
Definition: db.h:42
float reliability
Definition: db.h:44
void Update(bool good, int64_t age, double tau)
Definition: db.h:49
A CService with information about it as peer.
Definition: protocol.h:442
const CCheckpointData & Checkpoints() const
Definition: chainparams.h:128
bool IsRoutable() const
Definition: netaddress.cpp:514
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
std::string ToString() const
uint16_t GetPort() const
int success
Definition: db.h:91
CAddrStat stat8H
Definition: db.h:84
CAddrStat stat1W
Definition: db.h:86
int64_t lastTry
Definition: db.h:79
SERIALIZE_METHODS(SeederAddrInfo, obj)
Definition: db.h:205
int64_t GetIgnoreTime() const
Definition: db.h:178
CAddrStat stat1D
Definition: db.h:85
CAddrStat stat2H
Definition: db.h:83
CAddrReport GetReport() const
Definition: db.h:99
int64_t ignoreTill
Definition: db.h:82
int64_t GetBanTime() const
Definition: db.h:156
std::string clientSubVersion
Definition: db.h:92
int total
Definition: db.h:90
bool IsReliable() const
Definition: db.h:116
int64_t ourLastTry
Definition: db.h:80
CAddrStat stat1M
Definition: db.h:87
CService ip
Definition: db.h:77
void Update(bool good)
Definition: db.cpp:11
int blocks
Definition: db.h:89
uint64_t services
Definition: db.h:78
int64_t ourLastSuccess
Definition: db.h:81
SeederAddrInfo()
Definition: db.h:95
int clientVersion
Definition: db.h:88
static const uint8_t tau[]
Definition: chacha20.cpp:30
unsigned int nHeight
@ NODE_NETWORK
Definition: protocol.h:342
static uint16_t GetDefaultPort()
Definition: bitcoin.h:18
static int GetRequireHeight()
Definition: db.h:28
#define REQUIRE_VERSION
Definition: db.h:26
static std::string ToString(const CService &ip)
Definition: db.h:32
CAddrDb db
Definition: main.cpp:35
#define SER_WRITE(obj, code)
Definition: serialize.h:173
#define READWRITE(...)
Definition: serialize.h:166
MapCheckpoints mapCheckpoints
Definition: chainparams.h:28
int nHeight
Definition: db.h:249
int nBanTime
Definition: db.h:248
CService service
Definition: db.h:245
std::string strClientV
Definition: db.h:251
uint64_t services
Definition: db.h:246
int64_t ourLastSuccess
Definition: db.h:252
bool fGood
Definition: db.h:247
int nClientV
Definition: db.h:250
#define LOCK(cs)
Definition: sync.h:306
int64_t GetTime()
Definition: time.cpp:109