Bitcoin ABC  0.26.3
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 (!(services & NODE_NETWORK)) {
118  return false;
119  }
120  if (!ip.IsRoutable()) {
121  return false;
122  }
124  return false;
125  }
126  if (blocks && blocks < GetRequireHeight()) {
127  return false;
128  }
129 
130  if (total <= 3 && success * 2 >= total) {
131  return true;
132  }
133 
134  if (stat2H.reliability > 0.85 && stat2H.count > 2) {
135  return true;
136  }
137  if (stat8H.reliability > 0.70 && stat8H.count > 4) {
138  return true;
139  }
140  if (stat1D.reliability > 0.55 && stat1D.count > 8) {
141  return true;
142  }
143  if (stat1W.reliability > 0.45 && stat1W.count > 16) {
144  return true;
145  }
146  if (stat1M.reliability > 0.35 && stat1M.count > 32) {
147  return true;
148  }
149 
150  return false;
151  }
152 
153  int64_t GetBanTime() const {
154  if (IsReliable()) {
155  return 0;
156  }
157  if (clientVersion && clientVersion < 31900) {
158  return 604800;
159  }
160  if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 &&
161  stat1M.count > 32) {
162  return 30 * 86400;
163  }
164  if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 &&
165  stat1W.count > 16) {
166  return 7 * 86400;
167  }
168  if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 &&
169  stat1D.count > 8) {
170  return 1 * 86400;
171  }
172  return 0;
173  }
174 
175  int64_t GetIgnoreTime() const {
176  if (IsReliable()) {
177  return 0;
178  }
179  if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 &&
180  stat1M.count > 2) {
181  return 10 * 86400;
182  }
183  if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 &&
184  stat1W.count > 2) {
185  return 3 * 86400;
186  }
187  if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 &&
188  stat1D.count > 2) {
189  return 8 * 3600;
190  }
191  if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 &&
192  stat8H.count > 2) {
193  return 2 * 3600;
194  }
195  return 0;
196  }
197 
198  void Update(bool good);
199 
200  friend class CAddrDb;
201 
203  uint8_t version = 4;
204  READWRITE(version, obj.ip, obj.services, obj.lastTry);
205  uint8_t tried = obj.ourLastTry != 0;
206  READWRITE(tried);
207  if (!tried) {
208  return;
209  }
210 
211  READWRITE(obj.ourLastTry, obj.ignoreTill, obj.stat2H, obj.stat8H,
212  obj.stat1D, obj.stat1W);
213  if (version >= 1) {
214  READWRITE(obj.stat1M);
215  } else {
216  SER_WRITE(obj, *((CAddrStat *)(&obj.stat1M)) = obj.stat1W);
217  }
218  READWRITE(obj.total, obj.success, obj.clientVersion);
219  if (version >= 2) {
220  READWRITE(obj.clientSubVersion);
221  }
222  if (version >= 3) {
223  READWRITE(obj.blocks);
224  }
225  if (version >= 4) {
226  READWRITE(obj.ourLastSuccess);
227  }
228  }
229 };
230 
232 public:
233  int nBanned;
234  int nAvail;
235  int nTracked;
236  int nNew;
237  int nGood;
238  int nAge;
239 };
240 
243  uint64_t services;
244  bool fGood;
245  int nBanTime;
246  int nHeight;
247  int nClientV;
248  std::string strClientV;
249  int64_t ourLastSuccess;
250 };
251 
261 class CAddrDb {
262 private:
264  // number of address id's
265  int nId;
266  // map address id to address info (b,c,d,e)
267  std::map<int, SeederAddrInfo> idToInfo;
268  // map ip to id (b,c,d,e)
269  std::map<CService, int> ipToId;
270  // sequence of tried nodes, in order we have tried connecting to them (c,d)
271  std::deque<int> ourId;
272  // set of nodes not yet tried (b)
273  std::set<int> unkId;
274  // set of good nodes (d, good e)
275  std::set<int> goodId;
276  int nDirty;
277 
278 protected:
279  // internal routines that assume proper locks are acquired
280  // add an address
281  void Add_(const CAddress &addr, bool force);
282  // get an IP to test (must call Good_ or Bad_ on result afterwards)
283  bool Get_(CServiceResult &ip, int &wait);
284  // mark an IP as good (must have been returned by Get_)
285  void Good_(const CService &ip, int clientV, std::string clientSV,
286  int blocks, uint64_t services);
287  // mark an IP as bad (and optionally ban it) (must have been returned by
288  // Get_)
289  void Bad_(const CService &ip, int ban);
290  // look up id of an IP
291  int Lookup_(const CService &ip);
292  // get a random set of IPs (shared lock only)
293  void GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
294  const bool *nets);
295 
296 public:
297  // nodes that are banned, with their unban time (a)
298  std::map<CService, int64_t> banned;
299 
300  void GetStats(CAddrDbStats &stats) const {
301  LOCK(cs);
302  stats.nBanned = banned.size();
303  stats.nAvail = idToInfo.size();
304  stats.nTracked = ourId.size();
305  stats.nGood = goodId.size();
306  stats.nNew = unkId.size();
307  if (ourId.size() > 0) {
308  stats.nAge = GetTime() - idToInfo.at(ourId.at(0)).ourLastTry;
309  } else {
310  stats.nAge = 0;
311  }
312  }
313 
314  void ResetIgnores() {
315  for (std::map<int, SeederAddrInfo>::iterator it = idToInfo.begin();
316  it != idToInfo.end(); it++) {
317  (*it).second.ignoreTill = 0;
318  }
319  }
320 
321  std::vector<CAddrReport> GetAll() {
322  std::vector<CAddrReport> ret;
323  LOCK(cs);
324  for (std::deque<int>::const_iterator it = ourId.begin();
325  it != ourId.end(); it++) {
326  const SeederAddrInfo &info = idToInfo[*it];
327  if (info.success > 0) {
328  ret.push_back(info.GetReport());
329  }
330  }
331  return ret;
332  }
333 
334  // serialization code
335  // format:
336  // nVersion (0 for now)
337  // n (number of ips in (b,c,d))
338  // SeederAddrInfo[n]
339  // banned
340  // acquires a shared lock (this does not suffice for read mode, but we
341  // assume that only happens at startup, single-threaded) this way, dumping
342  // does not interfere with GetIPs_, which is called from the DNS thread
343  template <typename Stream> void Serialize(Stream &s) const {
344  LOCK(cs);
345 
346  int nVersion = 0;
347  s << nVersion;
348 
349  CAddrDb *db = const_cast<CAddrDb *>(this);
350  int n = ourId.size() + unkId.size();
351  s << n;
352  for (std::deque<int>::const_iterator it = ourId.begin();
353  it != ourId.end(); it++) {
354  std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
355  s << (*ci).second;
356  }
357  for (std::set<int>::const_iterator it = unkId.begin();
358  it != unkId.end(); it++) {
359  std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
360  s << (*ci).second;
361  }
362  s << banned;
363  }
364 
365  template <typename Stream> void Unserialize(Stream &s) {
366  LOCK(cs);
367 
368  int nVersion;
369  s >> nVersion;
370 
371  CAddrDb *db = const_cast<CAddrDb *>(this);
372  db->nId = 0;
373  int n;
374  s >> n;
375  for (int i = 0; i < n; i++) {
376  SeederAddrInfo info;
377  s >> info;
378  if (!info.GetBanTime()) {
379  int id = db->nId++;
380  db->idToInfo[id] = info;
381  db->ipToId[info.ip] = id;
382  if (info.ourLastTry) {
383  db->ourId.push_back(id);
384  if (info.IsReliable()) {
385  db->goodId.insert(id);
386  }
387  } else {
388  db->unkId.insert(id);
389  }
390  }
391  }
392  db->nDirty++;
393 
394  s >> banned;
395  }
396 
397  void Add(const CAddress &addr, bool fForce = false) {
398  LOCK(cs);
399  Add_(addr, fForce);
400  }
401 
402  void Add(const std::vector<CAddress> &vAddr, bool fForce = false) {
403  LOCK(cs);
404  for (size_t i = 0; i < vAddr.size(); i++) {
405  Add_(vAddr[i], fForce);
406  }
407  }
408 
409  void GetMany(std::vector<CServiceResult> &ips, int max, int &wait) {
410  LOCK(cs);
411  while (max > 0) {
412  CServiceResult ip = {};
413  if (!Get_(ip, wait)) {
414  return;
415  }
416  ips.push_back(ip);
417  max--;
418  }
419  }
420 
421  void ResultMany(const std::vector<CServiceResult> &ips) {
422  LOCK(cs);
423  for (size_t i = 0; i < ips.size(); i++) {
424  if (ips[i].fGood) {
425  Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV,
426  ips[i].nHeight, ips[i].services);
427  } else {
428  Bad_(ips[i].service, ips[i].nBanTime);
429  }
430  }
431  }
432 
433  void GetIPs(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
434  const bool *nets) {
435  LOCK(cs);
436  GetIPs_(ips, requestedFlags, max, nets);
437  }
438 };
439 
440 #endif // BITCOIN_SEEDER_DB_H
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
Definition: db.h:261
void Add(const CAddress &addr, bool fForce=false)
Definition: db.h:397
std::set< int > unkId
Definition: db.h:273
void Bad_(const CService &ip, int ban)
Definition: db.cpp:112
RecursiveMutex cs
Definition: db.h:263
void ResultMany(const std::vector< CServiceResult > &ips)
Definition: db.h:421
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:300
void GetIPs_(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.cpp:192
int nId
Definition: db.h:265
void GetIPs(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.h:433
std::set< int > goodId
Definition: db.h:275
void Unserialize(Stream &s)
Definition: db.h:365
int nDirty
Definition: db.h:276
std::map< CService, int > ipToId
Definition: db.h:269
std::map< CService, int64_t > banned
Definition: db.h:298
std::vector< CAddrReport > GetAll()
Definition: db.h:321
std::deque< int > ourId
Definition: db.h:271
std::map< int, SeederAddrInfo > idToInfo
Definition: db.h:267
void ResetIgnores()
Definition: db.h:314
void Add(const std::vector< CAddress > &vAddr, bool fForce=false)
Definition: db.h:402
void Serialize(Stream &s) const
Definition: db.h:343
void GetMany(std::vector< CServiceResult > &ips, int max, int &wait)
Definition: db.h:409
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:235
int nAvail
Definition: db.h:234
int nNew
Definition: db.h:236
int nGood
Definition: db.h:237
int nBanned
Definition: db.h:233
int nAge
Definition: db.h:238
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:134
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
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:202
int64_t GetIgnoreTime() const
Definition: db.h:175
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:153
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 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:34
int nHeight
Definition: db.h:246
int nBanTime
Definition: db.h:245
CService service
Definition: db.h:242
std::string strClientV
Definition: db.h:248
uint64_t services
Definition: db.h:243
int64_t ourLastSuccess
Definition: db.h:249
bool fGood
Definition: db.h:244
int nClientV
Definition: db.h:247
#define LOCK(cs)
Definition: sync.h:306
int64_t GetTime()
Definition: time.cpp:109