Bitcoin ABC  0.29.2
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 <dnsseeds.h>
7 #include <fs.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/strencodings.h>
16 #include <util/system.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 
29 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
30 
31 extern "C" {
32 #include <seeder/dns.h>
33 }
34 
36 
37 extern "C" void *ThreadCrawler(void *data) {
38  int *nThreads = (int *)data;
39  do {
40  std::vector<CServiceResult> ips;
41  int wait = 5;
42  db.GetMany(ips, 16, wait);
43  int64_t now = GetTime();
44  if (ips.empty()) {
45  wait *= 1000;
46  wait += rand() % (500 * *nThreads);
47  UninterruptibleSleep(std::chrono::milliseconds(wait));
48  continue;
49  }
50 
51  std::vector<CAddress> addr;
52  for (size_t i = 0; i < ips.size(); i++) {
53  CServiceResult &res = ips[i];
54  res.nBanTime = 0;
55  res.nClientV = 0;
56  res.nHeight = 0;
57  res.strClientV = "";
58  res.services = 0;
59  bool getaddr = res.ourLastSuccess + 86400 < now;
60  try {
61  CSeederNode node(res.service, getaddr ? &addr : nullptr);
62  bool ret = node.Run();
63  if (!ret) {
64  res.nBanTime = node.GetBan();
65  } else {
66  res.nBanTime = 0;
67  }
68  res.nClientV = node.GetClientVersion();
69  res.strClientV = node.GetClientSubVersion();
70  res.nHeight = node.GetStartingHeight();
71  res.services = node.GetServices();
72  // tfm::format(std::cout, "%s: %s!!!\n", cip.ToString(),
73  // ret ? "GOOD" : "BAD");
74  res.fGood = ret;
75  } catch (std::ios_base::failure &e) {
76  res.nBanTime = 0;
77  res.fGood = false;
78  }
79  }
80 
81  db.ResultMany(ips);
82  db.Add(addr);
83  } while (1);
84  return nullptr;
85 }
86 
87 extern "C" uint32_t GetIPList(void *thread, char *requestedHostname,
88  addr_t *addr, uint32_t max, uint32_t ipv4,
89  uint32_t ipv6);
90 
91 class CDnsThread {
92 public:
94  int nIPv4, nIPv6;
95  std::vector<addr_t> cache;
96  time_t cacheTime;
97  unsigned int cacheHits;
99  };
100 
101  dns_opt_t dns_opt; // must be first
102  const int id;
103  std::map<uint64_t, FlagSpecificData> perflag;
104  std::atomic<uint64_t> dbQueries;
105  std::set<uint64_t> filterWhitelist;
106 
107  void cacheHit(uint64_t requestedFlags, bool force = false) {
108  static bool nets[NET_MAX] = {};
109  if (!nets[NET_IPV4]) {
110  nets[NET_IPV4] = true;
111  nets[NET_IPV6] = true;
112  }
113  int64_t now = GetTime();
114  FlagSpecificData &thisflag = perflag[requestedFlags];
115  thisflag.cacheHits++;
116  if (force ||
117  thisflag.cacheHits * 400 >
118  (thisflag.cache.size() * thisflag.cache.size()) ||
119  (thisflag.cacheHits * thisflag.cacheHits * 20 >
120  thisflag.cache.size() &&
121  (now - thisflag.cacheTime > 5))) {
122  std::set<CNetAddr> ips;
123  db.GetIPs(ips, requestedFlags, 1000, nets);
124  dbQueries++;
125  thisflag.cache.clear();
126  thisflag.nIPv4 = 0;
127  thisflag.nIPv6 = 0;
128  thisflag.cache.reserve(ips.size());
129  for (auto &ip : ips) {
130  struct in_addr addr;
131  struct in6_addr addr6;
132  if (ip.GetInAddr(&addr)) {
133  addr_t a;
134  a.v = 4;
135  memcpy(&a.data.v4, &addr, 4);
136  thisflag.cache.push_back(a);
137  thisflag.nIPv4++;
138  } else if (ip.GetIn6Addr(&addr6)) {
139  addr_t a;
140  a.v = 6;
141  memcpy(&a.data.v6, &addr6, 16);
142  thisflag.cache.push_back(a);
143  thisflag.nIPv6++;
144  }
145  }
146  thisflag.cacheHits = 0;
147  thisflag.cacheTime = now;
148  }
149  }
150 
151  CDnsThread(seeder::CDnsSeedOpts *opts, int idIn) : id(idIn) {
152  dns_opt.host = opts->host.c_str();
153  dns_opt.ns = opts->ns.c_str();
154  dns_opt.mbox = opts->mbox.c_str();
155  dns_opt.datattl = 3600;
156  dns_opt.nsttl = 40000;
157  dns_opt.cb = GetIPList;
158  dns_opt.addr = opts->ip_addr.c_str();
159  dns_opt.port = opts->nPort;
160  dns_opt.nRequests = 0;
161  dbQueries = 0;
162  perflag.clear();
164  }
165 
166  void run() { dnsserver(&dns_opt); }
167 };
168 
169 extern "C" uint32_t GetIPList(void *data, char *requestedHostname, addr_t *addr,
170  uint32_t max, uint32_t ipv4, uint32_t ipv6) {
171  CDnsThread *thread = (CDnsThread *)data;
172 
173  uint64_t requestedFlags = 0;
174  int hostlen = strlen(requestedHostname);
175  if (hostlen > 1 && requestedHostname[0] == 'x' &&
176  requestedHostname[1] != '0') {
177  char *pEnd;
178  uint64_t flags = (uint64_t)strtoull(requestedHostname + 1, &pEnd, 16);
179  if (*pEnd == '.' && pEnd <= requestedHostname + 17 &&
180  std::find(thread->filterWhitelist.begin(),
181  thread->filterWhitelist.end(),
182  flags) != thread->filterWhitelist.end()) {
183  requestedFlags = flags;
184  } else {
185  return 0;
186  }
187  } else if (strcasecmp(requestedHostname, thread->dns_opt.host)) {
188  return 0;
189  }
190  thread->cacheHit(requestedFlags);
191  auto &thisflag = thread->perflag[requestedFlags];
192  uint32_t size = thisflag.cache.size();
193  uint32_t maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0);
194  if (max > size) {
195  max = size;
196  }
197  if (max > maxmax) {
198  max = maxmax;
199  }
200  uint32_t i = 0;
201  while (i < max) {
202  uint32_t j = i + (rand() % (size - i));
203  do {
204  bool ok = (ipv4 && thisflag.cache[j].v == 4) ||
205  (ipv6 && thisflag.cache[j].v == 6);
206  if (ok) {
207  break;
208  }
209  j++;
210  if (j == size) {
211  j = i;
212  }
213  } while (1);
214  addr[i] = thisflag.cache[j];
215  thisflag.cache[j] = thisflag.cache[i];
216  thisflag.cache[i] = addr[i];
217  i++;
218  }
219  return max;
220 }
221 
222 std::vector<CDnsThread *> dnsThread;
223 
224 extern "C" void *ThreadDNS(void *arg) {
225  CDnsThread *thread = (CDnsThread *)arg;
226  thread->run();
227  return nullptr;
228 }
229 
230 int StatCompare(const CAddrReport &a, const CAddrReport &b) {
231  if (a.uptime[4] == b.uptime[4]) {
232  if (a.uptime[3] == b.uptime[3]) {
233  return a.clientVersion > b.clientVersion;
234  } else {
235  return a.uptime[3] > b.uptime[3];
236  }
237  } else {
238  return a.uptime[4] > b.uptime[4];
239  }
240 }
241 
242 extern "C" void *ThreadDumper(void *data) {
243  assert(data);
244  const auto dumpInterval(*(const std::chrono::seconds *)data);
245 
246  // First dump should occur no later than 10 seconds. Successive dumps will
247  // occur every dump interval.
248  UninterruptibleSleep(std::min(10s, dumpInterval));
249  do {
250  {
251  std::vector<CAddrReport> v = db.GetAll();
252  sort(v.begin(), v.end(), StatCompare);
253  FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+");
254  if (f) {
255  {
257  cf << db;
258  }
259  rename("dnsseed.dat.new", "dnsseed.dat");
260  }
261  std::ofstream d{"dnsseed.dump"};
262  tfm::format(
263  d, "# address good "
264  "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) "
265  "%%(30d) blocks svcs version\n");
266  double stat[5] = {0, 0, 0, 0, 0};
267  for (CAddrReport rep : v) {
268  tfm::format(
269  d,
270  "%-47s %4d %11" PRId64
271  " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64
272  " %5i \"%s\"\n",
273  rep.ip.ToString(), (int)rep.fGood, rep.lastSuccess,
274  100.0 * rep.uptime[0], 100.0 * rep.uptime[1],
275  100.0 * rep.uptime[2], 100.0 * rep.uptime[3],
276  100.0 * rep.uptime[4], rep.blocks, rep.services,
277  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 
295 extern "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  }
317  tfm::format(
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 
330 const static unsigned int MAX_HOSTS_PER_SEED = 128;
331 
332 extern "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  }
342  UninterruptibleSleep(30min);
343  } while (1);
344  return nullptr;
345 }
346 
347 int 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) {
418  db.ResetIgnores();
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, ".");
433  UninterruptibleSleep(20ms);
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 }
int flags
Definition: bitcoin-tx.cpp:533
const CChainParams & Params()
Return the currently selected parameters.
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition: system.cpp:1123
bool m_print_to_console
Definition: logging.h:102
Definition: db.h:264
void Add(const CAddress &addr, bool fForce=false)
Definition: db.h:400
void ResultMany(const std::vector< CServiceResult > &ips)
Definition: db.h:424
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.h:436
std::map< CService, int64_t > banned
Definition: db.h:301
std::vector< CAddrReport > GetAll()
Definition: db.h:324
void ResetIgnores()
Definition: db.h:317
void GetMany(std::vector< CServiceResult > &ips, int max, int &wait)
Definition: db.h:412
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
int clientVersion
Definition: db.h:66
A CService with information about it as peer.
Definition: protocol.h:442
dns_opt_t dns_opt
Definition: main.cpp:101
void run()
Definition: main.cpp:166
std::atomic< uint64_t > dbQueries
Definition: main.cpp:104
std::set< uint64_t > filterWhitelist
Definition: main.cpp:105
std::map< uint64_t, FlagSpecificData > perflag
Definition: main.cpp:103
const int id
Definition: main.cpp:102
CDnsThread(seeder::CDnsSeedOpts *opts, int idIn)
Definition: main.cpp:151
void cacheHit(uint64_t requestedFlags, bool force=false)
Definition: main.cpp:107
bool IsValid() const
Definition: netaddress.cpp:479
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:28
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:260
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:190
bool SetProxy(enum Network net, const proxyType &addrProxy)
Definition: netbase.cpp:710
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:43
static uint16_t GetDefaultPort()
Definition: bitcoin.h:18
void * ThreadDNS(void *arg)
Definition: main.cpp:224
int StatCompare(const CAddrReport &a, const CAddrReport &b)
Definition: main.cpp:230
void * ThreadSeeder(void *)
Definition: main.cpp:332
CAddrDb db
Definition: main.cpp:35
std::vector< CDnsThread * > dnsThread
Definition: main.cpp:222
void * ThreadStats(void *)
Definition: main.cpp:295
void * ThreadCrawler(void *data)
Definition: main.cpp:37
void * ThreadDumper(void *data)
Definition: main.cpp:242
uint32_t GetIPList(void *thread, char *requestedHostname, addr_t *addr, uint32_t max, uint32_t ipv4, uint32_t ipv6)
Definition: main.cpp:169
static const unsigned int MAX_HOSTS_PER_SEED
Definition: main.cpp:330
@ SER_DISK
Definition: serialize.h:153
std::vector< addr_t > cache
Definition: main.cpp:95
unsigned int cacheHits
Definition: main.cpp:97
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
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
ArgsManager gArgs
Definition: system.cpp:80
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
int64_t GetTime()
Definition: time.cpp:109
assert(!tx.IsCoinBase())