1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +00:00

New liteserver config format

* Specify shards and seqno/utime/lt limits for liteservers in global config
* Support in lite-client, tonlib, blockchain-explorer
* Rework proxy-liteserver
This commit is contained in:
SpyCheese 2024-06-12 18:12:45 +03:00
parent 38ab70c037
commit 007f1fb1d7
26 changed files with 1187 additions and 1130 deletions

View file

@ -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::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_));
auto query = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> 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::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_));
auto query = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getBlock>(ton::create_tl_lite_block_id(block_id_)), true);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> 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::lite_api::liteServer_getBlockHeader>(ton::create_tl_lite_block_id(block_id_), 0);
auto query = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getBlockHeader>(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::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_));
auto query_2 = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(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::lite_api::liteServer_listBlockTransactions>(
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::lite_api::liteServer_listBlockTransactions>(
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<td::BufferSlice> 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::lite_api::liteServer_listBlockTransactions>(
ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false);
auto query_3 = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
true);
auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> 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<ton::lite_api::liteServer_lookupBlock>(
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<ton::lite_api::liteServer_lookupBlock>(
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::lite_api::liteServer_getAllShardsInfo>(ton::create_tl_lite_block_id(block_id_));
auto query_2 = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getAllShardsInfo>(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::lite_api::liteServer_listBlockTransactions>(
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::lite_api::liteServer_listBlockTransactions>(
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<td::BufferSlice> 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::lite_api::liteServer_listBlockTransactions>(
ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false);
auto query_3 = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_listBlockTransactions>(
ton::create_tl_lite_block_id(block_id_), 7 + 128, 1024,
ton::create_tl_object<ton::lite_api::liteServer_transactionId3>(T.addr.addr, T.lt), false, false),
true);
auto P_3 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> 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<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
auto query = ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(ton::create_tl_lite_block_id(block_id_),
std::move(a));
auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
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<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
auto query = ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(1, std::move(a), lt_, hash_);
auto query = ton::serialize_tl_object(
ton::create_tl_object<ton::lite_api::liteServer_getTransactions>(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<ton::lite_api::liteServer_accountId>(addr_.workchain, addr_.addr);
auto query = ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
ton::create_tl_lite_block_id(block_id_), std::move(a), lt_);
auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getOneTransaction>(
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<ton::lite_api::liteServer_getMasterchainInfo>();
auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), 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<ton::lite_api::liteServer_getMasterchainInfo>();
auto query = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), 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<ton::lite_api::liteServer_getConfigParams>(
0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(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<ton::lite_api::liteServer_getConfigAll>(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<ton::lite_api::liteServer_getConfigParams>(
0, ton::create_tl_lite_block_id(block_id_), std::vector<int>(params_)),
true)
: ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigAll>(
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<ton::lite_api::liteServer_sendMessage>(std::move(data_));
auto query =
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_sendMessage>(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<ton::lite_api::liteServer_runSmcMethod>(
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<ton::lite_api::liteServer_runSmcMethod>(
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) {

View file

@ -155,8 +155,6 @@ class CoreActor : public CoreActorInterface {
td::int32 attempt_ = 0;
td::int32 waiting_ = 0;
std::vector<bool> ready_;
//void run_queries();
void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
@ -189,12 +187,6 @@ class CoreActor : public CoreActorInterface {
static CoreActor* instance_;
td::actor::ActorId<CoreActor> 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<td::BufferSlice> promise) override;
void send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) override;
void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override {
}
void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override {
@ -439,50 +431,24 @@ class CoreActor : public CoreActorInterface {
}
void run() {
std::vector<liteclient::ExtClient::LiteServer> servers;
std::vector<liteclient::LiteServerConfig> 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<td::uint16>(http_port_), nullptr, nullptr,
@ -545,7 +511,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::Buf
}
}*/
void CoreActor::send_lite_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
void CoreActor::send_lite_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> 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<ton::lite_api::liteServer_query>(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));
}

View file

@ -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<td::BufferSlice> promise) = 0;
virtual void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
virtual void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) = 0;
virtual void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) = 0;

View file

@ -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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <typename Query>
struct QueryTraits {
static ton::ShardIdFull get_shard(const Query& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfo> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfo& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getMasterchainInfoExt> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getMasterchainInfoExt& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getTime> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getTime& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getVersion> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getVersion& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getBlock> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlock& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getState> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getState& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getBlockHeader> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockHeader& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_sendMessage> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_sendMessage& q) {
auto shard = [&]() -> td::Result<ton::ShardIdFull> {
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<ton::lite_api::liteServer_getAccountState> {
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<ton::lite_api::liteServer_getAccountStatePrunned> {
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<ton::lite_api::liteServer_runSmcMethod> {
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<ton::lite_api::liteServer_getShardInfo> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardInfo& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getAllShardsInfo> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getAllShardsInfo& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getOneTransaction> {
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<ton::lite_api::liteServer_getTransactions> {
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<ton::lite_api::liteServer_lookupBlock> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_lookupBlock& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_listBlockTransactions> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactions& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_listBlockTransactionsExt> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_listBlockTransactionsExt& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getBlockProof> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getBlockProof& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getConfigAll> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigAll& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getConfigParams> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getConfigParams& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getValidatorStats> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getValidatorStats& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getLibraries> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getLibraries& q) {
return ton::ShardIdFull(ton::masterchainId, ton::shardIdAll);
}
};
template<>
struct QueryTraits<ton::lite_api::liteServer_getShardBlockProof> {
static ton::ShardIdFull get_shard(const ton::lite_api::liteServer_getShardBlockProof& q) {
return ton::ShardIdFull(q.id_->workchain_, q.id_->shard_);
}
};
template<typename Query>
inline ton::ShardIdFull get_query_shard(const Query& q) {
return QueryTraits<Query>::get_shard(q);
}
} // namespace tonlib

View file

@ -17,92 +17,75 @@
#include "ext-client.h"
#include "td/utils/Random.h"
#include "ton/ton-shard.h"
#include <map>
namespace liteclient {
class ExtClientImpl : public ExtClient {
public:
ExtClientImpl(std::vector<LiteServer> servers, td::unique_ptr<ExtClient::Callback> callback)
ExtClientImpl(std::vector<LiteServerConfig> liteservers, td::unique_ptr<Callback> 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<td::BufferSlice> 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<td::BufferSlice> P = [SelfId = actor_id(this), server_idx,
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error() &&
(R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
td::actor::send_closure(SelfId, &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<size_t> 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<size_t> 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<ExtClientImpl> parent, size_t idx)
: parent_(std::move(parent)), idx_(idx) {
explicit Callback(td::actor::ActorId<ExtClientImpl> 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<ExtClientImpl> parent_;
td::actor::ActorId<ExtClientImpl> 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<Callback>(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<Callback>(actor_id(this), server_idx));
return server_idx;
}
struct Server {
LiteServer s;
LiteServerConfig config;
size_t idx = 0;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> 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<Server> servers_;
std::map<ton::ShardIdFull, size_t> shard_to_server_;
int max_server_shard_depth_ = 0;
td::unique_ptr<ExtClient::Callback> callback_;
static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
bool is_closing_{false};
td::uint32 ref_cnt_{1};
td::unique_ptr<Callback> 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> ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
td::unique_ptr<Callback> callback) {
return create({LiteServer{dst, dst_addr, true, {}}}, std::move(callback));
td::unique_ptr<Callback> callback) {
return create({LiteServerConfig{dst, dst_addr}}, std::move(callback));
}
td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServer> servers,
td::unique_ptr<Callback> callback) {
return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(servers), std::move(callback));
td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServerConfig> liteservers,
td::unique_ptr<Callback> callback) {
return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(liteservers), std::move(callback));
}
} // namespace liteclient

View file

@ -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<ton::ShardIdFull> 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<td::BufferSlice> promise) = 0;
virtual void force_change_liteserver() = 0;
virtual void reset_servers() {
}
static td::actor::ActorOwn<ExtClient> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
td::unique_ptr<Callback> callback);
static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServer> servers, td::unique_ptr<Callback> callback);
static td::actor::ActorOwn<ExtClient> create(std::vector<LiteServerConfig> liteservers,
td::unique_ptr<Callback> callback);
};
} // namespace liteclient

File diff suppressed because it is too large Load diff

View file

@ -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<liteclient::ExtClient> client_;
td::actor::ActorOwn<td::TerminalIO> io_;
struct LiteServer {
td::IPAddress addr;
ton::PublicKey public_key;
bool is_full = true;
std::vector<ton::ShardIdFull> shards;
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client;
bool client_ready = false;
std::vector<td::Promise<td::Unit>> wait_client_ready;
bool supports(ton::ShardIdFull shard) const;
};
std::vector<LiteServer> servers_;
bool ready_ = false;
td::int32 single_liteserver_idx_ = -1;
td::IPAddress single_remote_addr_;
ton::PublicKey single_remote_public_key_;
std::map<ton::ShardIdFull, td::int32> shard_server_idx_cached_;
bool readline_enabled_ = true;
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<td::BufferSlice> R, td::Promise<td::BufferSlice> promise);
void after_got_result(bool ok);
bool envelope_send_query_to_any(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_shard(ton::ShardIdFull shard, td::BufferSlice query,
td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_account(ton::AccountIdPrefixFull prefix, td::BufferSlice query,
td::Promise<td::BufferSlice> promise);
bool envelope_send_query_to_server(td::int32 server_idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
void start_client(int server_idx);
void conn_ready(int server_idx);
void conn_closed(int server_idx);
bool envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
void parse_line(td::BufferSlice data);
TestNode() = default;

394
lite-client/query-utils.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <ton/ton-tl.hpp>
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<lite_api::liteServer_query>(data, true);
if (F.is_ok()) {
data = F.ok()->data_;
} else {
fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true).ignore();
}
fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore();
auto Q = fetch_tl_object<lite_api::Function>(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<lite_api::tonNode_blockIdExt>& 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<lite_api::Function&>(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<std::vector<LiteServerConfig>> LiteServerConfig::parse_global_config(
const ton_api::liteclient_config_global& config) {
std::vector<LiteServerConfig> 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<tl_object_ptr<ton_api::liteserver_descV2_shardInfo>>& shard_objs,
std::vector<ShardInfo>& 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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<ShardInfo> shards_from, shards_to;
bool unlimited = false;
bool accepts_query(const QueryInfo& query_info) const;
};
bool is_full = false;
std::vector<Slice> 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<std::vector<LiteServerConfig>> parse_global_config(
const ton::ton_api::liteclient_config_global& config);
};
} // namespace liteclient

View file

@ -148,6 +148,39 @@ td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>>
}
}
template <typename T>
td::Result<tl_object_ptr<std::enable_if_t<std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
bool boxed) {
td::TlParser p(data);
tl_object_ptr<T> R;
if (boxed) {
R = TlFetchBoxed<TlFetchObject<T>, T::ID>::parse(p);
} else {
R = move_tl_object_as<T>(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 <typename T>
td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
bool boxed) {
CHECK(boxed);
td::TlParser p(data);
tl_object_ptr<T> R;
R = move_tl_object_as<T>(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 <class T>
[[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) {
auto B = serialize_tl_object(obj, true);

View file

@ -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;

Binary file not shown.

View file

@ -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

Binary file not shown.

View file

@ -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<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) {
@ -65,67 +66,11 @@ td::Result<Config> 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<Config::LiteServer> {
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<td::int32>(ip)), port));
TRY_RESULT(id_obj, td::get_json_object_field(object, "id", td::JsonValue::Type::Object, false));
auto &id = id_obj.get_object();
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));

View file

@ -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<ton::BlockIdExt> hardforks;
std::vector<LiteServer> lite_servers;
std::vector<liteclient::LiteServerConfig> lite_servers;
std::string name;
static td::Result<Config> parse(std::string str);
};

View file

@ -54,7 +54,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
}
void ExtClient::send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise) {
void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
auto query_id = queries_.create(std::move(promise));
td::Promise<td::BufferSlice> P = [query_id, self = this,
actor_id = td::actor::actor_id()](td::Result<td::BufferSlice> result) {
@ -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

View file

@ -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 <class QueryT>
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise, td::int32 seq_no = -1) {
ton::ShardIdFull shard = liteclient::QueryTraits<QueryT>::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<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
send_raw_query(
std::move(liteserver_query), shard, [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
std::move(liteserver_query), [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
auto res = [&]() -> td::Result<typename QueryT::ReturnType> {
TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork());
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(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<td::Promise<LastBlockState>> last_block_queries_;
td::Container<td::Promise<LastConfigState>> last_config_queries_;
void send_raw_query(td::BufferSlice query, ton::ShardIdFull shard, td::Promise<td::BufferSlice> promise);
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
};
} // namespace tonlib

View file

@ -28,14 +28,11 @@ class ExtClientOutboundImpl : public ExtClientOutbound {
ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
}
void send_query(std::string name, td::BufferSlice data, ton::ShardIdFull shard, td::Timestamp timeout,
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
td::Promise<td::BufferSlice> 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<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {

View file

@ -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<td::BufferSlice> r_data, td::Promise<td::Unit> promise) = 0;
static td::actor::ActorOwn<ExtClientOutbound> create(td::unique_ptr<Callback> callback);
};

View file

@ -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<tonlib_api::updateSendLiteServerQuery>(query_id, data, shard.workchain, shard.shard));
void TonlibClient::proxy_request(td::int64 query_id, std::string data) {
on_update(tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(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<Callback>(td::actor::actor_shared()));
raw_client_ = liteclient::ExtClient::create(config_.lite_servers, nullptr);
}
}
@ -4491,8 +4481,8 @@ void deep_library_search(std::set<td::Bits256>& set, std::set<vm::Cell::Hash>& 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; i<loaded_cell.data_cell->get_refs_cnt(); i++) {
deep_library_search(set, visited, libs, loaded_cell.data_cell->get_ref(i), depth - 1, max_libs);
}
}

View file

@ -401,7 +401,7 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::getConfigAll& request,
td::Promise<object_ptr<tonlib_api::configInfo>>&& 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();

View file

@ -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<td::BufferSlice> res) {
send_closure(actor_id, &TonlibCli::on_adnl_result, id, std::move(res));
});

View file

@ -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 <unistd.h>
#endif
#include <iostream>
#include <map>
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<PublicKey> 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<td::uint16>(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<td::uint16>(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<td::Unit> R) {
if (R.is_error()) {
LOG(FATAL) << "Failed to store private key";
}
});
}
config_->id_ = id_.tl();
auto s = td::json_encode<std::string>(td::ToJson(*config_), true);
TRY_STATUS_PREFIX(td::write_file(config_file(), s), "failed to write file: ");
auto s = td::json_encode<std::string>(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<liteclient::ExtClient::LiteServer> 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<ProxyLiteserver> 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<ProxyLiteserver> 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<Callback>(actor_id(this), i));
server.alive = false;
}
class Callback : public liteclient::ExtClient::Callback {};
ext_client_ = liteclient::ExtClient::create(std::move(servers), td::make_unique<Callback>());
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<adnl::AdnlNodeIdShort>{id_.compute_short_id()}, std::vector<td::uint16>{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<ProxyLiteserver> 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<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &ProxyLiteserver::receive_query, std::move(data), std::move(promise));
}
private:
td::actor::ActorId<ProxyLiteserver> 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<AdnlCallback>(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<td::actor::ActorOwn<adnl::AdnlExtServer>> 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<adnl::AdnlExtServer> 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<liteclient::ExtClient> 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<td::BufferSlice> promise) override {
td::actor::create_actor<QueryWorker>("worker", client_, std::move(data), std::move(promise)).release();
}
private:
td::actor::ActorId<liteclient::ExtClient> 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<AdnlCallback>(ext_client_.get()));
alarm();
}
class QueryWorker : public td::actor::Actor {
public:
QueryWorker(td::actor::ActorId<liteclient::ExtClient> client, td::BufferSlice data,
td::Promise<td::BufferSlice> 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<lite_api::liteServer_query>(data, true);
if (F.is_ok()) {
data = std::move(F.move_as_ok()->data_);
} else {
auto G = fetch_tl_prefix<lite_api::liteServer_queryPrefix>(data, true);
if (G.is_error()) {
fatal_error(G.move_as_error());
return;
}
td::Result<size_t> 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<lite_api::liteServer_waitMasterchainSeqno>(data, true).ignore();
auto F2 = fetch_tl_object<ton::lite_api::Function>(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<td::BufferSlice> 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<td::BufferSlice> 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<lite_api::liteServer_error>(
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<td::BufferSlice> 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<td::BufferSlice> R) {
if (R.is_error()) {
LOG(INFO) << "Query to shard=" << shard_.to_str() << ": " << R.error();
promise_.set_value(create_serialize_tl_object<lite_api::liteServer_error>(
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<liteclient::ExtClient> client_;
td::BufferSlice data_;
td::Promise<td::BufferSlice> 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<ton_api::proxyLiteserver_config> config_ = create_tl_object<ton_api::proxyLiteserver_config>();
adnl::AdnlNodeIdFull id_;
@ -252,7 +302,15 @@ class ProxyLiteserver : public td::actor::Actor {
td::actor::ActorOwn<keyring::Keyring> keyring_;
td::actor::ActorOwn<adnl::Adnl> adnl_;
td::actor::ActorOwn<adnl::AdnlExtServer> ext_server_;
td::actor::ActorOwn<liteclient::ExtClient> ext_client_;
struct Server {
liteclient::LiteServerConfig config;
td::actor::ActorOwn<adnl::AdnlExtClient> client;
bool alive = false;
};
std::vector<Server> servers_;
std::map<int, td::uint32> 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<td::uint16>(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<td::uint16>(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 <db>/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<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port).release(); });
scheduler.run_in_context([&] {
td::actor::create_actor<ProxyLiteserver>("proxy-liteserver", global_config, db_root, port, public_key_hash)
.release();
});
while (scheduler.run(1)) {
}
}