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:
parent
849d995346
commit
625516c568
7 changed files with 214 additions and 37 deletions
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue