1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +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

@ -801,11 +801,6 @@ misbehaviour_punishment_config_v1#01
= MisbehaviourPunishmentConfig;
_ MisbehaviourPunishmentConfig = ConfigParam 40;
// collator_nodes: each collator is (workchain:int32 shard:uint64 adnl_id:uint256)
collator_info#00 = CollatorInfo;
colator_config#a0 full_collated_data:Bool collator_nodes:(HashmapE 352 CollatorInfo) = CollatorConfig;
_ CollatorConfig = ConfigParam 41;
size_limits_config#01 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 = SizeLimitsConfig;
size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16

View file

@ -2339,28 +2339,4 @@ td::optional<PrecompiledContractsConfig::Contract> PrecompiledContractsConfig::g
return c;
}
CollatorConfig Config::get_collator_config(bool need_collator_nodes) const {
CollatorConfig collator_config;
gen::CollatorConfig::Record rec;
auto cell = get_config_param(41, -41);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return collator_config;
}
collator_config.full_collated_data = rec.full_collated_data;
if (need_collator_nodes) {
vm::Dictionary dict{rec.collator_nodes->prefetch_ref(), 32 + 64 + 256};
dict.check_for_each([&](Ref<vm::CellSlice> value, 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);
collator_config.collator_nodes.push_back({ton::ShardIdFull(workchain, shard), adnl_id});
return true;
});
}
return collator_config;
}
} // namespace block

View file

@ -543,11 +543,6 @@ struct CollatorNodeDescr {
ton::NodeIdShort adnl_id;
};
struct CollatorConfig {
bool full_collated_data = false;
std::vector<CollatorNodeDescr> collator_nodes;
};
class Config {
enum {
default_mc_catchain_lifetime = 200,
@ -664,7 +659,6 @@ class Config {
std::vector<ton::ValidatorDescr> compute_validator_set(ton::ShardIdFull shard, ton::UnixTime time,
ton::CatchainSeqno cc_seqno) const;
std::vector<ton::ValidatorDescr> compute_total_validator_set(int next) const;
CollatorConfig get_collator_config(bool need_collator_nodes) const;
td::Result<SizeLimitsConfig> get_size_limits_config() const;
static td::Result<SizeLimitsConfig> do_get_size_limits_config(td::Ref<vm::CellSlice> cs);
std::unique_ptr<vm::Dictionary> get_suspended_addresses(ton::UnixTime now) const;

View file

@ -646,8 +646,9 @@ engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNode
engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
engine.validator.fullNodeConfig ext_messages_broadcast_disabled:Bool = engine.validator.FullNodeConfig;
engine.validator.fastSyncMemberCertificate adnl_id:int256 certificate:overlay.MemberCertificate = engine.validator.FastSyncMemberCertificate;
engine.validator.collatorNodeWhitelist enabled:Bool adnl_ids:(vector int256) = engine.validator.CollatorNodeWhitelist;
engine.validator.extraConfig state_serializer_enabled:Bool fast_sync_member_certificates:(vector engine.validator.fastSyncMemberCertificate)
= engine.validator.ExtraConfig;
collator_node_whitelist:engine.validator.collatorNodeWhitelist = engine.validator.ExtraConfig;
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
dht:(vector engine.dht)
validators:(vector engine.validator) collators:(vector engine.collator)
@ -670,11 +671,10 @@ engine.validator.collatorOptions
dispatch_phase_2_max_per_initiator:int dispatch_phase_3_max_per_initiator:int
whitelist:(vector string) prioritylist:(vector string) = engine.validator.CollatorOptions;
engine.validator.collatorsList.collator adnl_id:int256 trusted:Bool = engine.validator.collatorsList.Collator;
engine.validator.collatorsList.collator adnl_id:int256 = engine.validator.collatorsList.Collator;
engine.validator.collatorsList.shard shard_id:tonNode.shardId collators:(vector engine.validator.collatorsList.collator)
= engine.validator.collatorsList.Shard;
engine.validator.collatorsList self_collate:Bool use_config_41:Bool shards:(vector engine.validator.collatorsList.shard)
= engine.validator.CollatorsList;
self_collate:Bool select_mode:string = engine.validator.collatorsList.Shard;
engine.validator.collatorsList shards:(vector engine.validator.collatorsList.shard) = engine.validator.CollatorsList;
---functions---
---types---
@ -740,6 +740,11 @@ engine.validator.perfTimerStats stats:(vector engine.validator.PerfTimerStatsByN
engine.validator.shardOutQueueSize size:long = engine.validator.ShardOutQueueSize;
engine.validator.collationManagerStats.shard shard_id:tonNode.shardId self_collate:Bool select_mode:string active:Bool collators:(vector int256) = engine.validator.collationManagerStats.Shard;
engine.validator.collationManagerStats.collator adnl_id:int256 active:Bool alive:Bool ping_in:double = engine.validator.collationManagerStats.Collator;
engine.validator.collationManagerStats.localId adnl_id:int256 shards:(vector engine.validator.collationManagerStats.shard)
collators:(vector engine.validator.collationManagerStats.collator) = engine.validator.collationManagerStats.LocalId;
engine.validator.collationManagerStats local_ids:(vector engine.validator.collationManagerStats.localId) = engine.validator.CollationManagerStats;
---functions---
@ -811,8 +816,14 @@ engine.validator.addShard shard:tonNode.shardId = engine.validator.Success;
engine.validator.delCollator adnl_id:int256 shard:tonNode.shardId = engine.validator.Success;
engine.validator.delShard shard:tonNode.shardId = engine.validator.Success;
engine.validator.collatorNodeSetWhitelistedValidator adnl_id:int256 add:Bool = engine.validator.Success;
engine.validator.collatorNodeSetWhitelistEnabled enabled:Bool = engine.validator.Success;
engine.validator.showCollatorNodeWhitelist = engine.validator.CollatorNodeWhitelist;
engine.validator.setCollatorsList list:engine.validator.collatorsList = engine.validator.Success;
engine.validator.clearCollatorsList = engine.validator.Success;
engine.validator.showCollatorsList = engine.validator.CollatorsList;
engine.validator.getCollationManagerStats = engine.validator.CollationManagerStats;
engine.validator.signOverlayMemberCertificate sign_by:int256 adnl_id:int256 slot:int expire_at:int = overlay.MemberCertificate;
engine.validator.importFastSyncMemberCertificate adnl_id:int256 certificate:overlay.MemberCertificate = engine.validator.Success;
@ -887,8 +898,8 @@ validatorSession.stats success:Bool id:tonNode.blockIdExt timestamp:double self:
collatorNode.candidate source:PublicKey id:tonNode.blockIdExt data:bytes collated_data:bytes = collatorNode.Candidate;
collatorNode.compressedCandidate flags:# source:PublicKey id:tonNode.blockIdExt decompressed_size:int data:bytes = collatorNode.Candidate;
collatorNode.generateBlockSuccess candidate:collatorNode.Candidate = collatorNode.GenerateBlockResult;
collatorNode.generateBlockError code:int message:string = collatorNode.GenerateBlockResult;
collatorNode.pong flags:# = collatorNode.Pong;
collatorNode.error code:int message:string = collatorNode.Error;
validatorSession.newValidatorGroupStats.node id:int256 weight:long = validatorSession.newValidatorGroupStats.Node;
validatorSession.newValidatorGroupStats session_id:int256 workchain:int shard:long cc_seqno:int
@ -901,7 +912,8 @@ validatorSession.endValidatorGroupStats session_id:int256 timestamp:double
---functions---
collatorNode.generateBlock shard:tonNode.shardId cc_seqno:int prev_blocks:(vector tonNode.blockIdExt)
creator:int256 = collatorNode.GenerateBlockResult;
creator:int256 = collatorNode.Candidate;
collatorNode.ping flags:# = collatorNode.Pong;
---types---

Binary file not shown.

View file

@ -62,7 +62,8 @@ enum GlobalCapabilities {
capShortDequeue = 32,
capStoreOutMsgQueueSize = 64,
capMsgMetadata = 128,
capDeferMessages = 256
capDeferMessages = 256,
capFullCollatedData = 512
};
inline int shard_pfx_len(ShardId shard) {

View file

@ -1582,6 +1582,92 @@ td::Status DelShardQuery::receive(td::BufferSlice data) {
return td::Status::OK();
}
td::Status CollatorNodeAddWhitelistedValidatorQuery::run() {
TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<ton::PublicKeyHash>());
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status CollatorNodeAddWhitelistedValidatorQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_collatorNodeSetWhitelistedValidator>(
adnl_id_.bits256_value(), true);
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status CollatorNodeAddWhitelistedValidatorQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "success\n";
return td::Status::OK();
}
td::Status CollatorNodeDelWhitelistedValidatorQuery::run() {
TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<ton::PublicKeyHash>());
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status CollatorNodeDelWhitelistedValidatorQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_collatorNodeSetWhitelistedValidator>(
adnl_id_.bits256_value(), false);
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status CollatorNodeDelWhitelistedValidatorQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "success\n";
return td::Status::OK();
}
td::Status CollatorNodeEnableWhitelistQuery::run() {
TRY_RESULT(value, tokenizer_.get_token<int>());
if (value != 0 && value != 1) {
return td::Status::Error("expected 0 or 1");
}
TRY_STATUS(tokenizer_.check_endl());
enabled_ = value;
return td::Status::OK();
}
td::Status CollatorNodeEnableWhitelistQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_collatorNodeSetWhitelistEnabled>(enabled_);
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status CollatorNodeEnableWhitelistQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "success\n";
return td::Status::OK();
}
td::Status CollatorNodeShowWhitelistQuery::run() {
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status CollatorNodeShowWhitelistQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_showCollatorNodeWhitelist>();
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status CollatorNodeShowWhitelistQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f,
ton::fetch_tl_object<ton::ton_api::engine_validator_collatorNodeWhitelist>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "Collator node whitelist: " << (f->enabled_ ? "ENABLED" : "DISABLED") << "\n";
td::TerminalIO::out() << f->adnl_ids_.size() << " validator adnl ids\n";
for (const auto &id : f->adnl_ids_) {
td::TerminalIO::out() << id.to_hex() << "\n";
}
return td::Status::OK();
}
td::Status SetCollatorsListQuery::run() {
TRY_RESULT_ASSIGN(file_name_, tokenizer_.get_token<std::string>());
TRY_STATUS(tokenizer_.check_endl());
@ -1611,9 +1697,7 @@ td::Status ClearCollatorsListQuery::run() {
}
td::Status ClearCollatorsListQuery::send() {
auto list = ton::create_tl_object<ton::ton_api::engine_validator_collatorsList>();
list->self_collate_ = true;
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_setCollatorsList>(std::move(list));
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_clearCollatorsList>();
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
@ -1640,20 +1724,60 @@ td::Status ShowCollatorsListQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(list, ton::fetch_tl_object<ton::ton_api::engine_validator_collatorsList>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "Collators list:\n";
if (list->self_collate_) {
td::TerminalIO::out() << "self_collate = true\n";
}
if (list->use_config_41_) {
td::TerminalIO::out() << "use_config_41 = true\n";
}
if (list->shards_.empty()) {
td::TerminalIO::out() << "Shard list is empty\n";
return td::Status::OK();
}
for (const auto &shard : list->shards_) {
td::TerminalIO::out() << "Shard " << create_shard_id(shard->shard_id_).to_str() << "\n";
td::TerminalIO::out() << " Self collate = " << shard->self_collate_ << "\n";
td::TerminalIO::out() << " Select mode = " << shard->select_mode_ << "\n";
for (const auto &collator : shard->collators_) {
td::TerminalIO::out() << " Collator " << collator->adnl_id_ << (collator->trusted_ ? " (trusted)" : "") << "\n";
td::TerminalIO::out() << " Collator " << collator->adnl_id_ << "\n";
}
}
return td::Status::OK();
}
td::Status GetCollationManagerStatsQuery::run() {
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status GetCollationManagerStatsQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_getCollationManagerStats>();
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status GetCollationManagerStatsQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(list,
ton::fetch_tl_object<ton::ton_api::engine_validator_collationManagerStats>(data.as_slice(), true),
"received incorrect answer: ");
if (list->local_ids_.empty()) {
td::TerminalIO::out() << "No stats\n";
return td::Status::OK();;
}
for (auto &stats : list->local_ids_) {
td::TerminalIO::out() << "VALIDATOR ADNL ID = " << stats->adnl_id_ << "\n";
std::map<td::Bits256, ton::ton_api::engine_validator_collationManagerStats_collator*> collators;
for (auto &collator: stats->collators_) {
collators[collator->adnl_id_] = collator.get();
}
for (auto &shard : stats->shards_) {
td::TerminalIO::out() << " Shard " << create_shard_id(shard->shard_id_).to_str() << "\n";
td::TerminalIO::out() << " Self collate = " << shard->self_collate_ << "\n";
td::TerminalIO::out() << " Select mode = " << shard->select_mode_ << "\n";
td::TerminalIO::out() << " Active = " << shard->active_ << "\n";
td::TerminalIO::out() << " Collators: " << shard->collators_.size() << "\n";
for (auto &id : shard->collators_) {
auto collator = collators[id];
if (collator == nullptr) {
return td::Status::Error("collator not found");
}
td::TerminalIO::out() << " " << id << " alive=" << (int)collator->alive_
<< " ping_in=" << collator->ping_in_ << "\n";
}
}
}
return td::Status::OK();

View file

@ -1457,6 +1457,91 @@ class DelShardQuery : public Query {
td::int64 shard_;
};
class CollatorNodeAddWhitelistedValidatorQuery : public Query {
public:
CollatorNodeAddWhitelistedValidatorQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "collatorwhitelistadd";
}
static std::string get_help() {
return "collatorwhitelistadd <adnl_id>\tadd validator adnl id to collator node whitelist";
}
std::string name() const override {
return get_name();
}
private:
ton::PublicKeyHash adnl_id_;
};
class CollatorNodeDelWhitelistedValidatorQuery : public Query {
public:
CollatorNodeDelWhitelistedValidatorQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "collatorwhitelistdel";
}
static std::string get_help() {
return "collatorwhitelistdel <adnl_id>\tremove validator adnl id from collator node whitelist";
}
std::string name() const override {
return get_name();
}
private:
ton::PublicKeyHash adnl_id_;
};
class CollatorNodeEnableWhitelistQuery : public Query {
public:
CollatorNodeEnableWhitelistQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "collatorwhitelistenable";
}
static std::string get_help() {
return "collatorwhitelistenable <value>\tenable or disable collator node whiltelist (value is 0 or 1)";
}
std::string name() const override {
return get_name();
}
private:
bool enabled_;
};
class CollatorNodeShowWhitelistQuery : public Query {
public:
CollatorNodeShowWhitelistQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "collatorwhitelistshow";
}
static std::string get_help() {
return "collatorwhitelistshow\tshow collator node whitelist";
}
std::string name() const override {
return get_name();
}
};
class SetCollatorsListQuery : public Query {
public:
SetCollatorsListQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
@ -1517,6 +1602,25 @@ class ShowCollatorsListQuery : public Query {
}
};
class GetCollationManagerStatsQuery : public Query {
public:
GetCollationManagerStatsQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "collationmanagerstats";
}
static std::string get_help() {
return "collationmanagerstats\tshow stats of collation manager";
}
std::string name() const override {
return get_name();
}
};
class SignOverlayMemberCertificateQuery : public Query {
public:
SignOverlayMemberCertificateQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)

View file

@ -157,9 +157,14 @@ void ValidatorEngineConsole::run() {
add_query_runner(std::make_unique<QueryRunnerImpl<AddShardQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<DelShardQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<DelCollatorQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CollatorNodeAddWhitelistedValidatorQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CollatorNodeDelWhitelistedValidatorQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CollatorNodeEnableWhitelistQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<CollatorNodeShowWhitelistQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<SetCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ClearCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ShowCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<GetCollationManagerStatsQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<SignOverlayMemberCertificateQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ImportFastSyncMemberCertificateQuery>>());
}

View file

@ -75,6 +75,7 @@
#include "common/delay.h"
#include "block/precompiled-smc/PrecompiledSmartContract.h"
#include "interfaces/validator-manager.h"
#include "tl-utils/lite-utils.hpp"
#if TON_USE_JEMALLOC
#include <jemalloc/jemalloc.h>
@ -147,9 +148,9 @@ Config::Config(const ton::ton_api::engine_validator_config &config) {
}
}
for (auto &col : config.collators_) {
auto key = ton::PublicKeyHash{col->adnl_id_};
auto id = ton::adnl::AdnlNodeIdShort{col->adnl_id_};
ton::ShardIdFull shard = ton::create_shard_id(col->shard_);
config_add_collator(key, shard).ensure();
config_add_collator(id, shard).ensure();
}
config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure();
@ -175,6 +176,12 @@ Config::Config(const ton::ton_api::engine_validator_config &config) {
fast_sync_member_certificates.emplace_back(adnl_id, std::move(certificate));
}
}
if (config.extraconfig_->collator_node_whitelist_) {
collator_node_whiltelist_enabled = config.extraconfig_->collator_node_whitelist_->enabled_;
for (const auto& id : config.extraconfig_->collator_node_whitelist_->adnl_ids_) {
collator_node_whitelist.emplace(id);
}
}
} else {
state_serializer_enabled = true;
}
@ -242,9 +249,11 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_collator>> col_vec;
for (auto &col : collators) {
col_vec.push_back(
ton::create_tl_object<ton::ton_api::engine_collator>(col.adnl_id.tl(), ton::create_tl_shard_id(col.shard)));
for (auto &[col, shards] : collators) {
for (auto &shard : shards) {
col_vec.push_back(
ton::create_tl_object<ton::ton_api::engine_collator>(col.bits256_value(), ton::create_tl_shard_id(shard)));
}
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
@ -263,8 +272,17 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
full_node_config_obj = full_node_config.tl();
}
ton::tl_object_ptr<ton::ton_api::engine_validator_collatorNodeWhitelist> collator_node_whitelist_obj = {};
if (collator_node_whiltelist_enabled || !collator_node_whitelist.empty()) {
collator_node_whitelist_obj = ton::create_tl_object<ton::ton_api::engine_validator_collatorNodeWhitelist>();
collator_node_whitelist_obj->enabled_ = collator_node_whiltelist_enabled;
for (const auto& id : collator_node_whitelist) {
collator_node_whitelist_obj->adnl_ids_.push_back(id.bits256_value());
}
}
ton::tl_object_ptr<ton::ton_api::engine_validator_extraConfig> extra_config_obj = {};
if (!state_serializer_enabled || !fast_sync_member_certificates.empty()) {
if (!state_serializer_enabled || !fast_sync_member_certificates.empty() || collator_node_whitelist_obj) {
// Non-default values
extra_config_obj = ton::create_tl_object<ton::ton_api::engine_validator_extraConfig>();
extra_config_obj->state_serializer_enabled_ = state_serializer_enabled;
@ -273,6 +291,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
ton::create_tl_object<ton::ton_api::engine_validator_fastSyncMemberCertificate>(adnl_id.bits256_value(),
certificate.tl()));
}
extra_config_obj->collator_node_whitelist_ = std::move(collator_node_whitelist_obj);
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_liteServer>> liteserver_vec;
@ -448,28 +467,28 @@ td::Result<bool> Config::config_add_validator_adnl_id(ton::PublicKeyHash perm_ke
}
}
td::Result<bool> Config::config_add_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard) {
td::Result<bool> Config::config_add_collator(ton::adnl::AdnlNodeIdShort addr, ton::ShardIdFull shard) {
if (!shard.is_valid_ext()) {
return td::Status::Error(PSTRING() << "invalid shard: " << shard.to_str());
}
Collator c{addr, shard};
if (std::find(collators.begin(), collators.end(), c) != collators.end()) {
auto& shards = collators[addr];
if (std::ranges::find(shards, shard) != collators[addr].end()) {
return false;
}
collators.push_back(c);
shards.push_back(shard);
return true;
}
td::Result<bool> Config::config_del_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard) {
td::Result<bool> Config::config_del_collator(ton::adnl::AdnlNodeIdShort addr, ton::ShardIdFull shard) {
if (!shard.is_valid_ext()) {
return td::Status::Error(PSTRING() << "invalid shard: " << shard.to_str());
}
Collator c{addr, shard};
auto it = std::find(collators.begin(), collators.end(), c);
if (it == collators.end()) {
auto& shards = collators[addr];
auto it = std::ranges::find(shards, shard);
if (it == shards.end()) {
return false;
}
collators.erase(it);
shards.erase(it);
return true;
}
@ -1564,6 +1583,11 @@ td::Status ValidatorEngine::load_global_config() {
}
validator_options_.write().set_fast_state_serializer_enabled(fast_state_serializer_enabled_);
for (auto& id : config_.collator_node_whitelist) {
validator_options_.write().set_collator_node_whitelisted_validator(id, true);
}
validator_options_.write().set_collator_node_whitelist_enabled(config_.collator_node_whiltelist_enabled);
return td::Status::OK();
}
@ -1572,14 +1596,16 @@ void ValidatorEngine::set_shard_check_function() {
validator_options_.write().set_shard_check_function([](ton::ShardIdFull shard) -> bool { return true; });
} else {
std::vector<ton::ShardIdFull> shards = {ton::ShardIdFull(ton::masterchainId)};
for (const auto& c : config_.collators) {
shards.push_back(c.shard);
for (const auto& [_, collator_shards] : config_.collators) {
for (const auto& shard : collator_shards) {
shards.push_back(shard);
}
}
for (const auto& s : config_.shards_to_monitor) {
shards.push_back(s);
}
std::sort(shards.begin(), shards.end());
shards.erase(std::unique(shards.begin(), shards.end()), shards.end());
shards.erase(std::ranges::unique(shards).begin(), shards.end());
validator_options_.write().set_shard_check_function(
[shards = std::move(shards)](ton::ShardIdFull shard) -> bool {
for (auto s : shards) {
@ -1613,8 +1639,13 @@ void ValidatorEngine::load_collators_list() {
return;
}
td::Ref<ton::validator::CollatorsList> list{true};
list.write().unpack(*collators_list_);
validator_options_.write().set_collators_list(std::move(list));
S = list.write().unpack(*collators_list_);
if (S.is_ok()) {
validator_options_.write().set_collators_list(std::move(list));
} else {
LOG(ERROR) << "Invalid collators list: " << S.move_as_error();
collators_list_ = {};
}
}
void ValidatorEngine::load_empty_local_config(td::Promise<td::Unit> promise) {
@ -2100,9 +2131,8 @@ void ValidatorEngine::start_full_node() {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_permanent_key, v.first,
[](td::Unit) {});
}
for (auto &c : config_.collators) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_collator_adnl_id,
ton::adnl::AdnlNodeIdShort(c.adnl_id));
for (auto &[c, _] : config_.collators) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_collator_adnl_id, c);
}
for (auto &x : config_.fast_sync_member_certificates) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::import_fast_sync_member_certificate,
@ -2139,9 +2169,10 @@ void ValidatorEngine::started_lite_server() {
}
void ValidatorEngine::start_collator() {
for (auto &c : config_.collators) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator,
ton::adnl::AdnlNodeIdShort(c.adnl_id), c.shard);
for (auto& [id, shards] : config_.collators) {
for (auto& shard : shards) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator, id, shard);
}
}
started_collator();
@ -4054,6 +4085,92 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setCollat
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_collatorNodeSetWhitelistedValidator &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
ton::adnl::AdnlNodeIdShort adnl_id{query.adnl_id_};
if (query.add_) {
if (!config_.collator_node_whitelist.insert(adnl_id).second) {
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
return;
}
} else {
if (config_.collator_node_whitelist.erase(adnl_id) == 0) {
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
return;
}
}
validator_options_.write().set_collator_node_whitelisted_validator(adnl_id, query.add_);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
} else {
promise.set_value(
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
}
});
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_collatorNodeSetWhitelistEnabled &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
if (config_.collator_node_whiltelist_enabled == query.enabled_) {
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_success>());
return;
}
config_.collator_node_whiltelist_enabled = query.enabled_;
validator_options_.write().set_collator_node_whitelist_enabled(query.enabled_);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
} else {
promise.set_value(
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
}
});
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_showCollatorNodeWhitelist &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_default)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
ton::tl_object_ptr<ton::ton_api::engine_validator_collatorNodeWhitelist> result = {};
result = ton::create_tl_object<ton::ton_api::engine_validator_collatorNodeWhitelist>();
result->enabled_ = config_.collator_node_whiltelist_enabled;
for (const auto &id : config_.collator_node_whitelist) {
result->adnl_ids_.push_back(id.bits256_value());
}
promise.set_value(ton::serialize_tl_object(result, true));
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getCollatorOptionsJson &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
@ -4107,16 +4224,44 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setCollat
return;
}
td::Ref<ton::validator::CollatorsList> list{true};
auto S = list.write().unpack(*query.list_);
if (S.is_error()) {
promise.set_value(create_control_query_error(S.move_as_error_prefix("Invalid collators list: ")));
return;
}
auto s = td::json_encode<std::string>(td::ToJson(*query.list_), true);
auto S = td::write_file(collators_list_file(), s);
S = td::write_file(collators_list_file(), s);
if (S.is_error()) {
promise.set_value(create_control_query_error(std::move(S)));
return;
}
collators_list_ = std::move(query.list_);
validator_options_.write().set_collators_list(std::move(list));
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_clearCollatorsList &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
auto S = td::unlink(collators_list_file());
if (S.is_error()) {
promise.set_value(create_control_query_error(std::move(S)));
return;
}
collators_list_ = std::move(query.list_);
td::Ref<ton::validator::CollatorsList> list{true};
list.write().unpack(*collators_list_);
td::Ref<ton::validator::CollatorsList> list{true, ton::validator::CollatorsList::default_list()};
collators_list_ = {};
validator_options_.write().set_collators_list(std::move(list));
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
@ -4136,12 +4281,33 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_showColla
if (collators_list_) {
promise.set_value(ton::serialize_tl_object(collators_list_, true));
} else {
auto list = ton::create_tl_object<ton::ton_api::engine_validator_collatorsList>();
list->self_collate_ = true;
promise.set_value(ton::serialize_tl_object(list, true));
promise.set_value(create_control_query_error(td::Status::Error("collators list is empty")));
}
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_getCollationManagerStats &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_default)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
td::actor::send_closure(
validator_manager_, &ton::validator::ValidatorManagerInterface::get_collation_manager_stats,
[promise = std::move(promise)](
td::Result<ton::tl_object_ptr<ton::ton_api::engine_validator_collationManagerStats>> R) mutable {
if (R.is_ok()) {
promise.set_value(ton::serialize_tl_object(R.move_as_ok(), true));
} else {
promise.set_value(create_control_query_error(R.move_as_error()));
}
});
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollator &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
@ -4154,7 +4320,7 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollat
return;
}
auto id = ton::PublicKeyHash{query.adnl_id_};
auto id = ton::adnl::AdnlNodeIdShort{query.adnl_id_};
auto shard = ton::create_shard_id(query.shard_);
auto R = config_.config_add_collator(id, shard);
if (R.is_error()) {
@ -4169,12 +4335,10 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addCollat
if (!validator_manager_.empty()) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator,
ton::adnl::AdnlNodeIdShort(id), shard);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator, id, shard);
}
if (!full_node_.empty()) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_collator_adnl_id,
ton::adnl::AdnlNodeIdShort(id));
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_collator_adnl_id, id);
}
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
@ -4229,7 +4393,7 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delCollat
return;
}
auto id = ton::PublicKeyHash{query.adnl_id_};
auto id = ton::adnl::AdnlNodeIdShort{query.adnl_id_};
auto shard = ton::create_shard_id(query.shard_);
auto R = config_.config_del_collator(id, shard);
if (R.is_error()) {
@ -4248,12 +4412,10 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delCollat
if (!validator_manager_.empty()) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options,
validator_options_);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_collator,
ton::adnl::AdnlNodeIdShort(id), shard);
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_collator, id, shard);
}
if (!full_node_.empty()) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::del_collator_adnl_id,
ton::adnl::AdnlNodeIdShort(id));
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::del_collator_adnl_id, id);
}
write_config([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
@ -4318,7 +4480,7 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_signOverl
int expire_at = query.expire_at_;
td::actor::send_closure(
keyring_, &ton::keyring::Keyring::get_public_key, public_key_hash,
[=, promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
[=, keyring = keyring_.get(), promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
return;
@ -4330,7 +4492,7 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_signOverl
return;
}
td::BufferSlice to_sign = certificate.to_sign_data(adnl_id);
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_message, public_key_hash, std::move(to_sign),
td::actor::send_closure(keyring, &ton::keyring::Keyring::sign_message, public_key_hash, std::move(to_sign),
[certificate = std::move(certificate),
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {

View file

@ -67,14 +67,6 @@ struct Config {
ton::UnixTime election_date;
ton::UnixTime expire_at;
};
struct Collator {
ton::PublicKeyHash adnl_id;
ton::ShardIdFull shard;
bool operator==(const Collator& b) const {
return adnl_id == b.adnl_id && shard == b.shard;
}
};
struct Control {
ton::PublicKeyHash key;
std::map<ton::PublicKeyHash, td::uint32> clients;
@ -90,7 +82,9 @@ struct Config {
std::map<ton::PublicKeyHash, AdnlCategory> adnl_ids;
std::set<ton::PublicKeyHash> dht_ids;
std::map<ton::PublicKeyHash, Validator> validators;
std::vector<Collator> collators;
std::map<ton::adnl::AdnlNodeIdShort, std::vector<ton::ShardIdFull>> collators;
bool collator_node_whiltelist_enabled = false;
std::set<ton::adnl::AdnlNodeIdShort> collator_node_whitelist;
ton::PublicKeyHash full_node = ton::PublicKeyHash::zero();
std::vector<FullNodeSlave> full_node_slaves;
std::map<td::int32, ton::PublicKeyHash> full_node_masters;
@ -120,8 +114,8 @@ struct Config {
ton::UnixTime expire_at);
td::Result<bool> config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id,
ton::UnixTime expire_at);
td::Result<bool> config_add_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard);
td::Result<bool> config_del_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard);
td::Result<bool> config_add_collator(ton::adnl::AdnlNodeIdShort addr, ton::ShardIdFull shard);
td::Result<bool> config_del_collator(ton::adnl::AdnlNodeIdShort addr, ton::ShardIdFull shard);
td::Result<bool> config_add_full_node_adnl_id(ton::PublicKeyHash id);
td::Result<bool> config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id);
td::Result<bool> config_add_full_node_master(td::int32 port, ton::PublicKeyHash id);
@ -537,10 +531,21 @@ class ValidatorEngine : public td::actor::Actor {
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_setCollatorOptionsJson &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_collatorNodeSetWhitelistedValidator &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_collatorNodeSetWhitelistEnabled &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_showCollatorNodeWhitelist &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_setCollatorsList &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_clearCollatorsList &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_showCollatorsList &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_getCollationManagerStats &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_signOverlayMemberCertificate &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_importFastSyncMemberCertificate &query, td::BufferSlice data,

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