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

Add CollatorNode and make validators request blocks from it

This commit is contained in:
SpyCheese 2022-07-20 15:39:50 +03:00
parent 996c23e506
commit 53270a00e6
25 changed files with 577 additions and 33 deletions

View file

@ -53,6 +53,7 @@ set(VALIDATOR_HEADERS
import-db-slice.hpp
collator-node.hpp
manager-disk.h
manager-disk.hpp
manager-init.h
@ -68,6 +69,7 @@ set(VALIDATOR_HEADERS
set(VALIDATOR_SOURCE
apply-block.cpp
block-handle.cpp
collator-node.cpp
get-next-key-blocks.cpp
import-db-slice.cpp
shard-client.cpp

145
validator/collator-node.cpp Normal file
View file

@ -0,0 +1,145 @@
/*
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 "collator-node.hpp"
#include "ton/ton-tl.hpp"
#include "fabric.h"
namespace ton {
namespace validator {
CollatorNode::CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp)
: local_id_(local_id), manager_(std::move(manager)), adnl_(std::move(adnl)), rldp_(std::move(rldp)) {
}
void CollatorNode::start_up() {
class Cb : public adnl::Adnl::Callback {
public:
Cb(td::actor::ActorId<CollatorNode> id) : id_(std::move(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_, &CollatorNode::receive_query, src, std::move(data), std::move(promise));
}
private:
td::actor::ActorId<CollatorNode> id_;
};
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id_,
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID),
std::make_unique<Cb>(actor_id(this)));
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
}
void CollatorNode::tear_down() {
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id_,
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID));
}
void CollatorNode::add_shard(ShardIdFull shard) {
LOG(INFO) << "Collator node: local_id=" << local_id_ << " , shard=" << shard.to_str();
shards_.push_back(shard);
}
static td::BufferSlice serialize_error(td::Status error) {
return create_serialize_tl_object<ton_api::collatorNode_generateBlockError>(error.code(), error.message().c_str());
}
void CollatorNode::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto status = [&]() -> td::Status {
TRY_RESULT(f, fetch_tl_object<ton_api::collatorNode_generateBlock>(std::move(data), true));
ShardIdFull shard(f->workchain_, f->shard_);
if (!shard.is_valid_ext()) {
return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str());
}
bool found = false;
for (ShardIdFull our_shard : shards_) {
if (shard_is_ancestor(shard, our_shard)) {
found = true;
break;
}
}
if (!found) {
return td::Status::Error(PSTRING() << "this node doesn't collate shard " << shard.to_str());
}
if (f->prev_blocks_.size() != 1 && f->prev_blocks_.size() != 2) {
return td::Status::Error(PSTRING() << "invalid size of prev_blocks: " << f->prev_blocks_.size());
}
std::vector<BlockIdExt> prev_blocks;
for (const auto& b : f->prev_blocks_) {
prev_blocks.push_back(create_block_id(b));
}
BlockIdExt min_mc_id = create_block_id(f->min_mc_id_);
Ed25519_PublicKey creator(f->creator_);
LOG(INFO) << "Query from " << src << ": shard=" << shard.to_str() << ", min_mc_id=" << min_mc_id.to_str();
auto P = td::PromiseCreator::lambda([=, SelfId = actor_id(this), prev_blocks = std::move(prev_blocks),
promise = std::move(promise)](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_error()) {
LOG(WARNING) << "Query from " << src << ", error: " << R.error();
promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
} else {
td::Ref<MasterchainState> state(R.move_as_ok());
if (state.is_null()) {
LOG(WARNING) << "Query from " << src << ", error: failed to get masterchain state";
promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
return;
}
td::actor::send_closure(SelfId, &CollatorNode::receive_query_cont, src, shard, std::move(state),
std::move(prev_blocks), creator, std::move(promise));
}
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, min_mc_id, 1, td::Timestamp::in(5.0),
std::move(P));
return td::Status::OK();
}();
if (status.is_error()) {
LOG(WARNING) << "Query from " << src << ", error: " << status;
promise.set_result(serialize_error(std::move(status)));
}
}
void CollatorNode::receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard,
td::Ref<MasterchainState> min_mc_state, std::vector<BlockIdExt> prev_blocks,
Ed25519_PublicKey creator, td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda([promise = std::move(promise), src](td::Result<BlockCandidate> R) mutable {
if (R.is_error()) {
LOG(WARNING) << "Query from " << src << ", error: " << R.error();
promise.set_result(serialize_error(R.move_as_error()));
} else {
LOG(INFO) << "Query from " << src << ", success";
auto block = R.move_as_ok();
auto result = create_serialize_tl_object<ton_api::collatorNode_generateBlockSuccess>(
create_tl_object<ton_api::db_candidate>(PublicKey{pubkeys::Ed25519{block.pubkey.as_bits256()}}.tl(),
create_tl_block_id(block.id), std::move(block.data),
std::move(block.collated_data)));
promise.set_result(std::move(result));
}
});
run_collate_query(shard, min_mc_state->get_block_id(), std::move(prev_blocks), creator,
min_mc_state->get_validator_set(shard), manager_, td::Timestamp::in(10.0), std::move(P));
}
} // namespace validator
} // namespace ton

View file

@ -0,0 +1,51 @@
/*
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 "interfaces/validator-manager.h"
#include "rldp/rldp.h"
namespace ton {
namespace validator {
class ValidatorManager;
class CollatorNode : public td::actor::Actor {
public:
CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp);
void start_up() override;
void tear_down() override;
void add_shard(ShardIdFull shard);
private:
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard, td::Ref<MasterchainState> min_mc_state,
std::vector<BlockIdExt> prev_blocks, Ed25519_PublicKey creator,
td::Promise<td::BufferSlice> promise);
adnl::AdnlNodeIdShort local_id_;
td::actor::ActorId<ValidatorManager> manager_;
td::actor::ActorId<adnl::Adnl> adnl_;
td::actor::ActorId<rldp::Rldp> rldp_;
std::vector<ShardIdFull> shards_;
};
} // namespace validator
} // namespace ton

View file

@ -364,7 +364,8 @@ td::Status MasterchainStateQ::mc_init() {
td::Status MasterchainStateQ::mc_reinit() {
auto res = block::ConfigInfo::extract_config(
root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks);
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks |
block::ConfigInfo::needWorkchainInfo);
cur_validators_.reset();
next_validators_.reset();
if (res.is_error()) {
@ -510,6 +511,27 @@ bool MasterchainStateQ::check_old_mc_block_id(const ton::BlockIdExt& blkid, bool
return config_ && config_->check_old_mc_block_id(blkid, strict);
}
std::vector<CollatorNodeDescr> MasterchainStateQ::get_collator_set() const {
block::gen::CollatorSet::Record rec;
auto cell = config_->get_config_param(81);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return {};
}
vm::Dictionary dict{rec.collators->prefetch_ref(), 32 + 64 + 256};
std::vector<CollatorNodeDescr> collators;
dict.check_for_each([&](Ref<vm::CellSlice>, td::ConstBitPtr key, int n) {
CHECK(n == 32 + 64 + 256);
auto workchain = (td::int32)key.get_int(32);
key.advance(32);
td::uint64 shard = key.get_uint(64);
key.advance(64);
td::Bits256 adnl_id(key);
collators.push_back({ShardIdFull(workchain, shard), adnl_id});
return true;
});
return collators;
}
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
if (!config_) {
return 0;

View file

@ -147,6 +147,10 @@ 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();
}
std::vector<CollatorNodeDescr> get_collator_set() const override;
private:
ZeroStateIdExt zerostate_id_;

View file

@ -448,7 +448,6 @@ bool ValidateQuery::init_parse() {
return reject_query("after_merge value mismatch in block header");
}
rand_seed_ = extra.rand_seed;
created_by_ = extra.created_by;
if (created_by_ != extra.created_by) {
return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
" but the block header contains different value " + extra.created_by.to_hex());

View file

@ -81,6 +81,8 @@ 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 std::vector<CollatorNodeDescr> get_collator_set() const = 0;
virtual td::Status prepare() {
return td::Status::OK();
}

View file

@ -384,6 +384,10 @@ class ValidatorManagerImpl : public ValidatorManager {
UNREACHABLE();
}
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
UNREACHABLE();
}
private:
PublicKeyHash local_id_;

View file

@ -443,6 +443,9 @@ class ValidatorManagerImpl : public ValidatorManager {
UNREACHABLE();
}
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
UNREACHABLE();
}
private:
td::Ref<ValidatorManagerOptions> opts_;

View file

@ -2025,7 +2025,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, opts, keyring_, adnl_, rldp_, overlays_,
"validatorgroup", shard, validator_id, session_id, validator_set, last_masterchain_state_->get_collator_set(),
opts, keyring_, adnl_, rldp_, overlays_,
db_root_, actor_id(this), init_session,
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), true);
return G;
@ -2692,6 +2693,15 @@ void ValidatorManagerImpl::cleanup_old_pending_candidates(BlockId block_id, td::
}
}
void ValidatorManagerImpl::add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) {
auto it = collator_nodes_.find(id);
if (it == collator_nodes_.end()) {
auto actor = td::actor::create_actor<CollatorNode>("collatornode", id, actor_id(this), adnl_, rldp_);
it = collator_nodes_.emplace(id, std::move(actor)).first;
}
td::actor::send_closure(it->second, &CollatorNode::add_shard, shard);
}
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

@ -28,6 +28,7 @@
#include "state-serializer.hpp"
#include "rldp/rldp.h"
#include "token-manager.h"
#include "collator-node.hpp"
#include <map>
#include <set>
@ -539,6 +540,8 @@ class ValidatorManagerImpl : public ValidatorManager {
void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
void wait_block_candidate(BlockId block_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise) override;
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override;
private:
td::Timestamp resend_shard_blocks_at_;
td::Timestamp check_waiters_at_;
@ -606,6 +609,8 @@ class ValidatorManagerImpl : public ValidatorManager {
std::map<BlockId, std::vector<std::pair<td::Promise<BlockCandidate>, td::Timestamp>>> pending_block_candidates_;
void cleanup_old_pending_candidates(BlockId block_id, td::Timestamp now);
std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<CollatorNode>> collator_nodes_;
};
} // namespace validator

View file

@ -248,9 +248,11 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
void ShardClient::build_shard_overlays() {
auto v = masterchain_state_->get_shards();
std::set<WorkchainId> workchains;
for (auto &x : v) {
auto shard = x->shard();
workchains.insert(shard.workchain);
if (opts_->need_monitor(shard)) {
auto d = masterchain_state_->soft_min_split_depth(shard.workchain);
auto l = shard_prefix_length(shard.shard);
@ -264,6 +266,20 @@ void ShardClient::build_shard_overlays() {
}
}
}
for (const auto &wpair : masterchain_state_->get_workchain_list()) {
ton::WorkchainId wc = wpair.first;
const block::WorkchainInfo *winfo = wpair.second.get();
if (workchains.count(wc) == 0 && winfo->active && winfo->enabled_since <= masterchain_state_->get_unix_time()) {
auto shard = ShardIdFull(wc);
if (opts_->need_monitor(shard) && created_overlays_.count(shard) == 0) {
td::actor::send_closure(manager_, &ValidatorManager::subscribe_to_shard, shard);
BlockIdExt block_id(shard.workchain, shard.shard, 0, winfo->zerostate_root_hash, winfo->zerostate_file_hash);
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, block_id, 0,
td::Timestamp::in(5.0), [](td::Result<td::Ref<ShardState>>) {});
}
}
}
}
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {

View file

@ -22,6 +22,7 @@
#include "td/utils/overloaded.h"
#include "common/delay.h"
#include "ton/ton-tl.hpp"
#include "td/utils/Random.h"
namespace ton {
@ -36,19 +37,7 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
return;
}
if (lite_mode_) {
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise),
pubkey = Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}](td::Result<BlockCandidate> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
BlockCandidate candidate = R.move_as_ok();
candidate.pubkey = pubkey;
promise.set_result(std::move(candidate));
}
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_candidate, create_next_block_id_simple(),
td::Timestamp::in(15.0), std::move(P));
send_collate_query(round_id, td::Timestamp::in(10.0), std::move(promise));
return;
}
run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
@ -65,6 +54,17 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
promise.set_error(td::Status::Error(ErrorCode::notready, "too old"));
return;
}
if (approved_candidates_cache_round_ != round_id) {
approved_candidates_cache_round_ = round_id;
approved_candidates_cache_.clear();
}
CacheKey cache_key = block_to_cache_key(block);
auto it = approved_candidates_cache_.find(cache_key);
if (it != approved_candidates_cache_.end()) {
promise.set_result(it->second);
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), round_id, block = block.clone(),
promise = std::move(promise)](td::Result<ValidateCandidateResult> R) mutable {
if (R.is_error()) {
@ -80,11 +80,16 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
td::Timestamp::in(0.1));
} else {
auto v = R.move_as_ok();
v.visit(td::overloaded([&](UnixTime ts) { promise.set_result(ts); },
[&](CandidateReject reject) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation,
PSTRING() << "bad candidate: " << reject.reason));
}));
v.visit(td::overloaded(
[&](UnixTime ts) {
td::actor::send_closure(SelfId, &ValidatorGroup::update_approve_cache, round_id, block_to_cache_key(block),
ts);
promise.set_result(ts);
},
[&](CandidateReject reject) {
promise.set_error(
td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad candidate: " << reject.reason));
}));
}
});
if (!started_) {
@ -98,6 +103,14 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
td::Timestamp::in(10.0), std::move(P), lite_mode_ ? ValidateMode::lite : 0);
}
void ValidatorGroup::update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value) {
if (approved_candidates_cache_round_ != round_id) {
approved_candidates_cache_round_ = round_id;
approved_candidates_cache_.clear();
}
approved_candidates_cache_[key] = value;
}
void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,
RootHash root_hash, FileHash file_hash,
std::vector<BlockSignature> signatures,
@ -339,6 +352,91 @@ void ValidatorGroup::get_session_info(
td::actor::send_closure(session_, &validatorsession::ValidatorSession::get_session_info, std::move(P));
}
void ValidatorGroup::send_collate_query(td::uint32 round_id, td::Timestamp timeout,
td::Promise<BlockCandidate> promise) {
adnl::AdnlNodeIdShort collator = adnl::AdnlNodeIdShort::zero();
// TODO: some other way for storing and choosing collators for real network
int cnt = 0;
for (const CollatorNodeDescr& c : collator_set_) {
if (shard_is_ancestor(shard_, c.shard) && td::Random::fast(0, cnt) == 0) {
collator = adnl::AdnlNodeIdShort(c.adnl_id);
++cnt;
}
}
if (collator.is_zero()) {
promise.set_error(td::Status::Error(PSTRING() << "no collator for shard " << shard_.to_str()));
return;
}
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev_blocks;
for (const BlockIdExt &p : prev_block_ids_) {
prev_blocks.push_back(create_tl_block_id(p));
}
td::BufferSlice query = create_serialize_tl_object<ton_api::collatorNode_generateBlock>(
shard_.workchain, shard_.shard, create_tl_block_id(min_masterchain_block_id_), std::move(prev_blocks),
local_id_full_.ed25519_value().raw());
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), round_id, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("rldp query failed: "));
return;
}
td::actor::send_closure(SelfId, &ValidatorGroup::receive_collate_query_response, round_id, R.move_as_ok(),
std::move(promise));
});
LOG(INFO) << "collate query for " << shard_.to_str() << ": send query to " << collator;
size_t max_answer_size = config_.max_block_size + config_.max_collated_data_size + 256;
td::actor::send_closure(rldp_, &rldp::Rldp::send_query_ex, adnl::AdnlNodeIdShort(local_id_), collator, "collatequery",
std::move(P), timeout, std::move(query), max_answer_size);
}
void ValidatorGroup::receive_collate_query_response(td::uint32 round_id, td::BufferSlice data,
td::Promise<BlockCandidate> promise) {
if (round_id < last_known_round_id_) {
promise.set_error(td::Status::Error("too old"));
return;
}
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::collatorNode_GenerateBlockResult>(data, true));
tl_object_ptr<ton_api::db_candidate> b;
ton_api::downcast_call(*f, td::overloaded(
[&](ton_api::collatorNode_generateBlockError &r) {
td::Status error = td::Status::Error(r.code_, r.message_);
promise.set_error(error.move_as_error_prefix("collate query: "));
},
[&](ton_api::collatorNode_generateBlockSuccess &r) { b = std::move(r.candidate_); }));
if (!b) {
return;
}
auto key = PublicKey{b->source_};
if (!key.is_ed25519()) {
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
}
auto e_key = Ed25519_PublicKey{key.ed25519_value().raw()};
if (e_key != Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}) {
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
return;
}
auto block_id = ton::create_block_id(b->id_);
if (block_id.shard_full() != shard_) {
promise.set_error(td::Status::Error("collate query: shard mismatch"));
return;
}
auto collated_data_hash = td::sha256_bits256(b->collated_data_);
BlockCandidate candidate(e_key, block_id, collated_data_hash, std::move(b->data_), std::move(b->collated_data_));
auto P = td::PromiseCreator::lambda(
[candidate = candidate.clone(), promise = std::move(promise)](td::Result<UnixTime> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("validate received block error: "));
return;
}
promise.set_result(std::move(candidate));
});
validate_block_candidate(round_id, std::move(candidate), std::move(P));
}
} // namespace validator
} // namespace ton

View file

@ -55,12 +55,14 @@ class ValidatorGroup : public td::actor::Actor {
init_ = false;
create_session();
}
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
}
void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise);
ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
td::Ref<ValidatorSet> validator_set, validatorsession::ValidatorSessionOptions config,
td::Ref<ValidatorSet> validator_set, std::vector<CollatorNodeDescr> collator_set,
validatorsession::ValidatorSessionOptions config,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
std::string db_root, td::actor::ActorId<ValidatorManager> validator_manager, bool create_session,
@ -69,6 +71,7 @@ class ValidatorGroup : public td::actor::Actor {
, local_id_(std::move(local_id))
, session_id_(session_id)
, validator_set_(std::move(validator_set))
, collator_set_(std::move(collator_set))
, config_(std::move(config))
, keyring_(keyring)
, adnl_(adnl)
@ -83,6 +86,8 @@ class ValidatorGroup : public td::actor::Actor {
private:
std::unique_ptr<validatorsession::ValidatorSession::Callback> make_validator_session_callback();
void send_collate_query(td::uint32 round_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise);
void receive_collate_query_response(td::uint32 round_id, td::BufferSlice data, td::Promise<BlockCandidate> promise);
struct PostponedAccept {
RootHash root_hash;
@ -105,6 +110,7 @@ class ValidatorGroup : public td::actor::Actor {
BlockIdExt min_masterchain_block_id_;
td::Ref<ValidatorSet> validator_set_;
std::vector<CollatorNodeDescr> collator_set_;
validatorsession::ValidatorSessionOptions config_;
td::actor::ActorId<keyring::Keyring> keyring_;
@ -120,6 +126,16 @@ class ValidatorGroup : public td::actor::Actor {
bool allow_unsafe_self_blocks_resync_;
bool lite_mode_ = false;
td::uint32 last_known_round_id_ = 0;
typedef std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash> CacheKey;
std::map<CacheKey, UnixTime> approved_candidates_cache_;
td::uint32 approved_candidates_cache_round_ = 0;
void update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value);
static CacheKey block_to_cache_key(const BlockCandidate& block) {
return std::make_tuple(block.pubkey.as_bits256(), block.id, sha256_bits256(block.data), block.collated_file_hash);
}
};
} // namespace validator

View file

@ -220,6 +220,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void generate_block_candidate(BlockId block_id, td::Promise<BlockCandidate> promise) = 0;
virtual void get_required_block_candidates(td::Promise<std::vector<BlockId>> promise) = 0;
virtual void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
virtual void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0;
};
} // namespace validator