mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-15 04:32:21 +00:00
Out msg queue proof: send only the required part
This commit is contained in:
parent
597fd8443d
commit
81d32ba5d6
2 changed files with 68 additions and 11 deletions
|
@ -852,6 +852,10 @@ void FullNodeShardImpl::download_out_msg_queue_proof(BlockIdExt block_id, ShardI
|
||||||
// TODO: maybe more complex download (like other requests here)
|
// TODO: maybe more complex download (like other requests here)
|
||||||
// TODO: estimate max size
|
// TODO: estimate max size
|
||||||
auto &b = choose_neighbour(true);
|
auto &b = choose_neighbour(true);
|
||||||
|
if (b.adnl_id == adnl::AdnlNodeIdShort::zero()) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "no nodes"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto P = td::PromiseCreator::lambda(
|
auto P = td::PromiseCreator::lambda(
|
||||||
[=, promise = create_neighbour_promise(b, std::move(promise), true)](td::Result<td::BufferSlice> R) mutable {
|
[=, promise = create_neighbour_promise(b, std::move(promise), true)](td::Result<td::BufferSlice> R) mutable {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "vm/cells/MerkleProof.h"
|
#include "vm/cells/MerkleProof.h"
|
||||||
#include "common/delay.h"
|
#include "common/delay.h"
|
||||||
#include "interfaces/validator-manager.h"
|
#include "interfaces/validator-manager.h"
|
||||||
|
#include "block/block-parse.h"
|
||||||
|
#include "block/block-auto.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
|
@ -51,9 +53,31 @@ td::Result<td::Ref<OutMsgQueueProof>> OutMsgQueueProof::fetch(BlockIdExt block_i
|
||||||
// Validate proof
|
// Validate proof
|
||||||
auto state_root = vm::CellSlice(vm::NoVm(), queue_proof).prefetch_ref(0);
|
auto state_root = vm::CellSlice(vm::NoVm(), queue_proof).prefetch_ref(0);
|
||||||
TRY_RESULT_PREFIX(state, ShardStateQ::fetch(block_id, {}, state_root), "invalid proof: ");
|
TRY_RESULT_PREFIX(state, ShardStateQ::fetch(block_id, {}, state_root), "invalid proof: ");
|
||||||
TRY_RESULT_PREFIX(queue, state->message_queue(), "invalid proof: ");
|
TRY_RESULT_PREFIX(outq_descr, state->message_queue(), "invalid proof: ");
|
||||||
auto queue_root = queue->root_cell();
|
|
||||||
if (queue_root->get_level() != 0) {
|
block::gen::OutMsgQueueInfo::Record qinfo;
|
||||||
|
if (!tlb::unpack_cell(outq_descr->root_cell(), qinfo)) {
|
||||||
|
return td::Status::Error("invalid proof: invalid message queue");
|
||||||
|
}
|
||||||
|
td::Ref<vm::Cell> proc_info = qinfo.proc_info->prefetch_ref(0);
|
||||||
|
if (proc_info.not_null() && proc_info->get_level() != 0) {
|
||||||
|
return td::Status::Error("invalid proof: proc_info has prunned branches");
|
||||||
|
}
|
||||||
|
td::Ref<vm::Cell> ihr_pending = qinfo.ihr_pending->prefetch_ref(0);
|
||||||
|
if (ihr_pending.not_null() && ihr_pending->get_level() != 0) {
|
||||||
|
return td::Status::Error("invalid proof: ihr_pending has prunned branches");
|
||||||
|
}
|
||||||
|
auto queue =
|
||||||
|
std::make_unique<vm::AugmentedDictionary>(qinfo.out_queue->prefetch_ref(0), 352, block::tlb::aug_OutMsgQueue);
|
||||||
|
td::BitArray<96> prefix;
|
||||||
|
td::BitPtr ptr = prefix.bits();
|
||||||
|
ptr.store_int(dst_shard.workchain, 32);
|
||||||
|
ptr.advance(32);
|
||||||
|
ptr.store_uint(dst_shard.shard, 64);
|
||||||
|
if (!queue->cut_prefix_subdict(prefix.bits(), 32 + dst_shard.pfx_len())) {
|
||||||
|
return td::Status::Error("invalid proof: failed to cut queue dict");
|
||||||
|
}
|
||||||
|
if (queue->get_root_cell().not_null() && queue->get_root_cell()->get_level() != 0) {
|
||||||
return td::Status::Error("invalid proof: msg queue has prunned branches");
|
return td::Status::Error("invalid proof: msg queue has prunned branches");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,14 +88,20 @@ td::Result<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> OutMsgQueueProof::s
|
||||||
ShardIdFull dst_shard,
|
ShardIdFull dst_shard,
|
||||||
Ref<vm::Cell> state_root,
|
Ref<vm::Cell> state_root,
|
||||||
Ref<vm::Cell> block_root) {
|
Ref<vm::Cell> block_root) {
|
||||||
|
if (!dst_shard.is_valid_ext()) {
|
||||||
|
return td::Status::Error("invalid shard");
|
||||||
|
}
|
||||||
vm::MerkleProofBuilder mpb{std::move(state_root)};
|
vm::MerkleProofBuilder mpb{std::move(state_root)};
|
||||||
TRY_RESULT(state, ShardStateQ::fetch(block_id, {}, mpb.root()));
|
TRY_RESULT(state, ShardStateQ::fetch(block_id, {}, mpb.root()));
|
||||||
TRY_RESULT(outq_descr, state->message_queue());
|
TRY_RESULT(outq_descr, state->message_queue());
|
||||||
|
block::gen::OutMsgQueueInfo::Record qinfo;
|
||||||
|
if (!tlb::unpack_cell(outq_descr->root_cell(), qinfo)) {
|
||||||
|
return td::Status::Error("invalid message queue");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add only required part of msg queue
|
|
||||||
td::HashSet<vm::Cell::Hash> visited;
|
td::HashSet<vm::Cell::Hash> visited;
|
||||||
std::function<void(Ref<vm::Cell>)> dfs = [&](Ref<vm::Cell> cell) {
|
std::function<void(Ref<vm::Cell>)> dfs = [&](Ref<vm::Cell> cell) {
|
||||||
if (!visited.insert(cell->get_hash()).second) {
|
if (cell.is_null() || !visited.insert(cell->get_hash()).second) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm::CellSlice cs(vm::NoVm(), cell);
|
vm::CellSlice cs(vm::NoVm(), cell);
|
||||||
|
@ -79,16 +109,32 @@ td::Result<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> OutMsgQueueProof::s
|
||||||
dfs(cs.prefetch_ref(i));
|
dfs(cs.prefetch_ref(i));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dfs(outq_descr->root_cell());
|
auto dfs_cs = [&](const vm::CellSlice &cs) {
|
||||||
|
for (unsigned i = 0; i < cs.size_refs(); i++) {
|
||||||
|
dfs(cs.prefetch_ref(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dfs_cs(*qinfo.proc_info);
|
||||||
|
dfs_cs(*qinfo.ihr_pending);
|
||||||
|
|
||||||
|
auto queue =
|
||||||
|
std::make_unique<vm::AugmentedDictionary>(qinfo.out_queue->prefetch_ref(0), 352, block::tlb::aug_OutMsgQueue);
|
||||||
|
td::BitArray<96> prefix;
|
||||||
|
td::BitPtr ptr = prefix.bits();
|
||||||
|
ptr.store_int(dst_shard.workchain, 32);
|
||||||
|
ptr.advance(32);
|
||||||
|
ptr.store_uint(dst_shard.shard, 64);
|
||||||
|
if (!queue->cut_prefix_subdict(prefix.bits(), 32 + dst_shard.pfx_len())) {
|
||||||
|
return td::Status::Error("invalid message queue");
|
||||||
|
}
|
||||||
|
dfs(queue->get_root_cell());
|
||||||
|
|
||||||
TRY_RESULT(queue_proof, vm::std_boc_serialize(mpb.extract_proof()));
|
TRY_RESULT(queue_proof, vm::std_boc_serialize(mpb.extract_proof()));
|
||||||
|
|
||||||
td::BufferSlice block_state_proof;
|
td::BufferSlice block_state_proof;
|
||||||
if (block_id.seqno() != 0) {
|
if (block_id.seqno() != 0) {
|
||||||
TRY_RESULT(proof, create_block_state_proof(std::move(block_root)));
|
TRY_RESULT(proof, create_block_state_proof(std::move(block_root)));
|
||||||
TRY_RESULT_ASSIGN(block_state_proof, vm::std_boc_serialize(std::move(proof), 31));
|
TRY_RESULT_ASSIGN(block_state_proof, vm::std_boc_serialize(std::move(proof), 31));
|
||||||
}
|
}
|
||||||
|
|
||||||
return create_tl_object<ton_api::tonNode_outMsgQueueProof>(std::move(queue_proof), std::move(block_state_proof));
|
return create_tl_object<ton_api::tonNode_outMsgQueueProof>(std::move(queue_proof), std::move(block_state_proof));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +229,11 @@ void WaitOutMsgQueueProof::run_net() {
|
||||||
auto P =
|
auto P =
|
||||||
td::PromiseCreator::lambda([SelfId = actor_id(this), block_id = block_id_](td::Result<Ref<OutMsgQueueProof>> R) {
|
td::PromiseCreator::lambda([SelfId = actor_id(this), block_id = block_id_](td::Result<Ref<OutMsgQueueProof>> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
|
if (R.error().code() == ErrorCode::notready) {
|
||||||
LOG(DEBUG) << "failed to get msg queue for " << block_id.to_str() << " from net: " << R.move_as_error();
|
LOG(DEBUG) << "failed to get msg queue for " << block_id.to_str() << " from net: " << R.move_as_error();
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "failed to get msg queue for " << block_id.to_str() << " from net: " << R.move_as_error();
|
||||||
|
}
|
||||||
delay_action([SelfId]() mutable { td::actor::send_closure(SelfId, &WaitOutMsgQueueProof::run_net); },
|
delay_action([SelfId]() mutable { td::actor::send_closure(SelfId, &WaitOutMsgQueueProof::run_net); },
|
||||||
td::Timestamp::in(0.1));
|
td::Timestamp::in(0.1));
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,8 +296,11 @@ void BuildOutMsgQueueProof::got_block_root(Ref<vm::Cell> root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildOutMsgQueueProof::build_proof() {
|
void BuildOutMsgQueueProof::build_proof() {
|
||||||
promise_.set_result(
|
auto result = OutMsgQueueProof::serialize(block_id_, dst_shard_, std::move(state_root_), std::move(block_root_));
|
||||||
OutMsgQueueProof::serialize(block_id_, dst_shard_, std::move(state_root_), std::move(block_root_)));
|
if (result.is_error()) {
|
||||||
|
LOG(ERROR) << "Failed to build msg queue proof: " << result.error();
|
||||||
|
}
|
||||||
|
promise_.set_result(std::move(result));
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue