Bitcoin ABC  0.26.3
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 <functional>
26 #include <pthread.h>
27 
28 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
29 
30 extern "C" {
31 #include <seeder/dns.h>
32 }
33 
35 
36 extern "C" void *ThreadCrawler(void *data) {
37  int *nThreads = (int *)data;
38  do {
39  std::vector<CServiceResult> ips;
40  int wait = 5;
41  db.GetMany(ips, 16, wait);
42  int64_t now = GetTime();
43  if (ips.empty()) {
44  wait *= 1000;
45  wait += rand() % (500 * *nThreads);
46  UninterruptibleSleep(std::chrono::milliseconds(wait));
47  continue;
48  }
49 
50  std::vector<CAddress> addr;
51  for (size_t i = 0; i < ips.size(); i++) {
52  CServiceResult &res = ips[i];
53  res.nBanTime = 0;
54  res.nClientV = 0;
55  res.nHeight = 0;
56  res.strClientV = "";
57  res.services = 0;
58  bool getaddr = res.ourLastSuccess + 86400 < now;
59  try {
60  CSeederNode node(res.service, getaddr ? &addr : nullptr);
61  bool ret = node.Run();
62  if (!ret) {
63  res.nBanTime = node.GetBan();
64  } else {
65  res.nBanTime = 0;
66  }
67  res.nClientV = node.GetClientVersion();
68  res.strClientV = node.GetClientSubVersion();
69  res.nHeight = node.GetStartingHeight();
70  res.services = node.GetServices();
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 
86 extern "C" uint32_t GetIPList(void *thread, char *requestedHostname,
87  addr_t *addr, uint32_t max, uint32_t ipv4,
88  uint32_t ipv6);
89 
90 class CDnsThread {
91 public:
93  int nIPv4, nIPv6;
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;
156  dns_opt.cb = GetIPList;
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 
168 extern "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 
221 std::vector<CDnsThread *> dnsThread;
222 
223 extern "C" void *ThreadDNS(void *arg) {
224  CDnsThread *thread = (CDnsThread *)arg;
225  thread->run();
226  return nullptr;
227 }
228 
229 int 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 
241 extern "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  std::vector<CAddrReport> v = db.GetAll();
250  sort(v.begin(), v.end(), StatCompare);
251  FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+");
252  if (f) {
253  {
255  cf << db;
256  }
257  rename("dnsseed.dat.new", "dnsseed.dat");
258  }
259  fsbridge::ofstream d{"dnsseed.dump"};
260  tfm::format(d, "# address good "
261  "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) "
262  "%%(30d) blocks svcs version\n");
263  double stat[5] = {0, 0, 0, 0, 0};
264  for (CAddrReport rep : v) {
265  tfm::format(
266  d,
267  "%-47s %4d %11" PRId64
268  " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64
269  " %5i \"%s\"\n",
270  rep.ip.ToString(), (int)rep.fGood, rep.lastSuccess,
271  100.0 * rep.uptime[0], 100.0 * rep.uptime[1],
272  100.0 * rep.uptime[2], 100.0 * rep.uptime[3],
273  100.0 * rep.uptime[4], rep.blocks, rep.services,
274  rep.clientVersion, rep.clientSubVersion);
275  stat[0] += rep.uptime[0];
276  stat[1] += rep.uptime[1];
277  stat[2] += rep.uptime[2];
278  stat[3] += rep.uptime[3];
279  stat[4] += rep.uptime[4];
280  }
281  fsbridge::ofstream ff{"dnsstats.log", std::ios_base::app};
282  tfm::format(ff, "%llu %g %g %g %g %g\n", GetTime(), stat[0], stat[1],
283  stat[2], stat[3], stat[4]);
284 
285  UninterruptibleSleep(dumpInterval);
286  } while (1);
287  return nullptr;
288 }
289 
290 extern "C" void *ThreadStats(void *) {
291  bool first = true;
292  do {
293  char c[256];
294  time_t tim = time(nullptr);
295  struct tm *tmp = localtime(&tim);
296  strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp);
297  CAddrDbStats stats;
298  db.GetStats(stats);
299  if (first) {
300  first = false;
301  tfm::format(std::cout, "\n\n\n\x1b[3A");
302  } else {
303  tfm::format(std::cout, "\x1b[2K\x1b[u");
304  }
305  tfm::format(std::cout, "\x1b[s");
306  uint64_t requests = 0;
307  uint64_t queries = 0;
308  for (unsigned int i = 0; i < dnsThread.size(); i++) {
309  requests += dnsThread[i]->dns_opt.nRequests;
310  queries += dnsThread[i]->dbQueries;
311  }
312  tfm::format(
313  std::cout,
314  "%s %i/%i available (%i tried in %is, %i new, %i active), %i "
315  "banned; %llu DNS requests, %llu db queries\n",
316  c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge,
317  stats.nNew, stats.nAvail - stats.nTracked - stats.nNew,
318  stats.nBanned, (unsigned long long)requests,
319  (unsigned long long)queries);
321  } while (1);
322  return nullptr;
323 }
324 
325 const static unsigned int MAX_HOSTS_PER_SEED = 128;
326 
327 extern "C" void *ThreadSeeder(void *) {
328  do {
329  for (const std::string &seed : GetRandomizedDNSSeeds(Params())) {
330  std::vector<CNetAddr> ips;
331  LookupHost(seed.c_str(), ips, MAX_HOSTS_PER_SEED, true);
332  for (auto &ip : ips) {
334  true);
335  }
336  }
337  UninterruptibleSleep(30min);
338  } while (1);
339  return nullptr;
340 }
341 
342 int main(int argc, char **argv) {
343  // The logger dump everything on the console by default.
345 
346  signal(SIGPIPE, SIG_IGN);
347  setbuf(stdout, nullptr);
349  opts.SetupSeederArgs();
350  int parseResults =
351  opts.ParseCommandLine(argc, const_cast<const char **>(argv));
352  if (parseResults != seeder::CONTINUE_EXECUTION) {
353  return parseResults;
354  }
355 
356  tfm::format(std::cout, "Supporting whitelisted filters: ");
357  for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin();
358  it != opts.filter_whitelist.end(); it++) {
359  if (it != opts.filter_whitelist.begin()) {
360  tfm::format(std::cout, ",");
361  }
362  tfm::format(std::cout, "0x%lx", (unsigned long)*it);
363  }
364  tfm::format(std::cout, "\n");
365  if (!opts.tor.empty()) {
366  CService service(LookupNumeric(opts.tor.c_str(), 9050));
367  if (service.IsValid()) {
368  tfm::format(std::cout, "Using Tor proxy at %s\n",
369  service.ToStringIPPort());
370  SetProxy(NET_ONION, proxyType(service));
371  }
372  }
373  if (!opts.ipv4_proxy.empty()) {
374  CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050));
375  if (service.IsValid()) {
376  tfm::format(std::cout, "Using IPv4 proxy at %s\n",
377  service.ToStringIPPort());
378  SetProxy(NET_IPV4, proxyType(service));
379  }
380  }
381  if (!opts.ipv6_proxy.empty()) {
382  CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050));
383  if (service.IsValid()) {
384  tfm::format(std::cout, "Using IPv6 proxy at %s\n",
385  service.ToStringIPPort());
386  SetProxy(NET_IPV6, proxyType(service));
387  }
388  }
389  bool fDNS = true;
390  tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName());
391  if (opts.ns.empty()) {
392  tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n");
393  fDNS = false;
394  }
395  if (fDNS && opts.host.empty()) {
396  tfm::format(std::cerr, "No hostname set. Please use -h.\n");
397  return EXIT_FAILURE;
398  }
399  if (fDNS && opts.mbox.empty()) {
400  tfm::format(std::cerr, "No e-mail address set. Please use -m.\n");
401  return EXIT_FAILURE;
402  }
403  FILE *f = fsbridge::fopen("dnsseed.dat", "r");
404  if (f) {
405  tfm::format(std::cout, "Loading dnsseed.dat...");
407  cf >> db;
408  if (opts.fWipeBan) {
409  db.banned.clear();
410  tfm::format(std::cout, "Ban list wiped...");
411  }
412  if (opts.fWipeIgnore) {
413  db.ResetIgnores();
414  tfm::format(std::cout, "Ignore list wiped...");
415  }
416  tfm::format(std::cout, "done\n");
417  }
418  pthread_t threadDns, threadSeed, threadDump, threadStats;
419  if (fDNS) {
420  tfm::format(std::cout,
421  "Starting %i DNS threads for %s on %s (port %i)...",
422  opts.nDnsThreads, opts.host, opts.ns, opts.nPort);
423  dnsThread.clear();
424  for (int i = 0; i < opts.nDnsThreads; i++) {
425  dnsThread.push_back(new CDnsThread(&opts, i));
426  pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]);
427  tfm::format(std::cout, ".");
428  UninterruptibleSleep(20ms);
429  }
430  tfm::format(std::cout, "done\n");
431  }
432  tfm::format(std::cout, "Starting seeder...");
433  pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr);
434  tfm::format(std::cout, "done\n");
435  tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads);
436  pthread_attr_t attr_crawler;
437  pthread_attr_init(&attr_crawler);
438  pthread_attr_setstacksize(&attr_crawler, 0x20000);
439  for (int i = 0; i < opts.nThreads; i++) {
440  pthread_t thread;
441  pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads);
442  }
443  pthread_attr_destroy(&attr_crawler);
444  tfm::format(std::cout, "done\n");
445  pthread_create(&threadStats, nullptr, ThreadStats, nullptr);
446  pthread_create(&threadDump, nullptr, ThreadDumper, &opts.dumpInterval);
447  void *res;
448  pthread_join(threadDump, &res);
449  return EXIT_SUCCESS;
450 }
int flags
Definition: bitcoin-tx.cpp:534
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:1047
bool m_print_to_console
Definition: logging.h:100
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:445
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:581
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: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:44
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:19
fs::ofstream ofstream
Definition: fs.h:247
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:27
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:1111
@ NET_MAX
Dummy value to indicate the number of NET_* constants.
Definition: netaddress.h:70
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:57
@ NET_IPV6
IPv6.
Definition: netaddress.h:54
@ NET_IPV4
IPv4.
Definition: netaddress.h:51
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:338
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:37
static uint16_t GetDefaultPort()
Definition: bitcoin.h:16
void * ThreadDNS(void *arg)
Definition: main.cpp:223
int StatCompare(const CAddrReport &a, const CAddrReport &b)
Definition: main.cpp:229
void * ThreadSeeder(void *)
Definition: main.cpp:327
CAddrDb db
Definition: main.cpp:34
std::vector< CDnsThread * > dnsThread
Definition: main.cpp:221
void * ThreadStats(void *)
Definition: main.cpp:290
void * ThreadCrawler(void *data)
Definition: main.cpp:36
void * ThreadDumper(void *data)
Definition: main.cpp:241
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:325
@ SER_DISK
Definition: serialize.h:167
std::vector< addr_t > cache
Definition: main.cpp:94
unsigned int cacheHits
Definition: main.cpp:96
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:77
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
T GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:71
assert(!tx.IsCoinBase())