diff --git a/blockchain-explorer/blockchain-explorer-query.cpp b/blockchain-explorer/blockchain-explorer-query.cpp index 920ae2c7..1808a3c4 100644 --- a/blockchain-explorer/blockchain-explorer-query.cpp +++ b/blockchain-explorer/blockchain-explorer-query.cpp @@ -43,7 +43,6 @@ #include "block/block-auto.h" #include "crypto/vm/utils.h" #include "td/utils/crypto.h" -#include "lite-client/QueryTraits.h" #include "vm/boc.h" #include "vm/cellops.h" @@ -212,7 +211,8 @@ void HttpQueryBlockData::finish_query() { } void HttpQueryBlockData::start_up() { - auto query = ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)); + auto query = ton::serialize_tl_object( + ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)), true); auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { @@ -223,7 +223,7 @@ void HttpQueryBlockData::start_up() { }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryBlockData::got_block_data(td::BufferSlice data) { @@ -274,7 +274,8 @@ void HttpQueryBlockView::finish_query() { } void HttpQueryBlockView::start_up_query() { - auto query = ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)); + auto query = ton::serialize_tl_object( + ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)), true); auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { @@ -285,7 +286,7 @@ void HttpQueryBlockView::start_up_query() { }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryBlockView::got_block_data(td::BufferSlice data) { @@ -321,10 +322,11 @@ void HttpQueryBlockInfo::start_up_query() { td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_block_header, R.move_as_ok()); } }); - auto query = - ton::create_tl_object(ton::create_tl_lite_block_id(block_id_), 0); + auto query = ton::serialize_tl_object( + ton::create_tl_object(ton::create_tl_lite_block_id(block_id_), 0), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); pending_queries_ = 1; if (block_id_.is_masterchain()) { @@ -336,15 +338,16 @@ void HttpQueryBlockInfo::start_up_query() { td::actor::send_closure(SelfId, &HttpQueryBlockInfo::got_shard_info, R.move_as_ok()); } }); - auto query_2 = - ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)); + auto query_2 = ton::serialize_tl_object( + ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2), - std::move(P_2)); + std::move(query_2), std::move(P_2)); pending_queries_++; } - auto query_3 = ton::create_tl_object( - ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false); + auto query_3 = ton::serialize_tl_object(ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false), + true); auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: ")); @@ -353,8 +356,7 @@ void HttpQueryBlockInfo::start_up_query() { } }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), - std::move(P_3)); + std::move(query_3), std::move(P_3)); pending_queries_++; } @@ -407,9 +409,11 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) { if (f->incomplete_ && transactions_.size() > 0) { const auto &T = *transactions_.rbegin(); - auto query_3 = ton::create_tl_object( - ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, - ton::create_tl_object(T.addr.addr, T.lt), false, false); + auto query_3 = ton::serialize_tl_object( + ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, + ton::create_tl_object(T.addr.addr, T.lt), false, false), + true); auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &HttpQueryBlockInfo::abort_query, R.move_as_error_prefix("litequery failed: ")); @@ -418,8 +422,7 @@ void HttpQueryBlockInfo::got_transactions(td::BufferSlice data) { } }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), - std::move(P_3)); + std::move(query_3), std::move(P_3)); } else { if (!--pending_queries_) { finish_query(); @@ -539,13 +542,14 @@ void HttpQueryBlockSearch::start_up_query() { td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_block_header, R.move_as_ok()); } }); - auto query = ton::create_tl_object( - mode_, - ton::create_tl_lite_block_id_simple( - ton::BlockId{account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}), - lt_, utime_); + auto query = ton::serialize_tl_object(ton::create_tl_object( + mode_, + ton::create_tl_lite_block_id_simple(ton::BlockId{ + account_prefix_.workchain, account_prefix_.account_id_prefix, seqno_}), + lt_, utime_), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { @@ -567,16 +571,17 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { td::actor::send_closure(SelfId, &HttpQueryBlockSearch::got_shard_info, R.move_as_ok()); } }); - auto query_2 = - ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)); + auto query_2 = ton::serialize_tl_object( + ton::create_tl_object(ton::create_tl_lite_block_id(block_id_)), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_2, true), liteclient::get_query_shard(*query_2), - std::move(P_2)); + std::move(query_2), std::move(P_2)); pending_queries_++; } - auto query_3 = ton::create_tl_object( - ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false); + auto query_3 = ton::serialize_tl_object(ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), 7, 1024, nullptr, false, false), + true); auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, R.move_as_error_prefix("litequery failed: ")); @@ -585,8 +590,7 @@ void HttpQueryBlockSearch::got_block_header(td::BufferSlice data) { } }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), - std::move(P_3)); + std::move(query_3), std::move(P_3)); pending_queries_++; } @@ -626,9 +630,11 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) { if (f->incomplete_ && transactions_.size() > 0) { const auto &T = *transactions_.rbegin(); - auto query_3 = ton::create_tl_object( - ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, - ton::create_tl_object(T.addr.addr, T.lt), false, false); + auto query_3 = ton::serialize_tl_object( + ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024, + ton::create_tl_object(T.addr.addr, T.lt), false, false), + true); auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &HttpQueryBlockSearch::abort_query, @@ -638,8 +644,7 @@ void HttpQueryBlockSearch::got_transactions(td::BufferSlice data) { } }); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query_3, true), liteclient::get_query_shard(*query_3), - std::move(P_3)); + std::move(query_3), std::move(P_3)); } else { if (!--pending_queries_) { finish_query(); @@ -727,10 +732,11 @@ void HttpQueryViewAccount::start_up_query() { } }); auto a = ton::create_tl_object(addr_.workchain, addr_.addr); - auto query = ton::create_tl_object(ton::create_tl_lite_block_id(block_id_), - std::move(a)); + auto query = ton::serialize_tl_object(ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), std::move(a)), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryViewAccount::got_account(td::BufferSlice data) { @@ -823,9 +829,10 @@ void HttpQueryViewTransaction::start_up_query() { } }); auto a = ton::create_tl_object(addr_.workchain, addr_.addr); - auto query = ton::create_tl_object(1, std::move(a), lt_, hash_); + auto query = ton::serialize_tl_object( + ton::create_tl_object(1, std::move(a), lt_, hash_), true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryViewTransaction::got_transaction(td::BufferSlice data) { @@ -913,10 +920,11 @@ void HttpQueryViewTransaction2::start_up_query() { } }); auto a = ton::create_tl_object(addr_.workchain, addr_.addr); - auto query = ton::create_tl_object( - ton::create_tl_lite_block_id(block_id_), std::move(a), lt_); + auto query = ton::serialize_tl_object(ton::create_tl_object( + ton::create_tl_lite_block_id(block_id_), std::move(a), lt_), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryViewTransaction2::got_transaction(td::BufferSlice data) { @@ -975,9 +983,9 @@ void HttpQueryViewLastBlock::start_up() { } }); - auto query = ton::create_tl_object(); + auto query = ton::serialize_tl_object(ton::create_tl_object(), true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryViewLastBlock::got_result(td::BufferSlice data) { @@ -1041,9 +1049,9 @@ void HttpQueryConfig::start_up() { } }); - auto query = ton::create_tl_object(); + auto query = ton::serialize_tl_object(ton::create_tl_object(), true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } } @@ -1067,17 +1075,16 @@ void HttpQueryConfig::send_main_query() { td::actor::send_closure(SelfId, &HttpQueryConfig::got_result, R.move_as_ok()); } }); - if (params_.size() > 0) { - auto query = ton::create_tl_object( - 0, ton::create_tl_lite_block_id(block_id_), std::vector(params_)); - td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); - } else { - auto query = - ton::create_tl_object(0, ton::create_tl_lite_block_id(block_id_)); - td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); - } + auto query = + params_.size() > 0 + ? ton::serialize_tl_object(ton::create_tl_object( + 0, ton::create_tl_lite_block_id(block_id_), std::vector(params_)), + true) + : ton::serialize_tl_object(ton::create_tl_object( + 0, ton::create_tl_lite_block_id(block_id_)), + true); + td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, + std::move(query), std::move(P)); } void HttpQueryConfig::got_result(td::BufferSlice data) { @@ -1219,9 +1226,10 @@ void HttpQuerySend::start_up() { td::actor::send_closure(SelfId, &HttpQuerySend::got_result, R.move_as_ok()); } }); - auto query = ton::create_tl_object(std::move(data_)); + auto query = + ton::serialize_tl_object(ton::create_tl_object(std::move(data_)), true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQuerySend::got_result(td::BufferSlice data) { @@ -1327,10 +1335,12 @@ void HttpQueryRunMethod::start_up_query() { return abort_query(params_serialized.move_as_error_prefix("cannot serialize stack with get-method parameters : ")); } - auto query = ton::create_tl_object( - 0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()); + auto query = ton::serialize_tl_object( + ton::create_tl_object( + 0x17, ton::create_tl_lite_block_id(block_id_), std::move(a), method_id, params_serialized.move_as_ok()), + true); td::actor::send_closure(CoreActorInterface::instance_actor_id(), &CoreActorInterface::send_lite_query, - ton::serialize_tl_object(query, true), liteclient::get_query_shard(*query), std::move(P)); + std::move(query), std::move(P)); } void HttpQueryRunMethod::got_result(td::BufferSlice data) { diff --git a/blockchain-explorer/blockchain-explorer.cpp b/blockchain-explorer/blockchain-explorer.cpp index c22ce1b3..029c718d 100644 --- a/blockchain-explorer/blockchain-explorer.cpp +++ b/blockchain-explorer/blockchain-explorer.cpp @@ -155,8 +155,6 @@ class CoreActor : public CoreActorInterface { td::int32 attempt_ = 0; td::int32 waiting_ = 0; - std::vector ready_; - //void run_queries(); void got_result(td::uint32 idx, td::int32 attempt, td::Result data); @@ -189,12 +187,6 @@ class CoreActor : public CoreActorInterface { static CoreActor* instance_; td::actor::ActorId self_id_; - void conn_ready(td::uint32 idx) { - ready_.at(idx) = true; - } - void conn_closed(td::uint32 idx) { - ready_.at(idx) = false; - } void set_global_config(std::string str) { global_config_ = str; } @@ -219,7 +211,7 @@ class CoreActor : public CoreActorInterface { hide_ips_ = value; } - void send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise promise) override; + void send_lite_query(td::BufferSlice query, td::Promise promise) override; void get_last_result(td::Promise> promise) override { } void get_results(td::uint32 max, td::Promise promise) override { @@ -439,50 +431,24 @@ class CoreActor : public CoreActorInterface { } void run() { - std::vector servers; + std::vector servers; 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(); - - size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size(); - CHECK(size > 0); - ready_.resize(size, false); - - for (auto& s : gc.liteservers_) { - td::IPAddress addr; - addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); - addrs_.push_back(addr); - liteclient::ExtClient::LiteServer serv; - serv.address = addr; - serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); - servers.push_back(std::move(serv)); - } - for (auto& s : gc.liteservers_v2_) { - td::IPAddress addr; - addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); - addrs_.push_back(addr); - liteclient::ExtClient::LiteServer serv; - serv.address = addr; - serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); - serv.is_full = false; - for (auto& shard : s->shards_) { - serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_); - CHECK(serv.shards.back().is_valid_ext()); - } - servers.push_back(std::move(serv)); + auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc); + r_servers.ensure(); + servers = r_servers.move_as_ok(); + for (const auto& serv : servers) { + addrs_.push_back(serv.addr); } } else { if (!remote_addr_.is_valid()) { LOG(FATAL) << "remote addr not set"; } - ready_.resize(1, false); addrs_.push_back(remote_addr_); - liteclient::ExtClient::LiteServer serv; - serv.address = remote_addr_; - serv.adnl_id = ton::adnl::AdnlNodeIdFull{remote_public_key_}; - servers.push_back(std::move(serv)); + servers.push_back(liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_}); } client_ = liteclient::ExtClient::create(std::move(servers), make_callback()); daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast(http_port_), nullptr, nullptr, @@ -545,7 +511,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result promise) { +void CoreActor::send_lite_query(td::BufferSlice query, td::Promise promise) { auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result R) mutable { if (R.is_error()) { promise.set_error(R.move_as_error()); @@ -563,7 +529,7 @@ void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, t promise.set_value(std::move(B)); }); auto q = ton::create_tl_object(std::move(query)); - td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true), shard, + td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", serialize_tl_object(q, true), td::Timestamp::in(10.0), std::move(P)); } diff --git a/blockchain-explorer/blockchain-explorer.hpp b/blockchain-explorer/blockchain-explorer.hpp index d3c53e45..1bae362d 100644 --- a/blockchain-explorer/blockchain-explorer.hpp +++ b/blockchain-explorer/blockchain-explorer.hpp @@ -64,7 +64,7 @@ class CoreActorInterface : public td::actor::Actor { }; virtual ~CoreActorInterface() = default; - virtual void send_lite_query(td::BufferSlice data, ton::ShardIdFull shard, td::Promise promise) = 0; + virtual void send_lite_query(td::BufferSlice data, td::Promise promise) = 0; virtual void get_last_result(td::Promise> promise) = 0; virtual void get_results(td::uint32 max, td::Promise promise) = 0; diff --git a/lite-client/CMakeLists.txt b/lite-client/CMakeLists.txt index 5774c050..5b0c0fa9 100644 --- a/lite-client/CMakeLists.txt +++ b/lite-client/CMakeLists.txt @@ -1,7 +1,9 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) -add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h QueryTraits.h) -target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block) +add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h ext-client.cpp ext-client.h + query-utils.hpp query-utils.cpp) +target_link_libraries(lite-client-common PUBLIC tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto + ton_block) add_executable(lite-client lite-client.cpp lite-client.h ext-client.h ext-client.cpp) target_link_libraries(lite-client tdutils tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto ton_block diff --git a/lite-client/QueryTraits.h b/lite-client/QueryTraits.h deleted file mode 100644 index 54190244..00000000 --- a/lite-client/QueryTraits.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - This file is part of TON Blockchain Library. - - TON Blockchain Library is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - TON Blockchain Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with TON Blockchain Library. If not, see . -*/ -#pragma once -#include "ton/ton-types.h" -#include "auto/tl/lite_api.h" -#include "auto/tl/lite_api.hpp" -#include "vm/boc.h" -#include "vm/cellslice.h" -#include "block/block-auto.h" -#include "block/block-parse.h" -#include "auto/tl/lite_api.hpp" - -namespace liteclient { - -template -struct QueryTraits { - static ton::ShardIdFull get_shard(const Query& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfo& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfoExt& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTime& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getVersion& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlock& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getState& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockHeader& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_sendMessage& q) { - auto shard = [&]() -> td::Result { - vm::BagOfCells boc; - TRY_STATUS(boc.deserialize(q.body_.as_slice())); - if (boc.get_root_count() != 1) { - return td::Status::Error("external message is not a valid bag of cells"); - } - block::gen::CommonMsgInfo::Record_ext_in_msg_info info; - if (!tlb::unpack_cell_inexact(boc.get_root_cell(), info)) { - return td::Status::Error("cannot 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 an inbound external message is an invalid blockchain address"); - } - return dest_prefix.as_leaf_shard(); - }(); - if (shard.is_error()) { - LOG(DEBUG) << "Failed to get shard from query liteServer.sendMessage: " << shard.move_as_error(); - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } - return shard.move_as_ok(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountState& q) { - return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAccountStatePrunned& q) { - return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_runSmcMethod& q) { - return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardInfo& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAllShardsInfo& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getOneTransaction& q) { - return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTransactions& q) { - return ton::AccountIdPrefixFull(q.account_->workchain_, q.account_->id_.bits().get_uint(64)).as_leaf_shard(); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_lookupBlock& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactions& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactionsExt& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockProof& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigAll& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigParams& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getValidatorStats& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getLibraries& q) { - return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll); - } -}; - -template<> -struct QueryTraits { - static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardBlockProof& q) { - return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_); - } -}; - -template -inline ton::ShardIdFull get_query_shard(const Query& q) { - return QueryTraits::get_shard(q); -} - -} // namespace tonlib diff --git a/lite-client/ext-client.cpp b/lite-client/ext-client.cpp index e79ae9a4..0232c28f 100644 --- a/lite-client/ext-client.cpp +++ b/lite-client/ext-client.cpp @@ -17,92 +17,75 @@ #include "ext-client.h" #include "td/utils/Random.h" #include "ton/ton-shard.h" -#include namespace liteclient { class ExtClientImpl : public ExtClient { public: - ExtClientImpl(std::vector servers, td::unique_ptr callback) + ExtClientImpl(std::vector liteservers, td::unique_ptr callback) : callback_(std::move(callback)) { - CHECK(!servers.empty()); - servers_.resize(servers.size()); + CHECK(!liteservers.empty()); + servers_.resize(liteservers.size()); for (size_t i = 0; i < servers_.size(); ++i) { - servers_[i].s = std::move(servers[i]); - if (!servers_[i].s.is_full) { - for (auto shard : servers_[i].s.shards) { - CHECK(shard.is_valid_ext()); - max_server_shard_depth_ = std::max(max_server_shard_depth_, shard.pfx_len()); - } - } + servers_[i].config = std::move(liteservers[i]); + servers_[i].idx = i; } } void start_up() override { + LOG(INFO) << "Started ext client, " << servers_.size() << " liteservers"; td::Random::Fast rnd; td::random_shuffle(td::as_mutable_span(servers_), rnd); } - void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, + void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, td::Promise promise) override { - TRY_RESULT_PROMISE(promise, server_idx, before_query(shard)); + QueryInfo query_info = get_query_info(data); + TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info)); auto& server = servers_[server_idx]; CHECK(!server.client.empty()); alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); td::Promise P = [SelfId = actor_id(this), server_idx, - promise = std::move(promise)](td::Result R) mutable { + promise = std::move(promise)](td::Result R) mutable { if (R.is_error() && (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) { - td::actor::send_closure(SelfId, &ExtClientImpl::set_server_bad, server_idx); + td::actor::send_closure(SelfId, &ExtClientImpl::on_server_error, server_idx); } promise.set_result(std::move(R)); }; + LOG(DEBUG) << "Sending query " << query_info.to_str() << " to server #" << server.idx << " (" + << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; send_closure(server.client, &ton::adnl::AdnlExtClient::send_query, std::move(name), std::move(data), timeout, std::move(P)); } - void force_change_liteserver() override { - if (servers_.size() == 1) { - return; - } - auto it = shard_to_server_.find(ton::ShardIdFull(ton::masterchainId)); - if (it != shard_to_server_.end()) { - set_server_bad(it->second); + void reset_servers() override { + LOG(INFO) << "Force resetting all liteservers"; + for (Server& server : servers_) { + server.alive = false; + server.timeout = {}; + server.ignore_until = {}; + server.client.reset(); } } private: - td::Result before_query(ton::ShardIdFull shard) { - if (!shard.is_valid_ext()) { - return td::Status::Error("Invalid shard"); - } - if (is_closing_) { - return td::Status::Error("Client is closing"); - } - if (shard.pfx_len() > max_server_shard_depth_) { - shard = shard_prefix(shard, max_server_shard_depth_); - } - auto it = shard_to_server_.find(shard); - if (it != shard_to_server_.end()) { - size_t server_idx = it->second; - if (!servers_[server_idx].client.empty()) { - return server_idx; + td::Result select_server(const QueryInfo& query_info) { + for (size_t i = 0; i < servers_.size(); ++i) { + if (servers_[i].alive && servers_[i].config.accepts_query(query_info)) { + return i; } - shard_to_server_.erase(it); } - size_t server_idx = servers_.size(); int cnt = 0; int best_priority = -1; for (size_t i = 0; i < servers_.size(); ++i) { Server& server = servers_[i]; - if (!server.supports(shard)) { + if (!server.config.accepts_query(query_info)) { continue; } int priority = 0; - priority += (server.client.empty() ? 0 : 100); priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10); - priority += (server.s.is_full ? 1 : 0); if (priority < best_priority) { continue; } @@ -116,100 +99,76 @@ class ExtClientImpl : public ExtClient { ++cnt; } if (server_idx == servers_.size()) { - return td::Status::Error(PSTRING() << "No liteserver for shard " << shard.to_str()); + return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str()); } Server& server = servers_[server_idx]; + server.alive = true; + server.ignore_until = {}; + alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); if (!server.client.empty()) { return server_idx; } class Callback : public ton::adnl::AdnlExtClient::Callback { public: - explicit Callback(td::actor::ActorShared parent, size_t idx) - : parent_(std::move(parent)), idx_(idx) { + explicit Callback(td::actor::ActorId parent, size_t idx) : parent_(std::move(parent)), idx_(idx) { } void on_ready() override { } void on_stop_ready() override { - td::actor::send_closure(parent_, &ExtClientImpl::set_server_bad, idx_); + td::actor::send_closure(parent_, &ExtClientImpl::on_server_error, idx_); } private: - td::actor::ActorShared parent_; + td::actor::ActorId parent_; size_t idx_; }; - ref_cnt_++; - if (shard.is_masterchain()) { - LOG(INFO) << "Connecting to liteserver " << server.s.address << " for masterchain"; - } else { - LOG(INFO) << "Connecting to liteserver " << server.s.address << " for shard " << shard.to_str(); - } - server.client = ton::adnl::AdnlExtClient::create( - server.s.adnl_id, server.s.address, std::make_unique(td::actor::actor_shared(this), server_idx)); - alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT)); + LOG(INFO) << "Connecting to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() << ":" + << server.config.addr.get_port() << ") for query " << query_info.to_str(); + server.client = ton::adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr, + std::make_unique(actor_id(this), server_idx)); return server_idx; } struct Server { - LiteServer s; + LiteServerConfig config; + size_t idx = 0; td::actor::ActorOwn client; + bool alive = false; td::Timestamp timeout = td::Timestamp::never(); td::Timestamp ignore_until = td::Timestamp::never(); - - bool supports(const ton::ShardIdFull& shard) const { - return s.is_full || shard.is_masterchain() || - std::any_of(s.shards.begin(), s.shards.end(), - [&](const ton::ShardIdFull s_shard) { return ton::shard_intersects(shard, s_shard); }); - } }; std::vector servers_; - std::map shard_to_server_; - int max_server_shard_depth_ = 0; - td::unique_ptr callback_; - static constexpr double MAX_NO_QUERIES_TIMEOUT = 100; - - bool is_closing_{false}; - td::uint32 ref_cnt_{1}; + td::unique_ptr callback_; + static constexpr double MAX_NO_QUERIES_TIMEOUT = 100.0; + static constexpr double BAD_SERVER_TIMEOUT = 30.0; void alarm() override { for (Server& server : servers_) { if (server.timeout && server.timeout.is_in_past()) { + LOG(INFO) << "Closing connection to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() + << ":" << server.config.addr.get_port() << ")"; server.client.reset(); + server.alive = false; + server.ignore_until = {}; } } } - void set_server_bad(size_t idx) { - servers_[idx].client.reset(); - servers_[idx].timeout = td::Timestamp::never(); - servers_[idx].ignore_until = td::Timestamp::in(60.0); - } - void hangup_shared() override { - ref_cnt_--; - try_stop(); - } - void hangup() override { - is_closing_ = true; - ref_cnt_--; - for (Server& server : servers_) { - server.client.reset(); - } - try_stop(); - } - void try_stop() { - if (is_closing_ && ref_cnt_ == 0) { - stop(); - } + + void on_server_error(size_t idx) { + servers_[idx].alive = false; + servers_[idx].ignore_until = td::Timestamp::in(BAD_SERVER_TIMEOUT); } }; td::actor::ActorOwn ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr, - td::unique_ptr callback) { - return create({LiteServer{dst, dst_addr, true, {}}}, std::move(callback)); + td::unique_ptr callback) { + return create({LiteServerConfig{dst, dst_addr}}, std::move(callback)); } -td::actor::ActorOwn ExtClient::create(std::vector servers, - td::unique_ptr callback) { - return td::actor::create_actor("ExtClient", std::move(servers), std::move(callback)); +td::actor::ActorOwn ExtClient::create(std::vector liteservers, + td::unique_ptr callback) { + return td::actor::create_actor("ExtClient", std::move(liteservers), std::move(callback)); } } // namespace liteclient diff --git a/lite-client/ext-client.h b/lite-client/ext-client.h index c8569964..adcff9be 100644 --- a/lite-client/ext-client.h +++ b/lite-client/ext-client.h @@ -18,29 +18,24 @@ #include "td/actor/actor.h" #include "ton/ton-types.h" #include "adnl/adnl-ext-client.h" +#include "query-utils.hpp" namespace liteclient { class ExtClient : public td::actor::Actor { public: - struct LiteServer { - ton::adnl::AdnlNodeIdFull adnl_id; - td::IPAddress address; - bool is_full = true; - std::vector shards; - }; - class Callback { public: - virtual ~Callback() { - } + virtual ~Callback() = default; }; - virtual void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, + virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, td::Promise promise) = 0; - virtual void force_change_liteserver() = 0; + virtual void reset_servers() { + } static td::actor::ActorOwn create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr, td::unique_ptr callback); - static td::actor::ActorOwn create(std::vector servers, td::unique_ptr callback); + static td::actor::ActorOwn create(std::vector liteservers, + td::unique_ptr callback); }; } // namespace liteclient diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp index 923ea617..2e2770a4 100644 --- a/lite-client/lite-client.cpp +++ b/lite-client/lite-client.cpp @@ -67,12 +67,6 @@ using td::Ref; int verbosity; -bool TestNode::LiteServer::supports(ton::ShardIdFull shard) const { - return is_full || shard.is_masterchain() || - std::any_of(shards.begin(), shards.end(), - [&](const ton::ShardIdFull& our_shard) { return ton::shard_intersects(shard, our_shard); }); -} - void TestNode::run() { class Cb : public td::TerminalIO::Callback { public: @@ -88,55 +82,39 @@ 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); + std::vector servers; if (!single_remote_public_key_.empty()) { // Use single provided liteserver - LiteServer s; - s.addr = single_remote_addr_; - s.public_key = single_remote_public_key_; - single_liteserver_idx_ = 0; - td::TerminalIO::out() << "using liteserver " << s.addr << "\n"; - servers_.push_back(std::move(s)); - run_init_queries(); - return; - } + servers.push_back( + liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{single_remote_public_key_}, single_remote_addr_}); + td::TerminalIO::out() << "using liteserver " << single_remote_addr_ << "\n"; + } else { + 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(); + auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc); + r_servers.ensure(); + servers = r_servers.move_as_ok(); - 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() + gc.liteservers_v2_.size() > 0); + if (gc.validator_ && gc.validator_->zero_state_) { + zstate_id_.workchain = gc.validator_->zero_state_->workchain_; + if (zstate_id_.workchain != ton::workchainInvalid) { + 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 (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_liteserver_idx_ != -1) { // Use single liteserver from config + CHECK(single_liteserver_idx_ >= 0 && (size_t)single_liteserver_idx_ < servers.size()); + td::TerminalIO::out() << "using liteserver #" << single_liteserver_idx_ << " with addr " + << servers[single_liteserver_idx_].addr << "\n"; + servers = {servers[single_liteserver_idx_]}; } } - - for (auto& server : gc.liteservers_) { - LiteServer s; - s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure(); - s.public_key = ton::PublicKey{server->id_}; - servers_.push_back(std::move(s)); - } - for (auto& server : gc.liteservers_v2_) { - LiteServer s; - s.addr.init_host_port(td::IPAddress::ipv4_to_str(server->ip_), server->port_).ensure(); - s.public_key = ton::PublicKey{server->id_}; - s.is_full = false; - for (const auto& shard : server->shards_) { - s.shards.emplace_back(shard->workchain_, shard->shard_); - CHECK(s.shards.back().is_valid_ext()); - } - servers_.push_back(std::move(s)); - } - - 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"; - } + CHECK(!servers.empty()); + client_ = liteclient::ExtClient::create(std::move(servers), nullptr); + ready_ = true; run_init_queries(); } @@ -183,142 +161,23 @@ void TestNode::after_got_result(bool ok) { } } -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) { - return envelope_send_query_to_shard(prefix.as_leaf_shard(), std::move(query), std::move(promise)); -} - -bool TestNode::envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query, - td::Promise promise) { - if (single_liteserver_idx_ >= 0) { - return envelope_send_query_to_server(single_liteserver_idx_, std::move(query), std::move(promise)); - } - if (shard.is_masterchain() && mc_server_idx_ != -1) { - return envelope_send_query_to_server(mc_server_idx_, std::move(query), std::move(promise)); - } - auto it = shard_server_idx_cached_.find(shard); - if (it != shard_server_idx_cached_.end()) { - return envelope_send_query_to_server(it->second, std::move(query), std::move(promise)); - } - int server_idx = -1; - int random_idx = -1; - int cnt = 0; - bool selected_full = false; - for (int i = 0; i < (int)servers_.size(); ++i) { - const LiteServer& server = servers_[i]; - if (!server.supports(shard)) { - continue; - } - if (server.is_full && !selected_full) { - selected_full = true; - server_idx = -1; - cnt = 0; - } - if (!server.is_full && selected_full) { - continue; - } - if (!server.client.empty()) { - server_idx = i; - } - if (td::Random::fast(0, cnt) == 0) { - random_idx = i; - } - ++cnt; - } - if (server_idx == -1) { - server_idx = random_idx; - } - if (server_idx == -1) { - running_queries_++; - got_result(td::Status::Error(PSTRING() << "failed to select a suitable server for " << shard.to_str()), - std::move(promise)); +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)); 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); - 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: ")); - } - }); - } + td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", std::move(b), td::Timestamp::in(10.0), + std::move(P)); 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()) { @@ -433,7 +292,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_to_any(std::move(b), [&, Self = actor_id(this)](td::Result res) -> void { + return envelope_send_query(std::move(b), [&, Self = actor_id(this)](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot get server time"; return; @@ -453,7 +312,7 @@ 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_to_any(std::move(b), [Self = actor_id(this), mode](td::Result res) { + return envelope_send_query(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); }); }; @@ -501,7 +360,7 @@ bool TestNode::get_server_mc_block_id() { 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_to_any(std::move(b), [Self = actor_id(this)](td::Result res) -> void { + return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "cannot get masterchain info from server"; return; @@ -521,25 +380,24 @@ bool TestNode::get_server_mc_block_id() { } else { auto b = ton::serialize_tl_object(ton::create_tl_object(mode), true); - 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_); - } - } - }); + 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_); + } + } + }); } } @@ -594,54 +452,52 @@ 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_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_)); - } + 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(); } - }); + 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_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_)); - } + 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(); } - }); + 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) { @@ -1280,34 +1136,27 @@ td::Status TestNode::send_ext_msg_from_filename(std::string filename) { LOG(ERROR) << "failed to read file `" << filename << "`: " << err.to_string(); return err; } - 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"); + 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"); } - auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(info.dest); - if (!dest_prefix.is_valid()) { - return td::Status::Error("destination of the message is invalid"); - } - - auto P = td::PromiseCreator::lambda([](td::Result 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, @@ -1315,6 +1164,9 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress if (!ref_blkid.is_valid()) { return set_error("must obtain last block information before making other queries"); } + if (!(ready_ && !client_.empty())) { + return set_error("server connection not ready"); + } if (addr_ext) { return get_special_smc_addr( addr_ext, [this, ref_blkid, filename, mode, prunned](td::Result res) { @@ -1336,26 +1188,24 @@ bool TestNode::get_account_state(ton::WorkchainId workchain, ton::StdSmcAddress ton::create_tl_lite_block_id(ref_blkid), std::move(a)), true); } - ton::AccountIdPrefixFull account_prefix(workchain, addr.bits().get_uint(64)); LOG(INFO) << "requesting " << (prunned ? "prunned " : "") << "account state for " << workchain << ":" << addr.to_hex() << " with respect to " << ref_blkid.to_str() << " with savefile `" << filename << "` and mode " << mode; - return envelope_send_query_to_account( - account_prefix, std::move(b), - [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode, prunned](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.getAccountState"; - } else { - auto f = F.move_as_ok(); - td::actor::send_closure_later(Self, &TestNode::got_account_state, 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_), workchain, addr, filename, mode, - prunned); - } - }); + return envelope_send_query(std::move(b), [Self = actor_id(this), workchain, addr, ref_blkid, filename, mode, + prunned](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.getAccountState"; + } else { + auto f = F.move_as_ok(); + td::actor::send_closure_later(Self, &TestNode::got_account_state, 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_), workchain, addr, filename, mode, + prunned); + } + }); } td::int64 TestNode::compute_method_id(std::string method) { @@ -1421,18 +1271,19 @@ 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_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 { + 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 { if (R.is_error()) { promise.set_error(R.move_as_error()); return; @@ -1472,27 +1323,26 @@ 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_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)); - } - }); + 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)); + } + }); } } @@ -1722,8 +1572,8 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add params.emplace_back(td::make_refint(bits)); params.emplace_back(td::make_refint(refs)); params.emplace_back(td::make_refint(expires_in)); - auto P = - td::PromiseCreator::lambda([expires_in, bits, refs, chash, filename](td::Result> R) { + auto P = td::PromiseCreator::lambda( + [this, expires_in, bits, refs, chash, filename](td::Result> R) { if (R.is_error()) { LOG(ERROR) << R.move_as_error(); return; @@ -1748,9 +1598,8 @@ void TestNode::send_compute_complaint_price_query(ton::StdSmcAddress elector_add } bool TestNode::get_msg_queue_sizes() { - // TODO: rework for separated liteservers auto q = ton::serialize_tl_object(ton::create_tl_object(0, 0, 0), true); - return envelope_send_query_to_any(std::move(q), [Self = actor_id(this)](td::Result res) -> void { + return envelope_send_query(std::move(q), [Self = actor_id(this)](td::Result res) -> void { if (res.is_error()) { LOG(ERROR) << "liteServer.getOutMsgQueueSizes error: " << res.move_as_error(); return; @@ -1810,6 +1659,10 @@ 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; @@ -2018,16 +1871,17 @@ 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_to_account( - account_prefix, std::move(b), - [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result R) -> void { + return envelope_send_query( + std::move(b), [Self = actor_id(this), workchain, addr, lt, blkid, dump](td::Result R) -> void { if (R.is_error()) { return; } @@ -2044,15 +1898,16 @@ 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_to_account( - account_prefix, std::move(b), - [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result R) { + return envelope_send_query( + std::move(b), [Self = actor_id(this), workchain, addr, lt, hash, count, dump](td::Result R) { if (R.is_error()) { return; } @@ -2420,10 +2275,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; } @@ -2602,30 +2457,32 @@ 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_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_)); - } - }); + 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_)); + } + }); } void TestNode::got_block_transactions(ton::BlockIdExt blkid, int mode, unsigned req_count, bool incomplete, @@ -2651,23 +2508,25 @@ 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_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); - } - }); + 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); + } + }); } void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data, std::string filename) { @@ -2731,6 +2590,9 @@ 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"); } @@ -2749,6 +2611,10 @@ 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; @@ -2766,12 +2632,11 @@ 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(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, @@ -2959,8 +2824,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_to_shard( - blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { + return envelope_send_query( + 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(); @@ -2988,8 +2853,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_to_shard( - blkid.shard_full(), std::move(b), [Self = actor_id(this), blkid, dump](td::Result res) -> void { + return envelope_send_query( + 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(); @@ -3126,7 +2991,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](td::Result R) { + return get_block_header(blkid, mode, [this, blkid](td::Result R) { if (R.is_error()) { LOG(ERROR) << "unable to fetch block header: " << R.move_as_error(); } else { @@ -3141,9 +3006,8 @@ 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_to_shard( - blkid.shard_full(), std::move(b), - [this, blkid, promise = std::move(promise)](td::Result R) mutable -> void { + return envelope_send_query( + 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); @@ -3169,9 +3033,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_to_shard( - shard, std::move(b), - [this, id, mode, arg, promise = std::move(promise)](td::Result R) mutable -> void { + return envelope_send_query( + 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 :"); @@ -3285,9 +3148,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(); @@ -3316,15 +3179,14 @@ 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_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()); - } - }); + 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()); + } + }); } void TestNode::got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice pchain) { @@ -3378,6 +3240,9 @@ 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"); } @@ -3388,8 +3253,8 @@ 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, - [&os](const td::Bits256& key, const block::DiscountedCounter& mc_cnt, - const block::DiscountedCounter& shard_cnt) -> bool { + [min_utime, &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; }, @@ -3418,6 +3283,10 @@ 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; @@ -3436,7 +3305,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_to_any( + return envelope_send_query( 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)); @@ -3653,8 +3522,8 @@ 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, - [&info](const td::Bits256& key, const block::DiscountedCounter& mc_cnt, - const block::DiscountedCounter& shard_cnt) -> bool { + [min_utime, &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; }, @@ -3857,7 +3726,7 @@ bool compute_punishment_default(int interval, bool severe, td::RefInt256& fine, fine = td::make_refint(101 * 1000000000LL); // 101 fine_part = 0; - return true; // todo: (tolya-yanot) temporary reduction of fine + return true; // todo: (tolya-yanot) temporary reduction of fine if (severe) { fine = td::make_refint(2500 * 1000000000LL); // GR$2500 @@ -3879,49 +3748,41 @@ bool compute_punishment_default(int interval, bool severe, td::RefInt256& fine, return true; } -bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part, - Ref punishment_params) { - if (punishment_params.is_null()) { +bool compute_punishment(int interval, bool severe, td::RefInt256& fine, unsigned& fine_part, Ref punishment_params) { + if(punishment_params.is_null()) { return compute_punishment_default(interval, severe, fine, fine_part); } block::gen::MisbehaviourPunishmentConfig::Record rec; if (!tlb::unpack_cell(punishment_params, rec)) { - return false; + return false; } - if (interval <= rec.unpunishable_interval) { - return false; + if(interval <= rec.unpunishable_interval) { + return false; } fine = block::tlb::t_Grams.as_integer(rec.default_flat_fine); fine_part = rec.default_proportional_fine; if (severe) { - fine = fine * rec.severity_flat_mult; - fine >>= 8; - fine_part = fine_part * rec.severity_proportional_mult; - fine_part >>= 8; + fine = fine * rec.severity_flat_mult; fine >>= 8; + fine_part = fine_part * rec.severity_proportional_mult; fine_part >>= 8; } if (interval >= rec.long_interval) { - fine = fine * rec.long_flat_mult; - fine >>= 8; - fine_part = fine_part * rec.long_proportional_mult; - fine_part >>= 8; + fine = fine * rec.long_flat_mult; fine >>= 8; + fine_part = fine_part * rec.long_proportional_mult; fine_part >>= 8; return true; } if (interval >= rec.medium_interval) { - fine = fine * rec.medium_flat_mult; - fine >>= 8; - fine_part = fine_part * rec.medium_proportional_mult; - fine_part >>= 8; + fine = fine * rec.medium_flat_mult; fine >>= 8; + fine_part = fine_part * rec.medium_proportional_mult; fine_part >>= 8; return true; } return true; } -bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part, - Ref punishment_params) { +bool check_punishment(int interval, bool severe, td::RefInt256 fine, unsigned fine_part, Ref punishment_params) { td::RefInt256 computed_fine; unsigned computed_fine_part; return compute_punishment(interval, severe, computed_fine, computed_fine_part, punishment_params) && @@ -3957,7 +3818,7 @@ td::Status TestNode::write_val_create_proof(TestNode::ValidatorLoadInfo& info1, int severity = (severe ? 2 : 1); td::RefInt256 fine = td::make_refint(101000000000); - unsigned fine_part = 0; // todo: (tolya-yanot) temporary reduction of fine // 0xffffffff / 16; // 1/16 + unsigned fine_part = 0; // todo: (tolya-yanot) temporary reduction of fine // 0xffffffff / 16; // 1/16 if (!compute_punishment(interval, severe, fine, fine_part, punishment_params)) { return td::Status::Error("cannot compute adequate punishment"); } @@ -4056,7 +3917,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(entry, rec2)) { + } else if (tlb::csr_unpack(std::move(entry), rec2)) { pk = std::move(rec2.public_key); } else { return td::Status::Error("cannot unpack ValidatorDescr"); @@ -4272,8 +4133,7 @@ td::Status TestNode::continue_check_validator_load_proof(std::unique_ptrconfig->get_config_param(40))) { + if (!check_punishment(interval, severe, suggested_fine, rec.suggested_fine_part, info2->config->get_config_param(40))) { LOG(ERROR) << "proposed punishment (fine " << td::dec_string(suggested_fine) << ", fine_part=" << (double)rec.suggested_fine_part / (1LL << 32) << " is too harsh"; show_vote(root->get_hash().bits(), false); @@ -4422,8 +4282,7 @@ int main(int argc, char* argv[]) { return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9"); }); p.add_option('V', "version", "shows lite-client build information", [&]() { - std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1() - << ", Date: " << GitMetadata::CommitDate() << "]\n"; + std::cout << "lite-client build information: [ Commit: " << GitMetadata::CommitSHA1() << ", Date: " << GitMetadata::CommitDate() << "]\n"; std::exit(0); }); diff --git a/lite-client/lite-client.h b/lite-client/lite-client.h index da45ec92..59fc1165 100644 --- a/lite-client/lite-client.h +++ b/lite-client/lite-client.h @@ -26,6 +26,7 @@ Copyright 2017-2020 Telegram Systems LLP */ #pragma once +#include "ext-client.h" #include "adnl/adnl-ext-client.h" #include "tl-utils/tl-utils.hpp" #include "ton/ton-types.h" @@ -46,35 +47,19 @@ 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; - - bool supports(ton::ShardIdFull shard) const; - }; - std::vector servers_; + bool ready_ = false; 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; int print_limit_ = 1024; std::string db_root_; - // 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; @@ -443,18 +428,7 @@ 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_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); - + bool envelope_send_query(td::BufferSlice query, td::Promise promise); void parse_line(td::BufferSlice data); TestNode() = default; diff --git a/lite-client/query-utils.cpp b/lite-client/query-utils.cpp new file mode 100644 index 00000000..eddaa727 --- /dev/null +++ b/lite-client/query-utils.cpp @@ -0,0 +1,394 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . +*/ +#include "query-utils.hpp" + +#include "block-parse.h" +#include "td/utils/overloaded.h" +#include "tl-utils/common-utils.hpp" + +#include "block/block-auto.h" +#include "auto/tl/lite_api.hpp" +#include "overlay/overlay-broadcast.hpp" +#include "tl-utils/lite-utils.hpp" +#include "ton/lite-tl.hpp" +#include "ton/ton-shard.h" + +#include + +namespace liteclient { + +using namespace ton; + +std::string QueryInfo::to_str() const { + td::StringBuilder sb; + sb << "[ " << lite_query_name_by_id(query_id) << " " << shard_id.to_str(); + switch (type) { + case t_simple: + break; + case t_seqno: + sb << " seqno=" << value; + break; + case t_utime: + sb << " utime=" << value; + break; + case t_lt: + sb << " lt=" << value; + break; + case t_mc_seqno: + sb << " mc_seqno=" << value; + break; + } + sb << " ]"; + return sb.as_cslice().str(); +} + +QueryInfo get_query_info(td::Slice data) { + auto F = fetch_tl_object(data, true); + if (F.is_ok()) { + data = F.ok()->data_; + } else { + fetch_tl_prefix(data, true).ignore(); + } + fetch_tl_prefix(data, true).ignore(); + auto Q = fetch_tl_object(data, true); + if (Q.is_error()) { + return {}; + } + return get_query_info(*Q.ok()); +} + +QueryInfo get_query_info(const lite_api::Function& f) { + QueryInfo info; + info.query_id = f.get_id(); + auto from_block_id = [&](const tl_object_ptr& id) { + BlockIdExt block_id = create_block_id(id); + info.shard_id = block_id.shard_full(); + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno(); + }; + downcast_call( + const_cast(f), + td::overloaded([&](const lite_api::liteServer_getTime& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getVersion& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getMasterchainInfo& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getMasterchainInfoExt& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getBlock& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getBlockHeader& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getState& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getAccountState& q) { + BlockIdExt block_id = create_block_id(q.id_); + AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); + info.shard_id = acc_id_prefix.as_leaf_shard(); + // See LiteQuery::perform_getAccountState + if (block_id.id.workchain != masterchainId) { + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno(); + } else if (block_id.id.seqno != ~0U) { + info.type = QueryInfo::t_mc_seqno; + info.value = block_id.seqno(); + } else { + info.type = QueryInfo::t_simple; + } + }, + [&](const lite_api::liteServer_getAccountStatePrunned& q) { + BlockIdExt block_id = create_block_id(q.id_); + AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); + info.shard_id = acc_id_prefix.as_leaf_shard(); + // See LiteQuery::perform_getAccountState + if (block_id.id.workchain != masterchainId) { + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno(); + } else if (block_id.id.seqno != ~0U) { + info.type = QueryInfo::t_mc_seqno; + info.value = block_id.seqno(); + } else { + info.type = QueryInfo::t_simple; + } + }, + [&](const lite_api::liteServer_getOneTransaction& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getTransactions& q) { + AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); + info.shard_id = acc_id_prefix.as_leaf_shard(); + info.type = QueryInfo::t_lt; + info.value = q.lt_; + }, + [&](const lite_api::liteServer_sendMessage& q) { + info.type = QueryInfo::t_simple; + auto r_root = vm::std_boc_deserialize(q.body_); + if (r_root.is_error()) { + return; + } + block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; + if (!tlb::unpack_cell_inexact(r_root.ok(), msg_info)) { + return; + } + auto dest_prefix = block::tlb::MsgAddressInt::get_prefix(msg_info.dest); + if (!dest_prefix.is_valid()) { + return; + } + info.shard_id = dest_prefix.as_leaf_shard(); + }, + [&](const lite_api::liteServer_getShardInfo& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getAllShardsInfo& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_lookupBlock& q) { + BlockId block_id = create_block_id_simple(q.id_); + info.shard_id = block_id.shard_full(); + // See LiteQuery::perform_lookupBlock + if (q.mode_ & 1) { + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno; + } else if (q.mode_ == 2) { + info.type = QueryInfo::t_lt; + info.value = q.lt_; + } else if (q.mode_ == 4) { + info.type = QueryInfo::t_utime; + info.value = q.utime_; + } + }, + [&](const lite_api::liteServer_lookupBlockWithProof& q) { + BlockId block_id = create_block_id_simple(q.id_); + info.shard_id = block_id.shard_full(); + // See LiteQuery::perform_lookupBlockWithProof + if (q.mode_ & 1) { + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno; + } else if (q.mode_ == 2) { + info.type = QueryInfo::t_lt; + info.value = q.lt_; + } else if (q.mode_ == 4) { + info.type = QueryInfo::t_utime; + info.value = q.utime_; + } + }, + [&](const lite_api::liteServer_listBlockTransactions& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_listBlockTransactionsExt& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getConfigParams& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getConfigAll& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getBlockProof& q) { + info.shard_id = ShardIdFull{masterchainId}; + BlockIdExt from = create_block_id(q.known_block_); + BlockIdExt to = create_block_id(q.target_block_); + // See LiteQuery::perform_getBlockProof + if ((q.mode_ & 1) && (q.mode_ & 0x1000)) { + info.type = QueryInfo::t_seqno; + info.value = std::max(from.seqno(), to.seqno()); + } else { + info.type = QueryInfo::t_simple; + } + }, + [&](const lite_api::liteServer_getValidatorStats& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_runSmcMethod& q) { + BlockIdExt block_id = create_block_id(q.id_); + AccountIdPrefixFull acc_id_prefix = extract_addr_prefix(q.account_->workchain_, q.account_->id_); + info.shard_id = acc_id_prefix.as_leaf_shard(); + // See LiteQuery::perform_getAccountState + if (block_id.id.workchain != masterchainId) { + info.type = QueryInfo::t_seqno; + info.value = block_id.seqno(); + } else if (block_id.id.seqno != ~0U) { + info.type = QueryInfo::t_mc_seqno; + info.value = block_id.seqno(); + } else { + info.type = QueryInfo::t_simple; + } + }, + [&](const lite_api::liteServer_getLibraries& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getLibrariesWithProof& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_getShardBlockProof& q) { from_block_id(q.id_); }, + [&](const lite_api::liteServer_nonfinal_getCandidate& q) { /* t_simple */ }, + [&](const lite_api::liteServer_nonfinal_getValidatorGroups& q) { /* t_simple */ }, + [&](const lite_api::liteServer_getOutMsgQueueSizes& q) { /* t_simple */ }, + [&](const auto&) { /* t_simple */ })); + if (info.shard_id.workchain == masterchainId) { + info.shard_id.shard = shardIdAll; + } + if (!info.shard_id.is_valid_ext()) { + info.shard_id = ShardIdFull{masterchainId}; + info.type = QueryInfo::t_simple; + info.value = 0; + } + return info; +} + +bool LiteServerConfig::accepts_query(const QueryInfo& query_info) const { + if (is_full) { + return true; + } + for (const Slice& s : slices) { + if (s.accepts_query(query_info)) { + return true; + } + } + return false; +} + +bool LiteServerConfig::Slice::accepts_query(const QueryInfo& query_info) const { + if (unlimited) { + for (const ShardInfo& shard : shards_from) { + if (shard_intersects(shard.shard_id, query_info.shard_id)) { + return true; + } + } + return false; + } + if (!shards_from.empty()) { + bool from_ok = false; + DCHECK(shards_from[0].shard_id.is_masterchain()); + for (const ShardInfo& shard : shards_from) { + if (shard_intersects(shard.shard_id, query_info.shard_id)) { + switch (query_info.type) { + case QueryInfo::t_simple: + from_ok = true; + break; + case QueryInfo::t_seqno: + from_ok = shard.seqno <= query_info.value; + break; + case QueryInfo::t_utime: + from_ok = shard.utime <= query_info.value; + break; + case QueryInfo::t_lt: + from_ok = shard.lt <= query_info.value; + break; + case QueryInfo::t_mc_seqno: + from_ok = shards_from[0].seqno <= query_info.value; + break; + } + if (from_ok) { + break; + } + } + } + if (!from_ok) { + return false; + } + } + if (!shards_to.empty()) { + bool to_ok = false; + DCHECK(shards_to[0].shard_id.is_masterchain()); + for (const ShardInfo& shard : shards_to) { + if (shard_intersects(shard.shard_id, query_info.shard_id)) { + switch (query_info.type) { + case QueryInfo::t_simple: + break; + case QueryInfo::t_seqno: + to_ok = shard.seqno >= query_info.value; + break; + case QueryInfo::t_utime: + to_ok = shard.utime >= query_info.value; + break; + case QueryInfo::t_lt: + to_ok = shard.lt >= query_info.value; + break; + case QueryInfo::t_mc_seqno: + to_ok = shards_from[0].seqno >= query_info.value; + break; + } + if (to_ok) { + break; + } + } + } + if (!to_ok) { + return false; + } + } + return true; +} + +td::Result> LiteServerConfig::parse_global_config( + const ton_api::liteclient_config_global& config) { + std::vector servers; + for (const auto& f : config.liteservers_) { + LiteServerConfig server; + TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_)); + server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}}; + server.is_full = true; + servers.push_back(std::move(server)); + } + for (const auto& f : config.liteservers_v2_) { + LiteServerConfig server; + TRY_STATUS(server.addr.init_host_port(td::IPAddress::ipv4_to_str(f->ip_), f->port_)); + server.adnl_id = adnl::AdnlNodeIdFull{PublicKey{f->id_}}; + server.is_full = false; + for (const auto& slice_obj : f->slices_) { + Slice slice; + td::Status S = td::Status::OK(); + downcast_call(*slice_obj, + td::overloaded( + [&](const ton_api::liteserver_descV2_sliceSimple& s) { + slice.unlimited = true; + slice.shards_from.push_back({ShardIdFull{masterchainId}, 0, 0, 0}); + for (const auto& shard_obj : s.shards_) { + ShardIdFull shard_id = create_shard_id(shard_obj); + if (!shard_id.is_valid_ext()) { + S = td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str()); + break; + } + if (!shard_id.is_masterchain()) { + slice.shards_from.push_back({shard_id, 0, 0, 0}); + } + } + }, + [&](const ton_api::liteserver_descV2_sliceTimed& s) { + auto parse_shards = + [](const std::vector>& shard_objs, + std::vector& shards) -> td::Status { + if (shard_objs.empty()) { + return td::Status::OK(); + } + size_t i = 0; + int mc_idx = -1; + for (const auto& shard_obj : shard_objs) { + ShardIdFull shard_id = create_shard_id(shard_obj->shard_id_); + if (!shard_id.is_valid_ext()) { + return td::Status::Error(PSTRING() << "invalid shard id " << shard_id.to_str()); + } + if (shard_id.is_masterchain()) { + shard_id = ShardIdFull{masterchainId}; + if (mc_idx != -1) { + return td::Status::Error("duplicate masterchain shard in sliceTimed"); + } + mc_idx = (int)i; + } + shards.push_back({shard_id, (BlockSeqno)shard_obj->seqno_, (UnixTime)shard_obj->utime_, + (LogicalTime)shard_obj->lt_}); + ++i; + } + if (mc_idx == -1) { + return td::Status::Error("no masterchain shard in sliceTimed"); + } + std::swap(shards[0], shards[mc_idx]); + return td::Status::OK(); + }; + S = parse_shards(s.shards_from_, slice.shards_from); + if (S.is_ok()) { + S = parse_shards(s.shards_to_, slice.shards_to); + } + if (S.is_ok() && slice.shards_from.empty() && slice.shards_to.empty()) { + S = td::Status::Error("shards_from and shards_to are both empty"); + } + })); + TRY_STATUS(std::move(S)); + server.slices.push_back(slice); + } + + servers.push_back(std::move(server)); + } + return servers; +} + +} // namespace liteclient \ No newline at end of file diff --git a/lite-client/query-utils.hpp b/lite-client/query-utils.hpp new file mode 100644 index 00000000..28500e26 --- /dev/null +++ b/lite-client/query-utils.hpp @@ -0,0 +1,89 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + TON Blockchain Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . +*/ +#pragma once +#include "ton/ton-types.h" +#include "auto/tl/lite_api.h" +#include "td/utils/port/IPAddress.h" +#include "adnl/adnl-node-id.hpp" + +namespace liteclient { + +struct QueryInfo { + enum Type { t_simple, t_seqno, t_utime, t_lt, t_mc_seqno }; + int query_id = 0; + ton::ShardIdFull shard_id{ton::masterchainId}; + Type type = t_simple; + td::uint64 value = 0; + /* Query types and examples: + * t_simple - query to the recent blocks in a shard, or general info. value = 0. + * getTime, getMasterchainInfo (shard_id = masterchain) + * sendMessage + * getAccountState, runSmcMethod - when no block is given + * t_seqno - query to block with seqno in a shard. value = seqno. + * lookupBlock by seqno + * getBlock, getBlockHeader + * getAccountState, runSmcMethod - when shard block is given + * t_utime - query to a block with given unixtime in a shard. value = utime. + * lookupBlock by utime + * t_lt - query to a block with given lt in a shard. value = lt. + * lookupBlock by lt + * getTransactions + * t_mc_seqno - query to a block in a shard, masterchain seqno is given. value = mc_seqno. + * getAccountState, runSmcMethod - when mc block is given + */ + + std::string to_str() const; +}; + +QueryInfo get_query_info(td::Slice data); +QueryInfo get_query_info(const ton::lite_api::Function& f); + +struct LiteServerConfig { + private: + struct ShardInfo { + ton::ShardIdFull shard_id; + ton::BlockSeqno seqno; + ton::UnixTime utime; + ton::LogicalTime lt; + }; + + struct Slice { + std::vector shards_from, shards_to; + bool unlimited = false; + + bool accepts_query(const QueryInfo& query_info) const; + }; + + bool is_full = false; + std::vector slices; + + public: + ton::adnl::AdnlNodeIdFull adnl_id; + td::IPAddress addr; + + LiteServerConfig() = default; + LiteServerConfig(ton::adnl::AdnlNodeIdFull adnl_id, td::IPAddress addr) + : is_full(true), adnl_id(adnl_id), addr(addr) { + } + + bool accepts_query(const QueryInfo& query_info) const; + + static td::Result> parse_global_config( + const ton::ton_api::liteclient_config_global& config); +}; + +} // namespace liteclient diff --git a/tl-utils/common-utils.hpp b/tl-utils/common-utils.hpp index d61bd79c..05f8a825 100644 --- a/tl-utils/common-utils.hpp +++ b/tl-utils/common-utils.hpp @@ -148,6 +148,39 @@ td::Result::value, T>>> } } +template +td::Result::value, T>>> fetch_tl_prefix(td::Slice &data, + bool boxed) { + td::TlParser p(data); + tl_object_ptr R; + if (boxed) { + R = TlFetchBoxed, T::ID>::parse(p); + } else { + R = move_tl_object_as(T::fetch(p)); + } + if (p.get_status().is_ok()) { + data.remove_prefix(data.size() - p.get_left_len()); + return std::move(R); + } else { + return p.get_status(); + } +} + +template +td::Result::value, T>>> fetch_tl_prefix(td::Slice &data, + bool boxed) { + CHECK(boxed); + td::TlParser p(data); + tl_object_ptr R; + R = move_tl_object_as(T::fetch(p)); + if (p.get_status().is_ok()) { + data.remove_prefix(data.size() - p.get_left_len()); + return std::move(R); + } else { + return p.get_status(); + } +} + template [[deprecated]] tl_object_ptr clone_tl_object(const tl_object_ptr &obj) { auto B = serialize_tl_object(obj, true); diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl index 0d7f1249..3a46406f 100644 --- a/tl/generate/scheme/ton_api.tl +++ b/tl/generate/scheme/ton_api.tl @@ -588,8 +588,12 @@ dummyworkchain0.config.global zero_state_hash:int256 = dummyworkchain0.config.Gl validator.config.global zero_state:tonNode.blockIdExt init_block:tonNode.blockIdExt hardforks:(vector tonNode.blockIdExt) = validator.config.Global; config.global adnl:adnl.config.global dht:dht.config.Global validator:validator.config.global = config.Global; +liteserver.descV2.sliceSimple shards:(vector tonNode.shardId) = liteserver.descV2.Slice; +liteserver.descV2.shardInfo shard_id:tonNode.shardId seqno:int utime:int lt:long = liteserver.descV2.ShardInfo; +liteserver.descV2.sliceTimed shards_from:(vector liteserver.descV2.shardInfo) shards_to:(vector liteserver.descV2.shardInfo) = liteserver.descV2.Slice; + liteserver.desc id:PublicKey ip:int port:int = liteserver.Desc; -liteserver.descV2 id:PublicKey ip:int port:int shards:(vector tonNode.shardId) = liteserver.DescV2; +liteserver.descV2 id:PublicKey ip:int port:int slices:(vector liteserver.descV2.Slice) = liteserver.DescV2; liteclient.config.global liteservers:(vector liteserver.desc) liteservers_v2:(vector liteserver.descV2) validator:validator.config.global = liteclient.config.Global; engine.adnl id:int256 category:int = engine.Adnl; diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo index 0d286bdc..77bcff0c 100644 Binary files a/tl/generate/scheme/ton_api.tlo and b/tl/generate/scheme/ton_api.tlo differ diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index 95c9e74d..a6172376 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -190,7 +190,7 @@ smc.libraryQueryExt.one hash:int256 = smc.LibraryQueryExt; smc.libraryQueryExt.scanBoc boc:bytes max_libs:int32 = smc.LibraryQueryExt; smc.libraryResultExt dict_boc:bytes libs_ok:(vector int256) libs_not_found:(vector int256) = smc.LibraryResultExt; -updateSendLiteServerQuery id:int64 data:bytes workchain:int32 shard:int64 = Update; +updateSendLiteServerQuery id:int64 data:bytes = Update; updateSyncState sync_state:SyncState = Update; //@class LogStream @description Describes a stream to which tonlib internal log is written diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index d2da9621..7657852e 100644 Binary files a/tl/generate/scheme/tonlib_api.tlo and b/tl/generate/scheme/tonlib_api.tlo differ diff --git a/tonlib/tonlib/Config.cpp b/tonlib/tonlib/Config.cpp index 73d4e033..0f317f94 100644 --- a/tonlib/tonlib/Config.cpp +++ b/tonlib/tonlib/Config.cpp @@ -19,6 +19,7 @@ #include "Config.h" #include "adnl/adnl-node-id.hpp" #include "td/utils/JsonBuilder.h" +#include "auto/tl/ton_api_json.h" namespace tonlib { td::Result parse_block_id_ext(td::JsonObject &obj) { @@ -65,67 +66,11 @@ td::Result Config::parse(std::string str) { if (json.type() != td::JsonValue::Type::Object) { return td::Status::Error("Invalid config (1)"); } - td::JsonArray empty_array; - TRY_RESULT(lite_servers_obj, - td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, true)); - auto &lite_servers = - lite_servers_obj.type() == td::JsonValue::Type::Array ? lite_servers_obj.get_array() : empty_array; - TRY_RESULT(lite_servers_v2_obj, - td::get_json_object_field(json.get_object(), "liteservers_v2", td::JsonValue::Type::Array, true)); - auto &lite_servers_v2 = - lite_servers_v2_obj.type() == td::JsonValue::Type::Array ? lite_servers_v2_obj.get_array() : empty_array; - - auto parse_desc = [&](td::JsonValue &value) -> td::Result { - if (value.type() != td::JsonValue::Type::Object) { - return td::Status::Error("Invalid config (2)"); - } - auto &object = value.get_object(); - - TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false)); - TRY_RESULT(port, td::get_json_object_int_field(object, "port", false)); - Config::LiteServer server; - TRY_STATUS(server.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast(ip)), port)); - - TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false)); - auto &id = id_obj.get_object(); - TRY_RESULT(id_type, td::get_json_object_string_field(id, "@type", false)); - if (id_type != "pub.ed25519") { - return td::Status::Error("Invalid config (3)"); - } - TRY_RESULT(key_base64, td::get_json_object_string_field(id, "key", false)); - TRY_RESULT(key, td::base64_decode(key_base64)); - if (key.size() != 32) { - return td::Status::Error("Invalid config (4)"); - } - - server.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin()))); - return server; - }; Config res; - for (auto &value : lite_servers) { - TRY_RESULT(server, parse_desc(value)); - res.lite_servers.push_back(std::move(server)); - } - for (auto &value : lite_servers_v2) { - TRY_RESULT(server, parse_desc(value)); - server.is_full = false; - TRY_RESULT(shards_obj, td::get_json_object_field(value.get_object(), "shards", td::JsonValue::Type::Array, false)); - for (auto &shard : shards_obj.get_array()) { - if (shard.type() != td::JsonValue::Type::Object) { - return td::Status::Error("Invalid config (5)"); - } - auto &shard_obj = shard.get_object(); - TRY_RESULT(workchain, td::get_json_object_int_field(shard_obj, "workchain", false)); - TRY_RESULT(shard_id, td::get_json_object_long_field(shard_obj, "shard", false)); - if (shard_id == 0) { - return td::Status::Error("Invalid config (6)"); - } - server.shards.emplace_back(workchain, shard_id); - } - - res.lite_servers.push_back(std::move(server)); - } + ton::ton_api::liteclient_config_global conf; + TRY_STATUS(ton::ton_api::from_json(conf, json.get_object())); + TRY_RESULT_ASSIGN(res.lite_servers, liteclient::LiteServerConfig::parse_global_config(conf)); TRY_RESULT(validator_obj, td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false)); diff --git a/tonlib/tonlib/Config.h b/tonlib/tonlib/Config.h index 5ae304ea..28f23881 100644 --- a/tonlib/tonlib/Config.h +++ b/tonlib/tonlib/Config.h @@ -24,11 +24,10 @@ namespace tonlib { struct Config { - using LiteServer = liteclient::ExtClient::LiteServer; ton::BlockIdExt zero_state_id; ton::BlockIdExt init_block_id; std::vector hardforks; - std::vector lite_servers; + std::vector lite_servers; std::string name; static td::Result parse(std::string str); }; diff --git a/tonlib/tonlib/ExtClient.cpp b/tonlib/tonlib/ExtClient.cpp index f0c84d61..b66ca25c 100644 --- a/tonlib/tonlib/ExtClient.cpp +++ b/tonlib/tonlib/ExtClient.cpp @@ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise promise) { td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P)); } -void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise promise) { +void ExtClient::send_raw_query(td::BufferSlice query, td::Promise promise) { auto query_id = queries_.create(std::move(promise)); td::Promise P = [query_id, self = this, actor_id = td::actor::actor_id()](td::Result result) { @@ -66,6 +66,6 @@ void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td return P.set_error(TonlibError::NoLiteServers()); } td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::send_query, "query", std::move(query), - shard, td::Timestamp::in(10.0), std::move(P)); + td::Timestamp::in(10.0), std::move(P)); } } // namespace tonlib diff --git a/tonlib/tonlib/ExtClient.h b/tonlib/tonlib/ExtClient.h index 9db040bb..b0194c18 100644 --- a/tonlib/tonlib/ExtClient.h +++ b/tonlib/tonlib/ExtClient.h @@ -31,7 +31,6 @@ #include "lite-client/ext-client.h" #include "TonlibError.h" #include "utils.h" -#include "lite-client/QueryTraits.h" namespace tonlib { class LastBlock; @@ -65,7 +64,6 @@ class ExtClient { template void send_query(QueryT query, td::Promise promise, td::int32 seq_no = -1) { - ton::ShardIdFull shard = liteclient::QueryTraits::get_shard(query); auto raw_query = ton::serialize_tl_object(&query, true); td::uint32 tag = td::Random::fast_uint32(); VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query); @@ -79,7 +77,7 @@ class ExtClient { ton::serialize_tl_object(ton::create_tl_object(std::move(raw_query)), true); send_raw_query( - std::move(liteserver_query), shard, [promise = std::move(promise), tag](td::Result R) mutable { + std::move(liteserver_query), [promise = std::move(promise), tag](td::Result R) mutable { auto res = [&]() -> td::Result { TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork()); auto r_error = ton::fetch_tl_object(data.clone(), true); @@ -99,7 +97,7 @@ class ExtClient { void force_change_liteserver() { if (!client_.adnl_ext_client_.empty()) { - td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::force_change_liteserver); + td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::reset_servers); } } @@ -109,6 +107,6 @@ class ExtClient { td::Container> last_block_queries_; td::Container> last_config_queries_; - void send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise promise); + void send_raw_query(td::BufferSlice query, td::Promise promise); }; } // namespace tonlib diff --git a/tonlib/tonlib/ExtClientOutbound.cpp b/tonlib/tonlib/ExtClientOutbound.cpp index eb923734..e5fac8b4 100644 --- a/tonlib/tonlib/ExtClientOutbound.cpp +++ b/tonlib/tonlib/ExtClientOutbound.cpp @@ -28,14 +28,11 @@ class ExtClientOutboundImpl : public ExtClientOutbound { ExtClientOutboundImpl(td::unique_ptr callback) : callback_(std::move(callback)) { } - void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout, + void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, td::Promise promise) override { auto query_id = next_query_id_++; queries_[query_id] = std::move(promise); - callback_->request(query_id, data.as_slice().str(), shard); - } - - void force_change_liteserver() override { + callback_->request(query_id, data.as_slice().str()); } void on_query_result(td::int64 id, td::Result r_data, td::Promise promise) override { diff --git a/tonlib/tonlib/ExtClientOutbound.h b/tonlib/tonlib/ExtClientOutbound.h index 6eb6aa98..bf52c8c2 100644 --- a/tonlib/tonlib/ExtClientOutbound.h +++ b/tonlib/tonlib/ExtClientOutbound.h @@ -27,9 +27,8 @@ class ExtClientOutbound : public liteclient::ExtClient { public: virtual ~Callback() { } - virtual void request(td::int64 id, std::string data, ton::ShardIdFull shard) = 0; + virtual void request(td::int64 id, std::string data) = 0; }; - virtual void on_query_result(td::int64 id, td::Result r_data, td::Promise promise) = 0; static td::actor::ActorOwn create(td::unique_ptr callback); }; diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 3dda7fea..13a69594 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -2078,9 +2078,8 @@ ExtClientRef TonlibClient::get_client_ref() { return ref; } -void TonlibClient::proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard) { - on_update( - tonlib_api::make_object(query_id, data, shard.workchain, shard.shard)); +void TonlibClient::proxy_request(td::int64 query_id, std::string data) { + on_update(tonlib_api::make_object(query_id, data)); } void TonlibClient::init_ext_client() { @@ -2091,9 +2090,9 @@ void TonlibClient::init_ext_client() { : parent_(std::move(parent)), config_generation_(config_generation) { } - void request(td::int64 id, std::string data, ton::ShardIdFull shard) override { - send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), std::move(data), - shard); + void request(td::int64 id, std::string data) override { + send_closure(parent_, &TonlibClient::proxy_request, (id << 16) | (config_generation_ & 0xffff), + std::move(data)); } private: @@ -2106,17 +2105,8 @@ void TonlibClient::init_ext_client() { ext_client_outbound_ = client.get(); raw_client_ = std::move(client); } else { - class Callback : public liteclient::ExtClient::Callback { - public: - explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) { - } - - private: - td::actor::ActorShared<> parent_; - }; ext_client_outbound_ = {}; - ref_cnt_++; - raw_client_ = liteclient::ExtClient::create(config_.lite_servers, td::make_unique(td::actor::actor_shared())); + raw_client_ = liteclient::ExtClient::create(config_.lite_servers, nullptr); } } @@ -4491,8 +4481,8 @@ void deep_library_search(std::set& set, std::set& v } return; } - for (unsigned int i = 0; i < loaded_cell.data_cell->get_refs_cnt(); i++) { - deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1); + for (unsigned int i=0; iget_refs_cnt(); i++) { + deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1, max_libs); } } diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 32731e4e..973ede94 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -401,7 +401,7 @@ class TonlibClient : public td::actor::Actor { td::Status do_request(const tonlib_api::getConfigAll& request, td::Promise>&& promise); - void proxy_request(td::int64 query_id, std::string data, ton::ShardIdFull shard); + void proxy_request(td::int64 query_id, std::string data); void load_libs_from_disk(); void store_libs_to_disk(); diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index ba44481f..eb0f5af4 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -1541,7 +1541,7 @@ class TonlibCli : public td::actor::Actor { CHECK(!raw_client_.empty()); snd_bytes_ += update->data_.size(); send_closure(raw_client_, &liteclient::ExtClient::send_query, "query", td::BufferSlice(update->data_), - ton::ShardIdFull(update->workchain_, update->shard_), td::Timestamp::in(5), + td::Timestamp::in(5), [actor_id = actor_id(this), id = update->id_](td::Result res) { send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res)); }); diff --git a/utils/proxy-liteserver.cpp b/utils/proxy-liteserver.cpp index 7abaa1c7..66161fc4 100644 --- a/utils/proxy-liteserver.cpp +++ b/utils/proxy-liteserver.cpp @@ -29,50 +29,71 @@ #include "td/utils/OptionParser.h" #include "td/utils/port/path.h" #include "td/utils/port/signals.h" -#include "td/utils/port/user.h" #include "td/utils/port/IPAddress.h" #include "td/utils/Random.h" #include "td/utils/FileLog.h" #include "git.h" #include "auto/tl/ton_api.h" #include "auto/tl/lite_api.h" -#include "auto/tl/lite_api.hpp" #include "tl-utils/lite-utils.hpp" -#include "ton/lite-tl.hpp" #include "auto/tl/ton_api_json.h" #include "adnl/adnl.h" -#include "lite-client/QueryTraits.h" #include "lite-client/ext-client.h" #if TD_DARWIN || TD_LINUX #include #endif #include +#include using namespace ton; class ProxyLiteserver : public td::actor::Actor { public: - ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port) - : global_config_(std::move(global_config)), db_root_(std::move(db_root)), port_(port) { + ProxyLiteserver(std::string global_config, std::string db_root, td::uint16 port, PublicKeyHash public_key_hash) + : global_config_(std::move(global_config)) + , db_root_(std::move(db_root)) + , port_(port) + , public_key_hash_(public_key_hash) { } void start_up() override { - LOG_CHECK(db_root_ != "") << "db root is not set"; + LOG_CHECK(!db_root_.empty()) << "db root is not set"; td::mkdir(db_root_).ensure(); db_root_ = td::realpath(db_root_).move_as_ok(); keyring_ = keyring::Keyring::create(db_root_ + "/keyring"); + if (public_key_hash_.is_zero()) { + id_ = {}; + run(); + } else { + td::actor::send_closure(keyring_, &keyring::Keyring::get_public_key, public_key_hash_, + [SelfId = actor_id(this)](td::Result R) mutable { + if (R.is_error()) { + LOG(FATAL) << "Failed to load public key: " << R.move_as_error(); + } + td::actor::send_closure(SelfId, &ProxyLiteserver::got_public_key, R.move_as_ok()); + }); + } + } + + void got_public_key(PublicKey pub) { + id_ = adnl::AdnlNodeIdFull{pub}; + run(); + } + + void run() { td::Status S = prepare_local_config(); if (S.is_error()) { LOG(FATAL) << "Local config error: " << S; } - S = create_ext_client(); + S = parse_global_config(); if (S.is_error()) { LOG(FATAL) << S; } + run_clients(); create_ext_server(); } @@ -82,73 +103,123 @@ class ProxyLiteserver : public td::actor::Actor { auto conf_data = r_conf_data.move_as_ok(); TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: "); TRY_STATUS_PREFIX(ton_api::from_json(*config_, conf_json.get_object()), "json does not fit TL scheme: "); - TRY_RESULT_PREFIX_ASSIGN(port_, td::narrow_cast_safe(config_->port_), "invalid port: "); - TRY_RESULT_PREFIX_ASSIGN(id_, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: "); + TRY_RESULT_PREFIX(cfg_port, td::narrow_cast_safe(config_->port_), "invalid port: "); + TRY_RESULT_PREFIX(cfg_id, adnl::AdnlNodeIdFull::create(config_->id_), "invalid id: "); + bool rewrite_config = false; + if (port_ == 0) { + port_ = cfg_port; + } else { + rewrite_config |= (port_ != cfg_port); + } + if (id_.empty()) { + id_ = std::move(cfg_id); + } else { + rewrite_config |= (id_ != cfg_id); + } + if (!rewrite_config) { + return td::Status::OK(); + } } else { LOG(WARNING) << "First launch, creating local config"; - if (port_ == 0) { - return td::Status::Error("port is not set"); - } - config_->port_ = port_; + } + if (port_ == 0) { + return td::Status::Error("port is not set"); + } + config_->port_ = port_; + if (id_.empty()) { auto pk = PrivateKey{privkeys::Ed25519::random()}; id_ = adnl::AdnlNodeIdFull{pk.compute_public_key()}; - config_->id_ = id_.tl(); td::actor::send_closure(keyring_, &keyring::Keyring::add_key, std::move(pk), false, [](td::Result R) { if (R.is_error()) { LOG(FATAL) << "Failed to store private key"; } }); + } + config_->id_ = id_.tl(); - auto s = td::json_encode(td::ToJson(*config_), true); - TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: "); + auto s = td::json_encode(td::ToJson(*config_), true); + TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: "); + LOG(WARNING) << "Writing config.json"; + return td::Status::OK(); + } + + td::Status parse_global_config() { + TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: "); + TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()), + "Failed to parse global config: "); + ton_api::liteclient_config_global gc; + TRY_STATUS_PREFIX(ton_api::from_json(gc, global_config_json.get_object()), "Failed to parse global config: "); + TRY_RESULT_PREFIX(servers, liteclient::LiteServerConfig::parse_global_config(gc), + "Falied to parse liteservers in global config: "); + if (servers.empty()) { + return td::Status::Error("No liteservers in global config"); + } + for (auto& s : servers) { + servers_.emplace_back(); + servers_.back().config = std::move(s); } return td::Status::OK(); } - td::Status create_ext_client() { - std::vector servers; - TRY_RESULT_PREFIX(global_config_data, td::read_file(global_config_), "Failed to read global config: "); - TRY_RESULT_PREFIX(global_config_json, td::json_decode(global_config_data.as_slice()), - "Failed to parse global config: "); - ton::ton_api::liteclient_config_global gc; - ton::ton_api::from_json(gc, global_config_json.get_object()).ensure(); - - size_t size = gc.liteservers_.size() + gc.liteservers_v2_.size(); - if (size == 0) { - return td::Status::Error("No liteservers in global config"); - } - - for (auto& s : gc.liteservers_) { - td::IPAddress addr; - addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); - liteclient::ExtClient::LiteServer serv; - serv.address = addr; - serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); - servers.push_back(std::move(serv)); - } - for (auto& s : gc.liteservers_v2_) { - td::IPAddress addr; - addr.init_host_port(td::IPAddress::ipv4_to_str(s->ip_), s->port_).ensure(); - liteclient::ExtClient::LiteServer serv; - serv.address = addr; - serv.adnl_id = ton::adnl::AdnlNodeIdFull::create(s->id_).move_as_ok(); - serv.is_full = false; - for (auto& shard : s->shards_) { - serv.shards.emplace_back(shard->workchain_, (ton::ShardId)shard->shard_); - CHECK(serv.shards.back().is_valid_ext()); + void run_clients() { + class Callback : public adnl::AdnlExtClient::Callback { + public: + explicit Callback(td::actor::ActorId id, size_t idx) : id_(std::move(id)), idx_(idx) { } - servers.push_back(std::move(serv)); + void on_ready() override { + td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, true); + } + void on_stop_ready() override { + td::actor::send_closure(id_, &ProxyLiteserver::on_client_status, idx_, false); + } + + private: + td::actor::ActorId id_; + size_t idx_; + }; + + for (size_t i = 0; i < servers_.size(); ++i) { + Server& server = servers_[i]; + server.client = adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr, + std::make_unique(actor_id(this), i)); + server.alive = false; } - class Callback : public liteclient::ExtClient::Callback {}; - ext_client_ = liteclient::ExtClient::create(std::move(servers), td::make_unique()); - return td::Status::OK(); + } + + void on_client_status(size_t idx, bool ready) { + Server& server = servers_[idx]; + if (server.alive == ready) { + return; + } + server.alive = ready; + LOG(WARNING) << (ready ? "Connected to" : "Disconnected from") << " server #" << idx << " (" + << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; } void create_ext_server() { adnl_ = adnl::Adnl::create("", keyring_.get()); - td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, ton::adnl::AdnlAddressList{}, (td::uint8)255); - td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, - std::vector{id_.compute_short_id()}, std::vector{port_}, + td::actor::send_closure(adnl_, &adnl::Adnl::add_id, id_, adnl::AdnlAddressList{}, (td::uint8)255); + + class AdnlCallback : public adnl::Adnl::Callback { + public: + explicit AdnlCallback(td::actor::ActorId id) : id_(id) { + } + + void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override { + } + void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, + td::Promise promise) override { + td::actor::send_closure(id_, &ProxyLiteserver::receive_query, std::move(data), std::move(promise)); + } + + private: + td::actor::ActorId id_; + }; + td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(), + adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID), + std::make_unique(actor_id(this))); + td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, std::vector{id_.compute_short_id()}, + std::vector{port_}, [SelfId = actor_id(this)](td::Result> R) { R.ensure(); td::actor::send_closure(SelfId, &ProxyLiteserver::created_ext_server, R.move_as_ok()); @@ -158,93 +229,72 @@ class ProxyLiteserver : public td::actor::Actor { void created_ext_server(td::actor::ActorOwn s) { ext_server_ = std::move(s); LOG(WARNING) << "Started proxy liteserver on port " << port_; - - class AdnlCallback : public adnl::Adnl::Callback { - public: - AdnlCallback(td::actor::ActorId client) : client_(client) { - } - - void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override { - } - void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, - td::Promise promise) override { - td::actor::create_actor("worker", client_, std::move(data), std::move(promise)).release(); - } - - private: - td::actor::ActorId client_; - }; - td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, id_.compute_short_id(), - adnl::Adnl::int_to_bytestring(lite_api::liteServer_query::ID), - std::make_unique(ext_client_.get())); + alarm(); } - class QueryWorker : public td::actor::Actor { - public: - QueryWorker(td::actor::ActorId client, td::BufferSlice data, - td::Promise promise) - : client_(std::move(client)), data_(std::move(data)), promise_(std::move(promise)) { - } - - void start_up() override { - auto data = data_.clone(); - auto F = fetch_tl_object(data, true); - if (F.is_ok()) { - data = std::move(F.move_as_ok()->data_); - } else { - auto G = fetch_tl_prefix(data, true); - if (G.is_error()) { - fatal_error(G.move_as_error()); - return; - } + td::Result select_server(const liteclient::QueryInfo& query_info) { + size_t best_idx = servers_.size(); + int cnt = 0; + for (size_t i = 0; i < servers_.size(); ++i) { + Server& server = servers_[i]; + if (!server.alive || !server.config.accepts_query(query_info)) { + continue; } - fetch_tl_prefix(data, true).ignore(); - auto F2 = fetch_tl_object(std::move(data), true); - if (F2.is_error()) { - fatal_error(F2.move_as_error()); + ++cnt; + if (td::Random::fast(1, cnt) == 1) { + best_idx = i; + } + } + if (best_idx == servers_.size()) { + return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str()); + } + return best_idx; + } + + void receive_query(td::BufferSlice data, td::Promise promise) { + liteclient::QueryInfo query_info = liteclient::get_query_info(data); + ++ls_stats_[query_info.query_id]; + promise = [promise = std::move(promise), query_info, timer = td::Timer()](td::Result R) mutable { + if (R.is_ok()) { + LOG(INFO) << "Query " << query_info.to_str() << ": OK, time=" << timer.elapsed() + << ", response_size=" << R.ok().size(); + promise.set_value(R.move_as_ok()); return; } - auto query = F2.move_as_ok(); - lite_api::downcast_call(*query, [&](auto& obj) { shard_ = liteclient::get_query_shard(obj); }); + LOG(INFO) << "Query " << query_info.to_str() << ": " << R.error(); + promise.set_value(create_serialize_tl_object( + R.error().code(), "Gateway error: " + R.error().message().str())); + }; + TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info)); - LOG(INFO) << "Got query: shard=" << shard_.to_str() << " size=" << data_.size(); - td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "q", std::move(data_), shard_, - td::Timestamp::in(8.0), [SelfId = actor_id(this)](td::Result R) { - td::actor::send_closure(SelfId, &QueryWorker::got_result, std::move(R)); - }); - } + Server& server = servers_[server_idx]; + LOG(INFO) << "Sending query " << query_info.to_str() << ", size=" << data.size() << ", to server #" << server_idx + << " (" << server.config.addr.get_ip_str() << ":" << server.config.addr.get_port() << ")"; + td::actor::send_closure(server.client, &adnl::AdnlExtClient::send_query, "q", std::move(data), + td::Timestamp::in(8.0), std::move(promise)); + } - void got_result(td::Result R) { - if (R.is_error()) { - LOG(INFO) << "Query to shard=" << shard_.to_str() << ": " << R.error(); - promise_.set_value(create_serialize_tl_object( - R.error().code(), "gateway error: " + R.error().message().str())); - } else { - td::BufferSlice response = R.move_as_ok(); - LOG(INFO) << "Query to shard=" << shard_.to_str() << ": OK, size=" << response.size() - << " time=" << timer_.elapsed(); - promise_.set_value(std::move(response)); + void alarm() override { + alarm_timestamp() = td::Timestamp::in(60.0); + if (!ls_stats_.empty()) { + td::StringBuilder sb; + sb << "Liteserver stats (1 minute):"; + td::uint32 total = 0; + for (const auto& p : ls_stats_) { + sb << " " << lite_query_name_by_id(p.first) << ":" << p.second; + total += p.second; } - stop(); + sb << " TOTAL:" << total; + LOG(WARNING) << sb.as_cslice(); + ls_stats_.clear(); } - - void fatal_error(td::Status S) { - promise_.set_error(std::move(S)); - stop(); - } - - private: - td::actor::ActorId client_; - td::BufferSlice data_; - td::Promise promise_; - td::Timer timer_ = {}; - ShardIdFull shard_; - }; + } private: std::string global_config_; std::string db_root_; td::uint16 port_; + PublicKeyHash public_key_hash_; tl_object_ptr config_ = create_tl_object(); adnl::AdnlNodeIdFull id_; @@ -252,7 +302,15 @@ class ProxyLiteserver : public td::actor::Actor { td::actor::ActorOwn keyring_; td::actor::ActorOwn adnl_; td::actor::ActorOwn ext_server_; - td::actor::ActorOwn ext_client_; + + struct Server { + liteclient::LiteServerConfig config; + td::actor::ActorOwn client; + bool alive = false; + }; + std::vector servers_; + + std::map ls_stats_; // lite_api ID -> count, 0 for unknown std::string config_file() const { return db_root_ + "/config.json"; @@ -270,6 +328,7 @@ int main(int argc, char* argv[]) { std::string global_config, db_root; td::uint16 port = 0; + PublicKeyHash public_key_hash = PublicKeyHash::zero(); td::uint32 threads = 4; td::OptionParser p; @@ -290,15 +349,27 @@ int main(int argc, char* argv[]) { std::cout << sb.as_cslice().c_str(); std::exit(2); }); - p.add_checked_option('p', "port", "liteserver port (use only on first launch)", [&](td::Slice arg) -> td::Status { - TRY_RESULT_ASSIGN(port, td::to_integer_safe(arg)); - return td::Status::OK(); - }); + p.add_checked_option('p', "port", "liteserver port (required only on first launch)", + [&](td::Slice arg) -> td::Status { + TRY_RESULT_ASSIGN(port, td::to_integer_safe(arg)); + return td::Status::OK(); + }); + p.add_checked_option( + 'A', "adnl-id", + "liteserver public key hash in hex (optional). The corresponding private key is required in /keyring/", + [&](td::Slice arg) -> td::Status { + td::Bits256 value; + if (value.from_hex(arg) != 256) { + return td::Status::Error("invalid adnl-id"); + } + public_key_hash = PublicKeyHash{value}; + return td::Status::OK(); + }); p.add_option('C', "global-config", "global TON configuration file", [&](td::Slice arg) { global_config = arg.str(); }); p.add_option('D', "db", "db root", [&](td::Slice arg) { db_root = arg.str(); }); p.add_option('d', "daemonize", "set SIGHUP", [&]() { - td::set_signal_handler(td::SignalType::HangUp, [](int sig) { + td::set_signal_handler(td::SignalType::HangUp, [](int) { #if TD_DARWIN || TD_LINUX close(0); setsid(); @@ -318,8 +389,10 @@ int main(int argc, char* argv[]) { p.run(argc, argv).ensure(); td::actor::Scheduler scheduler({threads}); - scheduler.run_in_context( - [&] { td::actor::create_actor("proxy-liteserver", global_config, db_root, port).release(); }); + scheduler.run_in_context([&] { + td::actor::create_actor("proxy-liteserver", global_config, db_root, port, public_key_hash) + .release(); + }); while (scheduler.run(1)) { } }