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

Tonlib method getShardBlockProof (#465)

* Tonlib method getShardBlockProof

* Clarify limit of result.size() in getShardBlockProof
This commit is contained in:
SpyCheese 2022-09-20 10:49:28 +03:00 committed by GitHub
parent 9c6787d2ff
commit 2512f0287b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 337 additions and 0 deletions

View file

@ -201,6 +201,9 @@ void LiteQuery::start_up() {
[&](lite_api::liteServer_getLibraries& q) {
this->perform_getLibraries(q.library_list_);
},
[&](lite_api::liteServer_getShardBlockProof& q) {
this->perform_getShardBlockProof(create_block_id(q.id_));
},
[&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); }));
}
@ -2432,5 +2435,135 @@ void LiteQuery::continue_getValidatorStats(int mode, int limit, Bits256 start_af
finish_query(std::move(b));
}
void LiteQuery::perform_getShardBlockProof(BlockIdExt blkid) {
LOG(INFO) << "started a getMasterchainInfo(" << blkid.to_str() << ") liteserver query";
if (!blkid.is_valid_ext()) {
fatal_error("invalid block id");
return;
}
if (blkid.is_masterchain()) {
LOG(INFO) << "getShardBlockProof() query completed";
auto b = create_serialize_tl_object<lite_api::liteServer_shardBlockProof>(
create_tl_lite_block_id(blkid), std::vector<tl_object_ptr<lite_api::liteServer_shardBlockLink>>());
finish_query(std::move(b));
return;
}
blk_id_ = blkid;
get_block_handle_checked(blkid, [manager = manager_, Self = actor_id(this)](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
return;
}
ConstBlockHandle handle = R.move_as_ok();
if (!handle->inited_masterchain_ref_block()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, td::Status::Error("block doesn't have masterchain ref"));
return;
}
AccountIdPrefixFull pfx{masterchainId, shardIdAll};
td::actor::send_closure_later(
manager, &ValidatorManager::get_block_by_seqno_from_db, pfx, handle->masterchain_ref_block(),
[Self, manager](td::Result<ConstBlockHandle> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
} else {
ConstBlockHandle handle = R.move_as_ok();
td::actor::send_closure_later(
manager, &ValidatorManager::get_block_data_from_db, handle, [Self](td::Result<Ref<BlockData>> R) {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getShardBlockProof, R.move_as_ok(),
std::vector<std::pair<BlockIdExt, td::BufferSlice>>());
}
});
}
});
});
}
void LiteQuery::continue_getShardBlockProof(Ref<BlockData> cur_block,
std::vector<std::pair<BlockIdExt, td::BufferSlice>> result) {
BlockIdExt cur_id = cur_block->block_id();
BlockIdExt prev_id;
vm::MerkleProofBuilder mpb{cur_block->root_cell()};
if (cur_id.is_masterchain()) {
base_blk_id_ = cur_id;
block::gen::Block::Record blk;
block::gen::BlockExtra::Record extra;
block::gen::McBlockExtra::Record mc_extra;
if (!tlb::unpack_cell(mpb.root(), blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
fatal_error("cannot unpack header of block "s + cur_id.to_str());
return;
}
block::ShardConfig shards(mc_extra.shard_hashes->prefetch_ref());
ShardIdFull shard_id = blk_id_.shard_full();
shard_id.shard = (shard_id.shard & ~(1 << (63 - shard_id.pfx_len()))) | 1;
Ref<block::McShardHash> shard_hash = shards.get_shard_hash(shard_id, false);
if (shard_hash.is_null()) {
fatal_error("shard not found");
return;
}
prev_id = shard_hash->top_block_id();
} else {
std::vector<BlockIdExt> prev;
BlockIdExt mc_blkid;
bool after_split;
td::Status S = block::unpack_block_prev_blk_try(mpb.root(), cur_id, prev, mc_blkid, after_split);
if (S.is_error()) {
fatal_error(std::move(S));
return;
}
bool found = false;
for (const BlockIdExt& id : prev) {
if (shard_intersects(id.shard_full(), blk_id_.shard_full())) {
found = true;
prev_id = id;
break;
}
}
if (!found) {
fatal_error("failed to find block chain");
return;
}
}
auto proof = mpb.extract_proof_boc();
if (proof.is_error()) {
fatal_error(proof.move_as_error_prefix("cannot serialize Merkle proof : "));
return;
}
result.emplace_back(prev_id, proof.move_as_ok());
if (prev_id == blk_id_) {
CHECK(base_blk_id_.is_masterchain());
std::vector<tl_object_ptr<lite_api::liteServer_shardBlockLink>> links;
for (auto& p : result) {
links.push_back(
create_tl_object<lite_api::liteServer_shardBlockLink>(create_tl_lite_block_id(p.first), std::move(p.second)));
}
LOG(INFO) << "getShardBlockProof() query completed";
auto b = create_serialize_tl_object<lite_api::liteServer_shardBlockProof>(create_tl_lite_block_id(base_blk_id_),
std::move(links));
finish_query(std::move(b));
return;
}
if (result.size() == 8) {
// Chains of shardblocks between masterchain blocks can't be longer than 8 (see collator.cpp:991)
fatal_error("proof chain is too long");
return;
}
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, prev_id,
[Self = actor_id(this), result = std::move(result)](td::Result<Ref<BlockData>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, R.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getShardBlockProof, R.move_as_ok(),
std::move(result));
}
});
}
} // namespace validator
} // namespace ton