1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

changed validate broadcast logic, added new queries to

validator-engine-console
This commit is contained in:
ton 2019-09-11 16:50:29 +04:00
parent 47814dca3d
commit d8244eff53
24 changed files with 695 additions and 84 deletions

View file

@ -87,6 +87,11 @@ target_include_directories(adnl-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_S
target_link_libraries(adnl-proxy PUBLIC tdactor ton_crypto tl_api tdnet common
tl-utils)
add_executable(adnl-pong adnl-pong.cpp)
target_include_directories(adnl-pong PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnl-pong PUBLIC tdactor ton_crypto tl_api tdnet common
tl-utils adnl dht)
add_library(adnltest STATIC ${ADNL_TEST_SOURCE})
target_include_directories(adnltest PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnltest PUBLIC adnl )

View file

@ -283,11 +283,19 @@ void AdnlPeerTableImpl::start_up() {
void AdnlPeerTableImpl::write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
td::Promise<td::Unit> promise) {
if (db_.empty()) {
promise.set_value(td::Unit());
return;
}
td::actor::send_closure(db_, &AdnlDb::update, local_id, peer_id, std::move(node), std::move(promise));
}
void AdnlPeerTableImpl::get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
td::Promise<AdnlDbItem> promise) {
if (db_.empty()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "db not inited"));
return;
}
td::actor::send_closure(db_, &AdnlDb::get, local_id, peer_id, std::move(promise));
}
@ -295,7 +303,9 @@ AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<key
keyring_ = keyring;
static_nodes_manager_ = AdnlStaticNodesManager::create();
if (!db_root.empty()) {
db_ = AdnlDb::create(db_root + "/adnl");
}
}
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {

195
adnl/adnl-pong.cpp Normal file
View file

@ -0,0 +1,195 @@
/*
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.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/actor/actor.h"
#include "td/utils/buffer.h"
#include "td/utils/port/IPAddress.h"
#include "td/net/UdpServer.h"
#include "td/utils/port/signals.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/FileLog.h"
#include "td/utils/port/path.h"
#include "td/utils/port/user.h"
#include "td/utils/filesystem.h"
#include "common/checksum.h"
#include "common/errorcode.h"
#include "tl-utils/tl-utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "adnl/adnl.h"
#include <map>
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
namespace ton {
namespace adnl {
class Callback : public adnl::Adnl::Callback {
public:
void receive_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {
}
void receive_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
TRY_RESULT_PROMISE_PREFIX(promise, f, fetch_tl_object<ton_api::adnl_ping>(std::move(data), true),
"adnl.ping expected");
promise.set_value(create_serialize_tl_object<ton_api::adnl_pong>(f->value_));
}
Callback() {
}
private:
};
} // namespace adnl
} // namespace ton
std::atomic<bool> rotate_logs_flags{false};
void force_rotate_logs(int sig) {
rotate_logs_flags.store(true);
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
ton::PrivateKey pk;
td::IPAddress addr;
td::set_default_failure_signal_handler().ensure();
std::unique_ptr<td::LogInterface> logger_;
SCOPE_EXIT {
td::log_interface = td::default_log_interface;
};
std::string config = "/var/ton-work/etc/adnl-proxy.conf.json";
td::OptionsParser p;
p.set_description("adnl pinger");
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);
return td::Status::OK();
});
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
td::set_signal_handler(td::SignalType::HangUp, force_rotate_logs).ensure();
return td::Status::OK();
});
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto F = std::make_unique<td::FileLog>();
TRY_STATUS(F->init(fname.str(), std::numeric_limits<td::uint64>::max(), true));
logger_ = std::move(F);
td::log_interface = logger_.get();
return td::Status::OK();
});
td::uint32 threads = 7;
p.add_option('t', "threads", PSTRING() << "number of threads (default=" << threads << ")", [&](td::Slice fname) {
td::int32 v;
try {
v = std::stoi(fname.str());
} catch (...) {
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: not a number");
}
if (v < 1 || v > 256) {
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: should be in range [1..256]");
}
threads = v;
return td::Status::OK();
});
p.add_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user); });
p.add_option('k', "key", "private key", [&](td::Slice key) {
TRY_RESULT_ASSIGN(pk, ton::PrivateKey::import(key));
return td::Status::OK();
});
p.add_option('a', "addr", "ip:port of instance", [&](td::Slice key) {
TRY_STATUS(addr.init_host_port(key.str()));
return td::Status::OK();
});
p.run(argc, argv).ensure();
if (pk.empty()) {
LOG(FATAL) << "no --key given";
}
if (!addr.is_valid()) {
LOG(FATAL) << "no --addr given";
}
td::actor::Scheduler scheduler({threads});
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
td::actor::ActorOwn<ton::adnl::AdnlNetworkManager> network_manager;
auto pub = pk.compute_public_key();
scheduler.run_in_context([&]() {
keyring = ton::keyring::Keyring::create("");
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
adnl = ton::adnl::Adnl::create("", keyring.get());
network_manager = ton::adnl::AdnlNetworkManager::create(static_cast<td::uint16>(addr.get_port()));
td::actor::send_closure(network_manager, &ton::adnl::AdnlNetworkManager::add_self_addr, addr, 0);
auto tladdr = ton::create_tl_object<ton::ton_api::adnl_address_udp>(addr.get_ipv4(), addr.get_port());
auto addr_vec = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
addr_vec.push_back(std::move(tladdr));
auto tladdrlist = ton::create_tl_object<ton::ton_api::adnl_addressList>(
std::move(addr_vec), ton::adnl::Adnl::adnl_start_time(), ton::adnl::Adnl::adnl_start_time(), 0, 2000000000);
auto addrlist = ton::adnl::AdnlAddressList::create(tladdrlist).move_as_ok();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, std::move(addrlist));
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, ton::adnl::AdnlNodeIdShort{pub.compute_short_id()},
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::adnl_ping::ID),
std::make_unique<ton::adnl::Callback>());
});
while (scheduler.run(1)) {
if (rotate_logs_flags.exchange(false)) {
if (td::log_interface) {
td::log_interface->rotate();
}
}
}
}

View file

@ -67,7 +67,7 @@ td::Result<std::unique_ptr<Config>> Config::extract_from_key_block(Ref<vm::Cell>
tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra) && mc_extra.key_block && mc_extra.config.not_null())) {
return td::Status::Error(-400, "cannot unpack extra header of key block to extract configuration");
}
return block::Config::unpack_config(std::move(mc_extra.config));
return block::Config::unpack_config(std::move(mc_extra.config), mode);
}
td::Result<std::unique_ptr<Config>> Config::extract_from_state(Ref<vm::Cell> mc_state_root, int mode) {
@ -1482,6 +1482,7 @@ std::vector<ton::ValidatorDescr> Config::compute_validator_set(ton::ShardIdFull
std::vector<ton::ValidatorDescr> Config::compute_validator_set(ton::ShardIdFull shard, ton::UnixTime time,
ton::CatchainSeqno cc_seqno) const {
if (!cur_validators_) {
LOG(DEBUG) << "failed to compute validator set: cur_validators_ is empty";
return {};
} else {
return compute_validator_set(shard, *cur_validators_, time, cc_seqno);

View file

@ -498,6 +498,14 @@ engine.adnlProxy.config ports:(vector engine.adnlProxy.port) = engine.adnlProxy.
---types---
adnl.pong value:long = adnl.Pong;
---functions---
adnl.ping value:long = adnl.Pong;
---types---
engine.validator.keyHash key_hash:int256 = engine.validator.KeyHash;
engine.validator.signature signature:bytes = engine.validator.Signature;
@ -513,6 +521,9 @@ engine.validator.jsonConfig data:string = engine.validator.JsonConfig;
engine.validator.electionBid election_date:int perm_key:int256 adnl_addr:int256 to_send_payload:bytes = engine.validator.ElectionBid;
engine.validator.dhtServerStatus id:int256 status:int = engine.validator.DhtServerStatus;
engine.validator.dhtServersStatus servers:(vector engine.validator.dhtServerStatus) = engine.validator.DhtServersStatus;
---functions---
engine.validator.getTime = engine.validator.Time;
@ -550,4 +561,6 @@ engine.validator.setVerbosity verbosity:int = engine.validator.Success;
engine.validator.createElectionBid election_date:int election_addr:string wallet:string = engine.validator.ElectionBid;
engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus;
engine.validator.controlQuery data:bytes = Object;

Binary file not shown.

View file

@ -655,3 +655,23 @@ td::Status CreateElectionBidQuery::receive(td::BufferSlice data) {
TRY_STATUS(td::write_file(fname_, f->to_send_payload_.as_slice()));
return td::Status::OK();
}
td::Status CheckDhtServersQuery::run() {
TRY_RESULT_ASSIGN(id_, tokenizer_.get_token<ton::PublicKeyHash>());
return td::Status::OK();
}
td::Status CheckDhtServersQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_checkDhtServers>(id_.tl());
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status CheckDhtServersQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_dhtServersStatus>(data.as_slice(), true),
"received incorrect answer: ");
for (auto &s : f->servers_) {
td::TerminalIO::out() << "id=" << s->id_ << " status=" << (s->status_ ? "SUCCESS" : "FAIL") << "\n";
}
return td::Status::OK();
}

View file

@ -821,3 +821,24 @@ class CreateElectionBidQuery : public Query {
std::string fname_;
};
class CheckDhtServersQuery : public Query {
public:
CheckDhtServersQuery(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 "checkdht";
}
static std::string get_help() {
return "checkdht <adnlid>\tchecks, which root DHT servers are accessible from this ADNL addr";
}
std::string name() const override {
return get_name();
}
private:
ton::PublicKeyHash id_;
};

View file

@ -130,6 +130,7 @@ void ValidatorEngineConsole::run() {
add_query_runner(std::make_unique<QueryRunnerImpl<AddNetworkAddressQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<AddNetworkProxyAddressQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CreateElectionBidQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CheckDhtServersQuery>>());
}
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {

View file

@ -50,6 +50,8 @@
#include "memprof/memprof.h"
#include "dht/dht.hpp"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
@ -749,6 +751,65 @@ class ValidatorElectionBidCreator : public td::actor::Actor {
td::BufferSlice result_;
};
class CheckDhtServerStatusQuery : public td::actor::Actor {
public:
void start_up() override {
auto &n = dht_config_->nodes();
result_.resize(n.size(), false);
pending_ = n.size();
for (td::uint32 i = 0; i < n.size(); i++) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), idx = i](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &CheckDhtServerStatusQuery::got_result, idx, R.is_ok());
});
auto &E = n.list().at(i);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_peer, local_id_, E.adnl_id(), E.addr_list());
td::actor::send_closure(adnl_, &ton::adnl::Adnl::send_query, local_id_, E.adnl_id().compute_short_id(), "ping",
std::move(P), td::Timestamp::in(1.0),
ton::create_serialize_tl_object<ton::ton_api::dht_getSignedAddressList>());
}
}
void got_result(td::uint32 idx, bool result) {
result_[idx] = result;
CHECK(pending_ > 0);
if (!--pending_) {
finish_query();
}
}
void finish_query() {
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_dhtServerStatus>> vec;
auto &n = dht_config_->nodes();
for (td::uint32 i = 0; i < n.size(); i++) {
auto &E = n.list().at(i);
vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator_dhtServerStatus>(
E.adnl_id().compute_short_id().bits256_value(), result_[i] ? 1 : 0));
}
promise_.set_value(
ton::create_serialize_tl_object<ton::ton_api::engine_validator_dhtServersStatus>(std::move(vec)));
stop();
}
CheckDhtServerStatusQuery(std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config, ton::adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::Promise<td::BufferSlice> promise)
: dht_config_(std::move(dht_config)), local_id_(local_id), adnl_(adnl), promise_(std::move(promise)) {
}
private:
std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config_;
std::vector<bool> result_;
td::uint32 pending_;
ton::adnl::AdnlNodeIdShort local_id_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::Promise<td::BufferSlice> promise_;
};
void ValidatorEngine::set_local_config(std::string str) {
local_config_ = str;
}
@ -2535,6 +2596,31 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_createEle
.release();
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_checkDhtServers &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_default)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (keyring_.empty()) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "keyring not started")));
return;
}
if (!dht_config_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no dht config")));
return;
}
if (config_.adnl_ids.count(ton::PublicKeyHash{query.id_}) == 0) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "no dht config")));
return;
}
td::actor::create_actor<CheckDhtServerStatusQuery>("pinger", dht_config_, ton::adnl::AdnlNodeIdShort{query.id_},
adnl_.get(), std::move(promise))
.release();
}
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {

View file

@ -347,6 +347,8 @@ class ValidatorEngine : public td::actor::Actor {
td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_createElectionBid &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_checkDhtServers &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
template <class T>
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {

View file

@ -9,6 +9,7 @@ set(TON_VALIDATOR_SOURCE
block.cpp
check-proof.cpp
collator.cpp
config.cpp
external-message.cpp
fabric.cpp
ihr-message.cpp
@ -27,6 +28,7 @@ set(TON_VALIDATOR_SOURCE
collate-query-impl.h
collator-impl.h
collator.h
config.hpp
external-message.hpp
ihr-message.hpp
liteserver.hpp

58
validator/impl/config.cpp Normal file
View file

@ -0,0 +1,58 @@
/*
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-2019 Telegram Systems LLP
*/
#include "config.hpp"
#include "block/block-parse.h"
#include "block/block-auto.h"
#include "vm/boc.h"
#include "vm/cells/MerkleProof.h"
#include "validator-set.hpp"
namespace ton {
namespace validator {
td::Ref<ValidatorSet> ConfigHolderQ::get_total_validator_set(int next) const {
if (!config_) {
LOG(ERROR) << "MasterchainStateQ::get_total_validator_set() : no config";
return {};
}
auto nodes = config_->compute_total_validator_set(next);
if (nodes.empty()) {
return {};
}
return Ref<ValidatorSetQ>{true, 0, ton::ShardIdFull{}, std::move(nodes)};
}
td::Ref<ValidatorSet> ConfigHolderQ::get_validator_set(ShardIdFull shard, UnixTime utime,
CatchainSeqno cc_seqno) const {
if (!config_) {
LOG(ERROR) << "MasterchainStateQ::get_validator_set() : no config";
return {};
}
auto nodes = config_->compute_validator_set(shard, utime, cc_seqno);
if (nodes.empty()) {
return {};
}
return Ref<ValidatorSetQ>{true, cc_seqno, shard, std::move(nodes)};
}
} // namespace validator
} // namespace ton

50
validator/impl/config.hpp Normal file
View file

@ -0,0 +1,50 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "validator/interfaces/config.h"
namespace ton {
namespace validator {
using td::Ref;
class ConfigHolderQ : public ConfigHolder {
std::shared_ptr<block::Config> config_;
std::shared_ptr<vm::StaticBagOfCellsDb> boc_;
public:
ConfigHolderQ() = default;
ConfigHolderQ(std::shared_ptr<block::Config> config, std::shared_ptr<vm::StaticBagOfCellsDb> boc)
: config_(std::move(config)), boc_(std::move(boc)) {
}
ConfigHolderQ(std::shared_ptr<block::Config> config) : config_(std::move(config)) {
}
const block::Config *get_config() const {
return config_.get();
}
ConfigHolderQ *make_copy() const override {
return new ConfigHolderQ(*this);
}
// if necessary, add more public methods providing interface to config_->...()
td::Ref<ValidatorSet> get_total_validator_set(int next) const override; // next = -1 -> prev, next = 0 -> cur
td::Ref<ValidatorSet> get_validator_set(ShardIdFull shard, UnixTime utime, CatchainSeqno seqno) const override;
};
} // namespace validator
} // namespace ton

View file

@ -43,10 +43,10 @@ td::Result<Ref<ProofLink>> ProofQ::export_as_proof_link() const {
}
td::Result<BlockSeqno> ProofLinkQ::prev_key_mc_seqno() const {
if (!id_.is_masterchain()) {
return td::Status::Error(
-668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
}
//if (!id_.is_masterchain()) {
// return td::Status::Error(
// -668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
//}
TRY_RESULT(pair, get_virtual_root(true));
try {
block::gen::Block::Record blk;
@ -68,8 +68,7 @@ td::Result<td::Ref<ConfigHolder>> ProofLinkQ::get_key_block_config() const {
}
TRY_RESULT(pair, get_virtual_root(true));
try {
TRY_RESULT(cfg, block::Config::extract_from_key_block(
std::move(pair.first), block::Config::needValidatorSet | block::Config::needWorkchainInfo));
TRY_RESULT(cfg, block::Config::extract_from_key_block(std::move(pair.first), block::Config::needValidatorSet));
return td::make_ref<ConfigHolderQ>(std::move(cfg), std::move(pair.second));
} catch (vm::VmVirtError &) {
return td::Status::Error(-668,
@ -77,6 +76,26 @@ td::Result<td::Ref<ConfigHolder>> ProofLinkQ::get_key_block_config() const {
}
}
td::Result<ProofLink::BasicHeaderInfo> ProofLinkQ::get_basic_header_info() const {
BasicHeaderInfo res;
TRY_RESULT(pair, get_virtual_root(true));
try {
block::gen::Block::Record blk;
block::gen::BlockInfo::Record info;
if (!(tlb::unpack_cell(std::move(pair.first), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
return td::Status::Error(-668,
"cannot unpack block header in the Merkle proof for masterchain block "s + id_.to_str());
}
res.cc_seqno = info.gen_catchain_seqno;
res.utime = info.gen_utime;
res.validator_set_hash = info.gen_validator_list_hash_short;
res.prev_key_mc_seqno = info.prev_key_block_seqno;
return res;
} catch (vm::VmVirtError &) {
return td::Status::Error(-668, "virtualization error in masterchain block proof for "s + id_.to_str());
}
}
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> ProofLinkQ::get_virtual_root(
bool lazy) const {
if (data_.empty()) {
@ -127,17 +146,5 @@ td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> Pr
return std::make_pair(std::move(virt_root), std::move(boc));
}
td::Ref<ValidatorSet> ConfigHolderQ::get_total_validator_set(int next) const {
if (!config_) {
LOG(ERROR) << "MasterchainStateQ::get_total_validator_set() : no config";
return {};
}
auto nodes = config_->compute_total_validator_set(next);
if (nodes.empty()) {
return {};
}
return Ref<ValidatorSetQ>{true, 0, ton::ShardIdFull{}, std::move(nodes)};
}
} // namespace validator
} // namespace ton

View file

@ -22,32 +22,12 @@
#include "block/block-db.h"
#include "block/mc-config.h"
#include "vm/db/StaticBagOfCellsDb.h"
#include "config.hpp"
namespace ton {
namespace validator {
using td::Ref;
class ConfigHolderQ : public ConfigHolder {
std::shared_ptr<block::Config> config_;
std::shared_ptr<vm::StaticBagOfCellsDb> boc_;
public:
ConfigHolderQ() = default;
ConfigHolderQ(std::shared_ptr<block::Config> config, std::shared_ptr<vm::StaticBagOfCellsDb> boc)
: config_(std::move(config)), boc_(std::move(boc)) {
}
ConfigHolderQ(std::shared_ptr<block::Config> config) : config_(std::move(config)) {
}
const block::Config *get_config() const {
return config_.get();
}
ConfigHolderQ *make_copy() const override {
return new ConfigHolderQ(*this);
}
// if necessary, add more public methods providing interface to config_->...()
td::Ref<ValidatorSet> get_total_validator_set(int next) const override; // next = -1 -> prev, next = 0 -> cur
};
class ProofLinkQ : virtual public ProofLink {
protected:
BlockIdExt id_;
@ -67,6 +47,7 @@ class ProofLinkQ : virtual public ProofLink {
}
td::Result<BlockSeqno> prev_key_mc_seqno() const override;
td::Result<td::Ref<ConfigHolder>> get_key_block_config() const override;
td::Result<BasicHeaderInfo> get_basic_header_info() const override;
protected:
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> get_virtual_root(

View file

@ -20,6 +20,7 @@
#include "interfaces/shard.h"
#include "vm/db/StaticBagOfCellsDb.h"
#include "block/mc-config.h"
#include "config.hpp"
namespace ton {
@ -138,6 +139,13 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
std::shared_ptr<block::ConfigInfo> get_config() const {
return config_;
}
td::Result<td::Ref<ConfigHolder>> get_key_block_config() const override {
if (!config_) {
return td::Status::Error(ErrorCode::notready, "config not found");
} else {
return td::make_ref<ConfigHolderQ>(config_);
}
}
private:
ZeroStateIdExt zerostate_id_;

View file

@ -665,9 +665,7 @@ bool ValidateQuery::try_unpack_mc_state() {
}
config_ = res.move_as_ok();
CHECK(config_);
if (mc_seqno_) {
config_->set_block_id_ext(mc_blkid_);
}
old_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
if (!is_masterchain()) {
new_shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
@ -684,6 +682,11 @@ bool ValidateQuery::try_unpack_mc_state() {
} else {
prev_key_block_seqno_ = 0;
}
if (prev_key_seqno_ != prev_key_block_seqno_) {
return reject_query(PSTRING() << "previous key block seqno value in candidate block header is " << prev_key_seqno_
<< " while the correct value corresponding to reference masterchain state "
<< mc_blkid_.to_str() << " is " << prev_key_block_seqno_);
}
auto limits = config_->get_block_limits(is_masterchain());
if (limits.is_error()) {
return fatal_error(limits.move_as_error());
@ -5002,7 +5005,7 @@ bool ValidateQuery::check_mc_state_extra() {
} else if (!new_extra.r1.last_key_block->prefetch_ulong(1)) {
return reject_query("last_key_block:(Maybe ExtBlkRef) changed in the new state, but it became a nothing$0");
} else {
auto& cs = new_extra.r1.last_key_block.write();
vm::CellSlice cs = *new_extra.r1.last_key_block;
BlockIdExt blkid;
LogicalTime lt;
CHECK(cs.fetch_ulong(1) == 1 && block::tlb::t_ExtBlkRef.unpack(cs, blkid, &lt));
@ -5017,6 +5020,20 @@ bool ValidateQuery::check_mc_state_extra() {
", but it is not a key block");
}
}
if (new_extra.r1.last_key_block->prefetch_ulong(1)) {
auto& cs = new_extra.r1.last_key_block.write();
BlockIdExt blkid;
LogicalTime lt;
CHECK(cs.fetch_ulong(1) == 1 && block::tlb::t_ExtBlkRef.unpack(cs, blkid, &lt));
if (blkid != prev_key_block_) {
return reject_query("new masterchain state declares previous key block to be "s + blkid.to_str() +
" but the value computed from previous masterchain state is " + prev_key_block_.to_str());
}
} else if (prev_key_block_seqno_ > 0) {
return reject_query(PSTRING() << "new masterchain state declares no previous key block, but the block header "
"announces previous key block seqno "
<< prev_key_block_seqno_);
}
// global_balance:CurrencyCollection
block::CurrencyCollection global_balance, old_global_balance;
if (!global_balance.validate_unpack(new_extra.global_balance)) {

View file

@ -34,6 +34,7 @@ class ConfigHolder : public td::CntObject {
virtual ~ConfigHolder() = default;
virtual td::Ref<ValidatorSet> get_total_validator_set(int next) const = 0; // next = -1 -> prev, next = 0 -> cur
virtual td::Ref<ValidatorSet> get_validator_set(ShardIdFull shard, UnixTime utime, CatchainSeqno seqno) const = 0;
};
} // namespace validator

View file

@ -27,11 +27,18 @@ namespace validator {
class ProofLink : public td::CntObject {
public:
struct BasicHeaderInfo {
UnixTime utime;
CatchainSeqno cc_seqno;
td::uint32 validator_set_hash;
BlockSeqno prev_key_mc_seqno;
};
virtual ~ProofLink() = default;
virtual BlockIdExt block_id() const = 0;
virtual td::BufferSlice data() const = 0;
virtual td::Result<BlockSeqno> prev_key_mc_seqno() const = 0;
virtual td::Result<td::Ref<ConfigHolder>> get_key_block_config() const = 0;
virtual td::Result<BasicHeaderInfo> get_basic_header_info() const = 0;
};
class Proof : virtual public ProofLink {

View file

@ -79,6 +79,7 @@ class MasterchainState : virtual public ShardState {
virtual bool get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid,
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_key_block_config() const = 0;
virtual td::Status prepare() {
return td::Status::OK();
}

View file

@ -1908,12 +1908,14 @@ void ValidatorManagerImpl::send_peek_key_block_request() {
}
void ValidatorManagerImpl::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) {
std::vector<std::pair<std::string, std::string>> vec;
vec.emplace_back("unixtime", td::to_string(static_cast<UnixTime>(td::Clocks::system())));
if (!last_masterchain_block_handle_) {
promise.set_value(std::vector<std::pair<std::string, std::string>>());
promise.set_value(std::move(vec));
return;
}
std::vector<std::pair<std::string, std::string>> vec;
vec.emplace_back("masterchainblock", last_masterchain_block_id_.to_str());
vec.emplace_back("masterchainblocktime", td::to_string(last_masterchain_block_handle_->unix_time()));
vec.emplace_back("gcmasterchainblock", gc_masterchain_handle_->id().to_str());
vec.emplace_back("keymasterchainblock", last_key_block_handle_->id().to_str());
vec.emplace_back("knownkeymasterchainblock", last_known_key_block_handle_->id().to_str());

View file

@ -69,33 +69,150 @@ void ValidateBroadcast::start_up() {
return;
}
auto val_set = last_masterchain_state_->get_validator_set(broadcast_.block_id.shard_full());
if (val_set.not_null() && val_set->get_catchain_seqno() == broadcast_.catchain_seqno &&
val_set->get_validator_set_hash() == broadcast_.validator_set_hash) {
if (broadcast_.block_id.is_masterchain()) {
auto R = create_proof(broadcast_.block_id, broadcast_.proof.clone());
if (R.is_error()) {
abort_query(R.move_as_error_prefix("bad proof: "));
return;
}
proof_ = R.move_as_ok();
auto hR = proof_->get_basic_header_info();
if (hR.is_error()) {
abort_query(hR.move_as_error_prefix("bad proof: "));
return;
}
header_info_ = hR.move_as_ok();
} else {
auto R = create_proof_link(broadcast_.block_id, broadcast_.proof.clone());
if (R.is_error()) {
abort_query(R.move_as_error_prefix("bad proof link: "));
return;
}
proof_link_ = R.move_as_ok();
auto hR = proof_link_->get_basic_header_info();
if (hR.is_error()) {
abort_query(hR.move_as_error_prefix("bad proof link: "));
return;
}
header_info_ = hR.move_as_ok();
}
BlockSeqno key_block_seqno = header_info_.prev_key_mc_seqno;
exact_key_block_handle_ = key_block_seqno <= last_known_masterchain_block_handle_->id().seqno();
if (key_block_seqno < last_known_masterchain_block_handle_->id().seqno()) {
if (key_block_seqno < last_masterchain_state_->get_seqno()) {
BlockIdExt block_id;
if (!last_masterchain_state_->get_old_mc_block_id(key_block_seqno, block_id)) {
abort_query(td::Status::Error(ErrorCode::error, "too old reference key block"));
return;
}
got_key_block_id(block_id);
} else if (key_block_seqno == last_masterchain_state_->get_seqno()) {
got_key_block_handle(last_masterchain_block_handle_);
} else {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockIdExt> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
R.move_as_error_prefix("cannot find reference key block id: "));
} else {
td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_id, R.move_as_ok());
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_by_seqno_from_db,
AccountIdPrefixFull{masterchainId, 0}, key_block_seqno, std::move(P));
}
} else {
got_key_block_handle(last_known_masterchain_block_handle_);
}
}
void ValidateBroadcast::got_key_block_id(BlockIdExt block_id) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
R.move_as_error_prefix("cannot find reference key block handle: "));
} else {
td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_handle, R.move_as_ok());
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, block_id, false, std::move(P));
}
void ValidateBroadcast::got_key_block_handle(BlockHandle handle) {
if (handle->id().seqno() == 0) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
R.move_as_error_prefix("failed to get zero state: "));
} else {
td::actor::send_closure(SelfId, &ValidateBroadcast::got_zero_state, td::Ref<MasterchainState>{R.move_as_ok()});
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, handle, std::move(P));
} else {
if (!handle->inited_proof() && !handle->inited_proof_link()) {
abort_query(td::Status::Error(ErrorCode::notready, "reference key block proof not received"));
return;
}
if (!handle->is_key_block()) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "reference key block is not key"));
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ProofLink>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query,
R.move_as_error_prefix("cannot get reference key block proof: "));
} else {
td::actor::send_closure(SelfId, &ValidateBroadcast::got_key_block_proof_link, R.move_as_ok());
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_proof_link_from_db, handle, std::move(P));
}
}
void ValidateBroadcast::got_key_block_proof_link(td::Ref<ProofLink> key_proof_link) {
key_proof_link_ = key_proof_link;
auto confR = key_proof_link->get_key_block_config();
if (confR.is_error()) {
abort_query(confR.move_as_error_prefix("failed to extract config from key proof: "));
return;
}
check_signatures_common(confR.move_as_ok());
}
void ValidateBroadcast::got_zero_state(td::Ref<MasterchainState> state) {
zero_state_ = state;
auto confR = state->get_key_block_config();
if (confR.is_error()) {
abort_query(confR.move_as_error_prefix("failed to extract config from zero state: "));
return;
}
check_signatures_common(confR.move_as_ok());
}
void ValidateBroadcast::check_signatures_common(td::Ref<ConfigHolder> conf) {
auto val_set = conf->get_validator_set(broadcast_.block_id.shard_full(), header_info_.utime, header_info_.cc_seqno);
if (val_set.is_null()) {
abort_query(td::Status::Error(ErrorCode::notready, "failed to compute validator set"));
return;
}
if (val_set->get_validator_set_hash() != header_info_.validator_set_hash) {
if (!exact_key_block_handle_) {
abort_query(td::Status::Error(ErrorCode::notready, "too new block, don't know recent enough key block"));
return;
} else {
abort_query(td::Status::Error(ErrorCode::notready, "bad validator set hash"));
return;
}
}
auto S = val_set->check_signatures(broadcast_.block_id.root_hash, broadcast_.block_id.file_hash, sig_set_);
if (S.is_ok()) {
checked_signatures();
return;
} else {
abort_query(S.move_as_error_prefix("failed signature check: "));
return;
}
}
val_set = last_masterchain_state_->get_next_validator_set(broadcast_.block_id.shard_full());
if (val_set.not_null() && val_set->get_catchain_seqno() == broadcast_.catchain_seqno &&
val_set->get_validator_set_hash() == broadcast_.validator_set_hash) {
auto S = val_set->check_signatures(broadcast_.block_id.root_hash, broadcast_.block_id.file_hash, sig_set_);
if (S.is_ok()) {
checked_signatures();
return;
} else {
abort_query(S.move_as_error_prefix("failed signature check: "));
return;
}
}
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad signature set"));
}
void ValidateBroadcast::checked_signatures() {
@ -142,13 +259,7 @@ void ValidateBroadcast::written_block_data() {
checked_proof();
return;
}
auto proofR = create_proof(broadcast_.block_id, broadcast_.proof.clone());
if (proofR.is_error()) {
abort_query(proofR.move_as_error_prefix("bad proof: "));
return;
}
proof_ = proofR.move_as_ok();
if (handle_->id().id.seqno == last_masterchain_block_handle_->id().id.seqno + 1) {
if (exact_key_block_handle_) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error_prefix("db error: "));
@ -156,7 +267,12 @@ void ValidateBroadcast::written_block_data() {
td::actor::send_closure(SelfId, &ValidateBroadcast::checked_proof);
}
});
run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P));
if (!key_proof_link_.is_null()) {
run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), key_proof_link_);
} else {
CHECK(!zero_state_.not_null());
run_check_proof_query(broadcast_.block_id, proof_, manager_, timeout_, std::move(P), zero_state_);
}
} else {
checked_proof();
}
@ -165,12 +281,6 @@ void ValidateBroadcast::written_block_data() {
checked_proof();
return;
}
auto proofR = create_proof_link(broadcast_.block_id, broadcast_.proof.clone());
if (proofR.is_error()) {
abort_query(proofR.move_as_error());
return;
}
proof_link_ = proofR.move_as_ok();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error_prefix("db error: "));
@ -183,7 +293,10 @@ void ValidateBroadcast::written_block_data() {
}
void ValidateBroadcast::checked_proof() {
if (handle_->inited_proof()) {
if (handle_->inited_proof() && handle_->is_key_block()) {
td::actor::send_closure(manager_, &ValidatorManager::update_last_known_key_block, handle_, false);
}
if (handle_->inited_proof() && handle_->id().seqno() - last_masterchain_block_handle_->id().seqno() <= 16) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ValidateBroadcast::abort_query, R.move_as_error());

View file

@ -31,7 +31,8 @@ class ValidateBroadcast : public td::actor::Actor {
BlockHandle last_masterchain_block_handle_;
td::Ref<MasterchainState> last_masterchain_state_;
BlockHandle last_known_masterchain_block_handle_;
td::Ref<Proof> last_known_masterchain_block_proof_;
ProofLink::BasicHeaderInfo header_info_;
td::actor::ActorId<ValidatorManager> manager_;
td::Timestamp timeout_;
@ -45,6 +46,10 @@ class ValidateBroadcast : public td::actor::Actor {
td::PerfWarningTimer perf_timer_{"validatebroadcast", 0.1};
bool exact_key_block_handle_;
td::Ref<ProofLink> key_proof_link_;
td::Ref<MasterchainState> zero_state_;
public:
ValidateBroadcast(BlockBroadcast broadcast, BlockHandle last_masterchain_block_handle,
td::Ref<MasterchainState> last_masterchain_state, BlockHandle last_known_masterchain_block_handle,
@ -59,6 +64,11 @@ class ValidateBroadcast : public td::actor::Actor {
}
void start_up() override;
void got_key_block_id(BlockIdExt block_id);
void got_key_block_handle(BlockHandle block_handle);
void got_key_block_proof_link(td::Ref<ProofLink> proof_link);
void got_zero_state(td::Ref<MasterchainState> state);
void check_signatures_common(td::Ref<ConfigHolder> conf);
void checked_signatures();
void got_block_handle(BlockHandle handle);
void written_block_data();