mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
Tonlib method getShardBlockProof (#465)
* Tonlib method getShardBlockProof * Clarify limit of result.size() in getShardBlockProof
This commit is contained in:
parent
9c6787d2ff
commit
2512f0287b
8 changed files with 337 additions and 0 deletions
|
@ -52,6 +52,8 @@ liteServer.partialBlockProof complete:Bool from:tonNode.blockIdExt to:tonNode.bl
|
|||
liteServer.configInfo mode:# id:tonNode.blockIdExt state_proof:bytes config_proof:bytes = liteServer.ConfigInfo;
|
||||
liteServer.validatorStats mode:# id:tonNode.blockIdExt count:int complete:Bool state_proof:bytes data_proof:bytes = liteServer.ValidatorStats;
|
||||
liteServer.libraryResult result:(vector liteServer.libraryEntry) = liteServer.LibraryResult;
|
||||
liteServer.shardBlockLink id:tonNode.blockIdExt proof:bytes = liteServer.ShardBlockLink;
|
||||
liteServer.shardBlockProof masterchain_id:tonNode.blockIdExt links:(vector liteServer.shardBlockLink) = liteServer.ShardBlockProof;
|
||||
|
||||
liteServer.debug.verbosity value:int = liteServer.debug.Verbosity;
|
||||
|
||||
|
@ -78,6 +80,7 @@ liteServer.getConfigAll mode:# id:tonNode.blockIdExt = liteServer.ConfigInfo;
|
|||
liteServer.getConfigParams mode:# id:tonNode.blockIdExt param_list:(vector int) = liteServer.ConfigInfo;
|
||||
liteServer.getValidatorStats#091a58bc mode:# id:tonNode.blockIdExt limit:int start_after:mode.0?int256 modified_after:mode.2?int = liteServer.ValidatorStats;
|
||||
liteServer.getLibraries library_list:(vector int256) = liteServer.LibraryResult;
|
||||
liteServer.getShardBlockProof id:tonNode.blockIdExt = liteServer.ShardBlockProof;
|
||||
|
||||
liteServer.queryPrefix = Object;
|
||||
liteServer.query data:bytes = Object;
|
||||
|
|
Binary file not shown.
|
@ -219,6 +219,9 @@ blocks.header id:ton.blockIdExt global_id:int32 version:int32 flags:# after_merg
|
|||
|
||||
blocks.signature node_id_short:int256 signature:bytes = blocks.Signature;
|
||||
blocks.blockSignatures id:ton.blockIdExt signatures:(vector blocks.signature) = blocks.BlockSignatures;
|
||||
blocks.shardBlockLink id:ton.blockIdExt proof:bytes = blocks.ShardBlockLink;
|
||||
blocks.blockLinkBack to_key_block:Bool from:ton.blockIdExt to:ton.blockIdExt dest_proof:bytes proof:bytes state_proof:bytes = blocks.BlockLinkBack;
|
||||
blocks.shardBlockProof from:ton.blockIdExt mc_id:ton.blockIdExt links:(vector blocks.shardBlockLink) mc_proof:(vector blocks.blockLinkBack) = blocks.ShardBlockProof;
|
||||
|
||||
configInfo config:tvm.cell = ConfigInfo;
|
||||
|
||||
|
@ -311,6 +314,7 @@ blocks.lookupBlock mode:int32 id:ton.blockId lt:int64 utime:int32 = ton.BlockIdE
|
|||
blocks.getTransactions id:ton.blockIdExt mode:# count:# after:blocks.accountTransactionId = blocks.Transactions;
|
||||
blocks.getBlockHeader id:ton.blockIdExt = blocks.Header;
|
||||
blocks.getMasterchainBlockSignatures seqno:int32 = blocks.BlockSignatures;
|
||||
blocks.getShardBlockProof id:ton.blockIdExt mode:# from:mode.0?ton.blockIdExt = blocks.ShardBlockProof;
|
||||
|
||||
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
|
||||
onLiteServerQueryError id:int64 error:error = Ok;
|
||||
|
|
Binary file not shown.
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -145,6 +145,9 @@ class LiteQuery : public td::actor::Actor {
|
|||
bool construct_proof_link_back_cont(ton::BlockIdExt cur, ton::BlockIdExt next);
|
||||
bool adjust_last_proof_link(ton::BlockIdExt cur, Ref<vm::Cell> block_root);
|
||||
bool finish_proof_chain(ton::BlockIdExt id);
|
||||
void perform_getShardBlockProof(BlockIdExt blkid);
|
||||
void continue_getShardBlockProof(Ref<BlockData> cur_block,
|
||||
std::vector<std::pair<BlockIdExt, td::BufferSlice>> result);
|
||||
|
||||
void load_prevKeyBlock(ton::BlockIdExt blkid, td::Promise<std::pair<BlockIdExt, Ref<BlockQ>>>);
|
||||
void continue_loadPrevKeyBlock(ton::BlockIdExt blkid, td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res,
|
||||
|
|
Loading…
Reference in a new issue