mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 03:05:48 +00:00
Accelerator: partial fullnodes (#1393)
* Accelerator: partial fullnodes 1) Node can monitor a subset of shards 2) New archive slice format (sharded) 3) Validators are still required to have all shards 4) Support partial liteservers in lite-client, blockchain explorer, tonlib 5) Proxy liteserver * Fix compilation error
This commit is contained in:
parent
62444100f5
commit
954a96a077
83 changed files with 3213 additions and 1113 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -1432,7 +1432,7 @@ void HttpQueryStatus::finish_query() {
|
|||
for (td::uint32 i = 0; i < results_.ips.size(); i++) {
|
||||
A << "<tr>";
|
||||
if (results_.ips[i].is_valid()) {
|
||||
A << "<td>" << results_.ips[i] << "</td>";
|
||||
A << "<td>" << results_.ips[i].get_ip_str() << ":" << results_.ips[i].get_port() << "</td>";
|
||||
} else {
|
||||
A << "<td>hidden</td>";
|
||||
}
|
||||
|
|
|
@ -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 <microhttpd.h>
|
||||
|
||||
|
@ -127,7 +128,7 @@ class CoreActor : public CoreActorInterface {
|
|||
private:
|
||||
std::string global_config_ = "ton-global.config";
|
||||
|
||||
std::vector<td::actor::ActorOwn<ton::adnl::AdnlExtClient>> clients_;
|
||||
td::actor::ActorOwn<liteclient::ExtClient> 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<ton::adnl::AdnlExtClient::Callback> make_callback(td::uint32 idx) {
|
||||
class Callback : public ton::adnl::AdnlExtClient::Callback {
|
||||
td::unique_ptr<liteclient::ExtClient::Callback> 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<CoreActor> id, td::uint32 idx) : id_(std::move(id)), idx_(idx) {
|
||||
Callback(td::actor::ActorId<CoreActor> id) : id_(std::move(id)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<CoreActor> id_;
|
||||
td::uint32 idx_;
|
||||
};
|
||||
|
||||
return std::make_unique<Callback>(actor_id(this), idx);
|
||||
return td::make_unique<Callback>(actor_id(this));
|
||||
}
|
||||
|
||||
std::shared_ptr<RemoteNodeStatus> new_result_;
|
||||
td::int32 attempt_ = 0;
|
||||
td::int32 waiting_ = 0;
|
||||
|
||||
std::vector<bool> ready_;
|
||||
size_t n_servers_ = 0;
|
||||
|
||||
void run_queries();
|
||||
void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
|
||||
void send_query(td::uint32 idx);
|
||||
void got_servers_ready(td::int32 attempt, std::vector<bool> ready);
|
||||
void send_ping(td::uint32 idx);
|
||||
void got_ping_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
|
||||
|
||||
void add_result() {
|
||||
if (new_result_) {
|
||||
|
@ -196,12 +191,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;
|
||||
}
|
||||
|
@ -226,10 +215,7 @@ class CoreActor : public CoreActorInterface {
|
|||
hide_ips_ = value;
|
||||
}
|
||||
|
||||
void send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
|
||||
return send_lite_query(0, std::move(data), std::move(promise));
|
||||
}
|
||||
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 {
|
||||
|
@ -449,33 +435,27 @@ class CoreActor : public CoreActorInterface {
|
|||
}
|
||||
|
||||
void run() {
|
||||
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();
|
||||
|
||||
CHECK(gc.liteservers_.size() > 0);
|
||||
td::uint32 size = static_cast<td::uint32>(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<td::uint16>(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<td::BufferSlice> R) {
|
||||
void CoreActor::run_queries() {
|
||||
waiting_ = 0;
|
||||
new_result_ = std::make_shared<RemoteNodeStatus>(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<std::vector<bool>> 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<bool> 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<ton::lite_api::liteServer_getMasterchainInfo>();
|
||||
auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(serialize_tl_object(query, true));
|
||||
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result<td::BufferSlice> 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<td::BufferSlice> R) {
|
||||
if (attempt != attempt_) {
|
||||
return;
|
||||
}
|
||||
|
@ -524,39 +543,7 @@ void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::Buf
|
|||
}
|
||||
}
|
||||
|
||||
void CoreActor::send_query(td::uint32 idx) {
|
||||
if (!ready_[idx]) {
|
||||
return;
|
||||
}
|
||||
waiting_++;
|
||||
auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>();
|
||||
auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(serialize_tl_object(query, true));
|
||||
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result<td::BufferSlice> 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<RemoteNodeStatus>(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<td::BufferSlice> 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<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());
|
||||
|
@ -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<ton::lite_api::liteServer_query>(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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ton::validator::MasterchainState> state,
|
||||
std::set<ton::ShardIdFull> 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<std::vector<ton::BlockIdExt>> promise) override {
|
||||
}
|
||||
void download_archive(ton::BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
|
||||
td::Promise<std::string> promise) override {
|
||||
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||
}
|
||||
|
||||
void new_key_block(ton::validator::BlockHandle handle) override {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<td::uint16>(config.out_port_);
|
||||
if (!out_port) {
|
||||
out_port = 3278;
|
||||
|
@ -162,6 +162,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
control_vec.push_back(ton::create_tl_object<ton::ton_api::engine_controlInterface>(x.second.key.tl(), x.first,
|
||||
std::move(control_proc_vec)));
|
||||
}
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::tonNode_shardId>> shard_vec;
|
||||
|
||||
auto gc_vec = ton::create_tl_object<ton::ton_api::engine_gc>(std::vector<td::Bits256>{});
|
||||
for (auto &id : gc) {
|
||||
|
@ -170,7 +171,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
|
||||
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec),
|
||||
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<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
|
||||
|
|
|
@ -94,7 +94,7 @@ struct Config {
|
|||
ton::tl_object_ptr<ton::ton_api::engine_validator_config> tl() const;
|
||||
|
||||
Config();
|
||||
Config(ton::ton_api::engine_validator_config &config);
|
||||
Config(const ton::ton_api::engine_validator_config &config);
|
||||
};
|
||||
|
||||
class DhtServer : public td::actor::Actor {
|
||||
|
|
|
@ -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)
|
||||
|
|
228
lite-client/ext-client.cpp
Normal file
228
lite-client/ext-client.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ext-client.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "ton/ton-shard.h"
|
||||
|
||||
namespace liteclient {
|
||||
|
||||
class ExtClientImpl : public ExtClient {
|
||||
public:
|
||||
ExtClientImpl(std::vector<LiteServerConfig> liteservers, td::unique_ptr<Callback> 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<td::BufferSlice> 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<td::BufferSlice> 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<std::vector<bool>> promise) override {
|
||||
std::vector<bool> 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<td::BufferSlice> 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<td::BufferSlice> P = [SelfId = actor_id(this), server_idx,
|
||||
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::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<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;
|
||||
}
|
||||
}
|
||||
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<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::on_server_error, idx_);
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<ExtClientImpl> 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<Callback>(actor_id(this), server_idx));
|
||||
}
|
||||
|
||||
struct Server {
|
||||
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();
|
||||
};
|
||||
std::vector<Server> servers_;
|
||||
std::vector<size_t> server_indices_;
|
||||
|
||||
td::unique_ptr<Callback> 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> ExtClient::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
td::unique_ptr<Callback> callback) {
|
||||
return create({LiteServerConfig{dst, dst_addr}}, std::move(callback));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ExtClient> ExtClient::create(std::vector<LiteServerConfig> liteservers,
|
||||
td::unique_ptr<Callback> callback, bool connect_to_all) {
|
||||
return td::actor::create_actor<ExtClientImpl>("ExtClient", std::move(liteservers), std::move(callback),
|
||||
connect_to_all);
|
||||
}
|
||||
} // namespace liteclient
|
48
lite-client/ext-client.h
Normal file
48
lite-client/ext-client.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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<td::BufferSlice> promise) = 0;
|
||||
virtual void send_query_to_server(std::string name, td::BufferSlice data, size_t server_idx, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
promise.set_error(td::Status::Error("not supported"));
|
||||
}
|
||||
virtual void get_servers_status(td::Promise<std::vector<bool>> promise) {
|
||||
promise.set_error(td::Status::Error("not supported"));
|
||||
}
|
||||
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<LiteServerConfig> liteservers,
|
||||
td::unique_ptr<Callback> callback, bool connect_to_all = false);
|
||||
};
|
||||
} // namespace liteclient
|
|
@ -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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "git.h"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
@ -77,24 +67,6 @@ using td::Ref;
|
|||
|
||||
int verbosity;
|
||||
|
||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> TestNode::make_callback() {
|
||||
class Callback : public ton::adnl::AdnlExtClient::Callback {
|
||||
public:
|
||||
void on_ready() override {
|
||||
td::actor::send_closure(id_, &TestNode::conn_ready);
|
||||
}
|
||||
void on_stop_ready() override {
|
||||
td::actor::send_closure(id_, &TestNode::conn_closed);
|
||||
}
|
||||
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<TestNode> id_;
|
||||
};
|
||||
return std::make_unique<Callback>(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<Cb>(actor_id(this)));
|
||||
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
|
||||
|
||||
if (remote_public_key_.empty()) {
|
||||
std::vector<liteclient::LiteServerConfig> 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<td::uint32>(gc.liteservers_.size() - 1));
|
||||
CHECK(idx >= 0 && static_cast<td::uint32>(idx) <= gc.liteservers_.size());
|
||||
auto& cli = gc.liteservers_[idx];
|
||||
remote_addr_.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
|
||||
remote_public_key_ = ton::PublicKey{cli->id_};
|
||||
td::TerminalIO::out() << "using liteserver " << idx << " with addr " << remote_addr_ << "\n";
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client_ =
|
||||
ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_}, remote_addr_, make_callback());
|
||||
if (single_liteserver_idx_ != -1) { // Use single liteserver from config
|
||||
CHECK(single_liteserver_idx_ >= 0 && (size_t)single_liteserver_idx_ < 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;
|
||||
|
||||
run_init_queries();
|
||||
}
|
||||
|
||||
void TestNode::got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise) {
|
||||
|
@ -191,8 +173,8 @@ bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise<td::Buffer
|
|||
});
|
||||
td::BufferSlice b =
|
||||
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query)), true);
|
||||
td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
|
||||
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<td::BufferSlice> res, int mode) {
|
||||
server_ok_ = false;
|
||||
mc_server_ok_ = false;
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "cannot get server version and time (server too old?)";
|
||||
} else {
|
||||
|
@ -344,11 +327,11 @@ void TestNode::got_server_version(td::Result<td::BufferSlice> res, int mode) {
|
|||
LOG(ERROR) << "cannot parse answer to liteServer.getVersion";
|
||||
} else {
|
||||
auto a = F.move_as_ok();
|
||||
set_server_version(a->version_, a->capabilities_);
|
||||
set_server_time(a->now_);
|
||||
set_mc_server_version(a->version_, a->capabilities_);
|
||||
set_mc_server_time(a->now_);
|
||||
}
|
||||
}
|
||||
if (!server_ok_) {
|
||||
if (!mc_server_ok_) {
|
||||
LOG(ERROR) << "server version is too old (at least " << (min_ls_version >> 8) << "." << (min_ls_version & 0xff)
|
||||
<< " with capabilities " << min_ls_capabilities << " required), some queries are unavailable";
|
||||
}
|
||||
|
@ -357,24 +340,24 @@ void TestNode::got_server_version(td::Result<td::BufferSlice> res, int mode) {
|
|||
}
|
||||
}
|
||||
|
||||
void TestNode::set_server_version(td::int32 version, td::int64 capabilities) {
|
||||
if (server_version_ != version || server_capabilities_ != capabilities) {
|
||||
server_version_ = version;
|
||||
server_capabilities_ = capabilities;
|
||||
LOG(WARNING) << "server version is " << (server_version_ >> 8) << "." << (server_version_ & 0xff)
|
||||
<< ", capabilities " << server_capabilities_;
|
||||
void TestNode::set_mc_server_version(td::int32 version, td::int64 capabilities) {
|
||||
if (mc_server_version_ != version || mc_server_capabilities_ != capabilities) {
|
||||
mc_server_version_ = version;
|
||||
mc_server_capabilities_ = capabilities;
|
||||
LOG(WARNING) << "server version is " << (mc_server_version_ >> 8) << "." << (mc_server_version_ & 0xff)
|
||||
<< ", capabilities " << mc_server_capabilities_;
|
||||
}
|
||||
server_ok_ = (server_version_ >= min_ls_version) && !(~server_capabilities_ & min_ls_capabilities);
|
||||
mc_server_ok_ = (mc_server_version_ >= min_ls_version) && !(~mc_server_capabilities_ & min_ls_capabilities);
|
||||
}
|
||||
|
||||
void TestNode::set_server_time(int server_utime) {
|
||||
server_time_ = server_utime;
|
||||
server_time_got_at_ = now();
|
||||
LOG(INFO) << "server time is " << server_time_ << " (delta " << server_time_ - server_time_got_at_ << ")";
|
||||
void TestNode::set_mc_server_time(int server_utime) {
|
||||
mc_server_time_ = server_utime;
|
||||
mc_server_time_got_at_ = now();
|
||||
LOG(INFO) << "server time is " << mc_server_time_ << " (delta " << mc_server_time_ - mc_server_time_got_at_ << ")";
|
||||
}
|
||||
|
||||
bool TestNode::get_server_mc_block_id() {
|
||||
int mode = (server_capabilities_ & 2) ? 0 : -1;
|
||||
int mode = (mc_server_capabilities_ & 2) ? 0 : -1;
|
||||
if (mode < 0) {
|
||||
auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>(), true);
|
||||
return envelope_send_query(std::move(b), [Self = actor_id(this)](td::Result<td::BufferSlice> res) -> void {
|
||||
|
@ -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);
|
||||
|
|
|
@ -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<ton::adnl::AdnlExtClient> client_;
|
||||
td::actor::ActorOwn<liteclient::ExtClient> client_;
|
||||
td::actor::ActorOwn<td::TerminalIO> 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<ton::BlockIdExt> known_blk_ids_;
|
||||
std::size_t shown_blk_ids_ = 0;
|
||||
|
||||
|
@ -89,8 +89,6 @@ class TestNode : public td::actor::Actor {
|
|||
|
||||
std::map<td::Bits256, Ref<vm::Cell>> cell_cache_;
|
||||
|
||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback();
|
||||
|
||||
using creator_stats_func_t =
|
||||
std::function<bool(const td::Bits256&, const block::DiscountedCounter&, const block::DiscountedCounter&)>;
|
||||
|
||||
|
@ -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<vm::StackEntry>& 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<ton::PublicKey> {
|
||||
|
@ -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<ton::PublicKey> {
|
||||
|
@ -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<td::BufferSlice> promise);
|
||||
void parse_line(td::BufferSlice data);
|
||||
|
||||
TestNode() {
|
||||
}
|
||||
TestNode() = default;
|
||||
|
||||
void run();
|
||||
};
|
||||
|
|
400
lite-client/query-utils.cpp
Normal file
400
lite-client/query-utils.cpp
Normal file
|
@ -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 <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) {
|
||||
// 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<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
|
89
lite-client/query-utils.hpp
Normal file
89
lite-client/query-utils.hpp
Normal 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
|
|
@ -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<ton::validator::MasterchainState> state,
|
||||
std::set<ton::ShardIdFull> 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<std::vector<ton::BlockIdExt>> promise) override {
|
||||
}
|
||||
void download_archive(ton::BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
|
||||
td::Promise<std::string> promise) override {
|
||||
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||
}
|
||||
|
||||
void new_key_block(ton::validator::BlockHandle handle) override {
|
||||
|
|
|
@ -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;
|
||||
|
|
Binary file not shown.
|
@ -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<BlockIdExt> shard_blocks;
|
||||
UnixTime start_time, end_time;
|
||||
|
||||
virtual CntObject* make_copy() const {
|
||||
return new PersistentStateDescription(*this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) {
|
||||
|
@ -63,75 +65,26 @@ td::Result<ton::BlockIdExt> parse_block_id_ext(td::JsonObject &obj) {
|
|||
td::Result<Config> 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)");
|
||||
//}
|
||||
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(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<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 (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)");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
if (!conf.validator_->zero_state_) {
|
||||
return td::Status::Error("Invalid config: no zerostate");
|
||||
}
|
||||
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_);
|
||||
}
|
||||
|
||||
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)");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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<ton::BlockIdExt> hardforks;
|
||||
std::vector<LiteClient> lite_clients;
|
||||
std::vector<liteclient::LiteServerConfig> lite_servers;
|
||||
std::string name;
|
||||
static td::Result<Config> parse(std::string str);
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlic
|
|||
if (client_.adnl_ext_client_.empty()) {
|
||||
return P.set_error(TonlibError::NoLiteServers());
|
||||
}
|
||||
td::actor::send_closure(client_.adnl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
|
||||
td::actor::send_closure(client_.adnl_ext_client_, &liteclient::ExtClient::send_query, "query", std::move(query),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "td/utils/Container.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
#include "ExtClientLazy.h"
|
||||
#include "lite-client/ext-client.h"
|
||||
#include "TonlibError.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -38,7 +38,7 @@ class LastConfig;
|
|||
struct LastBlockState;
|
||||
struct LastConfigState;
|
||||
struct ExtClientRef {
|
||||
td::actor::ActorId<ExtClientLazy> adnl_ext_client_;
|
||||
td::actor::ActorId<liteclient::ExtClient> adnl_ext_client_;
|
||||
td::actor::ActorId<LastBlock> last_block_actor_;
|
||||
td::actor::ActorId<LastConfig> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers,
|
||||
td::unique_ptr<ExtClientLazy::Callback> 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<td::Unit> 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<td::BufferSlice> promise) override {
|
||||
before_query();
|
||||
if (client_.empty()) {
|
||||
return promise.set_error(TonlibError::Cancelled());
|
||||
}
|
||||
td::Promise<td::BufferSlice> P = [SelfId = actor_id(this), idx = cur_server_idx_,
|
||||
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, &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<ExtClientLazyImp> 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<ExtClientLazyImp> 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<Callback>(td::actor::actor_shared(this), cur_server_idx_));
|
||||
}
|
||||
|
||||
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers_;
|
||||
size_t cur_server_idx_ = 0;
|
||||
bool cur_server_bad_ = false;
|
||||
bool cur_server_bad_force_ = false;
|
||||
|
||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
|
||||
td::unique_ptr<ExtClientLazy::Callback> 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> ExtClientLazy::create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
td::unique_ptr<Callback> callback) {
|
||||
return create({std::make_pair(dst, dst_addr)}, std::move(callback));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ExtClientLazy> ExtClientLazy::create(
|
||||
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback) {
|
||||
return td::actor::create_actor<ExtClientLazyImp>("ExtClientLazy", std::move(servers), std::move(callback));
|
||||
}
|
||||
} // namespace tonlib
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<ExtClientLazy> create(ton::adnl::AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
td::unique_ptr<Callback> callback);
|
||||
static td::actor::ActorOwn<ExtClientLazy> create(
|
||||
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers, td::unique_ptr<Callback> callback);
|
||||
};
|
||||
|
||||
} // namespace tonlib
|
|
@ -20,15 +20,12 @@
|
|||
#include "ExtClientOutbound.h"
|
||||
#include "TonlibError.h"
|
||||
#include <map>
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
class ExtClientOutboundImp : public ExtClientOutbound {
|
||||
class ExtClientOutboundImpl : public ExtClientOutbound {
|
||||
public:
|
||||
ExtClientOutboundImp(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
|
||||
}
|
||||
|
||||
void check_ready(td::Promise<td::Unit> promise) override {
|
||||
promise.set_error(td::Status::Error("Not supported"));
|
||||
ExtClientOutboundImpl(td::unique_ptr<ExtClientOutbound::Callback> callback) : callback_(std::move(callback)) {
|
||||
}
|
||||
|
||||
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
|
||||
|
@ -38,9 +35,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
|||
callback_->request(query_id, data.as_slice().str());
|
||||
}
|
||||
|
||||
void force_change_liteserver() override {
|
||||
}
|
||||
|
||||
void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
|
||||
auto it = queries_.find(id);
|
||||
if (it == queries_.end()) {
|
||||
|
@ -66,6 +60,6 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
|||
};
|
||||
|
||||
td::actor::ActorOwn<ExtClientOutbound> ExtClientOutbound::create(td::unique_ptr<Callback> callback) {
|
||||
return td::actor::create_actor<ExtClientOutboundImp>("ExtClientOutbound", std::move(callback));
|
||||
return td::actor::create_actor<ExtClientOutboundImpl>("ExtClientOutbound", std::move(callback));
|
||||
}
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -18,11 +18,10 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "ExtClientLazy.h"
|
||||
#include "lite-client/ext-client.h"
|
||||
|
||||
namespace tonlib {
|
||||
class ExtClientOutbound : public ExtClientLazy {
|
||||
class ExtClientOutbound : public liteclient::ExtClient {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
#include "TonlibClient.h"
|
||||
|
||||
#include "tonlib/ExtClientLazy.h"
|
||||
#include "tonlib/ExtClientOutbound.h"
|
||||
#include "tonlib/LastBlock.h"
|
||||
#include "tonlib/LastConfig.h"
|
||||
|
@ -2184,21 +2183,8 @@ void TonlibClient::init_ext_client() {
|
|||
ext_client_outbound_ = client.get();
|
||||
raw_client_ = std::move(client);
|
||||
} else {
|
||||
std::vector<std::pair<ton::adnl::AdnlNodeIdFull, td::IPAddress>> servers;
|
||||
for (const auto& s : config_.lite_clients) {
|
||||
servers.emplace_back(s.adnl_id, s.address);
|
||||
}
|
||||
class Callback : public ExtClientLazy::Callback {
|
||||
public:
|
||||
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<> parent_;
|
||||
};
|
||||
ext_client_outbound_ = {};
|
||||
ref_cnt_++;
|
||||
raw_client_ = ExtClientLazy::create(std::move(servers), td::make_unique<Callback>(td::actor::actor_shared()));
|
||||
raw_client_ = liteclient::ExtClient::create(config_.lite_servers, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2860,7 +2846,7 @@ td::Result<TonlibClient::FullConfig> TonlibClient::validate_config(tonlib_api::o
|
|||
TRY_RESULT_PREFIX(new_config, Config::parse(std::move(config->config_)),
|
||||
TonlibError::InvalidConfig("can't parse config"));
|
||||
|
||||
if (new_config.lite_clients.empty() && !config->use_callbacks_for_network_) {
|
||||
if (new_config.lite_servers.empty() && !config->use_callbacks_for_network_) {
|
||||
return TonlibError::InvalidConfig("no lite clients");
|
||||
}
|
||||
td::optional<Config> o_master_config;
|
||||
|
@ -4613,7 +4599,7 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_getLibraries& request,
|
|||
if (query_context_.block_id) {
|
||||
get_libraries(query_context_.block_id.value(), request.library_list_, std::move(promise));
|
||||
} else {
|
||||
client_.with_last_block([this, promise = std::move(promise), library_list = request.library_list_](td::Result<LastBlockState> r_last_block) mutable {
|
||||
client_.with_last_block([this, promise = std::move(promise), library_list = request.library_list_](td::Result<LastBlockState> r_last_block) mutable {
|
||||
if (r_last_block.is_error()) {
|
||||
promise.set_error(r_last_block.move_as_error_prefix(TonlibError::Internal("get last block failed ")));
|
||||
} else {
|
||||
|
@ -4647,7 +4633,7 @@ void TonlibClient::get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256>
|
|||
|
||||
client_.send_query(ton::lite_api::liteServer_getLibrariesWithProof(ton::create_tl_lite_block_id(blkid), 1, std::move(not_cached_hashes)),
|
||||
promise.wrap([self=this, blkid, result_entries = std::move(result_entries), not_cached_hashes]
|
||||
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResultWithProof>> r_libraries) mutable
|
||||
(td::Result<ton::lite_api::object_ptr<ton::lite_api::liteServer_libraryResultWithProof>> r_libraries) mutable
|
||||
-> td::Result<tonlib_api::object_ptr<tonlib_api::smc_libraryResult>> {
|
||||
if (r_libraries.is_error()) {
|
||||
LOG(WARNING) << "cannot obtain found libraries: " << r_libraries.move_as_error().to_string();
|
||||
|
@ -4674,7 +4660,7 @@ void TonlibClient::get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256>
|
|||
auto csr = libraries_dict.lookup(hash.bits(), 256);
|
||||
if (csr.is_null()) {
|
||||
LOG(WARNING) << "library " << hash.to_hex() << " not found in config";
|
||||
if (std::any_of(libraries->result_.begin(), libraries->result_.end(),
|
||||
if (std::any_of(libraries->result_.begin(), libraries->result_.end(),
|
||||
[&hash](const auto& lib) { return lib->hash_.bits().equals(hash.cbits(), 256); })) {
|
||||
return TonlibError::Internal("library is included in response but it's not found in proof");
|
||||
}
|
||||
|
@ -4685,7 +4671,7 @@ void TonlibClient::get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256>
|
|||
return TonlibError::Internal("cannot unpack LibDescr record");
|
||||
}
|
||||
|
||||
auto lib_it = std::find_if(libraries->result_.begin(), libraries->result_.end(),
|
||||
auto lib_it = std::find_if(libraries->result_.begin(), libraries->result_.end(),
|
||||
[&hash](const auto& lib) { return lib->hash_.bits().equals(hash.cbits(), 256); });
|
||||
if (lib_it == libraries->result_.end()) {
|
||||
return TonlibError::Internal("library is found in proof but not in response");
|
||||
|
@ -4703,7 +4689,7 @@ void TonlibClient::get_libraries(ton::BlockIdExt blkid, std::vector<td::Bits256>
|
|||
if (contents.ok()->get_hash() != libdescr.lib->get_hash()) {
|
||||
return TonlibError::Internal(PSLICE() << "library hash mismatch data " << lib->hash_.to_hex() << " != proof " << libdescr.lib->get_hash().to_hex());
|
||||
}
|
||||
|
||||
|
||||
result_entries.push_back(tonlib_api::make_object<tonlib_api::smc_libraryEntry>(lib->hash_, lib->data_.as_slice().str()));
|
||||
self->libraries.set_ref(lib->hash_, contents.move_as_ok());
|
||||
LOG(DEBUG) << "registered library " << lib->hash_.to_hex();
|
||||
|
@ -5667,14 +5653,14 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& reques
|
|||
auto blkid = ton::BlockId(request.id_->workchain_, request.id_->shard_, request.id_->seqno_);
|
||||
client_.with_last_block(
|
||||
[self = this, blkid, lite_block = std::move(lite_block), mode = request.mode_, lt = (td::uint64)request.lt_,
|
||||
utime = (td::uint32)request.utime_, promise = std::move(promise)](td::Result<LastBlockState> r_last_block) mutable {
|
||||
utime = (td::uint32)request.utime_, promise = std::move(promise)](td::Result<LastBlockState> r_last_block) mutable {
|
||||
if (r_last_block.is_error()) {
|
||||
promise.set_error(r_last_block.move_as_error_prefix(TonlibError::Internal("get last block failed ")));
|
||||
return;
|
||||
}
|
||||
|
||||
self->client_.send_query(ton::lite_api::liteServer_lookupBlockWithProof(mode, std::move(lite_block), ton::create_tl_lite_block_id(r_last_block.ok().last_block_id), lt, utime),
|
||||
promise.wrap([blkid, mode, utime, lt, last_block = r_last_block.ok().last_block_id](lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>&& result)
|
||||
promise.wrap([blkid, mode, utime, lt, last_block = r_last_block.ok().last_block_id](lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>&& result)
|
||||
-> td::Result<object_ptr<tonlib_api::ton_blockIdExt>> {
|
||||
TRY_STATUS(check_lookup_block_proof(result, mode, blkid, last_block, lt, utime));
|
||||
return to_tonlib_api(*result->id_);
|
||||
|
@ -5706,7 +5692,7 @@ td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_looku
|
|||
if (state.is_error()) {
|
||||
LOG(WARNING) << "cannot check state proof: " << state.move_as_error().to_string();
|
||||
return state.move_as_error();
|
||||
}
|
||||
}
|
||||
auto state_root = state.move_as_ok();
|
||||
auto prev_blocks_dict = block::get_prev_blocks_dict(state_root);
|
||||
if (!prev_blocks_dict) {
|
||||
|
@ -5816,7 +5802,7 @@ td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_looku
|
|||
if (!(tlb::unpack_cell(prev_root, prev_blk) && tlb::unpack_cell(prev_blk.info, prev_info))) {
|
||||
return td::Status::Error("prev header unpack failed");
|
||||
}
|
||||
|
||||
|
||||
if (mode & 2) {
|
||||
if (prev_info.end_lt > lt) {
|
||||
return td::Status::Error("prev header end_lt > lt");
|
||||
|
@ -5831,7 +5817,7 @@ td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_looku
|
|||
if (info.gen_utime < utime) {
|
||||
return td::Status::Error("header end_lt < lt");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
return td::Status::Error(PSLICE() << "error while checking lookupBlock proof: " << err.get_msg());
|
||||
|
@ -5937,7 +5923,7 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
|
|||
bool check_proof = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::WANT_PROOF_MASK;
|
||||
bool reverse_mode = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::REVERSE_ORDER_MASK;
|
||||
bool has_starting_tx = request.mode_ & ton::lite_api::liteServer_listBlockTransactions::AFTER_MASK;
|
||||
|
||||
|
||||
td::Bits256 start_addr;
|
||||
ton::LogicalTime start_lt;
|
||||
ton::lite_api::object_ptr<ton::lite_api::liteServer_transactionId3> after;
|
||||
|
@ -5945,7 +5931,7 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getTransactions& re
|
|||
if (!request.after_) {
|
||||
return td::Status::Error("Missing field `after`");
|
||||
}
|
||||
TRY_RESULT_ASSIGN(start_addr, to_bits256(request.after_->account_, "account"));
|
||||
TRY_RESULT_ASSIGN(start_addr, to_bits256(request.after_->account_, "account"));
|
||||
start_lt = request.after_->lt_;
|
||||
after = ton::lite_api::make_object<ton::lite_api::liteServer_transactionId3>(start_addr, start_lt);
|
||||
} else {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "td/utils/optional.h"
|
||||
|
||||
#include "smc-envelope/ManualDns.h"
|
||||
#include "lite-client/ext-client.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
|
@ -113,7 +114,7 @@ class TonlibClient : public td::actor::Actor {
|
|||
vm::Dictionary libraries{256};
|
||||
|
||||
// network
|
||||
td::actor::ActorOwn<ExtClientLazy> raw_client_;
|
||||
td::actor::ActorOwn<liteclient::ExtClient> raw_client_;
|
||||
td::actor::ActorId<ExtClientOutbound> ext_client_outbound_;
|
||||
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
||||
td::actor::ActorOwn<LastConfig> raw_last_config_;
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
#include "tonlib/TonlibClient.h"
|
||||
#include "tonlib/TonlibCallback.h"
|
||||
|
||||
#include "tonlib/ExtClientLazy.h"
|
||||
|
||||
#include "smc-envelope/ManualDns.h"
|
||||
#include "smc-envelope/PaymentChannel.h"
|
||||
|
||||
|
@ -57,6 +55,7 @@
|
|||
#include "crypto/util/Miner.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/CellBuilder.h"
|
||||
#include "lite-client/ext-client.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <iostream>
|
||||
|
@ -174,7 +173,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
|
||||
std::map<std::uint64_t, td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>> query_handlers_;
|
||||
|
||||
td::actor::ActorOwn<tonlib::ExtClientLazy> raw_client_;
|
||||
td::actor::ActorOwn<liteclient::ExtClient> raw_client_;
|
||||
|
||||
bool is_closing_{false};
|
||||
td::uint32 ref_cnt_{1};
|
||||
|
@ -223,11 +222,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
|
||||
if (options_.use_callbacks_for_network) {
|
||||
auto config = tonlib::Config::parse(options_.config).move_as_ok();
|
||||
auto lite_clients_size = config.lite_clients.size();
|
||||
CHECK(lite_clients_size != 0);
|
||||
auto lite_client_id = td::Random::fast(0, td::narrow_cast<int>(lite_clients_size) - 1);
|
||||
auto& lite_client = config.lite_clients[lite_client_id];
|
||||
class Callback : public tonlib::ExtClientLazy::Callback {
|
||||
class Callback : public liteclient::ExtClient::Callback {
|
||||
public:
|
||||
explicit Callback(td::actor::ActorShared<> parent) : parent_(std::move(parent)) {
|
||||
}
|
||||
|
@ -236,14 +231,14 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::actor::ActorShared<> parent_;
|
||||
};
|
||||
ref_cnt_++;
|
||||
raw_client_ = tonlib::ExtClientLazy::create(lite_client.adnl_id, lite_client.address,
|
||||
raw_client_ = liteclient::ExtClient::create(config.lite_servers,
|
||||
td::make_unique<Callback>(td::actor::actor_shared()));
|
||||
}
|
||||
|
||||
auto config = !options_.config.empty()
|
||||
? make_object<tonlib_api::config>(options_.config, options_.name,
|
||||
options_.use_callbacks_for_network, options_.ignore_cache)
|
||||
: nullptr;
|
||||
? make_object<tonlib_api::config>(options_.config, options_.name,
|
||||
options_.use_callbacks_for_network, options_.ignore_cache)
|
||||
: nullptr;
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::KeyStoreType> ks_type;
|
||||
if (options_.in_memory) {
|
||||
|
@ -1545,7 +1540,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
auto update = tonlib_api::move_object_as<tonlib_api::updateSendLiteServerQuery>(std::move(result));
|
||||
CHECK(!raw_client_.empty());
|
||||
snd_bytes_ += update->data_.size();
|
||||
send_closure(raw_client_, &ton::adnl::AdnlExtClient::send_query, "query", td::BufferSlice(update->data_),
|
||||
send_closure(raw_client_, &liteclient::ExtClient::send_query, "query", td::BufferSlice(update->data_),
|
||||
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));
|
||||
|
|
|
@ -21,4 +21,7 @@ add_executable(opcode-timing opcode-timing.cpp )
|
|||
target_link_libraries(opcode-timing ton_crypto)
|
||||
target_include_directories(pack-viewer PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..)
|
||||
|
||||
add_executable(proxy-liteserver proxy-liteserver.cpp)
|
||||
target_link_libraries(proxy-liteserver tdutils tdactor adnl dht tl_api ton_crypto git lite-client-common)
|
||||
|
||||
install(TARGETS generate-random-id RUNTIME DESTINATION bin)
|
||||
|
|
473
utils/proxy-liteserver.cpp
Normal file
473
utils/proxy-liteserver.cpp
Normal file
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
*/
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "td/utils/OptionParser.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/port/signals.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 "tl-utils/lite-utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "adnl/adnl.h"
|
||||
#include "lite-client/ext-client.h"
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <auto/tl/lite_api.hpp>
|
||||
#include "td/utils/tl_storers.h"
|
||||
|
||||
using namespace ton;
|
||||
|
||||
class ProxyLiteserver : public td::actor::Actor {
|
||||
public:
|
||||
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_.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 = parse_global_config();
|
||||
if (S.is_error()) {
|
||||
LOG(FATAL) << S;
|
||||
}
|
||||
|
||||
run_clients();
|
||||
create_ext_server();
|
||||
}
|
||||
|
||||
td::Status prepare_local_config() {
|
||||
auto r_conf_data = td::read_file(config_file());
|
||||
if (r_conf_data.is_ok()) {
|
||||
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(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 (id_.empty()) {
|
||||
auto pk = PrivateKey{privkeys::Ed25519::random()};
|
||||
id_ = adnl::AdnlNodeIdFull{pk.compute_public_key()};
|
||||
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: ");
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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_, 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());
|
||||
});
|
||||
}
|
||||
|
||||
void created_ext_server(td::actor::ActorOwn<adnl::AdnlExtServer> s) {
|
||||
ext_server_ = std::move(s);
|
||||
LOG(WARNING) << "Started proxy liteserver on port " << port_;
|
||||
alarm();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
++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) {
|
||||
// Like in ValidatorManagerImpl::run_ext_query
|
||||
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()) {
|
||||
promise.set_error(G.move_as_error());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tl_object_ptr<lite_api::liteServer_waitMasterchainSeqno> wait_mc_seqno_obj;
|
||||
auto E = fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true);
|
||||
if (E.is_ok()) {
|
||||
wait_mc_seqno_obj = E.move_as_ok();
|
||||
}
|
||||
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(),
|
||||
wait_mc_seqno =
|
||||
(wait_mc_seqno_obj ? wait_mc_seqno_obj->seqno_ : 0)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_ok()) {
|
||||
LOG(INFO) << "Query " << query_info.to_str()
|
||||
<< (wait_mc_seqno ? PSTRING() << " (wait seqno " << wait_mc_seqno << ")" : "")
|
||||
<< ": OK, time=" << timer.elapsed() << ", response_size=" << R.ok().size();
|
||||
promise.set_value(R.move_as_ok());
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Query " << query_info.to_str()
|
||||
<< (wait_mc_seqno ? PSTRING() << " (wait seqno " << wait_mc_seqno << ")" : "") << ": " << 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));
|
||||
Server& server = servers_[server_idx];
|
||||
LOG(INFO) << "Sending query " << query_info.to_str()
|
||||
<< (wait_mc_seqno_obj ? PSTRING() << " (wait seqno " << wait_mc_seqno_obj->seqno_ << ")" : "")
|
||||
<< ", size=" << data.size() << ", to server #" << server_idx << " (" << server.config.addr.get_ip_str()
|
||||
<< ":" << server.config.addr.get_port() << ")";
|
||||
|
||||
BlockSeqno wait_mc_seqno = wait_mc_seqno_obj ? wait_mc_seqno_obj->seqno_ : 0;
|
||||
wait_mc_seqno = std::max(wait_mc_seqno, last_known_masterchain_seqno_);
|
||||
if (server.last_known_masterchain_seqno < wait_mc_seqno) {
|
||||
int timeout_ms = wait_mc_seqno_obj ? wait_mc_seqno_obj->timeout_ms_ : 8000;
|
||||
data = serialize_tl_object(create_tl_object<lite_api::liteServer_waitMasterchainSeqno>(wait_mc_seqno, timeout_ms),
|
||||
true, std::move(data));
|
||||
}
|
||||
data = create_serialize_tl_object<lite_api::liteServer_query>(std::move(data));
|
||||
td::actor::send_closure(server.client, &adnl::AdnlExtClient::send_query, "q", std::move(data),
|
||||
td::Timestamp::in(8.0),
|
||||
[SelfId = actor_id(this), promise = std::move(promise), server_idx,
|
||||
wait_mc_seqno](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_ok()) {
|
||||
td::actor::send_closure(SelfId, &ProxyLiteserver::process_query_response,
|
||||
R.ok().clone(), server_idx, wait_mc_seqno);
|
||||
}
|
||||
promise.set_result(std::move(R));
|
||||
});
|
||||
}
|
||||
|
||||
void process_query_response(td::BufferSlice data, size_t server_idx, BlockSeqno wait_mc_seqno) {
|
||||
auto F = fetch_tl_object<lite_api::Object>(data, true);
|
||||
if (F.is_error() || F.ok()->get_id() == lite_api::liteServer_error::ID) {
|
||||
return;
|
||||
}
|
||||
BlockSeqno new_seqno = wait_mc_seqno;
|
||||
lite_api::downcast_call(*F.ok_ref(), td::overloaded(
|
||||
[&](lite_api::liteServer_masterchainInfo& f) {
|
||||
new_seqno = std::max<BlockSeqno>(new_seqno, f.last_->seqno_);
|
||||
},
|
||||
[&](lite_api::liteServer_masterchainInfoExt& f) {
|
||||
new_seqno = std::max<BlockSeqno>(new_seqno, f.last_->seqno_);
|
||||
},
|
||||
[&](lite_api::liteServer_accountState& f) {
|
||||
if (f.id_->workchain_ == masterchainId) {
|
||||
new_seqno = std::max<BlockSeqno>(new_seqno, f.id_->seqno_);
|
||||
}
|
||||
},
|
||||
[&](auto& obj) {}));
|
||||
servers_[server_idx].last_known_masterchain_seqno =
|
||||
std::max(servers_[server_idx].last_known_masterchain_seqno, new_seqno);
|
||||
if (new_seqno > last_known_masterchain_seqno_) {
|
||||
last_known_masterchain_seqno_ = new_seqno;
|
||||
LOG(INFO) << "Last known masterchain seqno = " << new_seqno;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
sb << " TOTAL:" << total;
|
||||
LOG(WARNING) << sb.as_cslice();
|
||||
ls_stats_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
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_;
|
||||
|
||||
td::actor::ActorOwn<keyring::Keyring> keyring_;
|
||||
td::actor::ActorOwn<adnl::Adnl> adnl_;
|
||||
td::actor::ActorOwn<adnl::AdnlExtServer> ext_server_;
|
||||
|
||||
struct Server {
|
||||
liteclient::LiteServerConfig config;
|
||||
td::actor::ActorOwn<adnl::AdnlExtClient> client;
|
||||
bool alive = false;
|
||||
BlockSeqno last_known_masterchain_seqno = 0;
|
||||
};
|
||||
std::vector<Server> servers_;
|
||||
|
||||
std::map<int, td::uint32> ls_stats_; // lite_api ID -> count, 0 for unknown
|
||||
|
||||
BlockSeqno last_known_masterchain_seqno_ = 0;
|
||||
tl_object_ptr<lite_api::liteServer_masterchainInfoExt> last_masterchain_info_;
|
||||
|
||||
std::string config_file() const {
|
||||
return db_root_ + "/config.json";
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
SET_VERBOSITY_LEVEL(verbosity_WARNING);
|
||||
td::set_default_failure_signal_handler().ensure();
|
||||
|
||||
td::unique_ptr<td::LogInterface> logger_;
|
||||
SCOPE_EXIT {
|
||||
td::log_interface = td::default_log_interface;
|
||||
};
|
||||
|
||||
std::string global_config, db_root;
|
||||
td::uint16 port = 0;
|
||||
PublicKeyHash public_key_hash = PublicKeyHash::zero();
|
||||
td::uint32 threads = 4;
|
||||
|
||||
td::OptionParser p;
|
||||
p.set_description("Proxy liteserver: distributes incoming queries to servers in global config\n");
|
||||
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
||||
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
|
||||
SET_VERBOSITY_LEVEL(v);
|
||||
});
|
||||
p.add_option('V', "version", "show build information", [&]() {
|
||||
std::cout << "proxy-liteserver build information: [ Commit: " << GitMetadata::CommitSHA1()
|
||||
<< ", Date: " << GitMetadata::CommitDate() << "]\n";
|
||||
std::exit(0);
|
||||
});
|
||||
p.add_option('h', "help", "print help", [&]() {
|
||||
char b[10240];
|
||||
td::StringBuilder sb(td::MutableSlice{b, 10000});
|
||||
sb << p;
|
||||
std::cout << sb.as_cslice().c_str();
|
||||
std::exit(2);
|
||||
});
|
||||
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) {
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
close(0);
|
||||
setsid();
|
||||
#endif
|
||||
}).ensure();
|
||||
});
|
||||
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
|
||||
logger_ = td::FileLog::create(fname.str()).move_as_ok();
|
||||
td::log_interface = logger_.get();
|
||||
});
|
||||
p.add_checked_option('t', "threads", PSTRING() << "number of threads (default=" << 4 << ")",
|
||||
[&](td::Slice arg) -> td::Status {
|
||||
TRY_RESULT_ASSIGN(threads, td::to_integer_safe<td::uint32>(arg));
|
||||
return td::Status::OK();
|
||||
});
|
||||
|
||||
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, public_key_hash)
|
||||
.release();
|
||||
});
|
||||
while (scheduler.run(1)) {
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
|
@ -35,6 +35,7 @@
|
|||
#include "ton/ton-tl.hpp"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "tl/tl_json.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
|
@ -948,8 +949,18 @@ td::Status GetOverlaysStatsJsonQuery::receive(td::BufferSlice data) {
|
|||
|
||||
sb << " \"" << t->key_ << "\": \"" << t->value_ << "\"";
|
||||
}
|
||||
sb << "\n }\n";
|
||||
sb << "}\n";
|
||||
sb << "\n }";
|
||||
if (!s->extra_.empty()) {
|
||||
sb << ",\n \"extra\": ";
|
||||
for (char c : s->extra_) {
|
||||
if (c == '\n') {
|
||||
sb << "\n ";
|
||||
} else {
|
||||
sb << c;
|
||||
}
|
||||
}
|
||||
}
|
||||
sb << "\n}\n";
|
||||
}
|
||||
sb << "]\n";
|
||||
sb << std::flush;
|
||||
|
@ -1216,6 +1227,12 @@ td::Status ShowCustomOverlaysQuery::receive(td::BufferSlice data) {
|
|||
: "")
|
||||
<< (node->block_sender_ ? " (block sender)" : "") << "\n";
|
||||
}
|
||||
if (!overlay->sender_shards_.empty()) {
|
||||
td::TerminalIO::out() << "Sender shards:\n";
|
||||
for (const auto &shard : overlay->sender_shards_) {
|
||||
td::TerminalIO::out() << " " << ton::create_shard_id(shard).to_str() << "\n";
|
||||
}
|
||||
}
|
||||
td::TerminalIO::out() << "\n";
|
||||
}
|
||||
return td::Status::OK();
|
||||
|
@ -1482,3 +1499,43 @@ td::Status GetAdnlStatsQuery::receive(td::BufferSlice data) {
|
|||
td::TerminalIO::out() << sb.as_cslice();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddShardQuery::run() {
|
||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddShardQuery::send() {
|
||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addShard>(
|
||||
ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_)));
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddShardQuery::receive(td::BufferSlice data) {
|
||||
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
|
||||
"received incorrect answer: ");
|
||||
td::TerminalIO::out() << "successfully added shard\n";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status DelShardQuery::run() {
|
||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status DelShardQuery::send() {
|
||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_delShard>(
|
||||
ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_)));
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status DelShardQuery::receive(td::BufferSlice data) {
|
||||
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
|
||||
"received incorrect answer: ");
|
||||
td::TerminalIO::out() << "successfully removed shard\n";
|
||||
return td::Status::OK();
|
||||
}
|
|
@ -1362,3 +1362,49 @@ class GetAdnlStatsQuery : public Query {
|
|||
std::string file_name_;
|
||||
bool all_ = false;
|
||||
};
|
||||
|
||||
class AddShardQuery : public Query {
|
||||
public:
|
||||
AddShardQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||
: Query(console, std::move(tokenizer)) {
|
||||
}
|
||||
td::Status run() override;
|
||||
td::Status send() override;
|
||||
td::Status receive(td::BufferSlice data) override;
|
||||
static std::string get_name() {
|
||||
return "addshard";
|
||||
}
|
||||
static std::string get_help() {
|
||||
return "addshard <workchain> <shard>\tstart monitoring shard";
|
||||
}
|
||||
std::string name() const override {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
td::int32 wc_;
|
||||
td::int64 shard_;
|
||||
};
|
||||
|
||||
class DelShardQuery : public Query {
|
||||
public:
|
||||
DelShardQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||
: Query(console, std::move(tokenizer)) {
|
||||
}
|
||||
td::Status run() override;
|
||||
td::Status send() override;
|
||||
td::Status receive(td::BufferSlice data) override;
|
||||
static std::string get_name() {
|
||||
return "delshard";
|
||||
}
|
||||
static std::string get_help() {
|
||||
return "delshard <workchain> <shard>\tstop monitoring shard";
|
||||
}
|
||||
std::string name() const override {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
td::int32 wc_;
|
||||
td::int64 shard_;
|
||||
};
|
|
@ -153,6 +153,8 @@ void ValidatorEngineConsole::run() {
|
|||
add_query_runner(std::make_unique<QueryRunnerImpl<GetCollatorOptionsJsonQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<GetAdnlStatsJsonQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<GetAdnlStatsQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<AddShardQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<DelShardQuery>>());
|
||||
}
|
||||
|
||||
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "td/utils/Random.h"
|
||||
|
||||
#include "auto/tl/lite_api.h"
|
||||
#include "tl/tl_json.h"
|
||||
|
||||
#include "memprof/memprof.h"
|
||||
|
||||
|
@ -64,10 +65,10 @@
|
|||
#endif
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include "git.h"
|
||||
#include "block-auto.h"
|
||||
#include "block-parse.h"
|
||||
|
@ -84,7 +85,7 @@ Config::Config() {
|
|||
full_node = ton::PublicKeyHash::zero();
|
||||
}
|
||||
|
||||
Config::Config(ton::ton_api::engine_validator_config &config) {
|
||||
Config::Config(const ton::ton_api::engine_validator_config &config) {
|
||||
full_node = ton::PublicKeyHash::zero();
|
||||
out_port = static_cast<td::uint16>(config.out_port_);
|
||||
if (!out_port) {
|
||||
|
@ -97,7 +98,7 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
std::vector<AdnlCategory> categories;
|
||||
std::vector<AdnlCategory> priority_categories;
|
||||
ton::ton_api::downcast_call(
|
||||
*addr.get(),
|
||||
*addr,
|
||||
td::overloaded(
|
||||
[&](const ton::ton_api::engine_addr &obj) {
|
||||
in_ip.init_ipv4_port(td::IPAddress::ipv4_to_str(obj.ip_), static_cast<td::uint16>(obj.port_)).ensure();
|
||||
|
@ -179,6 +180,10 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto &shard : config.shards_to_monitor_) {
|
||||
config_add_shard(ton::create_shard_id(shard)).ensure();
|
||||
}
|
||||
|
||||
if (config.gc_) {
|
||||
for (auto &gc : config.gc_->ids_) {
|
||||
config_add_gc(ton::PublicKeyHash{gc}).ensure();
|
||||
|
@ -262,14 +267,21 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
std::move(control_proc_vec)));
|
||||
}
|
||||
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::tonNode_shardId>> shards_vec;
|
||||
for (auto &shard : shards_to_monitor) {
|
||||
shards_vec.push_back(ton::create_tl_shard_id(shard));
|
||||
}
|
||||
|
||||
auto gc_vec = ton::create_tl_object<ton::ton_api::engine_gc>(std::vector<td::Bits256>{});
|
||||
for (auto &id : gc) {
|
||||
gc_vec->ids_.push_back(id.tl());
|
||||
}
|
||||
|
||||
return ton::create_tl_object<ton::ton_api::engine_validator_config>(
|
||||
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), full_node.tl(),
|
||||
std::move(full_node_slaves_vec), std::move(full_node_masters_vec), std::move(full_node_config_obj),
|
||||
std::move(extra_config_obj), std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec));
|
||||
out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec),
|
||||
full_node.tl(), std::move(full_node_slaves_vec), std::move(full_node_masters_vec),
|
||||
std::move(full_node_config_obj), std::move(extra_config_obj), std::move(liteserver_vec), std::move(control_vec),
|
||||
std::move(shards_vec), std::move(gc_vec));
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip,
|
||||
|
@ -532,6 +544,32 @@ td::Result<bool> Config::config_add_control_process(ton::PublicKeyHash key, td::
|
|||
}
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_shard(ton::ShardIdFull shard) {
|
||||
if (shard.is_masterchain()) {
|
||||
return td::Status::Error("masterchain is monitored by default");
|
||||
}
|
||||
if (!shard.is_valid_ext()) {
|
||||
return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str());
|
||||
}
|
||||
if (std::find(shards_to_monitor.begin(), shards_to_monitor.end(), shard) != shards_to_monitor.end()) {
|
||||
return false;
|
||||
}
|
||||
shards_to_monitor.push_back(shard);
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_del_shard(ton::ShardIdFull shard) {
|
||||
if (!shard.is_valid_ext()) {
|
||||
return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str());
|
||||
}
|
||||
auto it = std::find(shards_to_monitor.begin(), shards_to_monitor.end(), shard);
|
||||
if (it == shards_to_monitor.end()) {
|
||||
return false;
|
||||
}
|
||||
shards_to_monitor.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_gc(ton::PublicKeyHash key) {
|
||||
return gc.insert(key).second;
|
||||
}
|
||||
|
@ -1393,15 +1431,6 @@ td::Status ValidatorEngine::load_global_config() {
|
|||
}
|
||||
|
||||
validator_options_ = ton::validator::ValidatorManagerOptions::create(zero_state, init_block);
|
||||
validator_options_.write().set_shard_check_function(
|
||||
[](ton::ShardIdFull shard, ton::CatchainSeqno cc_seqno,
|
||||
ton::validator::ValidatorManagerOptions::ShardCheckMode mode) -> bool {
|
||||
if (mode == ton::validator::ValidatorManagerOptions::ShardCheckMode::m_monitor) {
|
||||
return true;
|
||||
}
|
||||
CHECK(mode == ton::validator::ValidatorManagerOptions::ShardCheckMode::m_validate);
|
||||
return true;
|
||||
});
|
||||
if (state_ttl_ != 0) {
|
||||
validator_options_.write().set_state_ttl(state_ttl_);
|
||||
}
|
||||
|
@ -1490,6 +1519,28 @@ td::Status ValidatorEngine::load_global_config() {
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void ValidatorEngine::set_shard_check_function() {
|
||||
if (!not_all_shards_) {
|
||||
validator_options_.write().set_shard_check_function([](ton::ShardIdFull shard) -> bool { return true; });
|
||||
} else {
|
||||
std::vector<ton::ShardIdFull> shards = {ton::ShardIdFull(ton::masterchainId)};
|
||||
for (const auto& s : config_.shards_to_monitor) {
|
||||
shards.push_back(s);
|
||||
}
|
||||
std::sort(shards.begin(), shards.end());
|
||||
shards.erase(std::unique(shards.begin(), shards.end()), shards.end());
|
||||
validator_options_.write().set_shard_check_function(
|
||||
[shards = std::move(shards)](ton::ShardIdFull shard) -> bool {
|
||||
for (auto s : shards) {
|
||||
if (shard_intersects(shard, s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ValidatorEngine::load_empty_local_config(td::Promise<td::Unit> promise) {
|
||||
auto ret_promise = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
|
@ -1531,6 +1582,14 @@ void ValidatorEngine::load_empty_local_config(td::Promise<td::Unit> promise) {
|
|||
}
|
||||
|
||||
void ValidatorEngine::load_local_config(td::Promise<td::Unit> promise) {
|
||||
for (ton::ShardIdFull shard : add_shard_cmds_) {
|
||||
auto R = config_.config_add_shard(shard);
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "Cannot add shard " << shard.to_str() << " : " << R.move_as_error();
|
||||
} else if (R.ok()) {
|
||||
LOG(WARNING) << "Adding shard to monitor " << shard.to_str();
|
||||
}
|
||||
}
|
||||
if (local_config_.size() == 0) {
|
||||
load_empty_local_config(std::move(promise));
|
||||
return;
|
||||
|
@ -1746,6 +1805,15 @@ void ValidatorEngine::load_config(td::Promise<td::Unit> promise) {
|
|||
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key_short, key.first, get_key_promise(ig));
|
||||
}
|
||||
|
||||
for (ton::ShardIdFull shard : add_shard_cmds_) {
|
||||
auto R = config_.config_add_shard(shard);
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "Cannot add shard " << shard.to_str() << " : " << R.move_as_error();
|
||||
} else if (R.ok()) {
|
||||
LOG(WARNING) << "Adding shard to monitor " << shard.to_str();
|
||||
}
|
||||
}
|
||||
|
||||
write_config(ig.get_promise());
|
||||
}
|
||||
|
||||
|
@ -1781,6 +1849,7 @@ void ValidatorEngine::got_key(ton::PublicKey key) {
|
|||
}
|
||||
|
||||
void ValidatorEngine::start() {
|
||||
set_shard_check_function();
|
||||
read_config_ = true;
|
||||
start_adnl();
|
||||
}
|
||||
|
@ -1876,6 +1945,8 @@ void ValidatorEngine::started_dht() {
|
|||
void ValidatorEngine::start_rldp() {
|
||||
rldp_ = ton::rldp::Rldp::create(adnl_.get());
|
||||
rldp2_ = ton::rldp2::Rldp::create(adnl_.get());
|
||||
td::actor::send_closure(rldp_, &ton::rldp::Rldp::set_default_mtu, 2048);
|
||||
td::actor::send_closure(rldp2_, &ton::rldp2::Rldp::set_default_mtu, 2048);
|
||||
started_rldp();
|
||||
}
|
||||
|
||||
|
@ -1939,24 +2010,27 @@ void ValidatorEngine::start_full_node() {
|
|||
};
|
||||
full_node_client_ = ton::adnl::AdnlExtMultiClient::create(std::move(vec), std::make_unique<Cb>());
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &ValidatorEngine::started_full_node);
|
||||
});
|
||||
full_node_ = ton::validator::fullnode::FullNode::create(
|
||||
short_id, ton::adnl::AdnlNodeIdShort{config_.full_node}, validator_options_->zero_block_id().file_hash,
|
||||
config_.full_node_config, keyring_.get(), adnl_.get(), rldp_.get(), rldp2_.get(),
|
||||
default_dht_node_.is_zero() ? td::actor::ActorId<ton::dht::Dht>{} : dht_nodes_[default_dht_node_].get(),
|
||||
overlay_manager_.get(), validator_manager_.get(), full_node_client_.get(), db_root_);
|
||||
overlay_manager_.get(), validator_manager_.get(), full_node_client_.get(), db_root_, std::move(P));
|
||||
for (auto &v : config_.validators) {
|
||||
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_permanent_key, v.first,
|
||||
[](td::Unit) {});
|
||||
}
|
||||
load_custom_overlays_config();
|
||||
if (!validator_telemetry_filename_.empty()) {
|
||||
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::set_validator_telemetry_filename,
|
||||
validator_telemetry_filename_);
|
||||
}
|
||||
} else {
|
||||
started_full_node();
|
||||
}
|
||||
|
||||
for (auto &v : config_.validators) {
|
||||
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_permanent_key, v.first,
|
||||
[](td::Unit) {});
|
||||
}
|
||||
|
||||
started_full_node();
|
||||
}
|
||||
|
||||
void ValidatorEngine::started_full_node() {
|
||||
|
@ -3928,6 +4002,74 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getAdnlSt
|
|||
});
|
||||
}
|
||||
|
||||
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addShard &query,
|
||||
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||
return;
|
||||
}
|
||||
if (!started_) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
||||
return;
|
||||
}
|
||||
|
||||
auto shard = ton::create_shard_id(query.shard_);
|
||||
auto R = config_.config_add_shard(shard);
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
return;
|
||||
}
|
||||
set_shard_check_function();
|
||||
if (!validator_manager_.empty()) {
|
||||
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
|
||||
validator_options_);
|
||||
}
|
||||
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
} else {
|
||||
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delShard &query,
|
||||
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||
return;
|
||||
}
|
||||
if (!started_) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
|
||||
return;
|
||||
}
|
||||
|
||||
auto shard = ton::create_shard_id(query.shard_);
|
||||
auto R = config_.config_del_shard(shard);
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
return;
|
||||
}
|
||||
if (!R.move_as_ok()) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error("No such shard")));
|
||||
return;
|
||||
}
|
||||
set_shard_check_function();
|
||||
if (!validator_manager_.empty()) {
|
||||
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
|
||||
validator_options_);
|
||||
}
|
||||
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||
} else {
|
||||
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
|
||||
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
@ -3961,7 +4103,7 @@ void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNode
|
|||
}
|
||||
auto f = F.move_as_ok();
|
||||
|
||||
ton::ton_api::downcast_call(*f.get(), [&](auto &obj) {
|
||||
ton::ton_api::downcast_call(*f, [&](auto &obj) {
|
||||
run_control_query(obj, std::move(data), src.pubkey_hash(), it->second, std::move(promise));
|
||||
});
|
||||
}
|
||||
|
@ -4220,6 +4362,23 @@ int main(int argc, char *argv[]) {
|
|||
});
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('M', "not-all-shards", "monitor only a necessary set of shards instead of all", [&]() {
|
||||
acts.push_back([&x]() { td::actor::send_closure(x, &ValidatorEngine::set_not_all_shards); });
|
||||
});
|
||||
p.add_checked_option(
|
||||
'\0', "add-shard", "add shard to monitor (same as addshard in validator console), format: 0:8000000000000000",
|
||||
[&](td::Slice arg) -> td::Status {
|
||||
std::string str = arg.str();
|
||||
int wc;
|
||||
unsigned long long shard;
|
||||
if (sscanf(str.c_str(), "%d:%016llx", &wc, &shard) != 2) {
|
||||
return td::Status::Error(PSTRING() << "invalid shard " << str);
|
||||
}
|
||||
acts.push_back([=, &x]() {
|
||||
td::actor::send_closure(x, &ValidatorEngine::add_shard_cmd, ton::ShardIdFull{wc, (ton::ShardId)shard});
|
||||
});
|
||||
return td::Status::OK();
|
||||
});
|
||||
td::uint32 threads = 7;
|
||||
p.add_checked_option(
|
||||
't', "threads", PSTRING() << "number of threads (default=" << threads << ")", [&](td::Slice arg) {
|
||||
|
|
|
@ -89,6 +89,7 @@ struct Config {
|
|||
ton::validator::fullnode::FullNodeConfig full_node_config;
|
||||
std::map<td::int32, Control> controls;
|
||||
std::set<ton::PublicKeyHash> gc;
|
||||
std::vector<ton::ShardIdFull> shards_to_monitor;
|
||||
|
||||
bool state_serializer_enabled = true;
|
||||
|
||||
|
@ -115,6 +116,8 @@ struct Config {
|
|||
td::Result<bool> config_add_control_interface(ton::PublicKeyHash key, td::int32 port);
|
||||
td::Result<bool> config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id,
|
||||
td::uint32 permissions);
|
||||
td::Result<bool> config_add_shard(ton::ShardIdFull shard);
|
||||
td::Result<bool> config_del_shard(ton::ShardIdFull shard);
|
||||
td::Result<bool> config_add_gc(ton::PublicKeyHash key);
|
||||
td::Result<bool> config_del_network_addr(td::IPAddress addr, std::vector<AdnlCategory> cats,
|
||||
std::vector<AdnlCategory> prio_cats);
|
||||
|
@ -132,7 +135,7 @@ struct Config {
|
|||
ton::tl_object_ptr<ton::ton_api::engine_validator_config> tl() const;
|
||||
|
||||
Config();
|
||||
Config(ton::ton_api::engine_validator_config &config);
|
||||
Config(const ton::ton_api::engine_validator_config &config);
|
||||
};
|
||||
|
||||
class ValidatorEngine : public td::actor::Actor {
|
||||
|
@ -223,6 +226,8 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
std::string session_logs_file_;
|
||||
bool fast_state_serializer_enabled_ = false;
|
||||
std::string validator_telemetry_filename_;
|
||||
bool not_all_shards_ = false;
|
||||
std::vector<ton::ShardIdFull> add_shard_cmds_;
|
||||
|
||||
std::set<ton::CatchainSeqno> unsafe_catchains_;
|
||||
std::map<ton::BlockSeqno, std::pair<ton::CatchainSeqno, td::uint32>> unsafe_catchain_rotations_;
|
||||
|
@ -314,6 +319,13 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
void set_validator_telemetry_filename(std::string value) {
|
||||
validator_telemetry_filename_ = std::move(value);
|
||||
}
|
||||
void set_not_all_shards() {
|
||||
not_all_shards_ = true;
|
||||
}
|
||||
void add_shard_cmd(ton::ShardIdFull shard) {
|
||||
add_shard_cmds_.push_back(shard);
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
ValidatorEngine() {
|
||||
}
|
||||
|
@ -323,6 +335,7 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
void load_empty_local_config(td::Promise<td::Unit> promise);
|
||||
void load_local_config(td::Promise<td::Unit> promise);
|
||||
void load_config(td::Promise<td::Unit> promise);
|
||||
void set_shard_check_function();
|
||||
|
||||
void start();
|
||||
|
||||
|
@ -484,6 +497,10 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_getActorTextStats &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_addShard &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_delShard &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_getPerfTimerStats &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_getShardOutQueueSize &query, td::BufferSlice data,
|
||||
|
|
|
@ -624,7 +624,7 @@ void ArchiveManager::load_package(PackageId id) {
|
|||
}
|
||||
}
|
||||
|
||||
desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, db_root_,
|
||||
desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, 0, db_root_,
|
||||
archive_lru_.get(), statistics_);
|
||||
|
||||
m.emplace(id, std::move(desc));
|
||||
|
@ -659,7 +659,8 @@ const ArchiveManager::FileDescription *ArchiveManager::add_file_desc(ShardIdFull
|
|||
FileDescription new_desc{id, false};
|
||||
td::mkdir(db_root_ + id.path()).ensure();
|
||||
std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
|
||||
new_desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, db_root_,
|
||||
new_desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false,
|
||||
id.key || id.temp ? 0 : cur_shard_split_depth_, db_root_,
|
||||
archive_lru_.get(), statistics_);
|
||||
const FileDescription &desc = f.emplace(id, std::move(new_desc));
|
||||
if (!id.temp) {
|
||||
|
@ -1132,14 +1133,16 @@ PackageId ArchiveManager::get_package_id_force(BlockSeqno masterchain_seqno, Sha
|
|||
return it->first;
|
||||
}
|
||||
|
||||
void ArchiveManager::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
|
||||
void ArchiveManager::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) {
|
||||
auto F = get_file_desc_by_seqno(ShardIdFull{masterchainId}, masterchain_seqno, false);
|
||||
if (!F) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "archive not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(F->file_actor_id(), &ArchiveSlice::get_archive_id, masterchain_seqno, std::move(promise));
|
||||
td::actor::send_closure(F->file_actor_id(), &ArchiveSlice::get_archive_id, masterchain_seqno, shard_prefix,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void ArchiveManager::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
|
|
|
@ -67,7 +67,7 @@ class ArchiveManager : public td::actor::Actor {
|
|||
void get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<ConstBlockHandle> promise);
|
||||
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<ConstBlockHandle> promise);
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise);
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise);
|
||||
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
|
||||
|
@ -77,6 +77,10 @@ class ArchiveManager : public td::actor::Actor {
|
|||
void commit_transaction();
|
||||
void set_async_mode(bool mode, td::Promise<td::Unit> promise);
|
||||
|
||||
void set_current_shard_split_depth(td::uint32 value) {
|
||||
cur_shard_split_depth_ = value;
|
||||
}
|
||||
|
||||
static constexpr td::uint32 archive_size() {
|
||||
return 20000;
|
||||
}
|
||||
|
@ -175,6 +179,7 @@ class ArchiveManager : public td::actor::Actor {
|
|||
bool async_mode_ = false;
|
||||
bool huge_transaction_started_ = false;
|
||||
td::uint32 huge_transaction_size_ = 0;
|
||||
td::uint32 cur_shard_split_depth_ = 0;
|
||||
|
||||
DbStatistics statistics_;
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class PackageStatistics {
|
|||
void record_close(uint64_t count = 1) {
|
||||
close_count.fetch_add(count, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
||||
void record_read(double time, uint64_t bytes) {
|
||||
read_bytes.fetch_add(bytes, std::memory_order_relaxed);
|
||||
std::lock_guard guard(read_mutex);
|
||||
|
@ -56,10 +56,10 @@ class PackageStatistics {
|
|||
std::stringstream ss;
|
||||
ss.setf(std::ios::fixed);
|
||||
ss.precision(6);
|
||||
|
||||
|
||||
ss << "ton.pack.open COUNT : " << open_count.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
ss << "ton.pack.close COUNT : " << close_count.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
|
||||
|
||||
ss << "ton.pack.read.bytes COUNT : " << read_bytes.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
ss << "ton.pack.write.bytes COUNT : " << write_bytes.exchange(0, std::memory_order_relaxed) << "\n";
|
||||
|
||||
|
@ -118,7 +118,7 @@ void PackageWriter::append(std::string filename, td::BufferSlice data,
|
|||
return;
|
||||
}
|
||||
start = td::Timestamp::now();
|
||||
offset = p->append(std::move(filename), std::move(data), !async_mode_);
|
||||
offset = p->append(std::move(filename), std::move(data), !async_mode_);
|
||||
end = td::Timestamp::now();
|
||||
size = p->size();
|
||||
}
|
||||
|
@ -152,6 +152,21 @@ class PackageReader : public td::actor::Actor {
|
|||
std::shared_ptr<PackageStatistics> statistics_;
|
||||
};
|
||||
|
||||
static std::string get_package_file_name(PackageId p_id, ShardIdFull shard_prefix) {
|
||||
td::StringBuilder sb;
|
||||
sb << p_id.name();
|
||||
if (!shard_prefix.is_masterchain()) {
|
||||
sb << ".";
|
||||
sb << shard_prefix.workchain << ":" << shard_to_str(shard_prefix.shard);
|
||||
}
|
||||
sb << ".pack";
|
||||
return sb.as_cslice().str();
|
||||
}
|
||||
|
||||
static std::string package_info_to_str(BlockSeqno seqno, ShardIdFull shard_prefix) {
|
||||
return PSTRING() << seqno << "." << shard_prefix.workchain << ":" << shard_to_str(shard_prefix.shard);
|
||||
}
|
||||
|
||||
void ArchiveSlice::add_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
if (destroyed_) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "package already gc'd"));
|
||||
|
@ -271,7 +286,8 @@ void ArchiveSlice::add_file(BlockHandle handle, FileReference ref_id, td::Buffer
|
|||
TRY_RESULT_PROMISE(
|
||||
promise, p,
|
||||
choose_package(
|
||||
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0, true));
|
||||
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0,
|
||||
handle ? handle->id().shard_full() : ShardIdFull{masterchainId}, true));
|
||||
std::string value;
|
||||
auto R = kv_->get(ref_id.hash().to_hex(), value);
|
||||
R.ensure();
|
||||
|
@ -376,7 +392,8 @@ void ArchiveSlice::get_file(ConstBlockHandle handle, FileReference ref_id, td::P
|
|||
TRY_RESULT_PROMISE(
|
||||
promise, p,
|
||||
choose_package(
|
||||
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0, false));
|
||||
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0,
|
||||
handle ? handle->id().shard_full() : ShardIdFull{masterchainId}, false));
|
||||
promise = begin_async_query(std::move(promise));
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise)](td::Result<std::pair<std::string, td::BufferSlice>> R) mutable {
|
||||
|
@ -536,18 +553,32 @@ void ArchiveSlice::get_slice(td::uint64 archive_id, td::uint64 offset, td::uint3
|
|||
}
|
||||
before_query();
|
||||
auto value = static_cast<td::uint32>(archive_id >> 32);
|
||||
TRY_RESULT_PROMISE(promise, p, choose_package(value, false));
|
||||
PackageInfo *p;
|
||||
if (shard_split_depth_ == 0) {
|
||||
TRY_RESULT_PROMISE_ASSIGN(promise, p, choose_package(value, ShardIdFull{masterchainId}, false));
|
||||
} else {
|
||||
if (value >= packages_.size()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "no such package"));
|
||||
return;
|
||||
}
|
||||
p = &packages_[value];
|
||||
}
|
||||
promise = begin_async_query(std::move(promise));
|
||||
td::actor::create_actor<db::ReadFile>("readfile", p->path, offset, limit, 0, std::move(promise)).release();
|
||||
}
|
||||
|
||||
void ArchiveSlice::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
|
||||
void ArchiveSlice::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) {
|
||||
before_query();
|
||||
if (!sliced_mode_) {
|
||||
promise.set_result(archive_id_);
|
||||
} else {
|
||||
TRY_RESULT_PROMISE(promise, p, choose_package(masterchain_seqno, false));
|
||||
promise.set_result(p->id * (1ull << 32) + archive_id_);
|
||||
TRY_RESULT_PROMISE(promise, p, choose_package(masterchain_seqno, shard_prefix, false));
|
||||
if (shard_split_depth_ == 0) {
|
||||
promise.set_result(p->seqno * (1ull << 32) + archive_id_);
|
||||
} else {
|
||||
promise.set_result(p->idx * (1ull << 32) + archive_id_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,9 +604,18 @@ void ArchiveSlice::before_query() {
|
|||
R2.ensure();
|
||||
slice_size_ = td::to_integer<td::uint32>(value);
|
||||
CHECK(slice_size_ > 0);
|
||||
R2 = kv_->get("shard_split_depth", value);
|
||||
R2.ensure();
|
||||
if (R2.move_as_ok() == td::KeyValue::GetStatus::Ok) {
|
||||
shard_split_depth_ = td::to_integer<td::uint32>(value);
|
||||
CHECK(shard_split_depth_ <= 60);
|
||||
} else {
|
||||
shard_split_depth_ = 0;
|
||||
}
|
||||
for (td::uint32 i = 0; i < tot; i++) {
|
||||
R2 = kv_->get(PSTRING() << "status." << i, value);
|
||||
R2.ensure();
|
||||
CHECK(R2.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||
auto len = td::to_integer<td::uint64>(value);
|
||||
R2 = kv_->get(PSTRING() << "version." << i, value);
|
||||
R2.ensure();
|
||||
|
@ -583,12 +623,24 @@ void ArchiveSlice::before_query() {
|
|||
if (R2.move_as_ok() == td::KeyValue::GetStatus::Ok) {
|
||||
ver = td::to_integer<td::uint32>(value);
|
||||
}
|
||||
auto v = archive_id_ + slice_size_ * i;
|
||||
add_package(v, len, ver);
|
||||
td::uint32 seqno;
|
||||
ShardIdFull shard_prefix;
|
||||
if (shard_split_depth_ == 0) {
|
||||
seqno = archive_id_ + slice_size_ * i;
|
||||
shard_prefix = ShardIdFull{masterchainId};
|
||||
} else {
|
||||
R2 = kv_->get(PSTRING() << "info." << i, value);
|
||||
R2.ensure();
|
||||
CHECK(R2.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||
unsigned long long shard;
|
||||
CHECK(sscanf(value.c_str(), "%u.%d:%016llx", &seqno, &shard_prefix.workchain, &shard) == 3);
|
||||
shard_prefix.shard = shard;
|
||||
}
|
||||
add_package(seqno, shard_prefix, len, ver);
|
||||
}
|
||||
} else {
|
||||
auto len = td::to_integer<td::uint64>(value);
|
||||
add_package(archive_id_, len, 0);
|
||||
add_package(archive_id_, ShardIdFull{masterchainId}, len, 0);
|
||||
}
|
||||
} else {
|
||||
if (!temp_ && !key_blocks_only_) {
|
||||
|
@ -599,13 +651,17 @@ void ArchiveSlice::before_query() {
|
|||
kv_->set("slice_size", td::to_string(slice_size_)).ensure();
|
||||
kv_->set("status.0", "0").ensure();
|
||||
kv_->set("version.0", td::to_string(default_package_version())).ensure();
|
||||
if (shard_split_depth_ > 0) {
|
||||
kv_->set("info.0", package_info_to_str(archive_id_, ShardIdFull{masterchainId})).ensure();
|
||||
kv_->set("shard_split_depth", td::to_string(shard_split_depth_)).ensure();
|
||||
}
|
||||
kv_->commit_transaction().ensure();
|
||||
add_package(archive_id_, 0, default_package_version());
|
||||
add_package(archive_id_, ShardIdFull{masterchainId}, 0, default_package_version());
|
||||
} else {
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set("status", "0").ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
add_package(archive_id_, 0, 0);
|
||||
add_package(archive_id_, ShardIdFull{masterchainId}, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -642,6 +698,7 @@ void ArchiveSlice::do_close() {
|
|||
statistics_.pack_statistics->record_close(packages_.size());
|
||||
}
|
||||
packages_.clear();
|
||||
id_to_package_.clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -697,48 +754,61 @@ void ArchiveSlice::set_async_mode(bool mode, td::Promise<td::Unit> promise) {
|
|||
}
|
||||
}
|
||||
|
||||
ArchiveSlice::ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, std::string db_root,
|
||||
ArchiveSlice::ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized,
|
||||
td::uint32 shard_split_depth, std::string db_root,
|
||||
td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics)
|
||||
: archive_id_(archive_id)
|
||||
, key_blocks_only_(key_blocks_only)
|
||||
, temp_(temp)
|
||||
, finalized_(finalized)
|
||||
, p_id_(archive_id_, key_blocks_only_, temp_)
|
||||
, shard_split_depth_(temp || key_blocks_only ? 0 : shard_split_depth)
|
||||
, db_root_(std::move(db_root))
|
||||
, archive_lru_(std::move(archive_lru))
|
||||
, statistics_(statistics) {
|
||||
db_path_ = PSTRING() << db_root_ << p_id_.path() << p_id_.name() << ".index";
|
||||
}
|
||||
|
||||
td::Result<ArchiveSlice::PackageInfo *> ArchiveSlice::choose_package(BlockSeqno masterchain_seqno, bool force) {
|
||||
td::Result<ArchiveSlice::PackageInfo *> ArchiveSlice::choose_package(BlockSeqno masterchain_seqno,
|
||||
ShardIdFull shard_prefix, bool force) {
|
||||
if (temp_ || key_blocks_only_ || !sliced_mode_) {
|
||||
return &packages_[0];
|
||||
}
|
||||
if (masterchain_seqno < archive_id_) {
|
||||
return td::Status::Error(ErrorCode::notready, "too small masterchain seqno");
|
||||
}
|
||||
auto v = (masterchain_seqno - archive_id_) / slice_size_;
|
||||
if (v >= packages_.size()) {
|
||||
masterchain_seqno -= (masterchain_seqno - archive_id_) % slice_size_;
|
||||
CHECK((masterchain_seqno - archive_id_) % slice_size_ == 0);
|
||||
if (shard_split_depth_ == 0) {
|
||||
shard_prefix = ShardIdFull{masterchainId};
|
||||
} else if (!shard_prefix.is_masterchain()) {
|
||||
shard_prefix.shard |= 1; // In case length is < split depth
|
||||
shard_prefix = ton::shard_prefix(shard_prefix, shard_split_depth_);
|
||||
}
|
||||
auto it = id_to_package_.find({masterchain_seqno, shard_prefix});
|
||||
if (it == id_to_package_.end()) {
|
||||
if (!force) {
|
||||
return td::Status::Error(ErrorCode::notready, "too big masterchain seqno");
|
||||
return td::Status::Error(ErrorCode::notready, "no such package");
|
||||
}
|
||||
CHECK(v == packages_.size());
|
||||
begin_transaction();
|
||||
size_t v = packages_.size();
|
||||
kv_->set("slices", td::to_string(v + 1)).ensure();
|
||||
kv_->set(PSTRING() << "status." << v, "0").ensure();
|
||||
kv_->set(PSTRING() << "version." << v, td::to_string(default_package_version())).ensure();
|
||||
if (shard_split_depth_ > 0) {
|
||||
kv_->set(PSTRING() << "info." << v, package_info_to_str(masterchain_seqno, shard_prefix)).ensure();
|
||||
}
|
||||
commit_transaction();
|
||||
CHECK((masterchain_seqno - archive_id_) % slice_size_ == 0);
|
||||
add_package(masterchain_seqno, 0, default_package_version());
|
||||
add_package(masterchain_seqno, shard_prefix, 0, default_package_version());
|
||||
return &packages_[v];
|
||||
} else {
|
||||
return &packages_[v];
|
||||
return &packages_[it->second];
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 version) {
|
||||
void ArchiveSlice::add_package(td::uint32 seqno, ShardIdFull shard_prefix, td::uint64 size, td::uint32 version) {
|
||||
PackageId p_id{seqno, key_blocks_only_, temp_};
|
||||
std::string path = PSTRING() << db_root_ << p_id.path() << p_id.name() << ".pack";
|
||||
std::string path = PSTRING() << db_root_ << p_id.path() << get_package_file_name(p_id, shard_prefix);
|
||||
auto R = Package::open(path, false, true);
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << "failed to open/create archive '" << path << "': " << R.move_as_error();
|
||||
|
@ -748,8 +818,9 @@ void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 ver
|
|||
statistics_.pack_statistics->record_open();
|
||||
}
|
||||
auto idx = td::narrow_cast<td::uint32>(packages_.size());
|
||||
id_to_package_[{seqno, shard_prefix}] = idx;
|
||||
if (finalized_) {
|
||||
packages_.emplace_back(nullptr, td::actor::ActorOwn<PackageWriter>(), seqno, path, idx, version);
|
||||
packages_.emplace_back(nullptr, td::actor::ActorOwn<PackageWriter>(), seqno, shard_prefix, path, idx, version);
|
||||
return;
|
||||
}
|
||||
auto pack = std::make_shared<Package>(R.move_as_ok());
|
||||
|
@ -757,7 +828,7 @@ void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 ver
|
|||
pack->truncate(size).ensure();
|
||||
}
|
||||
auto writer = td::actor::create_actor<PackageWriter>("writer", pack, async_mode_, statistics_.pack_statistics);
|
||||
packages_.emplace_back(std::move(pack), std::move(writer), seqno, path, idx, version);
|
||||
packages_.emplace_back(std::move(pack), std::move(writer), seqno, shard_prefix, path, idx, version);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -790,6 +861,7 @@ void ArchiveSlice::destroy(td::Promise<td::Unit> promise) {
|
|||
statistics_.pack_statistics->record_close(packages_.size());
|
||||
}
|
||||
packages_.clear();
|
||||
id_to_package_.clear();
|
||||
kv_ = nullptr;
|
||||
|
||||
delay_action([name = db_path_, attempt = 0,
|
||||
|
@ -861,7 +933,7 @@ void ArchiveSlice::move_handle(ConstBlockHandle handle, Package *old_pack, Packa
|
|||
move_file(fileref::Block{handle->id()}, old_pack, pack);
|
||||
}
|
||||
|
||||
bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_idx,
|
||||
bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_seqno,
|
||||
Package *pack) {
|
||||
std::string value;
|
||||
auto R = kv_->get(get_db_key_block_info(block_id), value);
|
||||
|
@ -876,18 +948,18 @@ bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block
|
|||
return false;
|
||||
}
|
||||
|
||||
auto S = choose_package(seqno, false);
|
||||
auto S = choose_package(seqno, block_id.shard_full(), false);
|
||||
S.ensure();
|
||||
auto p = S.move_as_ok();
|
||||
CHECK(p->idx <= cutoff_idx);
|
||||
if (p->idx == cutoff_idx) {
|
||||
CHECK(p->seqno <= cutoff_seqno);
|
||||
if (p->seqno == cutoff_seqno) {
|
||||
move_handle(std::move(handle), p->package.get(), pack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_idx,
|
||||
void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_seqno,
|
||||
Package *pack) {
|
||||
auto key = get_db_key_lt_desc(shard);
|
||||
std::string value;
|
||||
|
@ -913,7 +985,7 @@ void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shar
|
|||
E.ensure();
|
||||
auto e = E.move_as_ok();
|
||||
|
||||
if (truncate_block(masterchain_seqno, create_block_id(e->id_), cutoff_idx, pack)) {
|
||||
if (truncate_block(masterchain_seqno, create_block_id(e->id_), cutoff_seqno, pack)) {
|
||||
CHECK(new_last_idx == i);
|
||||
new_last_idx = i + 1;
|
||||
}
|
||||
|
@ -925,7 +997,7 @@ void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shar
|
|||
}
|
||||
}
|
||||
|
||||
void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle, td::Promise<td::Unit> promise) {
|
||||
if (temp_ || archive_id_ > masterchain_seqno) {
|
||||
destroy(std::move(promise));
|
||||
return;
|
||||
|
@ -938,15 +1010,8 @@ void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handl
|
|||
return;
|
||||
}
|
||||
|
||||
auto cutoff = choose_package(masterchain_seqno, false);
|
||||
cutoff.ensure();
|
||||
auto pack = cutoff.move_as_ok();
|
||||
CHECK(pack);
|
||||
|
||||
auto pack_r = Package::open(pack->path + ".new", false, true);
|
||||
pack_r.ensure();
|
||||
auto new_package = std::make_shared<Package>(pack_r.move_as_ok());
|
||||
new_package->truncate(0).ensure();
|
||||
std::map<ShardIdFull, PackageInfo*> old_packages;
|
||||
std::map<ShardIdFull, std::shared_ptr<Package>> new_packages;
|
||||
|
||||
std::string value;
|
||||
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
|
||||
|
@ -967,38 +1032,71 @@ void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handl
|
|||
auto G = fetch_tl_object<ton_api::db_lt_shard_value>(value, true);
|
||||
G.ensure();
|
||||
auto g = G.move_as_ok();
|
||||
ShardIdFull shard{g->workchain_, static_cast<td::uint64>(g->shard_)};
|
||||
|
||||
truncate_shard(masterchain_seqno, ShardIdFull{g->workchain_, static_cast<td::uint64>(g->shard_)}, pack->idx,
|
||||
new_package.get());
|
||||
auto package_r = choose_package(masterchain_seqno, shard, false);
|
||||
if (package_r.is_error()) {
|
||||
continue;
|
||||
}
|
||||
auto package = package_r.move_as_ok();
|
||||
CHECK(package);
|
||||
if (!old_packages.count(package->shard_prefix)) {
|
||||
old_packages[package->shard_prefix] = package;
|
||||
auto new_package_r = Package::open(package->path + ".new", false, true);
|
||||
new_package_r.ensure();
|
||||
auto new_package = std::make_shared<Package>(new_package_r.move_as_ok());
|
||||
new_package->truncate(0).ensure();
|
||||
new_packages[package->shard_prefix] = std::move(new_package);
|
||||
}
|
||||
truncate_shard(masterchain_seqno, shard, package->seqno, new_packages[package->shard_prefix].get());
|
||||
}
|
||||
|
||||
for (auto& [shard_prefix, package] : old_packages) {
|
||||
auto new_package = new_packages[shard_prefix];
|
||||
CHECK(new_package);
|
||||
package->package = new_package;
|
||||
package->writer.reset();
|
||||
td::unlink(package->path).ensure();
|
||||
td::rename(package->path + ".new", package->path).ensure();
|
||||
package->writer = td::actor::create_actor<PackageWriter>("writer", new_package, async_mode_);
|
||||
}
|
||||
|
||||
std::vector<PackageInfo> new_packages_info;
|
||||
|
||||
if (!sliced_mode_) {
|
||||
kv_->set("status", td::to_string(new_package->size())).ensure();
|
||||
kv_->set("status", td::to_string(packages_.at(0).package->size())).ensure();
|
||||
} else {
|
||||
kv_->set(PSTRING() << "status." << pack->idx, td::to_string(new_package->size())).ensure();
|
||||
for (size_t i = pack->idx + 1; i < packages_.size(); i++) {
|
||||
for (PackageInfo &package : packages_) {
|
||||
if (package.seqno <= masterchain_seqno) {
|
||||
new_packages_info.push_back(std::move(package));
|
||||
} else {
|
||||
td::unlink(package.path).ensure();
|
||||
}
|
||||
}
|
||||
id_to_package_.clear();
|
||||
for (td::uint32 i = 0; i < new_packages_info.size(); ++i) {
|
||||
PackageInfo &package = new_packages_info[i];
|
||||
package.idx = i;
|
||||
kv_->set(PSTRING() << "status." << i, td::to_string(package.package->size())).ensure();
|
||||
kv_->set(PSTRING() << "version." << i, td::to_string(package.version)).ensure();
|
||||
if (shard_split_depth_ > 0) {
|
||||
kv_->set(PSTRING() << "info." << i, package_info_to_str(package.seqno, package.shard_prefix)).ensure();
|
||||
}
|
||||
id_to_package_[{package.seqno, package.shard_prefix}] = i;
|
||||
}
|
||||
for (size_t i = new_packages_info.size(); i < packages_.size(); i++) {
|
||||
kv_->erase(PSTRING() << "status." << i);
|
||||
kv_->erase(PSTRING() << "version." << i);
|
||||
kv_->erase(PSTRING() << "info." << i);
|
||||
}
|
||||
kv_->set("slices", td::to_string(pack->idx + 1));
|
||||
kv_->set("slices", td::to_string(new_packages_info.size()));
|
||||
if (statistics_.pack_statistics) {
|
||||
statistics_.pack_statistics->record_close(packages_.size() - new_packages_info.size());
|
||||
}
|
||||
packages_ = std::move(new_packages_info);
|
||||
}
|
||||
|
||||
pack->package = new_package;
|
||||
pack->writer.reset();
|
||||
td::unlink(pack->path).ensure();
|
||||
td::rename(pack->path + ".new", pack->path).ensure();
|
||||
pack->writer = td::actor::create_actor<PackageWriter>("writer", new_package, async_mode_);
|
||||
|
||||
for (auto idx = pack->idx + 1; idx < packages_.size(); idx++) {
|
||||
td::unlink(packages_[idx].path).ensure();
|
||||
}
|
||||
if (statistics_.pack_statistics) {
|
||||
statistics_.pack_statistics->record_close(packages_.size() - pack->idx - 1);
|
||||
}
|
||||
packages_.erase(packages_.begin() + pack->idx + 1, packages_.end());
|
||||
|
||||
kv_->commit_transaction().ensure();
|
||||
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
|
|
|
@ -96,10 +96,10 @@ class ArchiveLru;
|
|||
|
||||
class ArchiveSlice : public td::actor::Actor {
|
||||
public:
|
||||
ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, std::string db_root,
|
||||
td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics = {});
|
||||
ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, td::uint32 shard_split_depth,
|
||||
std::string db_root, td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics = {});
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise);
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise);
|
||||
|
||||
void add_handle(BlockHandle handle, td::Promise<td::Unit> promise);
|
||||
void update_handle(BlockHandle handle, td::Promise<td::Unit> promise);
|
||||
|
@ -159,6 +159,7 @@ class ArchiveSlice : public td::actor::Actor {
|
|||
bool sliced_mode_{false};
|
||||
td::uint32 huge_transaction_size_ = 0;
|
||||
td::uint32 slice_size_{100};
|
||||
td::uint32 shard_split_depth_ = 0;
|
||||
|
||||
enum Status {
|
||||
st_closed, st_open, st_want_close
|
||||
|
@ -171,28 +172,31 @@ class ArchiveSlice : public td::actor::Actor {
|
|||
std::unique_ptr<td::KeyValue> kv_;
|
||||
|
||||
struct PackageInfo {
|
||||
PackageInfo(std::shared_ptr<Package> package, td::actor::ActorOwn<PackageWriter> writer, BlockSeqno id,
|
||||
PackageInfo(std::shared_ptr<Package> package, td::actor::ActorOwn<PackageWriter> writer, BlockSeqno seqno, ShardIdFull shard_prefix,
|
||||
std::string path, td::uint32 idx, td::uint32 version)
|
||||
: package(std::move(package))
|
||||
, writer(std ::move(writer))
|
||||
, id(id)
|
||||
, seqno(seqno)
|
||||
, shard_prefix(shard_prefix)
|
||||
, path(std::move(path))
|
||||
, idx(idx)
|
||||
, version(version) {
|
||||
}
|
||||
std::shared_ptr<Package> package;
|
||||
td::actor::ActorOwn<PackageWriter> writer;
|
||||
BlockSeqno id;
|
||||
BlockSeqno seqno;
|
||||
ShardIdFull shard_prefix;
|
||||
std::string path;
|
||||
td::uint32 idx;
|
||||
td::uint32 version;
|
||||
};
|
||||
std::vector<PackageInfo> packages_;
|
||||
std::map<std::pair<BlockSeqno, ShardIdFull>, td::uint32> id_to_package_;
|
||||
|
||||
td::Result<PackageInfo *> choose_package(BlockSeqno masterchain_seqno, bool force);
|
||||
void add_package(BlockSeqno masterchain_seqno, td::uint64 size, td::uint32 version);
|
||||
void truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_idx, Package *pack);
|
||||
bool truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_idx, Package *pack);
|
||||
td::Result<PackageInfo *> choose_package(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, bool force);
|
||||
void add_package(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::uint64 size, td::uint32 version);
|
||||
void truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_seqno, Package *pack);
|
||||
bool truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_seqno, Package *pack);
|
||||
|
||||
void delete_handle(ConstBlockHandle handle);
|
||||
void delete_file(FileReference ref_id);
|
||||
|
|
|
@ -25,11 +25,27 @@ namespace ton {
|
|||
namespace validator {
|
||||
|
||||
BlockArchiver::BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db,
|
||||
td::Promise<td::Unit> promise)
|
||||
: handle_(std::move(handle)), archive_(archive_db), promise_(std::move(promise)) {
|
||||
td::actor::ActorId<Db> db, td::Promise<td::Unit> promise)
|
||||
: handle_(std::move(handle)), archive_(archive_db), db_(std::move(db)), promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void BlockArchiver::start_up() {
|
||||
if (handle_->id().is_masterchain()) {
|
||||
td::actor::send_closure(db_, &Db::get_block_state, handle_,
|
||||
[SelfId = actor_id(this), archive = archive_](td::Result<td::Ref<ShardState>> R) {
|
||||
R.ensure();
|
||||
td::Ref<MasterchainState> state{R.move_as_ok()};
|
||||
td::uint32 monitor_min_split = state->monitor_min_split_depth(basechainId);
|
||||
td::actor::send_closure(archive, &ArchiveManager::set_current_shard_split_depth,
|
||||
monitor_min_split);
|
||||
td::actor::send_closure(SelfId, &BlockArchiver::move_handle);
|
||||
});
|
||||
} else {
|
||||
move_handle();
|
||||
}
|
||||
}
|
||||
|
||||
void BlockArchiver::move_handle() {
|
||||
if (handle_->handle_moved_to_archive()) {
|
||||
moved_handle();
|
||||
} else {
|
||||
|
|
|
@ -33,11 +33,13 @@ class FileDb;
|
|||
|
||||
class BlockArchiver : public td::actor::Actor {
|
||||
public:
|
||||
BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db, td::Promise<td::Unit> promise);
|
||||
BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db, td::actor::ActorId<Db> db,
|
||||
td::Promise<td::Unit> promise);
|
||||
|
||||
void abort_query(td::Status error);
|
||||
|
||||
void start_up() override;
|
||||
void move_handle();
|
||||
void moved_handle();
|
||||
void got_proof(td::BufferSlice data);
|
||||
void written_proof();
|
||||
|
@ -50,6 +52,7 @@ class BlockArchiver : public td::actor::Actor {
|
|||
private:
|
||||
BlockHandle handle_;
|
||||
td::actor::ActorId<ArchiveManager> archive_;
|
||||
td::actor::ActorId<Db> db_;
|
||||
td::Promise<td::Unit> promise_;
|
||||
};
|
||||
|
||||
|
|
|
@ -347,7 +347,8 @@ void RootDb::try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice
|
|||
}
|
||||
|
||||
void RootDb::apply_block(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<BlockArchiver>("archiver", std::move(handle), archive_db_.get(), std::move(promise))
|
||||
td::actor::create_actor<BlockArchiver>("archiver", std::move(handle), archive_db_.get(), actor_id(this),
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
@ -421,7 +422,8 @@ void RootDb::start_up() {
|
|||
}
|
||||
|
||||
void RootDb::archive(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
td::actor::create_actor<BlockArchiver>("archiveblock", std::move(handle), archive_db_.get(), std::move(promise))
|
||||
td::actor::create_actor<BlockArchiver>("archiveblock", std::move(handle), archive_db_.get(), actor_id(this),
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
@ -501,8 +503,9 @@ void RootDb::check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<
|
|||
std::move(P));
|
||||
}
|
||||
|
||||
void RootDb::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
|
||||
td::actor::send_closure(archive_db_, &ArchiveManager::get_archive_id, masterchain_seqno, std::move(promise));
|
||||
void RootDb::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) {
|
||||
td::actor::send_closure(archive_db_, &ArchiveManager::get_archive_id, masterchain_seqno, shard_prefix,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
|
@ -519,6 +522,14 @@ void RootDb::run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) {
|
|||
td::actor::send_closure(archive_db_, &ArchiveManager::run_gc, mc_ts, gc_ts, archive_ttl);
|
||||
}
|
||||
|
||||
void RootDb::add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::add_persistent_state_description, std::move(desc), std::move(promise));
|
||||
}
|
||||
|
||||
void RootDb::get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) {
|
||||
td::actor::send_closure(state_db_, &StateDb::get_persistent_state_descriptions, std::move(promise));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -132,12 +132,15 @@ class RootDb : public Db {
|
|||
void check_key_block_proof_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
|
||||
void check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override;
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) override;
|
||||
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void set_async_mode(bool mode, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) override;
|
||||
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise) override;
|
||||
void get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) override;
|
||||
|
||||
|
||||
private:
|
||||
td::actor::ActorId<ValidatorManager> validator_manager_;
|
||||
|
|
|
@ -240,6 +240,101 @@ void StateDb::start_up() {
|
|||
}
|
||||
}
|
||||
|
||||
void StateDb::add_persistent_state_description(td::Ref<PersistentStateDescription> desc,
|
||||
td::Promise<td::Unit> promise) {
|
||||
std::string value;
|
||||
auto list_key = create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionsList>();
|
||||
auto R = kv_->get(list_key.as_slice(), value);
|
||||
R.ensure();
|
||||
tl_object_ptr<ton_api::db_state_persistentStateDescriptionsList> list;
|
||||
if (R.ok() == td::KeyValue::GetStatus::Ok) {
|
||||
auto F = fetch_tl_object<ton_api::db_state_persistentStateDescriptionsList>(value, true);
|
||||
F.ensure();
|
||||
list = F.move_as_ok();
|
||||
} else {
|
||||
list = create_tl_object<ton_api::db_state_persistentStateDescriptionsList>(
|
||||
std::vector<tl_object_ptr<ton_api::db_state_persistentStateDescriptionHeader>>());
|
||||
}
|
||||
for (const auto& obj : list->list_) {
|
||||
if ((BlockSeqno)obj->masterchain_id_->seqno_ == desc->masterchain_id.seqno()) {
|
||||
promise.set_error(td::Status::Error("duplicate masterchain seqno"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto now = (UnixTime)td::Clocks::system();
|
||||
size_t new_size = 0;
|
||||
kv_->begin_write_batch().ensure();
|
||||
for (auto& obj : list->list_) {
|
||||
auto end_time = (UnixTime)obj->end_time_;
|
||||
if (end_time <= now) {
|
||||
auto key =
|
||||
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(obj->masterchain_id_->seqno_);
|
||||
kv_->erase(key.as_slice()).ensure();
|
||||
} else {
|
||||
list->list_[new_size++] = std::move(obj);
|
||||
}
|
||||
}
|
||||
list->list_.resize(new_size);
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> shard_blocks;
|
||||
for (const BlockIdExt& block_id : desc->shard_blocks) {
|
||||
shard_blocks.push_back(create_tl_block_id(block_id));
|
||||
}
|
||||
auto key =
|
||||
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(desc->masterchain_id.seqno());
|
||||
kv_->set(key.as_slice(),
|
||||
create_serialize_tl_object<ton_api::db_state_persistentStateDescriptionShards>(std::move(shard_blocks))
|
||||
.as_slice())
|
||||
.ensure();
|
||||
|
||||
list->list_.push_back(create_tl_object<ton_api::db_state_persistentStateDescriptionHeader>(
|
||||
create_tl_block_id(desc->masterchain_id), desc->start_time, desc->end_time));
|
||||
kv_->set(list_key.as_slice(), serialize_tl_object(list, true).as_slice()).ensure();
|
||||
|
||||
kv_->commit_write_batch().ensure();
|
||||
|
||||
promise.set_result(td::Unit());
|
||||
}
|
||||
|
||||
void StateDb::get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) {
|
||||
std::string value;
|
||||
auto R = kv_->get(create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionsList>().as_slice(), value);
|
||||
R.ensure();
|
||||
if (R.ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_value({});
|
||||
return;
|
||||
}
|
||||
auto F = fetch_tl_object<ton_api::db_state_persistentStateDescriptionsList>(value, true);
|
||||
F.ensure();
|
||||
std::vector<td::Ref<PersistentStateDescription>> result;
|
||||
auto now = (UnixTime)td::Clocks::system();
|
||||
for (const auto& obj : F.ok()->list_) {
|
||||
auto end_time = (UnixTime)obj->end_time_;
|
||||
if (end_time <= now) {
|
||||
continue;
|
||||
}
|
||||
PersistentStateDescription desc;
|
||||
desc.start_time = (UnixTime)obj->start_time_;
|
||||
desc.end_time = end_time;
|
||||
desc.masterchain_id = create_block_id(obj->masterchain_id_);
|
||||
auto key =
|
||||
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(desc.masterchain_id.seqno());
|
||||
auto R2 = kv_->get(key.as_slice(), value);
|
||||
R2.ensure();
|
||||
if (R2.ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
continue;
|
||||
}
|
||||
auto F2 = fetch_tl_object<ton_api::db_state_persistentStateDescriptionShards>(value, true);
|
||||
F2.ensure();
|
||||
for (const auto& block_id : F2.ok()->shard_blocks_) {
|
||||
desc.shard_blocks.push_back(create_block_id(block_id));
|
||||
}
|
||||
result.push_back(td::Ref<PersistentStateDescription>(true, std::move(desc)));
|
||||
}
|
||||
promise.set_result(std::move(result));
|
||||
}
|
||||
|
||||
void StateDb::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
{
|
||||
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();
|
||||
|
|
|
@ -50,6 +50,9 @@ class StateDb : public td::actor::Actor {
|
|||
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise);
|
||||
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise);
|
||||
|
||||
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise);
|
||||
void get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise);
|
||||
|
||||
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
|
||||
|
||||
void start_up() override;
|
||||
|
|
|
@ -106,13 +106,24 @@ void WaitBlockData::start() {
|
|||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, handle_->id().file_hash, std::move(P));
|
||||
} else if (try_get_candidate_) {
|
||||
try_get_candidate_ = false;
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::get_candidate_data_by_block_id_from_db, handle_->id(),
|
||||
[SelfId = actor_id(this), id = handle_->id()](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::start);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::loaded_data, ReceivedBlock{id, R.move_as_ok()});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::failed_to_get_block_data_from_net,
|
||||
R.move_as_error_prefix("net error: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::got_data_from_net, R.move_as_ok());
|
||||
td::actor::send_closure(SelfId, &WaitBlockData::loaded_data, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -137,16 +148,16 @@ void WaitBlockData::failed_to_get_block_data_from_net(td::Status reason) {
|
|||
td::Timestamp::in(0.1));
|
||||
}
|
||||
|
||||
void WaitBlockData::got_data_from_net(ReceivedBlock block) {
|
||||
void WaitBlockData::loaded_data(ReceivedBlock block) {
|
||||
auto X = create_block(std::move(block));
|
||||
if (X.is_error()) {
|
||||
failed_to_get_block_data_from_net(X.move_as_error_prefix("bad block from net: "));
|
||||
return;
|
||||
}
|
||||
got_block_data_from_net(X.move_as_ok());
|
||||
loaded_block_data(X.move_as_ok());
|
||||
}
|
||||
|
||||
void WaitBlockData::got_block_data_from_net(td::Ref<BlockData> block) {
|
||||
void WaitBlockData::loaded_block_data(td::Ref<BlockData> block) {
|
||||
if (data_.not_null()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -30,15 +30,16 @@ class ValidatorManager;
|
|||
class WaitBlockData : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockData(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<BlockData>> promise)
|
||||
td::Timestamp timeout, bool try_get_candidate, td::Promise<td::Ref<BlockData>> promise)
|
||||
: handle_(std::move(handle))
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, try_get_candidate_(try_get_candidate)
|
||||
, promise_(std::move(promise))
|
||||
, perf_timer_("waitdata", 1.0, [manager](double duration) {
|
||||
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitdata", duration);
|
||||
}) {
|
||||
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitdata", duration);
|
||||
}) {
|
||||
}
|
||||
|
||||
void update_timeout(td::Timestamp timeout, td::uint32 priority) {
|
||||
|
@ -57,8 +58,8 @@ class WaitBlockData : public td::actor::Actor {
|
|||
void set_is_hardfork(bool value);
|
||||
void start();
|
||||
void got_block_data_from_db(td::Ref<BlockData> data);
|
||||
void got_data_from_net(ReceivedBlock data);
|
||||
void got_block_data_from_net(td::Ref<BlockData> block);
|
||||
void loaded_data(ReceivedBlock data);
|
||||
void loaded_block_data(td::Ref<BlockData> block);
|
||||
void checked_proof_link();
|
||||
void failed_to_get_block_data_from_net(td::Status reason);
|
||||
|
||||
|
@ -73,6 +74,7 @@ class WaitBlockData : public td::actor::Actor {
|
|||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
bool try_get_candidate_;
|
||||
td::Promise<td::Ref<BlockData>> promise_;
|
||||
|
||||
td::Ref<BlockData> data_;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "ton/ton-io.hpp"
|
||||
#include "common/checksum.h"
|
||||
#include "common/delay.h"
|
||||
#include "validator/downloaders/download-state.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -106,6 +107,19 @@ void WaitBlockState::start() {
|
|||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_,
|
||||
std::move(P));
|
||||
} else if (check_persistent_state_desc()) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "failed to get persistent state: " << R.move_as_error();
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::start);
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &WaitBlockState::written_state, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
BlockIdExt masterchain_id = persistent_state_desc_->masterchain_id;
|
||||
td::actor::create_actor<DownloadShardState>("downloadstate", handle_->id(), masterchain_id, priority_, manager_,
|
||||
timeout_, std::move(P))
|
||||
.release();
|
||||
} else if (!handle_->inited_prev() || (!handle_->inited_proof() && !handle_->inited_proof_link())) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
|
|
|
@ -27,12 +27,14 @@ namespace validator {
|
|||
class WaitBlockState : public td::actor::Actor {
|
||||
public:
|
||||
WaitBlockState(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise)
|
||||
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise,
|
||||
td::Ref<PersistentStateDescription> persistent_state_desc = {})
|
||||
: handle_(std::move(handle))
|
||||
, priority_(priority)
|
||||
, manager_(manager)
|
||||
, timeout_(timeout)
|
||||
, promise_(std::move(promise))
|
||||
, persistent_state_desc_(std::move(persistent_state_desc))
|
||||
, perf_timer_("waitstate", 1.0, [manager](double duration) {
|
||||
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitstate", duration);
|
||||
}) {
|
||||
|
@ -90,6 +92,7 @@ class WaitBlockState : public td::actor::Actor {
|
|||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::Ref<ShardState>> promise_;
|
||||
td::Ref<PersistentStateDescription> persistent_state_desc_;
|
||||
|
||||
td::Ref<ShardState> prev_state_;
|
||||
td::Ref<BlockData> block_;
|
||||
|
@ -99,7 +102,15 @@ class WaitBlockState : public td::actor::Actor {
|
|||
bool waiting_proof_ = false;
|
||||
td::Timestamp next_static_file_attempt_;
|
||||
|
||||
td::PerfWarningTimer perf_timer_;
|
||||
td::PerfWarningTimer perf_timer_{"waitstate", 1.0};
|
||||
|
||||
bool check_persistent_state_desc() const {
|
||||
if (persistent_state_desc_.is_null()) {
|
||||
return false;
|
||||
}
|
||||
auto now = (UnixTime)td::Clocks::system();
|
||||
return persistent_state_desc_->end_time > now + 3600 && persistent_state_desc_->start_time < now - 6 * 3600;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -371,7 +371,8 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
|
|||
|
||||
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
promise.set_value(create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version(), proto_capabilities()));
|
||||
promise.set_value(
|
||||
create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version_major(), proto_version_minor(), 0));
|
||||
}
|
||||
|
||||
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
|
||||
|
@ -385,7 +386,7 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
|
|||
}
|
||||
});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
|
||||
std::move(P));
|
||||
ShardIdFull{masterchainId}, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
|
||||
|
|
|
@ -28,10 +28,10 @@ namespace fullnode {
|
|||
|
||||
class FullNodeMasterImpl : public FullNodeMaster {
|
||||
public:
|
||||
static constexpr td::uint32 proto_version() {
|
||||
static constexpr td::uint32 proto_version_major() {
|
||||
return 1;
|
||||
}
|
||||
static constexpr td::uint64 proto_capabilities() {
|
||||
static constexpr td::uint32 proto_version_minor() {
|
||||
return 0;
|
||||
}
|
||||
void start_up() override;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "checksum.h"
|
||||
#include "overlays.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "full-node-shard.hpp"
|
||||
#include "full-node-shard-queries.hpp"
|
||||
#include "full-node-serializer.hpp"
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "td/utils/buffer.h"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
|
||||
#include "adnl/utils.hpp"
|
||||
#include "net/download-block-new.hpp"
|
||||
|
@ -41,6 +41,9 @@
|
|||
#include "td/utils/Random.h"
|
||||
|
||||
#include "common/delay.h"
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "tl/tl_json.h"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -50,9 +53,10 @@ namespace fullnode {
|
|||
|
||||
Neighbour Neighbour::zero = Neighbour{adnl::AdnlNodeIdShort::zero()};
|
||||
|
||||
void Neighbour::update_proto_version(const ton_api::tonNode_capabilities &q) {
|
||||
proto_version = q.version_;
|
||||
capabilities = q.capabilities_;
|
||||
void Neighbour::update_proto_version(ton_api::tonNode_capabilities &q) {
|
||||
version_major = q.version_major_;
|
||||
version_minor = q.version_minor_;
|
||||
flags = q.flags_;
|
||||
}
|
||||
|
||||
void Neighbour::query_success(double t) {
|
||||
|
@ -74,8 +78,9 @@ void Neighbour::update_roundtrip(double t) {
|
|||
void FullNodeShardImpl::create_overlay() {
|
||||
class Callback : public overlay::Overlays::Callback {
|
||||
public:
|
||||
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
|
||||
// just ignore
|
||||
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id,
|
||||
td::BufferSlice data) override {
|
||||
td::actor::send_closure(node_, &FullNodeShardImpl::receive_message, src, std::move(data));
|
||||
}
|
||||
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
|
@ -88,15 +93,22 @@ void FullNodeShardImpl::create_overlay() {
|
|||
td::Promise<td::Unit> promise) override {
|
||||
td::actor::send_closure(node_, &FullNodeShardImpl::check_broadcast, src, std::move(data), std::move(promise));
|
||||
}
|
||||
void get_stats_extra(td::Promise<std::string> promise) override {
|
||||
td::actor::send_closure(node_, &FullNodeShardImpl::get_stats_extra, std::move(promise));
|
||||
}
|
||||
Callback(td::actor::ActorId<FullNodeShardImpl> node) : node_(node) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<FullNodeShardImpl> node_;
|
||||
};
|
||||
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::create_public_overlay, adnl_id_, overlay_id_full_.clone(),
|
||||
std::make_unique<Callback>(actor_id(this)), rules_, PSTRING() << "{ \"type\": \"shard\", \"shard_id\": " << get_shard() << ", \"workchain_id\": " << get_workchain() << " }");
|
||||
overlay::OverlayOptions opts;
|
||||
opts.announce_self_ = active_;
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::create_public_overlay_ex, adnl_id_, overlay_id_full_.clone(),
|
||||
std::make_unique<Callback>(actor_id(this)), rules_,
|
||||
PSTRING() << "{ \"type\": \"shard\", \"shard_id\": " << get_shard()
|
||||
<< ", \"workchain_id\": " << get_workchain() << " }",
|
||||
opts);
|
||||
|
||||
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl_id_);
|
||||
td::actor::send_closure(rldp2_, &rldp2::Rldp::add_id, adnl_id_);
|
||||
|
@ -106,6 +118,9 @@ void FullNodeShardImpl::create_overlay() {
|
|||
}
|
||||
|
||||
void FullNodeShardImpl::check_broadcast(PublicKeyHash src, td::BufferSlice broadcast, td::Promise<td::Unit> promise) {
|
||||
if (!active_) {
|
||||
return promise.set_error(td::Status::Error("cannot check broadcast: shard is not active"));
|
||||
}
|
||||
auto B = fetch_tl_object<ton_api::tonNode_externalMessageBroadcast>(std::move(broadcast), true);
|
||||
if (B.is_error()) {
|
||||
return promise.set_error(B.move_as_error_prefix("failed to parse external message broadcast: "));
|
||||
|
@ -134,6 +149,10 @@ void FullNodeShardImpl::check_broadcast(PublicKeyHash src, td::BufferSlice broad
|
|||
promise.wrap([](td::Ref<ExtMessage>) { return td::Unit(); }));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::remove_neighbour(adnl::AdnlNodeIdShort id) {
|
||||
neighbours_.erase(id);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
|
||||
adnl_id_ = adnl_id;
|
||||
|
@ -141,6 +160,18 @@ void FullNodeShardImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promis
|
|||
create_overlay();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::set_active(bool active) {
|
||||
if (shard_.is_masterchain()) {
|
||||
return;
|
||||
}
|
||||
if (active_ == active) {
|
||||
return;
|
||||
}
|
||||
active_ = active;
|
||||
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
|
||||
create_overlay();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise<ReceivedBlock> promise) {
|
||||
if (timeout.is_in_past()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||
|
@ -148,7 +179,7 @@ void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise<Re
|
|||
}
|
||||
|
||||
auto &b = choose_neighbour();
|
||||
if (!b.adnl_id.is_zero() && b.proto_version >= 1) {
|
||||
if (!b.adnl_id.is_zero() && b.version_major >= 1) {
|
||||
VLOG(FULL_NODE_DEBUG) << "using new download method with adnlid=" << b.adnl_id;
|
||||
td::actor::create_actor<DownloadBlockNew>("downloadnext", adnl_id_, overlay_id_, handle_->id(), b.adnl_id,
|
||||
download_next_priority(), timeout, validator_manager_, rldp_, overlays_,
|
||||
|
@ -187,7 +218,6 @@ void FullNodeShardImpl::got_next_block(td::Result<BlockHandle> R) {
|
|||
}
|
||||
|
||||
void FullNodeShardImpl::get_next_block() {
|
||||
//return;
|
||||
attempt_++;
|
||||
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_, attempt = attempt_,
|
||||
block_id = handle_->id(), SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
||||
|
@ -591,7 +621,8 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
|
|||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
VLOG(FULL_NODE_DEBUG) << "Got query getCapabilities from " << src;
|
||||
promise.set_value(create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version(), proto_capabilities()));
|
||||
promise.set_value(
|
||||
create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version_major(), proto_version_minor(), 0));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
|
||||
|
@ -606,7 +637,24 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
|
|||
});
|
||||
VLOG(FULL_NODE_DEBUG) << "Got query getArchiveInfo " << query.masterchain_seqno_ << " from " << src;
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
|
||||
std::move(P));
|
||||
ShardIdFull{masterchainId}, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getShardArchiveInfo &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::uint64> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_serialize_tl_object<ton_api::tonNode_archiveNotFound>());
|
||||
} else {
|
||||
promise.set_value(create_serialize_tl_object<ton_api::tonNode_archiveInfo>(R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
ShardIdFull shard_prefix = create_shard_id(query.shard_prefix_);
|
||||
VLOG(FULL_NODE_DEBUG) << "Got query getShardArchiveInfo " << query.masterchain_seqno_ << " " << shard_prefix.to_str()
|
||||
<< " from " << src;
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
|
||||
shard_prefix, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
|
||||
|
@ -623,6 +671,12 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
|
|||
|
||||
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!active_) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_message, src, adnl_id_, overlay_id_,
|
||||
create_serialize_tl_object<ton_api::tonNode_forgetPeer>());
|
||||
promise.set_error(td::Status::Error("shard is inactive"));
|
||||
return;
|
||||
}
|
||||
auto B = fetch_tl_object<ton_api::Function>(std::move(query), true);
|
||||
if (B.is_error()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot parse tonnode query"));
|
||||
|
@ -631,6 +685,16 @@ void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice
|
|||
ton_api::downcast_call(*B.move_as_ok().get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
|
||||
auto B = fetch_tl_object<ton_api::tonNode_forgetPeer>(std::move(data), true);
|
||||
if (B.is_error()) {
|
||||
return;
|
||||
}
|
||||
VLOG(FULL_NODE_DEBUG) << "Got tonNode.forgetPeer from " << src;
|
||||
neighbours_.erase(src);
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::forget_peer, adnl_id_, overlay_id_, src);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_ihrMessageBroadcast &query) {
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_ihr_message,
|
||||
std::move(query.message_->data_));
|
||||
|
@ -691,11 +755,19 @@ void FullNodeShardImpl::process_block_broadcast(PublicKeyHash src, ton_api::tonN
|
|||
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
|
||||
return;
|
||||
}
|
||||
//if (!shard_is_ancestor(shard_, block_id.shard_full())) {
|
||||
// LOG(FULL_NODE_WARNING) << "dropping block broadcast: shard mismatch. overlay=" << shard_.to_str()
|
||||
// << " block=" << block_id.to_str();
|
||||
// return;
|
||||
//}
|
||||
VLOG(FULL_NODE_DEBUG) << "Received block broadcast from " << src << ": " << B.ok().block_id.to_str();
|
||||
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
|
||||
if (!active_) {
|
||||
return;
|
||||
}
|
||||
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
|
||||
if (B.is_error()) {
|
||||
return;
|
||||
|
@ -804,7 +876,7 @@ void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
|
|||
void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) {
|
||||
auto &b = choose_neighbour();
|
||||
if (!b.adnl_id.is_zero() && b.proto_version >= 1) {
|
||||
if (!b.adnl_id.is_zero() && b.version_major >= 1) {
|
||||
VLOG(FULL_NODE_DEBUG) << "new block download";
|
||||
td::actor::create_actor<DownloadBlockNew>("downloadreq", id, adnl_id_, overlay_id_, b.adnl_id, priority, timeout,
|
||||
validator_manager_, rldp_, overlays_, adnl_, client_,
|
||||
|
@ -863,12 +935,12 @@ void FullNodeShardImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp t
|
|||
.release();
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) {
|
||||
void FullNodeShardImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) {
|
||||
auto &b = choose_neighbour();
|
||||
td::actor::create_actor<DownloadArchiveSlice>("archive", masterchain_seqno, std::move(tmp_dir), adnl_id_, overlay_id_,
|
||||
b.adnl_id, timeout, validator_manager_, rldp2_, overlays_, adnl_,
|
||||
client_, create_neighbour_promise(b, std::move(promise)))
|
||||
td::actor::create_actor<DownloadArchiveSlice>(
|
||||
"archive", masterchain_seqno, shard_prefix, std::move(tmp_dir), adnl_id_, overlay_id_, b.adnl_id, timeout,
|
||||
validator_manager_, rldp2_, overlays_, adnl_, client_, create_neighbour_promise(b, std::move(promise)))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
@ -936,6 +1008,10 @@ void FullNodeShardImpl::start_up() {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::tear_down() {
|
||||
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::sign_new_certificate(PublicKeyHash sign_by) {
|
||||
if (sign_by.is_zero()) {
|
||||
return;
|
||||
|
@ -1083,15 +1159,19 @@ const Neighbour &FullNodeShardImpl::choose_neighbour() const {
|
|||
return Neighbour::zero;
|
||||
}
|
||||
|
||||
double min_unreliability = 1e9;
|
||||
for (auto &x : neighbours_) {
|
||||
min_unreliability = std::min(min_unreliability, x.second.unreliability);
|
||||
}
|
||||
const Neighbour *best = nullptr;
|
||||
td::uint32 sum = 0;
|
||||
|
||||
for (auto &x : neighbours_) {
|
||||
td::uint32 unr = static_cast<td::uint32>(x.second.unreliability);
|
||||
auto unr = static_cast<td::uint32>(x.second.unreliability - min_unreliability);
|
||||
|
||||
if (x.second.proto_version < proto_version()) {
|
||||
if (x.second.version_major < proto_version_major()) {
|
||||
unr += 4;
|
||||
} else if (x.second.proto_version == proto_version() && x.second.capabilities < proto_capabilities()) {
|
||||
} else if (x.second.version_major == proto_version_major() && x.second.version_minor < proto_version_minor()) {
|
||||
unr += 2;
|
||||
}
|
||||
|
||||
|
@ -1105,7 +1185,10 @@ const Neighbour &FullNodeShardImpl::choose_neighbour() const {
|
|||
}
|
||||
}
|
||||
}
|
||||
return best ? *best : Neighbour::zero;
|
||||
if (best) {
|
||||
return *best;
|
||||
}
|
||||
return Neighbour::zero;
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::update_neighbour_stats(adnl::AdnlNodeIdShort adnl_id, double t, bool success) {
|
||||
|
@ -1128,7 +1211,7 @@ void FullNodeShardImpl::got_neighbour_capabilities(adnl::AdnlNodeIdShort adnl_id
|
|||
if (F.is_error()) {
|
||||
it->second.query_failed();
|
||||
} else {
|
||||
it->second.update_proto_version(*F.move_as_ok().get());
|
||||
it->second.update_proto_version(*F.ok());
|
||||
it->second.query_success(t);
|
||||
}
|
||||
}
|
||||
|
@ -1157,7 +1240,7 @@ void FullNodeShardImpl::ping_neighbours() {
|
|||
td::Time::now() - start_time, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
auto q = create_serialize_tl_object<ton_api::tonNode_getCapabilities>();
|
||||
td::BufferSlice q = create_serialize_tl_object<ton_api::tonNode_getCapabilities>();
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_query, it->first, adnl_id_, overlay_id_,
|
||||
"get_prepare_block", std::move(P), td::Timestamp::in(1.0), std::move(q));
|
||||
|
||||
|
@ -1167,6 +1250,24 @@ void FullNodeShardImpl::ping_neighbours() {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeShardImpl::get_stats_extra(td::Promise<std::string> promise) {
|
||||
auto res = create_tl_object<ton_api::engine_validator_shardOverlayStats>();
|
||||
res->shard_ = shard_.to_str();
|
||||
res->active_ = active_;
|
||||
for (const auto &p : neighbours_) {
|
||||
const auto &n = p.second;
|
||||
auto f = create_tl_object<ton_api::engine_validator_shardOverlayStats_neighbour>();
|
||||
f->id_ = n.adnl_id.bits256_value().to_hex();
|
||||
f->verison_major_ = n.version_major;
|
||||
f->version_minor_ = n.version_minor;
|
||||
f->flags_ = n.flags;
|
||||
f->roundtrip_ = n.roundtrip;
|
||||
f->unreliability_ = n.unreliability;
|
||||
res->neighbours_.push_back(std::move(f));
|
||||
}
|
||||
promise.set_result(td::json_encode<std::string>(td::ToJson(*res), true));
|
||||
}
|
||||
|
||||
FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
|
@ -1174,7 +1275,7 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
|
|||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client,
|
||||
td::actor::ActorId<FullNode> full_node)
|
||||
td::actor::ActorId<FullNode> full_node, bool active)
|
||||
: shard_(shard)
|
||||
, local_id_(local_id)
|
||||
, adnl_id_(adnl_id)
|
||||
|
@ -1187,6 +1288,7 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
|
|||
, validator_manager_(validator_manager)
|
||||
, client_(client)
|
||||
, full_node_(full_node)
|
||||
, active_(active)
|
||||
, config_(config) {
|
||||
}
|
||||
|
||||
|
@ -1195,10 +1297,10 @@ td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
|
|||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node) {
|
||||
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, config,
|
||||
keyring, adnl, rldp, rldp2, overlays, validator_manager, client,
|
||||
full_node);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node, bool active) {
|
||||
return td::actor::create_actor<FullNodeShardImpl>(PSTRING() << "tonnode" << shard.to_str(), shard, local_id, adnl_id,
|
||||
zero_state_file_hash, config, keyring, adnl, rldp, rldp2, overlays,
|
||||
validator_manager, client, full_node, active);
|
||||
}
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -36,6 +36,7 @@ class FullNodeShard : public td::actor::Actor {
|
|||
virtual ShardIdFull get_shard_full() const = 0;
|
||||
|
||||
virtual void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void set_active(bool active) = 0;
|
||||
virtual void set_config(FullNodeConfig config) = 0;
|
||||
|
||||
virtual void send_ihr_message(td::BufferSlice data) = 0;
|
||||
|
@ -45,9 +46,10 @@ class FullNodeShard : public td::actor::Actor {
|
|||
td::BufferSlice data) = 0;
|
||||
virtual void send_broadcast(BlockBroadcast broadcast) = 0;
|
||||
|
||||
virtual void sign_overlay_certificate(PublicKeyHash signed_key, td::uint32 expiry_at, td::uint32 max_size, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void import_overlay_certificate(PublicKeyHash signed_key, std::shared_ptr<ton::overlay::Certificate> cert, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void sign_overlay_certificate(PublicKeyHash signed_key, td::uint32 expiry_at, td::uint32 max_size,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void import_overlay_certificate(PublicKeyHash signed_key, std::shared_ptr<ton::overlay::Certificate> cert,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<ReceivedBlock> promise) = 0;
|
||||
|
@ -62,8 +64,8 @@ class FullNodeShard : public td::actor::Actor {
|
|||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||
virtual void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) = 0;
|
||||
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||
|
||||
virtual void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
|
@ -74,7 +76,7 @@ class FullNodeShard : public td::actor::Actor {
|
|||
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node, bool active);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -32,16 +32,17 @@ namespace fullnode {
|
|||
|
||||
struct Neighbour {
|
||||
adnl::AdnlNodeIdShort adnl_id;
|
||||
td::uint32 proto_version = 0;
|
||||
td::uint64 capabilities = 0;
|
||||
td::uint32 version_major = 0;
|
||||
td::uint32 version_minor = 0;
|
||||
td::uint32 flags = 0;
|
||||
double roundtrip = 0;
|
||||
double roundtrip_relax_at = 0;
|
||||
double roundtrip_weight = 0;
|
||||
double unreliability = 0;
|
||||
|
||||
Neighbour(adnl::AdnlNodeIdShort adnl_id) : adnl_id(std::move(adnl_id)) {
|
||||
explicit Neighbour(adnl::AdnlNodeIdShort adnl_id) : adnl_id(std::move(adnl_id)) {
|
||||
}
|
||||
void update_proto_version(const ton_api::tonNode_capabilities &q);
|
||||
void update_proto_version(ton_api::tonNode_capabilities &q);
|
||||
void query_success(double t);
|
||||
void query_failed();
|
||||
void update_roundtrip(double t);
|
||||
|
@ -64,12 +65,12 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
static constexpr td::uint32 download_next_priority() {
|
||||
return 1;
|
||||
}
|
||||
static constexpr td::uint32 proto_version() {
|
||||
return 2;
|
||||
}
|
||||
static constexpr td::uint64 proto_capabilities() {
|
||||
static constexpr td::uint32 proto_version_major() {
|
||||
return 3;
|
||||
}
|
||||
static constexpr td::uint32 proto_version_minor() {
|
||||
return 0;
|
||||
}
|
||||
static constexpr td::uint32 max_neighbours() {
|
||||
return 16;
|
||||
}
|
||||
|
@ -82,14 +83,12 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
|
||||
void create_overlay();
|
||||
void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) override;
|
||||
void set_active(bool active) override;
|
||||
|
||||
void set_config(FullNodeConfig config) override {
|
||||
config_ = config;
|
||||
}
|
||||
|
||||
//td::Result<Block> fetch_block(td::BufferSlice data);
|
||||
void prevalidate_block(BlockIdExt block_id, td::BufferSlice data, td::BufferSlice proof,
|
||||
td::Promise<ReceivedBlock> promise);
|
||||
void try_get_next_block(td::Timestamp timestamp, td::Promise<ReceivedBlock> promise);
|
||||
void got_next_block(td::Result<BlockHandle> block);
|
||||
void get_next_block();
|
||||
|
@ -136,11 +135,14 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getShardArchiveInfo &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
|
||||
// td::Promise<td::BufferSlice> promise);
|
||||
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
|
||||
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
|
||||
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query);
|
||||
|
@ -156,6 +158,8 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
|
||||
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
|
||||
void check_broadcast(PublicKeyHash src, td::BufferSlice query, td::Promise<td::Unit> promise);
|
||||
void get_stats_extra(td::Promise<std::string> promise);
|
||||
void remove_neighbour(adnl::AdnlNodeIdShort id);
|
||||
|
||||
void send_ihr_message(td::BufferSlice data) override;
|
||||
void send_external_message(td::BufferSlice data) override;
|
||||
|
@ -177,12 +181,13 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::Promise<td::BufferSlice> promise) override;
|
||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) override;
|
||||
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) override;
|
||||
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
||||
|
||||
void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void start_up() override;
|
||||
void tear_down() override;
|
||||
void alarm() override;
|
||||
|
||||
void update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) override;
|
||||
|
@ -218,7 +223,8 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node,
|
||||
bool active);
|
||||
|
||||
private:
|
||||
bool use_new_download() const {
|
||||
|
@ -258,6 +264,8 @@ class FullNodeShardImpl : public FullNodeShard {
|
|||
td::Timestamp ping_neighbours_at_;
|
||||
adnl::AdnlNodeIdShort last_pinged_neighbour_ = adnl::AdnlNodeIdShort::zero();
|
||||
|
||||
bool active_;
|
||||
|
||||
FullNodeConfig config_;
|
||||
|
||||
std::set<td::Bits256> my_ext_msg_broadcasts_;
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "full-node.hpp"
|
||||
#include "ton/ton-shard.h"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "full-node.h"
|
||||
#include "common/delay.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -28,6 +30,8 @@ namespace validator {
|
|||
|
||||
namespace fullnode {
|
||||
|
||||
static const double INACTIVE_SHARD_TTL = (double)overlay::Overlays::overlay_peer_ttl() + 60.0;
|
||||
|
||||
void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
|
||||
if (local_keys_.count(key)) {
|
||||
promise.set_value(td::Unit());
|
||||
|
@ -52,7 +56,9 @@ void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
|
|||
}
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
if (!shard.second.actor.empty()) {
|
||||
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
@ -82,30 +88,34 @@ void FullNodeImpl::del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
|
|||
}
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
if (!shard.second.actor.empty()) {
|
||||
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void FullNodeImpl::sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
|
||||
td::uint32 expiry_at, td::uint32 max_size,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = shards_.find(shard_id);
|
||||
if(it == shards_.end()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second, &FullNodeShard::sign_overlay_certificate, signed_key, expiry_at, max_size, std::move(promise));
|
||||
void FullNodeImpl::sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key, td::uint32 expiry_at,
|
||||
td::uint32 max_size, td::Promise<td::BufferSlice> promise) {
|
||||
auto it = shards_.find(shard_id);
|
||||
if(it == shards_.end() || it->second.actor.empty()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second.actor, &FullNodeShard::sign_overlay_certificate, signed_key, expiry_at, max_size,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::import_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
|
||||
std::shared_ptr<ton::overlay::Certificate> cert,
|
||||
td::Promise<td::Unit> promise) {
|
||||
auto it = shards_.find(shard_id);
|
||||
if(it == shards_.end()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
|
||||
}
|
||||
td::actor::send_closure(it->second, &FullNodeShard::import_overlay_certificate, signed_key, cert, std::move(promise));
|
||||
auto it = shards_.find(shard_id);
|
||||
if(it == shards_.end() || it->second.actor.empty()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second.actor, &FullNodeShard::import_overlay_certificate, signed_key, cert,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
|
||||
|
@ -116,7 +126,9 @@ void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td:
|
|||
ig.add_promise(std::move(promise));
|
||||
|
||||
for (auto &s : shards_) {
|
||||
td::actor::send_closure(s.second, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
|
||||
if (!s.second.actor.empty()) {
|
||||
td::actor::send_closure(s.second.actor, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
|
||||
}
|
||||
}
|
||||
local_id_ = adnl_id_.pubkey_hash();
|
||||
|
||||
|
@ -127,8 +139,10 @@ void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td:
|
|||
|
||||
void FullNodeImpl::set_config(FullNodeConfig config) {
|
||||
config_ = config;
|
||||
for (auto& shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::set_config, config);
|
||||
for (auto& s : shards_) {
|
||||
if (!s.second.actor.empty()) {
|
||||
td::actor::send_closure(s.second.actor, &FullNodeShard::set_config, config);
|
||||
}
|
||||
}
|
||||
for (auto& overlay : private_block_overlays_) {
|
||||
td::actor::send_closure(overlay.second, &FullNodePrivateBlockOverlay::set_config, config);
|
||||
|
@ -173,32 +187,84 @@ void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
|
|||
td::actor::send_closure(SelfId, &FullNodeImpl::sync_completed);
|
||||
});
|
||||
auto it = shards_.find(ShardIdFull{masterchainId});
|
||||
CHECK(it != shards_.end());
|
||||
td::actor::send_closure(it->second, &FullNodeShard::set_handle, top_handle, std::move(P));
|
||||
CHECK(it != shards_.end() && !it->second.actor.empty());
|
||||
td::actor::send_closure(it->second.actor, &FullNodeShard::set_handle, top_handle, std::move(P));
|
||||
}
|
||||
|
||||
void FullNodeImpl::add_shard(ShardIdFull shard) {
|
||||
while (true) {
|
||||
if (shards_.count(shard) == 0) {
|
||||
shards_.emplace(shard,
|
||||
FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_, adnl_,
|
||||
rldp_, rldp2_, overlays_, validator_manager_, client_, actor_id(this)));
|
||||
if (all_validators_.size() > 0) {
|
||||
td::actor::send_closure(shards_[shard], &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
void FullNodeImpl::on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) {
|
||||
CHECK(shards_to_monitor.count(ShardIdFull(masterchainId)));
|
||||
bool join_all_overlays = !sign_cert_by_.is_zero();
|
||||
std::set<ShardIdFull> all_shards;
|
||||
std::set<ShardIdFull> new_active;
|
||||
all_shards.insert(ShardIdFull(masterchainId));
|
||||
std::set<WorkchainId> workchains;
|
||||
wc_monitor_min_split_ = state->monitor_min_split_depth(basechainId);
|
||||
auto cut_shard = [&](ShardIdFull shard) -> ShardIdFull {
|
||||
return wc_monitor_min_split_ < shard.pfx_len() ? shard_prefix(shard, wc_monitor_min_split_) : shard;
|
||||
};
|
||||
for (auto &info : state->get_shards()) {
|
||||
workchains.insert(info->shard().workchain);
|
||||
ShardIdFull shard = cut_shard(info->shard());
|
||||
while (true) {
|
||||
all_shards.insert(shard);
|
||||
if (shard.pfx_len() == 0) {
|
||||
break;
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
}
|
||||
}
|
||||
for (const auto &[wc, winfo] : state->get_workchain_list()) {
|
||||
if (!workchains.contains(wc) && winfo->active && winfo->enabled_since <= state->get_unix_time()) {
|
||||
all_shards.insert(ShardIdFull(wc));
|
||||
}
|
||||
}
|
||||
for (ShardIdFull shard : shards_to_monitor) {
|
||||
shard = cut_shard(shard);
|
||||
while (true) {
|
||||
new_active.insert(shard);
|
||||
if (shard.pfx_len() == 0) {
|
||||
break;
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = shards_.begin(); it != shards_.end(); ) {
|
||||
if (all_shards.contains(it->first)) {
|
||||
++it;
|
||||
} else {
|
||||
break;
|
||||
it = shards_.erase(it);
|
||||
}
|
||||
if (shard.shard == shardIdAll) {
|
||||
break;
|
||||
}
|
||||
for (ShardIdFull shard : all_shards) {
|
||||
bool active = new_active.contains(shard);
|
||||
bool overlay_exists = !shards_[shard].actor.empty();
|
||||
if (active || join_all_overlays || overlay_exists) {
|
||||
update_shard_actor(shard, active);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &[_, shard_info] : shards_) {
|
||||
if (!shard_info.active && shard_info.delete_at && shard_info.delete_at.is_in_past() && !join_all_overlays) {
|
||||
shard_info.actor = {};
|
||||
shard_info.delete_at = td::Timestamp::never();
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::del_shard(ShardIdFull shard) {
|
||||
LOG(FATAL) << "deleting shards not implemented: shard=" << shard;
|
||||
shards_.erase(shard);
|
||||
void FullNodeImpl::update_shard_actor(ShardIdFull shard, bool active) {
|
||||
ShardInfo &info = shards_[shard];
|
||||
if (info.actor.empty()) {
|
||||
info.actor = FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_, adnl_, rldp_,
|
||||
rldp2_, overlays_, validator_manager_, client_, actor_id(this), active);
|
||||
if (!all_validators_.empty()) {
|
||||
td::actor::send_closure(info.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
} else if (info.active != active) {
|
||||
td::actor::send_closure(info.actor, &FullNodeShard::set_active, active);
|
||||
}
|
||||
info.active = active;
|
||||
info.delete_at = active ? td::Timestamp::never() : td::Timestamp::in(INACTIVE_SHARD_TTL);
|
||||
}
|
||||
|
||||
void FullNodeImpl::sync_completed() {
|
||||
|
@ -206,7 +272,7 @@ void FullNodeImpl::sync_completed() {
|
|||
}
|
||||
|
||||
void FullNodeImpl::send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
auto shard = get_shard(dst);
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT ihr message to unknown shard";
|
||||
return;
|
||||
|
@ -220,11 +286,12 @@ void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice dat
|
|||
VLOG(FULL_NODE_WARNING) << "dropping OUT ext message to unknown shard";
|
||||
return;
|
||||
}
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.params_.msg_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_external_message, data.clone());
|
||||
for (auto &[_, private_overlay] : custom_overlays_) {
|
||||
if (private_overlay.params_.send_shard(dst.as_leaf_shard())) {
|
||||
for (auto &[local_id, actor] : private_overlay.actors_) {
|
||||
if (private_overlay.params_.msg_senders_.contains(local_id)) {
|
||||
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_external_message, data.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +299,7 @@ void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice dat
|
|||
}
|
||||
|
||||
void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId, shardIdAll});
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
|
||||
return;
|
||||
|
@ -266,14 +333,16 @@ void FullNodeImpl::send_broadcast(BlockBroadcast broadcast, int mode) {
|
|||
if (mode & broadcast_mode_custom) {
|
||||
send_block_broadcast_to_custom_overlays(broadcast);
|
||||
}
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
auto shard = get_shard(broadcast.block_id.shard_full());
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping OUT broadcast to unknown shard";
|
||||
return;
|
||||
}
|
||||
if (!private_block_overlays_.empty() && (mode & broadcast_mode_private_block)) {
|
||||
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
|
||||
broadcast.clone());
|
||||
if (mode & broadcast_mode_private_block) {
|
||||
if (!private_block_overlays_.empty()) {
|
||||
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
|
||||
broadcast.clone());
|
||||
}
|
||||
}
|
||||
if (mode & broadcast_mode_public) {
|
||||
td::actor::send_closure(shard, &FullNodeShard::send_broadcast, std::move(broadcast));
|
||||
|
@ -348,27 +417,43 @@ void FullNodeImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeou
|
|||
td::actor::send_closure(shard, &FullNodeShard::get_next_key_blocks, block_id, timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void FullNodeImpl::download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) {
|
||||
auto shard = get_shard(ShardIdFull{masterchainId});
|
||||
void FullNodeImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) {
|
||||
auto shard = get_shard(shard_prefix);
|
||||
if (shard.empty()) {
|
||||
VLOG(FULL_NODE_WARNING) << "dropping download archive query to unknown shard";
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||
return;
|
||||
}
|
||||
CHECK(!shard.empty());
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_archive, masterchain_seqno, std::move(tmp_dir), timeout,
|
||||
std::move(promise));
|
||||
td::actor::send_closure(shard, &FullNodeShard::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
|
||||
timeout, std::move(promise));
|
||||
}
|
||||
|
||||
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
|
||||
add_shard(ShardIdFull{shard.workchain, shardIdAll});
|
||||
while (shards_.count(shard) == 0) {
|
||||
if (shard.shard == shardIdAll) {
|
||||
return td::actor::ActorId<FullNodeShard>{};
|
||||
}
|
||||
shard = shard_parent(shard);
|
||||
if (shard.is_masterchain()) {
|
||||
return shards_[ShardIdFull{masterchainId}].actor.get();
|
||||
}
|
||||
return shards_[shard].get();
|
||||
if (shard.workchain != basechainId) {
|
||||
return {};
|
||||
}
|
||||
int pfx_len = shard.pfx_len();
|
||||
if (pfx_len > wc_monitor_min_split_) {
|
||||
shard = shard_prefix(shard, wc_monitor_min_split_);
|
||||
}
|
||||
auto it = shards_.find(shard);
|
||||
if (it != shards_.end()) {
|
||||
update_shard_actor(shard, it->second.active);
|
||||
return it->second.actor.get();
|
||||
}
|
||||
|
||||
// Special case if shards_ was not yet initialized.
|
||||
// This can happen briefly on node startup.
|
||||
return shards_[ShardIdFull{masterchainId}].actor.get();
|
||||
}
|
||||
|
||||
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(AccountIdPrefixFull dst) {
|
||||
return get_shard(shard_prefix(dst, 60));
|
||||
return get_shard(shard_prefix(dst, max_shard_pfx_len));
|
||||
}
|
||||
|
||||
void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
|
||||
|
@ -407,7 +492,9 @@ void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
|
|||
CHECK(all_validators_.size() > 0);
|
||||
|
||||
for (auto &shard : shards_) {
|
||||
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
if (!shard.second.actor.empty()) {
|
||||
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,9 +576,9 @@ void FullNodeImpl::update_validator_telemetry_collector() {
|
|||
}
|
||||
|
||||
void FullNodeImpl::start_up() {
|
||||
add_shard(ShardIdFull{masterchainId});
|
||||
update_shard_actor(ShardIdFull{masterchainId}, true);
|
||||
if (local_id_.is_zero()) {
|
||||
if(adnl_id_.is_zero()) {
|
||||
if (adnl_id_.is_zero()) {
|
||||
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
|
||||
local_id_ = pk.compute_short_id();
|
||||
|
||||
|
@ -505,11 +592,9 @@ void FullNodeImpl::start_up() {
|
|||
void initial_read_complete(BlockHandle handle) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::initial_read_complete, handle);
|
||||
}
|
||||
void add_shard(ShardIdFull shard) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::add_shard, shard);
|
||||
}
|
||||
void del_shard(ShardIdFull shard) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::del_shard, shard);
|
||||
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::on_new_masterchain_block, std::move(state),
|
||||
std::move(shards_to_monitor));
|
||||
}
|
||||
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::send_ihr_message, dst, std::move(data));
|
||||
|
@ -555,10 +640,10 @@ void FullNodeImpl::start_up() {
|
|||
td::Promise<std::vector<BlockIdExt>> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::get_next_key_blocks, block_id, timeout, std::move(promise));
|
||||
}
|
||||
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, std::move(tmp_dir), timeout,
|
||||
std::move(promise));
|
||||
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
|
||||
timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void new_key_block(BlockHandle handle) override {
|
||||
|
@ -568,16 +653,15 @@ void FullNodeImpl::start_up() {
|
|||
td::actor::send_closure(id_, &FullNodeImpl::send_validator_telemetry, key, std::move(telemetry));
|
||||
}
|
||||
|
||||
Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
|
||||
explicit Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<FullNodeImpl> id_;
|
||||
};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([](td::Unit R) {});
|
||||
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::install_callback,
|
||||
std::make_unique<Callback>(actor_id(this)), std::move(P));
|
||||
std::make_unique<Callback>(actor_id(this)), std::move(started_promise_));
|
||||
}
|
||||
|
||||
void FullNodeImpl::update_private_overlays() {
|
||||
|
@ -635,7 +719,7 @@ void FullNodeImpl::update_custom_overlay(CustomOverlayInfo &overlay) {
|
|||
}
|
||||
}
|
||||
|
||||
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast& broadcast) {
|
||||
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast &broadcast) {
|
||||
if (!custom_overlays_sent_broadcasts_.insert(broadcast.block_id).second) {
|
||||
return;
|
||||
}
|
||||
|
@ -644,11 +728,12 @@ void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast&
|
|||
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
|
||||
custom_overlays_sent_broadcasts_lru_.pop();
|
||||
}
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.params_.block_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_broadcast, broadcast.clone());
|
||||
for (auto &[_, private_overlay] : custom_overlays_) {
|
||||
if (private_overlay.params_.send_shard(broadcast.block_id.shard_full())) {
|
||||
for (auto &[local_id, actor] : private_overlay.actors_) {
|
||||
if (private_overlay.params_.block_senders_.contains(local_id)) {
|
||||
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_broadcast, broadcast.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -666,12 +751,13 @@ void FullNodeImpl::send_block_candidate_broadcast_to_custom_overlays(const Block
|
|||
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
|
||||
custom_overlays_sent_broadcasts_lru_.pop();
|
||||
}
|
||||
for (auto &private_overlay : custom_overlays_) {
|
||||
for (auto &actor : private_overlay.second.actors_) {
|
||||
auto local_id = actor.first;
|
||||
if (private_overlay.second.params_.block_senders_.count(local_id)) {
|
||||
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_block_candidate, block_id, cc_seqno,
|
||||
validator_set_hash, data.clone());
|
||||
for (auto &[_, private_overlay] : custom_overlays_) {
|
||||
if (private_overlay.params_.send_shard(block_id.shard_full())) {
|
||||
for (auto &[local_id, actor] : private_overlay.actors_) {
|
||||
if (private_overlay.params_.block_senders_.contains(local_id)) {
|
||||
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_block_candidate, block_id, cc_seqno,
|
||||
validator_set_hash, data.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -683,7 +769,8 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id
|
|||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root)
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root,
|
||||
td::Promise<td::Unit> started_promise)
|
||||
: local_id_(local_id)
|
||||
, adnl_id_(adnl_id)
|
||||
, zero_state_file_hash_(zero_state_file_hash)
|
||||
|
@ -696,19 +783,19 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id
|
|||
, validator_manager_(validator_manager)
|
||||
, client_(client)
|
||||
, db_root_(db_root)
|
||||
, started_promise_(std::move(started_promise))
|
||||
, config_(config) {
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<FullNode> FullNode::create(ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root) {
|
||||
td::actor::ActorOwn<FullNode> FullNode::create(
|
||||
ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root, td::Promise<td::Unit> started_promise) {
|
||||
return td::actor::create_actor<FullNodeImpl>("fullnode", local_id, adnl_id, zero_state_file_hash, config, keyring,
|
||||
adnl, rldp, rldp2, dht, overlays, validator_manager, client, db_root);
|
||||
adnl, rldp, rldp2, dht, overlays, validator_manager, client, db_root,
|
||||
std::move(started_promise));
|
||||
}
|
||||
|
||||
FullNodeConfig::FullNodeConfig(const tl_object_ptr<ton_api::engine_validator_fullNodeConfig> &obj)
|
||||
|
@ -725,18 +812,27 @@ bool FullNodeConfig::operator!=(const FullNodeConfig &rhs) const {
|
|||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool CustomOverlayParams::send_shard(const ShardIdFull &shard) const {
|
||||
return sender_shards_.empty() ||
|
||||
std::any_of(sender_shards_.begin(), sender_shards_.end(),
|
||||
[&](const ShardIdFull &our_shard) { return shard_intersects(shard, our_shard); });
|
||||
}
|
||||
|
||||
CustomOverlayParams CustomOverlayParams::fetch(const ton_api::engine_validator_customOverlay& f) {
|
||||
CustomOverlayParams c;
|
||||
c.name_ = f.name_;
|
||||
for (const auto &node : f.nodes_) {
|
||||
c.nodes_.emplace_back(node->adnl_id_);
|
||||
if (node->msg_sender_) {
|
||||
c.msg_senders_[ton::adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
|
||||
c.msg_senders_[adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
|
||||
}
|
||||
if (node->block_sender_) {
|
||||
c.block_senders_.emplace(node->adnl_id_);
|
||||
}
|
||||
}
|
||||
for (const auto &shard : f.sender_shards_) {
|
||||
c.sender_shards_.push_back(create_shard_id(shard));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,9 @@ struct CustomOverlayParams {
|
|||
std::vector<adnl::AdnlNodeIdShort> nodes_;
|
||||
std::map<adnl::AdnlNodeIdShort, int> msg_senders_;
|
||||
std::set<adnl::AdnlNodeIdShort> block_senders_;
|
||||
std::vector<ShardIdFull> sender_shards_;
|
||||
|
||||
bool send_shard(const ShardIdFull& shard) const;
|
||||
static CustomOverlayParams fetch(const ton_api::engine_validator_customOverlay& f);
|
||||
};
|
||||
|
||||
|
@ -103,14 +105,12 @@ class FullNode : public td::actor::Actor {
|
|||
}
|
||||
enum { broadcast_mode_public = 1, broadcast_mode_private_block = 2, broadcast_mode_custom = 4 };
|
||||
|
||||
static td::actor::ActorOwn<FullNode> create(ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
|
||||
FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root);
|
||||
static td::actor::ActorOwn<FullNode> create(
|
||||
ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, FullNodeConfig config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root, td::Promise<td::Unit> started_promise);
|
||||
};
|
||||
|
||||
} // namespace fullnode
|
||||
|
|
|
@ -44,9 +44,8 @@ class FullNodeImpl : public FullNode {
|
|||
void add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
|
||||
void del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
|
||||
td::uint32 expiry_at, td::uint32 max_size,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key, td::uint32 expiry_at,
|
||||
td::uint32 max_size, td::Promise<td::BufferSlice> promise) override;
|
||||
void import_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
|
||||
std::shared_ptr<ton::overlay::Certificate> cert,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
|
@ -57,8 +56,7 @@ class FullNodeImpl : public FullNode {
|
|||
void add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) override;
|
||||
void del_custom_overlay(std::string name, td::Promise<td::Unit> promise) override;
|
||||
|
||||
void add_shard(ShardIdFull shard);
|
||||
void del_shard(ShardIdFull shard);
|
||||
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor);
|
||||
|
||||
void sync_completed();
|
||||
|
||||
|
@ -79,8 +77,8 @@ class FullNodeImpl : public FullNode {
|
|||
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise);
|
||||
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise);
|
||||
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise);
|
||||
|
||||
void got_key_block_config(td::Ref<ConfigHolder> config);
|
||||
void new_key_block(BlockHandle handle);
|
||||
|
@ -99,17 +97,26 @@ class FullNodeImpl : public FullNode {
|
|||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
|
||||
td::actor::ActorId<dht::Dht> dht, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root);
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root,
|
||||
td::Promise<td::Unit> started_promise);
|
||||
|
||||
private:
|
||||
struct ShardInfo {
|
||||
td::actor::ActorOwn<FullNodeShard> actor;
|
||||
bool active = false;
|
||||
td::Timestamp delete_at = td::Timestamp::never();
|
||||
};
|
||||
|
||||
void update_shard_actor(ShardIdFull shard, bool active);
|
||||
|
||||
PublicKeyHash local_id_;
|
||||
adnl::AdnlNodeIdShort adnl_id_;
|
||||
FileHash zero_state_file_hash_;
|
||||
|
||||
td::actor::ActorId<FullNodeShard> get_shard(AccountIdPrefixFull dst);
|
||||
td::actor::ActorId<FullNodeShard> get_shard(ShardIdFull dst);
|
||||
|
||||
std::map<ShardIdFull, td::actor::ActorOwn<FullNodeShard>> shards_;
|
||||
td::actor::ActorId<FullNodeShard> get_shard(ShardIdFull shard);
|
||||
std::map<ShardIdFull, ShardInfo> shards_;
|
||||
int wc_monitor_min_split_ = 0;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
|
@ -127,6 +134,8 @@ class FullNodeImpl : public FullNode {
|
|||
std::map<PublicKeyHash, adnl::AdnlNodeIdShort> current_validators_;
|
||||
|
||||
std::set<PublicKeyHash> local_keys_;
|
||||
|
||||
td::Promise<td::Unit> started_promise_;
|
||||
FullNodeConfig config_;
|
||||
|
||||
std::map<PublicKeyHash, td::actor::ActorOwn<FullNodePrivateBlockOverlay>> private_block_overlays_;
|
||||
|
|
|
@ -40,8 +40,7 @@ set(TON_VALIDATOR_SOURCE
|
|||
signature-set.hpp
|
||||
top-shard-descr.hpp
|
||||
validate-query.hpp
|
||||
validator-set.hpp
|
||||
)
|
||||
validator-set.hpp)
|
||||
|
||||
add_library(ton_validator STATIC ${TON_VALIDATOR_SOURCE})
|
||||
|
||||
|
|
|
@ -160,6 +160,9 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
|
|||
return td::make_ref<ConfigHolderQ>(config_);
|
||||
}
|
||||
}
|
||||
block::WorkchainSet get_workchain_list() const override {
|
||||
return config_ ? config_->get_workchain_list() : block::WorkchainSet();
|
||||
}
|
||||
|
||||
private:
|
||||
ZeroStateIdExt zerostate_id_;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
Copyright 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "import-db-slice.hpp"
|
||||
|
||||
#include "validator/db/fileref.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "validator/fabric.h"
|
||||
|
@ -26,35 +27,91 @@
|
|||
#include "ton/ton-io.hpp"
|
||||
#include "downloaders/download-state.hpp"
|
||||
|
||||
#include <delay.h>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
ArchiveImporter::ArchiveImporter(std::string path, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
|
||||
ArchiveImporter::ArchiveImporter(std::string db_root, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
|
||||
td::Ref<ValidatorManagerOptions> opts, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<std::vector<BlockSeqno>> promise)
|
||||
: path_(std::move(path))
|
||||
, state_(std::move(state))
|
||||
std::vector<std::string> to_import_files,
|
||||
td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise)
|
||||
: db_root_(std::move(db_root))
|
||||
, last_masterchain_state_(std::move(state))
|
||||
, shard_client_seqno_(shard_client_seqno)
|
||||
, start_import_seqno_(shard_client_seqno + 1)
|
||||
, opts_(std::move(opts))
|
||||
, manager_(manager)
|
||||
, to_import_files_(std::move(to_import_files))
|
||||
, use_imported_files_(!to_import_files_.empty())
|
||||
, promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void ArchiveImporter::start_up() {
|
||||
auto R = Package::open(path_, false, false);
|
||||
if (R.is_error()) {
|
||||
abort_query(R.move_as_error());
|
||||
if (use_imported_files_) {
|
||||
LOG(INFO) << "Importing archive for masterchain seqno #" << start_import_seqno_ << " from disk";
|
||||
for (const std::string& path : to_import_files_) {
|
||||
LOG(INFO) << "Importing file from disk " << path;
|
||||
td::Status S = process_package(path, true);
|
||||
if (S.is_error()) {
|
||||
LOG(INFO) << "Error processing package " << path << ": " << S;
|
||||
}
|
||||
}
|
||||
files_to_cleanup_.clear();
|
||||
processed_mc_archive();
|
||||
return;
|
||||
}
|
||||
package_ = std::make_shared<Package>(R.move_as_ok());
|
||||
LOG(INFO) << "Importing archive for masterchain seqno #" << start_import_seqno_ << " from net";
|
||||
td::actor::send_closure(manager_, &ValidatorManager::send_download_archive_request, start_import_seqno_,
|
||||
ShardIdFull{masterchainId}, db_root_ + "/tmp/", td::Timestamp::in(3600.0),
|
||||
[SelfId = actor_id(this)](td::Result<std::string> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::downloaded_mc_archive, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
package_->iterate([&](std::string filename, td::BufferSlice data, td::uint64 offset) -> bool {
|
||||
void ArchiveImporter::downloaded_mc_archive(std::string path) {
|
||||
td::Status S = process_package(path, true);
|
||||
if (S.is_error()) {
|
||||
abort_query(std::move(S));
|
||||
return;
|
||||
}
|
||||
processed_mc_archive();
|
||||
}
|
||||
|
||||
void ArchiveImporter::processed_mc_archive() {
|
||||
if (masterchain_blocks_.empty()) {
|
||||
LOG(DEBUG) << "No masterhchain blocks in archive";
|
||||
last_masterchain_seqno_ = last_masterchain_state_->get_seqno();
|
||||
checked_all_masterchain_blocks();
|
||||
return;
|
||||
}
|
||||
|
||||
auto seqno = masterchain_blocks_.begin()->first;
|
||||
LOG(DEBUG) << "First mc seqno in archive = " << seqno;
|
||||
if (seqno > last_masterchain_state_->get_seqno() + 1) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "too big first masterchain seqno"));
|
||||
return;
|
||||
}
|
||||
|
||||
check_masterchain_block(seqno);
|
||||
}
|
||||
|
||||
td::Status ArchiveImporter::process_package(std::string path, bool with_masterchain) {
|
||||
LOG(DEBUG) << "Processing package " << path << " (with_masterchain=" << with_masterchain << ")";
|
||||
files_to_cleanup_.push_back(path);
|
||||
TRY_RESULT(p, Package::open(path, false, false));
|
||||
auto package = std::make_shared<Package>(std::move(p));
|
||||
|
||||
td::Status S = td::Status::OK();
|
||||
package->iterate([&](std::string filename, td::BufferSlice, td::uint64 offset) -> bool {
|
||||
auto F = FileReference::create(filename);
|
||||
if (F.is_error()) {
|
||||
abort_query(F.move_as_error());
|
||||
fail = true;
|
||||
S = F.move_as_error();
|
||||
return false;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
|
@ -79,33 +136,26 @@ void ArchiveImporter::start_up() {
|
|||
ignore = false;
|
||||
is_proof = false;
|
||||
},
|
||||
[&](const auto &p) { ignore = true; }));
|
||||
[&](const auto &) { ignore = true; }));
|
||||
|
||||
if (!ignore) {
|
||||
blocks_[b][is_proof ? 0 : 1] = offset;
|
||||
if (!ignore && (with_masterchain || !b.is_masterchain())) {
|
||||
if (is_proof) {
|
||||
blocks_[b].proof_pkg = package;
|
||||
blocks_[b].proof_offset = offset;
|
||||
} else {
|
||||
blocks_[b].data_pkg = package;
|
||||
blocks_[b].data_offset = offset;
|
||||
}
|
||||
if (b.is_masterchain()) {
|
||||
masterchain_blocks_[b.seqno()] = b;
|
||||
last_masterchain_seqno_ = std::max(last_masterchain_seqno_, b.seqno());
|
||||
} else {
|
||||
have_shard_blocks_ = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (fail) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (masterchain_blocks_.size() == 0) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "archive does not contain any masterchain blocks"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto seqno = masterchain_blocks_.begin()->first;
|
||||
if (seqno > state_->get_seqno() + 1) {
|
||||
abort_query(td::Status::Error(ErrorCode::notready, "too big first masterchain seqno"));
|
||||
return;
|
||||
}
|
||||
|
||||
check_masterchain_block(seqno);
|
||||
return S;
|
||||
}
|
||||
|
||||
void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
||||
|
@ -115,17 +165,17 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
|||
abort_query(td::Status::Error(ErrorCode::notready, "no new blocks"));
|
||||
return;
|
||||
}
|
||||
checked_all_masterchain_blocks(seqno - 1);
|
||||
checked_all_masterchain_blocks();
|
||||
return;
|
||||
}
|
||||
while (seqno <= state_->get_block_id().seqno()) {
|
||||
if (seqno < state_->get_block_id().seqno()) {
|
||||
if (!state_->check_old_mc_block_id(it->second)) {
|
||||
while (seqno <= last_masterchain_state_->get_block_id().seqno()) {
|
||||
if (seqno < last_masterchain_state_->get_block_id().seqno()) {
|
||||
if (!last_masterchain_state_->check_old_mc_block_id(it->second)) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad old masterchain block id"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (state_->get_block_id() != it->second) {
|
||||
if (last_masterchain_state_->get_block_id() != it->second) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad old masterchain block id"));
|
||||
return;
|
||||
}
|
||||
|
@ -133,18 +183,27 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
|||
seqno++;
|
||||
it = masterchain_blocks_.find(seqno);
|
||||
if (it == masterchain_blocks_.end()) {
|
||||
checked_all_masterchain_blocks(seqno - 1);
|
||||
checked_all_masterchain_blocks();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (seqno != state_->get_block_id().seqno() + 1) {
|
||||
LOG(DEBUG) << "Checking masterchain block #" << seqno;
|
||||
if (seqno != last_masterchain_state_->get_block_id().seqno() + 1) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "hole in masterchain seqno"));
|
||||
return;
|
||||
}
|
||||
auto it2 = blocks_.find(it->second);
|
||||
CHECK(it2 != blocks_.end());
|
||||
if (!it2->second.proof_pkg) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "no masterchain block proof"));
|
||||
return;
|
||||
}
|
||||
if (!it2->second.data_pkg) {
|
||||
abort_query(td::Status::Error(ErrorCode::protoviolation, "no masterchain block data"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto R1 = package_->read(it2->second[0]);
|
||||
auto R1 = it2->second.proof_pkg->read(it2->second.proof_offset);
|
||||
if (R1.is_error()) {
|
||||
abort_query(R1.move_as_error());
|
||||
return;
|
||||
|
@ -156,7 +215,7 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto R2 = package_->read(it2->second[1]);
|
||||
auto R2 = it2->second.data_pkg->read(it2->second.data_offset);
|
||||
if (R2.is_error()) {
|
||||
abort_query(R2.move_as_error());
|
||||
return;
|
||||
|
@ -175,7 +234,7 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
|||
auto proof = proofR.move_as_ok();
|
||||
auto data = dataR.move_as_ok();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = state_->get_block_id(),
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = last_masterchain_state_->get_block_id(),
|
||||
data](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
|
||||
|
@ -191,11 +250,12 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
|
|||
td::actor::send_closure(SelfId, &ArchiveImporter::checked_masterchain_proof, std::move(handle), std::move(data));
|
||||
});
|
||||
|
||||
run_check_proof_query(it->second, std::move(proof), manager_, td::Timestamp::in(2.0), std::move(P), state_,
|
||||
opts_->is_hardfork(it->second));
|
||||
run_check_proof_query(it->second, std::move(proof), manager_, td::Timestamp::in(2.0), std::move(P),
|
||||
last_masterchain_state_, opts_->is_hardfork(it->second));
|
||||
}
|
||||
|
||||
void ArchiveImporter::checked_masterchain_proof(BlockHandle handle, td::Ref<BlockData> data) {
|
||||
LOG(DEBUG) << "Checked proof for masterchain block #" << handle->id().seqno();
|
||||
CHECK(data.not_null());
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
|
@ -205,6 +265,7 @@ void ArchiveImporter::checked_masterchain_proof(BlockHandle handle, td::Ref<Bloc
|
|||
}
|
||||
|
||||
void ArchiveImporter::applied_masterchain_block(BlockHandle handle) {
|
||||
LOG(DEBUG) << "Applied masterchain block #" << handle->id().seqno();
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::got_new_materchain_state,
|
||||
|
@ -214,22 +275,87 @@ void ArchiveImporter::applied_masterchain_block(BlockHandle handle) {
|
|||
}
|
||||
|
||||
void ArchiveImporter::got_new_materchain_state(td::Ref<MasterchainState> state) {
|
||||
state_ = std::move(state);
|
||||
check_masterchain_block(state_->get_block_id().seqno() + 1);
|
||||
last_masterchain_state_ = std::move(state);
|
||||
imported_any_ = true;
|
||||
check_masterchain_block(last_masterchain_state_->get_block_id().seqno() + 1);
|
||||
}
|
||||
|
||||
void ArchiveImporter::checked_all_masterchain_blocks(BlockSeqno seqno) {
|
||||
check_next_shard_client_seqno(shard_client_seqno_ + 1);
|
||||
void ArchiveImporter::checked_all_masterchain_blocks() {
|
||||
LOG(DEBUG) << "Done importing masterchain blocks. Last block seqno = " << last_masterchain_seqno_;
|
||||
if (start_import_seqno_ > last_masterchain_state_->get_seqno()) {
|
||||
abort_query(td::Status::Error("no new masterchain blocks were imported"));
|
||||
return;
|
||||
}
|
||||
BlockIdExt block_id;
|
||||
CHECK(last_masterchain_state_->get_old_mc_block_id(start_import_seqno_, block_id));
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db_short, block_id,
|
||||
[SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
R.ensure();
|
||||
td::Ref<MasterchainState> state{R.move_as_ok()};
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::download_shard_archives,
|
||||
std::move(state));
|
||||
});
|
||||
}
|
||||
|
||||
void ArchiveImporter::download_shard_archives(td::Ref<MasterchainState> start_state) {
|
||||
start_state_ = start_state;
|
||||
td::uint32 monitor_min_split = start_state->monitor_min_split_depth(basechainId);
|
||||
LOG(DEBUG) << "Monitor min split = " << monitor_min_split;
|
||||
// If monitor_min_split == 0, we use the old archive format (packages are not separated by shard)
|
||||
// If masterchain package has shard blocks then it's old archive format, don't need to download shards
|
||||
if (monitor_min_split > 0 && !have_shard_blocks_ && !use_imported_files_) {
|
||||
for (td::uint64 i = 0; i < (1ULL << monitor_min_split); ++i) {
|
||||
ShardIdFull shard_prefix{basechainId, (i * 2 + 1) << (64 - monitor_min_split - 1)};
|
||||
if (opts_->need_monitor(shard_prefix, start_state)) {
|
||||
++pending_shard_archives_;
|
||||
LOG(DEBUG) << "Downloading shard archive #" << start_import_seqno_ << " " << shard_prefix.to_str();
|
||||
download_shard_archive(shard_prefix);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(DEBUG) << "Skip downloading shard archives";
|
||||
}
|
||||
if (pending_shard_archives_ == 0) {
|
||||
check_next_shard_client_seqno(shard_client_seqno_ + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveImporter::download_shard_archive(ShardIdFull shard_prefix) {
|
||||
td::actor::send_closure(
|
||||
manager_, &ValidatorManager::send_download_archive_request, start_import_seqno_, shard_prefix, db_root_ + "/tmp/",
|
||||
td::Timestamp::in(3600.0),
|
||||
[SelfId = actor_id(this), seqno = start_import_seqno_, shard_prefix](td::Result<std::string> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "Failed to download archive slice #" << seqno << " for shard " << shard_prefix.to_str();
|
||||
delay_action(
|
||||
[=]() { td::actor::send_closure(SelfId, &ArchiveImporter::download_shard_archive, shard_prefix); },
|
||||
td::Timestamp::in(2.0));
|
||||
} else {
|
||||
LOG(DEBUG) << "Downloaded shard archive #" << seqno << " " << shard_prefix.to_str();
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::downloaded_shard_archive, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ArchiveImporter::downloaded_shard_archive(std::string path) {
|
||||
td::Status S = process_package(path, false);
|
||||
if (S.is_error()) {
|
||||
LOG(INFO) << "Error processing package: " << S;
|
||||
}
|
||||
--pending_shard_archives_;
|
||||
if (pending_shard_archives_ == 0) {
|
||||
check_next_shard_client_seqno(shard_client_seqno_ + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveImporter::check_next_shard_client_seqno(BlockSeqno seqno) {
|
||||
if (seqno > state_->get_seqno()) {
|
||||
if (seqno > last_masterchain_state_->get_seqno() || seqno > last_masterchain_seqno_) {
|
||||
finish_query();
|
||||
} else if (seqno == state_->get_seqno()) {
|
||||
got_masterchain_state(state_);
|
||||
} else if (seqno == last_masterchain_state_->get_seqno()) {
|
||||
got_masterchain_state(last_masterchain_state_);
|
||||
} else {
|
||||
BlockIdExt b;
|
||||
bool f = state_->get_old_mc_block_id(seqno, b);
|
||||
bool f = last_masterchain_state_->get_old_mc_block_id(seqno, b);
|
||||
CHECK(f);
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
R.ensure();
|
||||
|
@ -241,33 +367,38 @@ void ArchiveImporter::check_next_shard_client_seqno(BlockSeqno seqno) {
|
|||
}
|
||||
|
||||
void ArchiveImporter::got_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
if (state->get_seqno() != start_import_seqno_ && state->is_key_state()) {
|
||||
finish_query();
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG) << "Applying shard client seqno " << state->get_seqno();
|
||||
auto s = state->get_shards();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = state->get_seqno()](td::Result<td::Unit> R) {
|
||||
td::MultiPromise mp;
|
||||
auto ig = mp.init_guard();
|
||||
for (auto &shard : s) {
|
||||
if (opts_->need_monitor(shard->shard(), state)) {
|
||||
apply_shard_block(shard->top_block_id(), state->get_block_id(), ig.get_promise());
|
||||
}
|
||||
}
|
||||
ig.add_promise([SelfId = actor_id(this), seqno = state->get_seqno()](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ArchiveImporter::checked_shard_client_seqno, seqno);
|
||||
}
|
||||
});
|
||||
|
||||
td::MultiPromise mp;
|
||||
auto ig = mp.init_guard();
|
||||
ig.add_promise(std::move(P));
|
||||
|
||||
for (auto &shard : s) {
|
||||
apply_shard_block(shard->top_block_id(), state->get_block_id(), ig.get_promise());
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveImporter::checked_shard_client_seqno(BlockSeqno seqno) {
|
||||
CHECK(shard_client_seqno_ + 1 == seqno);
|
||||
shard_client_seqno_++;
|
||||
imported_any_ = true;
|
||||
check_next_shard_client_seqno(seqno + 1);
|
||||
}
|
||||
|
||||
void ArchiveImporter::apply_shard_block(BlockIdExt block_id, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::Unit> promise) {
|
||||
LOG(DEBUG) << "Applying shard block " << block_id.id.to_str();
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), masterchain_block_id, promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
R.ensure();
|
||||
|
@ -286,7 +417,7 @@ void ArchiveImporter::apply_shard_block_cont1(BlockHandle handle, BlockIdExt mas
|
|||
|
||||
if (handle->id().seqno() == 0) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise)](td::Result<td::Ref<ShardState>> R) mutable { promise.set_value(td::Unit()); });
|
||||
[promise = std::move(promise)](td::Result<td::Ref<ShardState>>) mutable { promise.set_value(td::Unit()); });
|
||||
td::actor::create_actor<DownloadShardState>("downloadstate", handle->id(), masterchain_block_id, 2, manager_,
|
||||
td::Timestamp::in(3600), std::move(P))
|
||||
.release();
|
||||
|
@ -294,12 +425,13 @@ void ArchiveImporter::apply_shard_block_cont1(BlockHandle handle, BlockIdExt mas
|
|||
}
|
||||
|
||||
auto it = blocks_.find(handle->id());
|
||||
if (it == blocks_.end()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, PSTRING() << "no proof for shard block " << handle->id()));
|
||||
if (it == blocks_.end() || !it->second.proof_pkg || !it->second.data_pkg) {
|
||||
promise.set_error(
|
||||
td::Status::Error(ErrorCode::notready, PSTRING() << "no data/proof for shard block " << handle->id()));
|
||||
return;
|
||||
}
|
||||
TRY_RESULT_PROMISE(promise, data, package_->read(it->second[0]));
|
||||
TRY_RESULT_PROMISE(promise, proof, create_proof_link(handle->id(), std::move(data.second)));
|
||||
TRY_RESULT_PROMISE(promise, proof_data, it->second.proof_pkg->read(it->second.proof_offset));
|
||||
TRY_RESULT_PROMISE(promise, proof, create_proof_link(handle->id(), std::move(proof_data.second)));
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle, masterchain_block_id,
|
||||
promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
|
@ -345,8 +477,8 @@ void ArchiveImporter::apply_shard_block_cont2(BlockHandle handle, BlockIdExt mas
|
|||
void ArchiveImporter::apply_shard_block_cont3(BlockHandle handle, BlockIdExt masterchain_block_id,
|
||||
td::Promise<td::Unit> promise) {
|
||||
auto it = blocks_.find(handle->id());
|
||||
CHECK(it != blocks_.end());
|
||||
TRY_RESULT_PROMISE(promise, data, package_->read(it->second[1]));
|
||||
CHECK(it != blocks_.end() && it->second.data_pkg);
|
||||
TRY_RESULT_PROMISE(promise, data, it->second.data_pkg->read(it->second.data_offset));
|
||||
if (sha256_bits256(data.second.as_slice()) != handle->id().file_hash) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad block file hash"));
|
||||
return;
|
||||
|
@ -367,6 +499,7 @@ void ArchiveImporter::check_shard_block_applied(BlockIdExt block_id, td::Promise
|
|||
if (!handle->is_applied()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not applied"));
|
||||
} else {
|
||||
LOG(DEBUG) << "Applied shard block " << handle->id().id.to_str();
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
}
|
||||
|
@ -375,13 +508,24 @@ void ArchiveImporter::check_shard_block_applied(BlockIdExt block_id, td::Promise
|
|||
}
|
||||
|
||||
void ArchiveImporter::abort_query(td::Status error) {
|
||||
LOG(INFO) << error;
|
||||
if (!imported_any_) {
|
||||
for (const std::string &f : files_to_cleanup_) {
|
||||
td::unlink(f).ignore();
|
||||
}
|
||||
promise_.set_error(std::move(error));
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Archive import: " << error;
|
||||
finish_query();
|
||||
}
|
||||
|
||||
void ArchiveImporter::finish_query() {
|
||||
for (const std::string &f : files_to_cleanup_) {
|
||||
td::unlink(f).ignore();
|
||||
}
|
||||
if (promise_) {
|
||||
promise_.set_value(
|
||||
std::vector<BlockSeqno>{state_->get_seqno(), std::min<BlockSeqno>(state_->get_seqno(), shard_client_seqno_)});
|
||||
promise_.set_value({last_masterchain_state_->get_seqno(),
|
||||
std::min<BlockSeqno>(last_masterchain_state_->get_seqno(), shard_client_seqno_)});
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "validator/interfaces/validator-manager.h"
|
||||
#include "validator/db/package.hpp"
|
||||
|
||||
|
@ -28,19 +29,27 @@ namespace validator {
|
|||
|
||||
class ArchiveImporter : public td::actor::Actor {
|
||||
public:
|
||||
ArchiveImporter(std::string path, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
|
||||
ArchiveImporter(std::string db_root, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
|
||||
td::Ref<ValidatorManagerOptions> opts, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::Promise<std::vector<BlockSeqno>> promise);
|
||||
std::vector<std::string> to_import_files, td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise);
|
||||
void start_up() override;
|
||||
|
||||
void abort_query(td::Status error);
|
||||
void finish_query();
|
||||
|
||||
void downloaded_mc_archive(std::string path);
|
||||
td::Status process_package(std::string path, bool with_masterchain);
|
||||
|
||||
void processed_mc_archive();
|
||||
void check_masterchain_block(BlockSeqno seqno);
|
||||
void checked_masterchain_proof(BlockHandle handle, td::Ref<BlockData> data);
|
||||
void applied_masterchain_block(BlockHandle handle);
|
||||
void got_new_materchain_state(td::Ref<MasterchainState> state);
|
||||
void checked_all_masterchain_blocks(BlockSeqno seqno);
|
||||
|
||||
void checked_all_masterchain_blocks();
|
||||
void download_shard_archives(td::Ref<MasterchainState> start_state);
|
||||
void download_shard_archive(ShardIdFull shard_prefix);
|
||||
void downloaded_shard_archive(std::string path);
|
||||
|
||||
void check_next_shard_client_seqno(BlockSeqno seqno);
|
||||
void checked_shard_client_seqno(BlockSeqno seqno);
|
||||
|
@ -52,19 +61,36 @@ class ArchiveImporter : public td::actor::Actor {
|
|||
void check_shard_block_applied(BlockIdExt block_id, td::Promise<td::Unit> promise);
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
td::Ref<MasterchainState> state_;
|
||||
std::string db_root_;
|
||||
td::Ref<MasterchainState> last_masterchain_state_;
|
||||
BlockSeqno shard_client_seqno_;
|
||||
BlockSeqno start_import_seqno_;
|
||||
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
|
||||
std::shared_ptr<Package> package_;
|
||||
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::Promise<std::vector<BlockSeqno>> promise_;
|
||||
|
||||
std::vector<std::string> to_import_files_;
|
||||
bool use_imported_files_;
|
||||
td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise_;
|
||||
|
||||
std::map<BlockSeqno, BlockIdExt> masterchain_blocks_;
|
||||
std::map<BlockIdExt, std::array<td::uint64, 2>> blocks_;
|
||||
BlockSeqno last_masterchain_seqno_ = 0;
|
||||
|
||||
struct BlockInfo {
|
||||
std::shared_ptr<Package> data_pkg;
|
||||
td::uint64 data_offset = 0;
|
||||
std::shared_ptr<Package> proof_pkg;
|
||||
td::uint64 proof_offset = 0;
|
||||
};
|
||||
std::map<BlockIdExt, BlockInfo> blocks_;
|
||||
|
||||
td::Ref<MasterchainState> start_state_;
|
||||
size_t pending_shard_archives_ = 0;
|
||||
|
||||
bool imported_any_ = false;
|
||||
bool have_shard_blocks_ = false;
|
||||
std::vector<std::string> files_to_cleanup_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -117,12 +117,18 @@ class Db : public td::actor::Actor {
|
|||
virtual void check_key_block_proof_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
|
||||
virtual void check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
|
||||
|
||||
virtual void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) = 0;
|
||||
virtual void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) = 0;
|
||||
virtual void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void set_async_mode(bool mode, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) = 0;
|
||||
|
||||
virtual void add_persistent_state_description(td::Ref<PersistentStateDescription> desc,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_persistent_state_descriptions(
|
||||
td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) = 0;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -84,6 +84,7 @@ class MasterchainState : virtual public ShardState {
|
|||
ton::LogicalTime* end_lt = nullptr) const = 0;
|
||||
virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;
|
||||
virtual td::Result<td::Ref<ConfigHolder>> get_config_holder() const = 0;
|
||||
virtual block::WorkchainSet get_workchain_list() const = 0;
|
||||
virtual td::Status prepare() {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ using ValidateCandidateResult = td::Variant<UnixTime, CandidateReject>;
|
|||
|
||||
class ValidatorManager : public ValidatorManagerInterface {
|
||||
public:
|
||||
virtual void init_last_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
}
|
||||
virtual void set_block_state(BlockHandle handle, td::Ref<ShardState> state,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
virtual void get_cell_db_reader(td::Promise<std::shared_ptr<vm::CellDbReader>> promise) = 0;
|
||||
|
@ -75,10 +77,6 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
std::function<td::Status(td::FileFd&)> write_data,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
virtual void wait_block_state_short(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
|
||||
virtual void set_block_data(BlockHandle handle, td::Ref<BlockData> data, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void wait_block_data(BlockHandle handle, td::uint32 priority, td::Timestamp,
|
||||
|
@ -148,10 +146,11 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) = 0;
|
||||
virtual void send_block_broadcast(BlockBroadcast broadcast, int mode) = 0;
|
||||
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
||||
virtual void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||
|
||||
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) = 0;
|
||||
virtual void subscribe_to_shard(ShardIdFull shard) = 0;
|
||||
|
||||
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
|
||||
|
@ -212,6 +211,8 @@ class ValidatorManager : public ValidatorManagerInterface {
|
|||
virtual void record_validate_query_stats(BlockIdExt block_id, double work_time, double cpu_work_time) {
|
||||
}
|
||||
|
||||
virtual void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) = 0;
|
||||
|
||||
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
|
||||
return ts / (1 << 17) != prev_ts / (1 << 17);
|
||||
}
|
||||
|
|
|
@ -265,11 +265,13 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
||||
}
|
||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
|
||||
void subscribe_to_shard(ShardIdFull shard) override {
|
||||
}
|
||||
|
||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
|
||||
UNREACHABLE();
|
||||
|
@ -285,7 +287,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
||||
}
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override {
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
|
@ -402,8 +405,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
queue_size_counter_ =
|
||||
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{}, actor_id(this));
|
||||
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{},
|
||||
opts_, actor_id(this));
|
||||
}
|
||||
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
|
||||
}
|
||||
|
@ -437,6 +440,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override {
|
||||
promise.set_result(td::Status::Error("not implemented"));
|
||||
}
|
||||
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {
|
||||
}
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
|
||||
opts_ = std::move(opts);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "interfaces/db.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "validator-group.hpp"
|
||||
#include "manager-init.h"
|
||||
#include "manager-hardfork.h"
|
||||
|
@ -334,6 +335,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
||||
}
|
||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override {
|
||||
UNREACHABLE();
|
||||
|
@ -341,8 +346,6 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void subscribe_to_shard(ShardIdFull shard) override {
|
||||
}
|
||||
|
||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
|
||||
UNREACHABLE();
|
||||
|
@ -358,7 +361,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
||||
}
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override {
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
|
@ -466,8 +470,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
queue_size_counter_ =
|
||||
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{}, actor_id(this));
|
||||
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{},
|
||||
opts_, actor_id(this));
|
||||
}
|
||||
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
|
||||
}
|
||||
|
@ -504,6 +508,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {
|
||||
}
|
||||
|
||||
private:
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
|
|
|
@ -268,6 +268,7 @@ void ValidatorManagerMasterchainReiniter::downloaded_masterchain_state(td::Ref<S
|
|||
CHECK(handle_->received_state());
|
||||
CHECK(handle_->is_applied());
|
||||
LOG(INFO) << "downloaded masterchain state";
|
||||
td::actor::send_closure(manager_, &ValidatorManager::init_last_masterchain_state, state_);
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::downloaded_all_shards);
|
||||
|
@ -567,7 +568,7 @@ void ValidatorManagerMasterchainStarter::truncated() {
|
|||
truncate_shard_next(handle_->id(), ig.get_promise());
|
||||
auto s = state_->get_shards();
|
||||
for (auto &shard : s) {
|
||||
if (opts_->need_monitor(shard->shard())) {
|
||||
if (opts_->need_monitor(shard->shard(), state_)) {
|
||||
truncate_shard_next(shard->top_block_id(), ig.get_promise());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
#include "checksum.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "validator-group.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "downloaders/wait-block-state.hpp"
|
||||
#include "downloaders/wait-block-state-merge.hpp"
|
||||
#include "downloaders/wait-block-data.hpp"
|
||||
#include "validator-group.hpp"
|
||||
#include "fabric.h"
|
||||
#include "manager.h"
|
||||
#include "validate-broadcast.hpp"
|
||||
|
@ -202,7 +200,7 @@ void ValidatorManagerImpl::validate_block(ReceivedBlock block, td::Promise<Block
|
|||
CHECK(blkid.is_masterchain());
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise), id = block.id](td::Result<td::Unit> R) mutable {
|
||||
[SelfId = actor_id(this), promise = std::move(promise), id = blkid](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
|
@ -217,12 +215,26 @@ void ValidatorManagerImpl::prevalidate_block(BlockBroadcast broadcast, td::Promi
|
|||
promise.set_error(td::Status::Error(ErrorCode::notready, "node not started"));
|
||||
return;
|
||||
}
|
||||
if (!need_monitor(broadcast.block_id.shard_full())) {
|
||||
promise.set_error(td::Status::Error("not monitoring shard"));
|
||||
return;
|
||||
}
|
||||
promise = [SelfId = actor_id(this), promise = std::move(promise), block_id = broadcast.block_id,
|
||||
cc_seqno = broadcast.catchain_seqno](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_ok()) {
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::validated_block_broadcast, block_id, cc_seqno);
|
||||
}
|
||||
promise.set_result(std::move(R));
|
||||
};
|
||||
td::actor::create_actor<ValidateBroadcast>("broadcast", std::move(broadcast), last_masterchain_block_handle_,
|
||||
last_masterchain_state_, last_known_key_block_handle_, actor_id(this),
|
||||
td::Timestamp::in(2.0), std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::validated_block_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno) {
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::sync_complete(td::Promise<td::Unit> promise) {
|
||||
started_ = true;
|
||||
|
||||
|
@ -474,7 +486,7 @@ void ValidatorManagerImpl::new_ihr_message(td::BufferSlice data) {
|
|||
}
|
||||
|
||||
void ValidatorManagerImpl::new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
|
||||
if (!is_validator()) {
|
||||
if (!is_validator() && !cached_block_candidates_.count(block_id)) {
|
||||
return;
|
||||
}
|
||||
if (!last_masterchain_block_handle_) {
|
||||
|
@ -508,37 +520,36 @@ void ValidatorManagerImpl::new_block_candidate(BlockIdExt block_id, td::BufferSl
|
|||
if (!started_) {
|
||||
return;
|
||||
}
|
||||
if (!need_monitor(block_id.shard_full())) {
|
||||
VLOG(VALIDATOR_DEBUG) << "dropping block candidate broadcast: not monitoring shard";
|
||||
return;
|
||||
}
|
||||
add_cached_block_candidate(ReceivedBlock{block_id, std::move(data)});
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_shard_block_description(td::Ref<ShardTopBlockDescription> desc) {
|
||||
if (desc->may_be_valid(last_masterchain_block_handle_, last_masterchain_state_)) {
|
||||
auto it = shard_blocks_.find(ShardTopBlockDescriptionId{desc->shard(), desc->catchain_seqno()});
|
||||
if (it != shard_blocks_.end() && desc->block_id().id.seqno <= it->second->block_id().id.seqno) {
|
||||
VLOG(VALIDATOR_DEBUG) << "dropping duplicate shard block broadcast";
|
||||
return;
|
||||
}
|
||||
shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
|
||||
VLOG(VALIDATOR_DEBUG) << "new shard block descr for " << desc->block_id();
|
||||
if (last_masterchain_block_handle_ && last_masterchain_seqno_ > 0 &&
|
||||
desc->generated_at() < last_masterchain_block_handle_->unix_time() + 60) {
|
||||
delay_action(
|
||||
[SelfId = actor_id(this), desc]() {
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
auto S = R.move_as_error();
|
||||
if (S.code() != ErrorCode::timeout && S.code() != ErrorCode::notready) {
|
||||
VLOG(VALIDATOR_NOTICE) << "failed to get shard state: " << S;
|
||||
} else {
|
||||
VLOG(VALIDATOR_DEBUG) << "failed to get shard state: " << S;
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(SelfId, &ValidatorManager::wait_block_state_short, desc->block_id(), 0,
|
||||
td::Timestamp::in(60.0), std::move(P));
|
||||
},
|
||||
td::Timestamp::in(1.0));
|
||||
}
|
||||
if (!desc->may_be_valid(last_masterchain_block_handle_, last_masterchain_state_)) {
|
||||
return;
|
||||
}
|
||||
auto it = shard_blocks_.find(ShardTopBlockDescriptionId{desc->shard(), desc->catchain_seqno()});
|
||||
if (it != shard_blocks_.end() && desc->block_id().id.seqno <= it->second->block_id().id.seqno) {
|
||||
VLOG(VALIDATOR_DEBUG) << "dropping duplicate shard block broadcast";
|
||||
return;
|
||||
}
|
||||
shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
|
||||
VLOG(VALIDATOR_DEBUG) << "new shard block descr for " << desc->block_id();
|
||||
if (need_monitor(desc->block_id().shard_full())) {
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
auto S = R.move_as_error();
|
||||
if (S.code() != ErrorCode::timeout && S.code() != ErrorCode::notready) {
|
||||
VLOG(VALIDATOR_NOTICE) << "failed to get shard state: " << S;
|
||||
} else {
|
||||
VLOG(VALIDATOR_DEBUG) << "failed to get shard state: " << S;
|
||||
}
|
||||
}
|
||||
});
|
||||
wait_block_state_short(desc->block_id(), 0, td::Timestamp::in(60.0), std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +565,7 @@ void ValidatorManagerImpl::add_cached_block_candidate(ReceivedBlock block) {
|
|||
if (it != wait_block_data_.end()) {
|
||||
auto r_block = create_block(cached_block_candidates_[id].clone());
|
||||
if (r_block.is_ok()) {
|
||||
td::actor::send_closure(it->second.actor_, &WaitBlockData::got_block_data_from_net, r_block.move_as_ok());
|
||||
td::actor::send_closure(it->second.actor_, &WaitBlockData::loaded_block_data, r_block.move_as_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -672,6 +683,10 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
|
|||
|
||||
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) {
|
||||
if (last_masterchain_state_.not_null() && !opts_->need_monitor(handle->id().shard_full(), last_masterchain_state_)) {
|
||||
return promise.set_error(
|
||||
td::Status::Error(PSTRING() << "not monitoring shard " << handle->id().shard_full().to_str()));
|
||||
}
|
||||
auto it0 = block_state_cache_.find(handle->id());
|
||||
if (it0 != block_state_cache_.end()) {
|
||||
it0->second.ttl_ = td::Timestamp::in(30.0);
|
||||
|
@ -683,9 +698,11 @@ void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 prior
|
|||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Ref<ShardState>> R) {
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_state, handle, std::move(R));
|
||||
});
|
||||
auto id = td::actor::create_actor<WaitBlockState>("waitstate", handle, priority, actor_id(this),
|
||||
td::Timestamp::in(10.0), std::move(P))
|
||||
.release();
|
||||
auto id =
|
||||
td::actor::create_actor<WaitBlockState>("waitstate", handle, priority, actor_id(this),
|
||||
td::Timestamp::at(timeout.at() + 10.0), std::move(P),
|
||||
get_block_persistent_state(handle->id()))
|
||||
.release();
|
||||
wait_state_[handle->id()].actor_ = id;
|
||||
it = wait_state_.find(handle->id());
|
||||
}
|
||||
|
@ -717,7 +734,7 @@ void ValidatorManagerImpl::wait_block_data(BlockHandle handle, td::uint32 priori
|
|||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_data, handle, std::move(R));
|
||||
});
|
||||
auto id = td::actor::create_actor<WaitBlockData>("waitdata", handle, priority, actor_id(this),
|
||||
td::Timestamp::in(10.0), std::move(P))
|
||||
td::Timestamp::at(timeout.at() + 10.0), false, std::move(P))
|
||||
.release();
|
||||
wait_block_data_[handle->id()].actor_ = id;
|
||||
it = wait_block_data_.find(handle->id());
|
||||
|
@ -744,6 +761,10 @@ void ValidatorManagerImpl::wait_block_data_short(BlockIdExt block_id, td::uint32
|
|||
|
||||
void ValidatorManagerImpl::wait_block_state_merge(BlockIdExt left_id, BlockIdExt right_id, td::uint32 priority,
|
||||
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise) {
|
||||
if (last_masterchain_state_.not_null() && !opts_->need_monitor(left_id.shard_full(), last_masterchain_state_)) {
|
||||
return promise.set_error(
|
||||
td::Status::Error(PSTRING() << "not monitoring shard " << left_id.shard_full().to_str()));
|
||||
}
|
||||
td::actor::create_actor<WaitBlockStateMerge>("merge", left_id, right_id, priority, actor_id(this), timeout,
|
||||
std::move(promise))
|
||||
.release();
|
||||
|
@ -1128,7 +1149,7 @@ void ValidatorManagerImpl::finished_wait_state(BlockHandle handle, td::Result<td
|
|||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_state, handle, std::move(R));
|
||||
});
|
||||
auto id = td::actor::create_actor<WaitBlockState>("waitstate", handle, X.second, actor_id(this), X.first,
|
||||
std::move(P))
|
||||
std::move(P), get_block_persistent_state(handle->id()))
|
||||
.release();
|
||||
it->second.actor_ = id;
|
||||
return;
|
||||
|
@ -1158,8 +1179,9 @@ void ValidatorManagerImpl::finished_wait_data(BlockHandle handle, td::Result<td:
|
|||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_data, handle, std::move(R));
|
||||
});
|
||||
auto id =
|
||||
td::actor::create_actor<WaitBlockData>("waitdata", handle, X.second, actor_id(this), X.first, std::move(P))
|
||||
.release();
|
||||
td::actor::create_actor<WaitBlockData>("waitdata", handle, X.second, actor_id(this), X.first, false,
|
||||
std::move(P))
|
||||
.release();
|
||||
it->second.actor_ = id;
|
||||
return;
|
||||
}
|
||||
|
@ -1617,6 +1639,7 @@ void ValidatorManagerImpl::send_top_shard_block_description(td::Ref<ShardTopBloc
|
|||
} else {
|
||||
out_shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
|
||||
callback_->send_shard_block_info(desc->block_id(), desc->catchain_seqno(), desc->serialize());
|
||||
add_shard_block_description(desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1629,6 +1652,12 @@ void ValidatorManagerImpl::send_validator_telemetry(PublicKeyHash key,
|
|||
callback_->send_validator_telemetry(key, std::move(telemetry));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix,
|
||||
std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) {
|
||||
callback_->download_archive(mc_seqno, shard_prefix, std::move(tmp_dir), timeout, std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::start_up() {
|
||||
db_ = create_db_actor(actor_id(this), db_root_, opts_);
|
||||
actor_stats_ = td::actor::create_actor<td::actor::ActorStats>("actor_stats");
|
||||
|
@ -1664,7 +1693,6 @@ void ValidatorManagerImpl::start_up() {
|
|||
if (fname.substr(fname.size() - 5) != ".pack") {
|
||||
return;
|
||||
}
|
||||
fname = fname.substr(0, fname.size() - 5);
|
||||
if (fname.substr(0, 8) != "archive.") {
|
||||
return;
|
||||
}
|
||||
|
@ -1673,13 +1701,18 @@ void ValidatorManagerImpl::start_up() {
|
|||
while (fname.size() > 1 && fname[0] == '0') {
|
||||
fname.remove_prefix(1);
|
||||
}
|
||||
auto i = fname.find('.');
|
||||
if (i == td::Slice::npos) {
|
||||
return;
|
||||
}
|
||||
fname = fname.substr(0, i);
|
||||
auto v = td::to_integer_safe<BlockSeqno>(fname);
|
||||
if (v.is_error()) {
|
||||
return;
|
||||
}
|
||||
auto pos = v.move_as_ok();
|
||||
LOG(INFO) << "found archive slice '" << cfname << "' for position " << pos;
|
||||
to_import_[pos] = std::make_pair(cfname.str(), true);
|
||||
auto seqno = v.move_as_ok();
|
||||
LOG(INFO) << "found archive slice '" << cfname << "' for seqno " << seqno;
|
||||
to_import_[seqno].push_back(cfname.str());
|
||||
}
|
||||
});
|
||||
if (S.is_error()) {
|
||||
|
@ -1692,6 +1725,14 @@ void ValidatorManagerImpl::start_up() {
|
|||
alarm_timestamp().relax(check_waiters_at_);
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::init_last_masterchain_state(td::Ref<MasterchainState> state) {
|
||||
if (last_masterchain_state_.not_null()) {
|
||||
return;
|
||||
}
|
||||
last_masterchain_state_ = std::move(state);
|
||||
update_shard_overlays();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
|
||||
CHECK(R.handle);
|
||||
CHECK(R.state.not_null());
|
||||
|
@ -1730,6 +1771,17 @@ void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
|
|||
candidates_buffer_ = td::actor::create_actor<CandidatesBuffer>("candidates-buffer", actor_id(this));
|
||||
}
|
||||
init_validator_telemetry();
|
||||
|
||||
auto Q = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this)](td::Result<std::vector<td::Ref<PersistentStateDescription>>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << "db error: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::got_persistent_state_descriptions, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(db_, &Db::get_persistent_state_descriptions, std::move(Q));
|
||||
update_shard_overlays();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::read_gc_list(std::vector<ValidatorSessionId> list) {
|
||||
|
@ -1832,61 +1884,35 @@ void ValidatorManagerImpl::download_next_archive() {
|
|||
}
|
||||
|
||||
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
|
||||
std::vector<std::string> to_import_files;
|
||||
auto it = to_import_.upper_bound(seqno + 1);
|
||||
if (it != to_import_.begin()) {
|
||||
it--;
|
||||
if (it->second.second) {
|
||||
it->second.second = false;
|
||||
downloaded_archive_slice(it->second.first, false);
|
||||
return;
|
||||
}
|
||||
--it;
|
||||
to_import_files = std::move(it->second);
|
||||
it->second.clear();
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::string> R) {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::pair<BlockSeqno, BlockSeqno>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(INFO) << "failed to download archive slice: " << R.error();
|
||||
LOG(INFO) << "failed to download and import archive slice: " << R.error();
|
||||
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
|
||||
td::Timestamp::in(2.0));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::downloaded_archive_slice, R.move_as_ok(), true);
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::checked_archive_slice, R.ok().first, R.ok().second);
|
||||
}
|
||||
});
|
||||
callback_->download_archive(seqno + 1, db_root_ + "/tmp/", td::Timestamp::in(36000.0), std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::downloaded_archive_slice(std::string name, bool is_tmp) {
|
||||
LOG(INFO) << "downloaded archive slice: " << name;
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), name, is_tmp](td::Result<std::vector<BlockSeqno>> R) {
|
||||
if (is_tmp) {
|
||||
td::unlink(name).ensure();
|
||||
}
|
||||
if (R.is_error()) {
|
||||
LOG(INFO) << "failed to check downloaded archive slice: " << R.error();
|
||||
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
|
||||
td::Timestamp::in(2.0));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ValidatorManagerImpl::checked_archive_slice, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
|
||||
|
||||
td::actor::create_actor<ArchiveImporter>("archiveimport", name, last_masterchain_state_, seqno, opts_, actor_id(this),
|
||||
std::move(P))
|
||||
td::actor::create_actor<ArchiveImporter>("archiveimport", db_root_, last_masterchain_state_, seqno, opts_,
|
||||
actor_id(this), std::move(to_import_files), std::move(P))
|
||||
.release();
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::checked_archive_slice(std::vector<BlockSeqno> seqno) {
|
||||
CHECK(seqno.size() == 2);
|
||||
LOG(INFO) << "checked downloaded archive slice: mc_top_seqno=" << seqno[0] << " shard_top_seqno_=" << seqno[1];
|
||||
CHECK(seqno[0] <= last_masterchain_seqno_);
|
||||
CHECK(seqno[1] <= last_masterchain_seqno_);
|
||||
void ValidatorManagerImpl::checked_archive_slice(BlockSeqno new_last_mc_seqno, BlockSeqno new_shard_client_seqno) {
|
||||
LOG(INFO) << "checked downloaded archive slice: mc_top_seqno=" << new_last_mc_seqno
|
||||
<< " shard_top_seqno_=" << new_shard_client_seqno;
|
||||
CHECK(new_last_mc_seqno <= last_masterchain_seqno_);
|
||||
CHECK(new_shard_client_seqno <= last_masterchain_seqno_);
|
||||
|
||||
BlockIdExt b;
|
||||
if (seqno[1] < last_masterchain_seqno_) {
|
||||
CHECK(last_masterchain_state_->get_old_mc_block_id(seqno[1], b));
|
||||
} else {
|
||||
b = last_masterchain_block_id_;
|
||||
}
|
||||
BlockIdExt shard_client_block_id;
|
||||
CHECK(last_masterchain_state_->get_old_mc_block_id(new_shard_client_seqno, shard_client_block_id));
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), db = db_.get(), client = shard_client_.get()](td::Result<BlockHandle> R) {
|
||||
|
@ -1902,7 +1928,7 @@ void ValidatorManagerImpl::checked_archive_slice(std::vector<BlockSeqno> seqno)
|
|||
});
|
||||
td::actor::send_closure(db, &Db::get_block_state, std::move(handle), std::move(P));
|
||||
});
|
||||
get_block_handle(b, true, std::move(P));
|
||||
get_block_handle(shard_client_block_id, true, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::finish_prestart_sync() {
|
||||
|
@ -1939,6 +1965,7 @@ void ValidatorManagerImpl::new_masterchain_block() {
|
|||
init_validator_telemetry();
|
||||
}
|
||||
|
||||
update_shard_overlays();
|
||||
update_shards();
|
||||
update_shard_blocks();
|
||||
|
||||
|
@ -1952,6 +1979,26 @@ void ValidatorManagerImpl::new_masterchain_block() {
|
|||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::update_shard_overlays() {
|
||||
CHECK(last_masterchain_state_.not_null());
|
||||
std::set<ShardIdFull> shards_to_monitor;
|
||||
shards_to_monitor.insert(ShardIdFull{masterchainId});
|
||||
std::set<WorkchainId> workchains;
|
||||
for (const auto& shard : last_masterchain_state_->get_shards()) {
|
||||
workchains.insert(shard->shard().workchain);
|
||||
if (opts_->need_monitor(shard->shard(),last_masterchain_state_)) {
|
||||
shards_to_monitor.insert(shard->shard());
|
||||
}
|
||||
}
|
||||
for (const auto &[wc, desc] : last_masterchain_state_->get_workchain_list()) {
|
||||
if (!workchains.count(wc) && desc->active &&
|
||||
opts_->need_monitor(ShardIdFull{wc, shardIdAll}, last_masterchain_state_)) {
|
||||
shards_to_monitor.insert(ShardIdFull{wc, shardIdAll});
|
||||
}
|
||||
}
|
||||
callback_->on_new_masterchain_block(last_masterchain_state_, std::move(shards_to_monitor));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::update_shards() {
|
||||
if ((last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) &&
|
||||
opts_->get_last_fork_masterchain_seqno() <= last_masterchain_seqno_) {
|
||||
|
@ -2268,7 +2315,8 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
|
|||
auto validator_id = get_validator(shard, validator_set);
|
||||
CHECK(!validator_id.is_zero());
|
||||
auto G = td::actor::create_actor<ValidatorGroup>(
|
||||
"validatorgroup", shard, validator_id, session_id, validator_set, key_seqno, opts, keyring_, adnl_, rldp_,
|
||||
PSTRING() << "valgroup" << shard.to_str(), shard, validator_id, session_id, validator_set, key_seqno, opts,
|
||||
keyring_, adnl_, rldp_,
|
||||
overlays_, db_root_, actor_id(this), init_session,
|
||||
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), opts_);
|
||||
return G;
|
||||
|
@ -2444,7 +2492,7 @@ void ValidatorManagerImpl::allow_block_state_gc(BlockIdExt block_id, td::Promise
|
|||
return;
|
||||
}
|
||||
auto shards = gc_masterchain_state_->get_shards();
|
||||
for (auto shard : shards) {
|
||||
for (const auto &shard : shards) {
|
||||
if (shard_intersects(shard->shard(), block_id.shard_full())) {
|
||||
promise.set_result(block_id.id.seqno < shard->top_block_id().id.seqno);
|
||||
return;
|
||||
|
@ -2682,10 +2730,6 @@ void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<Bloc
|
|||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::subscribe_to_shard(ShardIdFull shard) {
|
||||
callback_->add_shard(shard);
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(db_, &Db::update_async_serializer_state, std::move(state), std::move(promise));
|
||||
}
|
||||
|
@ -2698,12 +2742,13 @@ void ValidatorManagerImpl::try_get_static_file(FileHash file_hash, td::Promise<t
|
|||
td::actor::send_closure(db_, &Db::try_get_static_file, file_hash, std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
|
||||
void ValidatorManagerImpl::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) {
|
||||
if (masterchain_seqno > last_masterchain_seqno_) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "masterchain seqno too big"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(db_, &Db::get_archive_id, masterchain_seqno, std::move(promise));
|
||||
td::actor::send_closure(db_, &Db::get_archive_id, masterchain_seqno, shard_prefix, std::move(promise));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
|
@ -2715,10 +2760,13 @@ bool ValidatorManagerImpl::is_validator() {
|
|||
return temp_keys_.size() > 0 || permanent_keys_.size() > 0;
|
||||
}
|
||||
|
||||
bool ValidatorManagerImpl::validating_masterchain() {
|
||||
return !get_validator(ShardIdFull(masterchainId),
|
||||
last_masterchain_state_->get_validator_set(ShardIdFull(masterchainId)))
|
||||
.is_zero();
|
||||
}
|
||||
|
||||
PublicKeyHash ValidatorManagerImpl::get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set) {
|
||||
if (!opts_->need_validate(shard, val_set->get_catchain_seqno())) {
|
||||
return PublicKeyHash::zero();
|
||||
}
|
||||
for (auto &key : temp_keys_) {
|
||||
if (val_set->is_validator(key.bits256_value())) {
|
||||
return key;
|
||||
|
@ -3224,10 +3272,15 @@ void ValidatorManagerImpl::get_validator_groups_info_for_litequery(
|
|||
}
|
||||
|
||||
void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts) {
|
||||
// Currently options can be updated only to change state_serializer_enabled flag and collator_options
|
||||
if (!shard_client_.empty()) {
|
||||
td::actor::send_closure(shard_client_, &ShardClient::update_options, opts);
|
||||
}
|
||||
if (!serializer_.empty()) {
|
||||
td::actor::send_closure(serializer_, &AsyncStateSerializer::update_options, opts);
|
||||
}
|
||||
if (!queue_size_counter_.empty()) {
|
||||
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::update_options, opts);
|
||||
}
|
||||
for (auto &group : validator_groups_) {
|
||||
td::actor::send_closure(group.second.actor, &ValidatorGroup::update_options, opts);
|
||||
}
|
||||
|
@ -3237,6 +3290,53 @@ void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts)
|
|||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_persistent_state_description(td::Ref<PersistentStateDescription> desc) {
|
||||
auto now = (UnixTime)td::Clocks::system();
|
||||
if (desc->end_time <= now) {
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(db_, &Db::add_persistent_state_description, desc, [](td::Result<td::Unit>) {});
|
||||
auto it = persistent_state_descriptions_.begin();
|
||||
while (it != persistent_state_descriptions_.end()) {
|
||||
const auto &prev_desc = it->second;
|
||||
if (prev_desc->end_time <= now) {
|
||||
for (const BlockIdExt &block_id : prev_desc->shard_blocks) {
|
||||
persistent_state_blocks_.erase(block_id);
|
||||
}
|
||||
it = persistent_state_descriptions_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
add_persistent_state_description_impl(std::move(desc));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_persistent_state_description_impl(td::Ref<PersistentStateDescription> desc) {
|
||||
if (!persistent_state_descriptions_.emplace(desc->masterchain_id.seqno(), desc).second) {
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG) << "Add persistent state description for mc block " << desc->masterchain_id.to_str()
|
||||
<< " start_time=" << desc->start_time << " end_time=" << desc->end_time;
|
||||
for (const BlockIdExt &block_id : desc->shard_blocks) {
|
||||
persistent_state_blocks_[block_id] = desc;
|
||||
LOG(DEBUG) << "Persistent state description: shard block " << block_id.to_str();
|
||||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::got_persistent_state_descriptions(std::vector<td::Ref<PersistentStateDescription>> descs) {
|
||||
for (auto &desc : descs) {
|
||||
add_persistent_state_description_impl(std::move(desc));
|
||||
}
|
||||
}
|
||||
|
||||
td::Ref<PersistentStateDescription> ValidatorManagerImpl::get_block_persistent_state(BlockIdExt block_id) {
|
||||
auto it = persistent_state_blocks_.find(block_id);
|
||||
if (it == persistent_state_blocks_.end()) {
|
||||
return {};
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
||||
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
|
|
|
@ -189,6 +189,12 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
waiting_.resize(j);
|
||||
}
|
||||
};
|
||||
template <typename ActorT, typename ResType>
|
||||
struct WaitListCaching : public WaitList<ActorT, ResType> {
|
||||
bool done_ = false;
|
||||
ResType result_;
|
||||
td::Timestamp remove_at_;
|
||||
};
|
||||
std::map<BlockIdExt, WaitList<WaitBlockState, td::Ref<ShardState>>> wait_state_;
|
||||
std::map<BlockIdExt, WaitList<WaitBlockData, td::Ref<BlockData>>> wait_block_data_;
|
||||
|
||||
|
@ -305,6 +311,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
std::vector<PerfTimerStats> perf_timer_stats;
|
||||
|
||||
void new_masterchain_block();
|
||||
void update_shard_overlays();
|
||||
void update_shards();
|
||||
void update_shard_blocks();
|
||||
void written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> groups);
|
||||
|
@ -323,8 +330,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void applied_hardfork();
|
||||
void prestart_sync();
|
||||
void download_next_archive();
|
||||
void downloaded_archive_slice(std::string name, bool is_tmp);
|
||||
void checked_archive_slice(std::vector<BlockSeqno> seqno);
|
||||
void checked_archive_slice(BlockSeqno new_last_mc_seqno, BlockSeqno new_shard_client_seqno);
|
||||
void finish_prestart_sync();
|
||||
void completed_prestart_sync();
|
||||
|
||||
|
@ -361,6 +367,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
td::Promise<td::Unit> promise) override;
|
||||
void validate_block(ReceivedBlock block, td::Promise<BlockHandle> promise) override;
|
||||
void prevalidate_block(BlockBroadcast broadcast, td::Promise<td::Unit> promise) override;
|
||||
void validated_block_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno);
|
||||
|
||||
//void create_validate_block(BlockId block, td::BufferSlice data, td::Promise<Block> promise) = 0;
|
||||
void sync_complete(td::Promise<td::Unit> promise) override;
|
||||
|
@ -505,10 +512,11 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
|
||||
void send_block_broadcast(BlockBroadcast broadcast, int mode) override;
|
||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override;
|
||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
||||
|
||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
|
||||
void subscribe_to_shard(ShardIdFull shard) override;
|
||||
|
||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
||||
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
|
||||
|
@ -521,7 +529,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
std::move(promise));
|
||||
}
|
||||
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override;
|
||||
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) override;
|
||||
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
|
||||
|
@ -542,10 +550,12 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void finished_wait_data(BlockHandle handle, td::Result<td::Ref<BlockData>> R);
|
||||
|
||||
void start_up() override;
|
||||
void init_last_masterchain_state(td::Ref<MasterchainState> state) override;
|
||||
void started(ValidatorManagerInitResult result);
|
||||
void read_gc_list(std::vector<ValidatorSessionId> list);
|
||||
|
||||
bool is_validator();
|
||||
bool validating_masterchain();
|
||||
PublicKeyHash get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set);
|
||||
|
||||
ValidatorManagerImpl(td::Ref<ValidatorManagerOptions> opts, std::string db_root,
|
||||
|
@ -604,14 +614,20 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) override;
|
||||
|
||||
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override;
|
||||
|
||||
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
|
||||
if (queue_size_counter_.empty()) {
|
||||
if (last_masterchain_state_.is_null()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
|
||||
return;
|
||||
}
|
||||
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter",
|
||||
last_masterchain_state_, actor_id(this));
|
||||
queue_size_counter_ =
|
||||
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", last_masterchain_state_, opts_, actor_id(this));
|
||||
}
|
||||
if (!opts_->need_monitor(block_id.shard_full(), last_masterchain_state_)) {
|
||||
return promise.set_error(
|
||||
td::Status::Error(PSTRING() << "not monitoring shard " << block_id.shard_full().to_str()));
|
||||
}
|
||||
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
|
||||
}
|
||||
|
@ -682,7 +698,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
|
||||
td::actor::ActorOwn<AsyncStateSerializer> serializer_;
|
||||
|
||||
std::map<BlockSeqno, std::pair<std::string, bool>> to_import_;
|
||||
std::map<BlockSeqno, std::vector<std::string>> to_import_;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Callback> callback_;
|
||||
|
@ -712,7 +728,15 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
return 3 * 10;
|
||||
}
|
||||
|
||||
void got_persistent_state_descriptions(std::vector<td::Ref<PersistentStateDescription>> descs);
|
||||
void add_persistent_state_description_impl(td::Ref<PersistentStateDescription> desc);
|
||||
td::Ref<PersistentStateDescription> get_block_persistent_state(BlockIdExt block_id);
|
||||
|
||||
private:
|
||||
bool need_monitor(ShardIdFull shard) const {
|
||||
return opts_->need_monitor(shard, last_masterchain_state_);
|
||||
}
|
||||
|
||||
std::map<BlockSeqno, WaitList<td::actor::Actor, td::Unit>> shard_client_waiters_;
|
||||
td::actor::ActorOwn<QueueSizeCounter> queue_size_counter_;
|
||||
|
||||
|
@ -740,6 +764,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
std::map<PublicKeyHash, td::actor::ActorOwn<ValidatorTelemetry>> validator_telemetry_;
|
||||
|
||||
void init_validator_telemetry();
|
||||
|
||||
std::map<BlockSeqno, td::Ref<PersistentStateDescription>> persistent_state_descriptions_;
|
||||
std::map<BlockIdExt, td::Ref<PersistentStateDescription>> persistent_state_blocks_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
#include <ton/ton-tl.hpp>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
@ -27,12 +29,13 @@ namespace validator {
|
|||
namespace fullnode {
|
||||
|
||||
DownloadArchiveSlice::DownloadArchiveSlice(
|
||||
BlockSeqno masterchain_seqno, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
|
||||
BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
|
||||
overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager, td::actor::ActorId<adnl::AdnlSenderInterface> rldp,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<adnl::AdnlExtClient> client, td::Promise<std::string> promise)
|
||||
: masterchain_seqno_(masterchain_seqno)
|
||||
, shard_prefix_(shard_prefix)
|
||||
, tmp_dir_(std::move(tmp_dir))
|
||||
, local_id_(local_id)
|
||||
, overlay_id_(overlay_id)
|
||||
|
@ -114,7 +117,13 @@ void DownloadArchiveSlice::got_node_to_download(adnl::AdnlNodeIdShort download_f
|
|||
}
|
||||
});
|
||||
|
||||
auto q = create_serialize_tl_object<ton_api::tonNode_getArchiveInfo>(masterchain_seqno_);
|
||||
td::BufferSlice q;
|
||||
if (shard_prefix_.is_masterchain()) {
|
||||
q = create_serialize_tl_object<ton_api::tonNode_getArchiveInfo>(masterchain_seqno_);
|
||||
} else {
|
||||
q = create_serialize_tl_object<ton_api::tonNode_getShardArchiveInfo>(masterchain_seqno_,
|
||||
create_tl_shard_id(shard_prefix_));
|
||||
}
|
||||
if (client_.empty()) {
|
||||
td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_,
|
||||
"get_archive_info", std::move(P), td::Timestamp::in(3.0), std::move(q));
|
||||
|
@ -145,7 +154,8 @@ void DownloadArchiveSlice::got_archive_info(td::BufferSlice data) {
|
|||
}
|
||||
|
||||
prev_logged_timer_ = td::Timer();
|
||||
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " from " << download_from_;
|
||||
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str() << " from "
|
||||
<< download_from_;
|
||||
get_archive_slice();
|
||||
}
|
||||
|
||||
|
@ -186,13 +196,15 @@ void DownloadArchiveSlice::got_archive_slice(td::BufferSlice data) {
|
|||
double elapsed = prev_logged_timer_.elapsed();
|
||||
if (elapsed > 10.0) {
|
||||
prev_logged_timer_ = td::Timer();
|
||||
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << ": total=" << offset_ << " ("
|
||||
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str()
|
||||
<< ": total=" << offset_ << " ("
|
||||
<< td::format::as_size((td::uint64)(double(offset_ - prev_logged_sum_) / elapsed)) << "/s)";
|
||||
prev_logged_sum_ = offset_;
|
||||
}
|
||||
|
||||
if (data.size() < slice_size()) {
|
||||
LOG(INFO) << "finished downloading arcrive slice #" << masterchain_seqno_ << ": total=" << offset_;
|
||||
LOG(INFO) << "finished downloading arcrive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str()
|
||||
<< ": total=" << offset_;
|
||||
finish_query();
|
||||
} else {
|
||||
get_archive_slice();
|
||||
|
|
|
@ -32,8 +32,9 @@ namespace fullnode {
|
|||
|
||||
class DownloadArchiveSlice : public td::actor::Actor {
|
||||
public:
|
||||
DownloadArchiveSlice(BlockSeqno masterchain_seqno, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
|
||||
overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
|
||||
DownloadArchiveSlice(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
adnl::AdnlNodeIdShort local_id, overlay::OverlayIdShort overlay_id,
|
||||
adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
|
||||
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> rldp,
|
||||
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
|
@ -55,6 +56,7 @@ class DownloadArchiveSlice : public td::actor::Actor {
|
|||
|
||||
private:
|
||||
BlockSeqno masterchain_seqno_;
|
||||
ShardIdFull shard_prefix_;
|
||||
std::string tmp_dir_;
|
||||
std::string tmp_name_;
|
||||
td::FileFd fd_;
|
||||
|
|
|
@ -234,7 +234,9 @@ void QueueSizeCounter::process_top_shard_blocks_cont(td::Ref<MasterchainState> s
|
|||
last_top_blocks_.clear();
|
||||
last_top_blocks_.push_back(state->get_block_id());
|
||||
for (auto &shard : state->get_shards()) {
|
||||
last_top_blocks_.push_back(shard->top_block_id());
|
||||
if (opts_->need_monitor(shard->shard(), state)) {
|
||||
last_top_blocks_.push_back(shard->top_block_id());
|
||||
}
|
||||
}
|
||||
for (const BlockIdExt &block_id : last_top_blocks_) {
|
||||
get_queue_size_ex_retry(block_id, init, ig.get_promise());
|
||||
|
|
|
@ -21,16 +21,22 @@ namespace ton::validator {
|
|||
|
||||
class QueueSizeCounter : public td::actor::Actor {
|
||||
public:
|
||||
QueueSizeCounter(td::Ref<MasterchainState> last_masterchain_state, td::actor::ActorId<ValidatorManager> manager)
|
||||
: init_masterchain_state_(last_masterchain_state), manager_(std::move(manager)) {
|
||||
QueueSizeCounter(td::Ref<MasterchainState> last_masterchain_state, td::Ref<ValidatorManagerOptions> opts,
|
||||
td::actor::ActorId<ValidatorManager> manager)
|
||||
: init_masterchain_state_(last_masterchain_state), opts_(std::move(opts)), manager_(std::move(manager)) {
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
void get_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise);
|
||||
void alarm() override;
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts) {
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
private:
|
||||
td::Ref<MasterchainState> init_masterchain_state_;
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
bool simple_mode_ = false;
|
||||
|
||||
|
|
|
@ -70,18 +70,13 @@ void ShardClient::got_init_handle_from_db(BlockHandle handle) {
|
|||
}
|
||||
|
||||
void ShardClient::got_init_state_from_db(td::Ref<MasterchainState> state) {
|
||||
masterchain_state_ = std::move(state);
|
||||
build_shard_overlays();
|
||||
masterchain_state_.clear();
|
||||
|
||||
saved_to_db();
|
||||
}
|
||||
|
||||
void ShardClient::start_up_init_mode() {
|
||||
build_shard_overlays();
|
||||
std::vector<BlockIdExt> shards;
|
||||
for (const auto& s : masterchain_state_->get_shards()) {
|
||||
if (opts_->need_monitor(s->shard())) {
|
||||
if (opts_->need_monitor(s->shard(), masterchain_state_)) {
|
||||
shards.push_back(s->top_block_id());
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +161,6 @@ void ShardClient::download_masterchain_state() {
|
|||
|
||||
void ShardClient::got_masterchain_block_state(td::Ref<MasterchainState> state) {
|
||||
masterchain_state_ = std::move(state);
|
||||
build_shard_overlays();
|
||||
if (started_) {
|
||||
apply_all_shards();
|
||||
}
|
||||
|
@ -189,8 +183,10 @@ void ShardClient::apply_all_shards() {
|
|||
ig.add_promise(std::move(P));
|
||||
|
||||
auto vec = masterchain_state_->get_shards();
|
||||
std::set<WorkchainId> workchains;
|
||||
for (auto &shard : vec) {
|
||||
if (opts_->need_monitor(shard->shard())) {
|
||||
workchains.insert(shard->shard().workchain);
|
||||
if (opts_->need_monitor(shard->shard(), masterchain_state_)) {
|
||||
auto Q = td::PromiseCreator::lambda([SelfId = actor_id(this), promise = ig.get_promise(),
|
||||
shard = shard->shard()](td::Result<td::Ref<ShardState>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
|
@ -200,7 +196,22 @@ void ShardClient::apply_all_shards() {
|
|||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, shard->top_block_id(),
|
||||
shard_client_priority(), td::Timestamp::in(600), std::move(Q));
|
||||
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
|
||||
}
|
||||
}
|
||||
for (const auto &[wc, desc] : masterchain_state_->get_workchain_list()) {
|
||||
if (!workchains.count(wc) && desc->active && opts_->need_monitor(ShardIdFull{wc, shardIdAll}, masterchain_state_)) {
|
||||
auto Q = td::PromiseCreator::lambda([SelfId = actor_id(this), promise = ig.get_promise(),
|
||||
workchain = wc](td::Result<td::Ref<ShardState>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix(PSTRING() << "workchain " << workchain << ": "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ShardClient::downloaded_shard_state, R.move_as_ok(), std::move(promise));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short,
|
||||
BlockIdExt{wc, shardIdAll, 0, desc->zerostate_root_hash, desc->zerostate_file_hash},
|
||||
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +234,6 @@ void ShardClient::new_masterchain_block_notification(BlockHandle handle, td::Ref
|
|||
masterchain_block_handle_ = std::move(handle);
|
||||
masterchain_state_ = std::move(state);
|
||||
waiting_ = false;
|
||||
build_shard_overlays();
|
||||
|
||||
apply_all_shards();
|
||||
}
|
||||
|
@ -244,26 +254,6 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
|
|||
}
|
||||
}
|
||||
|
||||
void ShardClient::build_shard_overlays() {
|
||||
auto v = masterchain_state_->get_shards();
|
||||
|
||||
for (auto &x : v) {
|
||||
auto shard = x->shard();
|
||||
if (opts_->need_monitor(shard)) {
|
||||
auto d = masterchain_state_->monitor_min_split_depth(shard.workchain);
|
||||
auto l = shard_prefix_length(shard.shard);
|
||||
if (l > d) {
|
||||
shard = shard_prefix(shard, d);
|
||||
}
|
||||
|
||||
if (created_overlays_.count(shard) == 0) {
|
||||
created_overlays_.insert(shard);
|
||||
td::actor::send_closure(manager_, &ValidatorManager::subscribe_to_shard, shard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
CHECK(!init_mode_);
|
||||
CHECK(!started_);
|
||||
|
@ -294,10 +284,13 @@ void ShardClient::force_update_shard_client_ex(BlockHandle handle, td::Ref<Maste
|
|||
masterchain_block_handle_ = std::move(handle);
|
||||
masterchain_state_ = std::move(state);
|
||||
promise_ = std::move(promise);
|
||||
build_shard_overlays();
|
||||
applied_all_shards();
|
||||
}
|
||||
|
||||
void ShardClient::update_options(td::Ref<ValidatorManagerOptions> opts) {
|
||||
opts_ = std::move(opts);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -42,8 +42,6 @@ class ShardClient : public td::actor::Actor {
|
|||
|
||||
td::Promise<td::Unit> promise_;
|
||||
|
||||
std::set<ShardIdFull> created_overlays_;
|
||||
|
||||
public:
|
||||
ShardClient(td::Ref<ValidatorManagerOptions> opts, BlockHandle masterchain_block_handle,
|
||||
td::Ref<MasterchainState> masterchain_state, td::actor::ActorId<ValidatorManager> manager,
|
||||
|
@ -64,8 +62,6 @@ class ShardClient : public td::actor::Actor {
|
|||
return 2;
|
||||
}
|
||||
|
||||
void build_shard_overlays();
|
||||
|
||||
void start_up() override;
|
||||
void start_up_init_mode();
|
||||
void download_shard_states(BlockIdExt masterchain_block_id, std::vector<BlockIdExt> shards, size_t idx);
|
||||
|
@ -90,6 +86,8 @@ class ShardClient : public td::actor::Actor {
|
|||
|
||||
void force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise);
|
||||
void force_update_shard_client_ex(BlockHandle handle, td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
|
||||
|
||||
void update_options(td::Ref<ValidatorManagerOptions> opts);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
#include "state-serializer.hpp"
|
||||
#include "td/utils/Random.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "ton/ton-io.hpp"
|
||||
#include "common/delay.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
|
@ -151,6 +150,21 @@ void AsyncStateSerializer::next_iteration() {
|
|||
CHECK(masterchain_handle_->id() == last_block_id_);
|
||||
if (attempt_ < max_attempt() && last_key_block_id_.id.seqno < last_block_id_.id.seqno &&
|
||||
need_serialize(masterchain_handle_)) {
|
||||
if (!stored_persistent_state_description_) {
|
||||
LOG(INFO) << "storing persistent state description for " << masterchain_handle_->id().id;
|
||||
running_ = true;
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler,
|
||||
R.move_as_error_prefix("failed to get masterchain state: "));
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AsyncStateSerializer::store_persistent_state_description,
|
||||
td::Ref<MasterchainState>(R.move_as_ok()));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, masterchain_handle_, std::move(P));
|
||||
return;
|
||||
}
|
||||
if (!have_masterchain_state_ && !opts_->get_state_serializer_enabled()) {
|
||||
LOG(ERROR) << "skipping serializing persistent state for " << masterchain_handle_->id().id.to_str()
|
||||
<< ": serializer is disabled (by user)";
|
||||
|
@ -174,14 +188,10 @@ void AsyncStateSerializer::next_iteration() {
|
|||
td::Timestamp::in(delay));
|
||||
return;
|
||||
}
|
||||
while (next_idx_ < shards_.size()) {
|
||||
if (!need_monitor(shards_[next_idx_].shard_full())) {
|
||||
next_idx_++;
|
||||
} else {
|
||||
running_ = true;
|
||||
request_shard_state(shards_[next_idx_]);
|
||||
return;
|
||||
}
|
||||
if (next_idx_ < shards_.size()) {
|
||||
running_ = true;
|
||||
request_shard_state(shards_[next_idx_]);
|
||||
return;
|
||||
}
|
||||
LOG(ERROR) << "finished serializing persistent state for " << masterchain_handle_->id().id.to_str();
|
||||
}
|
||||
|
@ -203,6 +213,7 @@ void AsyncStateSerializer::next_iteration() {
|
|||
if (masterchain_handle_->inited_next_left()) {
|
||||
last_block_id_ = masterchain_handle_->one_next(true);
|
||||
have_masterchain_state_ = false;
|
||||
stored_persistent_state_description_ = false;
|
||||
masterchain_handle_ = nullptr;
|
||||
saved_to_db_ = false;
|
||||
shards_.clear();
|
||||
|
@ -217,6 +228,24 @@ void AsyncStateSerializer::got_top_masterchain_handle(BlockIdExt block_id) {
|
|||
}
|
||||
}
|
||||
|
||||
void AsyncStateSerializer::store_persistent_state_description(td::Ref<MasterchainState> state) {
|
||||
stored_persistent_state_description_ = true;
|
||||
attempt_ = 0;
|
||||
running_ = false;
|
||||
|
||||
PersistentStateDescription desc;
|
||||
desc.masterchain_id = state->get_block_id();
|
||||
desc.start_time = state->get_unix_time();
|
||||
desc.end_time = ValidatorManager::persistent_state_ttl(desc.start_time);
|
||||
for (const auto &v : state->get_shards()) {
|
||||
desc.shard_blocks.push_back(v->top_block_id());
|
||||
}
|
||||
td::actor::send_closure(manager_, &ValidatorManager::add_persistent_state_description,
|
||||
td::Ref<PersistentStateDescription>(true, std::move(desc)));
|
||||
|
||||
next_iteration();
|
||||
}
|
||||
|
||||
void AsyncStateSerializer::got_masterchain_handle(BlockHandle handle) {
|
||||
CHECK(!masterchain_handle_);
|
||||
masterchain_handle_ = std::move(handle);
|
||||
|
@ -318,8 +347,10 @@ void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state
|
|||
CHECK(shards_.size() == 0);
|
||||
|
||||
auto vec = state->get_shards();
|
||||
for (auto& v : vec) {
|
||||
shards_.push_back(v->top_block_id());
|
||||
for (auto &v : vec) {
|
||||
if (opts_->need_monitor(v->shard(), state)) {
|
||||
shards_.push_back(v->top_block_id());
|
||||
}
|
||||
}
|
||||
|
||||
auto write_data = [shard = state->get_shard(), root = state->root_cell(), cell_db_reader,
|
||||
|
@ -447,11 +478,6 @@ void AsyncStateSerializer::auto_disable_serializer(bool disabled) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool AsyncStateSerializer::need_monitor(ShardIdFull shard) {
|
||||
return opts_->need_monitor(shard);
|
||||
}
|
||||
|
||||
bool AsyncStateSerializer::need_serialize(BlockHandle handle) {
|
||||
if (handle->id().id.seqno == 0 || !handle->is_key_block()) {
|
||||
return false;
|
||||
|
|
|
@ -46,6 +46,7 @@ class AsyncStateSerializer : public td::actor::Actor {
|
|||
td::uint32 next_idx_ = 0;
|
||||
|
||||
BlockHandle masterchain_handle_;
|
||||
bool stored_persistent_state_description_ = false;
|
||||
bool have_masterchain_state_ = false;
|
||||
|
||||
std::vector<BlockIdExt> shards_;
|
||||
|
@ -69,7 +70,6 @@ class AsyncStateSerializer : public td::actor::Actor {
|
|||
}
|
||||
|
||||
bool need_serialize(BlockHandle handle);
|
||||
bool need_monitor(ShardIdFull shard);
|
||||
bool have_newer_persistent_state(UnixTime cur_ts);
|
||||
|
||||
void alarm() override;
|
||||
|
@ -84,6 +84,7 @@ class AsyncStateSerializer : public td::actor::Actor {
|
|||
|
||||
void next_iteration();
|
||||
void got_top_masterchain_handle(BlockIdExt block_id);
|
||||
void store_persistent_state_description(td::Ref<MasterchainState> state);
|
||||
void got_masterchain_handle(BlockHandle handle_);
|
||||
void got_masterchain_state(td::Ref<MasterchainState> state, std::shared_ptr<vm::CellDbReader> cell_db_reader);
|
||||
void stored_masterchain_state();
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace validator {
|
|||
|
||||
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
|
||||
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard, bool allow_blockchain_init,
|
||||
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
|
||||
double sync_blocks_before, double block_ttl, double state_ttl, double max_mempool_num,
|
||||
double archive_ttl, double key_proof_ttl, bool initial_sync_disabled) {
|
||||
return td::make_ref<ValidatorManagerOptionsImpl>(zero_block_id, init_block_id, std::move(check_shard),
|
||||
|
|
|
@ -32,11 +32,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
BlockIdExt init_block_id() const override {
|
||||
return init_block_id_;
|
||||
}
|
||||
bool need_monitor(ShardIdFull shard) const override {
|
||||
return check_shard_(shard, 0, ShardCheckMode::m_monitor);
|
||||
}
|
||||
bool need_validate(ShardIdFull shard, CatchainSeqno cc_seqno) const override {
|
||||
return check_shard_(shard, cc_seqno, ShardCheckMode::m_validate);
|
||||
bool need_monitor(ShardIdFull shard, const td::Ref<MasterchainState>& state) const override {
|
||||
td::uint32 min_split = state->monitor_min_split_depth(shard.workchain);
|
||||
return check_shard_((td::uint32)shard.pfx_len() <= min_split ? shard : shard_prefix(shard, min_split));
|
||||
}
|
||||
bool allow_blockchain_init() const override {
|
||||
return allow_blockchain_init_;
|
||||
|
@ -163,7 +161,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
void set_init_block_id(BlockIdExt block_id) override {
|
||||
init_block_id_ = block_id;
|
||||
}
|
||||
void set_shard_check_function(std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard) override {
|
||||
void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) override {
|
||||
check_shard_ = std::move(check_shard);
|
||||
}
|
||||
void set_allow_blockchain_init(bool value) override {
|
||||
|
@ -257,11 +255,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
}
|
||||
|
||||
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard,
|
||||
bool allow_blockchain_init, double sync_blocks_before,
|
||||
double block_ttl, double state_ttl, double max_mempool_num,
|
||||
double archive_ttl, double key_proof_ttl,
|
||||
bool initial_sync_disabled)
|
||||
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
|
||||
double sync_blocks_before, double block_ttl, double state_ttl, double max_mempool_num,
|
||||
double archive_ttl, double key_proof_ttl, bool initial_sync_disabled)
|
||||
: zero_block_id_(zero_block_id)
|
||||
, init_block_id_(init_block_id)
|
||||
, check_shard_(std::move(check_shard))
|
||||
|
@ -278,7 +274,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
private:
|
||||
BlockIdExt zero_block_id_;
|
||||
BlockIdExt init_block_id_;
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard_;
|
||||
std::function<bool(ShardIdFull)> check_shard_;
|
||||
bool allow_blockchain_init_;
|
||||
double sync_blocks_before_;
|
||||
double block_ttl_;
|
||||
|
|
|
@ -77,8 +77,7 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
|
||||
virtual BlockIdExt zero_block_id() const = 0;
|
||||
virtual BlockIdExt init_block_id() const = 0;
|
||||
virtual bool need_monitor(ShardIdFull shard) const = 0;
|
||||
virtual bool need_validate(ShardIdFull shard, CatchainSeqno cc_seqno) const = 0;
|
||||
virtual bool need_monitor(ShardIdFull shard, const td::Ref<MasterchainState>& state) const = 0;
|
||||
virtual bool allow_blockchain_init() const = 0;
|
||||
virtual double sync_blocks_before() const = 0;
|
||||
virtual double block_ttl() const = 0;
|
||||
|
@ -118,8 +117,7 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
|
||||
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
|
||||
virtual void set_init_block_id(BlockIdExt block_id) = 0;
|
||||
virtual void set_shard_check_function(
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard) = 0;
|
||||
virtual void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) = 0;
|
||||
virtual void set_allow_blockchain_init(bool value) = 0;
|
||||
virtual void set_sync_blocks_before(double value) = 0;
|
||||
virtual void set_block_ttl(double value) = 0;
|
||||
|
@ -151,12 +149,11 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
|
||||
static td::Ref<ValidatorManagerOptions> create(
|
||||
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard = [](ShardIdFull, CatchainSeqno,
|
||||
ShardCheckMode) { return true; },
|
||||
|
||||
std::function<bool(ShardIdFull)> check_shard = [](ShardIdFull) { return true; },
|
||||
bool allow_blockchain_init = false, double sync_blocks_before = 3600, double block_ttl = 86400,
|
||||
double state_ttl = 86400, double archive_ttl = 86400 * 7, double key_proof_ttl = 86400 * 3650,
|
||||
double max_mempool_num = 999999,
|
||||
bool initial_sync_disabled = false);
|
||||
double max_mempool_num = 999999, bool initial_sync_disabled = false);
|
||||
};
|
||||
|
||||
class ValidatorManagerInterface : public td::actor::Actor {
|
||||
|
@ -166,8 +163,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual ~Callback() = default;
|
||||
|
||||
virtual void initial_read_complete(BlockHandle top_masterchain_blocks) = 0;
|
||||
virtual void add_shard(ShardIdFull shard) = 0;
|
||||
virtual void del_shard(ShardIdFull shard) = 0;
|
||||
virtual void on_new_masterchain_block(td::Ref<ton::validator::MasterchainState> state,
|
||||
std::set<ShardIdFull> shards_to_monitor) = 0;
|
||||
|
||||
virtual void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
|
||||
virtual void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
|
||||
|
@ -187,8 +184,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
|
||||
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||
virtual void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
|
||||
td::Promise<std::string> promise) = 0;
|
||||
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||
|
||||
virtual void new_key_block(BlockHandle handle) = 0;
|
||||
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
||||
|
@ -272,7 +269,13 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual void get_block_by_seqno_from_db(AccountIdPrefixFull account, BlockSeqno seqno,
|
||||
td::Promise<ConstBlockHandle> promise) = 0;
|
||||
|
||||
virtual void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) = 0;
|
||||
virtual void wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
virtual void wait_block_state_short(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
|
||||
td::Promise<td::Ref<ShardState>> promise) = 0;
|
||||
|
||||
virtual void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
|
||||
td::Promise<td::uint64> promise) = 0;
|
||||
virtual void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue