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

Lite-mode for validate-query, more collated data in collator

This commit is contained in:
SpyCheese 2022-07-12 11:04:31 +03:00
parent 849d995346
commit 625516c568
7 changed files with 214 additions and 37 deletions

View file

@ -31,6 +31,7 @@
#include "vm/cells/MerkleProof.h"
#include "vm/cells/MerkleUpdate.h"
#include "common/errorlog.h"
#include "fabric.h"
#include <ctime>
namespace ton {
@ -51,7 +52,7 @@ std::string ErrorCtx::as_string() const {
ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, BlockCandidate candidate, Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake)
td::Promise<ValidateCandidateResult> promise, unsigned mode)
: shard_(shard)
, id_(candidate.id)
, min_ts(min_ts)
@ -62,7 +63,8 @@ ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_
, manager(std::move(manager))
, timeout(timeout)
, main_promise(std::move(promise))
, is_fake_(is_fake)
, is_fake_(mode & ValidateMode::fake)
, is_lite_(mode & ValidateMode::lite)
, shard_pfx_(shard_.shard)
, shard_pfx_len_(ton::shard_prefix_length(shard_)) {
proc_hash_.zero();
@ -257,18 +259,20 @@ void ValidateQuery::start_up() {
td::actor::send_closure_later(
std::move(self), &ValidateQuery::after_get_latest_mc_state, std::move(res));
});
// 3. load state(s) corresponding to previous block(s)
// 3. load state(s) corresponding to previous block(s) (non-lite mode or masterchain)
prev_states.resize(prev_blocks.size());
for (int i = 0; (unsigned)i < prev_blocks.size(); i++) {
// 3.1. load state
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 {
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));
});
if (is_masterchain() || !is_lite_) {
for (int i = 0; (unsigned)i < prev_blocks.size(); i++) {
// 3.1. load state
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 {
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));
});
}
}
// 4. unpack block candidate (while necessary data is being loaded)
if (!unpack_block_candidate()) {
@ -988,6 +992,9 @@ bool ValidateQuery::check_this_shard_mc_info() {
*/
bool ValidateQuery::compute_prev_state() {
if (!is_masterchain() && is_lite_) {
return compute_prev_state_lite_mode();
}
CHECK(prev_states.size() == 1u + after_merge_);
prev_state_root_ = prev_states[0]->root_cell();
CHECK(prev_state_root_.not_null());
@ -1006,6 +1013,46 @@ bool ValidateQuery::compute_prev_state() {
return true;
}
bool ValidateQuery::compute_prev_state_lite_mode() {
td::Bits256 state_hash;
if (id_.seqno() == 1) {
if (prev_blocks.size() != 1) {
return reject_query("seqno is 1, but number of previous blocks is not 1");
}
state_hash = prev_blocks[0].root_hash;
} else {
std::vector<Ref<vm::Cell>> prev_state_roots(prev_blocks.size());
for (size_t i = 0; i < prev_blocks.size(); ++i) {
prev_state_roots[i] = get_virt_state_root(prev_blocks[i].root_hash);
if (prev_state_roots[i].is_null()) {
return reject_query(PSTRING() << "cannot get hash of previous state root: " << prev_blocks[i]);
}
}
if (prev_state_roots.size() == 1) {
state_hash = prev_state_roots[0]->get_hash().bits();
} else {
CHECK(prev_state_roots.size() == 2);
Ref<vm::Cell> merged;
if (!block::gen::t_ShardState.cell_pack_split_state(merged, prev_state_roots[0], prev_state_roots[1])) {
return fatal_error(-667, "cannot construct mechanically merged previously state");
}
state_hash = merged->get_hash().bits();
}
}
if (state_hash != prev_state_hash_) {
return reject_query("previous state hash mismatch for block "s + id_.to_str() + " : block header declares " +
prev_state_hash_.to_hex() + " , actual " + state_hash.to_hex());
}
auto it = virt_roots_.find(state_hash);
if (it == virt_roots_.end()) {
return reject_query(PSTRING() << "no state root for previous block in collated data (hash = "
<< state_hash.to_hex() << ")");
}
prev_state_root_ = it->second;
return true;
}
bool ValidateQuery::compute_next_state() {
LOG(DEBUG) << "computing next state";
auto res = vm::MerkleUpdate::validate(state_update_);
@ -1209,15 +1256,42 @@ bool ValidateQuery::request_neighbor_queues() {
neighbors_.emplace_back(*shard_ptr);
}
int i = 0;
for (block::McShardDescr& descr : neighbors_) {
LOG(DEBUG) << "requesting outbound queue of 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) {
td::actor::send_closure(std::move(self), &ValidateQuery::got_neighbor_out_queue, i,
std::move(res));
});
++i;
if (is_lite_) {
for (block::McShardDescr& descr : neighbors_) {
LOG(DEBUG) << "getting outbound queue of neighbor #" << i << " from collated data : " << descr.blk_.to_str();
td::Bits256 state_root_hash;
if (descr.blk_.seqno() == 0) {
state_root_hash = descr.blk_.root_hash;
} else {
Ref<vm::Cell> state_root = get_virt_state_root(descr.blk_.root_hash);
if (state_root.is_null()) {
return reject_query(PSTRING() << "cannot get hash of state root: " << descr.blk_);
}
state_root_hash = state_root->get_hash().bits();
}
auto it = virt_roots_.find(state_root_hash);
if (it == virt_roots_.end()) {
return reject_query(PSTRING() << "cannot get state root form collated data: " << descr.blk_);
}
auto state = ShardStateQ::fetch(descr.blk_, {}, it->second);
if (state.is_error()) {
return reject_query("cannot fetch shard state from collated data", state.move_as_error());
}
++pending;
send_closure_later(get_self(), &ValidateQuery::got_neighbor_out_queue, i, state.move_as_ok()->message_queue());
++i;
}
} else {
for (block::McShardDescr& descr : neighbors_) {
LOG(DEBUG) << "requesting outbound queue of 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) {
td::actor::send_closure(std::move(self), &ValidateQuery::got_neighbor_out_queue, i,
std::move(res));
});
++i;
}
}
return true;
}
@ -5430,6 +5504,24 @@ bool ValidateQuery::check_mc_block_extra() {
return true;
}
Ref<vm::Cell> ValidateQuery::get_virt_state_root(td::Bits256 block_root_hash) {
auto it = virt_roots_.find(block_root_hash);
if (it == virt_roots_.end()) {
return {};
}
Ref<vm::Cell> root = it->second;
block::gen::Block::Record block;
if (!tlb::unpack_cell(root, block)) {
return {};
}
vm::CellSlice upd_cs{vm::NoVmSpec(), block.state_update};
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 // merkle update
&& upd_cs.size_ext() == 0x20228)) {
return {};
}
return vm::MerkleProof::virtualize_raw(upd_cs.prefetch_ref(1), {0, 1});
}
/*
*
* MAIN VALIDATOR FUNCTION
@ -5533,7 +5625,7 @@ bool ValidateQuery::try_validate() {
} catch (vm::VmError& err) {
return fatal_error(-666, err.get_msg());
} catch (vm::VmVirtError& err) {
return fatal_error(-666, err.get_msg());
return reject_query(err.get_msg());
}
return save_candidate();
}