Ton

Форк
0
/
blockchain-explorer-query.cpp 
1464 строки · 54.1 Кб
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
    along with TON Blockchain.  If not, see <http://www.gnu.org/licenses/>.
16

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

27
    Copyright 2017-2020 Telegram Systems LLP
28
*/
29
#include "blockchain-explorer-query.hpp"
30
#include "blockchain-explorer-http.hpp"
31
#include "block/mc-config.h"
32
#include "crypto/block/check-proof.h"
33

34
#include "auto/tl/lite_api.h"
35

36
#include "tl-utils/tl-utils.hpp"
37
#include "tl-utils/lite-utils.hpp"
38

39
#include "ton/ton-tl.hpp"
40
#include "ton/lite-tl.hpp"
41

42
#include "common/errorcode.h"
43
#include "block/block-auto.h"
44
#include "crypto/vm/utils.h"
45
#include "td/utils/crypto.h"
46

47
#include "vm/boc.h"
48
#include "vm/cellops.h"
49
#include "vm/cells/MerkleProof.h"
50
#include "vm/vm.h"
51
#include "vm/cp0.h"
52

53
td::Result<ton::BlockIdExt> parse_block_id(std::map<std::string, std::string> &opts, bool allow_empty) {
54
  if (allow_empty) {
55
    if (opts.count("workchain") == 0 && opts.count("shard") == 0 && opts.count("seqno") == 0) {
56
      return ton::BlockIdExt{};
57
    }
58
  }
59
  try {
60
    ton::BlockIdExt block_id;
61
    auto it = opts.find("workchain");
62
    if (it == opts.end()) {
63
      return td::Status::Error(ton::ErrorCode::protoviolation, "workchain not set");
64
    }
65
    block_id.id.workchain = std::stoi(it->second);
66
    it = opts.find("shard");
67
    if (it == opts.end()) {
68
      return td::Status::Error(ton::ErrorCode::protoviolation, "shard not set");
69
    }
70
    block_id.id.shard = std::stoull(it->second, nullptr, 16);
71
    it = opts.find("seqno");
72
    if (it == opts.end()) {
73
      return td::Status::Error(ton::ErrorCode::protoviolation, "seqno not set");
74
    }
75
    auto s = std::stoull(it->second);
76
    auto seqno = static_cast<ton::BlockSeqno>(s);
77
    if (s != seqno) {
78
      return td::Status::Error(ton::ErrorCode::protoviolation, "seqno too big");
79
    }
80
    block_id.id.seqno = seqno;
81
    it = opts.find("roothash");
82
    if (it == opts.end()) {
83
      return td::Status::Error(ton::ErrorCode::protoviolation, "roothash not set");
84
    }
85
    if (it->second.length() != 64) {
86
      return td::Status::Error(ton::ErrorCode::protoviolation, "roothash bad length");
87
    }
88
    auto R = td::hex_decode(td::Slice(it->second));
89
    if (R.is_error()) {
90
      return td::Status::Error(ton::ErrorCode::protoviolation, "roothash bad hex");
91
    }
92
    block_id.root_hash.as_slice().copy_from(td::as_slice(R.move_as_ok()));
93
    it = opts.find("filehash");
94
    if (it == opts.end()) {
95
      return td::Status::Error(ton::ErrorCode::protoviolation, "filehash not set");
96
    }
97
    if (it->second.length() != 64) {
98
      return td::Status::Error(ton::ErrorCode::protoviolation, "filehash bad length");
99
    }
100
    R = td::hex_decode(td::Slice(it->second));
101
    if (R.is_error()) {
102
      return td::Status::Error(ton::ErrorCode::protoviolation, "filehash bad hex");
103
    }
104
    block_id.file_hash.as_slice().copy_from(td::as_slice(R.move_as_ok()));
105
    return block_id;
106
  } catch (...) {
107
    return td::Status::Error(ton::ErrorCode::protoviolation, "cannot parse int");
108
  }
109
}
110

111
td::Result<ton::AccountIdPrefixFull> parse_account_prefix(std::map<std::string, std::string> &opts, bool allow_empty) {
112
  if (allow_empty) {
113
    if (opts.count("workchain") == 0 && opts.count("shard") == 0 && opts.count("account") == 0) {
114
      return ton::AccountIdPrefixFull{ton::masterchainId, 0};
115
    }
116
  }
117
  try {
118
    ton::AccountIdPrefixFull account_id;
119
    auto it = opts.find("workchain");
120
    if (it == opts.end()) {
121
      return td::Status::Error(ton::ErrorCode::protoviolation, "workchain not set");
122
    }
123
    account_id.workchain = std::stoi(it->second);
124
    it = opts.find("shard");
125
    if (it == opts.end()) {
126
      it = opts.find("account");
127
      if (it == opts.end()) {
128
        return td::Status::Error(ton::ErrorCode::protoviolation, "shard/account not set");
129
      }
130
    }
131
    account_id.account_id_prefix = std::stoull(it->second, nullptr, 16);
132
    return account_id;
133
  } catch (...) {
134
    return td::Status::Error(ton::ErrorCode::protoviolation, "cannot parse int");
135
  }
136
}
137

138
td::Result<block::StdAddress> parse_account_addr(std::map<std::string, std::string> &opts) {
139
  auto it = opts.find("account");
140
  if (it == opts.end()) {
141
    return td::Status::Error(ton::ErrorCode::error, "no account id");
142
  }
143
  std::string acc_string = it->second;
144
  block::StdAddress a;
145
  if (a.parse_addr(td::Slice(acc_string))) {
146
    return a;
147
  }
148
  ton::WorkchainId workchain_id;
149
  it = opts.find("accountworkchain");
150
  if (it == opts.end()) {
151
    it = opts.find("workchain");
152
    if (it == opts.end()) {
153
      return td::Status::Error(ton::ErrorCode::error, "no account workchain id");
154
    }
155
  }
156
  try {
157
    workchain_id = std::stoi(it->second);
158
  } catch (...) {
159
    return td::Status::Error(ton::ErrorCode::error, "bad account workchain id");
160
  }
161
  if (acc_string.size() == 64) {
162
    TRY_RESULT(R, td::hex_decode(acc_string));
163
    a.addr.as_slice().copy_from(td::Slice(R));
164
    a.workchain = workchain_id;
165
    return a;
166
  }
167
  return td::Status::Error(ton::ErrorCode::error, "bad account id");
168
}
169

170
void HttpQueryCommon::abort_query(td::Status error) {
171
  if (promise_) {
172
    HttpAnswer A{"error", prefix_};
173
    A.abort(std::move(error));
174
    auto page = A.finish();
175
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
176
    MHD_add_response_header(R, "Content-Type", "text/html");
177
    promise_.set_value(std::move(R));
178
  }
179
  stop();
180
}
181

182
HttpQueryBlockData::HttpQueryBlockData(ton::BlockIdExt block_id, std::string prefix,
183
                                       td::Promise<MHD_Response *> promise)
184
    : HttpQueryCommon(std::move(prefix), std::move(promise)), block_id_(block_id) {
185
}
186

187
HttpQueryBlockData::HttpQueryBlockData(std::map<std::string, std::string> opts, std::string prefix,
188
                                       td::Promise<MHD_Response *> promise)
189
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
190
  auto R = parse_block_id(opts);
191
  if (R.is_ok()) {
192
    block_id_ = R.move_as_ok();
193
  } else {
194
    error_ = R.move_as_error();
195
  }
196
}
197

198
void HttpQueryBlockData::abort_query(td::Status error) {
199
  if (promise_) {
200
    promise_.set_result(nullptr);
201
  }
202
  stop();
203
}
204

205
void HttpQueryBlockData::finish_query() {
206
  if (promise_) {
207
    auto response = MHD_create_response_from_buffer(data_.length(), data_.as_slice().begin(), MHD_RESPMEM_MUST_COPY);
208
    promise_.set_result(response);
209
  }
210
  stop();
211
}
212

213
void HttpQueryBlockData::start_up() {
214
  auto query = ton::serialize_tl_object(
215
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
216

217
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
218
    if (R.is_error()) {
219
      td::actor::send_closure(SelfId, &HttpQueryBlockData::abort_query, R.move_as_error_prefix("litequery failed: "));
220
    } else {
221
      td::actor::send_closure(SelfId, &HttpQueryBlockData::got_block_data, R.move_as_ok());
222
    }
223
  });
224

225
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
226
                          std::move(query), std::move(P));
227
}
228

229
void HttpQueryBlockData::got_block_data(td::BufferSlice data) {
230
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockData>(std::move(data), true);
231
  if (F.is_error()) {
232
    abort_query(F.move_as_error());
233
    return;
234
  }
235
  data_ = std::move(F.move_as_ok()->data_);
236
  finish_query();
237
}
238

239
HttpQueryBlockView::HttpQueryBlockView(ton::BlockIdExt block_id, std::string prefix,
240
                                       td::Promise<MHD_Response *> promise)
241
    : HttpQueryCommon(std::move(prefix), std::move(promise)), block_id_(block_id) {
242
}
243

244
HttpQueryBlockView::HttpQueryBlockView(std::map<std::string, std::string> opts, std::string prefix,
245
                                       td::Promise<MHD_Response *> promise)
246
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
247
  auto R = parse_block_id(opts);
248
  if (R.is_ok()) {
249
    block_id_ = R.move_as_ok();
250
  } else {
251
    error_ = R.move_as_error();
252
  }
253
}
254

255
void HttpQueryBlockView::finish_query() {
256
  if (promise_) {
257
    auto page = [&]() -> std::string {
258
      HttpAnswer A{"viewblock", prefix_};
259
      A.set_block_id(block_id_);
260
      auto res = vm::std_boc_deserialize(data_.clone());
261
      if (res.is_error()) {
262
        return A.abort(PSTRING() << "cannot deserialize block: " << res.move_as_error());
263
      }
264
      create_header(A);
265
      auto root = res.move_as_ok();
266
      A << HttpAnswer::RawData<block::gen::Block>{root};
267
      return A.finish();
268
    }();
269
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
270
    MHD_add_response_header(R, "Content-Type", "text/html");
271
    promise_.set_value(std::move(R));
272
  }
273
  stop();
274
}
275

276
void HttpQueryBlockView::start_up_query() {
277
  auto query = ton::serialize_tl_object(
278
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
279

280
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
281
    if (R.is_error()) {
282
      td::actor::send_closure(SelfId, &HttpQueryBlockView::abort_query, R.move_as_error_prefix("litequery failed: "));
283
    } else {
284
      td::actor::send_closure(SelfId, &HttpQueryBlockView::got_block_data, R.move_as_ok());
285
    }
286
  });
287

288
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
289
                          std::move(query), std::move(P));
290
}
291

292
void HttpQueryBlockView::got_block_data(td::BufferSlice data) {
293
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockData>(std::move(data), true);
294
  if (F.is_error()) {
295
    abort_query(F.move_as_error());
296
  }
297
  data_ = std::move(F.move_as_ok()->data_);
298
  finish_query();
299
}
300

301
HttpQueryBlockInfo::HttpQueryBlockInfo(ton::BlockIdExt block_id, std::string prefix,
302
                                       td::Promise<MHD_Response *> promise)
303
    : HttpQueryCommon(std::move(prefix), std::move(promise)), block_id_(block_id) {
304
}
305

306
HttpQueryBlockInfo::HttpQueryBlockInfo(std::map<std::string, std::string> opts, std::string prefix,
307
                                       td::Promise<MHD_Response *> promise)
308
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
309
  auto R = parse_block_id(opts);
310
  if (R.is_ok()) {
311
    block_id_ = R.move_as_ok();
312
  } else {
313
    error_ = R.move_as_error();
314
  }
315
}
316

317
void HttpQueryBlockInfo::start_up_query() {
318
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
319
    if (R.is_error()) {
320
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
321
    } else {
322
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_block_header, R.move_as_ok());
323
    }
324
  });
325
  auto query = ton::serialize_tl_object(
326
      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0),
327
      true);
328
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
329
                          std::move(query), std::move(P));
330
  pending_queries_ = 1;
331

332
  if (block_id_.is_masterchain()) {
333
    auto P_2 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
334
      if (R.is_error()) {
335
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::failed_to_get_shard_info,
336
                                R.move_as_error_prefix("litequery failed: "));
337
      } else {
338
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_shard_info, R.move_as_ok());
339
      }
340
    });
341
    auto query_2 = ton::serialize_tl_object(
342
        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)),
343
        true);
344
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
345
                            std::move(query_2), std::move(P_2));
346
    pending_queries_++;
347
  }
348
  auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
349
                                              ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false),
350
                                          true);
351
  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
352
    if (R.is_error()) {
353
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
354
    } else {
355
      td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_transactions, R.move_as_ok());
356
    }
357
  });
358
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
359
                          std::move(query_3), std::move(P_3));
360
  pending_queries_++;
361
}
362

363
void HttpQueryBlockInfo::got_block_header(td::BufferSlice data) {
364
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockHeader>(std::move(data), true);
365
  if (F.is_error()) {
366
    abort_query(F.move_as_error());
367
    return;
368
  }
369
  data_ = std::move(F.move_as_ok()->header_proof_);
370

371
  if (!--pending_queries_) {
372
    finish_query();
373
  }
374
}
375

376
void HttpQueryBlockInfo::got_shard_info(td::BufferSlice data) {
377
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_allShardsInfo>(std::move(data), true);
378
  if (F.is_error()) {
379
    abort_query(F.move_as_error());
380
    return;
381
  }
382
  shard_data_ = std::move(F.move_as_ok()->data_);
383

384
  if (!--pending_queries_) {
385
    finish_query();
386
  }
387
}
388

389
void HttpQueryBlockInfo::failed_to_get_shard_info(td::Status error) {
390
  shard_data_error_ = std::move(error);
391
  if (!--pending_queries_) {
392
    finish_query();
393
  }
394
}
395

396
void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) {
397
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockTransactions>(std::move(data), true);
398
  if (F.is_error()) {
399
    abort_query(F.move_as_error());
400
    return;
401
  }
402
  auto f = F.move_as_ok();
403
  trans_req_count_ = f->req_count_;
404

405
  for (auto &T : f->ids_) {
406
    transactions_.emplace_back(block::StdAddress{block_id_.id.workchain, T->account_},
407
                               static_cast<ton::LogicalTime>(T->lt_), T->hash_);
408
  }
409

410
  if (f->incomplete_ && transactions_.size() > 0) {
411
    const auto &T = *transactions_.rbegin();
412
    auto query_3 = ton::serialize_tl_object(
413
        ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
414
            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
415
            ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
416
        true);
417
    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
418
      if (R.is_error()) {
419
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: "));
420
      } else {
421
        td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_transactions, R.move_as_ok());
422
      }
423
    });
424
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
425
                            std::move(query_3), std::move(P_3));
426
  } else {
427
    if (!--pending_queries_) {
428
      finish_query();
429
    }
430
  }
431
}
432

433
void HttpQueryBlockInfo::finish_query() {
434
  if (promise_) {
435
    auto page = [&]() -> std::string {
436
      HttpAnswer A{"blockinfo", prefix_};
437
      A.set_block_id(block_id_);
438
      create_header(A);
439
      auto res = vm::std_boc_deserialize(data_.clone());
440
      if (res.is_error()) {
441
        return A.abort(PSTRING() << "cannot deserialize block header data: " << res.move_as_error());
442
      }
443
      A << HttpAnswer::BlockHeaderCell{block_id_, res.move_as_ok()};
444

445
      if (shard_data_.size() > 0) {
446
        auto R = vm::std_boc_deserialize(shard_data_.clone());
447
        if (R.is_error()) {
448
          return A.abort(PSTRING() << "cannot deserialize shard configuration: " << R.move_as_error());
449
        } else {
450
          A << HttpAnswer::BlockShardsCell{block_id_, R.move_as_ok()};
451
        }
452
      }
453
      if (shard_data_error_.is_error()) {
454
        A << HttpAnswer::Error{shard_data_error_.clone()};
455
      }
456

457
      HttpAnswer::TransactionList I;
458
      I.block_id = block_id_;
459
      I.req_count_ = trans_req_count_;
460
      for (auto &T : transactions_) {
461
        I.vec.emplace_back(T.addr, T.lt, T.hash);
462
      }
463
      A << I;
464

465
      return A.finish();
466
    }();
467
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
468
    MHD_add_response_header(R, "Content-Type", "text/html");
469
    promise_.set_value(std::move(R));
470
  }
471
  stop();
472
}
473

474
HttpQueryBlockSearch::HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account,
475
                                           ton::BlockSeqno seqno, std::string prefix,
476
                                           td::Promise<MHD_Response *> promise)
477
    : HttpQueryCommon(std::move(prefix), std::move(promise))
478
    , account_prefix_{workchain, account}
479
    , mode_(1)
480
    , seqno_(seqno) {
481
}
482
HttpQueryBlockSearch::HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account,
483
                                           ton::LogicalTime lt, std::string prefix, td::Promise<MHD_Response *> promise)
484
    : HttpQueryCommon(std::move(prefix), std::move(promise)), account_prefix_{workchain, account}, mode_(2), lt_(lt) {
485
}
486
HttpQueryBlockSearch::HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account, bool dummy,
487
                                           ton::UnixTime utime, std::string prefix, td::Promise<MHD_Response *> promise)
488
    : HttpQueryCommon(std::move(prefix), std::move(promise))
489
    , account_prefix_{workchain, account}
490
    , mode_(4)
491
    , utime_(utime) {
492
}
493

494
HttpQueryBlockSearch::HttpQueryBlockSearch(std::map<std::string, std::string> opts, std::string prefix,
495
                                           td::Promise<MHD_Response *> promise)
496
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
497
  auto R2 = parse_account_prefix(opts, false);
498
  if (R2.is_ok()) {
499
    account_prefix_ = R2.move_as_ok();
500
  } else {
501
    error_ = R2.move_as_error();
502
    return;
503
  }
504
  if (opts.count("seqno") + opts.count("lt") + opts.count("utime") != 1) {
505
    error_ = td::Status::Error(ton::ErrorCode::protoviolation, "exactly one of seqno/lt/utime must be set");
506
    return;
507
  }
508
  if (opts.count("seqno") == 1) {
509
    try {
510
      seqno_ = static_cast<td::uint32>(std::stoull(opts["seqno"]));
511
      mode_ = 1;
512
    } catch (...) {
513
      error_ = td::Status::Error("cannot parse seqno");
514
      return;
515
    }
516
  }
517
  if (opts.count("lt") == 1) {
518
    try {
519
      lt_ = std::stoull(opts["lt"]);
520
      mode_ = 2;
521
    } catch (...) {
522
      error_ = td::Status::Error("cannot parse lt");
523
      return;
524
    }
525
  }
526
  if (opts.count("utime") == 1) {
527
    try {
528
      seqno_ = static_cast<td::uint32>(std::stoull(opts["utime"]));
529
      mode_ = 1;
530
    } catch (...) {
531
      error_ = td::Status::Error("cannot parse utime");
532
      return;
533
    }
534
  }
535
}
536

537
void HttpQueryBlockSearch::start_up_query() {
538
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
539
    if (R.is_error()) {
540
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: "));
541
    } else {
542
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_block_header, R.move_as_ok());
543
    }
544
  });
545
  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
546
                                            mode_,
547
                                            ton::create_tl_lite_block_id_simple(ton::BlockId{
548
                                                account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}),
549
                                            lt_, utime_),
550
                                        true);
551
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
552
                          std::move(query), std::move(P));
553
}
554

555
void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) {
556
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockHeader>(std::move(data), true);
557
  if (F.is_error()) {
558
    abort_query(F.move_as_error());
559
    return;
560
  }
561
  auto f = F.move_as_ok();
562
  data_ = std::move(f->header_proof_);
563
  block_id_ = ton::create_block_id(f->id_);
564

565
  if (block_id_.is_masterchain()) {
566
    auto P_2 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
567
      if (R.is_error()) {
568
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::failed_to_get_shard_info,
569
                                R.move_as_error_prefix("litequery failed: "));
570
      } else {
571
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_shard_info, R.move_as_ok());
572
      }
573
    });
574
    auto query_2 = ton::serialize_tl_object(
575
        ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_)),
576
        true);
577
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
578
                            std::move(query_2), std::move(P_2));
579
    pending_queries_++;
580
  }
581

582
  auto query_3 = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
583
                                              ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false),
584
                                          true);
585
  auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
586
    if (R.is_error()) {
587
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: "));
588
    } else {
589
      td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_transactions, R.move_as_ok());
590
    }
591
  });
592
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
593
                          std::move(query_3), std::move(P_3));
594
  pending_queries_++;
595
}
596

597
void HttpQueryBlockSearch::got_shard_info(td::BufferSlice data) {
598
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_allShardsInfo>(std::move(data), true);
599
  if (F.is_error()) {
600
    abort_query(F.move_as_error());
601
    return;
602
  }
603
  shard_data_ = std::move(F.move_as_ok()->data_);
604

605
  if (!--pending_queries_) {
606
    finish_query();
607
  }
608
}
609

610
void HttpQueryBlockSearch::failed_to_get_shard_info(td::Status error) {
611
  shard_data_error_ = std::move(error);
612
  if (!--pending_queries_) {
613
    finish_query();
614
  }
615
}
616

617
void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) {
618
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_blockTransactions>(std::move(data), true);
619
  if (F.is_error()) {
620
    abort_query(F.move_as_error());
621
    return;
622
  }
623
  auto f = F.move_as_ok();
624
  trans_req_count_ = f->req_count_;
625

626
  for (auto &T : f->ids_) {
627
    transactions_.emplace_back(block::StdAddress{block_id_.id.workchain, T->account_},
628
                               static_cast<ton::LogicalTime>(T->lt_), T->hash_);
629
  }
630

631
  if (f->incomplete_ && transactions_.size() > 0) {
632
    const auto &T = *transactions_.rbegin();
633
    auto query_3 = ton::serialize_tl_object(
634
        ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
635
            ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
636
            ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
637
        true);
638
    auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
639
      if (R.is_error()) {
640
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query,
641
                                R.move_as_error_prefix("litequery failed: "));
642
      } else {
643
        td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_transactions, R.move_as_ok());
644
      }
645
    });
646
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
647
                            std::move(query_3), std::move(P_3));
648
  } else {
649
    if (!--pending_queries_) {
650
      finish_query();
651
    }
652
  }
653
}
654

655
void HttpQueryBlockSearch::finish_query() {
656
  if (promise_) {
657
    auto page = [&]() -> std::string {
658
      HttpAnswer A{"blockinfo", prefix_};
659
      A.set_block_id(block_id_);
660
      create_header(A);
661
      auto res = vm::std_boc_deserialize(data_.clone());
662
      if (res.is_error()) {
663
        return A.abort(PSTRING() << "cannot deserialize block header data: " << res.move_as_error());
664
      }
665
      A << HttpAnswer::BlockHeaderCell{block_id_, res.move_as_ok()};
666

667
      if (shard_data_.size() > 0) {
668
        auto R = vm::std_boc_deserialize(shard_data_.clone());
669
        if (R.is_error()) {
670
          return A.abort(PSTRING() << "cannot deserialize shard configuration: " << R.move_as_error());
671
        } else {
672
          A << HttpAnswer::BlockShardsCell{block_id_, R.move_as_ok()};
673
        }
674
      }
675
      if (shard_data_error_.is_error()) {
676
        A << HttpAnswer::Error{shard_data_error_.clone()};
677
      }
678

679
      HttpAnswer::TransactionList I;
680
      I.block_id = block_id_;
681
      I.req_count_ = trans_req_count_;
682
      for (auto &T : transactions_) {
683
        I.vec.emplace_back(T.addr, T.lt, T.hash);
684
      }
685
      A << I;
686

687
      return A.finish();
688
    }();
689
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
690
    MHD_add_response_header(R, "Content-Type", "text/html");
691
    promise_.set_value(std::move(R));
692
  }
693
  stop();
694
}
695
HttpQueryViewAccount::HttpQueryViewAccount(ton::BlockIdExt block_id, block::StdAddress addr, std::string prefix,
696
                                           td::Promise<MHD_Response *> promise)
697
    : HttpQueryCommon(std::move(prefix), std::move(promise)), block_id_(block_id), addr_(addr) {
698
}
699

700
HttpQueryViewAccount::HttpQueryViewAccount(std::map<std::string, std::string> opts, std::string prefix,
701
                                           td::Promise<MHD_Response *> promise)
702
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
703
  auto R = parse_block_id(opts, true);
704
  if (R.is_ok()) {
705
    block_id_ = R.move_as_ok();
706
    if (!block_id_.is_valid()) {
707
      block_id_.id.workchain = ton::masterchainId;
708
      block_id_.id.shard = ton::shardIdAll;
709
      block_id_.id.seqno = static_cast<td::uint32>(0xffffffff);
710
      block_id_.root_hash.set_zero();
711
      block_id_.file_hash.set_zero();
712
    }
713
  } else {
714
    error_ = R.move_as_error();
715
    return;
716
  }
717
  auto R2 = parse_account_addr(opts);
718
  if (R2.is_ok()) {
719
    addr_ = R2.move_as_ok();
720
  } else {
721
    error_ = R2.move_as_error();
722
    return;
723
  }
724
}
725

726
void HttpQueryViewAccount::start_up_query() {
727
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
728
    if (R.is_error()) {
729
      td::actor::send_closure(SelfId, &HttpQueryViewAccount::abort_query, R.move_as_error_prefix("litequery failed: "));
730
    } else {
731
      td::actor::send_closure(SelfId, &HttpQueryViewAccount::got_account, R.move_as_ok());
732
    }
733
  });
734
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
735
  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
736
                                            ton::create_tl_lite_block_id(block_id_), std::move(a)),
737
                                        true);
738
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
739
                          std::move(query), std::move(P));
740
}
741

742
void HttpQueryViewAccount::got_account(td::BufferSlice data) {
743
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(std::move(data), true);
744
  if (F.is_error()) {
745
    abort_query(F.move_as_error());
746
    return;
747
  }
748

749
  auto f = F.move_as_ok();
750
  data_ = std::move(f->state_);
751
  proof_ = std::move(f->proof_);
752
  res_block_id_ = ton::create_block_id(f->shardblk_);
753

754
  finish_query();
755
}
756

757
void HttpQueryViewAccount::finish_query() {
758
  if (promise_) {
759
    auto page = [&]() -> std::string {
760
      HttpAnswer A{"account", prefix_};
761
      A.set_account_id(addr_);
762
      A.set_block_id(res_block_id_);
763
      auto R = vm::std_boc_deserialize(data_.clone());
764
      if (R.is_error()) {
765
        return A.abort(PSTRING() << "FATAL: cannot deserialize account state" << R.move_as_error());
766
      }
767
      auto Q = vm::std_boc_deserialize_multi(proof_.clone());
768
      if (Q.is_error()) {
769
        return A.abort(PSTRING() << "FATAL: cannot deserialize account proof" << Q.move_as_error());
770
      }
771
      auto Q_roots = Q.move_as_ok();
772
      auto root = R.move_as_ok();
773
      A << HttpAnswer::AccountCell{addr_, res_block_id_, root, Q_roots};
774
      return A.finish();
775
    }();
776
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
777
    MHD_add_response_header(R, "Content-Type", "text/html");
778
    promise_.set_value(std::move(R));
779
  }
780
  stop();
781
}
782

783
HttpQueryViewTransaction::HttpQueryViewTransaction(block::StdAddress addr, ton::LogicalTime lt, ton::Bits256 hash,
784
                                                   std::string prefix, td::Promise<MHD_Response *> promise)
785
    : HttpQueryCommon(std::move(prefix), std::move(promise)), addr_(addr), lt_(lt), hash_(hash) {
786
}
787

788
HttpQueryViewTransaction::HttpQueryViewTransaction(std::map<std::string, std::string> opts, std::string prefix,
789
                                                   td::Promise<MHD_Response *> promise)
790
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
791
  auto R2 = parse_account_addr(opts);
792
  if (R2.is_ok()) {
793
    addr_ = R2.move_as_ok();
794
  } else {
795
    error_ = R2.move_as_error();
796
    return;
797
  }
798
  try {
799
    lt_ = std::stoull(opts["lt"]);
800
  } catch (...) {
801
    error_ = td::Status::Error("cannot trans parse lt");
802
    return;
803
  }
804
  try {
805
    auto h = opts["hash"];
806
    if (h.length() != 64) {
807
      error_ = td::Status::Error("cannot trans parse hash");
808
      return;
809
    }
810
    auto R = td::hex_decode(td::Slice(h));
811
    if (R.is_error()) {
812
      error_ = td::Status::Error("cannot trans parse hash");
813
      return;
814
    }
815
    hash_.as_slice().copy_from(R.move_as_ok());
816
  } catch (...) {
817
    error_ = td::Status::Error("cannot trans parse hash");
818
    return;
819
  }
820
}
821

822
void HttpQueryViewTransaction::start_up_query() {
823
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
824
    if (R.is_error()) {
825
      td::actor::send_closure(SelfId, &HttpQueryViewTransaction::abort_query,
826
                              R.move_as_error_prefix("litequery failed: "));
827
    } else {
828
      td::actor::send_closure(SelfId, &HttpQueryViewTransaction::got_transaction, R.move_as_ok());
829
    }
830
  });
831
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
832
  auto query = ton::serialize_tl_object(
833
      ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_), true);
834
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
835
                          std::move(query), std::move(P));
836
}
837

838
void HttpQueryViewTransaction::got_transaction(td::BufferSlice data) {
839
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_transactionList>(std::move(data), true);
840
  if (F.is_error()) {
841
    abort_query(F.move_as_error());
842
    return;
843
  }
844

845
  auto f = F.move_as_ok();
846
  data_ = std::move(f->transactions_);
847
  if (f->ids_.size() == 0) {
848
    abort_query(td::Status::Error("no transactions found"));
849
    return;
850
  }
851
  res_block_id_ = ton::create_block_id(f->ids_[0]);
852

853
  finish_query();
854
}
855

856
void HttpQueryViewTransaction::finish_query() {
857
  if (promise_) {
858
    auto page = [&]() -> std::string {
859
      HttpAnswer A{"transaction", prefix_};
860
      A.set_block_id(res_block_id_);
861
      A.set_account_id(addr_);
862
      auto R = vm::std_boc_deserialize_multi(std::move(data_));
863
      if (R.is_error()) {
864
        return A.abort(PSTRING() << "FATAL: cannot deserialize transactions BoC");
865
      }
866
      auto list = R.move_as_ok();
867
      auto n = list.size();
868
      if (n != 1) {
869
        return A.abort(PSTRING() << "obtained " << n << " transaction, but only 1 have been requested");
870
      } else {
871
        A << HttpAnswer::TransactionCell{addr_, res_block_id_, list[0]};
872
      }
873
      return A.finish();
874
    }();
875
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
876
    MHD_add_response_header(R, "Content-Type", "text/html");
877
    promise_.set_value(std::move(R));
878
  }
879
  stop();
880
}
881

882
HttpQueryViewTransaction2::HttpQueryViewTransaction2(ton::BlockIdExt block_id, block::StdAddress addr,
883
                                                     ton::LogicalTime lt, std::string prefix,
884
                                                     td::Promise<MHD_Response *> promise)
885
    : HttpQueryCommon(std::move(prefix), std::move(promise)), block_id_(block_id), addr_(addr), lt_(lt) {
886
}
887

888
HttpQueryViewTransaction2::HttpQueryViewTransaction2(std::map<std::string, std::string> opts, std::string prefix,
889
                                                     td::Promise<MHD_Response *> promise)
890
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
891
  auto R = parse_block_id(opts);
892
  if (R.is_ok()) {
893
    block_id_ = R.move_as_ok();
894
  } else {
895
    error_ = R.move_as_error();
896
    return;
897
  }
898
  auto R2 = parse_account_addr(opts);
899
  if (R2.is_ok()) {
900
    addr_ = R2.move_as_ok();
901
  } else {
902
    error_ = R2.move_as_error();
903
    return;
904
  }
905
  try {
906
    lt_ = std::stoull(opts["lt"]);
907
  } catch (...) {
908
    error_ = td::Status::Error("cannot trans parse lt");
909
    return;
910
  }
911
}
912

913
void HttpQueryViewTransaction2::start_up_query() {
914
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
915
    if (R.is_error()) {
916
      td::actor::send_closure(SelfId, &HttpQueryViewTransaction2::abort_query,
917
                              R.move_as_error_prefix("litequery failed: "));
918
    } else {
919
      td::actor::send_closure(SelfId, &HttpQueryViewTransaction2::got_transaction, R.move_as_ok());
920
    }
921
  });
922
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
923
  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
924
                                            ton::create_tl_lite_block_id(block_id_), std::move(a), lt_),
925
                                        true);
926
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
927
                          std::move(query), std::move(P));
928
}
929

930
void HttpQueryViewTransaction2::got_transaction(td::BufferSlice data) {
931
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_transactionInfo>(std::move(data), true);
932
  if (F.is_error()) {
933
    abort_query(F.move_as_error());
934
    return;
935
  }
936

937
  auto f = F.move_as_ok();
938
  data_ = std::move(f->transaction_);
939

940
  finish_query();
941
}
942

943
void HttpQueryViewTransaction2::finish_query() {
944
  if (promise_) {
945
    auto page = [&]() -> std::string {
946
      HttpAnswer A{"transaction", prefix_};
947
      A.set_block_id(block_id_);
948
      A.set_account_id(addr_);
949
      auto R = vm::std_boc_deserialize(std::move(data_));
950
      if (R.is_error()) {
951
        return A.abort(PSTRING() << "FATAL: cannot deserialize transactions BoC");
952
      }
953
      auto list = R.move_as_ok();
954
      A << HttpAnswer::TransactionCell{addr_, block_id_, list};
955
      return A.finish();
956
    }();
957
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
958
    MHD_add_response_header(R, "Content-Type", "text/html");
959
    promise_.set_value(std::move(R));
960
  }
961
  stop();
962
}
963

964
HttpQueryViewLastBlock::HttpQueryViewLastBlock(std::string prefix, td::Promise<MHD_Response *> promise)
965
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
966
}
967

968
HttpQueryViewLastBlock::HttpQueryViewLastBlock(std::map<std::string, std::string> opts, std::string prefix,
969
                                               td::Promise<MHD_Response *> promise)
970
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
971
}
972

973
void HttpQueryViewLastBlock::start_up() {
974
  if (error_.is_error()) {
975
    abort_query(std::move(error_));
976
    return;
977
  }
978
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
979
    if (R.is_error()) {
980
      td::actor::send_closure(SelfId, &HttpQueryViewLastBlock::abort_query, R.move_as_error());
981
    } else {
982
      td::actor::send_closure(SelfId, &HttpQueryViewLastBlock::got_result, R.move_as_ok());
983
    }
984
  });
985

986
  auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
987
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
988
                          std::move(query), std::move(P));
989
}
990

991
void HttpQueryViewLastBlock::got_result(td::BufferSlice data) {
992
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_masterchainInfo>(std::move(data), true);
993
  if (F.is_error()) {
994
    abort_query(F.move_as_error());
995
    return;
996
  }
997
  auto f = F.move_as_ok();
998
  res_block_id_ = ton::create_block_id(f->last_);
999

1000
  finish_query();
1001
}
1002

1003
void HttpQueryViewLastBlock::finish_query() {
1004
  if (promise_) {
1005
    td::actor::create_actor<HttpQueryBlockInfo>("blockinfo", res_block_id_, prefix_, std::move(promise_)).release();
1006
  }
1007
  stop();
1008
}
1009

1010
HttpQueryConfig::HttpQueryConfig(std::string prefix, ton::BlockIdExt block_id, std::vector<td::int32> params,
1011
                                 td::Promise<MHD_Response *> promise)
1012
    : HttpQueryCommon(prefix, std::move(promise)), block_id_(block_id), params_(std::move(params)) {
1013
}
1014

1015
HttpQueryConfig::HttpQueryConfig(std::map<std::string, std::string> opts, std::string prefix,
1016
                                 td::Promise<MHD_Response *> promise)
1017
    : HttpQueryCommon(prefix, std::move(promise)) {
1018
  auto R = parse_block_id(opts, true);
1019
  if (R.is_error()) {
1020
    error_ = R.move_as_error();
1021
    return;
1022
  }
1023
  block_id_ = R.move_as_ok();
1024

1025
  auto it = opts.find("param");
1026
  if (it != opts.end()) {
1027
    auto R2 = td::to_integer_safe<int>(it->second);
1028
    if (R2.is_error()) {
1029
      error_ = R2.move_as_error();
1030
      return;
1031
    }
1032
    params_.push_back(R2.move_as_ok());
1033
  }
1034
}
1035

1036
void HttpQueryConfig::start_up() {
1037
  if (error_.is_error()) {
1038
    abort_query(std::move(error_));
1039
    return;
1040
  }
1041
  if (block_id_.is_valid()) {
1042
    send_main_query();
1043
  } else {
1044
    auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
1045
      if (R.is_error()) {
1046
        td::actor::send_closure(SelfId, &HttpQueryConfig::abort_query, R.move_as_error());
1047
      } else {
1048
        td::actor::send_closure(SelfId, &HttpQueryConfig::got_block, R.move_as_ok());
1049
      }
1050
    });
1051

1052
    auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
1053
    td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
1054
                            std::move(query), std::move(P));
1055
  }
1056
}
1057

1058
void HttpQueryConfig::got_block(td::BufferSlice data) {
1059
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_masterchainInfo>(std::move(data), true);
1060
  if (F.is_error()) {
1061
    abort_query(F.move_as_error());
1062
    return;
1063
  }
1064
  auto f = F.move_as_ok();
1065
  block_id_ = ton::create_block_id(f->last_);
1066

1067
  send_main_query();
1068
}
1069

1070
void HttpQueryConfig::send_main_query() {
1071
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
1072
    if (R.is_error()) {
1073
      td::actor::send_closure(SelfId, &HttpQueryConfig::abort_query, R.move_as_error());
1074
    } else {
1075
      td::actor::send_closure(SelfId, &HttpQueryConfig::got_result, R.move_as_ok());
1076
    }
1077
  });
1078
  auto query =
1079
      params_.size() > 0
1080
          ? ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>(
1081
                                         0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_)),
1082
                                     true)
1083
          : ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>(
1084
                                         0, ton::create_tl_lite_block_id(block_id_)),
1085
                                     true);
1086
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
1087
                          std::move(query), std::move(P));
1088
}
1089

1090
void HttpQueryConfig::got_result(td::BufferSlice data) {
1091
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_configInfo>(std::move(data), true);
1092
  if (F.is_error()) {
1093
    abort_query(F.move_as_error());
1094
    return;
1095
  }
1096
  auto f = F.move_as_ok();
1097

1098
  state_proof_ = std::move(f->state_proof_);
1099
  config_proof_ = std::move(f->config_proof_);
1100

1101
  finish_query();
1102
}
1103

1104
void HttpQueryConfig::finish_query() {
1105
  if (promise_) {
1106
    auto page = [&]() -> std::string {
1107
      HttpAnswer A{"config", prefix_};
1108
      A.set_block_id(block_id_);
1109
      auto R = block::check_extract_state_proof(block_id_, state_proof_.as_slice(), config_proof_.as_slice());
1110
      if (R.is_error()) {
1111
        A.abort(PSTRING() << "masterchain state proof for " << block_id_.to_str()
1112
                          << " is invalid : " << R.move_as_error());
1113
        return A.finish();
1114
      }
1115
      try {
1116
        auto res = block::Config::extract_from_state(R.move_as_ok(), 0);
1117
        if (res.is_error()) {
1118
          A.abort(PSTRING() << "cannot unpack configuration: " << res.move_as_error());
1119
          return A.finish();
1120
        }
1121
        auto config = res.move_as_ok();
1122
        if (params_.size() > 0) {
1123
          A << "<p>params: ";
1124
          for (int i : params_) {
1125
            auto value = config->get_config_param(i);
1126
            if (value.not_null()) {
1127
              A << "<a href=\"#configparam" << i << "\">" << i << "</a> ";
1128
            }
1129
          }
1130
          A << "</p>";
1131
          for (int i : params_) {
1132
            auto value = config->get_config_param(i);
1133
            if (value.not_null()) {
1134
              A << HttpAnswer::ConfigParam{i, value};
1135
            } else {
1136
              A << HttpAnswer::Error{td::Status::Error(404, PSTRING() << "empty param " << i)};
1137
            }
1138
          }
1139
        } else {
1140
          A << "<p>params: ";
1141
          config->foreach_config_param([&](int i, td::Ref<vm::Cell> value) {
1142
            if (value.not_null()) {
1143
              A << "<a href=\"#configparam" << i << "\">" << i << "</a> ";
1144
            }
1145
            return true;
1146
          });
1147
          A << "</p>";
1148
          config->foreach_config_param([&](int i, td::Ref<vm::Cell> value) {
1149
            if (value.not_null()) {
1150
              A << HttpAnswer::ConfigParam{i, value};
1151
            }
1152
            return true;
1153
          });
1154
        }
1155
      } catch (vm::VmError &err) {
1156
        A.abort(PSTRING() << "error while traversing configuration: " << err.get_msg());
1157
      } catch (vm::VmVirtError &err) {
1158
        A.abort(PSTRING() << "virtualization error while traversing configuration: " << err.get_msg());
1159
      }
1160
      return A.finish();
1161
    }();
1162
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
1163
    MHD_add_response_header(R, "Content-Type", "text/html");
1164
    promise_.set_value(std::move(R));
1165
  }
1166
  stop();
1167
}
1168

1169
HttpQuerySendForm::HttpQuerySendForm(std::string prefix, td::Promise<MHD_Response *> promise)
1170
    : HttpQueryCommon(prefix, std::move(promise)) {
1171
}
1172

1173
HttpQuerySendForm::HttpQuerySendForm(std::map<std::string, std::string> opts, std::string prefix,
1174
                                     td::Promise<MHD_Response *> promise)
1175
    : HttpQueryCommon(prefix, std::move(promise)) {
1176
}
1177

1178
void HttpQuerySendForm::start_up() {
1179
  finish_query();
1180
}
1181

1182
void HttpQuerySendForm::finish_query() {
1183
  if (promise_) {
1184
    auto page = [&]() -> std::string {
1185
      HttpAnswer A{"send", prefix_};
1186
      A << "<div class=\"row\"><form action=\"" << prefix_
1187
        << "send\" method=\"post\" enctype=\"multipart/form-data\"><div class=\"form-group-row\">"
1188
        << "<label for=\"filedata\">bag of cells</label>"
1189
        << "<input type=\"file\" class=\"form-control-file\" id=\"filedata\" name=\"filedata\">"
1190
        << "<button type=\"submit\" class=\"btn btn-primary\">send</button>"
1191
        << "</div></form></div>";
1192
      return A.finish();
1193
    }();
1194
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
1195
    MHD_add_response_header(R, "Content-Type", "text/html");
1196
    promise_.set_value(std::move(R));
1197
  }
1198
  stop();
1199
}
1200

1201
HttpQuerySend::HttpQuerySend(std::string prefix, td::BufferSlice data, td::Promise<MHD_Response *> promise)
1202
    : HttpQueryCommon(prefix, std::move(promise)), data_(std::move(data)) {
1203
}
1204

1205
HttpQuerySend::HttpQuerySend(std::map<std::string, std::string> opts, std::string prefix,
1206
                             td::Promise<MHD_Response *> promise)
1207
    : HttpQueryCommon(prefix, std::move(promise)) {
1208
  auto it = opts.find("filedata");
1209
  if (it != opts.end()) {
1210
    data_ = td::BufferSlice{it->second};
1211
  } else {
1212
    error_ = td::Status::Error("no file data");
1213
    return;
1214
  }
1215
}
1216

1217
void HttpQuerySend::start_up() {
1218
  if (error_.is_error()) {
1219
    abort_query(std::move(error_));
1220
    return;
1221
  }
1222
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
1223
    if (R.is_error()) {
1224
      td::actor::send_closure(SelfId, &HttpQuerySend::abort_query, R.move_as_error());
1225
    } else {
1226
      td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok());
1227
    }
1228
  });
1229
  auto query =
1230
      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(std::move(data_)), true);
1231
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
1232
                          std::move(query), std::move(P));
1233
}
1234

1235
void HttpQuerySend::got_result(td::BufferSlice data) {
1236
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_sendMsgStatus>(std::move(data), true);
1237
  if (F.is_error()) {
1238
    abort_query(F.move_as_error());
1239
  } else {
1240
    status_ = F.move_as_ok()->status_;
1241
  }
1242
  finish_query();
1243
}
1244

1245
void HttpQuerySend::finish_query() {
1246
  if (promise_) {
1247
    auto page = [&]() -> std::string {
1248
      HttpAnswer A{"send", prefix_};
1249
      if (status_ >= 0) {
1250
        A << HttpAnswer::Notification{"success"};
1251
      } else {
1252
        A << HttpAnswer::Error{td::Status::Error(status_, "failed")};
1253
      }
1254
      return A.finish();
1255
    }();
1256
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
1257
    MHD_add_response_header(R, "Content-Type", "text/html");
1258
    promise_.set_value(std::move(R));
1259
  }
1260
  stop();
1261
}
1262

1263
HttpQueryRunMethod::HttpQueryRunMethod(ton::BlockIdExt block_id, block::StdAddress addr, std::string method_name,
1264
                                       std::vector<vm::StackEntry> params, std::string prefix,
1265
                                       td::Promise<MHD_Response *> promise)
1266
    : HttpQueryCommon(std::move(prefix), std::move(promise))
1267
    , block_id_(block_id)
1268
    , addr_(addr)
1269
    , method_name_(std::move(method_name))
1270
    , params_(std::move(params)) {
1271
}
1272

1273
HttpQueryRunMethod::HttpQueryRunMethod(std::map<std::string, std::string> opts, std::string prefix,
1274
                                       td::Promise<MHD_Response *> promise)
1275
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
1276
  auto R = parse_block_id(opts, true);
1277
  if (R.is_ok()) {
1278
    block_id_ = R.move_as_ok();
1279
    if (!block_id_.is_valid()) {
1280
      block_id_.id.workchain = ton::masterchainId;
1281
      block_id_.id.shard = ton::shardIdAll;
1282
      block_id_.id.seqno = static_cast<td::uint32>(0xffffffff);
1283
      block_id_.root_hash.set_zero();
1284
      block_id_.file_hash.set_zero();
1285
    }
1286
  } else {
1287
    error_ = R.move_as_error();
1288
    return;
1289
  }
1290
  auto R2 = parse_account_addr(opts);
1291
  if (R2.is_ok()) {
1292
    addr_ = R2.move_as_ok();
1293
  } else {
1294
    error_ = R2.move_as_error();
1295
    return;
1296
  }
1297
  auto it = opts.find("method");
1298
  if (it == opts.end()) {
1299
    error_ = td::Status::Error("no method");
1300
    return;
1301
  } else {
1302
    method_name_ = it->second;
1303
  }
1304
  it = opts.find("params");
1305
  if (it != opts.end()) {
1306
    auto R3 = vm::parse_stack_entries(it->second);
1307
    if (R3.is_error()) {
1308
      error_ = R3.move_as_error();
1309
      return;
1310
    }
1311
    params_ = R3.move_as_ok();
1312
  }
1313
}
1314

1315
void HttpQueryRunMethod::start_up_query() {
1316
  auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
1317
    if (R.is_error()) {
1318
      td::actor::send_closure(SelfId, &HttpQueryRunMethod::abort_query, R.move_as_error_prefix("litequery failed: "));
1319
    } else {
1320
      td::actor::send_closure(SelfId, &HttpQueryRunMethod::got_result, R.move_as_ok());
1321
    }
1322
  });
1323

1324
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
1325
  td::int64 method_id = (td::crc16(td::Slice{method_name_}) & 0xffff) | 0x10000;
1326

1327
  // serialize params
1328
  vm::CellBuilder cb;
1329
  td::Ref<vm::Cell> cell;
1330
  if (!(vm::Stack{params_}.serialize(cb) && cb.finalize_to(cell))) {
1331
    return abort_query(td::Status::Error("cannot serialize stack with get-method parameters"));
1332
  }
1333
  auto params_serialized = vm::std_boc_serialize(std::move(cell));
1334
  if (params_serialized.is_error()) {
1335
    return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : "));
1336
  }
1337

1338
  auto query = ton::serialize_tl_object(
1339
      ton::create_tl_object<ton::lite_api::liteServer_runSmcMethod>(
1340
          0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()),
1341
      true);
1342
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query,
1343
                          std::move(query), std::move(P));
1344
}
1345

1346
void HttpQueryRunMethod::got_result(td::BufferSlice data) {
1347
  auto F = ton::fetch_tl_object<ton::lite_api::liteServer_runMethodResult>(std::move(data), true);
1348
  if (F.is_error()) {
1349
    return abort_query(F.move_as_error());
1350
  }
1351
  auto f = F.move_as_ok();
1352
  auto page = [&]() -> std::string {
1353
    HttpAnswer A{"account", prefix_};
1354
    A.set_account_id(addr_);
1355
    A.set_block_id(ton::create_block_id(f->id_));
1356
    if (f->exit_code_ != 0) {
1357
      A.abort(PSTRING() << "VM terminated with error code " << f->exit_code_);
1358
      return A.finish();
1359
    }
1360

1361
    std::ostringstream os;
1362
    os << "result: ";
1363
    if (f->result_.empty()) {
1364
      os << "<none>";
1365
    } else {
1366
      auto r_cell = vm::std_boc_deserialize(f->result_);
1367
      if (r_cell.is_error()) {
1368
        A.abort(PSTRING() << "cannot deserialize VM result boc: " << r_cell.move_as_error());
1369
        return A.finish();
1370
      }
1371
      auto cs = vm::load_cell_slice(r_cell.move_as_ok());
1372
      td::Ref<vm::Stack> stack;
1373
      if (!(vm::Stack::deserialize_to(cs, stack, 0) && cs.empty_ext())) {
1374
        A.abort("VM result boc cannot be deserialized");
1375
        return A.finish();
1376
      }
1377
      stack->dump(os, 3);
1378
    }
1379
    A << HttpAnswer::CodeBlock{os.str()};
1380
    return A.finish();
1381
  }();
1382
  auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
1383
  MHD_add_response_header(R, "Content-Type", "text/html");
1384
  promise_.set_value(std::move(R));
1385
  stop();
1386
}
1387
HttpQueryStatus::HttpQueryStatus(std::string prefix, td::Promise<MHD_Response *> promise)
1388
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
1389
}
1390

1391
HttpQueryStatus::HttpQueryStatus(std::map<std::string, std::string> opts, std::string prefix,
1392
                                 td::Promise<MHD_Response *> promise)
1393
    : HttpQueryCommon(std::move(prefix), std::move(promise)) {
1394
}
1395

1396
void HttpQueryStatus::start_up() {
1397
  if (error_.is_error()) {
1398
    abort_query(std::move(error_));
1399
    return;
1400
  }
1401

1402
  auto P =
1403
      td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<CoreActorInterface::RemoteNodeStatusList> R) {
1404
        if (R.is_error()) {
1405
          td::actor::send_closure(SelfId, &HttpQueryStatus::abort_query, R.move_as_error());
1406
        } else {
1407
          td::actor::send_closure(SelfId, &HttpQueryStatus::got_results, R.move_as_ok());
1408
        }
1409
      });
1410
  td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::get_results, 60, std::move(P));
1411
}
1412

1413
void HttpQueryStatus::got_results(CoreActorInterface::RemoteNodeStatusList results) {
1414
  results_ = std::move(results);
1415

1416
  finish_query();
1417
}
1418

1419
void HttpQueryStatus::finish_query() {
1420
  if (promise_) {
1421
    auto page = [&]() -> std::string {
1422
      std::map<td::uint32, std::set<td::uint32>> m;
1423

1424
      HttpAnswer A{"status", prefix_};
1425
      A << "<div class=\"table-responsive my-3\">\n"
1426
        << "<table class=\"table-sm\">\n"
1427
        << "<tr><td>ip</td>";
1428
      for (auto &x : results_.results) {
1429
        A << "<td>" << static_cast<td::int32>(x->ts_.at_unix()) << "</td>";
1430
      }
1431
      A << "</tr>\n";
1432
      for (td::uint32 i = 0; i < results_.ips.size(); i++) {
1433
        A << "<tr>";
1434
        if (results_.ips[i].is_valid()) {
1435
          A << "<td>" << results_.ips[i] << "</td>";
1436
        } else {
1437
          A << "<td>hidden</td>";
1438
        }
1439
        td::uint32 j = 0;
1440
        for (auto &X : results_.results) {
1441
          if (!X->values_[i].is_valid()) {
1442
            A << "<td class=\"table-danger\">FAIL</td>";
1443
          } else {
1444
            if (m[j].count(X->values_[i].id.seqno) == 0) {
1445
              m[j].insert(X->values_[i].id.seqno);
1446
              A << "<td><a href=\"" << HttpAnswer::BlockLink{X->values_[i]} << "\">" << X->values_[i].id.seqno
1447
                << "</a></td>";
1448
            } else {
1449
              A << "<td>" << X->values_[i].id.seqno << "</td>";
1450
            }
1451
          }
1452
          j++;
1453
        }
1454
        A << "</tr>\n";
1455
      }
1456
      A << "</table></div>";
1457
      return A.finish();
1458
    }();
1459
    auto R = MHD_create_response_from_buffer(page.length(), const_cast<char *>(page.c_str()), MHD_RESPMEM_MUST_COPY);
1460
    MHD_add_response_header(R, "Content-Type", "text/html");
1461
    promise_.set_value(std::move(R));
1462
  }
1463
  stop();
1464
}
1465

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

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

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

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