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:
parent
996c23e506
commit
53270a00e6
25 changed files with 577 additions and 33 deletions
|
@ -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
145
validator/collator-node.cpp
Normal 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
|
51
validator/collator-node.hpp
Normal file
51
validator/collator-node.hpp
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -384,6 +384,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
PublicKeyHash local_id_;
|
||||
|
||||
|
|
|
@ -443,6 +443,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue