mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
liteclient signature check support
1. update liteclient/liteserver. Now liteserver sends signatures of blocks and liteclient checks them. I.e. liteclient completely checks received data. 2. validator-engine: more GC options 3. blockchain-explorer: show all block transactions (instead of 256) 4. some bugfixes
This commit is contained in:
parent
d8244eff53
commit
9d6853ef24
58 changed files with 1480 additions and 325 deletions
|
@ -45,7 +45,8 @@ void BlockArchiver::got_block_handle(BlockHandle handle) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!handle_->is_applied() && !handle_->is_archived()) {
|
||||
if (!handle_->is_applied() && !handle_->is_archived() &&
|
||||
(!handle_->inited_is_key_block() || !handle_->is_key_block())) {
|
||||
// no need for this block
|
||||
// probably this block not in final chain
|
||||
// this will eventually delete all associated data
|
||||
|
|
|
@ -142,7 +142,9 @@ void CellDbIn::gc() {
|
|||
}
|
||||
|
||||
void CellDbIn::gc_cont(BlockHandle handle) {
|
||||
CHECK(handle->inited_state_boc());
|
||||
if (!handle->inited_state_boc()) {
|
||||
LOG(WARNING) << "inited_state_boc=false, but state in db. blockid=" << handle->id();
|
||||
}
|
||||
handle->set_deleted_state_boc();
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
|
||||
|
|
|
@ -34,11 +34,14 @@ std::string FileDb::get_file_name(const RefId& ref_id, bool create_dirs) {
|
|||
auto ref_id_hash = get_ref_id_hash(ref_id);
|
||||
|
||||
auto s = ref_id_hash.to_hex();
|
||||
if (create_dirs) {
|
||||
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/").ensure();
|
||||
td::mkdir(root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/").ensure();
|
||||
std::string path = root_path_ + "/files/";
|
||||
for (td::uint32 i = 0; i < depth_; i++) {
|
||||
path = path + s[2 * i] + s[2 * i + 1] + "/";
|
||||
if (create_dirs) {
|
||||
td::mkdir(path).ensure();
|
||||
}
|
||||
}
|
||||
return root_path_ + "/files/" + s[0] + s[1] + "/" + s[2] + s[3] + "/" + s;
|
||||
return path + s;
|
||||
}
|
||||
|
||||
void FileDb::store_file(RefId ref_id, td::BufferSlice data, td::Promise<FileHash> promise) {
|
||||
|
@ -169,8 +172,8 @@ void FileDb::set_block(const RefIdHash& ref, DbEntry entry) {
|
|||
kv_->set(get_key(ref), entry.release()).ensure();
|
||||
}
|
||||
|
||||
FileDb::FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive)
|
||||
: root_db_(root_db), root_path_(root_path), is_archive_(is_archive) {
|
||||
FileDb::FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, td::uint32 depth, bool is_archive)
|
||||
: root_db_(root_db), root_path_(root_path), depth_(depth), is_archive_(is_archive) {
|
||||
}
|
||||
|
||||
void FileDb::start_up() {
|
||||
|
|
|
@ -152,7 +152,7 @@ class FileDb : public td::actor::Actor {
|
|||
void gc();
|
||||
void skip_gc();
|
||||
|
||||
FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, bool is_archive);
|
||||
FileDb(td::actor::ActorId<RootDb> root_db, std::string root_path, td::uint32 depth, bool is_archive);
|
||||
|
||||
private:
|
||||
struct DbEntry {
|
||||
|
@ -187,6 +187,7 @@ class FileDb : public td::actor::Actor {
|
|||
|
||||
std::string root_path_;
|
||||
std::string db_path_;
|
||||
td::uint32 depth_;
|
||||
|
||||
bool is_archive_;
|
||||
|
||||
|
|
|
@ -408,8 +408,9 @@ void RootDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promis
|
|||
void RootDb::start_up() {
|
||||
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
|
||||
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
|
||||
file_db_ = td::actor::create_actor<FileDb>("filedb", actor_id(this), root_path_ + "/files/", false);
|
||||
archive_db_ = td::actor::create_actor<FileDb>("filedbarchive", actor_id(this), root_path_ + "/archive/", true);
|
||||
file_db_ = td::actor::create_actor<FileDb>("filedb", actor_id(this), root_path_ + "/files/", depth_, false);
|
||||
archive_db_ =
|
||||
td::actor::create_actor<FileDb>("filedbarchive", actor_id(this), root_path_ + "/archive/", depth_, true);
|
||||
lt_db_ = td::actor::create_actor<LtDb>("ltdb", actor_id(this), root_path_ + "/ltdb/");
|
||||
state_db_ = td::actor::create_actor<StateDb>("statedb", actor_id(this), root_path_ + "/state/");
|
||||
static_files_db_ = td::actor::create_actor<StaticFilesDb>("staticfilesdb", actor_id(this), root_path_ + "/static/");
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace validator {
|
|||
class RootDb : public Db {
|
||||
public:
|
||||
enum class Flags : td::uint32 { f_started = 1, f_ready = 2, f_switched = 4, f_archived = 8 };
|
||||
RootDb(td::actor::ActorId<ValidatorManager> validator_manager, std::string root_path)
|
||||
: validator_manager_(validator_manager), root_path_(std::move(root_path)) {
|
||||
RootDb(td::actor::ActorId<ValidatorManager> validator_manager, std::string root_path, td::uint32 depth)
|
||||
: validator_manager_(validator_manager), root_path_(std::move(root_path)), depth_(depth) {
|
||||
}
|
||||
|
||||
void start_up() override;
|
||||
|
@ -112,6 +112,7 @@ class RootDb : public Db {
|
|||
td::actor::ActorId<ValidatorManager> validator_manager_;
|
||||
|
||||
std::string root_path_;
|
||||
td::uint32 depth_;
|
||||
|
||||
td::actor::ActorOwn<CellDb> cell_db_;
|
||||
td::actor::ActorOwn<BlockDb> block_db_;
|
||||
|
|
|
@ -25,7 +25,8 @@ namespace ton {
|
|||
|
||||
namespace validator {
|
||||
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_);
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_,
|
||||
td::uint32 depth);
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(BlockIdExt block_id, td::BufferSlice data);
|
||||
td::Result<td::Ref<BlockData>> create_block(ReceivedBlock data);
|
||||
|
|
|
@ -671,7 +671,8 @@ void AcceptBlockQuery::got_proof_link(BlockIdExt id, Ref<ProofLink> proof) {
|
|||
// first link in chain
|
||||
if (ancestors_.size() != link_prev_.size() || ancestors_[0]->blk_ != link_prev_[0] ||
|
||||
(ancestors_.size() == 2 && ancestors_[1]->blk_ != link_prev_[1])) {
|
||||
fatal_error("invalid first link at block "s + id.to_str() + " for shardchain block " + id_.to_str());
|
||||
fatal_error("invalid first link at block "s + id.to_str() + " for shardchain block " + id_.to_str(),
|
||||
ErrorCode::cancelled);
|
||||
return;
|
||||
}
|
||||
create_topshard_blk_descr();
|
||||
|
@ -680,7 +681,8 @@ void AcceptBlockQuery::got_proof_link(BlockIdExt id, Ref<ProofLink> proof) {
|
|||
// intermediate link
|
||||
if (link_prev_.size() != 1 || ton::ShardIdFull(link_prev_[0].id) != ton::ShardIdFull(id_) ||
|
||||
link_prev_[0].id.seqno + 1 != id.id.seqno) {
|
||||
fatal_error("invalid intermediate link at block "s + id.to_str() + " for shardchain block " + id_.to_str());
|
||||
fatal_error("invalid intermediate link at block "s + id.to_str() + " for shardchain block " + id_.to_str(),
|
||||
ErrorCode::cancelled);
|
||||
return;
|
||||
}
|
||||
require_proof_link(link_prev_[0]);
|
||||
|
|
|
@ -38,8 +38,9 @@ namespace ton {
|
|||
|
||||
namespace validator {
|
||||
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_) {
|
||||
return td::actor::create_actor<RootDb>("db", manager, db_root_);
|
||||
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_,
|
||||
td::uint32 depth) {
|
||||
return td::actor::create_actor<RootDb>("db", manager, db_root_, depth);
|
||||
}
|
||||
|
||||
td::Result<td::Ref<BlockData>> create_block(BlockIdExt block_id, td::BufferSlice data) {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "vm/dict.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "shard.hpp"
|
||||
#include "validator-set.hpp"
|
||||
#include "signature-set.hpp"
|
||||
#include "fabric.h"
|
||||
#include <ctime>
|
||||
|
||||
|
@ -66,6 +68,14 @@ void LiteQuery::abort_query(td::Status reason) {
|
|||
stop();
|
||||
}
|
||||
|
||||
void LiteQuery::abort_query_ext(td::Status reason, std::string comment) {
|
||||
LOG(INFO) << "aborted liteserver query: " << comment << " : " << reason.to_string();
|
||||
if (promise_) {
|
||||
promise_.set_error(reason.move_as_error_prefix(comment + " : "));
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool LiteQuery::fatal_error(td::Status error) {
|
||||
abort_query(std::move(error));
|
||||
return false;
|
||||
|
@ -167,7 +177,7 @@ void LiteQuery::perform_getTime() {
|
|||
void LiteQuery::perform_getVersion() {
|
||||
LOG(INFO) << "started a getVersion() liteserver query";
|
||||
td::int32 now = static_cast<td::int32>(std::time(nullptr));
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_version>(0, 0x100, 0, now);
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_version>(0, ls_version, ls_capabilities, now);
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
|
@ -279,11 +289,10 @@ void LiteQuery::continue_getBlockHeader(BlockIdExt blkid, int mode, Ref<ton::val
|
|||
// create block header proof
|
||||
RootHash rhash{block_root->get_hash().bits()};
|
||||
CHECK(rhash == blkid.root_hash);
|
||||
auto usage_tree = std::make_shared<vm::CellUsageTree>();
|
||||
auto usage_cell = vm::UsageCell::create(block_root, usage_tree->root_ptr());
|
||||
vm::MerkleProofBuilder mpb{block_root};
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(usage_cell, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
if (!(tlb::unpack_cell(mpb.root(), blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
fatal_error("cannot unpack block header");
|
||||
return;
|
||||
}
|
||||
|
@ -327,12 +336,7 @@ void LiteQuery::continue_getBlockHeader(BlockIdExt blkid, int mode, Ref<ton::val
|
|||
}
|
||||
}
|
||||
}
|
||||
auto proof = vm::MerkleProof::generate(std::move(block_root), usage_tree.get());
|
||||
if (proof.is_null()) {
|
||||
fatal_error("cannot create Merkle proof for block header");
|
||||
return;
|
||||
}
|
||||
auto proof_data = vm::std_boc_serialize(std::move(proof));
|
||||
auto proof_data = mpb.extract_proof_boc();
|
||||
if (proof_data.is_error()) {
|
||||
fatal_error(proof_data.move_as_error());
|
||||
return;
|
||||
|
@ -353,15 +357,27 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
|
|||
fatal_error("cannot request total state: possibly too large");
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::continue_getState, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
if (blkid.id.seqno) {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::continue_getState, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::continue_getZeroState, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void LiteQuery::continue_getState(BlockIdExt blkid, Ref<ton::validator::ShardState> state) {
|
||||
|
@ -380,6 +396,14 @@ void LiteQuery::continue_getState(BlockIdExt blkid, Ref<ton::validator::ShardSta
|
|||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
void LiteQuery::continue_getZeroState(BlockIdExt blkid, td::BufferSlice state) {
|
||||
LOG(INFO) << "obtained data for getZeroState(" << blkid.to_str() << ")";
|
||||
CHECK(!state.empty());
|
||||
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_blockState>(
|
||||
ton::create_tl_lite_block_id(blkid), blkid.root_hash, blkid.file_hash, std::move(state));
|
||||
finish_query(std::move(b));
|
||||
}
|
||||
|
||||
void LiteQuery::perform_sendMessage(td::BufferSlice data) {
|
||||
LOG(INFO) << "started a sendMessage(<" << data.size() << " bytes>) liteserver query";
|
||||
auto res = ton::validator::create_ext_message(std::move(data));
|
||||
|
@ -402,15 +426,42 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
|
|||
}
|
||||
base_blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_data, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_data, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LiteQuery::request_mc_proof(BlockIdExt blkid, int mode) {
|
||||
if (!blkid.is_masterchain() || !blkid.is_valid_full()) {
|
||||
return fatal_error("reference block must belong to the masterchain");
|
||||
}
|
||||
if (!cont_set_) {
|
||||
return fatal_error("continuation not set");
|
||||
}
|
||||
if (mode) {
|
||||
base_blk_id_alt_ = blkid;
|
||||
} else {
|
||||
base_blk_id_ = blkid;
|
||||
}
|
||||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<Proof>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_proof, blkid, mode, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -423,15 +474,16 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) {
|
|||
}
|
||||
base_blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_state, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_mc_block_state, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -453,15 +505,16 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) {
|
|||
}
|
||||
blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_state, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_state, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -474,15 +527,63 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) {
|
|||
}
|
||||
blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_data, blkid,
|
||||
res.move_as_ok());
|
||||
}
|
||||
});
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_data, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LiteQuery::request_proof_link(BlockIdExt blkid) {
|
||||
if (!blkid.is_valid_full()) {
|
||||
return fatal_error("invalid block id requested");
|
||||
}
|
||||
if (!cont_set_) {
|
||||
return fatal_error("continuation not set");
|
||||
}
|
||||
blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ProofLink>> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_block_proof_link, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LiteQuery::request_zero_state(BlockIdExt blkid) {
|
||||
if (!blkid.is_valid_full()) {
|
||||
return fatal_error("invalid block id requested");
|
||||
}
|
||||
if (blkid.seqno()) {
|
||||
return fatal_error("invalid zerostate requested");
|
||||
}
|
||||
if (!cont_set_) {
|
||||
return fatal_error("continuation not set");
|
||||
}
|
||||
blk_id_ = blkid;
|
||||
++pending_;
|
||||
td::actor::send_closure_later(
|
||||
manager_, &ValidatorManager::get_zero_state, blkid,
|
||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
||||
if (res.is_error()) {
|
||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : "));
|
||||
} else {
|
||||
td::actor::send_closure_later(Self, &LiteQuery::got_zero_state, blkid, res.move_as_ok());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -595,6 +696,38 @@ void LiteQuery::got_mc_block_data(BlockIdExt blkid, Ref<BlockData> data) {
|
|||
dec_pending();
|
||||
}
|
||||
|
||||
void LiteQuery::got_mc_block_proof(BlockIdExt blkid, int mode, Ref<Proof> proof) {
|
||||
LOG(INFO) << "obtained data for getBlockProof(" << blkid.to_str() << ") needed by a liteserver query";
|
||||
CHECK(proof.not_null());
|
||||
if (mode) {
|
||||
mc_proof_alt_ = Ref<ProofQ>(std::move(proof));
|
||||
CHECK(mc_proof_alt_.not_null());
|
||||
CHECK(blkid == base_blk_id_alt_);
|
||||
} else {
|
||||
mc_proof_ = Ref<ProofQ>(std::move(proof));
|
||||
CHECK(mc_proof_.not_null());
|
||||
CHECK(blkid == base_blk_id_);
|
||||
}
|
||||
dec_pending();
|
||||
}
|
||||
|
||||
void LiteQuery::got_block_proof_link(BlockIdExt blkid, Ref<ProofLink> proof_link) {
|
||||
LOG(INFO) << "obtained data for getBlockProofLink(" << blkid.to_str() << ") needed by a liteserver query";
|
||||
CHECK(proof_link.not_null());
|
||||
proof_link_ = Ref<ProofLinkQ>(std::move(proof_link));
|
||||
CHECK(proof_link_.not_null());
|
||||
CHECK(blkid == blk_id_);
|
||||
dec_pending();
|
||||
}
|
||||
|
||||
void LiteQuery::got_zero_state(BlockIdExt blkid, td::BufferSlice zerostate) {
|
||||
LOG(INFO) << "obtained data for getZeroState(" << blkid.to_str() << ") needed by a liteserver query";
|
||||
CHECK(!zerostate.empty());
|
||||
buffer_ = std::move(zerostate);
|
||||
CHECK(blkid == blk_id_);
|
||||
dec_pending();
|
||||
}
|
||||
|
||||
void LiteQuery::check_pending() {
|
||||
CHECK(pending_ >= 0);
|
||||
if (!pending_) {
|
||||
|
@ -627,8 +760,11 @@ bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof) {
|
|||
bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof, Ref<ShardStateQ> state, Ref<BlockData> block,
|
||||
const BlockIdExt& blkid) {
|
||||
CHECK(block.not_null() && state.not_null());
|
||||
auto block_root = block->root_cell();
|
||||
auto state_root = state->root_cell();
|
||||
return make_state_root_proof(proof, state->root_cell(), block->root_cell(), blkid);
|
||||
}
|
||||
|
||||
bool LiteQuery::make_state_root_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_root, Ref<vm::Cell> block_root,
|
||||
const BlockIdExt& blkid) {
|
||||
CHECK(block_root.not_null() && state_root.not_null());
|
||||
RootHash rhash{block_root->get_hash().bits()};
|
||||
CHECK(rhash == blkid.root_hash);
|
||||
|
@ -714,6 +850,24 @@ bool LiteQuery::make_shard_info_proof(Ref<vm::Cell>& proof, BlockIdExt& blkid, A
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LiteQuery::make_ancestor_block_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_root, const BlockIdExt& old_blkid) {
|
||||
vm::MerkleProofBuilder mpb{std::move(state_root)};
|
||||
auto rconfig = block::ConfigInfo::extract_config(mpb.root(), block::ConfigInfo::needPrevBlocks);
|
||||
if (rconfig.is_error()) {
|
||||
return fatal_error(
|
||||
"cannot extract previous block configuration from masterchain state while constructing Merkle proof for "s +
|
||||
old_blkid.to_str());
|
||||
}
|
||||
if (!rconfig.move_as_ok()->check_old_mc_block_id(old_blkid, true)) {
|
||||
return fatal_error("cannot check that "s + old_blkid.to_str() +
|
||||
" is indeed a previous masterchain block while constructing Merkle proof");
|
||||
}
|
||||
if (!mpb.extract_proof_to(proof)) {
|
||||
return fatal_error("error while constructing Merkle proof for old masterchain block "s + old_blkid.to_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LiteQuery::continue_getAccountState() {
|
||||
LOG(INFO) << "continue getAccountState() query";
|
||||
if (acc_workchain_ == masterchainId) {
|
||||
|
@ -1000,10 +1154,8 @@ void LiteQuery::continue_getConfigParams(int mode, std::vector<int> param_list)
|
|||
if (!make_mc_state_root_proof(proof1)) {
|
||||
return;
|
||||
}
|
||||
auto state_root = mc_state_->root_cell();
|
||||
auto usage_tree = std::make_shared<vm::CellUsageTree>();
|
||||
auto usage_cell = vm::UsageCell::create(state_root, usage_tree->root_ptr());
|
||||
auto res = block::Config::extract_from_state(usage_cell, mode);
|
||||
vm::MerkleProofBuilder mpb{mc_state_->root_cell()};
|
||||
auto res = block::Config::extract_from_state(mpb.root(), mode);
|
||||
if (res.is_error()) {
|
||||
fatal_error(res.move_as_error());
|
||||
return;
|
||||
|
@ -1025,15 +1177,12 @@ void LiteQuery::continue_getConfigParams(int mode, std::vector<int> param_list)
|
|||
fatal_error("error while traversing required configuration parameters: "s + err.get_msg());
|
||||
return;
|
||||
}
|
||||
auto proof2 = vm::MerkleProof::generate(state_root, usage_tree.get());
|
||||
usage_tree.reset();
|
||||
usage_cell.clear();
|
||||
auto res1 = vm::std_boc_serialize(std::move(proof1));
|
||||
if (res1.is_error()) {
|
||||
fatal_error("cannot serialize Merkle proof : "s + res1.move_as_error().to_string());
|
||||
return;
|
||||
}
|
||||
auto res2 = vm::std_boc_serialize(std::move(proof2));
|
||||
auto res2 = mpb.extract_proof_boc();
|
||||
if (res2.is_error()) {
|
||||
fatal_error("cannot serialize Merkle proof : "s + res2.move_as_error().to_string());
|
||||
return;
|
||||
|
@ -1094,22 +1243,21 @@ void LiteQuery::continue_getShardInfo(ShardIdFull shard, bool exact) {
|
|||
|
||||
void LiteQuery::continue_getAllShardsInfo() {
|
||||
LOG(INFO) << "completing getAllShardsInfo() query";
|
||||
Ref<vm::Cell> proof1;
|
||||
Ref<vm::Cell> proof1, proof2;
|
||||
if (!make_mc_state_root_proof(proof1)) {
|
||||
return;
|
||||
}
|
||||
auto state_root = mc_state_->root_cell();
|
||||
auto usage_tree = std::make_shared<vm::CellUsageTree>();
|
||||
auto usage_cell = vm::UsageCell::create(state_root, usage_tree->root_ptr());
|
||||
auto shards_dict = block::ShardConfig::extract_shard_hashes_dict(usage_cell);
|
||||
vm::MerkleProofBuilder mpb{mc_state_->root_cell()};
|
||||
auto shards_dict = block::ShardConfig::extract_shard_hashes_dict(mpb.root());
|
||||
if (!shards_dict) {
|
||||
fatal_error("cannot extract ShardHashes from last mc state");
|
||||
return;
|
||||
}
|
||||
auto proof2 = vm::MerkleProof::generate(state_root, usage_tree.get());
|
||||
usage_tree.reset();
|
||||
usage_cell.clear();
|
||||
shards_dict = block::ShardConfig::extract_shard_hashes_dict(state_root);
|
||||
if (!mpb.extract_proof_to(proof2)) {
|
||||
fatal_error("cannot construct Merkle proof for all shards dictionary");
|
||||
return;
|
||||
}
|
||||
shards_dict = block::ShardConfig::extract_shard_hashes_dict(mc_state_->root_cell());
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
if (!(std::move(shards_dict)->append_dict_to_bool(cb) && cb.finalize_to(cell))) {
|
||||
|
@ -1329,7 +1477,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
|
||||
void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to, int mode,
|
||||
Ref<MasterchainStateQ> state) {
|
||||
if (mode & 1) {
|
||||
if (!(mode & 1)) {
|
||||
base_blk_id_ = to;
|
||||
if (!to.is_masterchain_ext()) {
|
||||
fatal_error("last masterchain block id "s + to.to_str() + " is invalid");
|
||||
|
@ -1362,7 +1510,7 @@ void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
base_blk_id_.to_str());
|
||||
return;
|
||||
}
|
||||
chain_ = std::make_unique<block::BlkProofChain>(from, to, mode);
|
||||
chain_ = std::make_unique<block::BlockProofChain>(from, to, mode);
|
||||
blk_id_ = from;
|
||||
construct_proof_chain(from);
|
||||
}
|
||||
|
@ -1370,7 +1518,12 @@ void LiteQuery::continue_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
|||
bool LiteQuery::construct_proof_chain(ton::BlockIdExt id) {
|
||||
CHECK(chain_);
|
||||
if (chain_->link_count() >= 16 || id == chain_->to) {
|
||||
return finish_proof_chain(std::move(id));
|
||||
if (!(chain_->last_link_incomplete() && chain_->last_link().to.seqno())) {
|
||||
return finish_proof_chain(std::move(id));
|
||||
} else {
|
||||
set_continuation([this, id]() { finish_proof_chain(id); });
|
||||
return request_proof_link(id);
|
||||
}
|
||||
}
|
||||
if (chain_->to.seqno() == id.seqno()) {
|
||||
return fatal_error("cannot have two different masterchain blocks "s + chain_->to.to_str() + " and " + id.to_str() +
|
||||
|
@ -1400,6 +1553,28 @@ bool LiteQuery::construct_proof_chain(ton::BlockIdExt id) {
|
|||
}
|
||||
}
|
||||
|
||||
// adjust dest_proof and is_key of the last link of existing proof
|
||||
bool LiteQuery::adjust_last_proof_link(ton::BlockIdExt cur, Ref<vm::Cell> block_root) {
|
||||
CHECK(chain_);
|
||||
if (!(chain_->last_link_incomplete() && chain_->last_link().to.seqno())) {
|
||||
return true;
|
||||
}
|
||||
auto& link = chain_->last_link();
|
||||
CHECK(link.dest_proof.is_null());
|
||||
CHECK(link.to == cur);
|
||||
if (cur.root_hash != block_root->get_hash().bits()) {
|
||||
return fatal_error("root hash mismatch in block root of "s + cur.to_str());
|
||||
}
|
||||
vm::MerkleProofBuilder mpb{std::move(block_root)};
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(mpb.root(), blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
return fatal_error("cannot unpack header of block "s + cur.to_str());
|
||||
}
|
||||
link.is_key = info.key_block;
|
||||
return mpb.extract_proof_to(link.dest_proof);
|
||||
}
|
||||
|
||||
bool LiteQuery::construct_proof_link_forward(ton::BlockIdExt cur, ton::BlockIdExt next) {
|
||||
LOG(INFO) << "constructing a forward proof link from " << cur.to_str() << " to " << next.to_str();
|
||||
if (!(cur.is_masterchain_ext() && next.is_masterchain_ext() && mc_state0_->check_old_mc_block_id(cur) &&
|
||||
|
@ -1410,17 +1585,144 @@ bool LiteQuery::construct_proof_link_forward(ton::BlockIdExt cur, ton::BlockIdEx
|
|||
if (cur.seqno() >= next.seqno()) {
|
||||
return fatal_error("cannot construct forward proof link from "s + cur.to_str() + " to " + next.to_str());
|
||||
}
|
||||
set_continuation([this, cur, next]() { construct_proof_link_back_cont(cur, next); });
|
||||
return request_mc_block_data(cur);
|
||||
set_continuation([this, cur, next]() { construct_proof_link_forward_cont(cur, next); });
|
||||
return (cur.seqno() ? request_proof_link(cur) : request_zero_state(cur)) && request_mc_proof(next);
|
||||
}
|
||||
|
||||
bool LiteQuery::construct_proof_link_forward_cont(ton::BlockIdExt cur, ton::BlockIdExt next) {
|
||||
// ...
|
||||
LOG(INFO) << "continue constructing a forward proof link from " << cur.to_str() << " to " << next.to_str();
|
||||
CHECK(cur.seqno() ? proof_link_.not_null() && proof_link_->block_id() == cur : !buffer_.empty());
|
||||
CHECK(mc_proof_.not_null() && mc_proof_->block_id() == next);
|
||||
try {
|
||||
Ref<vm::Cell> cur_root, next_root;
|
||||
// virtualize roots
|
||||
ton::validator::ProofQ::VirtualizedProof virt1;
|
||||
if (cur.seqno()) {
|
||||
auto vres1 = proof_link_->get_virtual_root();
|
||||
if (vres1.is_error()) {
|
||||
return fatal_error(vres1.move_as_error());
|
||||
}
|
||||
virt1 = vres1.move_as_ok();
|
||||
cur_root = virt1.root;
|
||||
} else {
|
||||
// for zero state, lazily deserialize buffer_ instead
|
||||
vm::StaticBagOfCellsDbLazy::Options options;
|
||||
options.check_crc32c = true;
|
||||
auto res = vm::StaticBagOfCellsDbLazy::create(vm::BufferSliceBlobView::create(std::move(buffer_)), options);
|
||||
if (res.is_error()) {
|
||||
return fatal_error(res.move_as_error());
|
||||
}
|
||||
virt1.boc = res.move_as_ok();
|
||||
auto t_root = virt1.boc->get_root_cell(0);
|
||||
if (t_root.is_error()) {
|
||||
return fatal_error(t_root.move_as_error());
|
||||
}
|
||||
cur_root = t_root.move_as_ok();
|
||||
}
|
||||
auto vres2 = mc_proof_->get_virtual_root();
|
||||
if (vres2.is_error()) {
|
||||
return fatal_error(vres2.move_as_error());
|
||||
}
|
||||
next_root = vres2.ok().root;
|
||||
if (cur.root_hash != cur_root->get_hash().bits()) {
|
||||
return fatal_error("incorrect root hash in ProofLink for block "s + cur.to_str());
|
||||
}
|
||||
if (next.root_hash != next_root->get_hash().bits()) {
|
||||
return fatal_error("incorrect root hash in ProofLink for block "s + cur.to_str());
|
||||
}
|
||||
// adjust dest_proof and is_key of the last link of existing proof
|
||||
if (!adjust_last_proof_link(cur, cur_root)) {
|
||||
return false;
|
||||
}
|
||||
// extract configuration from current block
|
||||
vm::MerkleProofBuilder cur_mpb{cur_root}, next_mpb{next_root};
|
||||
if (cur.seqno()) {
|
||||
auto err = block::check_block_header(cur_mpb.root(), cur);
|
||||
if (err.is_error()) {
|
||||
return fatal_error("incorrect header in ProofLink for block "s + cur.to_str());
|
||||
}
|
||||
}
|
||||
auto cfg_res = cur.seqno()
|
||||
? block::Config::extract_from_key_block(cur_mpb.root(), block::ConfigInfo::needValidatorSet)
|
||||
: block::Config::extract_from_state(cur_mpb.root(), block::ConfigInfo::needValidatorSet);
|
||||
if (cfg_res.is_error()) {
|
||||
return fatal_error(cfg_res.move_as_error());
|
||||
}
|
||||
auto config = cfg_res.move_as_ok();
|
||||
// unpack header of next block
|
||||
auto err = block::check_block_header(next_mpb.root(), next);
|
||||
if (err.is_error()) {
|
||||
return fatal_error("incorrect header in ProofLink for block "s + next.to_str());
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(next_mpb.root(), blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
return fatal_error("cannot unpack header of block "s + cur.to_str());
|
||||
}
|
||||
// compute validator set
|
||||
ShardIdFull shard{masterchainId};
|
||||
auto nodes = config->compute_validator_set(shard, info.gen_utime, info.gen_catchain_seqno);
|
||||
if (nodes.empty()) {
|
||||
return fatal_error(PSTRING() << "cannot compute validator set for block " << next.to_str() << " with utime "
|
||||
<< info.gen_utime << " and cc_seqno " << info.gen_catchain_seqno
|
||||
<< " starting from previous key block " << cur.to_str());
|
||||
}
|
||||
auto vset = Ref<ValidatorSetQ>{true, info.gen_catchain_seqno, shard, std::move(nodes)};
|
||||
if (vset.is_null()) {
|
||||
return fatal_error(PSTRING() << "cannot create validator set for block " << next.to_str() << " with utime "
|
||||
<< info.gen_utime << " and cc_seqno " << info.gen_catchain_seqno
|
||||
<< " starting from previous key block " << cur.to_str());
|
||||
}
|
||||
auto vset_hash = vset->get_validator_set_hash();
|
||||
if (vset_hash != info.gen_validator_list_hash_short) {
|
||||
return fatal_error(PSTRING() << "computed validator set for block " << next.to_str() << " with utime "
|
||||
<< info.gen_utime << " and cc_seqno " << info.gen_catchain_seqno
|
||||
<< " starting from previous key block " << cur.to_str() << " has hash " << vset_hash
|
||||
<< " different from " << info.gen_validator_list_hash_short
|
||||
<< " stated in block header");
|
||||
}
|
||||
// extract signatures
|
||||
auto sig_outer_root = vres2.ok().sig_root;
|
||||
block::gen::BlockSignatures::Record sign_rec;
|
||||
block::gen::BlockSignaturesPure::Record sign_pure;
|
||||
if (!(sig_outer_root.not_null() && tlb::unpack_cell(sig_outer_root, sign_rec) &&
|
||||
tlb::csr_unpack(sign_rec.pure_signatures, sign_pure))) {
|
||||
return fatal_error("cannot extract signature set from proof for block "s + next.to_str());
|
||||
}
|
||||
auto sigs = BlockSignatureSetQ::fetch(sign_pure.signatures->prefetch_ref());
|
||||
if (sigs.is_null()) {
|
||||
return fatal_error("cannot deserialize signature set from proof for block "s + next.to_str());
|
||||
}
|
||||
// check signatures (sanity check; comment later for better performance)
|
||||
/*
|
||||
auto S = vset->check_signatures(next.root_hash, next.file_hash, sigs);
|
||||
if (S.is_error()) {
|
||||
return fatal_error("error checking signatures from proof for block "s + next.to_str() + " : " +
|
||||
S.move_as_error().to_string());
|
||||
}
|
||||
*/
|
||||
// serialize signatures
|
||||
auto& link = chain_->new_link(cur, next, info.key_block);
|
||||
link.cc_seqno = info.gen_catchain_seqno;
|
||||
link.validator_set_hash = info.gen_validator_list_hash_short;
|
||||
link.signatures = std::move(sigs.write().signatures());
|
||||
// serialize proofs
|
||||
if (!(cur_mpb.extract_proof_to(link.proof) && next_mpb.extract_proof_to(link.dest_proof))) {
|
||||
return fatal_error("error constructing Merkle proof for forward proof link from "s + cur.to_str() + " to " +
|
||||
next.to_str());
|
||||
}
|
||||
// continue constructing from `next`
|
||||
return construct_proof_chain(next);
|
||||
} catch (vm::VmVirtError&) {
|
||||
return fatal_error("virtualization error during construction of forward proof link from "s + cur.to_str() + " to " +
|
||||
next.to_str());
|
||||
}
|
||||
return fatal_error("construction of forward proof links not implemented yet");
|
||||
}
|
||||
|
||||
bool LiteQuery::construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next) {
|
||||
LOG(INFO) << "constructing a backward proof link from " << cur.to_str() << " to " << next.to_str();
|
||||
CHECK(chain_);
|
||||
if (!(cur.is_masterchain_ext() && next.is_masterchain_ext() && mc_state0_->check_old_mc_block_id(cur) &&
|
||||
mc_state0_->check_old_mc_block_id(next))) {
|
||||
return fatal_error("cannot construct backward proof link from "s + cur.to_str() + " to " + next.to_str() +
|
||||
|
@ -1430,26 +1732,114 @@ bool LiteQuery::construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt n
|
|||
return fatal_error("cannot construct backward proof link from "s + cur.to_str() + " to " + next.to_str());
|
||||
}
|
||||
set_continuation([this, cur, next]() { construct_proof_link_back_cont(cur, next); });
|
||||
return request_mc_block_data_state(cur);
|
||||
return request_proof_link(cur) && request_mc_block_state(cur);
|
||||
}
|
||||
|
||||
bool LiteQuery::construct_proof_link_back_cont(ton::BlockIdExt cur, ton::BlockIdExt next) {
|
||||
LOG(INFO) << "continue constructing a backward proof link from " << cur.to_str() << " to " << next.to_str();
|
||||
CHECK(mc_state_.not_null() && mc_block_.not_null() && mc_state_->get_block_id() == cur &&
|
||||
mc_block_->block_id() == cur);
|
||||
// ...
|
||||
return fatal_error("construction of backward proof links not implemented yet");
|
||||
CHECK(mc_state_.not_null() && proof_link_.not_null() && mc_state_->get_block_id() == cur &&
|
||||
proof_link_->block_id() == cur);
|
||||
try {
|
||||
// virtualize proof link
|
||||
auto vres1 = proof_link_->get_virtual_root();
|
||||
if (vres1.is_error()) {
|
||||
return fatal_error(vres1.move_as_error());
|
||||
}
|
||||
auto vroot = vres1.ok().root;
|
||||
// adjust dest_proof and is_key of the last link of existing proof
|
||||
if (!adjust_last_proof_link(cur, vroot)) {
|
||||
return false;
|
||||
}
|
||||
// construct proof that `mc_state_` is the state of `cur`
|
||||
Ref<vm::Cell> state_proof, proof;
|
||||
if (!make_state_root_proof(proof, mc_state_->root_cell(), vroot, cur)) {
|
||||
return fatal_error("cannot construct proof for state of masterchain block "s + cur.to_str());
|
||||
}
|
||||
// construct proof that `next` is listed in OldMcBlocksInfo of `mc_state_`
|
||||
if (!make_ancestor_block_proof(state_proof, mc_state_->root_cell(), next)) {
|
||||
return fatal_error("cannot prove that "s + next.to_str() +
|
||||
" is in the previous block set of the masterchain state of " + cur.to_str());
|
||||
}
|
||||
// create a BlockProofLink for cur -> next (without dest_proof)
|
||||
auto& link = chain_->new_link(cur, next, !next.seqno());
|
||||
link.proof = std::move(proof);
|
||||
link.state_proof = std::move(state_proof);
|
||||
// continue constructing proof chain from `next`
|
||||
return construct_proof_chain(next);
|
||||
} catch (vm::VmVirtError&) {
|
||||
return fatal_error("virtualization error during construction of backward proof link from "s + cur.to_str() +
|
||||
" to " + next.to_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool LiteQuery::finish_proof_chain(ton::BlockIdExt id) {
|
||||
CHECK(chain_);
|
||||
LOG(INFO) << "finish constructing block proof chain from " << chain_->from.to_str() << " to " << chain_->to.to_str()
|
||||
<< " (constructed " << chain_->link_count() << " up to " << id.to_str() << ")";
|
||||
// bool complete = (id == chain_->to);
|
||||
chain_->to = id;
|
||||
// serialize answer
|
||||
// ...
|
||||
return fatal_error("cannot serialize PartialBlockProof from "s + chain_->from.to_str() + " to " + id.to_str());
|
||||
try {
|
||||
if (chain_->last_link_incomplete() && chain_->last_link().to.seqno()) {
|
||||
CHECK(proof_link_.not_null() && proof_link_->block_id() == id);
|
||||
auto vres1 = proof_link_->get_virtual_root();
|
||||
if (vres1.is_error()) {
|
||||
return fatal_error(vres1.move_as_error());
|
||||
}
|
||||
if (!adjust_last_proof_link(id, vres1.ok().root)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
chain_->complete = (id == chain_->to);
|
||||
chain_->to = id;
|
||||
// serialize answer
|
||||
std::vector<ton::tl_object_ptr<lite_api::liteServer_BlockLink>> a;
|
||||
for (auto& link : chain_->links) {
|
||||
td::BufferSlice dest_proof_boc;
|
||||
if (link.to.seqno()) {
|
||||
auto res = vm::std_boc_serialize(link.dest_proof);
|
||||
if (res.is_error()) {
|
||||
return fatal_error("error while serializing destination block Merkle proof in block proof link from "s +
|
||||
link.from.to_str() + " to " + link.to.to_str() + " : " + res.move_as_error().to_string());
|
||||
}
|
||||
dest_proof_boc = res.move_as_ok();
|
||||
}
|
||||
auto src_proof_boc = vm::std_boc_serialize(link.proof);
|
||||
if (src_proof_boc.is_error()) {
|
||||
return fatal_error("error while serializing source block Merkle proof in block proof link from "s +
|
||||
link.from.to_str() + " to " + link.to.to_str() + " : " +
|
||||
src_proof_boc.move_as_error().to_string());
|
||||
}
|
||||
if (link.is_fwd) {
|
||||
// serialize forward link
|
||||
std::vector<ton::tl_object_ptr<lite_api::liteServer_signature>> b;
|
||||
for (auto& sig : link.signatures) {
|
||||
b.push_back(create_tl_object<lite_api::liteServer_signature>(sig.node, std::move(sig.signature)));
|
||||
}
|
||||
a.push_back(create_tl_object<lite_api::liteServer_blockLinkForward>(
|
||||
link.is_key, ton::create_tl_lite_block_id(link.from), ton::create_tl_lite_block_id(link.to),
|
||||
std::move(dest_proof_boc), src_proof_boc.move_as_ok(),
|
||||
create_tl_object<lite_api::liteServer_signatureSet>(link.validator_set_hash, link.cc_seqno, std::move(b))));
|
||||
} else {
|
||||
// serialize backward link
|
||||
auto state_proof_boc = vm::std_boc_serialize(link.state_proof);
|
||||
if (state_proof_boc.is_error()) {
|
||||
return fatal_error("error while serializing source state Merkle proof in block proof link from "s +
|
||||
link.from.to_str() + " to " + link.to.to_str() + " : " +
|
||||
state_proof_boc.move_as_error().to_string());
|
||||
}
|
||||
a.push_back(create_tl_object<lite_api::liteServer_blockLinkBack>(
|
||||
link.is_key, ton::create_tl_lite_block_id(link.from), ton::create_tl_lite_block_id(link.to),
|
||||
std::move(dest_proof_boc), src_proof_boc.move_as_ok(), state_proof_boc.move_as_ok()));
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "getBlockProof() query completed";
|
||||
auto c = ton::create_serialize_tl_object<ton::lite_api::liteServer_partialBlockProof>(
|
||||
chain_->complete, ton::create_tl_lite_block_id(chain_->from), ton::create_tl_lite_block_id(chain_->to),
|
||||
std::move(a));
|
||||
return finish_query(std::move(c));
|
||||
} catch (vm::VmError& err) {
|
||||
return fatal_error("vm error while constructing block proof chain : "s + err.get_msg());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
return fatal_error("virtualization error while constructing block proof chain : "s + err.get_msg());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "interfaces/validator-manager.h"
|
||||
#include "interfaces/shard.h"
|
||||
#include "shard.hpp"
|
||||
#include "proof.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
|
@ -40,20 +41,25 @@ class LiteQuery : public td::actor::Actor {
|
|||
StdSmcAddress acc_addr_;
|
||||
LogicalTime trans_lt_;
|
||||
Bits256 trans_hash_;
|
||||
BlockIdExt base_blk_id_, blk_id_;
|
||||
BlockIdExt base_blk_id_, base_blk_id_alt_, blk_id_;
|
||||
Ref<MasterchainStateQ> mc_state_, mc_state0_;
|
||||
Ref<ShardStateQ> state_;
|
||||
Ref<BlockData> mc_block_, block_;
|
||||
Ref<ProofQ> mc_proof_, mc_proof_alt_;
|
||||
Ref<ProofLinkQ> proof_link_;
|
||||
td::BufferSlice buffer_;
|
||||
std::function<void()> continuation_;
|
||||
bool cont_set_{false};
|
||||
td::BufferSlice shard_proof_;
|
||||
std::vector<Ref<vm::Cell>> roots_;
|
||||
std::vector<Ref<td::CntObject>> aux_objs_;
|
||||
std::vector<ton::BlockIdExt> blk_ids_;
|
||||
std::unique_ptr<block::BlkProofChain> chain_;
|
||||
std::unique_ptr<block::BlockProofChain> chain_;
|
||||
|
||||
public:
|
||||
static constexpr double default_timeout_seconds = 4.5;
|
||||
static constexpr int ls_version = 0x101; // 1.1
|
||||
static constexpr long long ls_capabilities = 1; // +1 = build block proof chains
|
||||
LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
|
||||
|
@ -64,6 +70,7 @@ class LiteQuery : public td::actor::Actor {
|
|||
bool fatal_error(std::string err_msg, int err_code = -400);
|
||||
bool fatal_error(int err_code, std::string err_msg = "");
|
||||
void abort_query(td::Status reason);
|
||||
void abort_query_ext(td::Status reason, std::string err_msg);
|
||||
bool finish_query(td::BufferSlice result);
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
|
@ -77,6 +84,7 @@ class LiteQuery : public td::actor::Actor {
|
|||
void continue_getBlockHeader(BlockIdExt blkid, int mode, Ref<BlockData> block);
|
||||
void perform_getState(BlockIdExt blkid);
|
||||
void continue_getState(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void continue_getZeroState(BlockIdExt blkid, td::BufferSlice state);
|
||||
void perform_sendMessage(td::BufferSlice ext_msg);
|
||||
void perform_getAccountState(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr);
|
||||
void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid);
|
||||
|
@ -105,18 +113,25 @@ class LiteQuery : public td::actor::Actor {
|
|||
bool construct_proof_link_forward_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool construct_proof_link_back(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool construct_proof_link_back_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool adjust_last_proof_link(ton::BlockIdExt cur, Ref<vm::Cell> block_root);
|
||||
bool finish_proof_chain(ton::BlockIdExt id);
|
||||
|
||||
bool request_block_data(BlockIdExt blkid);
|
||||
bool request_block_state(BlockIdExt blkid);
|
||||
bool request_block_data_state(BlockIdExt blkid);
|
||||
bool request_proof_link(BlockIdExt blkid);
|
||||
bool request_mc_block_data(BlockIdExt blkid);
|
||||
bool request_mc_block_state(BlockIdExt blkid);
|
||||
bool request_mc_block_data_state(BlockIdExt blkid);
|
||||
bool request_mc_proof(BlockIdExt blkid, int mode = 0);
|
||||
bool request_zero_state(BlockIdExt blkid);
|
||||
void got_block_state(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void got_mc_block_state(BlockIdExt blkid, Ref<ShardState> state);
|
||||
void got_block_data(BlockIdExt blkid, Ref<BlockData> data);
|
||||
void got_mc_block_data(BlockIdExt blkid, Ref<BlockData> data);
|
||||
void got_mc_block_proof(BlockIdExt blkid, int mode, Ref<Proof> proof);
|
||||
void got_block_proof_link(BlockIdExt blkid, Ref<ProofLink> proof_link);
|
||||
void got_zero_state(BlockIdExt blkid, td::BufferSlice zerostate);
|
||||
void dec_pending() {
|
||||
if (!--pending_) {
|
||||
check_pending();
|
||||
|
@ -128,11 +143,14 @@ class LiteQuery : public td::actor::Actor {
|
|||
bool make_state_root_proof(Ref<vm::Cell>& proof);
|
||||
bool make_state_root_proof(Ref<vm::Cell>& proof, Ref<ShardStateQ> state, Ref<BlockData> block,
|
||||
const BlockIdExt& blkid);
|
||||
bool make_state_root_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_root, Ref<vm::Cell> block_root,
|
||||
const BlockIdExt& blkid);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, vm::CellSlice& cs, ShardIdFull shard, ShardIdFull& true_shard,
|
||||
Ref<vm::Cell>& leaf, bool& found, bool exact = true);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, Ref<block::McShardHash>& info, ShardIdFull shard, bool exact = true);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, Ref<block::McShardHash>& info, AccountIdPrefixFull prefix);
|
||||
bool make_shard_info_proof(Ref<vm::Cell>& proof, BlockIdExt& blkid, AccountIdPrefixFull prefix);
|
||||
bool make_ancestor_block_proof(Ref<vm::Cell>& proof, Ref<vm::Cell> state_root, const BlockIdExt& old_blkid);
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -47,11 +47,11 @@ td::Result<BlockSeqno> ProofLinkQ::prev_key_mc_seqno() const {
|
|||
// return td::Status::Error(
|
||||
// -668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
|
||||
//}
|
||||
TRY_RESULT(pair, get_virtual_root(true));
|
||||
TRY_RESULT(virt, get_virtual_root(true));
|
||||
try {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(std::move(pair.first), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
|
||||
if (!(tlb::unpack_cell(std::move(virt.root), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
|
||||
return td::Status::Error(-668,
|
||||
"cannot unpack block header in the Merkle proof for masterchain block "s + id_.to_str());
|
||||
}
|
||||
|
@ -66,10 +66,10 @@ td::Result<td::Ref<ConfigHolder>> ProofLinkQ::get_key_block_config() const {
|
|||
return td::Status::Error(
|
||||
-668, "cannot compute previous key masterchain block from ProofLink of non-masterchain block "s + id_.to_str());
|
||||
}
|
||||
TRY_RESULT(pair, get_virtual_root(true));
|
||||
TRY_RESULT(virt, get_virtual_root(true));
|
||||
try {
|
||||
TRY_RESULT(cfg, block::Config::extract_from_key_block(std::move(pair.first), block::Config::needValidatorSet));
|
||||
return td::make_ref<ConfigHolderQ>(std::move(cfg), std::move(pair.second));
|
||||
TRY_RESULT(cfg, block::Config::extract_from_key_block(std::move(virt.root), block::Config::needValidatorSet));
|
||||
return td::make_ref<ConfigHolderQ>(std::move(cfg), std::move(virt.boc));
|
||||
} catch (vm::VmVirtError &) {
|
||||
return td::Status::Error(-668,
|
||||
"virtualization error while traversing masterchain block proof for "s + id_.to_str());
|
||||
|
@ -78,11 +78,11 @@ td::Result<td::Ref<ConfigHolder>> ProofLinkQ::get_key_block_config() const {
|
|||
|
||||
td::Result<ProofLink::BasicHeaderInfo> ProofLinkQ::get_basic_header_info() const {
|
||||
BasicHeaderInfo res;
|
||||
TRY_RESULT(pair, get_virtual_root(true));
|
||||
TRY_RESULT(virt, get_virtual_root(true));
|
||||
try {
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(std::move(pair.first), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
|
||||
if (!(tlb::unpack_cell(std::move(virt.root), blk) && tlb::unpack_cell(blk.info, info) && !info.version)) {
|
||||
return td::Status::Error(-668,
|
||||
"cannot unpack block header in the Merkle proof for masterchain block "s + id_.to_str());
|
||||
}
|
||||
|
@ -96,8 +96,7 @@ td::Result<ProofLink::BasicHeaderInfo> ProofLinkQ::get_basic_header_info() const
|
|||
}
|
||||
}
|
||||
|
||||
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> ProofLinkQ::get_virtual_root(
|
||||
bool lazy) const {
|
||||
td::Result<ProofLinkQ::VirtualizedProof> ProofLinkQ::get_virtual_root(bool lazy) const {
|
||||
if (data_.empty()) {
|
||||
return td::Status::Error(-668, "block proof is empty");
|
||||
}
|
||||
|
@ -143,7 +142,23 @@ td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> Pr
|
|||
" contains a Merkle proof with incorrect root hash: expected " +
|
||||
proof_blk_id.root_hash.to_hex() + ", found " + virt_hash.to_hex());
|
||||
}
|
||||
return std::make_pair(std::move(virt_root), std::move(boc));
|
||||
return VirtualizedProof{std::move(virt_root), proof.signatures->prefetch_ref(), std::move(boc)};
|
||||
}
|
||||
|
||||
td::Result<Ref<vm::Cell>> ProofQ::get_signatures_root() const {
|
||||
if (data_.empty()) {
|
||||
return td::Status::Error(-668, "block proof is empty");
|
||||
}
|
||||
TRY_RESULT(root, vm::std_boc_deserialize(data_.as_slice()));
|
||||
block::gen::BlockProof::Record proof;
|
||||
BlockIdExt proof_blk_id;
|
||||
if (!(tlb::unpack_cell(root, proof) && block::tlb::t_BlockIdExt.unpack(proof.proof_for.write(), proof_blk_id))) {
|
||||
return td::Status::Error(-668, "masterchain block proof is invalid");
|
||||
}
|
||||
if (proof_blk_id != id_) {
|
||||
return td::Status::Error(-668, "masterchain block proof is for another block");
|
||||
}
|
||||
return proof.signatures->prefetch_ref();
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -49,9 +49,20 @@ class ProofLinkQ : virtual public ProofLink {
|
|||
td::Result<td::Ref<ConfigHolder>> get_key_block_config() const override;
|
||||
td::Result<BasicHeaderInfo> get_basic_header_info() const override;
|
||||
|
||||
protected:
|
||||
td::Result<std::pair<Ref<vm::Cell>, std::shared_ptr<vm::StaticBagOfCellsDb>>> get_virtual_root(
|
||||
bool lazy = false) const;
|
||||
struct VirtualizedProof {
|
||||
Ref<vm::Cell> root, sig_root;
|
||||
std::shared_ptr<vm::StaticBagOfCellsDb> boc;
|
||||
VirtualizedProof() = default;
|
||||
VirtualizedProof(Ref<vm::Cell> _vroot, Ref<vm::Cell> _sigroot, std::shared_ptr<vm::StaticBagOfCellsDb> _boc)
|
||||
: root(std::move(_vroot)), sig_root(std::move(_sigroot)), boc(std::move(_boc)) {
|
||||
}
|
||||
void clear() {
|
||||
root.clear();
|
||||
sig_root.clear();
|
||||
boc.reset();
|
||||
}
|
||||
};
|
||||
td::Result<VirtualizedProof> get_virtual_root(bool lazy = false) const;
|
||||
};
|
||||
|
||||
#if TD_MSVC
|
||||
|
@ -66,6 +77,7 @@ class ProofQ : public Proof, public ProofLinkQ {
|
|||
return new ProofQ(id_, data_.clone());
|
||||
}
|
||||
td::Result<Ref<ProofLink>> export_as_proof_link() const override;
|
||||
td::Result<Ref<vm::Cell>> get_signatures_root() const;
|
||||
};
|
||||
#if TD_MSVC
|
||||
#pragma warning(pop)
|
||||
|
|
|
@ -255,7 +255,7 @@ void ValidateQuery::start_up() {
|
|||
LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(),
|
||||
timeout, [ self = get_self(), i ](td::Result<Ref<ShardState>> res)->void {
|
||||
timeout, [self = get_self(), i](td::Result<Ref<ShardState>> res) -> void {
|
||||
LOG(DEBUG) << "got answer to wait_block_state_short query #" << i;
|
||||
td::actor::send_closure_later(
|
||||
std::move(self), &ValidateQuery::after_get_shard_state, i, std::move(res));
|
||||
|
@ -269,16 +269,16 @@ void ValidateQuery::start_up() {
|
|||
// 5. request masterchain state referred to in the block
|
||||
if (!is_masterchain()) {
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(),
|
||||
timeout, [self = get_self()](td::Result<Ref<ShardState>> res) {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(), timeout,
|
||||
[self = get_self()](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state() query for masterchain block";
|
||||
td::actor::send_closure_later(std::move(self), &ValidateQuery::after_get_mc_state,
|
||||
std::move(res));
|
||||
});
|
||||
// 5.1. request corresponding block handle
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_block_handle, mc_blkid_,
|
||||
true, [self = get_self()](td::Result<BlockHandle> res) {
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::get_block_handle, mc_blkid_, true,
|
||||
[self = get_self()](td::Result<BlockHandle> res) {
|
||||
LOG(DEBUG) << "got answer to get_block_handle() query for masterchain block";
|
||||
td::actor::send_closure_later(std::move(self), &ValidateQuery::got_mc_handle,
|
||||
std::move(res));
|
||||
|
@ -1008,7 +1008,8 @@ bool ValidateQuery::compute_next_state() {
|
|||
return reject_query("header of new state claims it belongs to block "s + hdr_id.to_str() + " instead of " +
|
||||
id_.id.to_str());
|
||||
}
|
||||
if (info.custom->size_refs() != is_masterchain()) {
|
||||
CHECK(info.custom->size_refs() == 0 || info.custom->size_refs() == 1);
|
||||
if (info.custom->size_refs() != static_cast<unsigned>(is_masterchain())) {
|
||||
return reject_query("McStateExtra in the new state of a non-masterchain block, or conversely");
|
||||
}
|
||||
if (is_masterchain()) {
|
||||
|
@ -1166,7 +1167,7 @@ bool ValidateQuery::request_neighbor_queues() {
|
|||
LOG(DEBUG) << "neighbor #" << i << " : " << descr.blk_.to_str();
|
||||
++pending;
|
||||
send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout,
|
||||
[ self = get_self(), i ](td::Result<Ref<MessageQueue>> res) {
|
||||
[self = get_self(), i](td::Result<Ref<MessageQueue>> res) {
|
||||
td::actor::send_closure(std::move(self), &ValidateQuery::got_neighbor_out_queue, i,
|
||||
std::move(res));
|
||||
});
|
||||
|
@ -1284,12 +1285,13 @@ bool ValidateQuery::request_aux_mc_state(BlockSeqno seqno, Ref<MasterchainStateQ
|
|||
CHECK(blkid.is_valid_ext() && blkid.is_masterchain());
|
||||
LOG(DEBUG) << "sending auxiliary wait_block_state() query for " << blkid.to_str() << " to Manager";
|
||||
++pending;
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, blkid, priority(), timeout, [
|
||||
self = get_self(), blkid
|
||||
](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query for " << blkid.to_str();
|
||||
td::actor::send_closure_later(std::move(self), &ValidateQuery::after_get_aux_shard_state, blkid, std::move(res));
|
||||
});
|
||||
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, blkid, priority(), timeout,
|
||||
[self = get_self(), blkid](td::Result<Ref<ShardState>> res) {
|
||||
LOG(DEBUG) << "got answer to wait_block_state query for " << blkid.to_str();
|
||||
td::actor::send_closure_later(std::move(self),
|
||||
&ValidateQuery::after_get_aux_shard_state, blkid,
|
||||
std::move(res));
|
||||
});
|
||||
state.clear();
|
||||
return true;
|
||||
}
|
||||
|
@ -1625,8 +1627,8 @@ bool ValidateQuery::check_shard_layout() {
|
|||
WorkchainId wc_id{ton::workchainInvalid};
|
||||
Ref<block::WorkchainInfo> wc_info;
|
||||
|
||||
if (!new_shard_conf_->process_sibling_shard_hashes([ self = this, &wc_set, &wc_id, &wc_info, &ccvc ](
|
||||
block::McShardHash & cur, const block::McShardHash* sibling) {
|
||||
if (!new_shard_conf_->process_sibling_shard_hashes([self = this, &wc_set, &wc_id, &wc_info, &ccvc](
|
||||
block::McShardHash& cur, const block::McShardHash* sibling) {
|
||||
if (!cur.is_valid()) {
|
||||
return -2;
|
||||
}
|
||||
|
@ -4617,8 +4619,8 @@ bool ValidateQuery::check_one_library_update(td::ConstBitPtr key, Ref<vm::CellSl
|
|||
old_publishers = std::make_unique<vm::Dictionary>(256);
|
||||
}
|
||||
if (!old_publishers->scan_diff(*new_publishers,
|
||||
[ this, lib_key = key ](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val,
|
||||
Ref<vm::CellSlice> new_val) {
|
||||
[this, lib_key = key](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val,
|
||||
Ref<vm::CellSlice> new_val) {
|
||||
CHECK(key_len == 256);
|
||||
if (old_val.not_null() && !old_val->empty_ext()) {
|
||||
return false;
|
||||
|
|
|
@ -822,7 +822,7 @@ void ValidatorManagerImpl::send_top_shard_block_description(td::Ref<ShardTopBloc
|
|||
}
|
||||
|
||||
void ValidatorManagerImpl::start_up() {
|
||||
db_ = create_db_actor(actor_id(this), db_root_);
|
||||
db_ = create_db_actor(actor_id(this), db_root_, opts_->get_filedb_depth());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ValidatorManagerInitResult> R) {
|
||||
R.ensure();
|
||||
|
|
|
@ -1275,7 +1275,7 @@ void ValidatorManagerImpl::send_block_broadcast(BlockBroadcast broadcast) {
|
|||
}
|
||||
|
||||
void ValidatorManagerImpl::start_up() {
|
||||
db_ = create_db_actor(actor_id(this), db_root_);
|
||||
db_ = create_db_actor(actor_id(this), db_root_, opts_->get_filedb_depth());
|
||||
token_manager_ = td::actor::create_actor<TokenManager>("tokenmanager");
|
||||
|
||||
auto Q =
|
||||
|
@ -1704,6 +1704,33 @@ void ValidatorManagerImpl::allow_archive(BlockIdExt block_id, td::Promise<bool>
|
|||
td::actor::send_closure(db_, &Db::archive, block_id, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::allow_delete(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
auto key_ttl = td::Clocks::system() - opts_->key_proof_ttl();
|
||||
auto ttl = td::Clocks::system() - opts_->archive_ttl();
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), promise = std::move(promise), ttl, key_ttl](td::Result<BlockHandle> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_result(true);
|
||||
return;
|
||||
}
|
||||
auto handle = R.move_as_ok();
|
||||
if (!handle->moved_to_storage()) {
|
||||
promise.set_result(false);
|
||||
return;
|
||||
}
|
||||
if (!handle->inited_unix_time()) {
|
||||
promise.set_result(true);
|
||||
return;
|
||||
}
|
||||
if (!handle->inited_is_key_block() || !handle->is_key_block()) {
|
||||
promise.set_result(handle->unix_time() <= ttl);
|
||||
} else {
|
||||
promise.set_result(handle->unix_time() <= key_ttl);
|
||||
}
|
||||
});
|
||||
get_block_handle(block_id, false, std::move(P));
|
||||
}
|
||||
|
||||
void ValidatorManagerImpl::allow_block_state_gc(BlockIdExt block_id, td::Promise<bool> promise) {
|
||||
if (!gc_masterchain_handle_) {
|
||||
promise.set_result(false);
|
||||
|
|
|
@ -455,12 +455,13 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
}
|
||||
|
||||
public:
|
||||
void allow_delete(BlockIdExt block_id, td::Promise<bool> promise);
|
||||
void allow_archive(BlockIdExt block_id, td::Promise<bool> promise);
|
||||
void allow_block_data_gc(BlockIdExt block_id, bool is_archive, td::Promise<bool> promise) override {
|
||||
if (!is_archive) {
|
||||
allow_archive(block_id, std::move(promise));
|
||||
} else {
|
||||
promise.set_result(false);
|
||||
allow_delete(block_id, std::move(promise));
|
||||
}
|
||||
}
|
||||
void allow_block_state_gc(BlockIdExt block_id, td::Promise<bool> promise) override;
|
||||
|
@ -476,21 +477,21 @@ class ValidatorManagerImpl : public ValidatorManager {
|
|||
if (!is_archive) {
|
||||
allow_archive(block_id, std::move(promise));
|
||||
} else {
|
||||
promise.set_result(false);
|
||||
allow_delete(block_id, std::move(promise));
|
||||
}
|
||||
}
|
||||
void allow_block_proof_link_gc(BlockIdExt block_id, bool is_archive, td::Promise<bool> promise) override {
|
||||
if (!is_archive) {
|
||||
allow_archive(block_id, std::move(promise));
|
||||
} else {
|
||||
promise.set_result(false);
|
||||
allow_delete(block_id, std::move(promise));
|
||||
}
|
||||
}
|
||||
void allow_block_candidate_gc(BlockIdExt block_id, td::Promise<bool> promise) override {
|
||||
allow_block_state_gc(block_id, std::move(promise));
|
||||
}
|
||||
void allow_block_info_gc(BlockIdExt block_id, td::Promise<bool> promise) override {
|
||||
promise.set_result(false);
|
||||
allow_delete(block_id, std::move(promise));
|
||||
}
|
||||
|
||||
void send_peek_key_block_request();
|
||||
|
|
|
@ -87,6 +87,10 @@ void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash s
|
|||
sig_set, approve_sig_set,
|
||||
promise = std::move(promise)](td::Result<td::Unit> R) mutable {
|
||||
if (R.is_error()) {
|
||||
if (R.error().code() == ErrorCode::cancelled) {
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
LOG_CHECK(R.error().code() == ErrorCode::timeout || R.error().code() == ErrorCode::notready) << R.move_as_error();
|
||||
td::actor::send_closure(SelfId, &ValidatorGroup::retry_accept_block_query, block_id, std::move(block),
|
||||
std::move(prev), std::move(sig_set), std::move(approve_sig_set), std::move(promise));
|
||||
|
|
|
@ -27,10 +27,11 @@ namespace validator {
|
|||
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
|
||||
BlockIdExt zero_block_id, BlockIdExt init_block_id, std::function<bool(ShardIdFull)> check_shard,
|
||||
bool allow_blockchain_init, td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
||||
td::ClocksBase::Duration state_ttl, bool initial_sync_disabled) {
|
||||
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration 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,
|
||||
initial_sync_disabled);
|
||||
archive_ttl, key_proof_ttl, initial_sync_disabled);
|
||||
}
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -47,6 +47,12 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
td::ClocksBase::Duration state_ttl() const override {
|
||||
return state_ttl_;
|
||||
}
|
||||
td::ClocksBase::Duration archive_ttl() const override {
|
||||
return archive_ttl_;
|
||||
}
|
||||
td::ClocksBase::Duration key_proof_ttl() const override {
|
||||
return key_proof_ttl_;
|
||||
}
|
||||
bool initial_sync_disabled() const override {
|
||||
return initial_sync_disabled_;
|
||||
}
|
||||
|
@ -70,6 +76,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
}
|
||||
return static_cast<td::uint32>(best);
|
||||
}
|
||||
td::uint32 get_filedb_depth() const override {
|
||||
return db_depth_;
|
||||
}
|
||||
|
||||
void set_zero_block_id(BlockIdExt block_id) override {
|
||||
zero_block_id_ = block_id;
|
||||
|
@ -92,12 +101,22 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
void set_state_ttl(td::ClocksBase::Duration value) override {
|
||||
state_ttl_ = value;
|
||||
}
|
||||
void set_archive_ttl(td::ClocksBase::Duration value) override {
|
||||
archive_ttl_ = value;
|
||||
}
|
||||
void set_key_proof_ttl(td::ClocksBase::Duration value) override {
|
||||
key_proof_ttl_ = value;
|
||||
}
|
||||
void set_initial_sync_disabled(bool value) override {
|
||||
initial_sync_disabled_ = value;
|
||||
}
|
||||
void set_hardforks(std::vector<BlockIdExt> vec) override {
|
||||
hardforks_ = std::move(vec);
|
||||
}
|
||||
void set_filedb_depth(td::uint32 value) override {
|
||||
CHECK(value <= 32);
|
||||
db_depth_ = value;
|
||||
}
|
||||
|
||||
ValidatorManagerOptionsImpl *make_copy() const override {
|
||||
return new ValidatorManagerOptionsImpl(*this);
|
||||
|
@ -106,7 +125,8 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
|
||||
td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
||||
td::ClocksBase::Duration state_ttl, bool initial_sync_disabled)
|
||||
td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration state_ttl,
|
||||
td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled)
|
||||
: zero_block_id_(zero_block_id)
|
||||
, init_block_id_(init_block_id)
|
||||
, check_shard_(std::move(check_shard))
|
||||
|
@ -114,6 +134,8 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
, sync_blocks_before_(sync_blocks_before)
|
||||
, block_ttl_(block_ttl)
|
||||
, state_ttl_(state_ttl)
|
||||
, archive_ttl_(archive_ttl)
|
||||
, key_proof_ttl_(key_proof_ttl)
|
||||
, initial_sync_disabled_(initial_sync_disabled) {
|
||||
}
|
||||
|
||||
|
@ -125,8 +147,11 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
|||
td::ClocksBase::Duration sync_blocks_before_;
|
||||
td::ClocksBase::Duration block_ttl_;
|
||||
td::ClocksBase::Duration state_ttl_;
|
||||
td::ClocksBase::Duration archive_ttl_;
|
||||
td::ClocksBase::Duration key_proof_ttl_;
|
||||
bool initial_sync_disabled_;
|
||||
std::vector<BlockIdExt> hardforks_;
|
||||
td::uint32 db_depth_ = 2;
|
||||
};
|
||||
|
||||
} // namespace validator
|
||||
|
|
|
@ -53,9 +53,12 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
virtual td::ClocksBase::Duration sync_blocks_before() const = 0;
|
||||
virtual td::ClocksBase::Duration block_ttl() const = 0;
|
||||
virtual td::ClocksBase::Duration state_ttl() const = 0;
|
||||
virtual td::ClocksBase::Duration archive_ttl() const = 0;
|
||||
virtual td::ClocksBase::Duration key_proof_ttl() const = 0;
|
||||
virtual bool initial_sync_disabled() const = 0;
|
||||
virtual bool is_hardfork(BlockIdExt block_id) const = 0;
|
||||
virtual td::uint32 get_vertical_height(BlockSeqno seqno) const = 0;
|
||||
virtual td::uint32 get_filedb_depth() const = 0;
|
||||
|
||||
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
|
||||
virtual void set_init_block_id(BlockIdExt block_id) = 0;
|
||||
|
@ -64,14 +67,18 @@ struct ValidatorManagerOptions : public td::CntObject {
|
|||
virtual void set_sync_blocks_before(td::ClocksBase::Duration value) = 0;
|
||||
virtual void set_block_ttl(td::ClocksBase::Duration value) = 0;
|
||||
virtual void set_state_ttl(td::ClocksBase::Duration value) = 0;
|
||||
virtual void set_archive_ttl(td::ClocksBase::Duration value) = 0;
|
||||
virtual void set_key_proof_ttl(td::ClocksBase::Duration value) = 0;
|
||||
virtual void set_initial_sync_disabled(bool value) = 0;
|
||||
virtual void set_hardforks(std::vector<BlockIdExt> hardforks) = 0;
|
||||
virtual void set_filedb_depth(td::uint32 value) = 0;
|
||||
|
||||
static td::Ref<ValidatorManagerOptions> create(
|
||||
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||
std::function<bool(ShardIdFull)> check_shard = [](ShardIdFull) { return true; },
|
||||
bool allow_blockchain_init = false, td::ClocksBase::Duration sync_blocks_before = 300,
|
||||
td::ClocksBase::Duration block_ttl = 86400 * 7, td::ClocksBase::Duration state_ttl = 3600,
|
||||
td::ClocksBase::Duration archive_ttl = 86400 * 365, td::ClocksBase::Duration key_proof_ttl = 86400 * 3650,
|
||||
bool initial_sync_disabled = false);
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue