diff --git a/dht-server/dht-server.cpp b/dht-server/dht-server.cpp index 24b7b7e3..d1f43953 100644 --- a/dht-server/dht-server.cpp +++ b/dht-server/dht-server.cpp @@ -38,6 +38,9 @@ #include "td/utils/TsFileLog.h" #include "td/utils/Random.h" +#include "ton/ton-tl.hpp" +#include "tl/tl_json.h" + #include "memprof/memprof.h" #if TD_DARWIN || TD_LINUX @@ -54,7 +57,7 @@ Config::Config() { out_port = 3278; } -Config::Config(ton::ton_api::engine_validator_config &config) { +Config::Config(const ton::ton_api::engine_validator_config_v2 &config) { out_port = static_cast(config.out_port_); if (!out_port) { out_port = 3278; @@ -121,7 +124,7 @@ Config::Config(ton::ton_api::engine_validator_config &config) { } } -ton::tl_object_ptr Config::tl() const { +ton::tl_object_ptr Config::tl() const { std::vector> addrs_vec; for (auto &x : addrs) { if (x.second.proxy) { @@ -146,7 +149,7 @@ ton::tl_object_ptr Config::tl() const { dht_vec.push_back(ton::create_tl_object(x.tl())); } - std::vector> val_vec; + std::vector> val_vec; std::vector> full_node_slaves_vec; std::vector> full_node_masters_vec; @@ -597,14 +600,14 @@ void DhtServer::load_config(td::Promise promise) { } auto conf_json = conf_json_R.move_as_ok(); - ton::ton_api::engine_validator_config conf; - auto S = ton::ton_api::from_json(conf, conf_json.get_object()); + ton::tl_object_ptr conf; + auto S = td::from_json(conf, std::move(conf_json)); if (S.is_error()) { promise.set_error(S.move_as_error_prefix("json does not fit TL scheme")); return; } - config_ = Config{conf}; + config_ = Config{*ton::unpack_engine_validator_config(std::move(conf))}; td::MultiPromise mp; auto ig = mp.init_guard(); diff --git a/dht-server/dht-server.hpp b/dht-server/dht-server.hpp index bf24d621..724e7bbf 100644 --- a/dht-server/dht-server.hpp +++ b/dht-server/dht-server.hpp @@ -91,10 +91,10 @@ struct Config { td::Result config_del_control_process(td::int32 port, ton::PublicKeyHash id); td::Result config_del_gc(ton::PublicKeyHash key); - ton::tl_object_ptr tl() const; + ton::tl_object_ptr tl() const; Config(); - Config(ton::ton_api::engine_validator_config &config); + Config(const ton::ton_api::engine_validator_config_v2 &config); }; class DhtServer : public td::actor::Actor { diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp index aad3ae6e..970cdad9 100644 --- a/lite-client/lite-client.cpp +++ b/lite-client/lite-client.cpp @@ -41,8 +41,6 @@ #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" @@ -59,17 +57,14 @@ #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 -#include #endif #include -#include #include "git.h" using namespace std::literals::string_literals; @@ -77,22 +72,27 @@ using td::Ref; int verbosity; -std::unique_ptr 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 id) : id_(std::move(id)) { +int TestNode::LiteServer::max_common_prefix(ton::ShardIdFull shard) const { + if (shard.is_masterchain()) { + return 0; + } + if (is_full) { + return shard.pfx_len(); + } + int res = -1; + for (const ton::ShardIdFull &our_shard : shards) { + 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; +} - private: - td::actor::ActorId id_; - }; - return std::make_unique(actor_id(this)); +bool TestNode::LiteServer::supports_shard(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_is_ancestor(shard, our_shard); }); } void TestNode::run() { @@ -110,31 +110,58 @@ void TestNode::run() { io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique(actor_id(this))); td::actor::send_closure(io_, &td::TerminalIO::set_log_interface); - if (remote_public_key_.empty()) { - 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(gc.liteservers_.size() - 1)); - CHECK(idx >= 0 && static_cast(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"; - if (gc.validator_ && gc.validator_->zero_state_) { - zstate_id_.workchain = gc.validator_->zero_state_->workchain_; - if (zstate_id_.workchain != ton::workchainInvalid) { - zstate_id_.root_hash = gc.validator_->zero_state_->root_hash_; - zstate_id_.file_hash = gc.validator_->zero_state_->file_hash_; - td::TerminalIO::out() << "zerostate set to " << zstate_id_.to_str() << "\n"; - } + 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; + 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); + + if (gc.validator_ && gc.validator_->zero_state_) { + zstate_id_.workchain = gc.validator_->zero_state_->workchain_; + if (zstate_id_.workchain != ton::workchainInvalid) { + zstate_id_.root_hash = gc.validator_->zero_state_->root_hash_; + zstate_id_.file_hash = gc.validator_->zero_state_->file_hash_; + td::TerminalIO::out() << "zerostate set to " << zstate_id_.to_str() << "\n"; } } - client_ = - ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_, make_callback()); + for (auto& server : gc.liteservers_) { + LiteServer s; + ton::ton_api::downcast_call(*server, + td::overloaded( + [&](ton::ton_api::liteserver_desc& obj) { + s.addr.init_host_port(td::IPAddress::ipv4_to_str(obj.ip_), obj.port_).ensure(); + s.public_key = ton::PublicKey{obj.id_}; + }, + [&](ton::ton_api::liteserver_descV2& obj) { + s.addr.init_host_port(td::IPAddress::ipv4_to_str(obj.ip_), obj.port_).ensure(); + s.public_key = ton::PublicKey{obj.id_}; + s.is_full = false; + for (const auto& shard : obj.shards_) { + s.shards.emplace_back(shard->workchain_, shard->shard_); + CHECK(s.shards.back().is_valid_ext()); + } + })); + servers_.push_back(std::move(s)); + } + + 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 R, td::Promise promise) { @@ -179,23 +206,156 @@ void TestNode::after_got_result(bool ok) { } } -bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise promise) { - running_queries_++; - if (!ready_ || client_.empty()) { - got_result(td::Status::Error("failed to send query to server: not ready"), std::move(promise)); +bool TestNode::envelope_send_query_to_any(td::BufferSlice query, td::Promise 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 promise) { + if (single_liteserver_idx_ >= 0) { + return envelope_send_query_to_server(single_liteserver_idx_, std::move(query), std::move(promise)); + } + // TODO: maybe use current shard configuration? + int max_prefix_len = -1; + for (const LiteServer &server : servers_) { + max_prefix_len = std::max(max_prefix_len, server.max_common_prefix(prefix.as_leaf_shard())); + } + max_prefix_len = std::min(max_prefix_len, ton::max_shard_pfx_len); + if (max_prefix_len == -1) { + running_queries_++; + got_result(td::Status::Error("failed to select a suitable server"), std::move(promise)); return false; } + ton::ShardIdFull shard = shard_prefix(prefix.as_leaf_shard(), max_prefix_len); + return envelope_send_query_to_shard(shard, std::move(query), std::move(promise)); +} + +bool TestNode::envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query, + td::Promise 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(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_++; + got_result(td::Status::Error("failed to select a suitable server"), 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 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 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(std::move(query)), true); - td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b), - td::Timestamp::in(10.0), std::move(P)); + 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 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 id, int server_idx) : id_(std::move(id)), server_idx_(server_idx) { + } + + private: + td::actor::ActorId 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(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 TestNode::trivial_promise() { return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result res) { if (res.is_error()) { @@ -310,7 +470,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(), true); - return envelope_send_query(std::move(b), [&, Self = actor_id(this)](td::Result res) -> void { + return envelope_send_query_to_any(std::move(b), [&, Self = actor_id(this)](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot get server time"; return; @@ -319,9 +479,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 +490,13 @@ bool TestNode::get_server_time() { bool TestNode::get_server_version(int mode) { auto b = ton::serialize_tl_object(ton::create_tl_object(), true); - return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result res) { + return envelope_send_query_to_any(std::move(b), [Self = actor_id(this), mode](td::Result res) { td::actor::send_closure_later(Self, &TestNode::got_server_version, std::move(res), mode); }); }; void TestNode::got_server_version(td::Result 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 +505,11 @@ void TestNode::got_server_version(td::Result 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 +518,27 @@ void TestNode::got_server_version(td::Result 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(), true); - return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result res) -> void { + return envelope_send_query_to_any(std::move(b), [Self = actor_id(this)](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot get masterchain info from server"; return; @@ -397,24 +558,25 @@ bool TestNode::get_server_mc_block_id() { } else { auto b = ton::serialize_tl_object(ton::create_tl_object(mode), true); - return envelope_send_query(std::move(b), [Self = actor_id(this), mode](td::Result res) -> void { - if (res.is_error()) { - LOG(ERROR) << "cannot get extended masterchain info from server"; - return; - } else { - auto F = ton::fetch_tl_object(res.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.getMasterchainInfoExt"; - } else { - auto f = F.move_as_ok(); - auto blk_id = create_block_id(f->last_); - auto zstate_id = create_zero_state_id(f->init_); - LOG(INFO) << "last masterchain block is " << blk_id.to_str(); - td::actor::send_closure_later(Self, &TestNode::got_server_mc_block_id_ext, blk_id, zstate_id, mode, - f->version_, f->capabilities_, f->last_utime_, f->now_); - } - } - }); + return envelope_send_query_to_any( + std::move(b), [Self = actor_id(this), mode](td::Result res) -> void { + if (res.is_error()) { + LOG(ERROR) << "cannot get extended masterchain info from server"; + return; + } else { + auto F = ton::fetch_tl_object(res.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.getMasterchainInfoExt"; + } else { + auto f = F.move_as_ok(); + auto blk_id = create_block_id(f->last_); + auto zstate_id = create_zero_state_id(f->init_); + LOG(INFO) << "last masterchain block is " << blk_id.to_str(); + td::actor::send_closure_later(Self, &TestNode::got_server_mc_block_id_ext, blk_id, zstate_id, mode, + f->version_, f->capabilities_, f->last_utime_, f->now_); + } + } + }); } } @@ -448,8 +610,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 +619,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,52 +631,54 @@ 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::create_tl_lite_block_id(blkid)), true); - return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result res) -> void { - if (res.is_error()) { - LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server"; - return; - } else { - auto F = ton::fetch_tl_object(res.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.getBlock"; - } else { - auto f = F.move_as_ok(); - auto blk_id = ton::create_block_id(f->id_); - LOG(INFO) << "obtained block " << blk_id.to_str() << " from server"; - if (blk_id != blkid) { - LOG(ERROR) << "block id mismatch: expected data for block " << blkid.to_str() << ", obtained for " - << blk_id.to_str(); + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result res) -> void { + if (res.is_error()) { + LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server"; + return; + } else { + auto F = ton::fetch_tl_object(res.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.getBlock"; + } else { + auto f = F.move_as_ok(); + auto blk_id = ton::create_block_id(f->id_); + LOG(INFO) << "obtained block " << blk_id.to_str() << " from server"; + if (blk_id != blkid) { + LOG(ERROR) << "block id mismatch: expected data for block " << blkid.to_str() << ", obtained for " + << blk_id.to_str(); + } + td::actor::send_closure_later(Self, &TestNode::got_mc_block, blk_id, std::move(f->data_)); + } } - td::actor::send_closure_later(Self, &TestNode::got_mc_block, blk_id, std::move(f->data_)); - } - } - }); + }); } bool TestNode::request_state(ton::BlockIdExt blkid) { auto b = ton::serialize_tl_object( ton::create_tl_object(ton::create_tl_lite_block_id(blkid)), true); - return envelope_send_query(std::move(b), [Self = actor_id(this), blkid](td::Result res) -> void { - if (res.is_error()) { - LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server"; - return; - } else { - auto F = ton::fetch_tl_object(res.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.getState"; - } else { - auto f = F.move_as_ok(); - auto blk_id = ton::create_block_id(f->id_); - LOG(INFO) << "obtained state " << blk_id.to_str() << " from server"; - if (blk_id != blkid) { - LOG(ERROR) << "block id mismatch: expected state for block " << blkid.to_str() << ", obtained for " - << blk_id.to_str(); + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid](td::Result res) -> void { + if (res.is_error()) { + LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server"; + return; + } else { + auto F = ton::fetch_tl_object(res.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.getState"; + } else { + auto f = F.move_as_ok(); + auto blk_id = ton::create_block_id(f->id_); + LOG(INFO) << "obtained state " << blk_id.to_str() << " from server"; + if (blk_id != blkid) { + LOG(ERROR) << "block id mismatch: expected state for block " << blkid.to_str() << ", obtained for " + << blk_id.to_str(); + } + td::actor::send_closure_later(Self, &TestNode::got_mc_state, blk_id, f->root_hash_, f->file_hash_, + std::move(f->data_)); + } } - td::actor::send_closure_later(Self, &TestNode::got_mc_state, blk_id, f->root_hash_, f->file_hash_, - std::move(f->data_)); - } - } - }); + }); } void TestNode::got_mc_block(ton::BlockIdExt blkid, td::BufferSlice data) { @@ -1149,27 +1313,34 @@ 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; - auto P = td::PromiseCreator::lambda([](td::Result R) { - if (R.is_error()) { - return; - } - auto F = ton::fetch_tl_object(R.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.sendMessage"; - } else { - int status = F.move_as_ok()->status_; - LOG(INFO) << "external message status is " << status; - } - }); - auto b = - ton::serialize_tl_object(ton::create_tl_object(F.move_as_ok()), true); - return envelope_send_query(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"); + 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::t_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 R) { + if (R.is_error()) { + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.sendMessage"; + } else { + int status = F.move_as_ok()->status_; + LOG(INFO) << "external message status is " << status; + } + }); + auto b = + ton::serialize_tl_object(ton::create_tl_object(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"); } bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid, @@ -1177,9 +1348,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](td::Result res) { if (res.is_error()) { @@ -1193,10 +1361,12 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress auto b = ton::serialize_tl_object(ton::create_tl_object( 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 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](td::Result R) { + return envelope_send_query_to_account( + account_prefix, std::move(b), + [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode](td::Result R) { if (R.is_error()) { return; } @@ -1275,19 +1445,18 @@ 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(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::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), - promise = std::move(promise)](td::Result R) mutable { + 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 R) mutable { if (R.is_error()) { promise.set_error(R.move_as_error()); return; @@ -1327,26 +1496,27 @@ 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), - promise = std::move(promise)](td::Result R) mutable { - if (R.is_error()) { - promise.set_error(R.move_as_error()); - return; - } - auto F = ton::fetch_tl_object(R.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod"; - 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)); - } - }); + 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 R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error()); + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod"; + 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)); + } + }); } } @@ -1577,7 +1747,7 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add 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> R) { + [expires_in, bits, refs, chash, filename](td::Result> R) { if (R.is_error()) { LOG(ERROR) << R.move_as_error(); return; @@ -1639,10 +1809,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; @@ -1843,17 +2009,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(workchain, addr); auto b = ton::serialize_tl_object(ton::create_tl_object( 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 R) -> void { + return envelope_send_query_to_account( + account_prefix, std::move(b), + [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result R) -> void { if (R.is_error()) { return; } @@ -1870,16 +2035,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(workchain, addr); auto b = ton::serialize_tl_object( ton::create_tl_object(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 R) { + return envelope_send_query_to_account( + account_prefix, std::move(b), + [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result R) { if (R.is_error()) { return; } @@ -2236,10 +2400,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; } @@ -2418,32 +2582,30 @@ void TestNode::got_last_transactions(std::vector 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(acc_addr, lt); auto b = ton::serialize_tl_object(ton::create_tl_object( 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 R) { - if (R.is_error()) { - return; - } - auto F = ton::fetch_tl_object(R.move_as_ok(), true); - if (F.is_error()) { - LOG(ERROR) << "cannot parse answer to liteServer.listBlockTransactions"; - } else { - auto f = F.move_as_ok(); - std::vector transactions; - for (auto& id : f->ids_) { - transactions.emplace_back(id->account_, id->lt_, id->hash_); - } - td::actor::send_closure_later(Self, &TestNode::got_block_transactions, ton::create_block_id(f->id_), mode, - f->req_count_, f->incomplete_, std::move(transactions), std::move(f->proof_)); - } - }); + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), [Self = actor_id(this), mode](td::Result R) { + if (R.is_error()) { + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + LOG(ERROR) << "cannot parse answer to liteServer.listBlockTransactions"; + } else { + auto f = F.move_as_ok(); + std::vector transactions; + for (auto& id : f->ids_) { + transactions.emplace_back(id->account_, id->lt_, id->hash_); + } + td::actor::send_closure_later(Self, &TestNode::got_block_transactions, ton::create_block_id(f->id_), mode, + f->req_count_, f->incomplete_, std::move(transactions), std::move(f->proof_)); + } + }); } void TestNode::got_block_transactions(ton::BlockIdExt blkid, int mode, unsigned req_count, bool incomplete, @@ -2469,25 +2631,23 @@ 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::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 R) -> void { - if (R.is_error()) { - return; - } - auto F = ton::fetch_tl_object(R.move_as_ok(), true); - if (F.is_error()) { - 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); - } - }); + return envelope_send_query_to_any( + std::move(b), [Self = actor_id(this), filename](td::Result R) -> void { + if (R.is_error()) { + return; + } + auto F = ton::fetch_tl_object(R.move_as_ok(), true); + if (F.is_error()) { + 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); + } + }); } void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data, std::string filename) { @@ -2551,9 +2711,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"); } @@ -2572,10 +2729,6 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, td::Promise promise, int mode, std::string filename, std::vector 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; @@ -2593,11 +2746,12 @@ bool TestNode::get_config_params_ext(ton::BlockIdExt blkid, td::Promise R) mutable { - td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, mode, filename, std::move(params), - std::move(R), std::move(promise)); - }); + 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 R) mutable { + td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, mode, filename, std::move(params), + std::move(R), std::move(promise)); + }); } void TestNode::got_config_params(ton::BlockIdExt req_blkid, int mode, std::string filename, std::vector params, @@ -2785,8 +2939,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::create_tl_lite_block_id(blkid)), true); - return envelope_send_query( - std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot obtain block " << blkid.to_str() << " from server : " << res.move_as_error().to_string(); @@ -2814,8 +2968,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::create_tl_lite_block_id(blkid)), true); - return envelope_send_query( - std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot obtain state " << blkid.to_str() << " from server : " << res.move_as_error().to_string(); @@ -2952,7 +3106,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 R) { + return get_block_header(blkid, mode, [this](td::Result R) { if (R.is_error()) { LOG(ERROR) << "unable to fetch block header: " << R.move_as_error(); } else { @@ -2967,8 +3121,9 @@ bool TestNode::get_block_header(ton::BlockIdExt blkid, int mode, td::Promise(ton::create_tl_lite_block_id(blkid), mode), true); - return envelope_send_query( - std::move(b), [this, blkid, promise = std::move(promise)](td::Result R) mutable -> void { + return envelope_send_query_to_shard( + blkid.shard_full(), std::move(b), + [this, blkid, promise = std::move(promise)](td::Result 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); @@ -2994,8 +3149,8 @@ bool TestNode::lookup_block(ton::ShardIdFull shard, int mode, td::uint64 arg, auto b = ton::serialize_tl_object(ton::create_tl_object( 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 R) mutable -> void { + return envelope_send_query_to_shard( + shard, std::move(b), [this, id, mode, arg, promise = std::move(promise)](td::Result 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 :"); @@ -3109,9 +3264,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(); @@ -3140,14 +3295,15 @@ bool TestNode::get_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mod ton::serialize_tl_object(ton::create_tl_object( 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 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(); - } else { - td::actor::send_closure_later(Self, &TestNode::got_block_proof, from, to, mode, res.move_as_ok()); - } - }); + return envelope_send_query_to_any( + std::move(b), [Self = actor_id(this), from, to, mode](td::Result 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(); + } else { + td::actor::send_closure_later(Self, &TestNode::got_block_proof, from, to, mode, res.move_as_ok()); + } + }); } void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice pchain) { @@ -3201,9 +3357,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"); } @@ -3214,7 +3367,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; @@ -3244,10 +3397,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 state, td::Promise> 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; @@ -3266,7 +3415,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 R) mutable { TRY_RESULT_PROMISE(promise, res, std::move(R)); @@ -3483,7 +3632,7 @@ bool TestNode::load_creator_stats(std::unique_ptr 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; @@ -3878,7 +4027,7 @@ td::Result> 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"); diff --git a/lite-client/lite-client.h b/lite-client/lite-client.h index e62e801c..adfa9a04 100644 --- a/lite-client/lite-client.h +++ b/lite-client/lite-client.h @@ -45,22 +45,41 @@ class TestNode : public td::actor::Actor { min_ls_version = 0x101, min_ls_capabilities = 1 }; // server version >= 1.1, capabilities at least +1 = build proof chains - td::actor::ActorOwn client_; td::actor::ActorOwn io_; + struct LiteServer { + td::IPAddress addr; + ton::PublicKey public_key; + bool is_full = true; + std::vector shards; + + td::actor::ActorOwn client; + bool client_ready = false; + std::vector> wait_client_ready; + + int max_common_prefix(ton::ShardIdFull shard) const; + bool supports_shard(ton::ShardIdFull shard) const; + }; + std::vector servers_; + + td::int32 single_liteserver_idx_ = -1; + td::IPAddress single_remote_addr_; + ton::PublicKey single_remote_public_key_; + + std::map shard_server_idx_cached_; + bool readline_enabled_ = true; - bool server_ok_ = false; - td::int32 liteserver_idx_ = -1; int print_limit_ = 1024; - bool ready_ = false; - bool inited_ = false; std::string db_root_; - int server_time_ = 0; - int server_time_got_at_ = 0; - int server_version_ = 0; - long long server_capabilities_ = 0; + // mc_server is the server for queries to masterchain + int mc_server_idx_ = -1; + int mc_server_time_ = 0; + int mc_server_time_got_at_ = 0; + int mc_server_version_ = 0; + long long mc_server_capabilities_ = 0; + bool mc_server_ok_ = false; ton::ZeroStateIdExt zstate_id_; ton::BlockIdExt mc_last_id_; @@ -75,9 +94,6 @@ class TestNode : public td::actor::Actor { const char *parse_ptr_, *parse_end_; td::Status error_; - td::IPAddress remote_addr_; - ton::PublicKey remote_public_key_; - std::vector known_blk_ids_; std::size_t shown_blk_ids_ = 0; @@ -88,8 +104,6 @@ class TestNode : public td::actor::Actor { std::map> cell_cache_; - std::unique_ptr make_callback(); - using creator_stats_func_t = std::function; @@ -182,8 +196,8 @@ class TestNode : public td::actor::Actor { void got_server_mc_block_id(ton::BlockIdExt blkid, ton::ZeroStateIdExt zstateid, int created_at); void 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); - void set_server_version(td::int32 version, td::int64 capabilities); - void set_server_time(int server_utime); + void set_mc_server_version(td::int32 version, td::int64 capabilities); + void set_mc_server_time(int server_utime); bool request_block(ton::BlockIdExt blkid); bool request_state(ton::BlockIdExt blkid); void got_mc_block(ton::BlockIdExt blkid, td::BufferSlice data); @@ -358,16 +372,6 @@ class TestNode : public td::actor::Actor { static const tlb::TypenameLookup& get_tlb_dict(); public: - void conn_ready() { - LOG(ERROR) << "conn ready"; - ready_ = true; - if (!inited_) { - run_init_queries(); - } - } - void conn_closed() { - ready_ = false; - } void set_global_config(std::string str) { global_config_ = str; } @@ -378,10 +382,10 @@ class TestNode : public td::actor::Actor { readline_enabled_ = value; } void set_liteserver_idx(td::int32 idx) { - liteserver_idx_ = idx; + single_liteserver_idx_ = idx; } void set_remote_addr(td::IPAddress addr) { - remote_addr_ = addr; + single_remote_addr_ = addr; } void set_public_key(td::BufferSlice file_name) { auto R = [&]() -> td::Result { @@ -392,7 +396,7 @@ class TestNode : public td::actor::Actor { if (R.is_error()) { LOG(FATAL) << "bad server public key: " << R.move_as_error(); } - remote_public_key_ = R.move_as_ok(); + single_remote_public_key_ = R.move_as_ok(); } void decode_public_key(td::BufferSlice b64_key) { auto R = [&]() -> td::Result { @@ -404,7 +408,7 @@ class TestNode : public td::actor::Actor { if (R.is_error()) { LOG(FATAL) << "bad b64 server public key: " << R.move_as_error(); } - remote_public_key_ = R.move_as_ok(); + single_remote_public_key_ = R.move_as_ok(); } void set_fail_timeout(td::Timestamp ts) { fail_timeout_ = ts; @@ -439,7 +443,18 @@ class TestNode : public td::actor::Actor { void got_result(td::Result R, td::Promise promise); void after_got_result(bool ok); - bool envelope_send_query(td::BufferSlice query, td::Promise promise); + bool envelope_send_query_to_any(td::BufferSlice query, td::Promise promise); + bool envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query, + td::Promise promise); + bool envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query, + td::Promise promise); + + bool envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query, td::Promise promise); + + void start_client(int server_idx); + void conn_ready(int server_idx); + void conn_closed(int server_idx); + void parse_line(td::BufferSlice data); TestNode() { diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl index f3ac4ee9..187c4952 100644 --- a/tl/generate/scheme/ton_api.tl +++ b/tl/generate/scheme/ton_api.tl @@ -364,6 +364,7 @@ tonNode.blockSignature who:int256 signature:bytes = tonNode.BlockSignature; tonNode.blockId workchain:int shard:long seqno:int = tonNode.BlockId; tonNode.blockIdExt workchain:int shard:long seqno:int root_hash:int256 file_hash:int256 = tonNode.BlockIdExt; tonNode.zeroStateIdExt workchain:int root_hash:int256 file_hash:int256 = tonNode.ZeroStateIdExt; +tonNode.shardId workchain:int shard:long = tonNode.ShardId; tonNode.blockDescriptionEmpty = tonNode.BlockDescription; tonNode.blockDescription id:tonNode.blockIdExt = tonNode.BlockDescription; @@ -568,7 +569,8 @@ validator.config.global zero_state:tonNode.blockIdExt init_block:tonNode.blockId config.global adnl:adnl.config.global dht:dht.config.global validator:validator.config.global = config.Global; liteserver.desc id:PublicKey ip:int port:int = liteserver.Desc; -liteclient.config.global liteservers:(vector liteserver.desc) validator:validator.config.global = liteclient.config.Global; +liteserver.descV2 id:PublicKey ip:int port:int shards:(vector tonNode.shardId) = liteserver.Desc; +liteclient.config.global liteservers:(vector liteserver.Desc) validator:validator.config.global = liteclient.config.Global; engine.adnl id:int256 category:int = engine.Adnl; engine.addr ip:int port:int categories:(vector int) priority_categories:(vector int) = engine.Addr; @@ -578,7 +580,7 @@ engine.dht id:int256 = engine.Dht; engine.validatorTempKey key:int256 expire_at:int = engine.ValidatorTempKey; engine.validatorAdnlAddress id:int256 expire_at:int = engine.ValidatorAdnlAddress; engine.validator id:int256 temp_keys:(vector engine.validatorTempKey) adnl_addrs:(vector engine.validatorAdnlAddress) election_date:int expire_at:int = engine.Validator; -engine.collator adnl_id:int256 workchain:int shard:long = engine.Validator; +engine.collator adnl_id:int256 shard:tonNode.shardId = engine.Collator; engine.liteServer id:int256 port:int = engine.LiteServer; engine.controlProcess id:int256 permissions:int = engine.ControlProcess; engine.controlInterface id:int256 port:int allowed:(vector engine.controlProcess) = engine.ControlInterface; @@ -592,7 +594,16 @@ engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector eng validators:(vector engine.Validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave) fullnodemasters:(vector engine.validator.fullNodeMaster) liteservers:(vector engine.liteServer) control:(vector engine.controlInterface) - gc:engine.gc = engine.validator.Config; + gc:engine.gc = engine.validator.Config; + +engine.validator.config_v2 out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) + dht:(vector engine.dht) + validators:(vector engine.validator) collators:(vector engine.collator) + fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave) + fullnodemasters:(vector engine.validator.fullNodeMaster) + liteservers:(vector engine.liteServer) control:(vector engine.controlInterface) + shards_to_monitor:(vector tonNode.shardId) + gc:engine.gc = engine.validator.Config; ---functions--- ---types--- @@ -697,7 +708,8 @@ engine.validator.generateBlockCandidate block_id:tonNode.BlockId = db.Candidate; engine.validator.getRequiredBlockCandidates = engine.validator.RequiredBlockCandidates; engine.validator.importBlockCandidate block:db.candidate = engine.validator.Success; -engine.validator.addCollator adnl_id:int256 workchain:int shard:long = engine.validator.Success; +engine.validator.addCollator adnl_id:int256 shard:tonNode.shardId = engine.validator.Success; +engine.validator.addShard shard:tonNode.shardId = engine.validator.Success; ---types--- diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo index 2960fa72..2bb8d64c 100644 Binary files a/tl/generate/scheme/ton_api.tlo and b/tl/generate/scheme/ton_api.tlo differ diff --git a/ton/ton-tl.hpp b/ton/ton-tl.hpp index 6d676ea8..f6bda4d9 100644 --- a/ton/ton-tl.hpp +++ b/ton/ton-tl.hpp @@ -19,7 +19,8 @@ #pragma once #include "ton-types.h" -#include "auto/tl/ton_api.h" +#include "auto/tl/ton_api.hpp" +#include "td/utils/overloaded.h" namespace ton { @@ -53,4 +54,31 @@ inline ZeroStateIdExt create_zero_state_id(tl_object_ptrworkchain_, B->root_hash_, B->file_hash_}; } +inline ShardIdFull create_shard_id(const tl_object_ptr &s) { + return ShardIdFull{s->workchain_, static_cast(s->shard_)}; +} + +inline tl_object_ptr create_tl_shard_id(const ShardIdFull &s) { + return create_tl_object(s.workchain, s.shard); +} + +inline tl_object_ptr unpack_engine_validator_config( + tl_object_ptr config) { + tl_object_ptr res; + ton_api::downcast_call(*config, td::overloaded( + [&](ton_api::engine_validator_config &c) { + res = create_tl_object( + c.out_port_, std::move(c.addrs_), std::move(c.adnl_), std::move(c.dht_), + std::move(c.validators_), + std::vector>(), c.fullnode_, + std::move(c.fullnodeslaves_), std::move(c.fullnodemasters_), + std::move(c.liteservers_), std::move(c.control_), + std::vector>(), std::move(c.gc_)); + }, + [&](ton_api::engine_validator_config_v2 &c) { + res = std::make_unique(std::move(c)); + })); + return res; +} + } // namespace ton diff --git a/validator-engine-console/validator-engine-console-query.cpp b/validator-engine-console/validator-engine-console-query.cpp index 9c5b6572..d1bc8d5c 100644 --- a/validator-engine-console/validator-engine-console-query.cpp +++ b/validator-engine-console/validator-engine-console-query.cpp @@ -1101,7 +1101,7 @@ td::Status AddCollatorQuery::run() { td::Status AddCollatorQuery::send() { auto b = ton::create_serialize_tl_object( - adnl_id_.tl(), wc_, shard_); + adnl_id_.tl(), ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_))); td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise()); return td::Status::OK(); } @@ -1112,3 +1112,23 @@ td::Status AddCollatorQuery::receive(td::BufferSlice data) { td::TerminalIO::out() << "successfully added collator\n"; return td::Status::OK(); } + +td::Status AddShardQuery::run() { + TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token()); + TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token()); + return td::Status::OK(); +} + +td::Status AddShardQuery::send() { + auto b = ton::create_serialize_tl_object( + ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_))); + td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise()); + return td::Status::OK(); +} + +td::Status AddShardQuery::receive(td::BufferSlice data) { + TRY_RESULT_PREFIX(f, ton::fetch_tl_object(data.as_slice(), true), + "received incorrect answer: "); + td::TerminalIO::out() << "successfully added shard\n"; + return td::Status::OK(); +} diff --git a/validator-engine-console/validator-engine-console-query.h b/validator-engine-console/validator-engine-console-query.h index 34b2ede3..daa19ab1 100644 --- a/validator-engine-console/validator-engine-console-query.h +++ b/validator-engine-console/validator-engine-console-query.h @@ -1187,3 +1187,26 @@ class AddCollatorQuery : public Query { td::int32 wc_; td::int64 shard_; }; + +class AddShardQuery : public Query { + public: + AddShardQuery(td::actor::ActorId console, Tokenizer tokenizer) + : Query(console, std::move(tokenizer)) { + } + td::Status run() override; + td::Status send() override; + td::Status receive(td::BufferSlice data) override; + static std::string get_name() { + return "addshard"; + } + static std::string get_help() { + return "addshard \tstart monitoring shard"; + } + std::string name() const override { + return get_name(); + } + + private: + td::int32 wc_; + td::int64 shard_; +}; diff --git a/validator-engine-console/validator-engine-console.cpp b/validator-engine-console/validator-engine-console.cpp index d70e2cf2..83375b20 100644 --- a/validator-engine-console/validator-engine-console.cpp +++ b/validator-engine-console/validator-engine-console.cpp @@ -145,6 +145,7 @@ void ValidatorEngineConsole::run() { add_query_runner(std::make_unique>()); add_query_runner(std::make_unique>()); add_query_runner(std::make_unique>()); + add_query_runner(std::make_unique>()); } bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise promise) { diff --git a/validator-engine/validator-engine.cpp b/validator-engine/validator-engine.cpp index b2617769..fda610af 100644 --- a/validator-engine/validator-engine.cpp +++ b/validator-engine/validator-engine.cpp @@ -54,6 +54,7 @@ #include "td/utils/Random.h" #include "auto/tl/lite_api.h" +#include "tl/tl_json.h" #include "memprof/memprof.h" @@ -74,7 +75,7 @@ Config::Config() { full_node = ton::PublicKeyHash::zero(); } -Config::Config(ton::ton_api::engine_validator_config &config) { +Config::Config(const ton::ton_api::engine_validator_config_v2 &config) { full_node = ton::PublicKeyHash::zero(); out_port = static_cast(config.out_port_); if (!out_port) { @@ -87,7 +88,7 @@ Config::Config(ton::ton_api::engine_validator_config &config) { std::vector categories; std::vector priority_categories; ton::ton_api::downcast_call( - *addr.get(), + *addr, td::overloaded( [&](const ton::ton_api::engine_addr &obj) { in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast(obj.port_)).ensure(); @@ -125,24 +126,20 @@ Config::Config(ton::ton_api::engine_validator_config &config) { for (auto &dht : config.dht_) { config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure(); } - for (auto &v : config.validators_) { - ton::ton_api::downcast_call( - *v, td::overloaded( - [&](ton::ton_api::engine_validator &val) { - auto key = ton::PublicKeyHash{val.id_}; - config_add_validator_permanent_key(key, val.election_date_, val.expire_at_).ensure(); - for (auto &temp : val.temp_keys_) { - config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure(); - } - for (auto &adnl : val.adnl_addrs_) { - config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure(); - } - }, - [&](ton::ton_api::engine_collator &col) { - auto key = ton::PublicKeyHash{col.adnl_id_}; - ton::ShardIdFull shard(col.workchain_, col.shard_); - config_add_collator(key, shard).ensure(); - })); + for (auto &val : config.validators_) { + auto key = ton::PublicKeyHash{val->id_}; + config_add_validator_permanent_key(key, val->election_date_, val->expire_at_).ensure(); + for (auto &temp : val->temp_keys_) { + config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure(); + } + for (auto &adnl : val->adnl_addrs_) { + config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure(); + } + } + for (auto &col : config.collators_) { + auto key = ton::PublicKeyHash{col->adnl_id_}; + ton::ShardIdFull shard = ton::create_shard_id(col->shard_); + config_add_collator(key, shard).ensure(); } config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure(); @@ -169,6 +166,10 @@ Config::Config(ton::ton_api::engine_validator_config &config) { } } + for (auto &shard : config.shards_to_monitor_) { + config_add_shard(ton::create_shard_id(shard)).ensure(); + } + if (config.gc_) { for (auto &gc : config.gc_->ids_) { config_add_gc(ton::PublicKeyHash{gc}).ensure(); @@ -176,7 +177,7 @@ Config::Config(ton::ton_api::engine_validator_config &config) { } } -ton::tl_object_ptr Config::tl() const { +ton::tl_object_ptr Config::tl() const { std::vector> addrs_vec; for (auto &x : addrs) { if (x.second.proxy) { @@ -201,7 +202,7 @@ ton::tl_object_ptr Config::tl() const { dht_vec.push_back(ton::create_tl_object(x.tl())); } - std::vector> val_vec; + std::vector> val_vec; for (auto &val : validators) { std::vector> temp_vec; for (auto &t : val.second.temp_keys) { @@ -214,9 +215,10 @@ ton::tl_object_ptr Config::tl() const { val_vec.push_back(ton::create_tl_object( val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at)); } + std::vector> col_vec; for (auto &col : collators) { - val_vec.push_back(ton::create_tl_object( - col.adnl_id.tl(), col.shard.workchain, col.shard.shard)); + col_vec.push_back( + ton::create_tl_object(col.adnl_id.tl(), ton::create_tl_shard_id(col.shard))); } std::vector> full_node_slaves_vec; @@ -245,14 +247,19 @@ ton::tl_object_ptr Config::tl() const { std::move(control_proc_vec))); } + std::vector> shards_vec; + for (auto &shard : shards_to_monitor) { + shards_vec.push_back(ton::create_tl_shard_id(shard)); + } + auto gc_vec = ton::create_tl_object(std::vector{}); for (auto &id : gc) { gc_vec->ids_.push_back(id.tl()); } - return ton::create_tl_object( - out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), full_node.tl(), - std::move(full_node_slaves_vec), std::move(full_node_masters_vec), std::move(liteserver_vec), - std::move(control_vec), std::move(gc_vec)); + return ton::create_tl_object( + out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), std::move(col_vec), + full_node.tl(), std::move(full_node_slaves_vec), std::move(full_node_masters_vec), std::move(liteserver_vec), + std::move(control_vec), std::move(shards_vec), std::move(gc_vec)); } td::Result Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip, @@ -527,6 +534,17 @@ td::Result Config::config_add_control_process(ton::PublicKeyHash key, td:: } } +td::Result Config::config_add_shard(ton::ShardIdFull shard) { + if (!shard.is_valid_ext()) { + return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str()); + } + if (std::find(shards_to_monitor.begin(), shards_to_monitor.end(), shard) != shards_to_monitor.end()) { + return false; + } + shards_to_monitor.push_back(shard); + return true; +} + td::Result Config::config_add_gc(ton::PublicKeyHash key) { return gc.insert(key).second; } @@ -1393,6 +1411,11 @@ void ValidatorEngine::init_validator_options() { for (const auto& c : config_.collators) { shards.push_back(c.shard); } + for (const auto& s : config_.shards_to_monitor) { + shards.push_back(s); + } + std::sort(shards.begin(), shards.end()); + shards.erase(std::unique(shards.begin(), shards.end()), shards.end()); validator_options_.write().set_shard_check_function( [shards = std::move(shards)](ton::ShardIdFull shard, ton::CatchainSeqno cc_seqno, ton::validator::ValidatorManagerOptions::ShardCheckMode mode) -> bool { @@ -1643,14 +1666,14 @@ void ValidatorEngine::load_config(td::Promise promise) { } auto conf_json = conf_json_R.move_as_ok(); - ton::ton_api::engine_validator_config conf; - auto S = ton::ton_api::from_json(conf, conf_json.get_object()); + ton::tl_object_ptr conf; + auto S = td::from_json(conf, std::move(conf_json)); if (S.is_error()) { promise.set_error(S.move_as_error_prefix("json does not fit TL scheme")); return; } - config_ = Config{conf}; + config_ = Config{*ton::unpack_engine_validator_config(std::move(conf))}; td::MultiPromise mp; auto ig = mp.init_guard(); @@ -3471,15 +3494,10 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollat } auto id = ton::PublicKeyHash{query.adnl_id_}; - auto shard = ton::ShardIdFull(query.workchain_, query.shard_); - if (!shard.is_valid_ext()) { - promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "invalid shard"))); - return; - } - + auto shard = ton::create_shard_id(query.shard_); auto R = config_.config_add_collator(id, shard); if (R.is_error()) { - promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized"))); + promise.set_value(create_control_query_error(R.move_as_error())); return; } if (!R.move_as_ok()) { @@ -3499,6 +3517,27 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollat }); } +void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addShard &query, + td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, + td::Promise promise) { + if (!(perm & ValidatorEnginePermissions::vep_modify)) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized"))); + return; + } + if (!started_) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started"))); + return; + } + + auto shard = ton::create_shard_id(query.shard_); + auto R = config_.config_add_shard(shard); + if (R.is_error()) { + promise.set_value(create_control_query_error(R.move_as_error())); + return; + } + promise.set_value(ton::serialize_tl_object(ton::create_tl_object(), true)); +} + void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data, td::Promise promise) { @@ -3532,7 +3571,7 @@ void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNode } auto f = F.move_as_ok(); - ton::ton_api::downcast_call(*f.get(), [&](auto &obj) { + ton::ton_api::downcast_call(*f, [&](auto &obj) { run_control_query(obj, std::move(data), src.pubkey_hash(), it->second, std::move(promise)); }); } @@ -3752,7 +3791,7 @@ int main(int argc, char *argv[]) { }); return td::Status::OK(); }); - p.add_option('M', "masterchain-only", "don't track shardchains", [&]() { + p.add_option('M', "not-all-shards", "monitor only a necessary set of shards instead of all", [&]() { acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_masterchain_only); }); }); td::uint32 threads = 7; diff --git a/validator-engine/validator-engine.hpp b/validator-engine/validator-engine.hpp index bf47e2d7..46de7e86 100644 --- a/validator-engine/validator-engine.hpp +++ b/validator-engine/validator-engine.hpp @@ -96,6 +96,7 @@ struct Config { std::map liteservers; std::map controls; std::set gc; + std::vector shards_to_monitor; void decref(ton::PublicKeyHash key); void incref(ton::PublicKeyHash key) { @@ -121,6 +122,7 @@ struct Config { td::Result config_add_control_interface(ton::PublicKeyHash key, td::int32 port); td::Result config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id, td::uint32 permissions); + td::Result config_add_shard(ton::ShardIdFull shard); td::Result config_add_gc(ton::PublicKeyHash key); td::Result config_del_network_addr(td::IPAddress addr, std::vector cats, std::vector prio_cats); @@ -135,10 +137,10 @@ struct Config { td::Result config_del_control_process(td::int32 port, ton::PublicKeyHash id); td::Result config_del_gc(ton::PublicKeyHash key); - ton::tl_object_ptr tl() const; + ton::tl_object_ptr tl() const; Config(); - Config(ton::ton_api::engine_validator_config &config); + Config(const ton::ton_api::engine_validator_config_v2 &config); }; class ValidatorEngine : public td::actor::Actor { @@ -434,6 +436,8 @@ class ValidatorEngine : public td::actor::Actor { ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); void run_control_query(ton::ton_api::engine_validator_addCollator &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); + void run_control_query(ton::ton_api::engine_validator_addShard &query, td::BufferSlice data, + ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); template void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, td::Promise promise) {