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

@ -1460,6 +1460,179 @@ class GetMasterchainBlockSignatures : public td::actor::Actor {
ton::BlockIdExt last_block_;
};
class GetShardBlockProof : public td::actor::Actor {
public:
GetShardBlockProof(ExtClientRef ext_client_ref, ton::BlockIdExt id, ton::BlockIdExt from,
td::actor::ActorShared<> parent,
td::Promise<tonlib_api_ptr<tonlib_api::blocks_shardBlockProof>>&& promise)
: id_(id), from_(from), parent_(std::move(parent)), promise_(std::move(promise)) {
client_.set_client(ext_client_ref);
}
void start_up() override {
if (from_.is_masterchain_ext()) {
got_from_block(from_);
} else {
client_.with_last_block([SelfId = actor_id(this)](td::Result<LastBlockState> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &GetShardBlockProof::abort, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &GetShardBlockProof::got_from_block, R.move_as_ok().last_block_id);
}
});
}
}
void got_from_block(ton::BlockIdExt from) {
from_ = from;
CHECK(from_.is_masterchain_ext());
client_.send_query(
ton::lite_api::liteServer_getShardBlockProof(ton::create_tl_lite_block_id(id_)),
[SelfId = actor_id(this)](td::Result<lite_api_ptr<ton::lite_api::liteServer_shardBlockProof>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &GetShardBlockProof::abort, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &GetShardBlockProof::got_shard_block_proof, R.move_as_ok());
}
});
}
void got_shard_block_proof(lite_api_ptr<ton::lite_api::liteServer_shardBlockProof> result) {
mc_id_ = create_block_id(std::move(result->masterchain_id_));
if (!mc_id_.is_masterchain_ext()) {
abort(td::Status::Error("got invalid masterchain block id"));
return;
}
if (result->links_.size() > 8) {
abort(td::Status::Error("chain is too long"));
return;
}
ton::BlockIdExt cur_id = mc_id_;
try {
for (auto& link : result->links_) {
ton::BlockIdExt prev_id = create_block_id(link->id_);
td::BufferSlice proof = std::move(link->proof_);
auto R = vm::std_boc_deserialize(proof);
if (R.is_error()) {
abort(TonlibError::InvalidBagOfCells("proof"));
return;
}
auto block_root = vm::MerkleProof::virtualize(R.move_as_ok(), 1);
if (cur_id.root_hash != block_root->get_hash().bits()) {
abort(td::Status::Error("invalid block hash in proof"));
return;
}
if (cur_id.is_masterchain()) {
block::gen::Block::Record blk;
block::gen::BlockExtra::Record extra;
block::gen::McBlockExtra::Record mc_extra;
if (!tlb::unpack_cell(block_root, blk) || !tlb::unpack_cell(blk.extra, extra) || !extra.custom->have_refs() ||
!tlb::unpack_cell(extra.custom->prefetch_ref(), mc_extra)) {
abort(td::Status::Error("cannot unpack block header"));
return;
}
block::ShardConfig shards(mc_extra.shard_hashes->prefetch_ref());
td::Ref<block::McShardHash> shard_hash = shards.get_shard_hash(prev_id.shard_full(), true);
if (shard_hash.is_null() || shard_hash->top_block_id() != prev_id) {
abort(td::Status::Error("invalid proof chain: prev block is not in mc shard list"));
return;
}
} else {
std::vector<ton::BlockIdExt> prev;
ton::BlockIdExt mc_blkid;
bool after_split;
td::Status S = block::unpack_block_prev_blk_try(block_root, cur_id, prev, mc_blkid, after_split);
if (S.is_error()) {
abort(std::move(S));
return;
}
CHECK(prev.size() == 1 || prev.size() == 2);
bool found = prev_id == prev[0] || (prev.size() == 2 && prev_id == prev[1]);
if (!found) {
abort(td::Status::Error("invalid proof chain: prev block is not in prev blocks list"));
return;
}
}
links_.emplace_back(prev_id, std::move(proof));
cur_id = prev_id;
}
} catch (vm::VmVirtError& err) {
abort(err.as_status());
return;
}
if (cur_id != id_) {
abort(td::Status::Error("got invalid proof chain"));
return;
}
if (mc_id_.seqno() > from_.seqno()) {
abort(td::Status::Error("from mc block is too old"));
return;
}
client_.send_query(
ton::lite_api::liteServer_getBlockProof(0x1001, ton::create_tl_lite_block_id(from_),
ton::create_tl_lite_block_id(mc_id_)),
[SelfId = actor_id(this)](td::Result<lite_api_ptr<ton::lite_api::liteServer_partialBlockProof>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &GetShardBlockProof::abort, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &GetShardBlockProof::got_mc_proof, R.move_as_ok());
}
});
}
void got_mc_proof(lite_api_ptr<ton::lite_api::liteServer_partialBlockProof> result) {
auto R = liteclient::deserialize_proof_chain(std::move(result));
if (R.is_error()) {
abort(R.move_as_error());
return;
}
auto chain = R.move_as_ok();
if (chain->from != from_ || chain->to != mc_id_ || !chain->complete || chain->link_count() > 1) {
abort(td::Status::Error("got invalid proof chain"));
return;
}
auto S = chain->validate();
if (S.is_error()) {
abort(std::move(S));
return;
}
std::vector<ton::tl_object_ptr<tonlib_api::blocks_shardBlockLink>> links;
std::vector<ton::tl_object_ptr<tonlib_api::blocks_blockLinkBack>> mc_proof;
for (const auto& p : links_) {
links.push_back(
ton::create_tl_object<tonlib_api::blocks_shardBlockLink>(to_tonlib_api(p.first), p.second.as_slice().str()));
}
if (chain->link_count() == 1) {
auto& link = chain->last_link();
td::BufferSlice dest_proof = vm::std_boc_serialize(link.dest_proof).move_as_ok();
td::BufferSlice proof = vm::std_boc_serialize(link.proof).move_as_ok();
td::BufferSlice state_proof = vm::std_boc_serialize(link.state_proof).move_as_ok();
mc_proof.push_back(ton::create_tl_object<tonlib_api::blocks_blockLinkBack>(
link.is_key, to_tonlib_api(link.from), to_tonlib_api(link.to), dest_proof.as_slice().str(),
proof.as_slice().str(), state_proof.as_slice().str()));
}
promise_.set_result(ton::create_tl_object<tonlib_api::blocks_shardBlockProof>(
to_tonlib_api(from_), to_tonlib_api(mc_id_), std::move(links), std::move(mc_proof)));
stop();
}
void abort(td::Status error) {
promise_.set_error(std::move(error));
stop();
}
private:
ton::BlockIdExt id_, from_, mc_id_;
td::actor::ActorShared<> parent_;
td::Promise<tonlib_api_ptr<tonlib_api::blocks_shardBlockProof>> promise_;
ExtClient client_;
std::vector<std::pair<ton::BlockIdExt, td::BufferSlice>> links_;
};
TonlibClient::TonlibClient(td::unique_ptr<TonlibCallback> callback) : callback_(std::move(callback)) {
}
TonlibClient::~TonlibClient() = default;
@ -4413,6 +4586,12 @@ auto to_lite_api(const tonlib_api::ton_blockIdExt& blk) -> td::Result<lite_api_p
blk.workchain_, blk.shard_, blk.seqno_, root_hash, file_hash);
}
td::Result<ton::BlockIdExt> to_block_id(const tonlib_api::ton_blockIdExt& blk) {
TRY_RESULT(root_hash, to_bits256(blk.root_hash_, "blk.root_hash"))
TRY_RESULT(file_hash, to_bits256(blk.file_hash_, "blk.file_hash"))
return ton::BlockIdExt(blk.workchain_, blk.shard_, blk.seqno_, root_hash, file_hash);
}
td::Status TonlibClient::do_request(const tonlib_api::getConfigParam& request,
td::Promise<object_ptr<tonlib_api::configInfo>>&& promise) {
TRY_RESULT(lite_block, to_lite_api(*request.id_))
@ -4624,6 +4803,19 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_getMasterchainBlock
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::blocks_getShardBlockProof& request,
td::Promise<object_ptr<tonlib_api::blocks_shardBlockProof>>&& promise) {
TRY_RESULT(id, to_block_id(*request.id_));
ton::BlockIdExt from;
if (request.mode_ & 1) {
TRY_RESULT_ASSIGN(from, to_block_id(*request.id_));
}
auto actor_id = actor_id_++;
actors_[actor_id] = td::actor::create_actor<GetShardBlockProof>("GetShardBlockProof", client_.get_client(), id, from,
actor_shared(this, actor_id), std::move(promise));
return td::Status::OK();
}
void TonlibClient::load_libs_from_disk() {
LOG(DEBUG) << "loading libraries from disk cache";
auto r_data = kv_->get("tonlib.libcache");

View file

@ -366,6 +366,8 @@ class TonlibClient : public td::actor::Actor {
td::Promise<object_ptr<tonlib_api::blocks_header>>&& promise);
td::Status do_request(const tonlib_api::blocks_getMasterchainBlockSignatures& request,
td::Promise<object_ptr<tonlib_api::blocks_blockSignatures>>&& promise);
td::Status do_request(const tonlib_api::blocks_getShardBlockProof& request,
td::Promise<object_ptr<tonlib_api::blocks_shardBlockProof>>&& promise);
td::Status do_request(const tonlib_api::getConfigParam& request,
td::Promise<object_ptr<tonlib_api::configInfo>>&& promise);