1
0
Fork 0
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:
SpyCheese 2024-11-26 15:46:58 +04:00 committed by GitHub
parent 62444100f5
commit 954a96a077
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 3213 additions and 1113 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,6 +26,7 @@
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "ext-client.h"
#include "adnl/adnl-ext-client.h"
#include "tl-utils/tl-utils.hpp"
#include "ton/ton-types.h"
@ -46,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
View 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

View file

@ -0,0 +1,89 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ton/ton-types.h"
#include "auto/tl/lite_api.h"
#include "td/utils/port/IPAddress.h"
#include "adnl/adnl-node-id.hpp"
namespace liteclient {
struct QueryInfo {
enum Type { t_simple, t_seqno, t_utime, t_lt, t_mc_seqno };
int query_id = 0;
ton::ShardIdFull shard_id{ton::masterchainId};
Type type = t_simple;
td::uint64 value = 0;
/* Query types and examples:
* t_simple - query to the recent blocks in a shard, or general info. value = 0.
* getTime, getMasterchainInfo (shard_id = masterchain)
* sendMessage
* getAccountState, runSmcMethod - when no block is given
* t_seqno - query to block with seqno in a shard. value = seqno.
* lookupBlock by seqno
* getBlock, getBlockHeader
* getAccountState, runSmcMethod - when shard block is given
* t_utime - query to a block with given unixtime in a shard. value = utime.
* lookupBlock by utime
* t_lt - query to a block with given lt in a shard. value = lt.
* lookupBlock by lt
* getTransactions
* t_mc_seqno - query to a block in a shard, masterchain seqno is given. value = mc_seqno.
* getAccountState, runSmcMethod - when mc block is given
*/
std::string to_str() const;
};
QueryInfo get_query_info(td::Slice data);
QueryInfo get_query_info(const ton::lite_api::Function& f);
struct LiteServerConfig {
private:
struct ShardInfo {
ton::ShardIdFull shard_id;
ton::BlockSeqno seqno;
ton::UnixTime utime;
ton::LogicalTime lt;
};
struct Slice {
std::vector<ShardInfo> shards_from, shards_to;
bool unlimited = false;
bool accepts_query(const QueryInfo& query_info) const;
};
bool is_full = false;
std::vector<Slice> slices;
public:
ton::adnl::AdnlNodeIdFull adnl_id;
td::IPAddress addr;
LiteServerConfig() = default;
LiteServerConfig(ton::adnl::AdnlNodeIdFull adnl_id, td::IPAddress addr)
: is_full(true), adnl_id(adnl_id), addr(addr) {
}
bool accepts_query(const QueryInfo& query_info) const;
static td::Result<std::vector<LiteServerConfig>> parse_global_config(
const ton::ton_api::liteclient_config_global& config);
};
} // namespace liteclient

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
View 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)) {
}
}

View file

@ -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();
}

View file

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

View file

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

View file

@ -54,6 +54,7 @@
#include "td/utils/Random.h"
#include "auto/tl/lite_api.h"
#include "tl/tl_json.h"
#include "memprof/memprof.h"
@ -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) {

View file

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

View file

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

View file

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

View file

@ -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());
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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()) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
}

View file

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

View file

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

View file

@ -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();
}

View file

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

View file

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

View file

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

View file

@ -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());
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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