Ton

Форк
0
/
blockchain-explorer.cpp 
672 строки · 22.8 Кб
1
/* 
2
    This file is part of TON Blockchain source code.
3

4
    TON Blockchain is free software; you can redistribute it and/or
5
    modify it under the terms of the GNU General Public License
6
    as published by the Free Software Foundation; either version 2
7
    of the License, or (at your option) any later version.
8

9
    TON Blockchain is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU General Public License for more details.
13

14
    You should have received a copy of the GNU General Public License
15

16
    In addition, as a special exception, the copyright holders give permission 
17
    to link the code of portions of this program with the OpenSSL library. 
18
    You must obey the GNU General Public License in all respects for all 
19
    of the code used other than OpenSSL. If you modify file(s) with this 
20
    exception, you may extend this exception to your version of the file(s), 
21
    but you are not obligated to do so. If you do not wish to do so, delete this 
22
    exception statement from your version. If you delete this exception statement 
23
    from all source files in the program, then also delete it here.
24
    along with TON Blockchain.  If not, see <http://www.gnu.org/licenses/>.
25

26
    Copyright 2017-2020 Telegram Systems LLP
27
*/
28
#include "adnl/adnl-ext-client.h"
29
#include "adnl/utils.hpp"
30
#include "auto/tl/ton_api_json.h"
31
#include "td/utils/OptionParser.h"
32
#include "td/utils/Time.h"
33
#include "td/utils/filesystem.h"
34
#include "td/utils/format.h"
35
#include "td/utils/Random.h"
36
#include "td/utils/crypto.h"
37
#include "td/utils/port/signals.h"
38
#include "td/utils/port/user.h"
39
#include "td/utils/port/FileFd.h"
40
#include "ton/ton-tl.hpp"
41
#include "block/block-db.h"
42
#include "block/block.h"
43
#include "block/block-auto.h"
44
#include "vm/boc.h"
45
#include "vm/cellops.h"
46
#include "vm/cells/MerkleProof.h"
47
#include "block/mc-config.h"
48
#include "blockchain-explorer.hpp"
49
#include "blockchain-explorer-http.hpp"
50
#include "blockchain-explorer-query.hpp"
51

52
#include "vm/boc.h"
53
#include "vm/cellops.h"
54
#include "vm/cells/MerkleProof.h"
55
#include "vm/vm.h"
56

57
#include "auto/tl/lite_api.h"
58
#include "ton/lite-tl.hpp"
59
#include "tl-utils/lite-utils.hpp"
60

61
#include <microhttpd.h>
62

63
#if TD_DARWIN || TD_LINUX
64
#include <unistd.h>
65
#include <fcntl.h>
66
#endif
67
#include <iostream>
68
#include <sstream>
69

70
int verbosity;
71

72
td::actor::Scheduler* scheduler_ptr;
73

74
static std::string urldecode(td::Slice from, bool decode_plus_sign_as_space) {
75
  size_t to_i = 0;
76

77
  td::BufferSlice x{from.size()};
78
  auto to = x.as_slice();
79

80
  for (size_t from_i = 0, n = from.size(); from_i < n; from_i++) {
81
    if (from[from_i] == '%' && from_i + 2 < n) {
82
      int high = td::hex_to_int(from[from_i + 1]);
83
      int low = td::hex_to_int(from[from_i + 2]);
84
      if (high < 16 && low < 16) {
85
        to[to_i++] = static_cast<char>(high * 16 + low);
86
        from_i += 2;
87
        continue;
88
      }
89
    }
90
    to[to_i++] = decode_plus_sign_as_space && from[from_i] == '+' ? ' ' : from[from_i];
91
  }
92

93
  return to.truncate(to_i).str();
94
}
95

96
class HttpQueryRunner {
97
 public:
98
  HttpQueryRunner(std::function<void(td::Promise<MHD_Response*>)> func) {
99
    auto P = td::PromiseCreator::lambda([Self = this](td::Result<MHD_Response*> R) {
100
      if (R.is_ok()) {
101
        Self->finish(R.move_as_ok());
102
      } else {
103
        Self->finish(nullptr);
104
      }
105
    });
106
    scheduler_ptr->run_in_context_external([&]() { func(std::move(P)); });
107
  }
108
  void finish(MHD_Response* response) {
109
    std::unique_lock<std::mutex> lock(mutex_);
110
    response_ = response;
111
    cond.notify_all();
112
  }
113
  MHD_Response* wait() {
114
    std::unique_lock<std::mutex> lock(mutex_);
115
    cond.wait(lock, [&]() { return response_ != nullptr; });
116
    return response_;
117
  }
118

119
 private:
120
  std::function<void(td::Promise<MHD_Response*>)> func_;
121
  MHD_Response* response_ = nullptr;
122
  std::mutex mutex_;
123
  std::condition_variable cond;
124
};
125

126
class CoreActor : public CoreActorInterface {
127
 private:
128
  std::string global_config_ = "ton-global.config";
129

130
  std::vector<td::actor::ActorOwn<ton::adnl::AdnlExtClient>> clients_;
131

132
  td::uint32 http_port_ = 80;
133
  MHD_Daemon* daemon_ = nullptr;
134

135
  td::IPAddress remote_addr_;
136
  ton::PublicKey remote_public_key_;
137

138
  bool hide_ips_ = false;
139

140
  std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback(td::uint32 idx) {
141
    class Callback : public ton::adnl::AdnlExtClient::Callback {
142
     public:
143
      void on_ready() override {
144
        td::actor::send_closure(id_, &CoreActor::conn_ready, idx_);
145
      }
146
      void on_stop_ready() override {
147
        td::actor::send_closure(id_, &CoreActor::conn_closed, idx_);
148
      }
149
      Callback(td::actor::ActorId<CoreActor> id, td::uint32 idx) : id_(std::move(id)), idx_(idx) {
150
      }
151

152
     private:
153
      td::actor::ActorId<CoreActor> id_;
154
      td::uint32 idx_;
155
    };
156

157
    return std::make_unique<Callback>(actor_id(this), idx);
158
  }
159

160
  std::shared_ptr<RemoteNodeStatus> new_result_;
161
  td::int32 attempt_ = 0;
162
  td::int32 waiting_ = 0;
163

164
  std::vector<bool> ready_;
165

166
  void run_queries();
167
  void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
168
  void send_query(td::uint32 idx);
169

170
  void add_result() {
171
    if (new_result_) {
172
      auto ts = static_cast<td::int32>(new_result_->ts_.at_unix());
173
      results_.emplace(ts, std::move(new_result_));
174
    }
175
  }
176

177
  void alarm() override {
178
    auto t = static_cast<td::int32>(td::Clocks::system() / 60);
179
    if (t <= attempt_) {
180
      alarm_timestamp() = td::Timestamp::at_unix((attempt_ + 1) * 60);
181
      return;
182
    }
183
    if (waiting_ > 0 && new_result_) {
184
      add_result();
185
    }
186
    attempt_ = t;
187
    run_queries();
188
    alarm_timestamp() = td::Timestamp::at_unix((attempt_ + 1) * 60);
189
  }
190

191
 public:
192
  std::mutex queue_mutex_;
193
  std::mutex res_mutex_;
194
  std::map<td::int32, std::shared_ptr<RemoteNodeStatus>> results_;
195
  std::vector<td::IPAddress> addrs_;
196
  static CoreActor* instance_;
197
  td::actor::ActorId<CoreActor> self_id_;
198

199
  void conn_ready(td::uint32 idx) {
200
    ready_.at(idx) = true;
201
  }
202
  void conn_closed(td::uint32 idx) {
203
    ready_.at(idx) = false;
204
  }
205
  void set_global_config(std::string str) {
206
    global_config_ = str;
207
  }
208
  void set_http_port(td::uint32 port) {
209
    http_port_ = port;
210
  }
211
  void set_remote_addr(td::IPAddress addr) {
212
    remote_addr_ = addr;
213
  }
214
  void set_remote_public_key(td::BufferSlice file_name) {
215
    auto R = [&]() -> td::Result<ton::PublicKey> {
216
      TRY_RESULT_PREFIX(conf_data, td::read_file(file_name.as_slice().str()), "failed to read: ");
217
      return ton::PublicKey::import(conf_data.as_slice());
218
    }();
219

220
    if (R.is_error()) {
221
      LOG(FATAL) << "bad server public key: " << R.move_as_error();
222
    }
223
    remote_public_key_ = R.move_as_ok();
224
  }
225
  void set_hide_ips(bool value) {
226
    hide_ips_ = value;
227
  }
228

229
  void send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
230
  void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
231
    return send_lite_query(0, std::move(data), std::move(promise));
232
  }
233
  void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override {
234
  }
235
  void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override {
236
    RemoteNodeStatusList r;
237
    r.ips = hide_ips_ ? std::vector<td::IPAddress>{addrs_.size()} : addrs_;
238
    auto it = results_.rbegin();
239
    while (it != results_.rend() && r.results.size() < max) {
240
      r.results.push_back(it->second);
241
      it++;
242
    }
243
    promise.set_value(std::move(r));
244
  }
245

246
  void start_up() override {
247
    instance_ = this;
248
    auto t = td::Clocks::system();
249
    attempt_ = static_cast<td::int32>(t / 60);
250
    auto next_t = (attempt_ + 1) * 60;
251
    alarm_timestamp() = td::Timestamp::at_unix(next_t);
252
    self_id_ = actor_id(this);
253
  }
254
  void tear_down() override {
255
    if (daemon_) {
256
      MHD_stop_daemon(daemon_);
257
      daemon_ = nullptr;
258
    }
259
  }
260

261
  CoreActor() {
262
  }
263

264
  static MHD_RESULT get_arg_iterate(void* cls, enum MHD_ValueKind kind, const char* key, const char* value) {
265
    auto X = static_cast<std::map<std::string, std::string>*>(cls);
266
    if (key && value && std::strlen(key) > 0 && std::strlen(value) > 0) {
267
      X->emplace(key, urldecode(td::Slice{value}, false));
268
    }
269
    return MHD_YES;
270
  }
271

272
  struct HttpRequestExtra {
273
    HttpRequestExtra(MHD_Connection* connection, bool is_post) {
274
      if (is_post) {
275
        postprocessor = MHD_create_post_processor(connection, 1 << 14, iterate_post, static_cast<void*>(this));
276
      }
277
    }
278
    ~HttpRequestExtra() {
279
      MHD_destroy_post_processor(postprocessor);
280
    }
281
    static MHD_RESULT iterate_post(void* coninfo_cls, enum MHD_ValueKind kind, const char* key, const char* filename,
282
                            const char* content_type, const char* transfer_encoding, const char* data, uint64_t off,
283
                            size_t size) {
284
      auto ptr = static_cast<HttpRequestExtra*>(coninfo_cls);
285
      ptr->total_size += strlen(key) + size;
286
      if (ptr->total_size > MAX_POST_SIZE) {
287
        return MHD_NO;
288
      }
289
      std::string k = key;
290
      if (ptr->opts[k].size() < off + size) {
291
        ptr->opts[k].resize(off + size);
292
      }
293
      td::MutableSlice(ptr->opts[k]).remove_prefix(off).copy_from(td::Slice(data, size));
294
      return MHD_YES;
295
    }
296
    MHD_PostProcessor* postprocessor;
297
    std::map<std::string, std::string> opts;
298
    td::uint64 total_size = 0;
299
  };
300

301
  static void request_completed(void* cls, struct MHD_Connection* connection, void** ptr,
302
                                enum MHD_RequestTerminationCode toe) {
303
    auto e = static_cast<HttpRequestExtra*>(*ptr);
304
    if (e) {
305
      delete e;
306
    }
307
  }
308

309
  static MHD_RESULT process_http_request(void* cls, struct MHD_Connection* connection, const char* url, const char* method,
310
                                  const char* version, const char* upload_data, size_t* upload_data_size, void** ptr) {
311
    struct MHD_Response* response = nullptr;
312
    MHD_RESULT ret;
313

314
    bool is_post = false;
315
    if (std::strcmp(method, "GET") == 0) {
316
      is_post = false;
317
    } else if (std::strcmp(method, "POST") == 0) {
318
      is_post = true;
319
    } else {
320
      return MHD_NO; /* unexpected method */
321
    }
322
    std::map<std::string, std::string> opts;
323
    if (!is_post) {
324
      if (!*ptr) {
325
        *ptr = static_cast<void*>(new HttpRequestExtra{connection, false});
326
        return MHD_YES;
327
      }
328
      if (0 != *upload_data_size)
329
        return MHD_NO; /* upload data in a GET!? */
330
    } else {
331
      if (!*ptr) {
332
        *ptr = static_cast<void*>(new HttpRequestExtra{connection, true});
333
        return MHD_YES;
334
      }
335
      auto e = static_cast<HttpRequestExtra*>(*ptr);
336
      if (0 != *upload_data_size) {
337
        CHECK(e->postprocessor);
338
        MHD_post_process(e->postprocessor, upload_data, *upload_data_size);
339
        *upload_data_size = 0;
340
        return MHD_YES;
341
      }
342
      for (auto& o : e->opts) {
343
        opts[o.first] = std::move(o.second);
344
      }
345
    }
346

347
    std::string url_s = url;
348

349
    *ptr = nullptr; /* clear context pointer */
350

351
    auto pos = url_s.rfind('/');
352
    std::string prefix;
353
    std::string command;
354
    if (pos == std::string::npos) {
355
      prefix = "";
356
      command = url_s;
357
    } else {
358
      prefix = url_s.substr(0, pos + 1);
359
      command = url_s.substr(pos + 1);
360
    }
361

362
    MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, get_arg_iterate, static_cast<void*>(&opts));
363

364
    if (command == "status") {
365
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
366
        td::actor::create_actor<HttpQueryStatus>("blockinfo", opts, prefix, std::move(promise)).release();
367
      }};
368
      response = g.wait();
369
    } else if (command == "block") {
370
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
371
        td::actor::create_actor<HttpQueryBlockInfo>("blockinfo", opts, prefix, std::move(promise)).release();
372
      }};
373
      response = g.wait();
374
    } else if (command == "search") {
375
      if (opts.count("roothash") + opts.count("filehash") > 0) {
376
        HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
377
          td::actor::create_actor<HttpQueryBlockInfo>("blockinfo", opts, prefix, std::move(promise)).release();
378
        }};
379
        response = g.wait();
380
      } else {
381
        HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
382
          td::actor::create_actor<HttpQueryBlockSearch>("blocksearch", opts, prefix, std::move(promise)).release();
383
        }};
384
        response = g.wait();
385
      }
386
    } else if (command == "last") {
387
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
388
        td::actor::create_actor<HttpQueryViewLastBlock>("", opts, prefix, std::move(promise)).release();
389
      }};
390
      response = g.wait();
391
    } else if (command == "download") {
392
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
393
        td::actor::create_actor<HttpQueryBlockData>("downloadblock", opts, prefix, std::move(promise)).release();
394
      }};
395
      response = g.wait();
396
    } else if (command == "viewblock") {
397
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
398
        td::actor::create_actor<HttpQueryBlockView>("viewblock", opts, prefix, std::move(promise)).release();
399
      }};
400
      response = g.wait();
401
    } else if (command == "account") {
402
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
403
        td::actor::create_actor<HttpQueryViewAccount>("viewaccount", opts, prefix, std::move(promise)).release();
404
      }};
405
      response = g.wait();
406
    } else if (command == "transaction") {
407
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
408
        td::actor::create_actor<HttpQueryViewTransaction>("viewtransaction", opts, prefix, std::move(promise))
409
            .release();
410
      }};
411
      response = g.wait();
412
    } else if (command == "transaction2") {
413
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
414
        td::actor::create_actor<HttpQueryViewTransaction2>("viewtransaction2", opts, prefix, std::move(promise))
415
            .release();
416
      }};
417
      response = g.wait();
418
    } else if (command == "config") {
419
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
420
        td::actor::create_actor<HttpQueryConfig>("getconfig", opts, prefix, std::move(promise)).release();
421
      }};
422
      response = g.wait();
423
    } else if (command == "send") {
424
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
425
        td::actor::create_actor<HttpQuerySend>("send", opts, prefix, std::move(promise)).release();
426
      }};
427
      response = g.wait();
428
    } else if (command == "sendform") {
429
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
430
        td::actor::create_actor<HttpQuerySendForm>("sendform", opts, prefix, std::move(promise)).release();
431
      }};
432
      response = g.wait();
433
    } else if (command == "runmethod") {
434
      HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
435
        td::actor::create_actor<HttpQueryRunMethod>("runmethod", opts, prefix, std::move(promise)).release();
436
      }};
437
      response = g.wait();
438
    } else {
439
      ret = MHD_NO;
440
    }
441
    if (response) {
442
      ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
443
      MHD_destroy_response(response);
444
    } else {
445
      ret = MHD_NO;
446
    }
447

448
    return ret;
449
  }
450

451
  void run() {
452
    if (remote_public_key_.empty()) {
453
      auto G = td::read_file(global_config_).move_as_ok();
454
      auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
455
      ton::ton_api::liteclient_config_global gc;
456
      ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
457

458
      CHECK(gc.liteservers_.size() > 0);
459
      td::uint32 size = static_cast<td::uint32>(gc.liteservers_.size());
460
      ready_.resize(size, false);
461

462
      for (td::uint32 i = 0; i < size; i++) {
463
        auto& cli = gc.liteservers_[i];
464
        td::IPAddress addr;
465
        addr.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
466
        addrs_.push_back(addr);
467
        clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull::create(cli->id_).move_as_ok(),
468
                                                               addr, make_callback(i)));
469
      }
470
    } else {
471
      if (!remote_addr_.is_valid()) {
472
        LOG(FATAL) << "remote addr not set";
473
      }
474
      ready_.resize(1, false);
475
      addrs_.push_back(remote_addr_);
476
      clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_},
477
                                                             remote_addr_, make_callback(0)));
478
    }
479
    daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast<td::uint16>(http_port_), nullptr, nullptr,
480
                               &process_http_request, nullptr, MHD_OPTION_NOTIFY_COMPLETED, request_completed, nullptr,
481
                               MHD_OPTION_THREAD_POOL_SIZE, 16, MHD_OPTION_END);
482
    CHECK(daemon_ != nullptr);
483
  }
484
};
485

486
void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> R) {
487
  if (attempt != attempt_) {
488
    return;
489
  }
490
  if (R.is_error()) {
491
    waiting_--;
492
    if (waiting_ == 0) {
493
      add_result();
494
    }
495
    return;
496
  }
497
  auto data = R.move_as_ok();
498
  {
499
    auto F = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
500
    if (F.is_ok()) {
501
      auto f = F.move_as_ok();
502
      auto err = td::Status::Error(f->code_, f->message_);
503
      waiting_--;
504
      if (waiting_ == 0) {
505
        add_result();
506
      }
507
      return;
508
    }
509
  }
510
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_masterchainInfo>(std::move(data), true);
511
  if (F.is_error()) {
512
    waiting_--;
513
    if (waiting_ == 0) {
514
      add_result();
515
    }
516
    return;
517
  }
518
  auto f = F.move_as_ok();
519
  new_result_->values_[idx] = ton::create_block_id(f->last_);
520
  waiting_--;
521
  CHECK(waiting_ >= 0);
522
  if (waiting_ == 0) {
523
    add_result();
524
  }
525
}
526

527
void CoreActor::send_query(td::uint32 idx) {
528
  if (!ready_[idx]) {
529
    return;
530
  }
531
  waiting_++;
532
  auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>();
533
  auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(serialize_tl_object(query, true));
534

535
  auto P =
536
      td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result<td::BufferSlice> R) {
537
        td::actor::send_closure(SelfId, &CoreActor::got_result, idx, attempt, std::move(R));
538
      });
539
  td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
540
                          td::Timestamp::in(10.0), std::move(P));
541
}
542

543
void CoreActor::run_queries() {
544
  waiting_ = 0;
545
  new_result_ = std::make_shared<RemoteNodeStatus>(ready_.size(), td::Timestamp::at_unix(attempt_ * 60));
546
  for (td::uint32 i = 0; i < ready_.size(); i++) {
547
    send_query(i);
548
  }
549
  CHECK(waiting_ >= 0);
550
  if (waiting_ == 0) {
551
    add_result();
552
  }
553
}
554

555
void CoreActor::send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
556
  if (!ready_[idx]) {
557
    promise.set_error(td::Status::Error(ton::ErrorCode::notready, "ext conn not ready"));
558
    return;
559
  }
560
  auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
561
    if (R.is_error()) {
562
      promise.set_error(R.move_as_error());
563
      return;
564
    }
565
    auto B = R.move_as_ok();
566
    {
567
      auto F = ton::fetch_tl_object<ton::lite_api::liteServer_error>(B.clone(), true);
568
      if (F.is_ok()) {
569
        auto f = F.move_as_ok();
570
        promise.set_error(td::Status::Error(f->code_, f->message_));
571
        return;
572
      }
573
    }
574
    promise.set_value(std::move(B));
575
  });
576
  auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query));
577
  td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
578
                          td::Timestamp::in(10.0), std::move(P));
579
}
580

581
td::actor::ActorId<CoreActorInterface> CoreActorInterface::instance_actor_id() {
582
  auto instance = CoreActor::instance_;
583
  CHECK(instance);
584
  return instance->self_id_;
585
}
586

587
CoreActor* CoreActor::instance_ = nullptr;
588

589
int main(int argc, char* argv[]) {
590
  SET_VERBOSITY_LEVEL(verbosity_INFO);
591
  td::set_default_failure_signal_handler().ensure();
592

593
  td::actor::ActorOwn<CoreActor> x;
594

595
  td::OptionParser p;
596
  p.set_description("TON Blockchain explorer");
597
  p.add_checked_option('h', "help", "prints_help", [&]() {
598
    char b[10240];
599
    td::StringBuilder sb(td::MutableSlice{b, 10000});
600
    sb << p;
601
    std::cout << sb.as_cslice().c_str();
602
    std::exit(2);
603
    return td::Status::OK();
604
  });
605
  p.add_checked_option('I', "hide-ips", "hides ips from status", [&]() {
606
    td::actor::send_closure(x, &CoreActor::set_hide_ips, true);
607
    return td::Status::OK();
608
  });
609
  p.add_checked_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user.str()); });
610
  p.add_checked_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
611
    td::actor::send_closure(x, &CoreActor::set_global_config, fname.str());
612
    return td::Status::OK();
613
  });
614
  p.add_checked_option('a', "addr", "connect to ip:port", [&](td::Slice arg) {
615
    td::IPAddress addr;
616
    TRY_STATUS(addr.init_host_port(arg.str()));
617
    td::actor::send_closure(x, &CoreActor::set_remote_addr, addr);
618
    return td::Status::OK();
619
  });
620
  p.add_checked_option('p', "pub", "remote public key", [&](td::Slice arg) {
621
    td::actor::send_closure(x, &CoreActor::set_remote_public_key, td::BufferSlice{arg});
622
    return td::Status::OK();
623
  });
624
  p.add_checked_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
625
    verbosity = td::to_integer<int>(arg);
626
    SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + verbosity);
627
    return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9");
628
  });
629
  p.add_checked_option('d', "daemonize", "set SIGHUP", [&]() {
630
    td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
631
#if TD_DARWIN || TD_LINUX
632
      close(0);
633
      setsid();
634
#endif
635
    }).ensure();
636
    return td::Status::OK();
637
  });
638
  p.add_checked_option('H', "http-port", "listen on http port", [&](td::Slice arg) {
639
    td::actor::send_closure(x, &CoreActor::set_http_port, td::to_integer<td::uint32>(arg));
640
    return td::Status::OK();
641
  });
642
  p.add_checked_option('L', "local-scripts", "use local copy of ajax/bootstrap/... JS", [&]() {
643
    local_scripts = true;
644
    return td::Status::OK();
645
  });
646
#if TD_DARWIN || TD_LINUX
647
  p.add_checked_option('l', "logname", "log to file", [&](td::Slice fname) {
648
    auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
649
                                    td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
650
                       .move_as_ok();
651

652
    dup2(FileLog.get_native_fd().fd(), 1);
653
    dup2(FileLog.get_native_fd().fd(), 2);
654
    return td::Status::OK();
655
  });
656
#endif
657

658
  vm::init_vm().ensure();
659

660
  td::actor::Scheduler scheduler({2});
661
  scheduler_ptr = &scheduler;
662
  scheduler.run_in_context([&] { x = td::actor::create_actor<CoreActor>("testnode"); });
663

664
  scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
665
  scheduler.run_in_context([&] {
666
    td::actor::send_closure(x, &CoreActor::run);
667
    x.release();
668
  });
669
  scheduler.run();
670

671
  return 0;
672
}
673

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.