mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-13 03:32:22 +00:00
Add CollatorNode and make validators request blocks from it
This commit is contained in:
parent
996c23e506
commit
53270a00e6
25 changed files with 577 additions and 33 deletions
|
@ -739,6 +739,10 @@ _ OracleBridgeParams = ConfigParam 71; // Ethereum bridge
|
|||
_ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
|
||||
_ OracleBridgeParams = ConfigParam 73; // Polygon bridge
|
||||
|
||||
// Set of collators: each collator is (workchain:int32 shard:int64 adnl_id:int256)
|
||||
colator_set#a0 collators:(HashmapE 352 Unit) = CollatorSet;
|
||||
_ CollatorSet = ConfigParam 81;
|
||||
|
||||
//
|
||||
// PROOFS
|
||||
//
|
||||
|
|
|
@ -253,6 +253,10 @@ class PublicKey {
|
|||
td::BufferSlice export_as_slice() const;
|
||||
static td::Result<PublicKey> import(td::Slice s);
|
||||
|
||||
bool is_ed25519() const {
|
||||
return pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>();
|
||||
}
|
||||
|
||||
pubkeys::Ed25519 ed25519_value() const {
|
||||
CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>());
|
||||
return pub_key_.get<pubkeys::Ed25519>();
|
||||
|
|
|
@ -572,6 +572,7 @@ engine.dht id:int256 = engine.Dht;
|
|||
engine.validatorTempKey key:int256 expire_at:int = engine.ValidatorTempKey;
|
||||
engine.validatorAdnlAddress id:int256 expire_at:int = engine.ValidatorAdnlAddress;
|
||||
engine.validator id:int256 temp_keys:(vector engine.validatorTempKey) adnl_addrs:(vector engine.validatorAdnlAddress) election_date:int expire_at:int = engine.Validator;
|
||||
engine.collator adnl_id:int256 workchain:int shard:long = engine.Validator;
|
||||
engine.liteServer id:int256 port:int = engine.LiteServer;
|
||||
engine.controlProcess id:int256 permissions:int = engine.ControlProcess;
|
||||
engine.controlInterface id:int256 port:int allowed:(vector engine.controlProcess) = engine.ControlInterface;
|
||||
|
@ -582,7 +583,7 @@ engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNode
|
|||
engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
|
||||
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
|
||||
dht:(vector engine.dht)
|
||||
validators:(vector engine.validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave)
|
||||
validators:(vector engine.Validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave)
|
||||
fullnodemasters:(vector engine.validator.fullNodeMaster)
|
||||
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
|
||||
gc:engine.gc = engine.validator.Config;
|
||||
|
@ -690,6 +691,8 @@ engine.validator.generateBlockCandidate block_id:tonNode.BlockId = db.Candidate;
|
|||
engine.validator.getRequiredBlockCandidates = engine.validator.RequiredBlockCandidates;
|
||||
engine.validator.importBlockCandidate block:db.candidate = engine.validator.Success;
|
||||
|
||||
engine.validator.addCollator adnl_id:int256 workchain:int shard:long = engine.validator.Success;
|
||||
|
||||
---types---
|
||||
|
||||
storage.pong = storage.Pong;
|
||||
|
@ -741,3 +744,10 @@ validatorSession.statsRound timestamp:long producers:(vector validatorSession.st
|
|||
validatorSession.stats id:tonNode.blockId timestamp:long self:int256 creator:int256 total_validators:int total_weight:long
|
||||
signatures:int signatures_weight:long approve_signatures:int approve_signatures_weight:long
|
||||
first_round:int rounds:(vector validatorSession.statsRound) = validatorSession.Stats;
|
||||
|
||||
collatorNode.generateBlockSuccess candidate:db.Candidate = collatorNode.GenerateBlockResult;
|
||||
collatorNode.generateBlockError code:int message:string = collatorNode.GenerateBlockResult;
|
||||
|
||||
---functions---
|
||||
collatorNode.generateBlock workchain:int shard:long min_mc_id:tonNode.blockIdExt prev_blocks:(vector tonNode.blockIdExt)
|
||||
creator:int256 = collatorNode.GenerateBlockResult;
|
Binary file not shown.
|
@ -397,6 +397,9 @@ struct Ed25519_PublicKey {
|
|||
bool operator==(const Ed25519_PublicKey& other) const {
|
||||
return _pubkey == other._pubkey;
|
||||
}
|
||||
bool operator!=(const Ed25519_PublicKey& other) const {
|
||||
return _pubkey != other._pubkey;
|
||||
}
|
||||
bool clear() {
|
||||
_pubkey.set_zero();
|
||||
return true;
|
||||
|
@ -479,4 +482,9 @@ struct ValidatorSessionConfig {
|
|||
static const td::uint32 BLOCK_HASH_COVERS_DATA_FROM_VERSION = 2;
|
||||
};
|
||||
|
||||
struct CollatorNodeDescr {
|
||||
ShardIdFull shard;
|
||||
NodeIdShort adnl_id;
|
||||
};
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -1091,3 +1091,24 @@ td::Status ImportBlockCandidateQuery::receive(td::BufferSlice data) {
|
|||
td::TerminalIO::out() << "successfully imported a block candidate\n";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddCollatorQuery::run() {
|
||||
TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<ton::PublicKeyHash>());
|
||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddCollatorQuery::send() {
|
||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addCollator>(
|
||||
adnl_id_.tl(), wc_, shard_);
|
||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AddCollatorQuery::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() << "successfully added collator\n";
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
|
|
@ -1163,3 +1163,27 @@ class ImportBlockCandidateQuery : public Query {
|
|||
private:
|
||||
std::string file_;
|
||||
};
|
||||
|
||||
class AddCollatorQuery : public Query {
|
||||
public:
|
||||
AddCollatorQuery(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 "addcollator";
|
||||
}
|
||||
static std::string get_help() {
|
||||
return "addcollator <adnl_id> <workchain> <shard>\tadd collator with given adnl_id and shard";
|
||||
}
|
||||
std::string name() const override {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
private:
|
||||
ton::PublicKeyHash adnl_id_;
|
||||
td::int32 wc_;
|
||||
td::int64 shard_;
|
||||
};
|
||||
|
|
|
@ -144,6 +144,7 @@ void ValidatorEngineConsole::run() {
|
|||
add_query_runner(std::make_unique<QueryRunnerImpl<GenerateBlockCandidateQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<GetRequiredBlockCandidatesQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<ImportBlockCandidateQuery>>());
|
||||
add_query_runner(std::make_unique<QueryRunnerImpl<AddCollatorQuery>>());
|
||||
}
|
||||
|
||||
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -125,15 +125,24 @@ Config::Config(ton::ton_api::engine_validator_config &config) {
|
|||
for (auto &dht : config.dht_) {
|
||||
config_add_dht_node(ton::PublicKeyHash{dht->id_}).ensure();
|
||||
}
|
||||
for (auto &val : config.validators_) {
|
||||
auto key = ton::PublicKeyHash{val->id_};
|
||||
config_add_validator_permanent_key(key, val->election_date_, val->expire_at_).ensure();
|
||||
for (auto &temp : val->temp_keys_) {
|
||||
for (auto &v : config.validators_) {
|
||||
ton::ton_api::downcast_call(
|
||||
*v, td::overloaded(
|
||||
[&](ton::ton_api::engine_validator &val) {
|
||||
auto key = ton::PublicKeyHash{val.id_};
|
||||
config_add_validator_permanent_key(key, val.election_date_, val.expire_at_).ensure();
|
||||
for (auto &temp : val.temp_keys_) {
|
||||
config_add_validator_temp_key(key, ton::PublicKeyHash{temp->key_}, temp->expire_at_).ensure();
|
||||
}
|
||||
for (auto &adnl : val->adnl_addrs_) {
|
||||
for (auto &adnl : val.adnl_addrs_) {
|
||||
config_add_validator_adnl_id(key, ton::PublicKeyHash{adnl->id_}, adnl->expire_at_).ensure();
|
||||
}
|
||||
},
|
||||
[&](ton::ton_api::engine_collator &col) {
|
||||
auto key = ton::PublicKeyHash{col.adnl_id_};
|
||||
ton::ShardIdFull shard(col.workchain_, col.shard_);
|
||||
config_add_collator(key, shard).ensure();
|
||||
}));
|
||||
}
|
||||
config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure();
|
||||
|
||||
|
@ -192,7 +201,7 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
dht_vec.push_back(ton::create_tl_object<ton::ton_api::engine_dht>(x.tl()));
|
||||
}
|
||||
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator>> val_vec;
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::engine_Validator>> val_vec;
|
||||
for (auto &val : validators) {
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validatorTempKey>> temp_vec;
|
||||
for (auto &t : val.second.temp_keys) {
|
||||
|
@ -205,6 +214,10 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
|
|||
val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_validator>(
|
||||
val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at));
|
||||
}
|
||||
for (auto &col : collators) {
|
||||
val_vec.push_back(ton::create_tl_object<ton::ton_api::engine_collator>(
|
||||
col.adnl_id.tl(), col.shard.workchain, col.shard.shard));
|
||||
}
|
||||
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::engine_validator_fullNodeSlave>> full_node_slaves_vec;
|
||||
for (auto &x : full_node_slaves) {
|
||||
|
@ -383,6 +396,18 @@ 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) {
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
collators.push_back(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Result<bool> Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) {
|
||||
if (full_node == id) {
|
||||
return false;
|
||||
|
@ -1836,6 +1861,19 @@ void ValidatorEngine::start_lite_server() {
|
|||
}
|
||||
|
||||
void ValidatorEngine::started_lite_server() {
|
||||
start_collator();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
started_collator();
|
||||
}
|
||||
|
||||
void ValidatorEngine::started_collator() {
|
||||
start_control_interface();
|
||||
}
|
||||
|
||||
|
@ -3395,6 +3433,47 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_importBlo
|
|||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
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 id = ton::PublicKeyHash{query.adnl_id_};
|
||||
auto shard = ton::ShardIdFull(query.workchain_, query.shard_);
|
||||
if (!shard.is_valid_ext()) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "invalid shard")));
|
||||
return;
|
||||
}
|
||||
|
||||
auto R = config_.config_add_collator(id, shard);
|
||||
if (R.is_error()) {
|
||||
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||
return;
|
||||
}
|
||||
if (!R.move_as_ok()) {
|
||||
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
|
||||
return;
|
||||
}
|
||||
if (!validator_manager_.empty()) {
|
||||
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::add_collator,
|
||||
ton::adnl::AdnlNodeIdShort(id), shard);
|
||||
}
|
||||
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::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
|
||||
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -66,6 +66,14 @@ 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;
|
||||
|
@ -81,6 +89,7 @@ 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;
|
||||
ton::PublicKeyHash full_node = ton::PublicKeyHash::zero();
|
||||
std::vector<FullNodeSlave> full_node_slaves;
|
||||
std::map<td::int32, ton::PublicKeyHash> full_node_masters;
|
||||
|
@ -104,6 +113,7 @@ 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_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);
|
||||
|
@ -293,6 +303,8 @@ class ValidatorEngine : public td::actor::Actor {
|
|||
void add_lite_server(ton::PublicKeyHash id, td::uint16 port);
|
||||
void start_lite_server();
|
||||
void started_lite_server();
|
||||
void start_collator();
|
||||
void started_collator();
|
||||
|
||||
void add_control_interface(ton::PublicKeyHash id, td::uint16 port);
|
||||
void add_control_process(ton::PublicKeyHash id, td::uint16 port, ton::PublicKeyHash pub, td::int32 permissions);
|
||||
|
@ -419,6 +431,8 @@ 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_importBlockCandidate &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
void run_control_query(ton::ton_api::engine_validator_addCollator &query, td::BufferSlice data,
|
||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||
template <class T>
|
||||
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
|
|
|
@ -53,6 +53,7 @@ set(VALIDATOR_HEADERS
|
|||
|
||||
import-db-slice.hpp
|
||||
|
||||
collator-node.hpp
|
||||
manager-disk.h
|
||||
manager-disk.hpp
|
||||
manager-init.h
|
||||
|
@ -68,6 +69,7 @@ set(VALIDATOR_HEADERS
|
|||
set(VALIDATOR_SOURCE
|
||||
apply-block.cpp
|
||||
block-handle.cpp
|
||||
collator-node.cpp
|
||||
get-next-key-blocks.cpp
|
||||
import-db-slice.cpp
|
||||
shard-client.cpp
|
||||
|
|
145
validator/collator-node.cpp
Normal file
145
validator/collator-node.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "collator-node.hpp"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "fabric.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
CollatorNode::CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp)
|
||||
: local_id_(local_id), manager_(std::move(manager)), adnl_(std::move(adnl)), rldp_(std::move(rldp)) {
|
||||
}
|
||||
|
||||
void CollatorNode::start_up() {
|
||||
class Cb : public adnl::Adnl::Callback {
|
||||
public:
|
||||
Cb(td::actor::ActorId<CollatorNode> id) : id_(std::move(id)) {
|
||||
}
|
||||
void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override {
|
||||
}
|
||||
void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &CollatorNode::receive_query, src, std::move(data), std::move(promise));
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<CollatorNode> id_;
|
||||
};
|
||||
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id_,
|
||||
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID),
|
||||
std::make_unique<Cb>(actor_id(this)));
|
||||
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
|
||||
}
|
||||
|
||||
void CollatorNode::tear_down() {
|
||||
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id_,
|
||||
adnl::Adnl::int_to_bytestring(ton_api::collatorNode_generateBlock::ID));
|
||||
}
|
||||
|
||||
void CollatorNode::add_shard(ShardIdFull shard) {
|
||||
LOG(INFO) << "Collator node: local_id=" << local_id_ << " , shard=" << shard.to_str();
|
||||
shards_.push_back(shard);
|
||||
}
|
||||
|
||||
static td::BufferSlice serialize_error(td::Status error) {
|
||||
return create_serialize_tl_object<ton_api::collatorNode_generateBlockError>(error.code(), error.message().c_str());
|
||||
}
|
||||
|
||||
void CollatorNode::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto status = [&]() -> td::Status {
|
||||
TRY_RESULT(f, fetch_tl_object<ton_api::collatorNode_generateBlock>(std::move(data), true));
|
||||
ShardIdFull shard(f->workchain_, f->shard_);
|
||||
if (!shard.is_valid_ext()) {
|
||||
return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str());
|
||||
}
|
||||
bool found = false;
|
||||
for (ShardIdFull our_shard : shards_) {
|
||||
if (shard_is_ancestor(shard, our_shard)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return td::Status::Error(PSTRING() << "this node doesn't collate shard " << shard.to_str());
|
||||
}
|
||||
if (f->prev_blocks_.size() != 1 && f->prev_blocks_.size() != 2) {
|
||||
return td::Status::Error(PSTRING() << "invalid size of prev_blocks: " << f->prev_blocks_.size());
|
||||
}
|
||||
std::vector<BlockIdExt> prev_blocks;
|
||||
for (const auto& b : f->prev_blocks_) {
|
||||
prev_blocks.push_back(create_block_id(b));
|
||||
}
|
||||
BlockIdExt min_mc_id = create_block_id(f->min_mc_id_);
|
||||
Ed25519_PublicKey creator(f->creator_);
|
||||
|
||||
LOG(INFO) << "Query from " << src << ": shard=" << shard.to_str() << ", min_mc_id=" << min_mc_id.to_str();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([=, SelfId = actor_id(this), prev_blocks = std::move(prev_blocks),
|
||||
promise = std::move(promise)](td::Result<td::Ref<ShardState>> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "Query from " << src << ", error: " << R.error();
|
||||
promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
|
||||
} else {
|
||||
td::Ref<MasterchainState> state(R.move_as_ok());
|
||||
if (state.is_null()) {
|
||||
LOG(WARNING) << "Query from " << src << ", error: failed to get masterchain state";
|
||||
promise.set_result(serialize_error(R.move_as_error_prefix("failed to get masterchain state: ")));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(SelfId, &CollatorNode::receive_query_cont, src, shard, std::move(state),
|
||||
std::move(prev_blocks), creator, std::move(promise));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, min_mc_id, 1, td::Timestamp::in(5.0),
|
||||
std::move(P));
|
||||
return td::Status::OK();
|
||||
}();
|
||||
if (status.is_error()) {
|
||||
LOG(WARNING) << "Query from " << src << ", error: " << status;
|
||||
promise.set_result(serialize_error(std::move(status)));
|
||||
}
|
||||
}
|
||||
|
||||
void CollatorNode::receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard,
|
||||
td::Ref<MasterchainState> min_mc_state, std::vector<BlockIdExt> prev_blocks,
|
||||
Ed25519_PublicKey creator, td::Promise<td::BufferSlice> promise) {
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise), src](td::Result<BlockCandidate> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "Query from " << src << ", error: " << R.error();
|
||||
promise.set_result(serialize_error(R.move_as_error()));
|
||||
} else {
|
||||
LOG(INFO) << "Query from " << src << ", success";
|
||||
auto block = R.move_as_ok();
|
||||
auto result = create_serialize_tl_object<ton_api::collatorNode_generateBlockSuccess>(
|
||||
create_tl_object<ton_api::db_candidate>(PublicKey{pubkeys::Ed25519{block.pubkey.as_bits256()}}.tl(),
|
||||
create_tl_block_id(block.id), std::move(block.data),
|
||||
std::move(block.collated_data)));
|
||||
promise.set_result(std::move(result));
|
||||
}
|
||||
});
|
||||
|
||||
run_collate_query(shard, min_mc_state->get_block_id(), std::move(prev_blocks), creator,
|
||||
min_mc_state->get_validator_set(shard), manager_, td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
51
validator/collator-node.hpp
Normal file
51
validator/collator-node.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "interfaces/validator-manager.h"
|
||||
#include "rldp/rldp.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace validator {
|
||||
|
||||
class ValidatorManager;
|
||||
|
||||
class CollatorNode : public td::actor::Actor {
|
||||
public:
|
||||
CollatorNode(adnl::AdnlNodeIdShort local_id, td::actor::ActorId<ValidatorManager> manager,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp);
|
||||
void start_up() override;
|
||||
void tear_down() override;
|
||||
void add_shard(ShardIdFull shard);
|
||||
|
||||
private:
|
||||
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
void receive_query_cont(adnl::AdnlNodeIdShort src, ShardIdFull shard, td::Ref<MasterchainState> min_mc_state,
|
||||
std::vector<BlockIdExt> prev_blocks, Ed25519_PublicKey creator,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
|
||||
adnl::AdnlNodeIdShort local_id_;
|
||||
td::actor::ActorId<ValidatorManager> manager_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
td::actor::ActorId<rldp::Rldp> rldp_;
|
||||
std::vector<ShardIdFull> shards_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
|
@ -364,7 +364,8 @@ td::Status MasterchainStateQ::mc_init() {
|
|||
td::Status MasterchainStateQ::mc_reinit() {
|
||||
auto res = block::ConfigInfo::extract_config(
|
||||
root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks);
|
||||
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks |
|
||||
block::ConfigInfo::needWorkchainInfo);
|
||||
cur_validators_.reset();
|
||||
next_validators_.reset();
|
||||
if (res.is_error()) {
|
||||
|
@ -510,6 +511,27 @@ bool MasterchainStateQ::check_old_mc_block_id(const ton::BlockIdExt& blkid, bool
|
|||
return config_ && config_->check_old_mc_block_id(blkid, strict);
|
||||
}
|
||||
|
||||
std::vector<CollatorNodeDescr> MasterchainStateQ::get_collator_set() const {
|
||||
block::gen::CollatorSet::Record rec;
|
||||
auto cell = config_->get_config_param(81);
|
||||
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
|
||||
return {};
|
||||
}
|
||||
vm::Dictionary dict{rec.collators->prefetch_ref(), 32 + 64 + 256};
|
||||
std::vector<CollatorNodeDescr> collators;
|
||||
dict.check_for_each([&](Ref<vm::CellSlice>, td::ConstBitPtr key, int n) {
|
||||
CHECK(n == 32 + 64 + 256);
|
||||
auto workchain = (td::int32)key.get_int(32);
|
||||
key.advance(32);
|
||||
td::uint64 shard = key.get_uint(64);
|
||||
key.advance(64);
|
||||
td::Bits256 adnl_id(key);
|
||||
collators.push_back({ShardIdFull(workchain, shard), adnl_id});
|
||||
return true;
|
||||
});
|
||||
return collators;
|
||||
}
|
||||
|
||||
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
|
||||
if (!config_) {
|
||||
return 0;
|
||||
|
|
|
@ -147,6 +147,10 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
|
|||
return td::make_ref<ConfigHolderQ>(config_);
|
||||
}
|
||||
}
|
||||
block::WorkchainSet get_workchain_list() const override {
|
||||
return config_ ? config_->get_workchain_list() : block::WorkchainSet();
|
||||
}
|
||||
std::vector<CollatorNodeDescr> get_collator_set() const override;
|
||||
|
||||
private:
|
||||
ZeroStateIdExt zerostate_id_;
|
||||
|
|
|
@ -448,7 +448,6 @@ bool ValidateQuery::init_parse() {
|
|||
return reject_query("after_merge value mismatch in block header");
|
||||
}
|
||||
rand_seed_ = extra.rand_seed;
|
||||
created_by_ = extra.created_by;
|
||||
if (created_by_ != extra.created_by) {
|
||||
return reject_query("block candidate "s + id_.to_str() + " has creator " + created_by_.to_hex() +
|
||||
" but the block header contains different value " + extra.created_by.to_hex());
|
||||
|
|
|
@ -81,6 +81,8 @@ class MasterchainState : virtual public ShardState {
|
|||
ton::LogicalTime* end_lt = nullptr) const = 0;
|
||||
virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;
|
||||
virtual td::Result<td::Ref<ConfigHolder>> get_config_holder() const = 0;
|
||||
virtual block::WorkchainSet get_workchain_list() const = 0;
|
||||
virtual std::vector<CollatorNodeDescr> get_collator_set() const = 0;
|
||||
virtual td::Status prepare() {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
|
|
@ -384,6 +384,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
PublicKeyHash local_id_;
|
||||
|
||||
|
|
|
@ -443,6 +443,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
td::Ref<ValidatorManagerOptions> opts_;
|
||||
|
|
|
@ -2025,7 +2025,8 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
|
|||
auto validator_id = get_validator(shard, validator_set);
|
||||
CHECK(!validator_id.is_zero());
|
||||
auto G = td::actor::create_actor<ValidatorGroup>(
|
||||
"validatorgroup", shard, validator_id, session_id, validator_set, opts, keyring_, adnl_, rldp_, overlays_,
|
||||
"validatorgroup", shard, validator_id, session_id, validator_set, last_masterchain_state_->get_collator_set(),
|
||||
opts, keyring_, adnl_, rldp_, overlays_,
|
||||
db_root_, actor_id(this), init_session,
|
||||
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), true);
|
||||
return G;
|
||||
|
@ -2692,6 +2693,15 @@ void ValidatorManagerImpl::cleanup_old_pending_candidates(BlockId block_id, td::
|
|||
}
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) {
|
||||
auto it = collator_nodes_.find(id);
|
||||
if (it == collator_nodes_.end()) {
|
||||
auto actor = td::actor::create_actor<CollatorNode>("collatornode", id, actor_id(this), adnl_, rldp_);
|
||||
it = collator_nodes_.emplace(id, std::move(actor)).first;
|
||||
}
|
||||
td::actor::send_closure(it->second, &CollatorNode::add_shard, shard);
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
||||
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "state-serializer.hpp"
|
||||
#include "rldp/rldp.h"
|
||||
#include "token-manager.h"
|
||||
#include "collator-node.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
@ -539,6 +540,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
|
||||
void wait_block_candidate(BlockId block_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise) override;
|
||||
|
||||
void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override;
|
||||
|
||||
private:
|
||||
td::Timestamp resend_shard_blocks_at_;
|
||||
td::Timestamp check_waiters_at_;
|
||||
|
@ -606,6 +609,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
|
||||
std::map<BlockId, std::vector<std::pair<td::Promise<BlockCandidate>, td::Timestamp>>> pending_block_candidates_;
|
||||
void cleanup_old_pending_candidates(BlockId block_id, td::Timestamp now);
|
||||
|
||||
std::map<adnl::AdnlNodeIdShort, td::actor::ActorOwn<CollatorNode>> collator_nodes_;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -248,9 +248,11 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
|
|||
|
||||
void ShardClient::build_shard_overlays() {
|
||||
auto v = masterchain_state_->get_shards();
|
||||
std::set<WorkchainId> workchains;
|
||||
|
||||
for (auto &x : v) {
|
||||
auto shard = x->shard();
|
||||
workchains.insert(shard.workchain);
|
||||
if (opts_->need_monitor(shard)) {
|
||||
auto d = masterchain_state_->soft_min_split_depth(shard.workchain);
|
||||
auto l = shard_prefix_length(shard.shard);
|
||||
|
@ -264,6 +266,20 @@ void ShardClient::build_shard_overlays() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &wpair : masterchain_state_->get_workchain_list()) {
|
||||
ton::WorkchainId wc = wpair.first;
|
||||
const block::WorkchainInfo *winfo = wpair.second.get();
|
||||
if (workchains.count(wc) == 0 && winfo->active && winfo->enabled_since <= masterchain_state_->get_unix_time()) {
|
||||
auto shard = ShardIdFull(wc);
|
||||
if (opts_->need_monitor(shard) && created_overlays_.count(shard) == 0) {
|
||||
td::actor::send_closure(manager_, &ValidatorManager::subscribe_to_shard, shard);
|
||||
BlockIdExt block_id(shard.workchain, shard.shard, 0, winfo->zerostate_root_hash, winfo->zerostate_file_hash);
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::wait_block_state_short, block_id, 0,
|
||||
td::Timestamp::in(5.0), [](td::Result<td::Ref<ShardState>>) {});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "td/utils/overloaded.h"
|
||||
#include "common/delay.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -36,19 +37,7 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
|
|||
return;
|
||||
}
|
||||
if (lite_mode_) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[promise = std::move(promise),
|
||||
pubkey = Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}](td::Result<BlockCandidate> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
BlockCandidate candidate = R.move_as_ok();
|
||||
candidate.pubkey = pubkey;
|
||||
promise.set_result(std::move(candidate));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_candidate, create_next_block_id_simple(),
|
||||
td::Timestamp::in(15.0), std::move(P));
|
||||
send_collate_query(round_id, td::Timestamp::in(10.0), std::move(promise));
|
||||
return;
|
||||
}
|
||||
run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
|
||||
|
@ -65,6 +54,17 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
|
|||
promise.set_error(td::Status::Error(ErrorCode::notready, "too old"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (approved_candidates_cache_round_ != round_id) {
|
||||
approved_candidates_cache_round_ = round_id;
|
||||
approved_candidates_cache_.clear();
|
||||
}
|
||||
CacheKey cache_key = block_to_cache_key(block);
|
||||
auto it = approved_candidates_cache_.find(cache_key);
|
||||
if (it != approved_candidates_cache_.end()) {
|
||||
promise.set_result(it->second);
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), round_id, block = block.clone(),
|
||||
promise = std::move(promise)](td::Result<ValidateCandidateResult> R) mutable {
|
||||
if (R.is_error()) {
|
||||
|
@ -80,10 +80,15 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
|
|||
td::Timestamp::in(0.1));
|
||||
} else {
|
||||
auto v = R.move_as_ok();
|
||||
v.visit(td::overloaded([&](UnixTime ts) { promise.set_result(ts); },
|
||||
v.visit(td::overloaded(
|
||||
[&](UnixTime ts) {
|
||||
td::actor::send_closure(SelfId, &ValidatorGroup::update_approve_cache, round_id, block_to_cache_key(block),
|
||||
ts);
|
||||
promise.set_result(ts);
|
||||
},
|
||||
[&](CandidateReject reject) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation,
|
||||
PSTRING() << "bad candidate: " << reject.reason));
|
||||
promise.set_error(
|
||||
td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad candidate: " << reject.reason));
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
@ -98,6 +103,14 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
|
|||
td::Timestamp::in(10.0), std::move(P), lite_mode_ ? ValidateMode::lite : 0);
|
||||
}
|
||||
|
||||
void ValidatorGroup::update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value) {
|
||||
if (approved_candidates_cache_round_ != round_id) {
|
||||
approved_candidates_cache_round_ = round_id;
|
||||
approved_candidates_cache_.clear();
|
||||
}
|
||||
approved_candidates_cache_[key] = value;
|
||||
}
|
||||
|
||||
void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,
|
||||
RootHash root_hash, FileHash file_hash,
|
||||
std::vector<BlockSignature> signatures,
|
||||
|
@ -339,6 +352,91 @@ void ValidatorGroup::get_session_info(
|
|||
td::actor::send_closure(session_, &validatorsession::ValidatorSession::get_session_info, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorGroup::send_collate_query(td::uint32 round_id, td::Timestamp timeout,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
adnl::AdnlNodeIdShort collator = adnl::AdnlNodeIdShort::zero();
|
||||
// TODO: some other way for storing and choosing collators for real network
|
||||
int cnt = 0;
|
||||
for (const CollatorNodeDescr& c : collator_set_) {
|
||||
if (shard_is_ancestor(shard_, c.shard) && td::Random::fast(0, cnt) == 0) {
|
||||
collator = adnl::AdnlNodeIdShort(c.adnl_id);
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
if (collator.is_zero()) {
|
||||
promise.set_error(td::Status::Error(PSTRING() << "no collator for shard " << shard_.to_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> prev_blocks;
|
||||
for (const BlockIdExt &p : prev_block_ids_) {
|
||||
prev_blocks.push_back(create_tl_block_id(p));
|
||||
}
|
||||
td::BufferSlice query = create_serialize_tl_object<ton_api::collatorNode_generateBlock>(
|
||||
shard_.workchain, shard_.shard, create_tl_block_id(min_masterchain_block_id_), std::move(prev_blocks),
|
||||
local_id_full_.ed25519_value().raw());
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), round_id, promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("rldp query failed: "));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(SelfId, &ValidatorGroup::receive_collate_query_response, round_id, R.move_as_ok(),
|
||||
std::move(promise));
|
||||
});
|
||||
LOG(INFO) << "collate query for " << shard_.to_str() << ": send query to " << collator;
|
||||
size_t max_answer_size = config_.max_block_size + config_.max_collated_data_size + 256;
|
||||
td::actor::send_closure(rldp_, &rldp::Rldp::send_query_ex, adnl::AdnlNodeIdShort(local_id_), collator, "collatequery",
|
||||
std::move(P), timeout, std::move(query), max_answer_size);
|
||||
}
|
||||
|
||||
void ValidatorGroup::receive_collate_query_response(td::uint32 round_id, td::BufferSlice data,
|
||||
td::Promise<BlockCandidate> promise) {
|
||||
if (round_id < last_known_round_id_) {
|
||||
promise.set_error(td::Status::Error("too old"));
|
||||
return;
|
||||
}
|
||||
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::collatorNode_GenerateBlockResult>(data, true));
|
||||
tl_object_ptr<ton_api::db_candidate> b;
|
||||
ton_api::downcast_call(*f, td::overloaded(
|
||||
[&](ton_api::collatorNode_generateBlockError &r) {
|
||||
td::Status error = td::Status::Error(r.code_, r.message_);
|
||||
promise.set_error(error.move_as_error_prefix("collate query: "));
|
||||
},
|
||||
[&](ton_api::collatorNode_generateBlockSuccess &r) { b = std::move(r.candidate_); }));
|
||||
if (!b) {
|
||||
return;
|
||||
}
|
||||
auto key = PublicKey{b->source_};
|
||||
if (!key.is_ed25519()) {
|
||||
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
|
||||
}
|
||||
auto e_key = Ed25519_PublicKey{key.ed25519_value().raw()};
|
||||
if (e_key != Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}) {
|
||||
promise.set_error(td::Status::Error("collate query: block candidate source mismatch"));
|
||||
return;
|
||||
}
|
||||
auto block_id = ton::create_block_id(b->id_);
|
||||
if (block_id.shard_full() != shard_) {
|
||||
promise.set_error(td::Status::Error("collate query: shard mismatch"));
|
||||
return;
|
||||
}
|
||||
auto collated_data_hash = td::sha256_bits256(b->collated_data_);
|
||||
BlockCandidate candidate(e_key, block_id, collated_data_hash, std::move(b->data_), std::move(b->collated_data_));
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[candidate = candidate.clone(), promise = std::move(promise)](td::Result<UnixTime> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error_prefix("validate received block error: "));
|
||||
return;
|
||||
}
|
||||
promise.set_result(std::move(candidate));
|
||||
});
|
||||
validate_block_candidate(round_id, std::move(candidate), std::move(P));
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
||||
} // namespace ton
|
||||
|
|
|
@ -55,12 +55,14 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
init_ = false;
|
||||
create_session();
|
||||
}
|
||||
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl::AdnlNodeIdShort(local_id_));
|
||||
}
|
||||
|
||||
void get_session_info(td::Promise<tl_object_ptr<ton_api::engine_validator_validatorSessionInfo>> promise);
|
||||
|
||||
ValidatorGroup(ShardIdFull shard, PublicKeyHash local_id, ValidatorSessionId session_id,
|
||||
td::Ref<ValidatorSet> validator_set, validatorsession::ValidatorSessionOptions config,
|
||||
td::Ref<ValidatorSet> validator_set, std::vector<CollatorNodeDescr> collator_set,
|
||||
validatorsession::ValidatorSessionOptions config,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
|
||||
std::string db_root, td::actor::ActorId<ValidatorManager> validator_manager, bool create_session,
|
||||
|
@ -69,6 +71,7 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
, local_id_(std::move(local_id))
|
||||
, session_id_(session_id)
|
||||
, validator_set_(std::move(validator_set))
|
||||
, collator_set_(std::move(collator_set))
|
||||
, config_(std::move(config))
|
||||
, keyring_(keyring)
|
||||
, adnl_(adnl)
|
||||
|
@ -83,6 +86,8 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
|
||||
private:
|
||||
std::unique_ptr<validatorsession::ValidatorSession::Callback> make_validator_session_callback();
|
||||
void send_collate_query(td::uint32 round_id, td::Timestamp timeout, td::Promise<BlockCandidate> promise);
|
||||
void receive_collate_query_response(td::uint32 round_id, td::BufferSlice data, td::Promise<BlockCandidate> promise);
|
||||
|
||||
struct PostponedAccept {
|
||||
RootHash root_hash;
|
||||
|
@ -105,6 +110,7 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
BlockIdExt min_masterchain_block_id_;
|
||||
|
||||
td::Ref<ValidatorSet> validator_set_;
|
||||
std::vector<CollatorNodeDescr> collator_set_;
|
||||
validatorsession::ValidatorSessionOptions config_;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
|
@ -120,6 +126,16 @@ class ValidatorGroup : public td::actor::Actor {
|
|||
bool allow_unsafe_self_blocks_resync_;
|
||||
bool lite_mode_ = false;
|
||||
td::uint32 last_known_round_id_ = 0;
|
||||
|
||||
typedef std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash> CacheKey;
|
||||
std::map<CacheKey, UnixTime> approved_candidates_cache_;
|
||||
td::uint32 approved_candidates_cache_round_ = 0;
|
||||
|
||||
void update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value);
|
||||
|
||||
static CacheKey block_to_cache_key(const BlockCandidate& block) {
|
||||
return std::make_tuple(block.pubkey.as_bits256(), block.id, sha256_bits256(block.data), block.collated_file_hash);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -220,6 +220,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
|||
virtual void generate_block_candidate(BlockId block_id, td::Promise<BlockCandidate> promise) = 0;
|
||||
virtual void get_required_block_candidates(td::Promise<std::vector<BlockId>> promise) = 0;
|
||||
virtual void import_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
virtual void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
Loading…
Reference in a new issue