Bitcoin ABC 0.30.5
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
28static inline int GetRequireHeight() {
29 return Params().Checkpoints().mapCheckpoints.rbegin()->first;
30}
31
32static inline bool HasCheckpoint() {
33 return !Params().Checkpoints().mapCheckpoints.empty() &&
34 GetRequireHeight() > 0;
35}
36
37static inline std::string ToString(const CService &ip) {
38 std::string str = ip.ToString();
39 while (str.size() < 22) {
40 str += ' ';
41 }
42 return str;
43}
44
45class CAddrStat {
46private:
47 float weight;
48 float count;
50
51public:
53
54 void Update(bool good, int64_t age, double tau) {
55 double f = exp(-age / tau);
56 reliability = reliability * f + (good ? (1.0 - f) : 0);
57 count = count * f + 1;
58 weight = weight * f + (1.0 - f);
59 }
60
62 READWRITE(obj.weight, obj.count, obj.reliability);
63 }
64
65 friend class SeederAddrInfo;
66};
67
69 OK,
76};
77
79public:
82 int blocks;
83 double uptime[5];
84 std::string clientSubVersion;
85 int64_t lastSuccess;
87 uint64_t services;
88};
89
91private:
93 uint64_t services;
94 int64_t lastTry;
95 int64_t ourLastTry;
97 int64_t ignoreTill;
105 int total;
107 std::string clientSubVersion;
109
110public:
112 : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0),
113 ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {}
114
116 CAddrReport ret;
117 ret.ip = ip;
120 ret.blocks = blocks;
121 ret.uptime[0] = stat2H.reliability;
122 ret.uptime[1] = stat8H.reliability;
123 ret.uptime[2] = stat1D.reliability;
124 ret.uptime[3] = stat1W.reliability;
125 ret.uptime[4] = stat1M.reliability;
128 ret.services = services;
129 return ret;
130 }
131
132 bool IsReliable() const {
134 }
135
136 // Return the first detected reason a node is unreliable or `OK` if no
137 // reason found
139 if (!(services & NODE_NETWORK)) {
141 }
142 if (!ip.IsRoutable()) {
144 }
147 }
148 if (blocks && blocks < GetRequireHeight()) {
150 }
151
152 if ((total > 3 || success * 2 < total) &&
153 (stat2H.reliability <= 0.85 || stat2H.count <= 2) &&
154 (stat8H.reliability <= 0.70 || stat8H.count <= 4) &&
155 (stat1D.reliability <= 0.55 || stat1D.count <= 8) &&
156 (stat1W.reliability <= 0.45 || stat1W.count <= 16) &&
157 (stat1M.reliability <= 0.35 || stat1M.count <= 32)) {
159 }
160 if (!checkpointVerified) {
162 }
164 }
165
166 int64_t GetBanTime() const {
167 if (IsReliable()) {
168 return 0;
169 }
170 if (clientVersion && clientVersion < 31900) {
171 return 604800;
172 }
173 if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 &&
174 stat1M.count > 32) {
175 return 30 * 86400;
176 }
177 if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 &&
178 stat1W.count > 16) {
179 return 7 * 86400;
180 }
181 if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 &&
182 stat1D.count > 8) {
183 return 1 * 86400;
184 }
185 return 0;
186 }
187
188 int64_t GetIgnoreTime() const {
189 if (IsReliable()) {
190 return 0;
191 }
192 if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 &&
193 stat1M.count > 2) {
194 return 10 * 86400;
195 }
196 if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 &&
197 stat1W.count > 2) {
198 return 3 * 86400;
199 }
200 if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 &&
201 stat1D.count > 2) {
202 return 8 * 3600;
203 }
204 if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 &&
205 stat8H.count > 2) {
206 return 2 * 3600;
207 }
208 return 0;
209 }
210
211 void Update(bool good);
212
213 friend class CAddrDb;
214
216 uint8_t version = 5;
217 READWRITE(version, obj.ip, obj.services, obj.lastTry);
218 uint8_t tried = obj.ourLastTry != 0;
219 READWRITE(tried);
220 if (!tried) {
221 return;
222 }
223
224 READWRITE(obj.ourLastTry, obj.ignoreTill, obj.stat2H, obj.stat8H,
225 obj.stat1D, obj.stat1W);
226 if (version >= 1) {
227 READWRITE(obj.stat1M);
228 } else {
229 SER_WRITE(obj, *((CAddrStat *)(&obj.stat1M)) = obj.stat1W);
230 }
231 READWRITE(obj.total, obj.success, obj.clientVersion);
232 if (version >= 2) {
233 READWRITE(obj.clientSubVersion);
234 }
235 if (version >= 3) {
236 READWRITE(obj.blocks);
237 }
238 if (version >= 4) {
239 READWRITE(obj.ourLastSuccess);
240 }
241 if (version >= 5) {
242 READWRITE(obj.checkpointVerified);
243 } else {
244 // To avoid a sudden drop of all nodes when seeders upgrade,
245 // initially mark all nodes as having their checkpoints verified,
246 // to keep previously considered good nodes live until they are
247 // later proven bad
248 SER_READ(obj, obj.checkpointVerified = true);
249 }
250 }
251};
252
254public:
258 int nNew;
259 int nGood;
260 int nAge;
261};
262
265 uint64_t services;
266 bool fGood;
270 std::string strClientV;
273};
274
284class CAddrDb {
285private:
287 // number of address id's
288 int nId;
289 // map address id to address info (b,c,d,e)
290 std::map<int, SeederAddrInfo> idToInfo;
291 // map ip to id (b,c,d,e)
292 std::map<CService, int> ipToId;
293 // sequence of tried nodes, in order we have tried connecting to them (c,d)
294 std::deque<int> ourId;
295 // set of nodes not yet tried (b)
296 std::set<int> unkId;
297 // set of good nodes (d, good e)
298 std::set<int> goodId;
299
300protected:
301 // internal routines that assume proper locks are acquired
302 // add an address
303 void Add_(const CAddress &addr, bool force);
304 // get an IP to test (must call Good_ or Bad_ on result afterwards)
305 bool Get_(CServiceResult &ip);
306 // mark an IP as good (must have been returned by Get_)
307 void Good_(const CService &ip, int clientV, std::string clientSV,
308 int blocks, uint64_t services, bool checkpointVerified);
309 // mark an IP as bad (and optionally ban it) (must have been returned by
310 // Get_)
311 void Bad_(const CService &ip, int ban);
312 // look up id of an IP
313 int Lookup_(const CService &ip);
314 // get a random set of IPs (shared lock only)
315 void GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
316 const bool *nets);
317
318public:
319 // nodes that are banned, with their unban time (a)
320 std::map<CService, int64_t> banned;
321
322 void GetStats(CAddrDbStats &stats) const {
323 LOCK(cs);
324 stats.nBanned = banned.size();
325 stats.nAvail = idToInfo.size();
326 stats.nTracked = ourId.size();
327 stats.nGood = goodId.size();
328 stats.nNew = unkId.size();
329 if (ourId.size() > 0) {
330 stats.nAge = GetTime() - idToInfo.at(ourId.at(0)).ourLastTry;
331 } else {
332 stats.nAge = 0;
333 }
334 }
335
337 for (std::map<int, SeederAddrInfo>::iterator it = idToInfo.begin();
338 it != idToInfo.end(); it++) {
339 (*it).second.ignoreTill = 0;
340 }
341 }
342
343 std::vector<CAddrReport> GetAll() {
344 std::vector<CAddrReport> ret;
345 LOCK(cs);
346 for (std::deque<int>::const_iterator it = ourId.begin();
347 it != ourId.end(); it++) {
348 const SeederAddrInfo &info = idToInfo[*it];
349 if (info.success > 0) {
350 ret.push_back(info.GetReport());
351 }
352 }
353 return ret;
354 }
355
356 // serialization code
357 // format:
358 // nVersion (0 for now)
359 // n (number of ips in (b,c,d))
360 // SeederAddrInfo[n]
361 // banned
362 // acquires a shared lock (this does not suffice for read mode, but we
363 // assume that only happens at startup, single-threaded) this way, dumping
364 // does not interfere with GetIPs_, which is called from the DNS thread
365 template <typename Stream> void Serialize(Stream &s) const {
366 LOCK(cs);
367
368 int nVersion = 0;
369 s << nVersion;
370
371 CAddrDb *db = const_cast<CAddrDb *>(this);
372 int n = ourId.size() + unkId.size();
373 s << n;
374 for (std::deque<int>::const_iterator it = ourId.begin();
375 it != ourId.end(); it++) {
376 std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
377 s << (*ci).second;
378 }
379 for (std::set<int>::const_iterator it = unkId.begin();
380 it != unkId.end(); it++) {
381 std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
382 s << (*ci).second;
383 }
384 s << banned;
385 }
386
387 template <typename Stream> void Unserialize(Stream &s) {
388 LOCK(cs);
389
390 int nVersion;
391 s >> nVersion;
392
393 CAddrDb *db = const_cast<CAddrDb *>(this);
394 db->nId = 0;
395 int n;
396 s >> n;
397 for (int i = 0; i < n; i++) {
398 SeederAddrInfo info;
399 s >> info;
400 if (!info.GetBanTime()) {
401 int id = db->nId++;
402 db->idToInfo[id] = info;
403 db->ipToId[info.ip] = id;
404 if (info.ourLastTry) {
405 db->ourId.push_back(id);
406 if (info.IsReliable()) {
407 db->goodId.insert(id);
408 }
409 } else {
410 db->unkId.insert(id);
411 }
412 }
413 }
414
415 s >> banned;
416 }
417
418 void Add(const CAddress &addr, bool fForce = false) {
419 LOCK(cs);
420 Add_(addr, fForce);
421 }
422
423 void Add(const std::vector<CAddress> &vAddr, bool fForce = false) {
424 LOCK(cs);
425 for (size_t i = 0; i < vAddr.size(); i++) {
426 Add_(vAddr[i], fForce);
427 }
428 }
429
430 void GetMany(std::vector<CServiceResult> &ips, int max) {
431 LOCK(cs);
432 while (max > 0) {
433 CServiceResult ip = {};
434 if (!Get_(ip)) {
435 return;
436 }
437 ips.push_back(ip);
438 max--;
439 }
440 }
441
442 void ResultMany(const std::vector<CServiceResult> &ips) {
443 LOCK(cs);
444 for (size_t i = 0; i < ips.size(); i++) {
445 if (ips[i].fGood) {
446 Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV,
447 ips[i].nHeight, ips[i].services,
448 ips[i].checkpointVerified);
449 } else {
450 Bad_(ips[i].service, ips[i].nBanTime);
451 }
452 }
453 }
454
455 void GetIPs(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
456 const bool *nets) {
457 LOCK(cs);
458 GetIPs_(ips, requestedFlags, max, nets);
459 }
460};
461
462#endif // BITCOIN_SEEDER_DB_H
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
Definition: db.h:284
void Add(const CAddress &addr, bool fForce=false)
Definition: db.h:418
void GetMany(std::vector< CServiceResult > &ips, int max)
Definition: db.h:430
std::set< int > unkId
Definition: db.h:296
void Bad_(const CService &ip, int ban)
Definition: db.cpp:110
RecursiveMutex cs
Definition: db.h:286
void ResultMany(const std::vector< CServiceResult > &ips)
Definition: db.h:442
void GetStats(CAddrDbStats &stats) const
Definition: db.h:322
void GetIPs_(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.cpp:188
void Good_(const CService &ip, int clientV, std::string clientSV, int blocks, uint64_t services, bool checkpointVerified)
Definition: db.cpp:87
std::vector< CAddrReport > GetAll()
Definition: db.h:343
int nId
Definition: db.h:288
void GetIPs(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.h:455
std::set< int > goodId
Definition: db.h:298
void Unserialize(Stream &s)
Definition: db.h:387
std::map< CService, int > ipToId
Definition: db.h:292
std::map< CService, int64_t > banned
Definition: db.h:320
std::deque< int > ourId
Definition: db.h:294
std::map< int, SeederAddrInfo > idToInfo
Definition: db.h:290
void ResetIgnores()
Definition: db.h:336
bool Get_(CServiceResult &ip)
Definition: db.cpp:44
void Add(const std::vector< CAddress > &vAddr, bool fForce=false)
Definition: db.h:423
void Serialize(Stream &s) const
Definition: db.h:365
void Add_(const CAddress &addr, bool force)
Definition: db.cpp:143
int Lookup_(const CService &ip)
Definition: db.cpp:80
int nTracked
Definition: db.h:257
int nAvail
Definition: db.h:256
int nNew
Definition: db.h:258
int nGood
Definition: db.h:259
int nBanned
Definition: db.h:255
int nAge
Definition: db.h:260
Definition: db.h:78
double uptime[5]
Definition: db.h:83
uint64_t services
Definition: db.h:87
int blocks
Definition: db.h:82
CService ip
Definition: db.h:80
int clientVersion
Definition: db.h:81
std::string clientSubVersion
Definition: db.h:84
int64_t lastSuccess
Definition: db.h:85
ReliabilityStatus reliabilityStatus
Definition: db.h:86
Definition: db.h:45
SERIALIZE_METHODS(CAddrStat, obj)
Definition: db.h:61
CAddrStat()
Definition: db.h:52
float count
Definition: db.h:48
float weight
Definition: db.h:47
float reliability
Definition: db.h:49
void Update(bool good, int64_t age, double tau)
Definition: db.h:54
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:512
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
std::string ToString() const
int success
Definition: db.h:106
CAddrStat stat8H
Definition: db.h:99
CAddrStat stat1W
Definition: db.h:101
int64_t lastTry
Definition: db.h:94
SERIALIZE_METHODS(SeederAddrInfo, obj)
Definition: db.h:215
int64_t GetIgnoreTime() const
Definition: db.h:188
bool checkpointVerified
Definition: db.h:108
CAddrStat stat1D
Definition: db.h:100
CAddrStat stat2H
Definition: db.h:98
CAddrReport GetReport() const
Definition: db.h:115
int64_t ignoreTill
Definition: db.h:97
int64_t GetBanTime() const
Definition: db.h:166
std::string clientSubVersion
Definition: db.h:107
int total
Definition: db.h:105
bool IsReliable() const
Definition: db.h:132
int64_t ourLastTry
Definition: db.h:95
ReliabilityStatus GetReliabilityStatus() const
Definition: db.h:138
CAddrStat stat1M
Definition: db.h:102
CService ip
Definition: db.h:92
void Update(bool good)
Definition: db.cpp:11
int blocks
Definition: db.h:104
uint64_t services
Definition: db.h:93
int64_t ourLastSuccess
Definition: db.h:96
SeederAddrInfo()
Definition: db.h:111
int clientVersion
Definition: db.h:103
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
static bool HasCheckpoint()
Definition: db.h:32
ReliabilityStatus
Definition: db.h:68
#define REQUIRE_VERSION
Definition: db.h:26
static std::string ToString(const CService &ip)
Definition: db.h:37
CAddrDb db
Definition: main.cpp:35
#define SER_WRITE(obj, code)
Definition: serialize.h:173
#define SER_READ(obj, code)
Definition: serialize.h:169
#define READWRITE(...)
Definition: serialize.h:166
MapCheckpoints mapCheckpoints
Definition: chainparams.h:34
int nHeight
Definition: db.h:268
int nBanTime
Definition: db.h:267
CService service
Definition: db.h:264
std::string strClientV
Definition: db.h:270
uint64_t services
Definition: db.h:265
int64_t ourLastSuccess
Definition: db.h:271
bool fGood
Definition: db.h:266
int nClientV
Definition: db.h:269
bool checkpointVerified
Definition: db.h:272
#define LOCK(cs)
Definition: sync.h:306
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:109