mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	Use partial liteservers in tonlib and lite-client
This commit is contained in:
		
							parent
							
								
									1ccf25d6b7
								
							
						
					
					
						commit
						2ea17ec03b
					
				
					 17 changed files with 891 additions and 974 deletions
				
			
		| 
						 | 
				
			
			@ -29,22 +29,16 @@
 | 
			
		|||
 | 
			
		||||
#include "lite-client-common.h"
 | 
			
		||||
 | 
			
		||||
#include "adnl/adnl-ext-client.h"
 | 
			
		||||
#include "tl-utils/lite-utils.hpp"
 | 
			
		||||
#include "auto/tl/ton_api_json.h"
 | 
			
		||||
#include "auto/tl/lite_api.hpp"
 | 
			
		||||
#include "td/utils/OptionParser.h"
 | 
			
		||||
#include "td/utils/Time.h"
 | 
			
		||||
#include "td/utils/filesystem.h"
 | 
			
		||||
#include "td/utils/format.h"
 | 
			
		||||
#include "td/utils/Random.h"
 | 
			
		||||
#include "td/utils/crypto.h"
 | 
			
		||||
#include "td/utils/overloaded.h"
 | 
			
		||||
#include "td/utils/port/signals.h"
 | 
			
		||||
#include "td/utils/port/stacktrace.h"
 | 
			
		||||
#include "td/utils/port/StdStreams.h"
 | 
			
		||||
#include "td/utils/port/FileFd.h"
 | 
			
		||||
#include "terminal/terminal.h"
 | 
			
		||||
#include "ton/lite-tl.hpp"
 | 
			
		||||
#include "block/block-db.h"
 | 
			
		||||
#include "block/block.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -58,18 +52,14 @@
 | 
			
		|||
#include "vm/vm.h"
 | 
			
		||||
#include "vm/cp0.h"
 | 
			
		||||
#include "vm/memo.h"
 | 
			
		||||
#include "ton/ton-shard.h"
 | 
			
		||||
#include "openssl/rand.hpp"
 | 
			
		||||
#include "crypto/vm/utils.h"
 | 
			
		||||
#include "crypto/common/util.h"
 | 
			
		||||
#include "common/checksum.h"
 | 
			
		||||
 | 
			
		||||
#if TD_DARWIN || TD_LINUX
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include "git.h"
 | 
			
		||||
 | 
			
		||||
using namespace std::literals::string_literals;
 | 
			
		||||
| 
						 | 
				
			
			@ -77,22 +67,10 @@ using td::Ref;
 | 
			
		|||
 | 
			
		||||
int verbosity;
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> TestNode::make_callback() {
 | 
			
		||||
  class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
			
		||||
   public:
 | 
			
		||||
    void on_ready() override {
 | 
			
		||||
      td::actor::send_closure(id_, &TestNode::conn_ready);
 | 
			
		||||
    }
 | 
			
		||||
    void on_stop_ready() override {
 | 
			
		||||
      td::actor::send_closure(id_, &TestNode::conn_closed);
 | 
			
		||||
    }
 | 
			
		||||
    Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   private:
 | 
			
		||||
    td::actor::ActorId<TestNode> id_;
 | 
			
		||||
  };
 | 
			
		||||
  return std::make_unique<Callback>(actor_id(this));
 | 
			
		||||
bool TestNode::LiteServer::supports(ton::ShardIdFull shard) const {
 | 
			
		||||
  return is_full || shard.is_masterchain() ||
 | 
			
		||||
         std::any_of(shards.begin(), shards.end(),
 | 
			
		||||
                     [&](const ton::ShardIdFull& our_shard) { return ton::shard_intersects(shard, our_shard); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::run() {
 | 
			
		||||
| 
						 | 
				
			
			@ -110,19 +88,23 @@ void TestNode::run() {
 | 
			
		|||
  io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique<Cb>(actor_id(this)));
 | 
			
		||||
  td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
 | 
			
		||||
 | 
			
		||||
  if (remote_public_key_.empty()) {
 | 
			
		||||
  if (!single_remote_public_key_.empty()) {  // Use single provided liteserver
 | 
			
		||||
    LiteServer s;
 | 
			
		||||
    s.addr = single_remote_addr_;
 | 
			
		||||
    s.public_key = single_remote_public_key_;
 | 
			
		||||
    single_liteserver_idx_ = 0;
 | 
			
		||||
    td::TerminalIO::out() << "using liteserver " << s.addr << "\n";
 | 
			
		||||
    servers_.push_back(std::move(s));
 | 
			
		||||
    run_init_queries();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto G = td::read_file(global_config_).move_as_ok();
 | 
			
		||||
  auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
 | 
			
		||||
  ton::ton_api::liteclient_config_global gc;
 | 
			
		||||
  ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
 | 
			
		||||
    CHECK(gc.liteservers_.size() > 0);
 | 
			
		||||
    auto idx = liteserver_idx_ >= 0 ? liteserver_idx_
 | 
			
		||||
                                    : td::Random::fast(0, static_cast<td::uint32>(gc.liteservers_.size() - 1));
 | 
			
		||||
    CHECK(idx >= 0 && static_cast<td::uint32>(idx) <= gc.liteservers_.size());
 | 
			
		||||
    auto& cli = gc.liteservers_[idx];
 | 
			
		||||
    remote_addr_.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
 | 
			
		||||
    remote_public_key_ = ton::PublicKey{cli->id_};
 | 
			
		||||
    td::TerminalIO::out() << "using liteserver " << idx << " with addr " << remote_addr_ << "\n";
 | 
			
		||||
  CHECK(gc.liteservers_.size() + gc.liteservers_v2_.size() > 0);
 | 
			
		||||
 | 
			
		||||
  if (gc.validator_ && gc.validator_->zero_state_) {
 | 
			
		||||
    zstate_id_.workchain = gc.validator_->zero_state_->workchain_;
 | 
			
		||||
    if (zstate_id_.workchain != ton::workchainInvalid) {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,10 +113,32 @@ void TestNode::run() {
 | 
			
		|||
      td::TerminalIO::out() << "zerostate set to " << zstate_id_.to_str() << "\n";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (auto& server : gc.liteservers_) {
 | 
			
		||||
    LiteServer s;
 | 
			
		||||
    s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure();
 | 
			
		||||
    s.public_key = ton::PublicKey{server->id_};
 | 
			
		||||
    servers_.push_back(std::move(s));
 | 
			
		||||
  }
 | 
			
		||||
  for (auto& server : gc.liteservers_v2_) {
 | 
			
		||||
    LiteServer s;
 | 
			
		||||
    s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure();
 | 
			
		||||
    s.public_key = ton::PublicKey{server->id_};
 | 
			
		||||
    s.is_full = false;
 | 
			
		||||
    for (const auto& shard : server->shards_) {
 | 
			
		||||
      s.shards.emplace_back(shard->workchain_, shard->shard_);
 | 
			
		||||
      CHECK(s.shards.back().is_valid_ext());
 | 
			
		||||
    }
 | 
			
		||||
    servers_.push_back(std::move(s));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  client_ =
 | 
			
		||||
      ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_, make_callback());
 | 
			
		||||
  if (single_liteserver_idx_ != -1) {  // Use single liteserver from config
 | 
			
		||||
    CHECK(single_liteserver_idx_ >= 0 && (size_t)single_liteserver_idx_ < gc.liteservers_.size());
 | 
			
		||||
    td::TerminalIO::out() << "using liteserver " << single_liteserver_idx_ << " with addr "
 | 
			
		||||
                          << servers_[single_liteserver_idx_].addr << "\n";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  run_init_queries();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
| 
						 | 
				
			
			@ -179,23 +183,142 @@ void TestNode::after_got_result(bool ok) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
bool TestNode::envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  return envelope_send_query_to_shard(ton::ShardIdFull(ton::masterchainId), std::move(query), std::move(promise));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query,
 | 
			
		||||
                                              td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  return envelope_send_query_to_shard(prefix.as_leaf_shard(), std::move(query), std::move(promise));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query,
 | 
			
		||||
                                            td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  if (single_liteserver_idx_ >= 0) {
 | 
			
		||||
    return envelope_send_query_to_server(single_liteserver_idx_, std::move(query), std::move(promise));
 | 
			
		||||
  }
 | 
			
		||||
  if (shard.is_masterchain() && mc_server_idx_ != -1) {
 | 
			
		||||
    return envelope_send_query_to_server(mc_server_idx_, std::move(query), std::move(promise));
 | 
			
		||||
  }
 | 
			
		||||
  auto it = shard_server_idx_cached_.find(shard);
 | 
			
		||||
  if (it != shard_server_idx_cached_.end()) {
 | 
			
		||||
    return envelope_send_query_to_server(it->second, std::move(query), std::move(promise));
 | 
			
		||||
  }
 | 
			
		||||
  int server_idx = -1;
 | 
			
		||||
  int random_idx = -1;
 | 
			
		||||
  int cnt = 0;
 | 
			
		||||
  bool selected_full = false;
 | 
			
		||||
  for (int i = 0; i < (int)servers_.size(); ++i) {
 | 
			
		||||
    const LiteServer& server = servers_[i];
 | 
			
		||||
    if (!server.supports(shard)) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (server.is_full && !selected_full) {
 | 
			
		||||
      selected_full = true;
 | 
			
		||||
      server_idx = -1;
 | 
			
		||||
      cnt = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (!server.is_full && selected_full) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (!server.client.empty()) {
 | 
			
		||||
      server_idx = i;
 | 
			
		||||
    }
 | 
			
		||||
    if (td::Random::fast(0, cnt) == 0) {
 | 
			
		||||
      random_idx = i;
 | 
			
		||||
    }
 | 
			
		||||
    ++cnt;
 | 
			
		||||
  }
 | 
			
		||||
  if (server_idx == -1) {
 | 
			
		||||
    server_idx = random_idx;
 | 
			
		||||
  }
 | 
			
		||||
  if (server_idx == -1) {
 | 
			
		||||
    running_queries_++;
 | 
			
		||||
  if (!ready_ || client_.empty()) {
 | 
			
		||||
    got_result(td::Status::Error("failed to send query to server: not ready"), std::move(promise));
 | 
			
		||||
    got_result(td::Status::Error(PSTRING() << "failed to select a suitable server for " << shard.to_str()),
 | 
			
		||||
               std::move(promise));
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  shard_server_idx_cached_[shard] = server_idx;
 | 
			
		||||
  if (shard.is_masterchain()) {
 | 
			
		||||
    mc_server_idx_ = server_idx;
 | 
			
		||||
  }
 | 
			
		||||
  return envelope_send_query_to_server(server_idx, std::move(query), std::move(promise));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query,
 | 
			
		||||
                                             td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  running_queries_++;
 | 
			
		||||
  LiteServer& server = servers_.at(server_idx);
 | 
			
		||||
  if (server.client.empty()) {
 | 
			
		||||
    start_client(server_idx);
 | 
			
		||||
  }
 | 
			
		||||
  CHECK(!server.client.empty());
 | 
			
		||||
 | 
			
		||||
  auto P = td::PromiseCreator::lambda(
 | 
			
		||||
      [SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
        td::actor::send_closure(SelfId, &TestNode::got_result, std::move(R), std::move(promise));
 | 
			
		||||
      });
 | 
			
		||||
  td::BufferSlice b =
 | 
			
		||||
      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query)), true);
 | 
			
		||||
  td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
 | 
			
		||||
  if (server.client_ready) {
 | 
			
		||||
    td::actor::send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
 | 
			
		||||
                            td::Timestamp::in(10.0), std::move(P));
 | 
			
		||||
  } else {
 | 
			
		||||
    server.wait_client_ready.push_back(
 | 
			
		||||
        [client = server.client.get(), b = std::move(b), P = std::move(P)](td::Result<td::Unit> R) mutable {
 | 
			
		||||
          if (R.is_ok()) {
 | 
			
		||||
            td::actor::send_closure(client, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
 | 
			
		||||
                                    td::Timestamp::in(10.0), std::move(P));
 | 
			
		||||
          } else {
 | 
			
		||||
            P.set_error(R.move_as_error_prefix("failed to connect: "));
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::start_client(int server_idx) {
 | 
			
		||||
  LiteServer& server = servers_[server_idx];
 | 
			
		||||
  CHECK(server.client.empty());
 | 
			
		||||
  class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
			
		||||
   public:
 | 
			
		||||
    void on_ready() override {
 | 
			
		||||
      td::actor::send_closure(id_, &TestNode::conn_ready, server_idx_);
 | 
			
		||||
    }
 | 
			
		||||
    void on_stop_ready() override {
 | 
			
		||||
      td::actor::send_closure(id_, &TestNode::conn_closed, server_idx_);
 | 
			
		||||
    }
 | 
			
		||||
    Callback(td::actor::ActorId<TestNode> id, int server_idx) : id_(std::move(id)), server_idx_(server_idx) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   private:
 | 
			
		||||
    td::actor::ActorId<TestNode> id_;
 | 
			
		||||
    int server_idx_;
 | 
			
		||||
  };
 | 
			
		||||
  server.client_ready = false;
 | 
			
		||||
  server.wait_client_ready.clear();
 | 
			
		||||
  LOG(INFO) << "Connecting to " << server.addr << " (liteserver #" << server_idx << ")";
 | 
			
		||||
  server.client = ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{server.public_key}, server.addr,
 | 
			
		||||
                                                   std::make_unique<Callback>(actor_id(this), server_idx));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::conn_ready(int server_idx) {
 | 
			
		||||
  LiteServer& server = servers_[server_idx];
 | 
			
		||||
  LOG(INFO) << "Connection to " << server.addr << " (liteserver #" << server_idx << ") is ready";
 | 
			
		||||
  server.client_ready = true;
 | 
			
		||||
  for (auto& p : server.wait_client_ready) {
 | 
			
		||||
    p.set_result(td::Unit());
 | 
			
		||||
  }
 | 
			
		||||
  server.wait_client_ready.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::conn_closed(int server_idx) {
 | 
			
		||||
  LiteServer& server = servers_[server_idx];
 | 
			
		||||
  LOG(INFO) << "Connection to " << server.addr << " (liteserver #" << server_idx << ") closed";
 | 
			
		||||
  server.client_ready = false;
 | 
			
		||||
  server.wait_client_ready.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Promise<td::Unit> TestNode::trivial_promise() {
 | 
			
		||||
  return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result<td::Unit> res) {
 | 
			
		||||
    if (res.is_error()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +433,7 @@ bool TestNode::dump_cached_cell(td::Slice hash_pfx, td::Slice type_name) {
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_server_time() {
 | 
			
		||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getTime>(), true);
 | 
			
		||||
  return envelope_send_query(std::move(b), [&, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
  return envelope_send_query_to_any(std::move(b), [&, Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
    if (res.is_error()) {
 | 
			
		||||
      LOG(ERROR) << "cannot get server time";
 | 
			
		||||
      return;
 | 
			
		||||
| 
						 | 
				
			
			@ -319,9 +442,10 @@ bool TestNode::get_server_time() {
 | 
			
		|||
      if (F.is_error()) {
 | 
			
		||||
        LOG(ERROR) << "cannot parse answer to liteServer.getTime";
 | 
			
		||||
      } else {
 | 
			
		||||
        server_time_ = F.move_as_ok()->now_;
 | 
			
		||||
        server_time_got_at_ = now();
 | 
			
		||||
        LOG(INFO) << "server time is " << server_time_ << " (delta " << server_time_ - server_time_got_at_ << ")";
 | 
			
		||||
        mc_server_time_ = F.move_as_ok()->now_;
 | 
			
		||||
        mc_server_time_got_at_ = now();
 | 
			
		||||
        LOG(INFO) << "server time is " << mc_server_time_ << " (delta " << mc_server_time_ - mc_server_time_got_at_
 | 
			
		||||
                  << ")";
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -329,13 +453,13 @@ bool TestNode::get_server_time() {
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_server_version(int mode) {
 | 
			
		||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getVersion>(), true);
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) {
 | 
			
		||||
  return envelope_send_query_to_any(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) {
 | 
			
		||||
    td::actor::send_closure_later(Self, &TestNode::got_server_version, std::move(res), mode);
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void TestNode::got_server_version(td::Result<td::BufferSlice> res, int mode) {
 | 
			
		||||
  server_ok_ = false;
 | 
			
		||||
  mc_server_ok_ = false;
 | 
			
		||||
  if (res.is_error()) {
 | 
			
		||||
    LOG(ERROR) << "cannot get server version and time (server too old?)";
 | 
			
		||||
  } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -344,11 +468,11 @@ void TestNode::got_server_version(td::Result<td::BufferSlice> res, int mode) {
 | 
			
		|||
      LOG(ERROR) << "cannot parse answer to liteServer.getVersion";
 | 
			
		||||
    } else {
 | 
			
		||||
      auto a = F.move_as_ok();
 | 
			
		||||
      set_server_version(a->version_, a->capabilities_);
 | 
			
		||||
      set_server_time(a->now_);
 | 
			
		||||
      set_mc_server_version(a->version_, a->capabilities_);
 | 
			
		||||
      set_mc_server_time(a->now_);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (!server_ok_) {
 | 
			
		||||
  if (!mc_server_ok_) {
 | 
			
		||||
    LOG(ERROR) << "server version is too old (at least " << (min_ls_version >> 8) << "." << (min_ls_version & 0xff)
 | 
			
		||||
               << " with capabilities " << min_ls_capabilities << " required), some queries are unavailable";
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -357,27 +481,27 @@ void TestNode::got_server_version(td::Result<td::BufferSlice> res, int mode) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::set_server_version(td::int32 version, td::int64 capabilities) {
 | 
			
		||||
  if (server_version_ != version || server_capabilities_ != capabilities) {
 | 
			
		||||
    server_version_ = version;
 | 
			
		||||
    server_capabilities_ = capabilities;
 | 
			
		||||
    LOG(WARNING) << "server version is " << (server_version_ >> 8) << "." << (server_version_ & 0xff)
 | 
			
		||||
                 << ", capabilities " << server_capabilities_;
 | 
			
		||||
void TestNode::set_mc_server_version(td::int32 version, td::int64 capabilities) {
 | 
			
		||||
  if (mc_server_version_ != version || mc_server_capabilities_ != capabilities) {
 | 
			
		||||
    mc_server_version_ = version;
 | 
			
		||||
    mc_server_capabilities_ = capabilities;
 | 
			
		||||
    LOG(WARNING) << "server version is " << (mc_server_version_ >> 8) << "." << (mc_server_version_ & 0xff)
 | 
			
		||||
                 << ", capabilities " << mc_server_capabilities_;
 | 
			
		||||
  }
 | 
			
		||||
  server_ok_ = (server_version_ >= min_ls_version) && !(~server_capabilities_ & min_ls_capabilities);
 | 
			
		||||
  mc_server_ok_ = (mc_server_version_ >= min_ls_version) && !(~mc_server_capabilities_ & min_ls_capabilities);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestNode::set_server_time(int server_utime) {
 | 
			
		||||
  server_time_ = server_utime;
 | 
			
		||||
  server_time_got_at_ = now();
 | 
			
		||||
  LOG(INFO) << "server time is " << server_time_ << " (delta " << server_time_ - server_time_got_at_ << ")";
 | 
			
		||||
void TestNode::set_mc_server_time(int server_utime) {
 | 
			
		||||
  mc_server_time_ = server_utime;
 | 
			
		||||
  mc_server_time_got_at_ = now();
 | 
			
		||||
  LOG(INFO) << "server time is " << mc_server_time_ << " (delta " << mc_server_time_ - mc_server_time_got_at_ << ")";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::get_server_mc_block_id() {
 | 
			
		||||
  int mode = (server_capabilities_ & 2) ? 0 : -1;
 | 
			
		||||
  int mode = (mc_server_capabilities_ & 2) ? 0 : -1;
 | 
			
		||||
  if (mode < 0) {
 | 
			
		||||
    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
 | 
			
		||||
    return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
    return envelope_send_query_to_any(std::move(b), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
      if (res.is_error()) {
 | 
			
		||||
        LOG(ERROR) << "cannot get masterchain info from server";
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -397,7 +521,8 @@ bool TestNode::get_server_mc_block_id() {
 | 
			
		|||
  } else {
 | 
			
		||||
    auto b =
 | 
			
		||||
        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfoExt>(mode), true);
 | 
			
		||||
    return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
    return envelope_send_query_to_any(
 | 
			
		||||
        std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
          if (res.is_error()) {
 | 
			
		||||
            LOG(ERROR) << "cannot get extended masterchain info from server";
 | 
			
		||||
            return;
 | 
			
		||||
| 
						 | 
				
			
			@ -448,8 +573,8 @@ void TestNode::got_server_mc_block_id(ton::BlockIdExt blkid, ton::ZeroStateIdExt
 | 
			
		|||
 | 
			
		||||
void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateIdExt zstateid, int mode, int version,
 | 
			
		||||
                                          long long capabilities, int last_utime, int server_now) {
 | 
			
		||||
  set_server_version(version, capabilities);
 | 
			
		||||
  set_server_time(server_now);
 | 
			
		||||
  set_mc_server_version(version, capabilities);
 | 
			
		||||
  set_mc_server_time(server_now);
 | 
			
		||||
  if (last_utime > server_now) {
 | 
			
		||||
    LOG(WARNING) << "server claims to have a masterchain block " << blkid.to_str() << " created at " << last_utime
 | 
			
		||||
                 << " (" << last_utime - server_now << " seconds in the future)";
 | 
			
		||||
| 
						 | 
				
			
			@ -457,10 +582,10 @@ void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateI
 | 
			
		|||
    LOG(WARNING) << "server appears to be out of sync: its newest masterchain block is " << blkid.to_str()
 | 
			
		||||
                 << " created at " << last_utime << " (" << server_now - last_utime
 | 
			
		||||
                 << " seconds ago according to the server's clock)";
 | 
			
		||||
  } else if (last_utime < server_time_got_at_ - 60) {
 | 
			
		||||
  } else if (last_utime < mc_server_time_got_at_ - 60) {
 | 
			
		||||
    LOG(WARNING) << "either the server is out of sync, or the local clock is set incorrectly: the newest masterchain "
 | 
			
		||||
                    "block known to server is "
 | 
			
		||||
                 << blkid.to_str() << " created at " << last_utime << " (" << server_now - server_time_got_at_
 | 
			
		||||
                 << blkid.to_str() << " created at " << last_utime << " (" << server_now - mc_server_time_got_at_
 | 
			
		||||
                 << " seconds ago according to the local clock)";
 | 
			
		||||
  }
 | 
			
		||||
  got_server_mc_block_id(blkid, zstateid, last_utime);
 | 
			
		||||
| 
						 | 
				
			
			@ -469,7 +594,8 @@ void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateI
 | 
			
		|||
bool TestNode::request_block(ton::BlockIdExt blkid) {
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server";
 | 
			
		||||
          return;
 | 
			
		||||
| 
						 | 
				
			
			@ -494,7 +620,8 @@ bool TestNode::request_block(ton::BlockIdExt blkid) {
 | 
			
		|||
bool TestNode::request_state(ton::BlockIdExt blkid) {
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server";
 | 
			
		||||
          return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1150,8 +1277,18 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
 | 
			
		|||
    LOG(ERROR) << "failed to read file `" << filename << "`: " << err.to_string();
 | 
			
		||||
    return err;
 | 
			
		||||
  }
 | 
			
		||||
  if (ready_ && !client_.empty()) {
 | 
			
		||||
  LOG(ERROR) << "sending query from file " << filename;
 | 
			
		||||
 | 
			
		||||
  TRY_RESULT_PREFIX(root, vm::std_boc_deserialize(F.ok().as_slice()), "invalid boc: ");
 | 
			
		||||
  block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
 | 
			
		||||
  if (!tlb::unpack_cell_inexact(root, info)) {
 | 
			
		||||
    return td::Status::Error("failed to unpack external message header");
 | 
			
		||||
  }
 | 
			
		||||
  auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(info.dest);
 | 
			
		||||
  if (!dest_prefix.is_valid()) {
 | 
			
		||||
    return td::Status::Error("destination of the message is invalid");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) {
 | 
			
		||||
    if (R.is_error()) {
 | 
			
		||||
      return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1164,13 +1301,10 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
 | 
			
		|||
      LOG(INFO) << "external message status is " << status;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
    auto b =
 | 
			
		||||
        ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(F.move_as_ok()), true);
 | 
			
		||||
    return envelope_send_query(std::move(b), std::move(P)) ? td::Status::OK()
 | 
			
		||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(F.move_as_ok()), true);
 | 
			
		||||
  return envelope_send_query_to_account(dest_prefix, std::move(b), std::move(P))
 | 
			
		||||
             ? td::Status::OK()
 | 
			
		||||
             : td::Status::Error("cannot send query to server");
 | 
			
		||||
  } else {
 | 
			
		||||
    return td::Status::Error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,9 +1312,6 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
			
		|||
  if (!ref_blkid.is_valid()) {
 | 
			
		||||
    return set_error("must obtain last block information before making other queries");
 | 
			
		||||
  }
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  if (addr_ext) {
 | 
			
		||||
    return get_special_smc_addr(
 | 
			
		||||
        addr_ext, [this, ref_blkid, filename, mode, prunned](td::Result<ton::StdSmcAddress> res) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1202,10 +1333,12 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
			
		|||
                                     ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
			
		||||
                                 true);
 | 
			
		||||
  }
 | 
			
		||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
			
		||||
  LOG(INFO) << "requesting " << (prunned ? "prunned " : "") << "account state for " << workchain << ":" << addr.to_hex()
 | 
			
		||||
            << " with respect to " << ref_blkid.to_str() << " with savefile `" << filename << "` and mode " << mode;
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode,
 | 
			
		||||
                                            prunned](td::Result<td::BufferSlice> R) {
 | 
			
		||||
  return envelope_send_query_to_account(
 | 
			
		||||
      account_prefix, std::move(b),
 | 
			
		||||
      [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode, prunned](td::Result<td::BufferSlice> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1285,18 +1418,17 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
			
		|||
  if (!ref_blkid.is_valid()) {
 | 
			
		||||
    return set_error("must obtain last block information before making other queries");
 | 
			
		||||
  }
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
			
		||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
			
		||||
  if (!mode) {
 | 
			
		||||
    auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
 | 
			
		||||
                                          ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
 | 
			
		||||
                                      true);
 | 
			
		||||
    LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to "
 | 
			
		||||
              << ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters";
 | 
			
		||||
    return envelope_send_query(
 | 
			
		||||
        std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params),
 | 
			
		||||
    return envelope_send_query_to_account(
 | 
			
		||||
        account_prefix, std::move(b),
 | 
			
		||||
        [Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params),
 | 
			
		||||
         promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
          if (R.is_error()) {
 | 
			
		||||
            promise.set_error(R.move_as_error());
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,8 +1469,9 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
			
		|||
    LOG(INFO) << "requesting remote get-method execution for " << workchain << ":" << addr.to_hex()
 | 
			
		||||
              << " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with "
 | 
			
		||||
              << params.size() << " parameters";
 | 
			
		||||
    return envelope_send_query(std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode,
 | 
			
		||||
                                              params = std::move(params),
 | 
			
		||||
    return envelope_send_query_to_account(
 | 
			
		||||
        account_prefix, std::move(b),
 | 
			
		||||
        [Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params),
 | 
			
		||||
         promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
          if (R.is_error()) {
 | 
			
		||||
            promise.set_error(R.move_as_error());
 | 
			
		||||
| 
						 | 
				
			
			@ -1350,11 +1483,11 @@ bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
 | 
			
		|||
            promise.set_error(td::Status::Error("cannot parse answer to liteServer.runSmcMethod"));
 | 
			
		||||
          } else {
 | 
			
		||||
            auto f = F.move_as_ok();
 | 
			
		||||
        td::actor::send_closure_later(Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
 | 
			
		||||
                                      ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
 | 
			
		||||
                                      std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name,
 | 
			
		||||
                                      std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_),
 | 
			
		||||
                                      std::move(f->result_), f->exit_code_, std::move(promise));
 | 
			
		||||
            td::actor::send_closure_later(
 | 
			
		||||
                Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
 | 
			
		||||
                ton::create_block_id(f->shardblk_), std::move(f->shard_proof_), std::move(f->proof_),
 | 
			
		||||
                std::move(f->state_proof_), workchain, addr, method_name, std::move(params), std::move(f->init_c7_),
 | 
			
		||||
                std::move(f->lib_extras_), std::move(f->result_), f->exit_code_, std::move(promise));
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1586,8 +1719,8 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add
 | 
			
		|||
  params.emplace_back(td::make_refint(bits));
 | 
			
		||||
  params.emplace_back(td::make_refint(refs));
 | 
			
		||||
  params.emplace_back(td::make_refint(expires_in));
 | 
			
		||||
  auto P = td::PromiseCreator::lambda(
 | 
			
		||||
      [this, expires_in, bits, refs, chash, filename](td::Result<std::vector<vm::StackEntry>> R) {
 | 
			
		||||
  auto P =
 | 
			
		||||
      td::PromiseCreator::lambda([expires_in, bits, refs, chash, filename](td::Result<std::vector<vm::StackEntry>> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          LOG(ERROR) << R.move_as_error();
 | 
			
		||||
          return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,10 +1782,6 @@ bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress
 | 
			
		|||
    return set_error("domain name too long");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (workchain == ton::workchainInvalid) {
 | 
			
		||||
    if (dns_root_queried_) {
 | 
			
		||||
      workchain = ton::masterchainId;
 | 
			
		||||
| 
						 | 
				
			
			@ -1861,17 +1990,16 @@ bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workc
 | 
			
		|||
  if (!ton::shard_contains(blkid.shard_full(), ton::extract_addr_prefix(workchain, addr))) {
 | 
			
		||||
    return set_error("the shard of this block cannot contain this account");
 | 
			
		||||
  }
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
			
		||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
 | 
			
		||||
                                        ton::create_tl_lite_block_id(blkid), std::move(a), lt),
 | 
			
		||||
                                    true);
 | 
			
		||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
			
		||||
  LOG(INFO) << "requesting transaction " << lt << " of " << workchain << ":" << addr.to_hex() << " from block "
 | 
			
		||||
            << blkid.to_str();
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result<td::BufferSlice> R) -> void {
 | 
			
		||||
  return envelope_send_query_to_account(
 | 
			
		||||
      account_prefix, std::move(b),
 | 
			
		||||
      [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result<td::BufferSlice> R) -> void {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1888,16 +2016,15 @@ bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workc
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_last_transactions(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::LogicalTime lt,
 | 
			
		||||
                                     ton::Bits256 hash, unsigned count, bool dump) {
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(count, std::move(a), lt, hash), true);
 | 
			
		||||
  ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64));
 | 
			
		||||
  LOG(INFO) << "requesting " << count << " last transactions from " << lt << ":" << hash.to_hex() << " of " << workchain
 | 
			
		||||
            << ":" << addr.to_hex();
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result<td::BufferSlice> R) {
 | 
			
		||||
  return envelope_send_query_to_account(
 | 
			
		||||
      account_prefix, std::move(b),
 | 
			
		||||
      [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result<td::BufferSlice> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2257,10 +2384,10 @@ void TestNode::got_one_transaction(ton::BlockIdExt req_blkid, ton::BlockIdExt bl
 | 
			
		|||
                 << " but received data has " << root->get_hash().bits().to_hex(256);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  } catch (vm::VmError err) {
 | 
			
		||||
  } catch (vm::VmError& err) {
 | 
			
		||||
    LOG(ERROR) << "error while traversing block transaction proof : " << err.get_msg();
 | 
			
		||||
    return;
 | 
			
		||||
  } catch (vm::VmVirtError err) {
 | 
			
		||||
  } catch (vm::VmVirtError& err) {
 | 
			
		||||
    LOG(ERROR) << "virtualization error while traversing block transaction proof : " << err.get_msg();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2439,16 +2566,14 @@ void TestNode::got_last_transactions(std::vector<ton::BlockIdExt> blkids, td::Bu
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_block_transactions(ton::BlockIdExt blkid, int mode, unsigned count, ton::Bits256 acc_addr,
 | 
			
		||||
                                      ton::LogicalTime lt) {
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  auto a = ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(acc_addr, lt);
 | 
			
		||||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
 | 
			
		||||
                                        ton::create_tl_lite_block_id(blkid), mode, count, std::move(a), false, false),
 | 
			
		||||
                                    true);
 | 
			
		||||
  LOG(INFO) << "requesting " << count << " transactions from block " << blkid.to_str() << " starting from account "
 | 
			
		||||
            << acc_addr.to_hex() << " lt " << lt;
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> R) {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), mode](td::Result<td::BufferSlice> R) {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2490,13 +2615,11 @@ bool TestNode::get_all_shards(std::string filename, bool use_last, ton::BlockIdE
 | 
			
		|||
  if (!blkid.is_masterchain()) {
 | 
			
		||||
    return set_error("only masterchain blocks contain shard configuration");
 | 
			
		||||
  }
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(blkid)), true);
 | 
			
		||||
  LOG(INFO) << "requesting recent shard configuration";
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), filename](td::Result<td::BufferSlice> R) -> void {
 | 
			
		||||
  return envelope_send_query_to_any(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), filename](td::Result<td::BufferSlice> R) -> void {
 | 
			
		||||
        if (R.is_error()) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2505,8 +2628,8 @@ bool TestNode::get_all_shards(std::string filename, bool use_last, ton::BlockIdE
 | 
			
		|||
          LOG(ERROR) << "cannot parse answer to liteServer.getAllShardsInfo";
 | 
			
		||||
        } else {
 | 
			
		||||
          auto f = F.move_as_ok();
 | 
			
		||||
      td::actor::send_closure_later(Self, &TestNode::got_all_shards, ton::create_block_id(f->id_), std::move(f->proof_),
 | 
			
		||||
                                    std::move(f->data_), filename);
 | 
			
		||||
          td::actor::send_closure_later(Self, &TestNode::got_all_shards, ton::create_block_id(f->id_),
 | 
			
		||||
                                        std::move(f->proof_), std::move(f->data_), filename);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2572,9 +2695,6 @@ bool TestNode::parse_get_config_params(ton::BlockIdExt blkid, int mode, std::str
 | 
			
		|||
      params.push_back(x);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  if (!blkid.is_masterchain_ext()) {
 | 
			
		||||
    return set_error("only masterchain blocks contain configuration");
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2593,10 +2713,6 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, td::Promise<std::unique_
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigInfo> promise, int mode,
 | 
			
		||||
                                     std::string filename, std::vector<int> params) {
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    promise.set_error(td::Status::Error("server connection not ready"));
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if (!blkid.is_masterchain_ext()) {
 | 
			
		||||
    promise.set_error(td::Status::Error("masterchain reference block expected"));
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -2614,7 +2730,8 @@ bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigIn
 | 
			
		|||
                                                      true);
 | 
			
		||||
  LOG(INFO) << "requesting " << params.size() << " configuration parameters with respect to masterchain block "
 | 
			
		||||
            << blkid.to_str();
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), mode, filename, blkid, params = std::move(params),
 | 
			
		||||
  return envelope_send_query_to_any(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), mode, filename, blkid, params = std::move(params),
 | 
			
		||||
                     promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
        td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, mode, filename, std::move(params),
 | 
			
		||||
                                      std::move(R), std::move(promise));
 | 
			
		||||
| 
						 | 
				
			
			@ -2806,8 +2923,8 @@ bool TestNode::get_block(ton::BlockIdExt blkid, bool dump) {
 | 
			
		|||
  LOG(INFO) << "got block download request for " << blkid.to_str();
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(blkid)), true);
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot obtain block " << blkid.to_str()
 | 
			
		||||
                     << " from server : " << res.move_as_error().to_string();
 | 
			
		||||
| 
						 | 
				
			
			@ -2835,8 +2952,8 @@ bool TestNode::get_state(ton::BlockIdExt blkid, bool dump) {
 | 
			
		|||
  LOG(INFO) << "got state download request for " << blkid.to_str();
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getState>(ton::create_tl_lite_block_id(blkid)), true);
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result<td::BufferSlice> res) -> void {
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot obtain state " << blkid.to_str()
 | 
			
		||||
                     << " from server : " << res.move_as_error().to_string();
 | 
			
		||||
| 
						 | 
				
			
			@ -2973,7 +3090,7 @@ void TestNode::got_state(ton::BlockIdExt blkid, ton::RootHash root_hash, ton::Fi
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool TestNode::get_show_block_header(ton::BlockIdExt blkid, int mode) {
 | 
			
		||||
  return get_block_header(blkid, mode, [this, blkid](td::Result<BlockHdrInfo> R) {
 | 
			
		||||
  return get_block_header(blkid, mode, [this](td::Result<BlockHdrInfo> R) {
 | 
			
		||||
    if (R.is_error()) {
 | 
			
		||||
      LOG(ERROR) << "unable to fetch block header: " << R.move_as_error();
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -2988,8 +3105,9 @@ bool TestNode::get_block_header(ton::BlockIdExt blkid, int mode, td::Promise<Tes
 | 
			
		|||
  LOG(INFO) << "got block header request for " << blkid.to_str() << " with mode " << mode;
 | 
			
		||||
  auto b = ton::serialize_tl_object(
 | 
			
		||||
      ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(blkid), mode), true);
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [this, blkid, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      blkid.shard_full(), std::move(b),
 | 
			
		||||
      [this, blkid, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
			
		||||
        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
			
		||||
                                  PSLICE() << "cannot obtain block header for " << blkid.to_str() << " from server :");
 | 
			
		||||
        got_block_header_raw(std::move(res), std::move(promise), blkid);
 | 
			
		||||
| 
						 | 
				
			
			@ -3015,8 +3133,9 @@ bool TestNode::lookup_block(ton::ShardIdFull shard, int mode, td::uint64 arg,
 | 
			
		|||
  auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_lookupBlock>(
 | 
			
		||||
                                        mode, ton::create_tl_lite_block_id_simple(id), arg, (td::uint32)arg),
 | 
			
		||||
                                    true);
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
      std::move(b), [this, id, mode, arg, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
			
		||||
  return envelope_send_query_to_shard(
 | 
			
		||||
      shard, std::move(b),
 | 
			
		||||
      [this, id, mode, arg, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable -> void {
 | 
			
		||||
        TRY_RESULT_PROMISE_PREFIX(promise, res, std::move(R),
 | 
			
		||||
                                  PSLICE() << "cannot look up block header for " << id.to_str() << " with mode " << mode
 | 
			
		||||
                                           << " and argument " << arg << " from server :");
 | 
			
		||||
| 
						 | 
				
			
			@ -3130,9 +3249,9 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
 | 
			
		|||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    show_block_header(blkid, std::move(virt_root), mode);
 | 
			
		||||
  } catch (vm::VmError err) {
 | 
			
		||||
  } catch (vm::VmError& err) {
 | 
			
		||||
    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
			
		||||
  } catch (vm::VmVirtError err) {
 | 
			
		||||
  } catch (vm::VmVirtError& err) {
 | 
			
		||||
    LOG(ERROR) << "error processing header for " << blkid.to_str() << " : " << err.get_msg();
 | 
			
		||||
  }
 | 
			
		||||
  show_new_blkids();
 | 
			
		||||
| 
						 | 
				
			
			@ -3161,7 +3280,8 @@ bool TestNode::get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod
 | 
			
		|||
      ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getBlockProof>(
 | 
			
		||||
                                   mode & 0xfff, ton::create_tl_lite_block_id(from), ton::create_tl_lite_block_id(to)),
 | 
			
		||||
                               true);
 | 
			
		||||
  return envelope_send_query(std::move(b), [Self = actor_id(this), from, to, mode](td::Result<td::BufferSlice> res) {
 | 
			
		||||
  return envelope_send_query_to_any(
 | 
			
		||||
      std::move(b), [Self = actor_id(this), from, to, mode](td::Result<td::BufferSlice> res) {
 | 
			
		||||
        if (res.is_error()) {
 | 
			
		||||
          LOG(ERROR) << "cannot obtain block proof for " << ((mode & 1) ? to.to_str() : "last masterchain block")
 | 
			
		||||
                     << " starting from " << from.to_str() << " from server : " << res.move_as_error().to_string();
 | 
			
		||||
| 
						 | 
				
			
			@ -3222,9 +3342,6 @@ void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod
 | 
			
		|||
 | 
			
		||||
bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after,
 | 
			
		||||
                                 ton::UnixTime min_utime) {
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    return set_error("server connection not ready");
 | 
			
		||||
  }
 | 
			
		||||
  if (!blkid.is_masterchain_ext()) {
 | 
			
		||||
    return set_error("only masterchain blocks contain block creator statistics");
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -3235,7 +3352,7 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_c
 | 
			
		|||
  auto& os = *osp;
 | 
			
		||||
  return get_creator_stats(
 | 
			
		||||
      blkid, mode, req_count, start_after, min_utime,
 | 
			
		||||
      [min_utime, &os](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
			
		||||
      [&os](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
			
		||||
            const block::DiscountedCounter& shard_cnt) -> bool {
 | 
			
		||||
        os << key.to_hex() << " mc_cnt:" << mc_cnt << " shard_cnt:" << shard_cnt << std::endl;
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -3265,10 +3382,6 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_c
 | 
			
		|||
bool TestNode::get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton::UnixTime min_utime,
 | 
			
		||||
                                 TestNode::creator_stats_func_t func, std::unique_ptr<TestNode::CreatorStatsRes> state,
 | 
			
		||||
                                 td::Promise<std::unique_ptr<TestNode::CreatorStatsRes>> promise) {
 | 
			
		||||
  if (!(ready_ && !client_.empty())) {
 | 
			
		||||
    promise.set_error(td::Status::Error("server connection not ready"));
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if (!state) {
 | 
			
		||||
    promise.set_error(td::Status::Error("null CreatorStatsRes"));
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -3287,7 +3400,7 @@ bool TestNode::get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton:
 | 
			
		|||
  LOG(INFO) << "requesting up to " << req_count << " block creator stats records with respect to masterchain block "
 | 
			
		||||
            << blkid.to_str() << " starting from validator public key " << state->last_key.to_hex() << " created after "
 | 
			
		||||
            << min_utime << " (mode=" << state->mode << ")";
 | 
			
		||||
  return envelope_send_query(
 | 
			
		||||
  return envelope_send_query_to_any(
 | 
			
		||||
      std::move(b), [this, blkid, req_count, state = std::move(state), min_utime, func = std::move(func),
 | 
			
		||||
                     promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
        TRY_RESULT_PROMISE(promise, res, std::move(R));
 | 
			
		||||
| 
						 | 
				
			
			@ -3504,7 +3617,7 @@ bool TestNode::load_creator_stats(std::unique_ptr<TestNode::ValidatorLoadInfo> l
 | 
			
		|||
  ton::UnixTime min_utime = info.valid_since - 1000;
 | 
			
		||||
  return get_creator_stats(
 | 
			
		||||
      info.blk_id, 1000, min_utime,
 | 
			
		||||
      [min_utime, &info](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
			
		||||
      [&info](const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
 | 
			
		||||
              const block::DiscountedCounter& shard_cnt) -> bool {
 | 
			
		||||
        info.store_record(key, mc_cnt, shard_cnt);
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -3730,7 +3843,8 @@ bool compute_punishment_default(int interval, bool severe, td::RefInt256& fine,
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part, Ref<vm::Cell> punishment_params) {
 | 
			
		||||
bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part,
 | 
			
		||||
                        Ref<vm::Cell> punishment_params) {
 | 
			
		||||
  if (punishment_params.is_null()) {
 | 
			
		||||
    return compute_punishment_default(interval, severe, fine, fine_part);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -3747,24 +3861,31 @@ bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned
 | 
			
		|||
  fine_part = rec.default_proportional_fine;
 | 
			
		||||
 | 
			
		||||
  if (severe) {
 | 
			
		||||
    fine = fine * rec.severity_flat_mult; fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.severity_proportional_mult; fine_part >>= 8;
 | 
			
		||||
    fine = fine * rec.severity_flat_mult;
 | 
			
		||||
    fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.severity_proportional_mult;
 | 
			
		||||
    fine_part >>= 8;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (interval >= rec.long_interval) {
 | 
			
		||||
    fine = fine * rec.long_flat_mult; fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.long_proportional_mult; fine_part >>= 8;
 | 
			
		||||
    fine = fine * rec.long_flat_mult;
 | 
			
		||||
    fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.long_proportional_mult;
 | 
			
		||||
    fine_part >>= 8;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  if (interval >= rec.medium_interval) {
 | 
			
		||||
    fine = fine * rec.medium_flat_mult; fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.medium_proportional_mult; fine_part >>= 8;
 | 
			
		||||
    fine = fine * rec.medium_flat_mult;
 | 
			
		||||
    fine >>= 8;
 | 
			
		||||
    fine_part = fine_part * rec.medium_proportional_mult;
 | 
			
		||||
    fine_part >>= 8;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part, Ref<vm::Cell> punishment_params) {
 | 
			
		||||
bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part,
 | 
			
		||||
                      Ref<vm::Cell> punishment_params) {
 | 
			
		||||
  td::RefInt256 computed_fine;
 | 
			
		||||
  unsigned computed_fine_part;
 | 
			
		||||
  return compute_punishment(interval, severe, computed_fine, computed_fine_part, punishment_params) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -3899,7 +4020,7 @@ td::Result<Ref<vm::Cell>> TestNode::ValidatorLoadInfo::build_proof(int idx, td::
 | 
			
		|||
    block::gen::ValidatorDescr::Record_validator_addr rec2;
 | 
			
		||||
    if (tlb::csr_unpack(entry, rec1)) {
 | 
			
		||||
      pk = std::move(rec1.public_key);
 | 
			
		||||
    } else if (tlb::csr_unpack(std::move(entry), rec2)) {
 | 
			
		||||
    } else if (tlb::csr_unpack(entry, rec2)) {
 | 
			
		||||
      pk = std::move(rec2.public_key);
 | 
			
		||||
    } else {
 | 
			
		||||
      return td::Status::Error("cannot unpack ValidatorDescr");
 | 
			
		||||
| 
						 | 
				
			
			@ -4115,7 +4236,8 @@ td::Status TestNode::continue_check_validator_load_proof(std::unique_ptr<Validat
 | 
			
		|||
    if (suggested_fine.is_null()) {
 | 
			
		||||
      return td::Status::Error("cannot parse suggested fine");
 | 
			
		||||
    }
 | 
			
		||||
    if (!check_punishment(interval, severe, suggested_fine, rec.suggested_fine_part, info2->config->get_config_param(40))) {
 | 
			
		||||
    if (!check_punishment(interval, severe, suggested_fine, rec.suggested_fine_part,
 | 
			
		||||
                          info2->config->get_config_param(40))) {
 | 
			
		||||
      LOG(ERROR) << "proposed punishment (fine " << td::dec_string(suggested_fine)
 | 
			
		||||
                 << ", fine_part=" << (double)rec.suggested_fine_part / (1LL << 32) << " is too harsh";
 | 
			
		||||
      show_vote(root->get_hash().bits(), false);
 | 
			
		||||
| 
						 | 
				
			
			@ -4264,7 +4386,8 @@ int main(int argc, char* argv[]) {
 | 
			
		|||
    return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9");
 | 
			
		||||
  });
 | 
			
		||||
  p.add_option('V', "version", "shows lite-client build information", [&]() {
 | 
			
		||||
    std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1() << ", Date: " << GitMetadata::CommitDate() << "]\n";
 | 
			
		||||
    std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1()
 | 
			
		||||
              << ", Date: " << GitMetadata::CommitDate() << "]\n";
 | 
			
		||||
 | 
			
		||||
    std::exit(0);
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,8 +57,7 @@ class TestNode : public td::actor::Actor {
 | 
			
		|||
    bool client_ready = false;
 | 
			
		||||
    std::vector<td::Promise<td::Unit>> wait_client_ready;
 | 
			
		||||
 | 
			
		||||
    int max_common_prefix(ton::ShardIdFull shard) const;
 | 
			
		||||
    bool supports_shard(ton::ShardIdFull shard) const;
 | 
			
		||||
    bool supports(ton::ShardIdFull shard) const;
 | 
			
		||||
  };
 | 
			
		||||
  std::vector<LiteServer> servers_;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -352,9 +351,6 @@ class TestNode : public td::actor::Actor {
 | 
			
		|||
  bool parse_shard_id(ton::ShardIdFull& shard);
 | 
			
		||||
  bool parse_block_id_ext(ton::BlockIdExt& blkid, bool allow_incomplete = false);
 | 
			
		||||
  bool parse_block_id_ext(std::string blk_id_string, ton::BlockIdExt& blkid, bool allow_incomplete = false) const;
 | 
			
		||||
  bool parse_stack_value(td::Slice str, vm::StackEntry& value);
 | 
			
		||||
  bool parse_stack_value(vm::StackEntry& value);
 | 
			
		||||
  bool parse_stack_values(std::vector<vm::StackEntry>& values);
 | 
			
		||||
  bool register_blkid(const ton::BlockIdExt& blkid);
 | 
			
		||||
  bool show_new_blkids(bool all = false);
 | 
			
		||||
  bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const;
 | 
			
		||||
| 
						 | 
				
			
			@ -458,8 +454,7 @@ class TestNode : public td::actor::Actor {
 | 
			
		|||
 | 
			
		||||
  void parse_line(td::BufferSlice data);
 | 
			
		||||
 | 
			
		||||
  TestNode() {
 | 
			
		||||
  }
 | 
			
		||||
  TestNode() = default;
 | 
			
		||||
 | 
			
		||||
  void run();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -8,7 +8,6 @@ set(TONLIB_SOURCE
 | 
			
		|||
  tonlib/Client.cpp
 | 
			
		||||
  tonlib/Config.cpp
 | 
			
		||||
  tonlib/ExtClient.cpp
 | 
			
		||||
  tonlib/ExtClientMulti.cpp
 | 
			
		||||
  tonlib/ExtClientLazy.cpp
 | 
			
		||||
  tonlib/ExtClientOutbound.cpp
 | 
			
		||||
  tonlib/KeyStorage.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +23,7 @@ set(TONLIB_SOURCE
 | 
			
		|||
  tonlib/Client.h
 | 
			
		||||
  tonlib/Config.h
 | 
			
		||||
  tonlib/ExtClient.h
 | 
			
		||||
  tonlib/ExtClientMulti.h
 | 
			
		||||
  tonlib/ExtClientRaw.h
 | 
			
		||||
  tonlib/ExtClientLazy.h
 | 
			
		||||
  tonlib/ExtClientOutbound.h
 | 
			
		||||
  tonlib/KeyStorage.h
 | 
			
		||||
  tonlib/KeyValue.h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,16 +66,16 @@ td::Result<Config> Config::parse(std::string str) {
 | 
			
		|||
    return td::Status::Error("Invalid config (1)");
 | 
			
		||||
  }
 | 
			
		||||
  td::JsonArray empty_array;
 | 
			
		||||
  TRY_RESULT(lite_clients_obj,
 | 
			
		||||
  TRY_RESULT(lite_servers_obj,
 | 
			
		||||
             td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, true));
 | 
			
		||||
  auto &lite_clients =
 | 
			
		||||
      lite_clients_obj.type() == td::JsonValue::Type::Array ? lite_clients_obj.get_array() : empty_array;
 | 
			
		||||
  TRY_RESULT(lite_clients_v2_obj,
 | 
			
		||||
  auto &lite_servers =
 | 
			
		||||
      lite_servers_obj.type() == td::JsonValue::Type::Array ? lite_servers_obj.get_array() : empty_array;
 | 
			
		||||
  TRY_RESULT(lite_servers_v2_obj,
 | 
			
		||||
             td::get_json_object_field(json.get_object(), "liteservers_v2", td::JsonValue::Type::Array, true));
 | 
			
		||||
  auto &lite_clients_v2 =
 | 
			
		||||
      lite_clients_v2_obj.type() == td::JsonValue::Type::Array ? lite_clients_v2_obj.get_array() : empty_array;
 | 
			
		||||
  auto &lite_servers_v2 =
 | 
			
		||||
      lite_servers_v2_obj.type() == td::JsonValue::Type::Array ? lite_servers_v2_obj.get_array() : empty_array;
 | 
			
		||||
 | 
			
		||||
  auto parse_desc = [&](td::JsonValue& value) -> td::Result<Config::LiteClient> {
 | 
			
		||||
  auto parse_desc = [&](td::JsonValue &value) -> td::Result<Config::LiteServer> {
 | 
			
		||||
    if (value.type() != td::JsonValue::Type::Object) {
 | 
			
		||||
      return td::Status::Error("Invalid config (2)");
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +83,8 @@ td::Result<Config> Config::parse(std::string str) {
 | 
			
		|||
 | 
			
		||||
    TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false));
 | 
			
		||||
    TRY_RESULT(port, td::get_json_object_int_field(object, "port", false));
 | 
			
		||||
    Config::LiteClient client;
 | 
			
		||||
    TRY_STATUS(client.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port));
 | 
			
		||||
    Config::LiteServer server;
 | 
			
		||||
    TRY_STATUS(server.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast<td::int32>(ip)), port));
 | 
			
		||||
 | 
			
		||||
    TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false));
 | 
			
		||||
    auto &id = id_obj.get_object();
 | 
			
		||||
| 
						 | 
				
			
			@ -98,20 +98,19 @@ td::Result<Config> Config::parse(std::string str) {
 | 
			
		|||
      return td::Status::Error("Invalid config (4)");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    client.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
 | 
			
		||||
    return client;
 | 
			
		||||
    server.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
 | 
			
		||||
    return server;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  Config res;
 | 
			
		||||
  for (auto &value : lite_clients) {
 | 
			
		||||
    TRY_RESULT(client, parse_desc(value));
 | 
			
		||||
    res.lite_clients.push_back(std::move(client));
 | 
			
		||||
  for (auto &value : lite_servers) {
 | 
			
		||||
    TRY_RESULT(server, parse_desc(value));
 | 
			
		||||
    res.lite_servers.push_back(std::move(server));
 | 
			
		||||
  }
 | 
			
		||||
  for (auto &value : lite_clients_v2) {
 | 
			
		||||
    TRY_RESULT(client, parse_desc(value));
 | 
			
		||||
    client.is_full = false;
 | 
			
		||||
    TRY_RESULT(shards_obj,
 | 
			
		||||
               td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false));
 | 
			
		||||
  for (auto &value : lite_servers_v2) {
 | 
			
		||||
    TRY_RESULT(server, parse_desc(value));
 | 
			
		||||
    server.is_full = false;
 | 
			
		||||
    TRY_RESULT(shards_obj, td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false));
 | 
			
		||||
    for (auto &shard : shards_obj.get_array()) {
 | 
			
		||||
      if (shard.type() != td::JsonValue::Type::Object) {
 | 
			
		||||
        return td::Status::Error("Invalid config (5)");
 | 
			
		||||
| 
						 | 
				
			
			@ -122,10 +121,10 @@ td::Result<Config> Config::parse(std::string str) {
 | 
			
		|||
      if (shard_id == 0) {
 | 
			
		||||
        return td::Status::Error("Invalid config (6)");
 | 
			
		||||
      }
 | 
			
		||||
      client.shards.emplace_back(workchain, shard_id);
 | 
			
		||||
      server.shards.emplace_back(workchain, shard_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res.lite_clients.push_back(std::move(client));
 | 
			
		||||
    res.lite_servers.push_back(std::move(server));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TRY_RESULT(validator_obj,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
struct Config {
 | 
			
		||||
  struct LiteClient {
 | 
			
		||||
  struct LiteServer {
 | 
			
		||||
    ton::adnl::AdnlNodeIdFull adnl_id;
 | 
			
		||||
    td::IPAddress address;
 | 
			
		||||
    bool is_full = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ struct Config {
 | 
			
		|||
  ton::BlockIdExt zero_state_id;
 | 
			
		||||
  ton::BlockIdExt init_block_id;
 | 
			
		||||
  std::vector<ton::BlockIdExt> hardforks;
 | 
			
		||||
  std::vector<LiteClient> lite_clients;
 | 
			
		||||
  std::vector<LiteServer> lite_servers;
 | 
			
		||||
  std::string name;
 | 
			
		||||
  static td::Result<Config> parse(std::string str);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
 | 
			
		|||
  td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  auto query_id = queries_.create(std::move(promise));
 | 
			
		||||
  td::Promise<td::BufferSlice> P = [query_id, self = this,
 | 
			
		||||
                                    actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlic
 | 
			
		|||
  if (client_.adnl_ext_client_.empty()) {
 | 
			
		||||
    return P.set_error(TonlibError::NoLiteServers());
 | 
			
		||||
  }
 | 
			
		||||
  td::actor::send_closure(client_.adnl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
 | 
			
		||||
                          td::Timestamp::in(10.0), std::move(P));
 | 
			
		||||
  td::actor::send_closure(client_.adnl_ext_client_, &ExtClientLazy::send_query, "query", std::move(query),
 | 
			
		||||
                          shard, td::Timestamp::in(10.0), std::move(P));
 | 
			
		||||
}
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,6 @@
 | 
			
		|||
#include "TonlibError.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
#include "QueryTraits.h"
 | 
			
		||||
#include "ExtClientRaw.h"
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
class LastBlock;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,14 +19,26 @@
 | 
			
		|||
#include "ExtClientLazy.h"
 | 
			
		||||
#include "TonlibError.h"
 | 
			
		||||
#include "td/utils/Random.h"
 | 
			
		||||
#include "ton/ton-shard.h"
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
 | 
			
		||||
class ExtClientLazyImp : public ExtClientLazy {
 | 
			
		||||
class ExtClientLazyImpl : public ExtClientLazy {
 | 
			
		||||
 public:
 | 
			
		||||
  ExtClientLazyImp(std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers,
 | 
			
		||||
                   td::unique_ptr<ExtClientLazy::Callback> callback)
 | 
			
		||||
      : servers_(std::move(servers)), callback_(std::move(callback)) {
 | 
			
		||||
    CHECK(!servers_.empty());
 | 
			
		||||
  ExtClientLazyImpl(std::vector<Config::LiteServer> servers, td::unique_ptr<ExtClientLazy::Callback> callback)
 | 
			
		||||
      : callback_(std::move(callback)) {
 | 
			
		||||
    CHECK(!servers.empty());
 | 
			
		||||
    servers_.resize(servers.size());
 | 
			
		||||
    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
			
		||||
      servers_[i].s = std::move(servers[i]);
 | 
			
		||||
      if (!servers_[i].s.is_full) {
 | 
			
		||||
        for (auto shard : servers_[i].s.shards) {
 | 
			
		||||
          CHECK(shard.is_valid_ext());
 | 
			
		||||
          max_server_shard_depth_ = std::max(max_server_shard_depth_, shard.pfx_len());
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void start_up() override {
 | 
			
		||||
| 
						 | 
				
			
			@ -34,29 +46,21 @@ class ExtClientLazyImp : public ExtClientLazy {
 | 
			
		|||
    td::random_shuffle(td::as_mutable_span(servers_), rnd);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void check_ready(td::Promise<td::Unit> promise) override {
 | 
			
		||||
    before_query();
 | 
			
		||||
    if (client_.empty()) {
 | 
			
		||||
      return promise.set_error(TonlibError::Cancelled());
 | 
			
		||||
    }
 | 
			
		||||
    send_closure(client_, &ton::adnl::AdnlExtClient::check_ready, std::move(promise));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
 | 
			
		||||
  void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
			
		||||
                  td::Promise<td::BufferSlice> promise) override {
 | 
			
		||||
    before_query();
 | 
			
		||||
    if (client_.empty()) {
 | 
			
		||||
      return promise.set_error(TonlibError::Cancelled());
 | 
			
		||||
    }
 | 
			
		||||
    td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), idx = cur_server_idx_,
 | 
			
		||||
    TRY_RESULT_PROMISE(promise, server_idx, before_query(shard));
 | 
			
		||||
    auto& server = servers_[server_idx];
 | 
			
		||||
    CHECK(!server.client.empty());
 | 
			
		||||
    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
			
		||||
    td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), server_idx,
 | 
			
		||||
                                      promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
      if (R.is_error() &&
 | 
			
		||||
          (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
 | 
			
		||||
        td::actor::send_closure(SelfId, &ExtClientLazyImp::set_server_bad, idx, true);
 | 
			
		||||
        td::actor::send_closure(SelfId, &ExtClientLazyImpl::set_server_bad, server_idx);
 | 
			
		||||
      }
 | 
			
		||||
      promise.set_result(std::move(R));
 | 
			
		||||
    };
 | 
			
		||||
    send_closure(client_, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
 | 
			
		||||
    send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
 | 
			
		||||
                 std::move(P));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,64 +68,124 @@ class ExtClientLazyImp : public ExtClientLazy {
 | 
			
		|||
    if (servers_.size() == 1) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    cur_server_bad_ = cur_server_bad_force_ = true;
 | 
			
		||||
    auto it = shard_to_server_.find(ton::ShardIdFull(ton::masterchainId));
 | 
			
		||||
    if (it != shard_to_server_.end()) {
 | 
			
		||||
      set_server_bad(it->second);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  void before_query() {
 | 
			
		||||
  td::Result<size_t> before_query(ton::ShardIdFull shard) {
 | 
			
		||||
    if (!shard.is_valid_ext()) {
 | 
			
		||||
      return td::Status::Error("Invalid shard");
 | 
			
		||||
    }
 | 
			
		||||
    if (is_closing_) {
 | 
			
		||||
      return;
 | 
			
		||||
      return td::Status::Error("Client is closing");
 | 
			
		||||
    }
 | 
			
		||||
    alarm_timestamp() = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
 | 
			
		||||
    if (cur_server_bad_) {
 | 
			
		||||
      ++cur_server_idx_;
 | 
			
		||||
    } else if (!client_.empty()) {
 | 
			
		||||
      return;
 | 
			
		||||
    if (shard.pfx_len() > max_server_shard_depth_) {
 | 
			
		||||
      shard = shard_prefix(shard, max_server_shard_depth_);
 | 
			
		||||
    }
 | 
			
		||||
    auto it = shard_to_server_.find(shard);
 | 
			
		||||
    if (it != shard_to_server_.end()) {
 | 
			
		||||
      size_t server_idx = it->second;
 | 
			
		||||
      if (!servers_[server_idx].client.empty()) {
 | 
			
		||||
        return server_idx;
 | 
			
		||||
      }
 | 
			
		||||
      shard_to_server_.erase(it);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t server_idx = servers_.size();
 | 
			
		||||
    int cnt = 0;
 | 
			
		||||
    int best_priority = -1;
 | 
			
		||||
    for (size_t i = 0; i < servers_.size(); ++i) {
 | 
			
		||||
      Server& server = servers_[i];
 | 
			
		||||
      if (!server.supports(shard)) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      int priority = 0;
 | 
			
		||||
      priority += (server.client.empty() ? 0 : 100);
 | 
			
		||||
      priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10);
 | 
			
		||||
      priority += (server.s.is_full ? 1 : 0);
 | 
			
		||||
      if (priority < best_priority) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if (priority > best_priority) {
 | 
			
		||||
        best_priority = priority;
 | 
			
		||||
        cnt = 0;
 | 
			
		||||
      }
 | 
			
		||||
      if (td::Random::fast(0, cnt) == 0) {
 | 
			
		||||
        server_idx = i;
 | 
			
		||||
      }
 | 
			
		||||
      ++cnt;
 | 
			
		||||
    }
 | 
			
		||||
    if (server_idx == servers_.size()) {
 | 
			
		||||
      return td::Status::Error(PSTRING() << "No liteserver for shard " << shard.to_str());
 | 
			
		||||
    }
 | 
			
		||||
    Server& server = servers_[server_idx];
 | 
			
		||||
    if (!server.client.empty()) {
 | 
			
		||||
      return server_idx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
			
		||||
     public:
 | 
			
		||||
      explicit Callback(td::actor::ActorShared<ExtClientLazyImp> parent, size_t idx)
 | 
			
		||||
      explicit Callback(td::actor::ActorShared<ExtClientLazyImpl> parent, size_t idx)
 | 
			
		||||
          : parent_(std::move(parent)), idx_(idx) {
 | 
			
		||||
      }
 | 
			
		||||
      void on_ready() override {
 | 
			
		||||
        td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, false);
 | 
			
		||||
      }
 | 
			
		||||
      void on_stop_ready() override {
 | 
			
		||||
        td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, true);
 | 
			
		||||
        td::actor::send_closure(parent_, &ExtClientLazyImpl::set_server_bad, idx_);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
     private:
 | 
			
		||||
      td::actor::ActorShared<ExtClientLazyImp> parent_;
 | 
			
		||||
      td::actor::ActorShared<ExtClientLazyImpl> parent_;
 | 
			
		||||
      size_t idx_;
 | 
			
		||||
    };
 | 
			
		||||
    ref_cnt_++;
 | 
			
		||||
    cur_server_bad_ = false;
 | 
			
		||||
    cur_server_bad_force_ = false;
 | 
			
		||||
    const auto& s = servers_[cur_server_idx_ % servers_.size()];
 | 
			
		||||
    LOG(INFO) << "Connecting to liteserver " << s.second;
 | 
			
		||||
    client_ = ton::adnl::AdnlExtClient::create(
 | 
			
		||||
        s.first, s.second, std::make_unique<Callback>(td::actor::actor_shared(this), cur_server_idx_));
 | 
			
		||||
    if (shard.is_masterchain()) {
 | 
			
		||||
      LOG(INFO) << "Connecting to liteserver " << server.s.address << " for masterchain";
 | 
			
		||||
    } else {
 | 
			
		||||
      LOG(INFO) << "Connecting to liteserver " << server.s.address << " for shard " << shard.to_str();
 | 
			
		||||
    }
 | 
			
		||||
    server.client = ton::adnl::AdnlExtClient::create(
 | 
			
		||||
        server.s.adnl_id, server.s.address, std::make_unique<Callback>(td::actor::actor_shared(this), server_idx));
 | 
			
		||||
    alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
 | 
			
		||||
    return server_idx;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers_;
 | 
			
		||||
  size_t cur_server_idx_ = 0;
 | 
			
		||||
  bool cur_server_bad_ = false;
 | 
			
		||||
  bool cur_server_bad_force_ = false;
 | 
			
		||||
  struct Server {
 | 
			
		||||
    Config::LiteServer s;
 | 
			
		||||
    td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
 | 
			
		||||
    td::Timestamp timeout = td::Timestamp::never();
 | 
			
		||||
    td::Timestamp ignore_until = td::Timestamp::never();
 | 
			
		||||
 | 
			
		||||
    bool supports(const ton::ShardIdFull& shard) const {
 | 
			
		||||
      return s.is_full || shard.is_masterchain() ||
 | 
			
		||||
             std::any_of(s.shards.begin(), s.shards.end(),
 | 
			
		||||
                         [&](const ton::ShardIdFull s_shard) { return ton::shard_intersects(shard, s_shard); });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  std::vector<Server> servers_;
 | 
			
		||||
  std::map<ton::ShardIdFull, size_t> shard_to_server_;
 | 
			
		||||
  int max_server_shard_depth_ = 0;
 | 
			
		||||
 | 
			
		||||
  td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
 | 
			
		||||
  td::unique_ptr<ExtClientLazy::Callback> callback_;
 | 
			
		||||
  static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
 | 
			
		||||
 | 
			
		||||
  bool is_closing_{false};
 | 
			
		||||
  td::uint32 ref_cnt_{1};
 | 
			
		||||
 | 
			
		||||
  void set_server_bad(size_t idx, bool bad) {
 | 
			
		||||
    if (idx == cur_server_idx_ && servers_.size() > 1 && !cur_server_bad_force_) {
 | 
			
		||||
      cur_server_bad_ = bad;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void alarm() override {
 | 
			
		||||
    client_.reset();
 | 
			
		||||
    for (Server& server : servers_) {
 | 
			
		||||
      if (server.timeout && server.timeout.is_in_past()) {
 | 
			
		||||
        server.client.reset();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void set_server_bad(size_t idx) {
 | 
			
		||||
    servers_[idx].client.reset();
 | 
			
		||||
    servers_[idx].timeout = td::Timestamp::never();
 | 
			
		||||
    servers_[idx].ignore_until = td::Timestamp::in(60.0);
 | 
			
		||||
  }
 | 
			
		||||
  void hangup_shared() override {
 | 
			
		||||
    ref_cnt_--;
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +194,9 @@ class ExtClientLazyImp : public ExtClientLazy {
 | 
			
		|||
  void hangup() override {
 | 
			
		||||
    is_closing_ = true;
 | 
			
		||||
    ref_cnt_--;
 | 
			
		||||
    client_.reset();
 | 
			
		||||
    for (Server& server : servers_) {
 | 
			
		||||
      server.client.reset();
 | 
			
		||||
    }
 | 
			
		||||
    try_stop();
 | 
			
		||||
  }
 | 
			
		||||
  void try_stop() {
 | 
			
		||||
| 
						 | 
				
			
			@ -142,11 +208,11 @@ class ExtClientLazyImp : public ExtClientLazy {
 | 
			
		|||
 | 
			
		||||
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
			
		||||
                                                         td::unique_ptr<Callback> callback) {
 | 
			
		||||
  return create({std::make_pair(dst, dst_addr)}, std::move(callback));
 | 
			
		||||
  return create({Config::LiteServer{dst, dst_addr, true, {}}}, std::move(callback));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(
 | 
			
		||||
    std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback) {
 | 
			
		||||
  return td::actor::create_actor<ExtClientLazyImp>("ExtClientLazy", std::move(servers), std::move(callback));
 | 
			
		||||
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(std::vector<Config::LiteServer> servers,
 | 
			
		||||
                                                         td::unique_ptr<Callback> callback) {
 | 
			
		||||
  return td::actor::create_actor<ExtClientLazyImpl>("ExtClientLazy", std::move(servers), std::move(callback));
 | 
			
		||||
}
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,23 +18,27 @@
 | 
			
		|||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "td/actor/actor.h"
 | 
			
		||||
#include "adnl/adnl-ext-client.h"
 | 
			
		||||
#include "ton/ton-types.h"
 | 
			
		||||
#include "adnl/adnl-ext-client.h"
 | 
			
		||||
#include "Config.h"
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
class ExtClientLazy : public ton::adnl::AdnlExtClient {
 | 
			
		||||
class ExtClientLazy : public td::actor::Actor {
 | 
			
		||||
 public:
 | 
			
		||||
  class Callback {
 | 
			
		||||
   public:
 | 
			
		||||
    virtual ~Callback() = default;
 | 
			
		||||
    virtual ~Callback() {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  virtual void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
			
		||||
                          td::Promise<td::BufferSlice> promise) = 0;
 | 
			
		||||
  virtual void force_change_liteserver() = 0;
 | 
			
		||||
 | 
			
		||||
  static td::actor::ActorOwn<ExtClientLazy> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
 | 
			
		||||
                                                   td::unique_ptr<Callback> callback);
 | 
			
		||||
  static td::actor::ActorOwn<ExtClientLazy> create(
 | 
			
		||||
      std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback);
 | 
			
		||||
  static td::actor::ActorOwn<ExtClientLazy> create(std::vector<Config::LiteServer> servers,
 | 
			
		||||
                                                   td::unique_ptr<Callback> callback);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			@ -1,169 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
    This file is part of TON Blockchain Library.
 | 
			
		||||
 | 
			
		||||
    TON Blockchain Library is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    TON Blockchain Library is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
#include "ExtClientMulti.h"
 | 
			
		||||
#include "ton/ton-shard.h"
 | 
			
		||||
#include "td/utils/Random.h"
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
 | 
			
		||||
static const double MAX_NO_QUERIES_TIMEOUT = 120;
 | 
			
		||||
 | 
			
		||||
ExtClientMulti::ExtClientMulti(std::vector<Config::LiteClient> clients, td::unique_ptr<Callback> callback)
 | 
			
		||||
    : callback_(std::move(callback)) {
 | 
			
		||||
  for (auto &desc : clients) {
 | 
			
		||||
    servers_.emplace_back();
 | 
			
		||||
    servers_.back().desc = std::move(desc);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::start_up() {
 | 
			
		||||
  alarm_timestamp() = td::Timestamp::in(60.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
			
		||||
                                td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  if (shard.is_masterchain() && mc_server_idx_ != -1 && !servers_[mc_server_idx_].is_bad()) {
 | 
			
		||||
    send_query_to_server(std::move(name), std::move(data), mc_server_idx_, timeout, std::move(promise));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  auto it = shard_server_idx_cached_.find(shard);
 | 
			
		||||
  if (it != shard_server_idx_cached_.end() && !servers_[it->second].is_bad()) {
 | 
			
		||||
    send_query_to_server(std::move(name), std::move(data), it->second, timeout, std::move(promise));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  int server_idx = -1;
 | 
			
		||||
  int random_idx = -1;
 | 
			
		||||
  int cnt = 0;
 | 
			
		||||
  int best_prefix = -1;
 | 
			
		||||
  for (int i = 0; i < (int)servers_.size(); ++i) {
 | 
			
		||||
    const Server &server = servers_[i];
 | 
			
		||||
    if (server.is_bad()) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    int len = server.desc.is_full ? 65 : server.max_supported_prefix(shard);
 | 
			
		||||
    if (len > best_prefix) {
 | 
			
		||||
      best_prefix = len;
 | 
			
		||||
      server_idx = -1;
 | 
			
		||||
      random_idx = -1;
 | 
			
		||||
      cnt = 0;
 | 
			
		||||
    } else if (len < best_prefix) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    if (!server.client.empty()) {
 | 
			
		||||
      server_idx = i;
 | 
			
		||||
    }
 | 
			
		||||
    if (td::Random::fast(0, cnt) == 0) {
 | 
			
		||||
      random_idx = i;
 | 
			
		||||
    }
 | 
			
		||||
    ++cnt;
 | 
			
		||||
  }
 | 
			
		||||
  if (server_idx == -1) {
 | 
			
		||||
    server_idx = random_idx;
 | 
			
		||||
  }
 | 
			
		||||
  if (server_idx == -1) {
 | 
			
		||||
    promise.set_error(td::Status::Error("failed to select a suitable server"));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (shard.pfx_len() <= ton::max_shard_pfx_len) {
 | 
			
		||||
    shard_server_idx_cached_[shard] = server_idx;
 | 
			
		||||
  }
 | 
			
		||||
  if (shard.is_masterchain() || servers_[server_idx].desc.is_full) {
 | 
			
		||||
    mc_server_idx_ = server_idx;
 | 
			
		||||
  }
 | 
			
		||||
  send_query_to_server(std::move(name), std::move(data), server_idx, timeout, std::move(promise));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::send_query_to_server(std::string name, td::BufferSlice data, int server_idx, td::Timestamp timeout,
 | 
			
		||||
                                          td::Promise<td::BufferSlice> promise) {
 | 
			
		||||
  Server &server = servers_.at(server_idx);
 | 
			
		||||
  if (server.client.empty()) {
 | 
			
		||||
    start_client(server_idx);
 | 
			
		||||
  }
 | 
			
		||||
  server.ttl = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
 | 
			
		||||
  td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), idx = server_idx,
 | 
			
		||||
      promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
 | 
			
		||||
    if (R.is_error() &&
 | 
			
		||||
        (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
 | 
			
		||||
      td::actor::send_closure(SelfId, &ExtClientMulti::set_server_bad, idx);
 | 
			
		||||
    }
 | 
			
		||||
    promise.set_result(std::move(R));
 | 
			
		||||
  };
 | 
			
		||||
  send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
 | 
			
		||||
               std::move(P));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::force_change_liteserver() {
 | 
			
		||||
  if (mc_server_idx_ != -1) {
 | 
			
		||||
    set_server_bad(mc_server_idx_);
 | 
			
		||||
    mc_server_idx_ = -1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::start_client(int server_idx) {
 | 
			
		||||
  class Callback : public ton::adnl::AdnlExtClient::Callback {
 | 
			
		||||
   public:
 | 
			
		||||
    Callback(td::actor::ActorId<ExtClientMulti> parent, int idx) : parent_(std::move(parent)), idx_(idx) {
 | 
			
		||||
    }
 | 
			
		||||
    void on_ready() override {
 | 
			
		||||
    }
 | 
			
		||||
    void on_stop_ready() override {
 | 
			
		||||
      td::actor::send_closure(parent_, &ExtClientMulti::set_server_bad, idx_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   private:
 | 
			
		||||
    td::actor::ActorId<ExtClientMulti> parent_;
 | 
			
		||||
    int idx_;
 | 
			
		||||
  };
 | 
			
		||||
  Server &server = servers_.at(server_idx);
 | 
			
		||||
  server.client = ton::adnl::AdnlExtClient::create(server.desc.adnl_id, server.desc.address,
 | 
			
		||||
                                                   std::make_unique<Callback>(actor_id(this), server_idx));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::alarm() {
 | 
			
		||||
  for (Server& server : servers_) {
 | 
			
		||||
    if (server.ttl && server.ttl.is_in_past()) {
 | 
			
		||||
      server.client.reset();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  alarm_timestamp() = td::Timestamp::in(60.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtClientMulti::set_server_bad(int idx) {
 | 
			
		||||
  Server& server = servers_.at(idx);
 | 
			
		||||
  server.client.reset();
 | 
			
		||||
  server.ttl = td::Timestamp::never();
 | 
			
		||||
  server.ignore_until = td::Timestamp::in(10.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ExtClientMulti::Server::max_supported_prefix(ton::ShardIdFull shard) const {
 | 
			
		||||
  if (desc.is_full || shard.is_masterchain()) {
 | 
			
		||||
    return shard.pfx_len();
 | 
			
		||||
  }
 | 
			
		||||
  int res = -1;
 | 
			
		||||
  for (const ton::ShardIdFull &our_shard : desc.shards) {
 | 
			
		||||
    if (ton::shard_is_ancestor(our_shard, shard)) {
 | 
			
		||||
      return shard.pfx_len();
 | 
			
		||||
    }
 | 
			
		||||
    if (shard.workchain == our_shard.workchain) {
 | 
			
		||||
      int x = std::min({shard.pfx_len(), our_shard.pfx_len(), ton::count_matching_bits(shard.shard, our_shard.shard)});
 | 
			
		||||
      res = std::max(res, x);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			@ -1,61 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
    This file is part of TON Blockchain Library.
 | 
			
		||||
 | 
			
		||||
    TON Blockchain Library is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    TON Blockchain Library is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "td/actor/actor.h"
 | 
			
		||||
#include "adnl/adnl-ext-client.h"
 | 
			
		||||
#include "Config.h"
 | 
			
		||||
#include "ExtClientRaw.h"
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
 | 
			
		||||
class ExtClientMulti : public ExtClientRaw {
 | 
			
		||||
 public:
 | 
			
		||||
  ExtClientMulti(std::vector<Config::LiteClient> clients, td::unique_ptr<Callback> callback);
 | 
			
		||||
 | 
			
		||||
  void start_up() override;
 | 
			
		||||
  void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
			
		||||
                  td::Promise<td::BufferSlice> promise) override;
 | 
			
		||||
  void alarm() override;
 | 
			
		||||
  void force_change_liteserver() override;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  void send_query_to_server(std::string name, td::BufferSlice data, int server_idx, td::Timestamp timeout,
 | 
			
		||||
                            td::Promise<td::BufferSlice> promise);
 | 
			
		||||
  void start_client(int server_idx);
 | 
			
		||||
 | 
			
		||||
  struct Server {
 | 
			
		||||
    Config::LiteClient desc;
 | 
			
		||||
    td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
 | 
			
		||||
    td::Timestamp ttl;
 | 
			
		||||
    td::Timestamp ignore_until = td::Timestamp::never();
 | 
			
		||||
 | 
			
		||||
    int max_supported_prefix(ton::ShardIdFull shard) const;
 | 
			
		||||
    bool is_bad() const {
 | 
			
		||||
      return ignore_until && !ignore_until.is_in_past();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  void set_server_bad(int idx);
 | 
			
		||||
 | 
			
		||||
  td::unique_ptr<Callback> callback_;
 | 
			
		||||
  std::vector<Server> servers_;
 | 
			
		||||
  int mc_server_idx_ = -1;
 | 
			
		||||
  std::map<ton::ShardIdFull, int> shard_server_idx_cached_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			@ -20,11 +20,12 @@
 | 
			
		|||
#include "ExtClientOutbound.h"
 | 
			
		||||
#include "TonlibError.h"
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace tonlib {
 | 
			
		||||
 | 
			
		||||
class ExtClientOutboundImp : public ExtClientOutbound {
 | 
			
		||||
class ExtClientOutboundImpl : public ExtClientOutbound {
 | 
			
		||||
 public:
 | 
			
		||||
  ExtClientOutboundImp(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
 | 
			
		||||
  ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
 | 
			
		||||
| 
						 | 
				
			
			@ -37,9 +38,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
 | 
			
		|||
  void force_change_liteserver() override {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void force_change_liteserver() override {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
 | 
			
		||||
    auto it = queries_.find(id);
 | 
			
		||||
    if (it == queries_.end()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +63,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
td::actor::ActorOwn<ExtClientOutbound> ExtClientOutbound::create(td::unique_ptr<Callback> callback) {
 | 
			
		||||
  return td::actor::create_actor<ExtClientOutboundImp>("ExtClientOutbound", std::move(callback));
 | 
			
		||||
  return td::actor::create_actor<ExtClientOutboundImpl>("ExtClientOutbound", std::move(callback));
 | 
			
		||||
}
 | 
			
		||||
}  // namespace tonlib
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ class ExtClientOutbound : public ExtClientLazy {
 | 
			
		|||
    }
 | 
			
		||||
    virtual void request(td::int64 id, std::string data, ton::ShardIdFull shard) = 0;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  virtual void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0;
 | 
			
		||||
  static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,6 @@
 | 
			
		|||
#include "tonlib/keys/Mnemonic.h"
 | 
			
		||||
#include "tonlib/keys/SimpleEncryption.h"
 | 
			
		||||
#include "tonlib/TonlibError.h"
 | 
			
		||||
#include "tonlib/ExtClientMulti.h"
 | 
			
		||||
 | 
			
		||||
#include "smc-envelope/GenericAccount.h"
 | 
			
		||||
#include "smc-envelope/ManualDns.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -863,7 +862,9 @@ class Query {
 | 
			
		|||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
  td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig, std::shared_ptr<const block::Config>& cfg, vm::Dictionary& libraries) {
 | 
			
		||||
  td::Result<std::pair<Fee, std::vector<Fee>>> estimate_fees(bool ignore_chksig,
 | 
			
		||||
                                                             std::shared_ptr<const block::Config>& cfg,
 | 
			
		||||
                                                             vm::Dictionary& libraries) {
 | 
			
		||||
    // gas fees
 | 
			
		||||
    bool is_masterchain = raw_.source->get_address().workchain == ton::masterchainId;
 | 
			
		||||
    TRY_RESULT(gas_limits_prices, cfg->get_gas_limits_prices(is_masterchain));
 | 
			
		||||
| 
						 | 
				
			
			@ -892,7 +893,8 @@ class Query {
 | 
			
		|||
                                                                        .set_now(raw_.source->get_sync_time())
 | 
			
		||||
                                                                        .set_ignore_chksig(ignore_chksig)
 | 
			
		||||
                                                                        .set_address(raw_.source->get_address())
 | 
			
		||||
                                                                        .set_config(cfg).set_libraries(libraries));
 | 
			
		||||
                                                                        .set_config(cfg)
 | 
			
		||||
                                                                        .set_libraries(libraries));
 | 
			
		||||
    td::int64 fwd_fee = 0;
 | 
			
		||||
    if (res.success) {
 | 
			
		||||
      LOG(DEBUG) << "output actions:\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -962,8 +964,9 @@ td::Result<td::int64> to_balance(td::Ref<vm::CellSlice> balance_ref) {
 | 
			
		|||
 | 
			
		||||
class GetTransactionHistory : public td::actor::Actor {
 | 
			
		||||
 public:
 | 
			
		||||
  GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash, td::int32 count,
 | 
			
		||||
                        td::actor::ActorShared<> parent, td::Promise<block::TransactionList::Info> promise)
 | 
			
		||||
  GetTransactionHistory(ExtClientRef ext_client_ref, block::StdAddress address, ton::LogicalTime lt, ton::Bits256 hash,
 | 
			
		||||
                        td::int32 count, td::actor::ActorShared<> parent,
 | 
			
		||||
                        td::Promise<block::TransactionList::Info> promise)
 | 
			
		||||
      : address_(std::move(address))
 | 
			
		||||
      , lt_(std::move(lt))
 | 
			
		||||
      , hash_(std::move(hash))
 | 
			
		||||
| 
						 | 
				
			
			@ -1671,8 +1674,8 @@ void TonlibClient::init_ext_client() {
 | 
			
		|||
      }
 | 
			
		||||
 | 
			
		||||
      void request(td::int64 id, std::string data, ton::ShardIdFull shard) override {
 | 
			
		||||
        send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff),
 | 
			
		||||
                     std::move(data), shard);
 | 
			
		||||
        send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), std::move(data),
 | 
			
		||||
                     shard);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
     private:
 | 
			
		||||
| 
						 | 
				
			
			@ -1685,34 +1688,17 @@ void TonlibClient::init_ext_client() {
 | 
			
		|||
    ext_client_outbound_ = client.get();
 | 
			
		||||
    raw_client_ = std::move(client);
 | 
			
		||||
  } else {
 | 
			
		||||
    std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers;
 | 
			
		||||
    for (const auto& s : config_.lite_clients) {
 | 
			
		||||
      servers.emplace_back(s.adnl_id, s.address);
 | 
			
		||||
    }
 | 
			
		||||
    class Callback : public ExtClientLazy::Callback {
 | 
			
		||||
     public:
 | 
			
		||||
      explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
     private:
 | 
			
		||||
      td::actor::ActorShared<> parent_;
 | 
			
		||||
    };
 | 
			
		||||
    std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> full_servers;
 | 
			
		||||
    for (const auto& s : config_.lite_clients) {
 | 
			
		||||
      if (s.is_full) {
 | 
			
		||||
        full_servers.emplace_back(s.adnl_id, s.address);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (!full_servers.empty()) {
 | 
			
		||||
      raw_client_ =
 | 
			
		||||
          ExtClientRaw::create(std::move(full_servers), td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
    } else {
 | 
			
		||||
      CHECK(!config_.lite_clients.empty());
 | 
			
		||||
      raw_client_ = td::actor::create_actor<ExtClientMulti>("ExtClientMulti", config_.lite_clients,
 | 
			
		||||
                                                            td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
    }
 | 
			
		||||
    ext_client_outbound_ = {};
 | 
			
		||||
    ref_cnt_++;
 | 
			
		||||
    raw_client_ = ExtClientLazy::create(std::move(servers), td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
    raw_client_ = ExtClientLazy::create(config_.lite_servers, td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2360,7 +2346,7 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
 | 
			
		|||
  TRY_RESULT_PREFIX(new_config, Config::parse(std::move(config->config_)),
 | 
			
		||||
                    TonlibError::InvalidConfig("can't parse config"));
 | 
			
		||||
 | 
			
		||||
  if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) {
 | 
			
		||||
  if (new_config.lite_servers.empty() && !config->use_callbacks_for_network_) {
 | 
			
		||||
    return TonlibError::InvalidConfig("no lite clients");
 | 
			
		||||
  }
 | 
			
		||||
  td::optional<Config> o_master_config;
 | 
			
		||||
| 
						 | 
				
			
			@ -2427,8 +2413,7 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
 | 
			
		|||
  state.vert_seqno = vert_seqno;
 | 
			
		||||
 | 
			
		||||
  bool user_defined_init_block = false;
 | 
			
		||||
  if (new_config.init_block_id.is_valid() &&
 | 
			
		||||
      state.last_key_block_id.id.seqno < new_config.init_block_id.id.seqno) {
 | 
			
		||||
  if (new_config.init_block_id.is_valid() && state.last_key_block_id.id.seqno < new_config.init_block_id.id.seqno) {
 | 
			
		||||
    state.last_key_block_id = new_config.init_block_id;
 | 
			
		||||
    user_defined_init_block = true;
 | 
			
		||||
    LOG(INFO) << "Use init block from USER config: " << new_config.init_block_id.to_str();
 | 
			
		||||
| 
						 | 
				
			
			@ -2524,8 +2509,7 @@ td::Result<std::string> to_std_address(td::Ref<vm::CellSlice> cs) {
 | 
			
		|||
}
 | 
			
		||||
struct ToRawTransactions {
 | 
			
		||||
  explicit ToRawTransactions(td::optional<td::Ed25519::PrivateKey> private_key, bool try_decode_messages = true)
 | 
			
		||||
    : private_key_(std::move(private_key))
 | 
			
		||||
    , try_decode_messages_(try_decode_messages) {
 | 
			
		||||
      : private_key_(std::move(private_key)), try_decode_messages_(try_decode_messages) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  td::optional<td::Ed25519::PrivateKey> private_key_;
 | 
			
		||||
| 
						 | 
				
			
			@ -2588,7 +2572,8 @@ struct ToRawTransactions {
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!data) {
 | 
			
		||||
        data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)), to_bytes(std::move(init_state_cell)));
 | 
			
		||||
        data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)),
 | 
			
		||||
                                                                to_bytes(std::move(init_state_cell)));
 | 
			
		||||
      }
 | 
			
		||||
      return data;
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -2636,7 +2621,8 @@ struct ToRawTransactions {
 | 
			
		|||
        auto created_lt = static_cast<td::int64>(msg_info.created_lt);
 | 
			
		||||
        return tonlib_api::make_object<tonlib_api::raw_message>(
 | 
			
		||||
            tonlib_api::make_object<tonlib_api::accountAddress>(src),
 | 
			
		||||
            tonlib_api::make_object<tonlib_api::accountAddress>(), 0, 0, 0, created_lt, std::move(body_hash), get_data(src));
 | 
			
		||||
            tonlib_api::make_object<tonlib_api::accountAddress>(), 0, 0, 0, created_lt, std::move(body_hash),
 | 
			
		||||
            get_data(src));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2746,8 +2732,7 @@ td::Status TonlibClient::do_request(const tonlib_api::raw_sendMessageReturnHash&
 | 
			
		|||
                                    td::Promise<object_ptr<tonlib_api::raw_extMessageInfo>>&& promise) {
 | 
			
		||||
  TRY_RESULT_PREFIX(body, vm::std_boc_deserialize(request.body_), TonlibError::InvalidBagOfCells("body"));
 | 
			
		||||
  auto hash = body->get_hash().as_slice().str();
 | 
			
		||||
  make_request(int_api::SendMessage{std::move(body)},
 | 
			
		||||
    promise.wrap([hash = std::move(hash)](auto res) {
 | 
			
		||||
  make_request(int_api::SendMessage{std::move(body)}, promise.wrap([hash = std::move(hash)](auto res) {
 | 
			
		||||
    return tonlib_api::make_object<tonlib_api::raw_extMessageInfo>(std::move(hash));
 | 
			
		||||
  }));
 | 
			
		||||
  return td::Status::OK();
 | 
			
		||||
| 
						 | 
				
			
			@ -2875,7 +2860,8 @@ td::Status TonlibClient::do_request(tonlib_api::raw_getTransactionsV2& request,
 | 
			
		|||
  auto actor_id = actor_id_++;
 | 
			
		||||
  actors_[actor_id] = td::actor::create_actor<GetTransactionHistory>(
 | 
			
		||||
      "GetTransactionHistory", client_.get_client(), account_address, lt, hash, count, actor_shared(this, actor_id),
 | 
			
		||||
      promise.wrap([private_key = std::move(private_key), try_decode_messages = request.try_decode_messages_](auto&& x) mutable {
 | 
			
		||||
      promise.wrap(
 | 
			
		||||
          [private_key = std::move(private_key), try_decode_messages = request.try_decode_messages_](auto&& x) mutable {
 | 
			
		||||
            return ToRawTransactions(std::move(private_key), try_decode_messages).to_raw_transactions(std::move(x));
 | 
			
		||||
          }));
 | 
			
		||||
  return td::Status::OK();
 | 
			
		||||
| 
						 | 
				
			
			@ -3044,8 +3030,8 @@ class GenericCreateSendGrams : public TonlibQueryActor {
 | 
			
		|||
 | 
			
		||||
  td::Result<ton::ManualDns::Action> to_dns_action(tonlib_api::dns_Action& action) {
 | 
			
		||||
    using R = td::Result<ton::ManualDns::Action>;
 | 
			
		||||
    return downcast_call2<R>(action,
 | 
			
		||||
                             td::overloaded(
 | 
			
		||||
    return downcast_call2<R>(
 | 
			
		||||
        action, td::overloaded(
 | 
			
		||||
                    [&](tonlib_api::dns_actionDeleteAll& del_all) -> R {
 | 
			
		||||
                      return ton::ManualDns::Action{"", td::Bits256::zero(), {}};
 | 
			
		||||
                    },
 | 
			
		||||
| 
						 | 
				
			
			@ -3061,8 +3047,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
 | 
			
		|||
                      }
 | 
			
		||||
                      TRY_RESULT(entry_data, to_dns_entry_data(*set.entry_->entry_));
 | 
			
		||||
                      TRY_RESULT(data_cell, entry_data.as_cell());
 | 
			
		||||
                                   return ton::ManualDns::Action{set.entry_->name_, set.entry_->category_,
 | 
			
		||||
                                                                 std::move(data_cell)};
 | 
			
		||||
                      return ton::ManualDns::Action{set.entry_->name_, set.entry_->category_, std::move(data_cell)};
 | 
			
		||||
                    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3868,8 +3853,8 @@ td::Result<vm::StackEntry> from_tonlib_api(tonlib_api::tvm_StackEntry& entry) {
 | 
			
		|||
          }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& visited,
 | 
			
		||||
                         vm::Dictionary& libs, td::Ref<vm::Cell> cell, int depth) {
 | 
			
		||||
void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& visited, vm::Dictionary& libs,
 | 
			
		||||
                         td::Ref<vm::Cell> cell, int depth) {
 | 
			
		||||
  if (depth <= 0 || set.size() >= 16 || visited.size() >= 256) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -3919,10 +3904,11 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
 | 
			
		|||
    return td::Status::OK();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(not_cached_hashes)),
 | 
			
		||||
                     promise.wrap([self=this, result_entries = std::move(result_entries)]
 | 
			
		||||
                                  (td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
 | 
			
		||||
    {
 | 
			
		||||
  client_.send_query(
 | 
			
		||||
      ton::lite_api::liteServer_getLibraries(std::move(not_cached_hashes)),
 | 
			
		||||
      promise.wrap(
 | 
			
		||||
          [self = this, result_entries = std::move(result_entries)](
 | 
			
		||||
              td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
 | 
			
		||||
            if (r_libraries.is_error()) {
 | 
			
		||||
              LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3935,7 +3921,8 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
 | 
			
		|||
                    LOG(WARNING) << "hash mismatch for library " << lr->hash_.to_hex();
 | 
			
		||||
                    continue;
 | 
			
		||||
                  }
 | 
			
		||||
            result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lr->hash_, lr->data_.as_slice().str()));
 | 
			
		||||
                  result_entries.push_back(
 | 
			
		||||
                      tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lr->hash_, lr->data_.as_slice().str()));
 | 
			
		||||
                  self->libraries.set_ref(lr->hash_, contents.move_as_ok());
 | 
			
		||||
                  updated = true;
 | 
			
		||||
                  LOG(DEBUG) << "registered library " << lr->hash_.to_hex();
 | 
			
		||||
| 
						 | 
				
			
			@ -3975,8 +3962,8 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
 | 
			
		|||
  args.set_now(it->second->get_sync_time());
 | 
			
		||||
  args.set_address(it->second->get_address());
 | 
			
		||||
 | 
			
		||||
  client_.with_last_config([self = this, smc = std::move(smc), args = std::move(args), promise = std::move(promise)
 | 
			
		||||
  ](td::Result<LastConfigState> r_state) mutable {
 | 
			
		||||
  client_.with_last_config([self = this, smc = std::move(smc), args = std::move(args),
 | 
			
		||||
                            promise = std::move(promise)](td::Result<LastConfigState> r_state) mutable {
 | 
			
		||||
    TRY_RESULT_PROMISE(promise, state, std::move(r_state));
 | 
			
		||||
    args.set_config(state.config);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3988,10 +3975,10 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
 | 
			
		|||
      std::vector<td::Bits256> libraryList{librarySet.begin(), librarySet.end()};
 | 
			
		||||
      if (libraryList.size() > 0) {
 | 
			
		||||
        LOG(DEBUG) << "Requesting found libraries in code (" << libraryList.size() << ")";
 | 
			
		||||
        self->client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(libraryList)),
 | 
			
		||||
                    [self, smc = std::move(smc), args = std::move(args), promise = std::move(promise)]
 | 
			
		||||
                    (td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
 | 
			
		||||
        {
 | 
			
		||||
        self->client_.send_query(
 | 
			
		||||
            ton::lite_api::liteServer_getLibraries(std::move(libraryList)),
 | 
			
		||||
            [self, smc = std::move(smc), args = std::move(args), promise = std::move(promise)](
 | 
			
		||||
                td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
 | 
			
		||||
              if (r_libraries.is_error()) {
 | 
			
		||||
                LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
 | 
			
		||||
              } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -4017,12 +4004,10 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
 | 
			
		|||
              }
 | 
			
		||||
              self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
 | 
			
		||||
            });
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
      } else {
 | 
			
		||||
        self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    } else {
 | 
			
		||||
      self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -4031,7 +4016,6 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
 | 
			
		|||
 | 
			
		||||
void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::SmartContract::Args args,
 | 
			
		||||
                                         td::Promise<object_ptr<tonlib_api::smc_runResult>>&& promise) {
 | 
			
		||||
 | 
			
		||||
  args.set_libraries(libraries);
 | 
			
		||||
 | 
			
		||||
  auto res = smc->run_get_method(args);
 | 
			
		||||
| 
						 | 
				
			
			@ -4046,14 +4030,15 @@ void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::S
 | 
			
		|||
    td::Bits256 hash = res.missing_library;
 | 
			
		||||
    LOG(DEBUG) << "Requesting missing library: " << hash.to_hex();
 | 
			
		||||
    std::vector<td::Bits256> req = {std::move(hash)};
 | 
			
		||||
    client_.send_query(ton::lite_api::liteServer_getLibraries(std::move(req)),
 | 
			
		||||
    client_.send_query(
 | 
			
		||||
        ton::lite_api::liteServer_getLibraries(std::move(req)),
 | 
			
		||||
        [self = this, res = std::move(res), res_stack = std::move(res_stack), hash = std::move(hash),
 | 
			
		||||
                 smc = std::move(smc), args = std::move(args), promise = std::move(promise)]
 | 
			
		||||
                (td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable
 | 
			
		||||
    {
 | 
			
		||||
         smc = std::move(smc), args = std::move(args), promise = std::move(promise)](
 | 
			
		||||
            td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResult>> r_libraries) mutable {
 | 
			
		||||
          if (r_libraries.is_error()) {
 | 
			
		||||
            LOG(WARNING) << "cannot obtain missing library: " << r_libraries.move_as_error().to_string();
 | 
			
		||||
        promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
 | 
			
		||||
            promise.set_value(
 | 
			
		||||
                tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          bool found = false, updated = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -4078,13 +4063,13 @@ void TonlibClient::perform_smc_execution(td::Ref<ton::SmartContract> smc, ton::S
 | 
			
		|||
          }
 | 
			
		||||
          if (!found) {
 | 
			
		||||
            LOG(WARNING) << "cannot obtain library " << hash.to_hex() << ", it may not exist";
 | 
			
		||||
        promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
 | 
			
		||||
            promise.set_value(
 | 
			
		||||
                tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
 | 
			
		||||
          } else {
 | 
			
		||||
            self->perform_smc_execution(std::move(smc), std::move(args), std::move(promise));
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
  } else {
 | 
			
		||||
    promise.set_value(tonlib_api::make_object<tonlib_api::smc_runResult>(res.gas_used, std::move(res_stack), res.code));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4160,9 +4145,8 @@ void TonlibClient::do_dns_request(std::string name, td::Bits256 category, td::in
 | 
			
		|||
                                  td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
 | 
			
		||||
                                  td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
 | 
			
		||||
  auto block_id_copy = block_id.copy();
 | 
			
		||||
  td::Promise<DnsFinishData> new_promise =
 | 
			
		||||
      promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id),
 | 
			
		||||
                           address);
 | 
			
		||||
  td::Promise<DnsFinishData> new_promise = promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name,
 | 
			
		||||
                                                                category, ttl, std::move(block_id), address);
 | 
			
		||||
 | 
			
		||||
  if (0) {
 | 
			
		||||
    make_request(int_api::GetAccountState{address, std::move(block_id_copy), {}},
 | 
			
		||||
| 
						 | 
				
			
			@ -4200,8 +4184,7 @@ td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
 | 
			
		|||
    name += '.';
 | 
			
		||||
  }
 | 
			
		||||
  TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_));
 | 
			
		||||
  do_dns_request(name, request.category_, request.ttl_, std::move(block_id), account_address,
 | 
			
		||||
                 std::move(promise));
 | 
			
		||||
  do_dns_request(name, request.category_, request.ttl_, std::move(block_id), account_address, std::move(promise));
 | 
			
		||||
  return td::Status::OK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4646,8 +4629,8 @@ auto to_tonlib_api(const ton::lite_api::tonNode_zeroStateIdExt& zeroStateId)
 | 
			
		|||
auto to_lite_api(const tonlib_api::ton_blockIdExt& blk) -> td::Result<lite_api_ptr<ton::lite_api::tonNode_blockIdExt>> {
 | 
			
		||||
  TRY_RESULT(root_hash, to_bits256(blk.root_hash_, "blk.root_hash"))
 | 
			
		||||
  TRY_RESULT(file_hash, to_bits256(blk.file_hash_, "blk.file_hash"))
 | 
			
		||||
  return ton::lite_api::make_object<ton::lite_api::tonNode_blockIdExt>(
 | 
			
		||||
      blk.workchain_, blk.shard_, blk.seqno_, root_hash, file_hash);
 | 
			
		||||
  return ton::lite_api::make_object<ton::lite_api::tonNode_blockIdExt>(blk.workchain_, blk.shard_, blk.seqno_,
 | 
			
		||||
                                                                       root_hash, file_hash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Result<ton::BlockIdExt> to_block_id(const tonlib_api::ton_blockIdExt& blk) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4675,7 +4658,8 @@ td::Status TonlibClient::do_request(const tonlib_api::getConfigParam& request,
 | 
			
		|||
                         LOG(ERROR) << "block::Config::extract_from_state failed: " << config.error();
 | 
			
		||||
                       }
 | 
			
		||||
                       tonlib_api::configInfo config_result;
 | 
			
		||||
    config_result.config_ = tonlib_api::make_object<tonlib_api::tvm_cell>(to_bytes(config.move_as_ok()->get_config_param(param)));
 | 
			
		||||
                       config_result.config_ = tonlib_api::make_object<tonlib_api::tvm_cell>(
 | 
			
		||||
                           to_bytes(config.move_as_ok()->get_config_param(param)));
 | 
			
		||||
                       return tonlib_api::make_object<tonlib_api::configInfo>(std::move(config_result));
 | 
			
		||||
                     }));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4728,14 +4712,13 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getShards& request,
 | 
			
		|||
  return td::Status::OK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& request,
 | 
			
		||||
                                    td::Promise<object_ptr<tonlib_api::ton_blockIdExt>>&& promise) {
 | 
			
		||||
  client_.send_query(ton::lite_api::liteServer_lookupBlock(
 | 
			
		||||
                         request.mode_,
 | 
			
		||||
                       ton::lite_api::make_object<ton::lite_api::tonNode_blockId>((*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_),
 | 
			
		||||
                       (td::uint64)(request.lt_),
 | 
			
		||||
                       (td::uint32)(request.utime_)),
 | 
			
		||||
                         ton::lite_api::make_object<ton::lite_api::tonNode_blockId>(
 | 
			
		||||
                             (*request.id_).workchain_, (*request.id_).shard_, (*request.id_).seqno_),
 | 
			
		||||
                         (td::uint64)(request.lt_), (td::uint32)(request.utime_)),
 | 
			
		||||
                     promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& header) {
 | 
			
		||||
                       const auto& id = header->id_;
 | 
			
		||||
                       return to_tonlib_api(*id);
 | 
			
		||||
| 
						 | 
				
			
			@ -4748,8 +4731,8 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& reques
 | 
			
		|||
 | 
			
		||||
auto to_tonlib_api(const ton::lite_api::liteServer_transactionId& txid)
 | 
			
		||||
    -> tonlib_api_ptr<tonlib_api::blocks_shortTxId> {
 | 
			
		||||
  return tonlib_api::make_object<tonlib_api::blocks_shortTxId>(
 | 
			
		||||
      txid.mode_, txid.account_.as_slice().str(), txid.lt_, txid.hash_.as_slice().str());
 | 
			
		||||
  return tonlib_api::make_object<tonlib_api::blocks_shortTxId>(txid.mode_, txid.account_.as_slice().str(), txid.lt_,
 | 
			
		||||
                                                               txid.hash_.as_slice().str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& request,
 | 
			
		||||
| 
						 | 
				
			
			@ -4757,13 +4740,8 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
 | 
			
		|||
  TRY_RESULT(block, to_lite_api(*request.id_))
 | 
			
		||||
  TRY_RESULT(account, to_bits256((*request.after_).account_, "account"));
 | 
			
		||||
  auto after = ton::lite_api::make_object<ton::lite_api::liteServer_transactionId3>(account, (*request.after_).lt_);
 | 
			
		||||
  client_.send_query(ton::lite_api::liteServer_listBlockTransactions(
 | 
			
		||||
                       std::move(block),
 | 
			
		||||
                       request.mode_,
 | 
			
		||||
                       request.count_,
 | 
			
		||||
                       std::move(after),
 | 
			
		||||
                       false,
 | 
			
		||||
                       false),
 | 
			
		||||
  client_.send_query(ton::lite_api::liteServer_listBlockTransactions(std::move(block), request.mode_, request.count_,
 | 
			
		||||
                                                                     std::move(after), false, false),
 | 
			
		||||
                     promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockTransactions>&& bTxes) {
 | 
			
		||||
                       const auto& id = bTxes->id_;
 | 
			
		||||
                       //for (auto id : ids) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4784,9 +4762,8 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
 | 
			
		|||
td::Status TonlibClient::do_request(const tonlib_api::blocks_getBlockHeader& request,
 | 
			
		||||
                                    td::Promise<object_ptr<tonlib_api::blocks_header>>&& promise) {
 | 
			
		||||
  TRY_RESULT(block, to_lite_api(*request.id_))
 | 
			
		||||
  client_.send_query(ton::lite_api::liteServer_getBlockHeader(
 | 
			
		||||
                       std::move(block),
 | 
			
		||||
                       0xffff),
 | 
			
		||||
  client_.send_query(
 | 
			
		||||
      ton::lite_api::liteServer_getBlockHeader(std::move(block), 0xffff),
 | 
			
		||||
      promise.wrap([](lite_api_ptr<ton::lite_api::liteServer_blockHeader>&& hdr) {
 | 
			
		||||
        auto blk_id = ton::create_block_id(hdr->id_);
 | 
			
		||||
        auto R = vm::std_boc_deserialize(std::move(hdr->header_proof_));
 | 
			
		||||
| 
						 | 
				
			
			@ -4890,15 +4867,17 @@ void TonlibClient::load_libs_from_disk() {
 | 
			
		|||
  if (r_dict.is_error()) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  libraries = vm::Dictionary(vm::load_cell_slice(vm::CellBuilder().append_cellslice(vm::load_cell_slice(
 | 
			
		||||
                                                                   r_dict.move_as_ok())).finalize()), 256);
 | 
			
		||||
  libraries = vm::Dictionary(
 | 
			
		||||
      vm::load_cell_slice(vm::CellBuilder().append_cellslice(vm::load_cell_slice(r_dict.move_as_ok())).finalize()),
 | 
			
		||||
      256);
 | 
			
		||||
  // int n = 0; for (auto&& lr : libraries) n++;
 | 
			
		||||
  LOG(DEBUG) << "loaded libraries from disk cache";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TonlibClient::store_libs_to_disk() {  // NB: Dictionary.get_root_cell does not compute_root, and it is protected
 | 
			
		||||
  kv_->set("tonlib.libcache", vm::std_boc_serialize(vm::CellBuilder().append_cellslice(libraries.get_root())
 | 
			
		||||
                                                        .finalize()).move_as_ok().as_slice());
 | 
			
		||||
  kv_->set("tonlib.libcache", vm::std_boc_serialize(vm::CellBuilder().append_cellslice(libraries.get_root()).finalize())
 | 
			
		||||
                                  .move_as_ok()
 | 
			
		||||
                                  .as_slice());
 | 
			
		||||
  // int n = 0; for (auto&& lr : libraries) n++;
 | 
			
		||||
  LOG(DEBUG) << "stored libraries to disk cache";
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@
 | 
			
		|||
#include "tonlib/TonlibClient.h"
 | 
			
		||||
#include "tonlib/TonlibCallback.h"
 | 
			
		||||
 | 
			
		||||
#include "tonlib/ExtClientRaw.h"
 | 
			
		||||
#include "tonlib/ExtClientLazy.h"
 | 
			
		||||
 | 
			
		||||
#include "smc-envelope/ManualDns.h"
 | 
			
		||||
#include "smc-envelope/PaymentChannel.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,6 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include "git.h"
 | 
			
		||||
#include "ExtClientMulti.h"
 | 
			
		||||
 | 
			
		||||
using tonlib_api::make_object;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +223,7 @@ class TonlibCli : public td::actor::Actor {
 | 
			
		|||
 | 
			
		||||
    if (options_.use_callbacks_for_network) {
 | 
			
		||||
      auto config = tonlib::Config::parse(options_.config).move_as_ok();
 | 
			
		||||
      class Callback : public tonlib::ExtClientRaw::Callback {
 | 
			
		||||
      class Callback : public tonlib::ExtClientLazy::Callback {
 | 
			
		||||
       public:
 | 
			
		||||
        explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -232,22 +231,9 @@ class TonlibCli : public td::actor::Actor {
 | 
			
		|||
       private:
 | 
			
		||||
        td::actor::ActorShared<> parent_;
 | 
			
		||||
      };
 | 
			
		||||
      std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> full_servers;
 | 
			
		||||
      int lite_client_id = -1, cnt = 0;
 | 
			
		||||
      for (const auto& s : config.lite_clients) {
 | 
			
		||||
        if (s.is_full) {
 | 
			
		||||
          full_servers.emplace_back(s.adnl_id, s.address);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!full_servers.empty()) {
 | 
			
		||||
        raw_client_ = tonlib::ExtClientRaw::create(std::move(full_servers),
 | 
			
		||||
                                                   td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
      } else {
 | 
			
		||||
        CHECK(!config.lite_clients.empty());
 | 
			
		||||
        raw_client_ = td::actor::create_actor<tonlib::ExtClientMulti>(
 | 
			
		||||
            "ExtClientMulti", config.lite_clients, td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
      }
 | 
			
		||||
      ref_cnt_++;
 | 
			
		||||
      raw_client_ = tonlib::ExtClientLazy::create(config.lite_servers,
 | 
			
		||||
                                                  td::make_unique<Callback>(td::actor::actor_shared()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto config = !options_.config.empty()
 | 
			
		||||
| 
						 | 
				
			
			@ -1544,9 +1530,8 @@ class TonlibCli : public td::actor::Actor {
 | 
			
		|||
          auto update = tonlib_api::move_object_as<tonlib_api::updateSendLiteServerQuery>(std::move(result));
 | 
			
		||||
          CHECK(!raw_client_.empty());
 | 
			
		||||
          snd_bytes_ += update->data_.size();
 | 
			
		||||
          ton::ShardIdFull shard(update->workchain_, update->shard_);
 | 
			
		||||
          send_closure(raw_client_, &tonlib::ExtClientRaw::send_query, "query", td::BufferSlice(update->data_), shard,
 | 
			
		||||
                       td::Timestamp::in(5),
 | 
			
		||||
          send_closure(raw_client_, &tonlib::ExtClientLazy::send_query, "query", td::BufferSlice(update->data_),
 | 
			
		||||
                       ton::ShardIdFull(update->workchain_, update->shard_), td::Timestamp::in(5),
 | 
			
		||||
                       [actor_id = actor_id(this), id = update->id_](td::Result<td::BufferSlice> res) {
 | 
			
		||||
                         send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
 | 
			
		||||
                       });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue