Bitcoin ABC 0.30.5
P2P Digital Currency
main.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 <clientversion.h>
6#include <common/args.h>
7#include <dnsseeds.h>
8#include <logging.h>
9#include <protocol.h>
10#include <seeder/bitcoin.h>
11#include <seeder/db.h>
12#include <seeder/dns.h>
13#include <seeder/options.h>
14#include <streams.h>
15#include <util/fs.h>
16#include <util/strencodings.h>
17#include <util/time.h>
18#include <util/translation.h>
19
20#include <algorithm>
21#include <atomic>
22#include <cinttypes>
23#include <csignal>
24#include <cstdlib>
25#include <fstream>
26#include <functional>
27#include <pthread.h>
28
29const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
30
31extern "C" {
32#include <seeder/dns.h>
33}
34
36
37extern "C" void *ThreadCrawler(void *data) {
38 int *nThreads = (int *)data;
39 do {
40 std::vector<CServiceResult> ips;
41 db.GetMany(ips, 16);
42 int64_t now = GetTime();
43 if (ips.empty()) {
44 UninterruptibleSleep(std::chrono::milliseconds(
45 5000 + std::rand() % (500 * *nThreads)));
46 continue;
47 }
48
49 std::vector<CAddress> addr;
50 for (size_t i = 0; i < ips.size(); i++) {
51 CServiceResult &res = ips[i];
52 res.nBanTime = 0;
53 res.nClientV = 0;
54 res.nHeight = 0;
55 res.strClientV = "";
56 res.services = 0;
57 bool getaddr = res.ourLastSuccess + 86400 < now;
58 try {
59 CSeederNode node(res.service, getaddr ? &addr : nullptr);
60 bool ret = node.Run();
61 if (!ret) {
62 res.nBanTime = node.GetBan();
63 } else {
64 res.nBanTime = 0;
65 }
66 res.nClientV = node.GetClientVersion();
67 res.strClientV = node.GetClientSubVersion();
68 res.nHeight = node.GetStartingHeight();
69 res.services = node.GetServices();
70 res.checkpointVerified = node.IsCheckpointVerified();
71 // tfm::format(std::cout, "%s: %s!!!\n", cip.ToString(),
72 // ret ? "GOOD" : "BAD");
73 res.fGood = ret;
74 } catch (std::ios_base::failure &e) {
75 res.nBanTime = 0;
76 res.fGood = false;
77 }
78 }
79
80 db.ResultMany(ips);
81 db.Add(addr);
82 } while (1);
83 return nullptr;
84}
85
86extern "C" uint32_t GetIPList(void *thread, char *requestedHostname,
87 addr_t *addr, uint32_t max, uint32_t ipv4,
88 uint32_t ipv6);
89
91public:
94 std::vector<addr_t> cache;
95 time_t cacheTime;
96 unsigned int cacheHits;
98 };
99
100 dns_opt_t dns_opt; // must be first
101 const int id;
102 std::map<uint64_t, FlagSpecificData> perflag;
103 std::atomic<uint64_t> dbQueries;
104 std::set<uint64_t> filterWhitelist;
105
106 void cacheHit(uint64_t requestedFlags, bool force = false) {
107 static bool nets[NET_MAX] = {};
108 if (!nets[NET_IPV4]) {
109 nets[NET_IPV4] = true;
110 nets[NET_IPV6] = true;
111 }
112 int64_t now = GetTime();
113 FlagSpecificData &thisflag = perflag[requestedFlags];
114 thisflag.cacheHits++;
115 if (force ||
116 thisflag.cacheHits * 400 >
117 (thisflag.cache.size() * thisflag.cache.size()) ||
118 (thisflag.cacheHits * thisflag.cacheHits * 20 >
119 thisflag.cache.size() &&
120 (now - thisflag.cacheTime > 5))) {
121 std::set<CNetAddr> ips;
122 db.GetIPs(ips, requestedFlags, 1000, nets);
123 dbQueries++;
124 thisflag.cache.clear();
125 thisflag.nIPv4 = 0;
126 thisflag.nIPv6 = 0;
127 thisflag.cache.reserve(ips.size());
128 for (auto &ip : ips) {
129 struct in_addr addr;
130 struct in6_addr addr6;
131 if (ip.GetInAddr(&addr)) {
132 addr_t a;
133 a.v = 4;
134 memcpy(&a.data.v4, &addr, 4);
135 thisflag.cache.push_back(a);
136 thisflag.nIPv4++;
137 } else if (ip.GetIn6Addr(&addr6)) {
138 addr_t a;
139 a.v = 6;
140 memcpy(&a.data.v6, &addr6, 16);
141 thisflag.cache.push_back(a);
142 thisflag.nIPv6++;
143 }
144 }
145 thisflag.cacheHits = 0;
146 thisflag.cacheTime = now;
147 }
148 }
149
150 CDnsThread(seeder::CDnsSeedOpts *opts, int idIn) : id(idIn) {
151 dns_opt.host = opts->host.c_str();
152 dns_opt.ns = opts->ns.c_str();
153 dns_opt.mbox = opts->mbox.c_str();
154 dns_opt.datattl = 3600;
155 dns_opt.nsttl = 40000;
157 dns_opt.addr = opts->ip_addr.c_str();
158 dns_opt.port = opts->nPort;
159 dns_opt.nRequests = 0;
160 dbQueries = 0;
161 perflag.clear();
163 }
164
165 void run() { dnsserver(&dns_opt); }
166};
167
168extern "C" uint32_t GetIPList(void *data, char *requestedHostname, addr_t *addr,
169 uint32_t max, uint32_t ipv4, uint32_t ipv6) {
170 CDnsThread *thread = (CDnsThread *)data;
171
172 uint64_t requestedFlags = 0;
173 int hostlen = strlen(requestedHostname);
174 if (hostlen > 1 && requestedHostname[0] == 'x' &&
175 requestedHostname[1] != '0') {
176 char *pEnd;
177 uint64_t flags = (uint64_t)strtoull(requestedHostname + 1, &pEnd, 16);
178 if (*pEnd == '.' && pEnd <= requestedHostname + 17 &&
179 std::find(thread->filterWhitelist.begin(),
180 thread->filterWhitelist.end(),
181 flags) != thread->filterWhitelist.end()) {
182 requestedFlags = flags;
183 } else {
184 return 0;
185 }
186 } else if (strcasecmp(requestedHostname, thread->dns_opt.host)) {
187 return 0;
188 }
189 thread->cacheHit(requestedFlags);
190 auto &thisflag = thread->perflag[requestedFlags];
191 uint32_t size = thisflag.cache.size();
192 uint32_t maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0);
193 if (max > size) {
194 max = size;
195 }
196 if (max > maxmax) {
197 max = maxmax;
198 }
199 uint32_t i = 0;
200 while (i < max) {
201 uint32_t j = i + (rand() % (size - i));
202 do {
203 bool ok = (ipv4 && thisflag.cache[j].v == 4) ||
204 (ipv6 && thisflag.cache[j].v == 6);
205 if (ok) {
206 break;
207 }
208 j++;
209 if (j == size) {
210 j = i;
211 }
212 } while (1);
213 addr[i] = thisflag.cache[j];
214 thisflag.cache[j] = thisflag.cache[i];
215 thisflag.cache[i] = addr[i];
216 i++;
217 }
218 return max;
219}
220
221std::vector<CDnsThread *> dnsThread;
222
223extern "C" void *ThreadDNS(void *arg) {
224 CDnsThread *thread = (CDnsThread *)arg;
225 thread->run();
226 return nullptr;
227}
228
229int StatCompare(const CAddrReport &a, const CAddrReport &b) {
230 if (a.uptime[4] == b.uptime[4]) {
231 if (a.uptime[3] == b.uptime[3]) {
232 return a.clientVersion > b.clientVersion;
233 } else {
234 return a.uptime[3] > b.uptime[3];
235 }
236 } else {
237 return a.uptime[4] > b.uptime[4];
238 }
239}
240
241extern "C" void *ThreadDumper(void *data) {
242 assert(data);
243 const auto dumpInterval(*(const std::chrono::seconds *)data);
244
245 // First dump should occur no later than 10 seconds. Successive dumps will
246 // occur every dump interval.
247 UninterruptibleSleep(std::min(10s, dumpInterval));
248 do {
249 {
250 std::vector<CAddrReport> v = db.GetAll();
251 sort(v.begin(), v.end(), StatCompare);
252 FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+");
253 if (f) {
254 {
256 cf << db;
257 }
258 rename("dnsseed.dat.new", "dnsseed.dat");
259 }
260 std::ofstream d{"dnsseed.dump"};
262 d, "# address good "
263 "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) "
264 "%%(30d) blocks svcs version\n");
265 double stat[5] = {0, 0, 0, 0, 0};
266 for (CAddrReport rep : v) {
268 d,
269 "%-47s %4d %11" PRId64
270 " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64
271 " %5i \"%s\"\n",
272 rep.ip.ToString(),
273 rep.reliabilityStatus == ReliabilityStatus::OK ? 1 : 0,
274 rep.lastSuccess, 100.0 * rep.uptime[0],
275 100.0 * rep.uptime[1], 100.0 * rep.uptime[2],
276 100.0 * rep.uptime[3], 100.0 * rep.uptime[4], rep.blocks,
277 rep.services, rep.clientVersion, rep.clientSubVersion);
278 stat[0] += rep.uptime[0];
279 stat[1] += rep.uptime[1];
280 stat[2] += rep.uptime[2];
281 stat[3] += rep.uptime[3];
282 stat[4] += rep.uptime[4];
283 }
284 std::ofstream ff{"dnsstats.log", std::ios_base::app};
285 tfm::format(ff, "%llu %g %g %g %g %g\n", GetTime(), stat[0],
286 stat[1], stat[2], stat[3], stat[4]);
287 // End scope so all streams flush before sleeping
288 }
289
290 UninterruptibleSleep(dumpInterval);
291 } while (1);
292 return nullptr;
293}
294
295extern "C" void *ThreadStats(void *) {
296 bool first = true;
297 do {
298 char c[256];
299 time_t tim = time(nullptr);
300 struct tm *tmp = localtime(&tim);
301 strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp);
302 CAddrDbStats stats;
303 db.GetStats(stats);
304 if (first) {
305 first = false;
306 tfm::format(std::cout, "\n\n\n\x1b[3A");
307 } else {
308 tfm::format(std::cout, "\x1b[2K\x1b[u");
309 }
310 tfm::format(std::cout, "\x1b[s");
311 uint64_t requests = 0;
312 uint64_t queries = 0;
313 for (unsigned int i = 0; i < dnsThread.size(); i++) {
314 requests += dnsThread[i]->dns_opt.nRequests;
315 queries += dnsThread[i]->dbQueries;
316 }
318 std::cout,
319 "%s %i/%i available (%i tried in %is, %i new, %i active), %i "
320 "banned; %llu DNS requests, %llu db queries\n",
321 c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge,
322 stats.nNew, stats.nAvail - stats.nTracked - stats.nNew,
323 stats.nBanned, (unsigned long long)requests,
324 (unsigned long long)queries);
326 } while (1);
327 return nullptr;
328}
329
330const static unsigned int MAX_HOSTS_PER_SEED = 128;
331
332extern "C" void *ThreadSeeder(void *) {
333 do {
334 for (const std::string &seed : GetRandomizedDNSSeeds(Params())) {
335 std::vector<CNetAddr> ips;
336 LookupHost(seed.c_str(), ips, MAX_HOSTS_PER_SEED, true);
337 for (auto &ip : ips) {
339 true);
340 }
341 }
343 } while (1);
344 return nullptr;
345}
346
347int main(int argc, char **argv) {
348 // The logger dump everything on the console by default.
350
351 signal(SIGPIPE, SIG_IGN);
352 setbuf(stdout, nullptr);
354 opts.SetupSeederArgs();
355 int parseResults =
356 opts.ParseCommandLine(argc, const_cast<const char **>(argv));
357 if (parseResults != seeder::CONTINUE_EXECUTION) {
358 return parseResults;
359 }
360
361 tfm::format(std::cout, "Supporting whitelisted filters: ");
362 for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin();
363 it != opts.filter_whitelist.end(); it++) {
364 if (it != opts.filter_whitelist.begin()) {
365 tfm::format(std::cout, ",");
366 }
367 tfm::format(std::cout, "0x%lx", (unsigned long)*it);
368 }
369 tfm::format(std::cout, "\n");
370 if (!opts.tor.empty()) {
371 CService service(LookupNumeric(opts.tor.c_str(), 9050));
372 if (service.IsValid()) {
373 tfm::format(std::cout, "Using Tor proxy at %s\n",
374 service.ToStringIPPort());
375 SetProxy(NET_ONION, proxyType(service));
376 }
377 }
378 if (!opts.ipv4_proxy.empty()) {
379 CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050));
380 if (service.IsValid()) {
381 tfm::format(std::cout, "Using IPv4 proxy at %s\n",
382 service.ToStringIPPort());
383 SetProxy(NET_IPV4, proxyType(service));
384 }
385 }
386 if (!opts.ipv6_proxy.empty()) {
387 CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050));
388 if (service.IsValid()) {
389 tfm::format(std::cout, "Using IPv6 proxy at %s\n",
390 service.ToStringIPPort());
391 SetProxy(NET_IPV6, proxyType(service));
392 }
393 }
394 bool fDNS = true;
395 tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName());
396 if (opts.ns.empty()) {
397 tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n");
398 fDNS = false;
399 }
400 if (fDNS && opts.host.empty()) {
401 tfm::format(std::cerr, "No hostname set. Please use -h.\n");
402 return EXIT_FAILURE;
403 }
404 if (fDNS && opts.mbox.empty()) {
405 tfm::format(std::cerr, "No e-mail address set. Please use -m.\n");
406 return EXIT_FAILURE;
407 }
408 FILE *f = fsbridge::fopen("dnsseed.dat", "r");
409 if (f) {
410 tfm::format(std::cout, "Loading dnsseed.dat...");
412 cf >> db;
413 if (opts.fWipeBan) {
414 db.banned.clear();
415 tfm::format(std::cout, "Ban list wiped...");
416 }
417 if (opts.fWipeIgnore) {
419 tfm::format(std::cout, "Ignore list wiped...");
420 }
421 tfm::format(std::cout, "done\n");
422 }
423 pthread_t threadDns, threadSeed, threadDump, threadStats;
424 if (fDNS) {
425 tfm::format(std::cout,
426 "Starting %i DNS threads for %s on %s (port %i)...",
427 opts.nDnsThreads, opts.host, opts.ns, opts.nPort);
428 dnsThread.clear();
429 for (int i = 0; i < opts.nDnsThreads; i++) {
430 dnsThread.push_back(new CDnsThread(&opts, i));
431 pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]);
432 tfm::format(std::cout, ".");
434 }
435 tfm::format(std::cout, "done\n");
436 }
437 tfm::format(std::cout, "Starting seeder...");
438 pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr);
439 tfm::format(std::cout, "done\n");
440 tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads);
441 pthread_attr_t attr_crawler;
442 pthread_attr_init(&attr_crawler);
443 pthread_attr_setstacksize(&attr_crawler, 0x20000);
444 for (int i = 0; i < opts.nThreads; i++) {
445 pthread_t thread;
446 pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads);
447 }
448 pthread_attr_destroy(&attr_crawler);
449 tfm::format(std::cout, "done\n");
450 pthread_create(&threadStats, nullptr, ThreadStats, nullptr);
451 pthread_create(&threadDump, nullptr, ThreadDumper, &opts.dumpInterval);
452 void *res;
453 pthread_join(threadDump, &res);
454 return EXIT_SUCCESS;
455}
ArgsManager gArgs
Definition: args.cpp:38
int flags
Definition: bitcoin-tx.cpp:541
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition: args.cpp:793
bool m_print_to_console
Definition: logging.h:103
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
void ResultMany(const std::vector< CServiceResult > &ips)
Definition: db.h:442
void GetStats(CAddrDbStats &stats) const
Definition: db.h:322
std::vector< CAddrReport > GetAll()
Definition: db.h:343
void GetIPs(std::set< CNetAddr > &ips, uint64_t requestedFlags, uint32_t max, const bool *nets)
Definition: db.h:455
std::map< CService, int64_t > banned
Definition: db.h:320
void ResetIgnores()
Definition: db.h:336
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
int clientVersion
Definition: db.h:81
A CService with information about it as peer.
Definition: protocol.h:442
dns_opt_t dns_opt
Definition: main.cpp:100
void run()
Definition: main.cpp:165
std::atomic< uint64_t > dbQueries
Definition: main.cpp:103
std::set< uint64_t > filterWhitelist
Definition: main.cpp:104
std::map< uint64_t, FlagSpecificData > perflag
Definition: main.cpp:102
const int id
Definition: main.cpp:101
CDnsThread(seeder::CDnsSeedOpts *opts, int idIn)
Definition: main.cpp:150
void cacheHit(uint64_t requestedFlags, bool force=false)
Definition: main.cpp:106
bool IsValid() const
Definition: netaddress.cpp:477
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
std::string ToStringIPPort() const
std::string ip_addr
Definition: options.h:45
std::chrono::seconds dumpInterval
Definition: options.h:35
std::string tor
Definition: options.h:44
std::string ipv4_proxy
Definition: options.h:46
std::string ns
Definition: options.h:42
int ParseCommandLine(int argc, const char **argv)
Definition: options.cpp:15
std::string host
Definition: options.h:43
std::string mbox
Definition: options.h:41
std::set< uint64_t > filter_whitelist
Definition: options.h:48
std::string ipv6_proxy
Definition: options.h:47
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
int dnsserver(dns_opt_t *opt)
Definition: dns.cpp:596
const std::vector< std::string > GetRandomizedDNSSeeds(const CChainParams &params)
Return the list of hostnames to look up for DNS seeds.
Definition: dnsseeds.cpp:11
BCLog::Logger & LogInstance()
Definition: logging.cpp:20
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
Definition: init.h:28
static const int CONTINUE_EXECUTION
Definition: options.h:16
void format(std::ostream &out, const char *fmt, const Args &...args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1112
@ NET_MAX
Dummy value to indicate the number of NET_* constants.
Definition: netaddress.h:69
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:56
@ NET_IPV6
IPv6.
Definition: netaddress.h:53
@ NET_IPV4
IPv4.
Definition: netaddress.h:50
CService LookupNumeric(const std::string &name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
Resolve a service string with a numeric IP to its first corresponding service.
Definition: netbase.cpp:261
bool LookupHost(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition: netbase.cpp:191
bool SetProxy(enum Network net, const proxyType &addrProxy)
Definition: netbase.cpp:705
ServiceFlags
nServices flags.
Definition: protocol.h:335
int main(int argc, char *argv[])
Definition: main.cpp:20
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoin-cli.cpp:47
static uint16_t GetDefaultPort()
Definition: bitcoin.h:18
int StatCompare(const CAddrReport &a, const CAddrReport &b)
Definition: main.cpp:229
void * ThreadDNS(void *arg)
Definition: main.cpp:223
CAddrDb db
Definition: main.cpp:35
void * ThreadDumper(void *data)
Definition: main.cpp:241
std::vector< CDnsThread * > dnsThread
Definition: main.cpp:221
void * ThreadStats(void *)
Definition: main.cpp:295
uint32_t GetIPList(void *thread, char *requestedHostname, addr_t *addr, uint32_t max, uint32_t ipv4, uint32_t ipv6)
Definition: main.cpp:168
static const unsigned int MAX_HOSTS_PER_SEED
Definition: main.cpp:330
void * ThreadSeeder(void *)
Definition: main.cpp:332
void * ThreadCrawler(void *data)
Definition: main.cpp:37
@ SER_DISK
Definition: serialize.h:153
std::vector< addr_t > cache
Definition: main.cpp:94
unsigned int cacheHits
Definition: main.cpp:96
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
Definition: dns.h:16
uint8_t v6[16]
Definition: dns.h:20
union addr_t::@17 data
uint8_t v4[4]
Definition: dns.h:19
int v
Definition: dns.h:17
Definition: dns.h:24
int nsttl
Definition: dns.h:27
const char * ns
Definition: dns.h:30
uint32_t(* cb)(void *opt, char *requested_hostname, addr_t *addr, uint32_t max, uint32_t ipv4, uint32_t ipv6)
Definition: dns.h:32
int datattl
Definition: dns.h:26
const char * addr
Definition: dns.h:29
uint64_t nRequests
Definition: dns.h:35
const char * host
Definition: dns.h:28
int port
Definition: dns.h:25
const char * mbox
Definition: dns.h:31
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:109
assert(!tx.IsCoinBase())