diff --git a/blockchain-explorer/CMakeLists.txt b/blockchain-explorer/CMakeLists.txt
index 36d4e5069..86cb3e740 100644
--- a/blockchain-explorer/CMakeLists.txt
+++ b/blockchain-explorer/CMakeLists.txt
@@ -36,6 +36,7 @@ endif()
target_include_directories(blockchain-explorer PUBLIC ${MHD_INCLUDE_DIR})
target_link_libraries(blockchain-explorer tdactor adnllite tl_lite_api tl-lite-utils ton_crypto ${MHD_LIBRARY})
+target_link_libraries(blockchain-explorer lite-client-common)
install(TARGETS blockchain-explorer RUNTIME DESTINATION bin)
diff --git a/blockchain-explorer/blockchain-explorer-query.cpp b/blockchain-explorer/blockchain-explorer-query.cpp
index 1808a3c46..26a6787e1 100644
--- a/blockchain-explorer/blockchain-explorer-query.cpp
+++ b/blockchain-explorer/blockchain-explorer-query.cpp
@@ -1432,7 +1432,7 @@ void HttpQueryStatus::finish_query() {
for (td::uint32 i = 0; i < results_.ips.size(); i++) {
A << "
";
if (results_.ips[i].is_valid()) {
- A << "" << results_.ips[i] << " | ";
+ A << "" << results_.ips[i].get_ip_str() << ":" << results_.ips[i].get_port() << " | ";
} else {
A << "hidden | ";
}
diff --git a/blockchain-explorer/blockchain-explorer.cpp b/blockchain-explorer/blockchain-explorer.cpp
index 3b5346b73..ca50d5266 100644
--- a/blockchain-explorer/blockchain-explorer.cpp
+++ b/blockchain-explorer/blockchain-explorer.cpp
@@ -57,6 +57,7 @@
#include "auto/tl/lite_api.h"
#include "ton/lite-tl.hpp"
#include "tl-utils/lite-utils.hpp"
+#include "lite-client/ext-client.h"
#include
@@ -127,7 +128,7 @@ class CoreActor : public CoreActorInterface {
private:
std::string global_config_ = "ton-global.config";
- std::vector> clients_;
+ td::actor::ActorOwn client_;
td::uint32 http_port_ = 80;
MHD_Daemon* daemon_ = nullptr;
@@ -137,35 +138,29 @@ class CoreActor : public CoreActorInterface {
bool hide_ips_ = false;
- std::unique_ptr make_callback(td::uint32 idx) {
- class Callback : public ton::adnl::AdnlExtClient::Callback {
+ td::unique_ptr make_callback() {
+ class Callback : public liteclient::ExtClient::Callback {
public:
- void on_ready() override {
- td::actor::send_closure(id_, &CoreActor::conn_ready, idx_);
- }
- void on_stop_ready() override {
- td::actor::send_closure(id_, &CoreActor::conn_closed, idx_);
- }
- Callback(td::actor::ActorId id, td::uint32 idx) : id_(std::move(id)), idx_(idx) {
+ Callback(td::actor::ActorId id) : id_(std::move(id)) {
}
private:
td::actor::ActorId id_;
- td::uint32 idx_;
};
- return std::make_unique(actor_id(this), idx);
+ return td::make_unique(actor_id(this));
}
std::shared_ptr new_result_;
td::int32 attempt_ = 0;
td::int32 waiting_ = 0;
- std::vector ready_;
+ size_t n_servers_ = 0;
void run_queries();
- void got_result(td::uint32 idx, td::int32 attempt, td::Result data);
- void send_query(td::uint32 idx);
+ void got_servers_ready(td::int32 attempt, std::vector ready);
+ void send_ping(td::uint32 idx);
+ void got_ping_result(td::uint32 idx, td::int32 attempt, td::Result data);
void add_result() {
if (new_result_) {
@@ -196,12 +191,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;
}
@@ -226,10 +215,7 @@ class CoreActor : public CoreActorInterface {
hide_ips_ = value;
}
- void send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise promise);
- void send_lite_query(td::BufferSlice data, td::Promise promise) override {
- return send_lite_query(0, std::move(data), std::move(promise));
- }
+ 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 {
@@ -449,33 +435,27 @@ class CoreActor : public CoreActorInterface {
}
void run() {
+ 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();
-
- CHECK(gc.liteservers_.size() > 0);
- td::uint32 size = static_cast(gc.liteservers_.size());
- ready_.resize(size, false);
-
- for (td::uint32 i = 0; i < size; i++) {
- auto& cli = gc.liteservers_[i];
- td::IPAddress addr;
- addr.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
- addrs_.push_back(addr);
- clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull::create(cli->id_).move_as_ok(),
- addr, make_callback(i)));
+ 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_);
- clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_},
- remote_addr_, make_callback(0)));
+ servers.push_back(liteclient::LiteServerConfig{ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_});
}
+ n_servers_ = servers.size();
+ client_ = liteclient::ExtClient::create(std::move(servers), make_callback(), true);
daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast(http_port_), nullptr, nullptr,
&process_http_request, nullptr, MHD_OPTION_NOTIFY_COMPLETED, request_completed, nullptr,
MHD_OPTION_THREAD_POOL_SIZE, 16, MHD_OPTION_END);
@@ -483,7 +463,46 @@ class CoreActor : public CoreActorInterface {
}
};
-void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result R) {
+void CoreActor::run_queries() {
+ waiting_ = 0;
+ new_result_ = std::make_shared(n_servers_, td::Timestamp::at_unix(attempt_ * 60));
+ td::actor::send_closure(client_, &liteclient::ExtClient::get_servers_status,
+ [SelfId = actor_id(this), attempt = attempt_](td::Result> R) {
+ R.ensure();
+ td::actor::send_closure(SelfId, &CoreActor::got_servers_ready, attempt, R.move_as_ok());
+ });
+}
+
+void CoreActor::got_servers_ready(td::int32 attempt, std::vector ready) {
+ if (attempt != attempt_) {
+ return;
+ }
+ CHECK(ready.size() == n_servers_);
+ for (td::uint32 i = 0; i < n_servers_; i++) {
+ if (ready[i]) {
+ send_ping(i);
+ }
+ }
+ CHECK(waiting_ >= 0);
+ if (waiting_ == 0) {
+ add_result();
+ }
+}
+
+void CoreActor::send_ping(td::uint32 idx) {
+ waiting_++;
+ auto query = ton::create_tl_object();
+ auto q = ton::create_tl_object(serialize_tl_object(query, true));
+
+ auto P =
+ td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result R) {
+ td::actor::send_closure(SelfId, &CoreActor::got_ping_result, idx, attempt, std::move(R));
+ });
+ td::actor::send_closure(client_, &liteclient::ExtClient::send_query_to_server, "query", serialize_tl_object(q, true),
+ idx, td::Timestamp::in(10.0), std::move(P));
+}
+
+void CoreActor::got_ping_result(td::uint32 idx, td::int32 attempt, td::Result R) {
if (attempt != attempt_) {
return;
}
@@ -524,39 +543,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result();
- auto q = ton::create_tl_object(serialize_tl_object(query, true));
-
- auto P =
- td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result R) {
- td::actor::send_closure(SelfId, &CoreActor::got_result, idx, attempt, std::move(R));
- });
- td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
- td::Timestamp::in(10.0), std::move(P));
-}
-
-void CoreActor::run_queries() {
- waiting_ = 0;
- new_result_ = std::make_shared(ready_.size(), td::Timestamp::at_unix(attempt_ * 60));
- for (td::uint32 i = 0; i < ready_.size(); i++) {
- send_query(i);
- }
- CHECK(waiting_ >= 0);
- if (waiting_ == 0) {
- add_result();
- }
-}
-
-void CoreActor::send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise promise) {
- if (!ready_[idx]) {
- promise.set_error(td::Status::Error(ton::ErrorCode::notready, "ext conn not ready"));
- return;
- }
+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());
@@ -574,7 +561,7 @@ void CoreActor::send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promi
promise.set_value(std::move(B));
});
auto q = ton::create_tl_object(std::move(query));
- td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
+ 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/create-hardfork/create-hardfork.cpp b/create-hardfork/create-hardfork.cpp
index a24f3f8e0..31a60b56a 100644
--- a/create-hardfork/create-hardfork.cpp
+++ b/create-hardfork/create-hardfork.cpp
@@ -236,9 +236,8 @@ class HardforkCreator : public td::actor::Actor {
td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete,
td::PromiseCreator::lambda([](td::Unit) {}));
}
- void add_shard(ton::ShardIdFull) override {
- }
- void del_shard(ton::ShardIdFull) override {
+ void on_new_masterchain_block(td::Ref state,
+ std::set shards_to_monitor) override {
}
void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
@@ -270,9 +269,8 @@ class HardforkCreator : public td::actor::Actor {
void get_next_key_blocks(ton::BlockIdExt block_id, td::Timestamp timeout,
td::Promise> promise) override {
}
- void download_archive(ton::BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
-
- td::Promise promise) override {
+ void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
+ td::Timestamp timeout, td::Promise promise) override {
}
void new_key_block(ton::validator::BlockHandle handle) override {
diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb
index 6f9754267..560433bfe 100644
--- a/crypto/block/block.tlb
+++ b/crypto/block/block.tlb
@@ -818,7 +818,7 @@ _ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
_ OracleBridgeParams = ConfigParam 73; // Polygon bridge
// Note that chains in which bridge, minter and jetton-wallet operate are fixated
-jetton_bridge_prices#_ bridge_burn_fee:Coins bridge_mint_fee:Coins
+jetton_bridge_prices#_ bridge_burn_fee:Coins bridge_mint_fee:Coins
wallet_min_tons_for_storage:Coins
wallet_gas_consumption:Coins
minter_min_tons_for_storage:Coins
diff --git a/dht-server/dht-server.cpp b/dht-server/dht-server.cpp
index eb183cad6..fa9fad132 100644
--- a/dht-server/dht-server.cpp
+++ b/dht-server/dht-server.cpp
@@ -54,7 +54,7 @@ Config::Config() {
out_port = 3278;
}
-Config::Config(ton::ton_api::engine_validator_config &config) {
+Config::Config(const ton::ton_api::engine_validator_config &config) {
out_port = static_cast(config.out_port_);
if (!out_port) {
out_port = 3278;
@@ -162,6 +162,7 @@ ton::tl_object_ptr Config::tl() const {
control_vec.push_back(ton::create_tl_object(x.second.key.tl(), x.first,
std::move(control_proc_vec)));
}
+ std::vector> shard_vec;
auto gc_vec = ton::create_tl_object(std::vector{});
for (auto &id : gc) {
@@ -170,7 +171,7 @@ ton::tl_object_ptr Config::tl() const {
return ton::create_tl_object(
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec),
ton::PublicKeyHash::zero().tl(), std::move(full_node_slaves_vec), std::move(full_node_masters_vec),
- nullptr, nullptr, std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
+ nullptr, nullptr, std::move(liteserver_vec), std::move(control_vec), std::move(shard_vec), std::move(gc_vec));
}
td::Result Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
diff --git a/dht-server/dht-server.hpp b/dht-server/dht-server.hpp
index 5b81875be..7c9e56194 100644
--- a/dht-server/dht-server.hpp
+++ b/dht-server/dht-server.hpp
@@ -94,7 +94,7 @@ struct Config {
ton::tl_object_ptr tl() const;
Config();
- Config(ton::ton_api::engine_validator_config &config);
+ Config(const ton::ton_api::engine_validator_config &config);
};
class DhtServer : public td::actor::Actor {
diff --git a/lite-client/CMakeLists.txt b/lite-client/CMakeLists.txt
index c6988cf56..b28a14e9a 100644
--- a/lite-client/CMakeLists.txt
+++ b/lite-client/CMakeLists.txt
@@ -1,9 +1,10 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-add_library(lite-client-common STATIC lite-client-common.cpp lite-client-common.h)
+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 tdactor adnllite tl_api tl_lite_api tl-lite-utils ton_crypto)
-add_executable(lite-client lite-client.cpp lite-client.h)
+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 terminal lite-client-common git)
install(TARGETS lite-client RUNTIME DESTINATION bin)
diff --git a/lite-client/ext-client.cpp b/lite-client/ext-client.cpp
new file mode 100644
index 000000000..a0e48e64a
--- /dev/null
+++ b/lite-client/ext-client.cpp
@@ -0,0 +1,228 @@
+/*
+ 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 "ext-client.h"
+#include "td/utils/Random.h"
+#include "ton/ton-shard.h"
+
+namespace liteclient {
+
+class ExtClientImpl : public ExtClient {
+ public:
+ ExtClientImpl(std::vector liteservers, td::unique_ptr callback, bool connect_to_all)
+ : callback_(std::move(callback)), connect_to_all_(connect_to_all) {
+ CHECK(!liteservers.empty());
+ servers_.resize(liteservers.size());
+ for (size_t i = 0; i < servers_.size(); ++i) {
+ 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);
+ server_indices_.resize(servers_.size());
+ for (size_t i = 0; i < servers_.size(); ++i) {
+ server_indices_[servers_[i].idx] = i;
+ }
+
+ if (connect_to_all_) {
+ for (size_t i = 0; i < servers_.size(); ++i) {
+ prepare_server(i, nullptr);
+ }
+ }
+ }
+
+ void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
+ td::Promise promise) override {
+ QueryInfo query_info = get_query_info(data);
+ TRY_RESULT_PROMISE(promise, server_idx, select_server(query_info));
+ send_query_internal(std::move(name), std::move(data), std::move(query_info), server_idx, timeout,
+ std::move(promise));
+ }
+
+ void send_query_to_server(std::string name, td::BufferSlice data, size_t server_idx, td::Timestamp timeout,
+ td::Promise promise) override {
+ if (server_idx >= servers_.size()) {
+ promise.set_error(td::Status::Error(PSTRING() << "server idx " << server_idx << " is too big"));
+ return;
+ }
+ server_idx = server_indices_[server_idx];
+ QueryInfo query_info = get_query_info(data);
+ prepare_server(server_idx, &query_info);
+ send_query_internal(std::move(name), std::move(data), std::move(query_info), server_idx, timeout,
+ std::move(promise));
+ }
+
+ void get_servers_status(td::Promise> promise) override {
+ std::vector status(servers_.size());
+ for (const Server& s : servers_) {
+ status[s.idx] = s.alive;
+ }
+ promise.set_result(std::move(status));
+ }
+
+ 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:
+ void send_query_internal(std::string name, td::BufferSlice data, QueryInfo query_info, size_t server_idx,
+ td::Timestamp timeout, td::Promise promise) {
+ auto& server = servers_[server_idx];
+ CHECK(!server.client.empty());
+ if (!connect_to_all_) {
+ 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 {
+ if (R.is_error() &&
+ (R.error().code() == ton::ErrorCode::timeout || R.error().code() == ton::ErrorCode::cancelled)) {
+ 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));
+ }
+
+ 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;
+ }
+ }
+ 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.config.accepts_query(query_info)) {
+ continue;
+ }
+ int priority = 0;
+ priority += (server.ignore_until && !server.ignore_until.is_in_past() ? 0 : 10);
+ if (priority < best_priority) {
+ continue;
+ }
+ if (priority > best_priority) {
+ best_priority = priority;
+ cnt = 0;
+ }
+ if (td::Random::fast(0, cnt) == 0) {
+ server_idx = i;
+ }
+ ++cnt;
+ }
+ if (server_idx == servers_.size()) {
+ return td::Status::Error(PSTRING() << "no liteserver for query " << query_info.to_str());
+ }
+ prepare_server(server_idx, &query_info);
+ return server_idx;
+ }
+
+ void prepare_server(size_t server_idx, const QueryInfo* query_info) {
+ Server& server = servers_[server_idx];
+ if (server.alive) {
+ return;
+ }
+ server.alive = true;
+ server.ignore_until = {};
+ if (!connect_to_all_) {
+ alarm_timestamp().relax(server.timeout = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT));
+ }
+ if (!server.client.empty()) {
+ return;
+ }
+
+ class Callback : public ton::adnl::AdnlExtClient::Callback {
+ public:
+ 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::on_server_error, idx_);
+ }
+
+ private:
+ td::actor::ActorId parent_;
+ size_t idx_;
+ };
+ LOG(INFO) << "Connecting to liteserver #" << server.idx << " (" << server.config.addr.get_ip_str() << ":"
+ << server.config.addr.get_port() << ") for query " << (query_info ? query_info->to_str() : "[none]");
+ server.client = ton::adnl::AdnlExtClient::create(server.config.adnl_id, server.config.addr,
+ std::make_unique(actor_id(this), server_idx));
+ }
+
+ struct Server {
+ 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();
+ };
+ std::vector servers_;
+ std::vector server_indices_;
+
+ td::unique_ptr callback_;
+ bool connect_to_all_ = false;
+ static constexpr double MAX_NO_QUERIES_TIMEOUT = 100.0;
+ static constexpr double BAD_SERVER_TIMEOUT = 30.0;
+
+ void alarm() override {
+ if (connect_to_all_) {
+ return;
+ }
+ 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 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({LiteServerConfig{dst, dst_addr}}, std::move(callback));
+}
+
+td::actor::ActorOwn ExtClient::create(std::vector liteservers,
+ td::unique_ptr callback, bool connect_to_all) {
+ return td::actor::create_actor("ExtClient", std::move(liteservers), std::move(callback),
+ connect_to_all);
+}
+} // namespace liteclient
diff --git a/lite-client/ext-client.h b/lite-client/ext-client.h
new file mode 100644
index 000000000..ef4523fd6
--- /dev/null
+++ b/lite-client/ext-client.h
@@ -0,0 +1,48 @@
+/*
+ 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 "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:
+ class Callback {
+ public:
+ virtual ~Callback() = default;
+ };
+
+ virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
+ td::Promise promise) = 0;
+ virtual void send_query_to_server(std::string name, td::BufferSlice data, size_t server_idx, td::Timestamp timeout,
+ td::Promise promise) {
+ promise.set_error(td::Status::Error("not supported"));
+ }
+ virtual void get_servers_status(td::Promise> promise) {
+ promise.set_error(td::Status::Error("not supported"));
+ }
+ 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 liteservers,
+ td::unique_ptr callback, bool connect_to_all = false);
+};
+} // namespace liteclient
diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp
index 77c9a8c8b..dc09ae52b 100644
--- a/lite-client/lite-client.cpp
+++ b/lite-client/lite-client.cpp
@@ -29,22 +29,16 @@
#include "lite-client-common.h"
-#include "adnl/adnl-ext-client.h"
#include "tl-utils/lite-utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "auto/tl/lite_api.hpp"
#include "td/utils/OptionParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
-#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/crypto.h"
-#include "td/utils/overloaded.h"
#include "td/utils/port/signals.h"
-#include "td/utils/port/stacktrace.h"
-#include "td/utils/port/StdStreams.h"
#include "td/utils/port/FileFd.h"
-#include "terminal/terminal.h"
#include "ton/lite-tl.hpp"
#include "block/block-db.h"
#include "block/block.h"
@@ -58,18 +52,14 @@
#include "vm/vm.h"
#include "vm/cp0.h"
#include "vm/memo.h"
-#include "ton/ton-shard.h"
-#include "openssl/rand.hpp"
#include "crypto/vm/utils.h"
#include "crypto/common/util.h"
#include "common/checksum.h"
#if TD_DARWIN || TD_LINUX
#include
-#include
#endif
#include
-#include
#include "git.h"
using namespace std::literals::string_literals;
@@ -77,24 +67,6 @@ using td::Ref;
int verbosity;
-std::unique_ptr TestNode::make_callback() {
- class Callback : public ton::adnl::AdnlExtClient::Callback {
- public:
- void on_ready() override {
- td::actor::send_closure(id_, &TestNode::conn_ready);
- }
- void on_stop_ready() override {
- td::actor::send_closure(id_, &TestNode::conn_closed);
- }
- Callback(td::actor::ActorId id) : id_(std::move(id)) {
- }
-
- private:
- td::actor::ActorId id_;
- };
- return std::make_unique(actor_id(this));
-}
-
void TestNode::run() {
class Cb : public td::TerminalIO::Callback {
public:
@@ -110,19 +82,20 @@ void TestNode::run() {
io_ = td::TerminalIO::create("> ", readline_enabled_, ex_mode_, std::make_unique(actor_id(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
- if (remote_public_key_.empty()) {
+ std::vector servers;
+ if (!single_remote_public_key_.empty()) { // Use single provided liteserver
+ 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();
- CHECK(gc.liteservers_.size() > 0);
- auto idx = liteserver_idx_ >= 0 ? liteserver_idx_
- : td::Random::fast(0, static_cast(gc.liteservers_.size() - 1));
- CHECK(idx >= 0 && static_cast(idx) <= gc.liteservers_.size());
- auto& cli = gc.liteservers_[idx];
- remote_addr_.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
- remote_public_key_ = ton::PublicKey{cli->id_};
- td::TerminalIO::out() << "using liteserver " << idx << " with addr " << remote_addr_ << "\n";
+ auto r_servers = liteclient::LiteServerConfig::parse_global_config(gc);
+ r_servers.ensure();
+ servers = r_servers.move_as_ok();
+
if (gc.validator_ && gc.validator_->zero_state_) {
zstate_id_.workchain = gc.validator_->zero_state_->workchain_;
if (zstate_id_.workchain != ton::workchainInvalid) {
@@ -131,10 +104,19 @@ void TestNode::run() {
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_]};
+ }
}
+ CHECK(!servers.empty());
+ client_ = liteclient::ExtClient::create(std::move(servers), nullptr);
+ ready_ = true;
- client_ =
- ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_, make_callback());
+ run_init_queries();
}
void TestNode::got_result(td::Result R, td::Promise promise) {
@@ -191,8 +173,8 @@ bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise(std::move(query)), true);
- td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
- td::Timestamp::in(10.0), std::move(P));
+ td::actor::send_closure(client_, &liteclient::ExtClient::send_query, "query", std::move(b), td::Timestamp::in(10.0),
+ std::move(P));
return true;
}
@@ -319,9 +301,10 @@ bool TestNode::get_server_time() {
if (F.is_error()) {
LOG(ERROR) << "cannot parse answer to liteServer.getTime";
} else {
- server_time_ = F.move_as_ok()->now_;
- server_time_got_at_ = now();
- LOG(INFO) << "server time is " << server_time_ << " (delta " << server_time_ - server_time_got_at_ << ")";
+ mc_server_time_ = F.move_as_ok()->now_;
+ mc_server_time_got_at_ = now();
+ LOG(INFO) << "server time is " << mc_server_time_ << " (delta " << mc_server_time_ - mc_server_time_got_at_
+ << ")";
}
}
});
@@ -335,7 +318,7 @@ bool TestNode::get_server_version(int mode) {
};
void TestNode::got_server_version(td::Result res, int mode) {
- server_ok_ = false;
+ mc_server_ok_ = false;
if (res.is_error()) {
LOG(ERROR) << "cannot get server version and time (server too old?)";
} else {
@@ -344,11 +327,11 @@ void TestNode::got_server_version(td::Result res, int mode) {
LOG(ERROR) << "cannot parse answer to liteServer.getVersion";
} else {
auto a = F.move_as_ok();
- set_server_version(a->version_, a->capabilities_);
- set_server_time(a->now_);
+ set_mc_server_version(a->version_, a->capabilities_);
+ set_mc_server_time(a->now_);
}
}
- if (!server_ok_) {
+ if (!mc_server_ok_) {
LOG(ERROR) << "server version is too old (at least " << (min_ls_version >> 8) << "." << (min_ls_version & 0xff)
<< " with capabilities " << min_ls_capabilities << " required), some queries are unavailable";
}
@@ -357,24 +340,24 @@ void TestNode::got_server_version(td::Result res, int mode) {
}
}
-void TestNode::set_server_version(td::int32 version, td::int64 capabilities) {
- if (server_version_ != version || server_capabilities_ != capabilities) {
- server_version_ = version;
- server_capabilities_ = capabilities;
- LOG(WARNING) << "server version is " << (server_version_ >> 8) << "." << (server_version_ & 0xff)
- << ", capabilities " << server_capabilities_;
+void TestNode::set_mc_server_version(td::int32 version, td::int64 capabilities) {
+ if (mc_server_version_ != version || mc_server_capabilities_ != capabilities) {
+ mc_server_version_ = version;
+ mc_server_capabilities_ = capabilities;
+ LOG(WARNING) << "server version is " << (mc_server_version_ >> 8) << "." << (mc_server_version_ & 0xff)
+ << ", capabilities " << mc_server_capabilities_;
}
- server_ok_ = (server_version_ >= min_ls_version) && !(~server_capabilities_ & min_ls_capabilities);
+ mc_server_ok_ = (mc_server_version_ >= min_ls_version) && !(~mc_server_capabilities_ & min_ls_capabilities);
}
-void TestNode::set_server_time(int server_utime) {
- server_time_ = server_utime;
- server_time_got_at_ = now();
- LOG(INFO) << "server time is " << server_time_ << " (delta " << server_time_ - server_time_got_at_ << ")";
+void TestNode::set_mc_server_time(int server_utime) {
+ mc_server_time_ = server_utime;
+ mc_server_time_got_at_ = now();
+ LOG(INFO) << "server time is " << mc_server_time_ << " (delta " << mc_server_time_ - mc_server_time_got_at_ << ")";
}
bool TestNode::get_server_mc_block_id() {
- int mode = (server_capabilities_ & 2) ? 0 : -1;
+ int mode = (mc_server_capabilities_ & 2) ? 0 : -1;
if (mode < 0) {
auto b = ton::serialize_tl_object(ton::create_tl_object(), true);
return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result res) -> void {
@@ -448,8 +431,8 @@ void TestNode::got_server_mc_block_id(ton::BlockIdExt blkid, ton::ZeroStateIdExt
void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateIdExt zstateid, int mode, int version,
long long capabilities, int last_utime, int server_now) {
- set_server_version(version, capabilities);
- set_server_time(server_now);
+ set_mc_server_version(version, capabilities);
+ set_mc_server_time(server_now);
if (last_utime > server_now) {
LOG(WARNING) << "server claims to have a masterchain block " << blkid.to_str() << " created at " << last_utime
<< " (" << last_utime - server_now << " seconds in the future)";
@@ -457,10 +440,10 @@ void TestNode::got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateI
LOG(WARNING) << "server appears to be out of sync: its newest masterchain block is " << blkid.to_str()
<< " created at " << last_utime << " (" << server_now - last_utime
<< " seconds ago according to the server's clock)";
- } else if (last_utime < server_time_got_at_ - 60) {
+ } else if (last_utime < mc_server_time_got_at_ - 60) {
LOG(WARNING) << "either the server is out of sync, or the local clock is set incorrectly: the newest masterchain "
"block known to server is "
- << blkid.to_str() << " created at " << last_utime << " (" << server_now - server_time_got_at_
+ << blkid.to_str() << " created at " << last_utime << " (" << server_now - mc_server_time_got_at_
<< " seconds ago according to the local clock)";
}
got_server_mc_block_id(blkid, zstateid, last_utime);
diff --git a/lite-client/lite-client.h b/lite-client/lite-client.h
index 90a2fb8a4..721d2b20d 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,22 +47,24 @@ 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 client_;
td::actor::ActorOwn io_;
+ bool ready_ = false;
+
+ td::int32 single_liteserver_idx_ = -1;
+ td::IPAddress single_remote_addr_;
+ ton::PublicKey single_remote_public_key_;
bool readline_enabled_ = true;
- bool server_ok_ = false;
- td::int32 liteserver_idx_ = -1;
int print_limit_ = 1024;
- bool ready_ = false;
- bool inited_ = false;
std::string db_root_;
- int server_time_ = 0;
- int server_time_got_at_ = 0;
- int server_version_ = 0;
- long long server_capabilities_ = 0;
+ int mc_server_time_ = 0;
+ int mc_server_time_got_at_ = 0;
+ int mc_server_version_ = 0;
+ long long mc_server_capabilities_ = 0;
+ bool mc_server_ok_ = false;
ton::ZeroStateIdExt zstate_id_;
ton::BlockIdExt mc_last_id_;
@@ -76,9 +79,6 @@ class TestNode : public td::actor::Actor {
const char *parse_ptr_, *parse_end_;
td::Status error_;
- td::IPAddress remote_addr_;
- ton::PublicKey remote_public_key_;
-
std::vector known_blk_ids_;
std::size_t shown_blk_ids_ = 0;
@@ -89,8 +89,6 @@ class TestNode : public td::actor::Actor {
std::map> cell_cache_;
- std::unique_ptr make_callback();
-
using creator_stats_func_t =
std::function;
@@ -183,8 +181,8 @@ class TestNode : public td::actor::Actor {
void got_server_mc_block_id(ton::BlockIdExt blkid, ton::ZeroStateIdExt zstateid, int created_at);
void got_server_mc_block_id_ext(ton::BlockIdExt blkid, ton::ZeroStateIdExt zstateid, int mode, int version,
long long capabilities, int last_utime, int server_now);
- void set_server_version(td::int32 version, td::int64 capabilities);
- void set_server_time(int server_utime);
+ void set_mc_server_version(td::int32 version, td::int64 capabilities);
+ void set_mc_server_time(int server_utime);
bool request_block(ton::BlockIdExt blkid);
bool request_state(ton::BlockIdExt blkid);
void got_mc_block(ton::BlockIdExt blkid, td::BufferSlice data);
@@ -370,9 +368,6 @@ class TestNode : public td::actor::Actor {
bool parse_shard_id(ton::ShardIdFull& shard);
bool parse_block_id_ext(ton::BlockIdExt& blkid, bool allow_incomplete = false);
bool parse_block_id_ext(std::string blk_id_string, ton::BlockIdExt& blkid, bool allow_incomplete = false) const;
- bool parse_stack_value(td::Slice str, vm::StackEntry& value);
- bool parse_stack_value(vm::StackEntry& value);
- bool parse_stack_values(std::vector& values);
bool register_blkid(const ton::BlockIdExt& blkid);
bool show_new_blkids(bool all = false);
bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const;
@@ -391,16 +386,6 @@ class TestNode : public td::actor::Actor {
static const tlb::TypenameLookup& get_tlb_dict();
public:
- void conn_ready() {
- LOG(ERROR) << "conn ready";
- ready_ = true;
- if (!inited_) {
- run_init_queries();
- }
- }
- void conn_closed() {
- ready_ = false;
- }
void set_global_config(std::string str) {
global_config_ = str;
}
@@ -411,10 +396,10 @@ class TestNode : public td::actor::Actor {
readline_enabled_ = value;
}
void set_liteserver_idx(td::int32 idx) {
- liteserver_idx_ = idx;
+ single_liteserver_idx_ = idx;
}
void set_remote_addr(td::IPAddress addr) {
- remote_addr_ = addr;
+ single_remote_addr_ = addr;
}
void set_public_key(td::BufferSlice file_name) {
auto R = [&]() -> td::Result {
@@ -425,7 +410,7 @@ class TestNode : public td::actor::Actor {
if (R.is_error()) {
LOG(FATAL) << "bad server public key: " << R.move_as_error();
}
- remote_public_key_ = R.move_as_ok();
+ single_remote_public_key_ = R.move_as_ok();
}
void decode_public_key(td::BufferSlice b64_key) {
auto R = [&]() -> td::Result {
@@ -437,7 +422,7 @@ class TestNode : public td::actor::Actor {
if (R.is_error()) {
LOG(FATAL) << "bad b64 server public key: " << R.move_as_error();
}
- remote_public_key_ = R.move_as_ok();
+ single_remote_public_key_ = R.move_as_ok();
}
void set_fail_timeout(td::Timestamp ts) {
fail_timeout_ = ts;
@@ -475,8 +460,7 @@ class TestNode : public td::actor::Actor {
bool envelope_send_query(td::BufferSlice query, td::Promise promise);
void parse_line(td::BufferSlice data);
- TestNode() {
- }
+ TestNode() = default;
void run();
};
diff --git a/lite-client/query-utils.cpp b/lite-client/query-utils.cpp
new file mode 100644
index 000000000..a3a663be0
--- /dev/null
+++ b/lite-client/query-utils.cpp
@@ -0,0 +1,400 @@
+/*
+ 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) {
+ // This query is expected to be removed, as it is not fully compatible with separated liteservers
+ /* t_simple */
+ },
+ [&](const lite_api::liteServer_getBlockOutMsgQueueSize& q) { from_block_id(q.id_); },
+ [&](const lite_api::liteServer_getDispatchQueueInfo& q) { from_block_id(q.id_); },
+ [&](const lite_api::liteServer_getDispatchQueueMessages& q) { from_block_id(q.id_); },
+ [&](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 000000000..28500e266
--- /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/test/test-ton-collator.cpp b/test/test-ton-collator.cpp
index 78e0e6039..118248519 100644
--- a/test/test-ton-collator.cpp
+++ b/test/test-ton-collator.cpp
@@ -323,9 +323,8 @@ class TestNode : public td::actor::Actor {
td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete,
td::PromiseCreator::lambda([](td::Unit) {}));
}
- void add_shard(ton::ShardIdFull) override {
- }
- void del_shard(ton::ShardIdFull) override {
+ void on_new_masterchain_block(td::Ref state,
+ std::set shards_to_monitor) override {
}
void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
@@ -371,9 +370,8 @@ class TestNode : public td::actor::Actor {
void get_next_key_blocks(ton::BlockIdExt block_id, td::Timestamp timeout,
td::Promise> promise) override {
}
- void download_archive(ton::BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
-
- td::Promise promise) override {
+ void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
+ td::Timestamp timeout, td::Promise promise) override {
}
void new_key_block(ton::validator::BlockHandle handle) override {
diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl
index f7bbfd868..16f48345c 100644
--- a/tl/generate/scheme/ton_api.tl
+++ b/tl/generate/scheme/ton_api.tl
@@ -447,13 +447,15 @@ tonNode.dataFull id:tonNode.blockIdExt proof:bytes block:bytes is_link:Bool = to
tonNode.dataFullCompressed id:tonNode.blockIdExt flags:# compressed:bytes is_link:Bool = tonNode.DataFull;
tonNode.dataFullEmpty = tonNode.DataFull;
-tonNode.capabilities version:int capabilities:long = tonNode.Capabilities;
+tonNode.capabilities#f5bf60c0 version_major:int version_minor:int flags:# = tonNode.Capabilities;
tonNode.success = tonNode.Success;
tonNode.archiveNotFound = tonNode.ArchiveInfo;
tonNode.archiveInfo id:long = tonNode.ArchiveInfo;
+tonNode.forgetPeer = tonNode.ForgetPeer;
+
---functions---
tonNode.getNextBlockDescription prev_block:tonNode.blockIdExt = tonNode.BlockDescription;
@@ -479,6 +481,7 @@ tonNode.downloadKeyBlockProof block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
tonNode.downloadKeyBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
tonNode.getArchiveInfo masterchain_seqno:int = tonNode.ArchiveInfo;
+tonNode.getShardArchiveInfo masterchain_seqno:int shard_prefix:tonNode.shardId = tonNode.ArchiveInfo;
tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data;
tonNode.getCapabilities = tonNode.Capabilities;
@@ -545,6 +548,9 @@ db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient;
db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer;
db.state.hardforks blocks:(vector tonNode.blockIdExt) = db.state.Hardforks;
db.state.dbVersion version:int = db.state.DbVersion;
+db.state.persistentStateDescriptionShards shard_blocks:(vector tonNode.blockIdExt) = db.state.PersistentStateDescriptionShards;
+db.state.persistentStateDescriptionHeader masterchain_id:tonNode.blockIdExt start_time:int end_time:int = db.state.PersistentStateDescriptionHeader;
+db.state.persistentStateDescriptionsList list:(vector db.state.persistentStateDescriptionHeader) = db.state.PersistentStateDescriptionsList;
db.state.key.destroyedSessions = db.state.Key;
db.state.key.initBlockId = db.state.Key;
@@ -553,6 +559,8 @@ db.state.key.shardClient = db.state.Key;
db.state.key.asyncSerializer = db.state.Key;
db.state.key.hardforks = db.state.Key;
db.state.key.dbVersion = db.state.Key;
+db.state.key.persistentStateDescriptionShards masterchain_seqno:int = db.state.Key;
+db.state.key.persistentStateDescriptionsList = db.state.Key;
db.lt.el.key workchain:int shard:long idx:int = db.lt.Key;
db.lt.desc.key workchain:int shard:long = db.lt.Key;
@@ -608,8 +616,13 @@ 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;
-liteclient.config.global liteservers:(vector liteserver.desc) validator:validator.config.global = liteclient.config.Global;
+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;
engine.addr ip:int port:int categories:(vector int) priority_categories:(vector int) = engine.Addr;
@@ -636,10 +649,12 @@ engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector eng
fullnodeconfig:engine.validator.fullNodeConfig
extraconfig:engine.validator.extraConfig
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
+ shards_to_monitor:(vector tonNode.shardId)
gc:engine.gc = engine.validator.Config;
engine.validator.customOverlayNode adnl_id:int256 msg_sender:Bool msg_sender_priority:int block_sender:Bool = engine.validator.CustomOverlayNode;
-engine.validator.customOverlay name:string nodes:(vector engine.validator.customOverlayNode) = engine.validator.CustomOverlay;
+engine.validator.customOverlay name:string nodes:(vector engine.validator.customOverlayNode) sender_shards:(vector tonNode.shardId)
+ = engine.validator.CustomOverlay;
engine.validator.customOverlaysConfig overlays:(vector engine.validator.customOverlay) = engine.validator.CustomOverlaysConfig;
engine.validator.collatorOptions
@@ -699,6 +714,11 @@ engine.validator.overlayStats overlay_id:int256 overlay_id_full:PublicKey adnl_i
extra:string = engine.validator.OverlayStats;
engine.validator.overlaysStats overlays:(vector engine.validator.overlayStats) = engine.validator.OverlaysStats;
+engine.validator.shardOverlayStats.neighbour id:string verison_major:int version_minor:int flags:#
+ roundtrip:double unreliability:double = engine.validator.shardOverlayStats.Neighbour;
+engine.validator.shardOverlayStats shard:string active:Bool
+ neighbours:(vector engine.validator.shardOverlayStats.neighbour) = engine.validator.ShardOverlayStats;
+
engine.validator.onePerfTimerStat time:int min:double avg:double max:double = engine.validator.OnePerfTimerStat;
engine.validator.perfTimerStatsByName name:string stats:(vector engine.validator.OnePerfTimerStat) = engine.validator.PerfTimerStatsByName;
engine.validator.perfTimerStats stats:(vector engine.validator.PerfTimerStatsByName) = engine.validator.PerfTimerStats;
@@ -771,6 +791,9 @@ engine.validator.getCollatorOptionsJson = engine.validator.JsonConfig;
engine.validator.getAdnlStats all:Bool = adnl.Stats;
engine.validator.getActorTextStats = engine.validator.TextStats;
+engine.validator.addShard shard:tonNode.shardId = engine.validator.Success;
+engine.validator.delShard shard:tonNode.shardId = engine.validator.Success;
+
---types---
storage.pong = storage.Pong;
@@ -985,3 +1008,6 @@ storage.daemon.withdraw contract:string = storage.daemon.Success;
storage.daemon.sendCoins address:string amount:string message:string = storage.daemon.Success;
storage.daemon.closeStorageContract address:string = storage.daemon.Success;
storage.daemon.removeStorageProvider = storage.daemon.Success;
+
+---types---
+proxyLiteserver.config port:int id:PublicKey = proxyLiteserver.Config;
diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo
index 0cd394bd5..1689260bc 100644
Binary files a/tl/generate/scheme/ton_api.tlo and b/tl/generate/scheme/ton_api.tlo differ
diff --git a/ton/ton-types.h b/ton/ton-types.h
index efdb795d1..cd9700814 100644
--- a/ton/ton-types.h
+++ b/ton/ton-types.h
@@ -408,6 +408,9 @@ struct Ed25519_PublicKey {
bool operator==(const Ed25519_PublicKey& other) const {
return _pubkey == other._pubkey;
}
+ bool operator!=(const Ed25519_PublicKey& other) const {
+ return _pubkey != other._pubkey;
+ }
bool clear() {
_pubkey.set_zero();
return true;
@@ -490,4 +493,14 @@ struct ValidatorSessionConfig {
static const td::uint32 BLOCK_HASH_COVERS_DATA_FROM_VERSION = 2;
};
+struct PersistentStateDescription : public td::CntObject {
+ BlockIdExt masterchain_id;
+ std::vector shard_blocks;
+ UnixTime start_time, end_time;
+
+ virtual CntObject* make_copy() const {
+ return new PersistentStateDescription(*this);
+ }
+};
+
} // namespace ton
diff --git a/tonlib/CMakeLists.txt b/tonlib/CMakeLists.txt
index 67d18e019..0855012cc 100644
--- a/tonlib/CMakeLists.txt
+++ b/tonlib/CMakeLists.txt
@@ -10,7 +10,6 @@ set(TONLIB_SOURCE
tonlib/Client.cpp
tonlib/Config.cpp
tonlib/ExtClient.cpp
- tonlib/ExtClientLazy.cpp
tonlib/ExtClientOutbound.cpp
tonlib/KeyStorage.cpp
tonlib/KeyValue.cpp
@@ -25,7 +24,6 @@ set(TONLIB_SOURCE
tonlib/Client.h
tonlib/Config.h
tonlib/ExtClient.h
- tonlib/ExtClientLazy.h
tonlib/ExtClientOutbound.h
tonlib/KeyStorage.h
tonlib/KeyValue.h
diff --git a/tonlib/test/offline.cpp b/tonlib/test/offline.cpp
index b7423853c..47d5d6a26 100644
--- a/tonlib/test/offline.cpp
+++ b/tonlib/test/offline.cpp
@@ -659,11 +659,12 @@ TEST(Tonlib, ConfigCache) {
],
"validator": {
"@type": "validator.config.global",
- "zero_state": {
+ "init_block": {
"workchain": -1,
"shard": -9223372036854775808,
"seqno": 0,
"file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo="
+ "root_hash": "ZXSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=",
}
}
})abc";
diff --git a/tonlib/tonlib/Config.cpp b/tonlib/tonlib/Config.cpp
index 3cd9d50ea..063b34bbd 100644
--- a/tonlib/tonlib/Config.cpp
+++ b/tonlib/tonlib/Config.cpp
@@ -19,6 +19,8 @@
#include "Config.h"
#include "adnl/adnl-node-id.hpp"
#include "td/utils/JsonBuilder.h"
+#include "auto/tl/ton_api_json.h"
+#include "ton/ton-tl.hpp"
namespace tonlib {
td::Result parse_block_id_ext(td::JsonObject &obj) {
@@ -63,75 +65,26 @@ td::Result parse_block_id_ext(td::JsonObject &obj) {
td::Result Config::parse(std::string str) {
TRY_RESULT(json, td::json_decode(str));
if (json.type() != td::JsonValue::Type::Object) {
- return td::Status::Error("Invalid config (1)");
+ return td::Status::Error("Invalid config: json is not an object");
}
- //TRY_RESULT(main_type, td::get_json_object_string_field(json.get_object(), "@type", false));
- //if (main_type != "config.global") {
- //return td::Status::Error("Invalid config (3)");
- //}
- TRY_RESULT(lite_clients_obj,
- td::get_json_object_field(json.get_object(), "liteservers", td::JsonValue::Type::Array, false));
- auto &lite_clients = lite_clients_obj.get_array();
-
Config res;
- for (auto &value : lite_clients) {
- if (value.type() != td::JsonValue::Type::Object) {
- return td::Status::Error("Invalid config (2)");
- }
- auto &object = value.get_object();
- //TRY_RESULT(value_type, td::get_json_object_string_field(object, "@type", false));
- //if (value_type != "liteclient.config.global") {
- //return td::Status::Error("Invalid config (4)");
- //}
-
- TRY_RESULT(ip, td::get_json_object_long_field(object, "ip", false));
- TRY_RESULT(port, td::get_json_object_int_field(object, "port", false));
- Config::LiteClient client;
- TRY_STATUS(client.address.init_host_port(td::IPAddress::ipv4_to_str(static_cast(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 (5)");
- }
- 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 (6)");
- }
+ 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));
- client.adnl_id = ton::adnl::AdnlNodeIdFull(ton::pubkeys::Ed25519(td::Bits256(td::Slice(key).ubegin())));
- res.lite_clients.push_back(std::move(client));
+ if (!conf.validator_) {
+ return td::Status::Error("Invalid config: no 'validator' section");
}
-
- TRY_RESULT(validator_obj,
- td::get_json_object_field(json.get_object(), "validator", td::JsonValue::Type::Object, false));
- auto &validator = validator_obj.get_object();
- TRY_RESULT(validator_type, td::get_json_object_string_field(validator, "@type", false));
- if (validator_type != "validator.config.global") {
- return td::Status::Error("Invalid config (7)");
+ if (!conf.validator_->zero_state_) {
+ return td::Status::Error("Invalid config: no zerostate");
}
- TRY_RESULT(zero_state_obj, td::get_json_object_field(validator, "zero_state", td::JsonValue::Type::Object, false));
- TRY_RESULT(zero_state_id, parse_block_id_ext(zero_state_obj.get_object()));
- res.zero_state_id = zero_state_id;
- auto r_init_block_obj = td::get_json_object_field(validator, "init_block", td::JsonValue::Type::Object, false);
- if (r_init_block_obj.is_ok()) {
- TRY_RESULT(init_block_id, parse_block_id_ext(r_init_block_obj.move_as_ok().get_object()));
- res.init_block_id = init_block_id;
+ res.zero_state_id = ton::create_block_id(conf.validator_->zero_state_);
+ if (conf.validator_->init_block_) {
+ res.init_block_id = ton::create_block_id(conf.validator_->init_block_);
}
- auto r_hardforks = td::get_json_object_field(validator, "hardforks", td::JsonValue::Type::Array, false);
- if (r_hardforks.is_ok()) {
- auto hardforks_obj = r_hardforks.move_as_ok();
- auto &hardforks = hardforks_obj.get_array();
- for (auto &fork : hardforks) {
- if (fork.type() != td::JsonValue::Type::Object) {
- return td::Status::Error("Invalid config (8)");
- }
- TRY_RESULT(fork_block, parse_block_id_ext(fork.get_object()));
- res.hardforks.push_back(std::move(fork_block));
- }
+ for (auto &fork : conf.validator_->hardforks_) {
+ res.hardforks.push_back(ton::create_block_id(fork));
}
for (auto hardfork : res.hardforks) {
diff --git a/tonlib/tonlib/Config.h b/tonlib/tonlib/Config.h
index 3902c3419..28f23881b 100644
--- a/tonlib/tonlib/Config.h
+++ b/tonlib/tonlib/Config.h
@@ -20,17 +20,14 @@
#include "adnl/adnl-node-id.hpp"
#include "td/utils/port/IPAddress.h"
#include "ton/ton-types.h"
+#include "lite-client/ext-client.h"
namespace tonlib {
struct Config {
- struct LiteClient {
- ton::adnl::AdnlNodeIdFull adnl_id;
- td::IPAddress address;
- };
ton::BlockIdExt zero_state_id;
ton::BlockIdExt init_block_id;
std::vector hardforks;
- std::vector lite_clients;
+ 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 30a29b59c..b66ca25c1 100644
--- a/tonlib/tonlib/ExtClient.cpp
+++ b/tonlib/tonlib/ExtClient.cpp
@@ -65,7 +65,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise adnl_ext_client_;
+ td::actor::ActorId adnl_ext_client_;
td::actor::ActorId last_block_actor_;
td::actor::ActorId last_config_actor_;
};
@@ -97,7 +97,7 @@ class ExtClient {
void force_change_liteserver() {
if (!client_.adnl_ext_client_.empty()) {
- td::actor::send_closure(client_.adnl_ext_client_, &ExtClientLazy::force_change_liteserver);
+ td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::reset_servers);
}
}
diff --git a/tonlib/tonlib/ExtClientLazy.cpp b/tonlib/tonlib/ExtClientLazy.cpp
deleted file mode 100644
index 335a0ff96..000000000
--- a/tonlib/tonlib/ExtClientLazy.cpp
+++ /dev/null
@@ -1,152 +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 .
-
- Copyright 2017-2020 Telegram Systems LLP
-*/
-#include "ExtClientLazy.h"
-#include "TonlibError.h"
-#include "td/utils/Random.h"
-namespace tonlib {
-
-class ExtClientLazyImp : public ExtClientLazy {
- public:
- ExtClientLazyImp(std::vector> servers,
- td::unique_ptr callback)
- : servers_(std::move(servers)), callback_(std::move(callback)) {
- CHECK(!servers_.empty());
- }
-
- void start_up() override {
- td::Random::Fast rnd;
- td::random_shuffle(td::as_mutable_span(servers_), rnd);
- }
-
- void check_ready(td::Promise promise) override {
- before_query();
- if (client_.empty()) {
- return promise.set_error(TonlibError::Cancelled());
- }
- send_closure(client_, &ton::adnl::AdnlExtClient::check_ready, std::move(promise));
- }
-
- void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
- td::Promise promise) override {
- before_query();
- if (client_.empty()) {
- return promise.set_error(TonlibError::Cancelled());
- }
- td::Promise P = [SelfId = actor_id(this), idx = cur_server_idx_,
- 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, &ExtClientLazyImp::set_server_bad, idx, true);
- }
- promise.set_result(std::move(R));
- };
- send_closure(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;
- }
- cur_server_bad_ = cur_server_bad_force_ = true;
- }
-
- private:
- void before_query() {
- if (is_closing_) {
- return;
- }
- alarm_timestamp() = td::Timestamp::in(MAX_NO_QUERIES_TIMEOUT);
- if (cur_server_bad_) {
- ++cur_server_idx_;
- } else if (!client_.empty()) {
- return;
- }
- class Callback : public ton::adnl::AdnlExtClient::Callback {
- public:
- explicit Callback(td::actor::ActorShared parent, size_t idx)
- : parent_(std::move(parent)), idx_(idx) {
- }
- void on_ready() override {
- td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, false);
- }
- void on_stop_ready() override {
- td::actor::send_closure(parent_, &ExtClientLazyImp::set_server_bad, idx_, true);
- }
-
- private:
- td::actor::ActorShared parent_;
- size_t idx_;
- };
- ref_cnt_++;
- cur_server_bad_ = false;
- cur_server_bad_force_ = false;
- const auto& s = servers_[cur_server_idx_ % servers_.size()];
- LOG(INFO) << "Connecting to liteserver " << s.second;
- client_ = ton::adnl::AdnlExtClient::create(
- s.first, s.second, std::make_unique(td::actor::actor_shared(this), cur_server_idx_));
- }
-
- std::vector> servers_;
- size_t cur_server_idx_ = 0;
- bool cur_server_bad_ = false;
- bool cur_server_bad_force_ = false;
-
- td::actor::ActorOwn client_;
- td::unique_ptr callback_;
- static constexpr double MAX_NO_QUERIES_TIMEOUT = 100;
-
- bool is_closing_{false};
- td::uint32 ref_cnt_{1};
-
- void set_server_bad(size_t idx, bool bad) {
- if (idx == cur_server_idx_ && servers_.size() > 1 && !cur_server_bad_force_) {
- cur_server_bad_ = bad;
- }
- }
- void alarm() override {
- client_.reset();
- }
- void hangup_shared() override {
- ref_cnt_--;
- try_stop();
- }
- void hangup() override {
- is_closing_ = true;
- ref_cnt_--;
- client_.reset();
- try_stop();
- }
- void try_stop() {
- if (is_closing_ && ref_cnt_ == 0) {
- stop();
- }
- }
-};
-
-td::actor::ActorOwn ExtClientLazy::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
- td::unique_ptr callback) {
- return create({std::make_pair(dst, dst_addr)}, std::move(callback));
-}
-
-td::actor::ActorOwn ExtClientLazy::create(
- std::vector> servers, td::unique_ptr callback) {
- return td::actor::create_actor("ExtClientLazy", std::move(servers), std::move(callback));
-}
-} // namespace tonlib
diff --git a/tonlib/tonlib/ExtClientLazy.h b/tonlib/tonlib/ExtClientLazy.h
deleted file mode 100644
index dc4490b3a..000000000
--- a/tonlib/tonlib/ExtClientLazy.h
+++ /dev/null
@@ -1,41 +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 .
-
- Copyright 2017-2020 Telegram Systems LLP
-*/
-#pragma once
-#include "td/actor/actor.h"
-
-#include "adnl/adnl-ext-client.h"
-
-namespace tonlib {
-class ExtClientLazy : public ton::adnl::AdnlExtClient {
- public:
- class Callback {
- public:
- virtual ~Callback() {
- }
- };
-
- virtual void force_change_liteserver() = 0;
-
- 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);
-};
-
-} // namespace tonlib
diff --git a/tonlib/tonlib/ExtClientOutbound.cpp b/tonlib/tonlib/ExtClientOutbound.cpp
index 025ba848e..e5fac8b47 100644
--- a/tonlib/tonlib/ExtClientOutbound.cpp
+++ b/tonlib/tonlib/ExtClientOutbound.cpp
@@ -20,15 +20,12 @@
#include "ExtClientOutbound.h"
#include "TonlibError.h"
#include