Bitcoin ABC 0.30.5
P2P Digital Currency
db.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2020 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#include <seeder/db.h>
6
7#include <util/time.h>
8
9#include <cstdlib>
10
11void SeederAddrInfo::Update(bool good) {
12 int64_t now = GetTime();
13 if (ourLastTry == 0) {
14 ourLastTry = now - MIN_RETRY;
15 }
16 int age = now - ourLastTry;
17 lastTry = now;
18 ourLastTry = now;
19 total++;
20 if (good) {
21 success++;
22 ourLastSuccess = now;
23 }
24 stat2H.Update(good, age, 3600 * 2);
25 stat8H.Update(good, age, 3600 * 8);
26 stat1D.Update(good, age, 3600 * 24);
27 stat1W.Update(good, age, 3600 * 24 * 7);
28 stat1M.Update(good, age, 3600 * 24 * 30);
29 int64_t ign = GetIgnoreTime();
30 if (ign && (ignoreTill == 0 || ignoreTill < ign + now)) {
31 ignoreTill = ign + now;
32 }
33 // tfm::format(std::cout, "%s: got %s result: success=%i/%i;
34 // 2H:%.2f%%-%.2f%%(%.2f) 8H:%.2f%%-%.2f%%(%.2f) 1D:%.2f%%-%.2f%%(%.2f)
35 // 1W:%.2f%%-%.2f%%(%.2f) \n", ToString(ip), good ? "good" : "bad",
36 // success, total, 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability
37 // + 1.0 - stat2H.weight), stat2H.count, 100.0 * stat8H.reliability, 100.0
38 // * (stat8H.reliability + 1.0 - stat8H.weight), stat8H.count, 100.0 *
39 // stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - stat1D.weight),
40 // stat1D.count, 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability
41 // + 1.0 - stat1W.weight), stat1W.count);
42}
43
45 int64_t now = GetTime();
46 size_t tot = unkId.size() + ourId.size();
47 if (tot == 0) {
48 return false;
49 }
50
51 do {
52 size_t rnd = rand() % tot;
53 int ret;
54 if (rnd < unkId.size()) {
55 std::set<int>::iterator it = unkId.end();
56 it--;
57 ret = *it;
58 unkId.erase(it);
59 } else {
60 ret = ourId.front();
61 if (GetTime() - idToInfo[ret].ourLastTry < MIN_RETRY) {
62 return false;
63 }
64 ourId.pop_front();
65 }
66
67 if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) {
68 ourId.push_back(ret);
69 idToInfo[ret].ourLastTry = now;
70 } else {
71 ip.service = idToInfo[ret].ip;
72 ip.ourLastSuccess = idToInfo[ret].ourLastSuccess;
73 break;
74 }
75 } while (1);
76
77 return true;
78}
79
80int CAddrDb::Lookup_(const CService &ip) {
81 if (ipToId.count(ip)) {
82 return ipToId[ip];
83 }
84 return -1;
85}
86
87void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV,
88 int blocks, uint64_t services, bool checkpointVerified) {
89 int id = Lookup_(addr);
90 if (id == -1) {
91 return;
92 }
93 unkId.erase(id);
94 banned.erase(addr);
95 SeederAddrInfo &info = idToInfo[id];
96 info.clientVersion = clientV;
97 info.clientSubVersion = clientSV;
98 info.blocks = blocks;
99 info.services = services;
100 info.checkpointVerified = checkpointVerified;
101 info.Update(true);
102 if (info.IsReliable() && goodId.count(id) == 0) {
103 goodId.insert(id);
104 // tfm::format(std::cout, "%s: good; %i good nodes now\n",
105 // ToString(addr), (int)goodId.size());
106 }
107 ourId.push_back(id);
108}
109
110void CAddrDb::Bad_(const CService &addr, int ban) {
111 int id = Lookup_(addr);
112 if (id == -1) {
113 return;
114 }
115 unkId.erase(id);
116 SeederAddrInfo &info = idToInfo[id];
117 info.Update(false);
118 uint32_t now = GetTime();
119 int ter = info.GetBanTime();
120 if (ter) {
121 // tfm::format(std::cout, "%s: terrible\n", ToString(addr));
122 if (ban < ter) {
123 ban = ter;
124 }
125 }
126 if (ban > 0) {
127 // tfm::format(std::cout, "%s: ban for %i seconds\n",
128 // ToString(addr), ban);
129 banned[info.ip] = ban + now;
130 ipToId.erase(info.ip);
131 goodId.erase(id);
132 idToInfo.erase(id);
133 } else {
134 if ( goodId.count(id) == 1) {
135 goodId.erase(id);
136 // tfm::format(std::cout, "%s: not good; %i good nodes left\n",
137 // ToString(addr), (int)goodId.size());
138 }
139 ourId.push_back(id);
140 }
141}
142
143void CAddrDb::Add_(const CAddress &addr, bool force) {
144 if (!force && !addr.IsRoutable()) {
145 return;
146 }
147 CService ipp(addr);
148 if (banned.count(ipp)) {
149 time_t bantime = banned[ipp];
150 if (force ||
151 (bantime < time(nullptr) &&
152 addr.nTime > NodeSeconds{std::chrono::seconds{bantime}})) {
153 banned.erase(ipp);
154 } else {
155 return;
156 }
157 }
158 if (ipToId.count(ipp)) {
159 SeederAddrInfo &ai = idToInfo[ipToId[ipp]];
160 if (addr.nTime > NodeSeconds{std::chrono::seconds{ai.lastTry}} ||
161 ai.services != addr.nServices) {
162 ai.lastTry = TicksSinceEpoch<std::chrono::seconds>(addr.nTime);
163 ai.services |= addr.nServices;
164 // tfm::format(std::cout, "%s: updated\n",
165 // ToString(addr));
166 }
167 if (force) {
168 ai.ignoreTill = 0;
169 }
170 return;
171 }
172
174 ai.ip = ipp;
175 ai.services = addr.nServices;
176 ai.lastTry = TicksSinceEpoch<std::chrono::seconds>(addr.nTime);
177 ai.ourLastTry = 0;
178 ai.total = 0;
179 ai.success = 0;
180 int id = nId++;
181 idToInfo[id] = ai;
182 ipToId[ipp] = id;
183 // tfm::format(std::cout, "%s: added\n", ToString(ipp),
184 // ipToId[ipp]);
185 unkId.insert(id);
186}
187
188void CAddrDb::GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags,
189 uint32_t max, const bool *nets) {
190 if (goodId.size() == 0) {
191 int id = -1;
192 if (ourId.size() == 0) {
193 if (unkId.size() == 0) {
194 return;
195 }
196 id = *unkId.begin();
197 } else {
198 id = *ourId.begin();
199 }
200
201 if (id >= 0 &&
202 (idToInfo[id].services & requestedFlags) == requestedFlags) {
203 ips.insert(idToInfo[id].ip);
204 }
205 return;
206 }
207
208 std::vector<int> goodIdFiltered;
209 for (auto &id : goodId) {
210 if ((idToInfo[id].services & requestedFlags) == requestedFlags) {
211 goodIdFiltered.push_back(id);
212 }
213 }
214
215 if (!goodIdFiltered.size()) {
216 return;
217 }
218
219 if (max > goodIdFiltered.size() / 2) {
220 max = goodIdFiltered.size() / 2;
221 }
222
223 if (max < 1) {
224 max = 1;
225 }
226
227 std::set<int> ids;
228 while (ids.size() < max) {
229 ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]);
230 }
231
232 for (auto &id : ids) {
233 CService &ip = idToInfo[id].ip;
234 if (nets[ip.GetNetwork()]) {
235 ips.insert(ip);
236 }
237 }
238}
std::set< int > unkId
Definition: db.h:296
void Bad_(const CService &ip, int ban)
Definition: db.cpp:110
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::set< int > goodId
Definition: db.h:298
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
bool Get_(CServiceResult &ip)
Definition: db.cpp:44
void Add_(const CAddress &addr, bool force)
Definition: db.cpp:143
int Lookup_(const CService &ip)
Definition: db.cpp:80
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
NodeSeconds nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
Definition: protocol.h:544
bool IsRoutable() const
Definition: netaddress.cpp:512
enum Network GetNetwork() const
Definition: netaddress.cpp:549
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
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
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
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
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
int clientVersion
Definition: db.h:103
#define MIN_RETRY
Definition: db.h:24
CService service
Definition: db.h:264
int64_t ourLastSuccess
Definition: db.h:271
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:109
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25