1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00

Update validator config format; partial liteservers and their support in liteclient

This commit is contained in:
SpyCheese 2022-08-08 12:21:15 +03:00
parent a792565afa
commit 51e6885f2c
12 changed files with 657 additions and 363 deletions

View file

@ -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<td::uint16>(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<ton::ton_api::engine_validator_config> Config::tl() const {
ton::tl_object_ptr<ton::ton_api::engine_validator_Config> Config::tl() const {
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Addr>> addrs_vec;
for (auto &x : addrs) {
if (x.second.proxy) {
@ -146,7 +149,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Validator>> val_vec;
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator>> val_vec;
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeMaster>> full_node_masters_vec;
@ -597,14 +600,14 @@ void DhtServer::load_config(td::Promise<td::Unit> 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<ton::ton_api::engine_validator_Config> 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();

View file

@ -91,10 +91,10 @@ struct Config {
td::Result<bool> config_del_control_process(td::int32 port, ton::PublicKeyHash id);
td::Result<bool> config_del_gc(ton::PublicKeyHash key);
ton::tl_object_ptr<ton::ton_api::engine_validator_config> tl() const;
ton::tl_object_ptr<ton::ton_api::engine_validator_Config> 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 {

View file

@ -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 <unistd.h>
#include <fcntl.h>
#endif
#include <iostream>
#include <sstream>
#include "git.h"
using namespace std::literals::string_literals;
@ -77,22 +72,27 @@ 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);
int TestNode::LiteServer::max_common_prefix(ton::ShardIdFull shard) const {
if (shard.is_masterchain()) {
return 0;
}
void on_stop_ready() override {
td::actor::send_closure(id_, &TestNode::conn_closed);
if (is_full) {
return shard.pfx_len();
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
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<TestNode> id_;
};
return std::make_unique<Callback>(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,19 +110,22 @@ 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;
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";
if (gc.validator_ && gc.validator_->zero_state_) {
zstate_id_.workchain = gc.validator_->zero_state_->workchain_;
if (zstate_id_.workchain != ton::workchainInvalid) {
@ -131,10 +134,34 @@ void TestNode::run() {
td::TerminalIO::out() << "zerostate set to " << zstate_id_.to_str() << "\n";
}
}
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));
}
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 +206,156 @@ 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) {
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_++;
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("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<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(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<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 +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<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 +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<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 +505,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 +518,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 +558,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 +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,7 +631,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 +657,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;
@ -1149,8 +1313,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::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<td::BufferSlice> R) {
if (R.is_error()) {
return;
@ -1165,11 +1339,8 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) {
});
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()
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,
@ -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<ton::StdSmcAddress> 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::lite_api::liteServer_getAccountState>(
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<td::BufferSlice> R) {
return envelope_send_query_to_account(
account_prefix, std::move(b),
[Self = actor_id(this), workchain, addr, ref_blkid, filename, mode](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
return;
}
@ -1275,18 +1445,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());
@ -1327,8 +1496,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());
@ -1340,11 +1510,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));
}
});
}
@ -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<std::vector<vm::StackEntry>> R) {
[expires_in, bits, refs, chash, filename](td::Result<std::vector<vm::StackEntry>> 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<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;
}
@ -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<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;
}
@ -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,16 +2582,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;
}
@ -2469,13 +2631,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;
}
@ -2484,8 +2644,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);
}
});
}
@ -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<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;
@ -2593,7 +2746,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));
@ -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::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();
@ -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::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();
@ -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<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 {
@ -2967,8 +3121,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);
@ -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<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 :");
@ -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,7 +3295,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();
@ -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<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;
@ -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<td::BufferSlice> R) mutable {
TRY_RESULT_PROMISE(promise, res, std::move(R));
@ -3483,7 +3632,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;
@ -3878,7 +4027,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");

View file

@ -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<ton::adnl::AdnlExtClient> client_;
td::actor::ActorOwn<td::TerminalIO> io_;
struct LiteServer {
td::IPAddress addr;
ton::PublicKey public_key;
bool is_full = true;
std::vector<ton::ShardIdFull> shards;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
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;
};
std::vector<LiteServer> servers_;
td::int32 single_liteserver_idx_ = -1;
td::IPAddress single_remote_addr_;
ton::PublicKey single_remote_public_key_;
std::map<ton::ShardIdFull, td::int32> 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<ton::BlockIdExt> known_blk_ids_;
std::size_t shown_blk_ids_ = 0;
@ -88,8 +104,6 @@ class TestNode : public td::actor::Actor {
std::map<td::Bits256, Ref<vm::Cell>> cell_cache_;
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback();
using creator_stats_func_t =
std::function<bool(const td::Bits256&, const block::DiscountedCounter&, const block::DiscountedCounter&)>;
@ -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<ton::PublicKey> {
@ -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<ton::PublicKey> {
@ -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<td::BufferSlice> R, td::Promise<td::BufferSlice> promise);
void after_got_result(bool ok);
bool envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query,
td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query,
td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query, td::Promise<td::BufferSlice> 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() {

View file

@ -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;
@ -594,6 +596,15 @@ engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector eng
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
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---

Binary file not shown.

View file

@ -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_ptr<ton_api::tonNode_zeroSt
return ZeroStateIdExt{B->workchain_, B->root_hash_, B->file_hash_};
}
inline ShardIdFull create_shard_id(const tl_object_ptr<ton_api::tonNode_shardId> &s) {
return ShardIdFull{s->workchain_, static_cast<td::uint64>(s->shard_)};
}
inline tl_object_ptr<ton_api::tonNode_shardId> create_tl_shard_id(const ShardIdFull &s) {
return create_tl_object<ton_api::tonNode_shardId>(s.workchain, s.shard);
}
inline tl_object_ptr<ton_api::engine_validator_config_v2> unpack_engine_validator_config(
tl_object_ptr<ton_api::engine_validator_Config> config) {
tl_object_ptr<ton_api::engine_validator_config_v2> res;
ton_api::downcast_call(*config, td::overloaded(
[&](ton_api::engine_validator_config &c) {
res = create_tl_object<ton_api::engine_validator_config_v2>(
c.out_port_, std::move(c.addrs_), std::move(c.adnl_), std::move(c.dht_),
std::move(c.validators_),
std::vector<tl_object_ptr<ton_api::engine_collator>>(), c.fullnode_,
std::move(c.fullnodeslaves_), std::move(c.fullnodemasters_),
std::move(c.liteservers_), std::move(c.control_),
std::vector<tl_object_ptr<ton_api::tonNode_shardId>>(), std::move(c.gc_));
},
[&](ton_api::engine_validator_config_v2 &c) {
res = std::make_unique<ton_api::engine_validator_config_v2>(std::move(c));
}));
return res;
}
} // namespace ton

View file

@ -1101,7 +1101,7 @@ td::Status AddCollatorQuery::run() {
td::Status AddCollatorQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addCollator>(
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<td::int32>());
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
return td::Status::OK();
}
td::Status AddShardQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addShard>(
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<ton::ton_api::engine_validator_success>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "successfully added shard\n";
return td::Status::OK();
}

View file

@ -1187,3 +1187,26 @@ class AddCollatorQuery : public Query {
td::int32 wc_;
td::int64 shard_;
};
class AddShardQuery : public Query {
public:
AddShardQuery(td::actor::ActorId<ValidatorEngineConsole> 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 <workchain> <shard>\tstart monitoring shard";
}
std::string name() const override {
return get_name();
}
private:
td::int32 wc_;
td::int64 shard_;
};

View file

@ -145,6 +145,7 @@ void ValidatorEngineConsole::run() {
add_query_runner(std::make_unique<QueryRunnerImpl<GetRequiredBlockCandidatesQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ImportBlockCandidateQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<AddCollatorQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<AddShardQuery>>());
}
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {

View file

@ -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<td::uint16>(config.out_port_);
if (!out_port) {
@ -87,7 +88,7 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
std::vector<AdnlCategory> categories;
std::vector<AdnlCategory> 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<td::uint16>(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_) {
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_) {
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_);
}
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<ton::ton_api::engine_validator_config> Config::tl() const {
ton::tl_object_ptr<ton::ton_api::engine_validator_config_v2> Config::tl() const {
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Addr>> addrs_vec;
for (auto &x : addrs) {
if (x.second.proxy) {
@ -201,7 +202,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Validator>> val_vec;
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator>> val_vec;
for (auto &val : validators) {
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorTempKey>> temp_vec;
for (auto &t : val.second.temp_keys) {
@ -214,9 +215,10 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator>(
val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_collator>> col_vec;
for (auto &col : collators) {
val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_collator>(
col.adnl_id.tl(), col.shard.workchain, col.shard.shard));
col_vec.push_back(
ton::create_tl_object<ton::ton_api::engine_collator>(col.adnl_id.tl(), ton::create_tl_shard_id(col.shard)));
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
@ -245,14 +247,19 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
std::move(control_proc_vec)));
}
std::vector<ton::tl_object_ptr<ton::ton_api::tonNode_shardId>> 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<ton::ton_api::engine_gc>(std::vector<td::Bits256>{});
for (auto &id : gc) {
gc_vec->ids_.push_back(id.tl());
}
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
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<ton::ton_api::engine_validator_config_v2>(
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<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
@ -527,6 +534,17 @@ td::Result<bool> Config::config_add_control_process(ton::PublicKeyHash key, td::
}
}
td::Result<bool> 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<bool> 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<td::Unit> 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<ton::ton_api::engine_validator_Config> 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<td::BufferSlice> 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<ton::ton_api::engine_validator_success>(), true));
}
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> 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;

View file

@ -96,6 +96,7 @@ struct Config {
std::map<td::int32, ton::PublicKeyHash> liteservers;
std::map<td::int32, Control> controls;
std::set<ton::PublicKeyHash> gc;
std::vector<ton::ShardIdFull> shards_to_monitor;
void decref(ton::PublicKeyHash key);
void incref(ton::PublicKeyHash key) {
@ -121,6 +122,7 @@ struct Config {
td::Result<bool> config_add_control_interface(ton::PublicKeyHash key, td::int32 port);
td::Result<bool> config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id,
td::uint32 permissions);
td::Result<bool> config_add_shard(ton::ShardIdFull shard);
td::Result<bool> config_add_gc(ton::PublicKeyHash key);
td::Result<bool> config_del_network_addr(td::IPAddress addr, std::vector<AdnlCategory> cats,
std::vector<AdnlCategory> prio_cats);
@ -135,10 +137,10 @@ struct Config {
td::Result<bool> config_del_control_process(td::int32 port, ton::PublicKeyHash id);
td::Result<bool> config_del_gc(ton::PublicKeyHash key);
ton::tl_object_ptr<ton::ton_api::engine_validator_config> tl() const;
ton::tl_object_ptr<ton::ton_api::engine_validator_config_v2> 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<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_addCollator &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_addShard &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
template <class T>
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {