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

Rework validator-collator interaction

1) Remove config 41, move "full collated data" to capabilities
2) Whitelist on collator nodes
3) "Ping" request for collator nodes
4) More customizable collators list for validators
5) CollationManager
This commit is contained in:
SpyCheese 2024-11-21 11:47:39 +03:00
parent 7d2110c8b0
commit b3bea413e3
34 changed files with 1204 additions and 319 deletions

View file

@ -58,6 +58,7 @@ set(VALIDATOR_HEADERS
import-db-slice.hpp
queue-size-counter.hpp
collation-manager.hpp
collator-node.hpp
manager-disk.h
manager-disk.hpp
@ -74,6 +75,7 @@ set(VALIDATOR_HEADERS
set(VALIDATOR_SOURCE
apply-block.cpp
block-handle.cpp
collation-manager.cpp
collator-node.cpp
get-next-key-blocks.cpp
import-db-slice.cpp

View file

@ -0,0 +1,373 @@
/*
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 "collation-manager.hpp"
#include "collator-node.hpp"
#include "fabric.h"
#include "td/utils/Random.h"
#include <delay.h>
#include <openssl/lhash.h>
#include <ton/ton-tl.hpp>
namespace ton::validator {
void CollationManager::start_up() {
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, local_id_);
update_collators_list(*opts_->get_collators_list());
}
void CollationManager::collate_block(ShardIdFull shard, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ed25519_PublicKey creator,
td::Ref<ValidatorSet> validator_set, td::uint64 max_answer_size,
td::CancellationToken cancellation_token, td::Promise<BlockCandidate> promise) {
if (shard.is_masterchain()) {
run_collate_query(shard, min_masterchain_block_id, std::move(prev), creator, std::move(validator_set),
opts_->get_collator_options(), manager_, td::Timestamp::in(10.0), std::move(promise),
std::move(cancellation_token), 0);
return;
}
collate_shard_block(shard, min_masterchain_block_id, std::move(prev), creator, std::move(validator_set),
max_answer_size, std::move(cancellation_token), std::move(promise), td::Timestamp::in(10.0));
}
void CollationManager::collate_shard_block(ShardIdFull shard, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ed25519_PublicKey creator,
td::Ref<ValidatorSet> validator_set, td::uint64 max_answer_size,
td::CancellationToken cancellation_token,
td::Promise<BlockCandidate> promise, td::Timestamp timeout) {
TRY_STATUS_PROMISE(promise, cancellation_token.check());
ShardInfo* s = select_shard_info(shard);
if (s == nullptr) {
promise.set_error(
td::Status::Error(PSTRING() << "shard " << shard.to_str() << " is not configured in collators list"));
return;
}
adnl::AdnlNodeIdShort selected_collator = adnl::AdnlNodeIdShort::zero();
size_t selected_idx = 0;
switch (s->select_mode) {
case CollatorsList::mode_random: {
int cnt = 0;
for (size_t i = 0; i < s->collators.size(); ++i) {
adnl::AdnlNodeIdShort collator = s->collators[i];
if (collators_[collator].alive) {
++cnt;
if (td::Random::fast(1, cnt) == 1) {
selected_collator = collator;
selected_idx = i;
}
}
}
break;
}
case CollatorsList::mode_ordered: {
for (size_t i = 0; i < s->collators.size(); ++i) {
adnl::AdnlNodeIdShort collator = s->collators[i];
if (collators_[collator].alive) {
selected_collator = collator;
selected_idx = i;
break;
}
}
break;
}
case CollatorsList::mode_round_robin: {
size_t iters = 0;
for (size_t i = s->cur_idx; iters < s->collators.size(); (++i) %= s->collators.size()) {
adnl::AdnlNodeIdShort& collator = s->collators[i];
if (collators_[collator].alive) {
selected_collator = collator;
selected_idx = i;
s->cur_idx = (i + 1) % s->collators.size();
break;
}
}
break;
}
}
if (selected_collator.is_zero() && s->self_collate) {
run_collate_query(shard, min_masterchain_block_id, std::move(prev), creator, std::move(validator_set),
opts_->get_collator_options(), manager_, td::Timestamp::in(10.0), std::move(promise),
std::move(cancellation_token), 0);
return;
}
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev_blocks;
BlockId next_block_id{shard, 0};
for (const BlockIdExt& p : prev) {
prev_blocks.push_back(create_tl_block_id(p));
next_block_id.seqno = std::max(next_block_id.seqno, p.seqno() + 1);
}
promise = [=, SelfId = actor_id(this), promise = std::move(promise),
retry_at = td::Timestamp::in(0.5)](td::Result<BlockCandidate> R) mutable {
if (R.is_ok()) {
promise.set_value(R.move_as_ok());
return;
}
if (!selected_collator.is_zero()) {
td::actor::send_closure(SelfId, &CollationManager::on_collate_query_error, selected_collator);
}
LOG(INFO) << "ERROR: collate query for " << next_block_id.to_str() << " to #" << selected_idx << " ("
<< selected_collator << "): " << R.error();
if (timeout < retry_at) {
promise.set_error(R.move_as_error());
return;
}
delay_action(
[=, promise = std::move(promise)]() mutable {
td::actor::send_closure(SelfId, &CollationManager::collate_shard_block, shard, min_masterchain_block_id, prev,
creator, validator_set, max_answer_size, cancellation_token, std::move(promise),
timeout);
},
retry_at);
};
if (selected_collator.is_zero()) {
promise.set_error(td::Status::Error(PSTRING() << "shard " << shard.to_str() << " has no alive collator node"));
return;
}
td::BufferSlice query = create_serialize_tl_object<ton_api::collatorNode_generateBlock>(
create_tl_shard_id(shard), validator_set->get_catchain_seqno(), std::move(prev_blocks), creator.as_bits256());
LOG(INFO) << "sending collate query for " << next_block_id.to_str() << ": send to #" << selected_idx << "("
<< selected_collator << ")";
td::Promise<td::BufferSlice> P = [=, SelfId = actor_id(this), promise = std::move(promise),
timer = td::Timer()](td::Result<td::BufferSlice> R) mutable {
TRY_RESULT_PROMISE_PREFIX(promise, data, std::move(R), "rldp query failed: ");
auto r_error = fetch_tl_object<ton_api::collatorNode_error>(data, true);
if (r_error.is_ok()) {
auto error = r_error.move_as_ok();
promise.set_error(td::Status::Error(error->code_, error->message_));
return;
}
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::collatorNode_Candidate>(data, true));
TRY_RESULT_PROMISE(promise, candidate,
CollatorNode::deserialize_candidate(std::move(f), td::narrow_cast<int>(max_answer_size)));
if (candidate.pubkey.as_bits256() != creator.as_bits256()) {
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
return;
}
if (candidate.id.id != next_block_id) {
promise.set_error(td::Status::Error("collate query: block id mismatch"));
return;
}
LOG(INFO) << "got collated block " << next_block_id.to_str() << " from #" << selected_idx << " ("
<< selected_collator << ") in " << timer.elapsed() << "s";
promise.set_result(std::move(candidate));
};
td::actor::send_closure(rldp_, &rldp::Rldp::send_query_ex, local_id_, selected_collator, "collatequery", std::move(P),
timeout, std::move(query), max_answer_size);
}
void CollationManager::update_options(td::Ref<ValidatorManagerOptions> opts) {
auto old_list = opts_->get_collators_list();
opts_ = std::move(opts);
auto list = opts_->get_collators_list();
if (old_list != list) {
update_collators_list(*list);
}
}
void CollationManager::validator_group_started(ShardIdFull shard) {
if (active_validator_groups_[shard]++ != 0) {
return;
}
ShardInfo* s = select_shard_info(shard);
if (s == nullptr) {
return;
}
if (s->active_cnt++ != 0) {
return;
}
for (adnl::AdnlNodeIdShort id : s->collators) {
CollatorInfo& collator = collators_[id];
collator.active_cnt++;
}
alarm();
}
void CollationManager::validator_group_finished(ShardIdFull shard) {
if (--active_validator_groups_[shard] != 0) {
return;
}
active_validator_groups_.erase(shard);
ShardInfo* s = select_shard_info(shard);
if (s == nullptr) {
return;
}
if (--s->active_cnt != 0) {
return;
}
for (adnl::AdnlNodeIdShort id : s->collators) {
CollatorInfo& collator = collators_[id];
--collator.active_cnt;
}
alarm();
}
void CollationManager::get_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats_localId>> promise) {
auto stats = create_tl_object<ton_api::engine_validator_collationManagerStats_localId>();
stats->adnl_id_ = local_id_.bits256_value();
for (ShardInfo& s : shards_) {
auto obj = create_tl_object<ton_api::engine_validator_collationManagerStats_shard>();
obj->shard_id_ = create_tl_shard_id(s.shard_id);
obj->active_ = s.active_cnt;
obj->self_collate_ = s.self_collate;
switch (s.select_mode) {
case CollatorsList::mode_random:
obj->select_mode_ = "random";
break;
case CollatorsList::mode_ordered:
obj->select_mode_ = "ordered";
break;
case CollatorsList::mode_round_robin:
obj->select_mode_ = "round_robin";
break;
}
for (adnl::AdnlNodeIdShort& id : s.collators) {
obj->collators_.push_back(id.bits256_value());
}
stats->shards_.push_back(std::move(obj));
}
for (auto& [id, collator] : collators_) {
auto obj = create_tl_object<ton_api::engine_validator_collationManagerStats_collator>();
obj->adnl_id_ = id.bits256_value();
obj->active_ = collator.active_cnt;
obj->alive_ = collator.alive;
if (collator.active_cnt && !collator.sent_ping) {
obj->ping_in_ = collator.ping_at.in();
} else {
obj->ping_in_ = -1.0;
}
stats->collators_.push_back(std::move(obj));
}
promise.set_value(std::move(stats));
}
void CollationManager::update_collators_list(const CollatorsList& collators_list) {
shards_.clear();
for (auto& [_, collator] : collators_) {
collator.active_cnt = 0;
}
auto old_collators = std::move(collators_);
collators_.clear();
for (const auto& shard : collators_list.shards) {
shards_.push_back({.shard_id = shard.shard_id, .select_mode = shard.select_mode, .collators = shard.collators});
for (auto id : shard.collators) {
auto it = old_collators.find(id);
if (it == old_collators.end()) {
collators_[id];
} else {
collators_[id] = std::move(it->second);
old_collators.erase(it);
}
}
}
for (auto& [shard, _] : active_validator_groups_) {
ShardInfo* s = select_shard_info(shard);
if (s == nullptr) {
continue;
}
if (s->active_cnt++ != 0) {
continue;
}
for (adnl::AdnlNodeIdShort id : s->collators) {
CollatorInfo& collator = collators_[id];
collator.active_cnt++;
}
}
alarm();
}
CollationManager::ShardInfo* CollationManager::select_shard_info(ShardIdFull shard) {
for (auto& s : shards_) {
if (shard_intersects(shard, s.shard_id)) {
return &s;
}
}
return nullptr;
}
void CollationManager::alarm() {
alarm_timestamp() = td::Timestamp::never();
for (auto& [id, collator] : collators_) {
if (collator.active_cnt == 0 || collator.sent_ping) {
continue;
}
if (collator.ping_at.is_in_past()) {
collator.sent_ping = true;
td::BufferSlice query = create_serialize_tl_object<ton_api::collatorNode_ping>(0);
td::Promise<td::BufferSlice> P = [=, SelfId = actor_id(this)](td::Result<td::BufferSlice> R) mutable {
td::actor::send_closure(SelfId, &CollationManager::got_pong, id, std::move(R));
};
LOG(DEBUG) << "sending ping to " << id;
td::actor::send_closure(rldp_, &rldp::Rldp::send_query, local_id_, id, "collatorping", std::move(P),
td::Timestamp::in(2.0), std::move(query));
} else {
alarm_timestamp().relax(collator.ping_at);
}
}
}
void CollationManager::got_pong(adnl::AdnlNodeIdShort id, td::Result<td::BufferSlice> R) {
auto it = collators_.find(id);
if (it == collators_.end()) {
return;
}
CollatorInfo& collator = it->second;
collator.sent_ping = false;
auto r_pong = [&]() -> td::Result<tl_object_ptr<ton_api::collatorNode_pong>> {
TRY_RESULT_PREFIX(data, std::move(R), "rldp query error: ");
auto r_error = fetch_tl_object<ton_api::collatorNode_error>(data, true);
if (r_error.is_ok()) {
auto error = r_error.move_as_ok();
return td::Status::Error(error->code_, error->message_);
}
return fetch_tl_object<ton_api::collatorNode_pong>(data, true);
}();
if (r_pong.is_error()) {
LOG(DEBUG) << "pong from " << id << " : " << r_pong.move_as_error();
collator.alive = false;
} else {
LOG(DEBUG) << "pong from " << id << " : OK";
collator.alive = true;
}
collator.ping_at = td::Timestamp::in(td::Random::fast(10.0, 20.0));
if (collator.active_cnt && !collator.sent_ping) {
alarm_timestamp().relax(collator.ping_at);
}
}
void CollationManager::on_collate_query_error(adnl::AdnlNodeIdShort id) {
auto it = collators_.find(id);
if (it == collators_.end()) {
return;
}
CollatorInfo& collator = it->second;
collator.ping_at = td::Timestamp::now();
if (collator.active_cnt && !collator.sent_ping) {
alarm_timestamp().relax(collator.ping_at);
}
}
} // namespace ton::validator

View file

@ -0,0 +1,87 @@
/*
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"
#include <map>
namespace ton::validator {
class ValidatorManager;
class CollationManager : public td::actor::Actor {
public:
CollationManager(adnl::AdnlNodeIdShort local_id, td::Ref<ValidatorManagerOptions> opts,
td::actor::ActorId<ValidatorManager> manager, td::actor::ActorId<rldp::Rldp> rldp)
: local_id_(local_id), opts_(opts), manager_(manager), rldp_(rldp) {
}
void start_up() override;
void alarm() override;
void collate_block(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set, td::uint64 max_answer_size,
td::CancellationToken cancellation_token, td::Promise<BlockCandidate> promise);
void update_options(td::Ref<ValidatorManagerOptions> opts);
void validator_group_started(ShardIdFull shard);
void validator_group_finished(ShardIdFull shard);
void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats_localId>> promise);
private:
adnl::AdnlNodeIdShort local_id_;
td::Ref<ValidatorManagerOptions> opts_;
td::actor::ActorId<ValidatorManager> manager_;
td::actor::ActorId<rldp::Rldp> rldp_;
void collate_shard_block(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set, td::uint64 max_answer_size,
td::CancellationToken cancellation_token, td::Promise<BlockCandidate> promise,
td::Timestamp timeout);
void update_collators_list(const CollatorsList& collators_list);
struct CollatorInfo {
bool alive = false;
td::Timestamp ping_at = td::Timestamp::now();
bool sent_ping = false;
size_t active_cnt = 0;
};
std::map<adnl::AdnlNodeIdShort, CollatorInfo> collators_;
struct ShardInfo {
ShardIdFull shard_id;
CollatorsList::SelectMode select_mode;
std::vector<adnl::AdnlNodeIdShort> collators;
bool self_collate = false;
size_t cur_idx = 0;
size_t active_cnt = 0;
};
std::vector<ShardInfo> shards_;
std::map<ShardIdFull, size_t> active_validator_groups_;
ShardInfo* select_shard_info(ShardIdFull shard);
void got_pong(adnl::AdnlNodeIdShort id, td::Result<td::BufferSlice> R);
void on_collate_query_error(adnl::AdnlNodeIdShort id);
};
} // namespace ton::validator

View file

@ -54,17 +54,22 @@ void CollatorNode::start_up() {
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(adnl_, &adnl::Adnl::subscribe, local_id_,
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_ping::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));
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id_,
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_ping::ID));
}
void CollatorNode::add_shard(ShardIdFull shard) {
CHECK(shard.is_valid_ext() && !shard.is_masterchain());
if (std::find(collating_shards_.begin(), collating_shards_.end(), shard) != collating_shards_.end()) {
if (std::ranges::find(collating_shards_, shard) != collating_shards_.end()) {
return;
}
LOG(INFO) << "Collator node: local_id=" << local_id_ << " , shard=" << shard.to_str();
@ -72,7 +77,7 @@ void CollatorNode::add_shard(ShardIdFull shard) {
}
void CollatorNode::del_shard(ShardIdFull shard) {
auto it = std::find(collating_shards_.begin(), collating_shards_.end(), shard);
auto it = std::ranges::find(collating_shards_, shard);
if (it != collating_shards_.end()) {
collating_shards_.erase(it);
}
@ -127,7 +132,7 @@ void CollatorNode::new_masterchain_block_notification(td::Ref<MasterchainState>
}
}
for (auto it = validator_groups_.begin(); it != validator_groups_.end();) {
if (new_shards.count(it->first)) {
if (new_shards.contains(it->first)) {
++it;
} else {
it->second.cleanup();
@ -253,7 +258,7 @@ void CollatorNode::CacheEntry::cancel(td::Status reason) {
}
static td::BufferSlice serialize_error(td::Status error) {
return create_serialize_tl_object<ton_api::collatorNode_generateBlockError>(error.code(), error.message().c_str());
return create_serialize_tl_object<ton_api::collatorNode_error>(error.code(), error.message().c_str());
}
static BlockCandidate change_creator(BlockCandidate block, Ed25519_PublicKey creator, CatchainSeqno& cc_seqno,
@ -285,25 +290,32 @@ static BlockCandidate change_creator(BlockCandidate block, Ed25519_PublicKey cre
void CollatorNode::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
td::Promise<BlockCandidate> new_promise = [promise = std::move(promise), src](td::Result<BlockCandidate> R) mutable {
promise = [promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
LOG(INFO) << "adnl query from " << src << ", error: " << R.error();
if (R.error().code() == ErrorCode::timeout) {
promise.set_error(R.move_as_error());
} else {
promise.set_result(serialize_error(R.move_as_error()));
}
} else {
LOG(INFO) << "adnl query from " << src << ", success";
promise.set_result(create_serialize_tl_object<ton_api::collatorNode_generateBlockSuccess>(
serialize_candidate(R.move_as_ok(), true)));
promise.set_result(R.move_as_ok());
}
};
if (!validator_adnl_ids_.count(src)) {
new_promise.set_error(td::Status::Error("src is not a validator"));
if (!opts_->check_collator_node_whitelist(src)) {
promise.set_error(td::Status::Error("not authorized"));
return;
}
TRY_RESULT_PROMISE(new_promise, f, fetch_tl_object<ton_api::collatorNode_generateBlock>(data, true));
if (!validator_adnl_ids_.contains(src)) {
promise.set_error(td::Status::Error("src is not a validator"));
return;
}
auto r_ping = fetch_tl_object<ton_api::collatorNode_ping>(data, true);
if (r_ping.is_ok()) {
process_ping(src, *r_ping.ok_ref(), std::move(promise));
return;
}
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::collatorNode_generateBlock>(data, true));
ShardIdFull shard = create_shard_id(f->shard_);
CatchainSeqno cc_seqno = f->cc_seqno_;
std::vector<BlockIdExt> prev_blocks;
@ -311,6 +323,16 @@ void CollatorNode::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data
prev_blocks.push_back(create_block_id(b));
}
Ed25519_PublicKey creator(f->creator_);
td::Promise<BlockCandidate> new_promise = [promise = std::move(promise), src,
shard](td::Result<BlockCandidate> R) mutable {
if (R.is_error()) {
LOG(INFO) << "collate query from " << src << ", shard=" << shard.to_str() << ": error: " << R.error();
promise.set_error(R.move_as_error());
} else {
LOG(INFO) << "collate query from " << src << ", shard=" << shard.to_str() << ": success";
promise.set_result(serialize_tl_object(serialize_candidate(R.move_as_ok(), true), true));
}
};
new_promise = [new_promise = std::move(new_promise), creator,
manager = manager_](td::Result<BlockCandidate> R) mutable {
TRY_RESULT_PROMISE(new_promise, block, std::move(R));
@ -427,9 +449,15 @@ void CollatorNode::process_result(std::shared_ptr<CacheEntry> cache_entry, td::R
cache_entry->promises.clear();
}
void CollatorNode::process_ping(adnl::AdnlNodeIdShort src, ton_api::collatorNode_ping& ping,
td::Promise<td::BufferSlice> promise) {
LOG(DEBUG) << "got ping from " << src;
promise.set_result(create_serialize_tl_object<ton_api::collatorNode_pong>(0));
}
bool CollatorNode::can_collate_shard(ShardIdFull shard) const {
return std::any_of(collating_shards_.begin(), collating_shards_.end(),
[&](const ShardIdFull& our_shard) { return shard_intersects(shard, our_shard); });
return std::ranges::any_of(collating_shards_,
[&](const ShardIdFull& our_shard) { return shard_intersects(shard, our_shard); });
}
tl_object_ptr<ton_api::collatorNode_Candidate> CollatorNode::serialize_candidate(const BlockCandidate& block,

View file

@ -43,6 +43,7 @@ class CollatorNode : public td::actor::Actor {
private:
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void process_ping(adnl::AdnlNodeIdShort src, ton_api::collatorNode_ping& ping, td::Promise<td::BufferSlice> promise);
bool can_collate_shard(ShardIdFull shard) const;

View file

@ -502,10 +502,16 @@ td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
if (pfx_len > wc_monitor_min_split_) {
shard = shard_prefix(shard, wc_monitor_min_split_);
}
auto it = shards_.find(shard);
if (it != shards_.end()) {
update_shard_actor(shard, it->second.active);
return it->second.actor.get();
while (true) {
auto it = shards_.find(shard);
if (it != shards_.end()) {
update_shard_actor(shard, it->second.active);
return it->second.actor.get();
}
if (shard.pfx_len() == 0) {
break;
}
shard = shard_parent(shard);
}
// Special case if shards_ was not yet initialized.

View file

@ -45,7 +45,7 @@ class Collator final : public td::actor::Actor {
}
static constexpr long long supported_capabilities() {
return ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion | ton::capShortDequeue |
ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages;
ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages | ton::capFullCollatedData;
}
using LtCellRef = block::LtCellRef;
using NewOutMsg = block::NewOutMsg;

View file

@ -730,6 +730,8 @@ bool Collator::unpack_last_mc_state() {
store_out_msg_queue_size_ = config_->has_capability(ton::capStoreOutMsgQueueSize);
msg_metadata_enabled_ = config_->has_capability(ton::capMsgMetadata);
deferring_messages_enabled_ = config_->has_capability(ton::capDeferMessages);
full_collated_data_ = config_->has_capability(capFullCollatedData);
LOG(DEBUG) << "full_collated_data is " << full_collated_data_;
shard_conf_ = std::make_unique<block::ShardConfig>(*config_);
prev_key_block_exists_ = config_->get_last_key_block(prev_key_block_, prev_key_block_lt_);
if (prev_key_block_exists_) {
@ -768,8 +770,6 @@ bool Collator::unpack_last_mc_state() {
<< " have been enabled in global configuration, but we support only " << supported_version()
<< " (upgrade validator software?)";
}
full_collated_data_ = config_->get_collator_config(false).full_collated_data;
LOG(DEBUG) << "full_collated_data is " << full_collated_data_;
// TODO: extract start_lt and end_lt from prev_mc_block as well
// std::cerr << " block::gen::ShardState::print_ref(mc_state_root) = ";
// block::gen::t_ShardState.print_ref(std::cerr, mc_state_root, 2);
@ -817,6 +817,9 @@ bool Collator::request_neighbor_msg_queues() {
auto neighbor_list = shard_conf_->get_neighbor_shard_hash_ids(shard_);
LOG(DEBUG) << "got a preliminary list of " << neighbor_list.size() << " neighbors for " << shard_.to_str();
for (ton::BlockId blk_id : neighbor_list) {
if (blk_id.seqno == 0 && blk_id.shard_full() != shard_) {
continue;
}
auto shard_ptr = shard_conf_->get_shard_hash(ton::ShardIdFull(blk_id));
if (shard_ptr.is_null()) {
return fatal_error(-667, "cannot obtain shard hash for neighbor "s + blk_id.to_str());

View file

@ -170,9 +170,6 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
block::WorkchainSet get_workchain_list() const override {
return config_ ? config_->get_workchain_list() : block::WorkchainSet();
}
block::CollatorConfig get_collator_config(bool need_collator_nodes) const override {
return config_ ? config_->get_collator_config(need_collator_nodes) : block::CollatorConfig();
}
private:
ZeroStateIdExt zerostate_id_;

View file

@ -1536,6 +1536,9 @@ bool ValidateQuery::request_neighbor_queues() {
auto neighbor_list = new_shard_conf_->get_neighbor_shard_hash_ids(shard_);
LOG(DEBUG) << "got a preliminary list of " << neighbor_list.size() << " neighbors for " << shard_.to_str();
for (ton::BlockId blk_id : neighbor_list) {
if (blk_id.seqno == 0 && blk_id.shard_full() != shard_) {
continue;
}
auto shard_ptr = new_shard_conf_->get_shard_hash(ton::ShardIdFull(blk_id));
if (shard_ptr.is_null()) {
return reject_query("cannot obtain shard hash for neighbor "s + blk_id.to_str());
@ -2305,6 +2308,12 @@ bool ValidateQuery::prepare_out_msg_queue_size() {
have_out_msg_queue_size_in_state_ = true;
return true;
}
if (ps_.out_msg_queue_->is_empty()) {
old_out_msg_queue_size_ = 0;
out_msg_queue_size_known_ = true;
have_out_msg_queue_size_in_state_ = true;
return true;
}
if (!store_out_msg_queue_size_) { // Don't need it
return true;
}

View file

@ -113,7 +113,7 @@ class ValidateQuery : public td::actor::Actor {
}
static constexpr long long supported_capabilities() {
return ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion | ton::capShortDequeue |
ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages;
ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages | ton::capFullCollatedData;
}
public:

View file

@ -50,6 +50,7 @@ class ValidatorSetQ : public ValidatorSet {
td::Ref<BlockSignatureSet> signatures) const override;
td::Result<ValidatorWeight> check_approve_signatures(RootHash root_hash, FileHash file_hash,
td::Ref<BlockSignatureSet> signatures) const override;
const ValidatorDescr* find_validator(const NodeIdShort& id) const override;
ValidatorSetQ* make_copy() const override;
@ -62,8 +63,6 @@ class ValidatorSetQ : public ValidatorSet {
ValidatorWeight total_weight_;
std::vector<ValidatorDescr> ids_;
std::vector<std::pair<NodeIdShort, size_t>> ids_map_;
const ValidatorDescr* find_validator(const NodeIdShort& id) const;
};
class ValidatorSetCompute {

View file

@ -85,7 +85,6 @@ class MasterchainState : virtual public ShardState {
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 block::CollatorConfig get_collator_config(bool need_collator_nodes) const = 0;
virtual td::Status prepare() {
return td::Status::OK();
}

View file

@ -35,6 +35,7 @@ class ValidatorSet : public td::CntObject {
virtual td::uint32 get_validator_set_hash() const = 0;
virtual ShardId get_validator_set_from() const = 0;
virtual std::vector<ValidatorDescr> export_vector() const = 0;
virtual const ValidatorDescr* find_validator(const NodeIdShort& id) const = 0;
virtual td::Result<ValidatorWeight> check_signatures(RootHash root_hash, FileHash file_hash,
td::Ref<BlockSignatureSet> signatures) const = 0;
virtual td::Result<ValidatorWeight> check_approve_signatures(RootHash root_hash, FileHash file_hash,

View file

@ -457,6 +457,11 @@ class ValidatorManagerImpl : public ValidatorManager {
UNREACHABLE();
}
void get_collation_manager_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise) override {
UNREACHABLE();
}
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
opts_ = std::move(opts);
}

View file

@ -525,6 +525,11 @@ class ValidatorManagerImpl : public ValidatorManager {
UNREACHABLE();
}
void get_collation_manager_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise) override {
UNREACHABLE();
}
private:
td::Ref<ValidatorManagerOptions> opts_;

View file

@ -799,7 +799,13 @@ void ValidatorManagerImpl::wait_neighbor_msg_queue_proofs(
public:
Worker(size_t pending, td::Promise<std::map<BlockIdExt, td::Ref<OutMsgQueueProof>>> promise)
: pending_(pending), promise_(std::move(promise)) {
CHECK(pending_ > 0);
}
void start_up() override {
if (pending_ == 0) {
promise_.set_result(std::move(result_));
stop();
}
}
void on_result(td::Ref<OutMsgQueueProof> res) {
@ -2462,15 +2468,27 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
auto validator_id = get_validator(shard, validator_set);
CHECK(!validator_id.is_zero());
auto descr = validator_set->find_validator(validator_id.bits256_value());
CHECK(descr);
auto adnl_id = adnl::AdnlNodeIdShort{
descr->addr.is_zero() ? ValidatorFullId{descr->key}.compute_short_id().bits256_value() : descr->addr};
auto G = td::actor::create_actor<ValidatorGroup>(
PSTRING() << "valgroup" << shard.to_str(), shard, validator_id, session_id, validator_set, key_seqno,
last_masterchain_state_->get_collator_config(true), opts, keyring_, adnl_, rldp_, overlays_, db_root_,
actor_id(this), init_session, opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), opts_,
PSTRING() << "valgroup" << shard.to_str(), shard, validator_id, session_id, validator_set, key_seqno, opts,
keyring_, adnl_, rldp_, overlays_, db_root_, actor_id(this), get_collation_manager(adnl_id), init_session,
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), opts_,
opts_->need_monitor(shard, last_masterchain_state_));
return G;
}
}
td::actor::ActorId<CollationManager> ValidatorManagerImpl::get_collation_manager(adnl::AdnlNodeIdShort adnl_id) {
auto &actor = collation_managers_[adnl_id];
if (actor.empty()) {
actor = td::actor::create_actor<CollationManager>("collation", adnl_id, opts_, actor_id(this), rldp_);
}
return actor.get();
}
void ValidatorManagerImpl::add_handle_to_lru(BlockHandle handle) {
auto it = handle_lru_map_.find(handle->id());
if (it != handle_lru_map_.end()) {
@ -3458,6 +3476,9 @@ void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts)
for (auto &collator : collator_nodes_) {
td::actor::send_closure(collator.second.actor, &CollatorNode::update_options, opts);
}
for (auto &[_, c] : collation_managers_) {
td::actor::send_closure(c, &CollationManager::update_options, opts);
}
opts_ = std::move(opts);
}
@ -3492,6 +3513,54 @@ void ValidatorManagerImpl::del_collator(adnl::AdnlNodeIdShort id, ShardIdFull sh
}
}
void ValidatorManagerImpl::get_collation_manager_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise) {
class Cb : public td::actor::Actor {
public:
explicit Cb(td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise)
: promise_(std::move(promise)) {
}
void got_stats(tl_object_ptr<ton_api::engine_validator_collationManagerStats_localId> s) {
result_.push_back(std::move(s));
dec_pending();
}
void inc_pending() {
++pending_;
}
void dec_pending() {
CHECK(pending_ > 0);
--pending_;
if (pending_ == 0) {
promise_.set_result(create_tl_object<ton_api::engine_validator_collationManagerStats>(std::move(result_)));
stop();
}
}
private:
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise_;
size_t pending_ = 1;
std::vector<tl_object_ptr<ton_api::engine_validator_collationManagerStats_localId>> result_;
};
auto callback = td::actor::create_actor<Cb>("stats", std::move(promise)).release();
for (auto &[_, actor] : collation_managers_) {
td::actor::send_closure(callback, &Cb::inc_pending);
td::actor::send_closure(
actor, &CollationManager::get_stats,
[callback](td::Result<tl_object_ptr<ton_api::engine_validator_collationManagerStats_localId>> R) {
if (R.is_error()) {
td::actor::send_closure(callback, &Cb::dec_pending);
} else {
td::actor::send_closure(callback, &Cb::got_stats, R.move_as_ok());
}
});
}
td::actor::send_closure(callback, &Cb::dec_pending);
}
void ValidatorManagerImpl::add_persistent_state_description(td::Ref<PersistentStateDescription> desc) {
auto now = (UnixTime)td::Clocks::system();
if (desc->end_time <= now) {

View file

@ -283,12 +283,15 @@ class ValidatorManagerImpl : public ValidatorManager {
td::Ref<ValidatorSet> validator_set, BlockSeqno key_seqno,
validatorsession::ValidatorSessionOptions opts,
bool create_catchain);
td::actor::ActorId<CollationManager> get_collation_manager(adnl::AdnlNodeIdShort adnl_id);
struct ValidatorGroupEntry {
td::actor::ActorOwn<ValidatorGroup> actor;
ShardIdFull shard;
};
std::map<ValidatorSessionId, ValidatorGroupEntry> validator_groups_;
std::map<ValidatorSessionId, ValidatorGroupEntry> next_validator_groups_;
std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<CollationManager>> collation_managers_;
std::set<ValidatorSessionId> check_gc_list_;
std::vector<ValidatorSessionId> gc_list_;
@ -634,6 +637,9 @@ class ValidatorManagerImpl : public ValidatorManager {
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override;
void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override;
void get_collation_manager_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise) override;
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
if (queue_size_counter_.empty()) {
if (last_masterchain_state_.is_null()) {

View file

@ -65,7 +65,10 @@ void ValidatorGroup::generate_block_candidate(
td::actor::send_closure(SelfId, &ValidatorGroup::generated_block_candidate, source_info, std::move(cache),
std::move(R));
};
collate_block(source_info, td::Timestamp::in(10.0), std::move(P));
td::uint64 max_answer_size = config_.max_block_size + config_.max_collated_data_size + 1024;
td::actor::send_closure(collation_manager_, &CollationManager::collate_block, shard_, min_masterchain_block_id_,
prev_block_ids_, Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_,
max_answer_size, cancellation_token_source_.get_cancellation_token(), std::move(P));
}
void ValidatorGroup::generated_block_candidate(validatorsession::BlockSourceInfo source_info,
@ -218,9 +221,9 @@ void ValidatorGroup::accept_block_query(BlockIdExt block_id, td::Ref<BlockData>
return;
}
LOG_CHECK(R.error().code() == ErrorCode::timeout || R.error().code() == ErrorCode::notready) << R.move_as_error();
td::actor::send_closure(SelfId, &ValidatorGroup::accept_block_query, block_id, std::move(block),
std::move(prev), std::move(sig_set), std::move(approve_sig_set), send_broadcast_mode,
std::move(promise), true);
td::actor::send_closure(SelfId, &ValidatorGroup::accept_block_query, block_id, std::move(block), std::move(prev),
std::move(sig_set), std::move(approve_sig_set), send_broadcast_mode, std::move(promise),
true);
} else {
promise.set_value(R.move_as_ok());
}
@ -292,7 +295,8 @@ std::unique_ptr<validatorsession::ValidatorSession::Callback> ValidatorGroup::ma
td::actor::send_closure(id_, &ValidatorGroup::generate_block_candidate, std::move(source_info),
std::move(promise));
}
void on_block_committed(validatorsession::BlockSourceInfo source_info, validatorsession::ValidatorSessionRootHash root_hash,
void on_block_committed(validatorsession::BlockSourceInfo source_info,
validatorsession::ValidatorSessionRootHash root_hash,
validatorsession::ValidatorSessionFileHash file_hash, td::BufferSlice data,
std::vector<std::pair<PublicKeyHash, td::BufferSlice>> signatures,
std::vector<std::pair<PublicKeyHash, td::BufferSlice>> approve_signatures,
@ -409,7 +413,7 @@ void ValidatorGroup::start(std::vector<BlockIdExt> prev, BlockIdExt min_masterch
stats.last_key_block_seqno = last_key_block_seqno_;
stats.timestamp = td::Clocks::system();
td::uint32 idx = 0;
for (const auto& node : validator_set_->export_vector()) {
for (const auto &node : validator_set_->export_vector()) {
PublicKeyHash id = ValidatorFullId{node.key}.compute_short_id();
if (id == local_id_) {
stats.self_idx = idx;
@ -489,7 +493,7 @@ void ValidatorGroup::get_validator_group_info_for_litequery_cont(
auto result = create_tl_object<lite_api::liteServer_nonfinal_validatorGroupInfo>();
result->next_block_id_ = create_tl_lite_block_id_simple(next_block_id);
for (const BlockIdExt& prev : prev_block_ids_) {
for (const BlockIdExt &prev : prev_block_ids_) {
result->prev_.push_back(create_tl_lite_block_id(prev));
}
result->cc_seqno_ = validator_set_->get_catchain_seqno();
@ -497,146 +501,6 @@ void ValidatorGroup::get_validator_group_info_for_litequery_cont(
promise.set_result(std::move(result));
}
void ValidatorGroup::collate_block(validatorsession::BlockSourceInfo source_info, td::Timestamp timeout,
td::Promise<BlockCandidate> promise, unsigned max_retries) {
if (source_info.round < last_known_round_id_) {
promise.set_error(td::Status::Error("too old"));
return;
}
BlockId next_block_id = create_next_block_id_simple();
adnl::AdnlNodeIdShort collator_adnl_id = adnl::AdnlNodeIdShort::zero();
bool self_collate = false;
bool trusted_collator = false;
if (shard_.is_masterchain()) {
self_collate = true;
} else {
for (const auto &s : opts_->get_collators_list()->shards) {
if (!shard_intersects(s.shard_id, shard_)) {
continue;
}
if (!s.collators.empty()) {
const CollatorsList::Collator &col = s.collators[td::Random::fast(0, s.collators.size() - 1)];
collator_adnl_id = col.adnl_id;
trusted_collator = col.trusted;
break;
}
}
if (collator_adnl_id.is_zero()) {
if (opts_->get_collators_list()->self_collate) {
self_collate = true;
} else if (opts_->get_collators_list()->use_config_41) {
// TODO: some way to choose node (similar to "unreliability" in full-node)
int cnt = 0;
for (const block::CollatorNodeDescr &c : collator_config_.collator_nodes) {
if (shard_intersects(shard_, c.shard)) {
if (td::Random::fast(0, cnt) == 0) {
collator_adnl_id = adnl::AdnlNodeIdShort(c.adnl_id);
}
++cnt;
}
}
}
}
}
if (self_collate) {
run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_,
opts_->get_collator_options(), manager_, td::Timestamp::in(10.0), std::move(promise),
cancellation_token_source_.get_cancellation_token(), 0);
return;
}
if (collator_adnl_id.is_zero()) {
promise.set_error(td::Status::Error(PSTRING() << "no collator for shard " << shard_.to_str()));
return;
}
promise = td::PromiseCreator::lambda([=, SelfId = actor_id(this), promise = std::move(promise),
timer = td::Timer()](td::Result<BlockCandidate> R) mutable {
if (R.is_ok()) {
LOG(INFO) << "collate query for " << next_block_id.to_str() << ": success, time=" << timer.elapsed() << "s";
promise.set_result(R.move_as_ok());
return;
}
bool retry = (!timeout || !timeout.is_in_past()) && max_retries > 0;
LOG(WARNING) << "collate query for " << next_block_id.to_str() << ": " << R.error() << ", time=" << timer.elapsed()
<< "s, " << (retry ? "retrying" : "giving up");
if (retry) {
td::actor::send_closure(SelfId, &ValidatorGroup::collate_block, source_info, timeout, std::move(promise),
max_retries - 1);
} else {
promise.set_result(td::Status::Error(ErrorCode::timeout, "timeout"));
}
});
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>(
create_tl_shard_id(shard_), validator_set_->get_catchain_seqno(), std::move(prev_blocks),
local_id_full_.ed25519_value().raw());
auto P = td::PromiseCreator::lambda(
[=, SelfId = actor_id(this), 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, source_info, R.move_as_ok(),
trusted_collator, std::move(promise));
});
LOG(INFO) << "sending collate query for " << next_block_id.to_str() << ": send to " << collator_adnl_id;
size_t max_answer_size = config_.max_block_size + config_.max_collated_data_size + 1024;
td::Timestamp query_timeout = td::Timestamp::in(10.0);
query_timeout.relax(timeout);
td::actor::send_closure(rldp_, &rldp::Rldp::send_query_ex, local_adnl_id_, collator_adnl_id, "collatequery",
std::move(P), timeout, std::move(query), max_answer_size);
}
void ValidatorGroup::receive_collate_query_response(validatorsession::BlockSourceInfo source_info, td::BufferSlice data,
bool trusted_collator, td::Promise<BlockCandidate> promise) {
if (source_info.round < 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));
td::Result<BlockCandidate> res;
ton_api::downcast_call(*f, td::overloaded(
[&](ton_api::collatorNode_generateBlockError &r) {
td::Status error = td::Status::Error(r.code_, r.message_);
res = error.move_as_error_prefix("collate query: ");
},
[&](ton_api::collatorNode_generateBlockSuccess &r) {
res = CollatorNode::deserialize_candidate(
std::move(r.candidate_),
config_.max_block_size + config_.max_collated_data_size + 1024);
}));
TRY_RESULT_PROMISE(promise, candidate, std::move(res));
if (candidate.pubkey.as_bits256() != local_id_full_.ed25519_value().raw()) {
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
return;
}
if (candidate.id.shard_full() != shard_) {
promise.set_error(td::Status::Error("collate query: shard mismatch"));
return;
}
if (trusted_collator) {
promise.set_result(std::move(candidate));
return;
}
auto P = td::PromiseCreator::lambda(
[candidate = candidate.clone(), promise = std::move(promise)](td::Result<std::pair<UnixTime, bool>> 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(source_info, std::move(candidate), std::move(P));
}
} // namespace validator
} // namespace ton

View file

@ -18,6 +18,7 @@
*/
#pragma once
#include "collation-manager.hpp"
#include "interfaces/validator-manager.h"
#include "validator-session/validator-session.h"
@ -59,6 +60,10 @@ class ValidatorGroup : public td::actor::Actor {
init_ = false;
create_session();
}
td::actor::send_closure(collation_manager_, &CollationManager::validator_group_started, shard_);
}
void tear_down() override {
td::actor::send_closure(collation_manager_, &CollationManager::validator_group_finished, shard_);
}
void get_validator_group_info_for_litequery(
@ -71,17 +76,17 @@ class ValidatorGroup : public td::actor::Actor {
ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
td::Ref<ValidatorSet> validator_set, BlockSeqno last_key_block_seqno,
block::CollatorConfig collator_config, 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,
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,
td::actor::ActorId<CollationManager> collation_manager, bool create_session,
bool allow_unsafe_self_blocks_resync, td::Ref<ValidatorManagerOptions> opts, bool monitoring_shard)
: shard_(shard)
, local_id_(std::move(local_id))
, session_id_(session_id)
, validator_set_(std::move(validator_set))
, last_key_block_seqno_(last_key_block_seqno)
, collator_config_(std::move(collator_config))
, config_(std::move(config))
, keyring_(keyring)
, adnl_(adnl)
@ -89,6 +94,7 @@ class ValidatorGroup : public td::actor::Actor {
, overlays_(overlays)
, db_root_(std::move(db_root))
, manager_(validator_manager)
, collation_manager_(collation_manager)
, init_(create_session)
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync)
, opts_(std::move(opts))
@ -97,10 +103,6 @@ class ValidatorGroup : public td::actor::Actor {
private:
std::unique_ptr<validatorsession::ValidatorSession::Callback> make_validator_session_callback();
void collate_block(validatorsession::BlockSourceInfo source_info, td::Timestamp timeout,
td::Promise<BlockCandidate> promise, unsigned max_retries = 4);
void receive_collate_query_response(validatorsession::BlockSourceInfo source_info, td::BufferSlice data,
bool trusted_collator, td::Promise<BlockCandidate> promise);
struct PostponedAccept {
RootHash root_hash;
@ -124,7 +126,6 @@ class ValidatorGroup : public td::actor::Actor {
td::Ref<ValidatorSet> validator_set_;
BlockSeqno last_key_block_seqno_;
block::CollatorConfig collator_config_;
validatorsession::ValidatorSessionOptions config_;
td::actor::ActorId<keyring::Keyring> keyring_;
@ -133,6 +134,7 @@ class ValidatorGroup : public td::actor::Actor {
td::actor::ActorId<overlay::Overlays> overlays_;
std::string db_root_;
td::actor::ActorId<ValidatorManager> manager_;
td::actor::ActorId<CollationManager> collation_manager_;
td::actor::ActorOwn<validatorsession::ValidatorSession> session_;
adnl::AdnlNodeIdShort local_adnl_id_;

View file

@ -26,29 +26,58 @@ namespace ton {
namespace validator {
void CollatorsList::unpack(const ton_api::engine_validator_collatorsList& obj) {
td::Status CollatorsList::unpack(const ton_api::engine_validator_collatorsList& obj) {
shards.clear();
self_collate = obj.self_collate_;
use_config_41 = obj.use_config_41_;
self_collate = false;
for (const auto& shard_obj : obj.shards_) {
ShardIdFull shard_id = create_shard_id(shard_obj->shard_id_);
if (shard_id.is_masterchain()) {
return td::Status::Error("masterchain shard in collators list");
}
if (!shard_id.is_valid_ext()) {
return td::Status::Error(PSTRING() << "invalid shard " << shard_id.to_str());
}
shards.emplace_back();
Shard& shard = shards.back();
shard.shard_id = create_shard_id(shard_obj->shard_id_);
shard.shard_id = shard_id;
shard.self_collate = shard_obj->self_collate_;
if (shard.self_collate) {
self_collate = true;
}
if (shard_obj->select_mode_.empty() || shard_obj->select_mode_ == "random") {
shard.select_mode = mode_random;
} else if (shard_obj->select_mode_ == "ordered") {
shard.select_mode = mode_ordered;
} else if (shard_obj->select_mode_ == "round_robin") {
shard.select_mode = mode_round_robin;
} else {
return td::Status::Error(PSTRING() << "invalid select mode '" << shard_obj->select_mode_
<< "' (allowed: 'random', 'ordered', 'round_robin')");
}
for (const auto& collator : shard_obj->collators_) {
shard.collators.push_back({adnl::AdnlNodeIdShort{collator->adnl_id_}, collator->trusted_});
shard.collators.push_back(adnl::AdnlNodeIdShort{collator->adnl_id_});
}
}
return td::Status::OK();
}
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
double sync_blocks_before, double block_ttl, double state_ttl, double max_mempool_num,
double archive_ttl, double key_proof_ttl, bool initial_sync_disabled) {
CollatorsList CollatorsList::default_list() {
CollatorsList list;
list.shards.push_back(
{.shard_id = ShardIdFull{basechainId, shardIdAll}, .select_mode = mode_random, .self_collate = true});
list.self_collate = true;
return list;
}
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull)> check_shard,
bool allow_blockchain_init, double sync_blocks_before,
double block_ttl, double state_ttl,
double max_mempool_num, double archive_ttl,
double key_proof_ttl, bool initial_sync_disabled) {
return td::make_ref<ValidatorManagerOptionsImpl>(zero_block_id, init_block_id, std::move(check_shard),
allow_blockchain_init, sync_blocks_before, block_ttl, state_ttl,
max_mempool_num,
archive_ttl, key_proof_ttl, initial_sync_disabled);
max_mempool_num, archive_ttl, key_proof_ttl, initial_sync_disabled);
}
} // namespace validator

View file

@ -157,6 +157,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
td::Ref<CollatorsList> get_collators_list() const override {
return collators_list_;
}
bool check_collator_node_whitelist(adnl::AdnlNodeIdShort id) const override {
return !collator_node_whitelist_enabled_ || collator_node_whitelist_.contains(id);
}
void set_zero_block_id(BlockIdExt block_id) override {
zero_block_id_ = block_id;
@ -255,6 +258,16 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
void set_collators_list(td::Ref<CollatorsList> list) override {
collators_list_ = std::move(list);
}
void set_collator_node_whitelisted_validator(adnl::AdnlNodeIdShort id, bool add) override {
if (add) {
collator_node_whitelist_.insert(id);
} else {
collator_node_whitelist_.erase(id);
}
}
void set_collator_node_whitelist_enabled(bool enabled) override {
collator_node_whitelist_enabled_ = enabled;
}
ValidatorManagerOptionsImpl *make_copy() const override {
return new ValidatorManagerOptionsImpl(*this);
@ -308,7 +321,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
bool state_serializer_enabled_ = true;
td::Ref<CollatorOptions> collator_options_{true};
bool fast_state_serializer_enabled_ = false;
td::Ref<CollatorsList> collators_list_{true, CollatorsList{}};
td::Ref<CollatorsList> collators_list_{true, CollatorsList::default_list()};
std::set<adnl::AdnlNodeIdShort> collator_node_whitelist_;
bool collator_node_whitelist_enabled_ = false;
};
} // namespace validator

View file

@ -73,19 +73,20 @@ struct CollatorOptions : public td::CntObject {
};
struct CollatorsList : public td::CntObject {
struct Collator {
adnl::AdnlNodeIdShort adnl_id;
bool trusted;
enum SelectMode {
mode_random, mode_ordered, mode_round_robin
};
struct Shard {
ShardIdFull shard_id;
std::vector<Collator> collators;
SelectMode select_mode = mode_random;
std::vector<adnl::AdnlNodeIdShort> collators;
bool self_collate = false;
};
bool self_collate = true;
bool use_config_41 = false;
std::vector<Shard> shards;
bool self_collate = false;
void unpack(const ton_api::engine_validator_collatorsList& obj);
td::Status unpack(const ton_api::engine_validator_collatorsList& obj);
static CollatorsList default_list();
};
struct ValidatorManagerOptions : public td::CntObject {
@ -130,6 +131,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual td::Ref<CollatorOptions> get_collator_options() const = 0;
virtual bool get_fast_state_serializer_enabled() const = 0;
virtual td::Ref<CollatorsList> get_collators_list() const = 0;
virtual bool check_collator_node_whitelist(adnl::AdnlNodeIdShort id) const = 0;
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
virtual void set_init_block_id(BlockIdExt block_id) = 0;
@ -163,6 +165,8 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual void set_collator_options(td::Ref<CollatorOptions> value) = 0;
virtual void set_fast_state_serializer_enabled(bool value) = 0;
virtual void set_collators_list(td::Ref<CollatorsList> list) = 0;
virtual void set_collator_node_whitelisted_validator(adnl::AdnlNodeIdShort id, bool add) = 0;
virtual void set_collator_node_whitelist_enabled(bool enabled) = 0;
static td::Ref<ValidatorManagerOptions> create(
BlockIdExt zero_block_id, BlockIdExt init_block_id,
@ -314,6 +318,9 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0;
virtual void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0;
virtual void get_collation_manager_stats(
td::Promise<tl_object_ptr<ton_api::engine_validator_collationManagerStats>> promise) = 0;
};
} // namespace validator