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

LS getDispatchQueueInfo and getDispatchQueueMessages methods (#1161)

* liteServer.getDispatchQueueInfo query

* Fix getting min/max lt

* LS getDispatchQueueMessages method
This commit is contained in:
SpyCheese 2024-09-13 20:47:30 +03:00 committed by GitHub
parent 9f203890f4
commit b304b1c7be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 364 additions and 3 deletions

View file

@ -290,6 +290,13 @@ void LiteQuery::perform() {
[&](lite_api::liteServer_getBlockOutMsgQueueSize& q) {
this->perform_getBlockOutMsgQueueSize(q.mode_, create_block_id(q.id_));
},
[&](lite_api::liteServer_getDispatchQueueInfo& q) {
this->perform_getDispatchQueueInfo(q.mode_, create_block_id(q.id_), q.after_addr_, q.max_accounts_);
},
[&](lite_api::liteServer_getDispatchQueueMessages& q) {
this->perform_getDispatchQueueMessages(q.mode_, create_block_id(q.id_), q.addr_,
std::max<td::int64>(q.after_lt_, 0), q.max_messages_);
},
[&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); }));
}
@ -3432,6 +3439,248 @@ void LiteQuery::finish_getBlockOutMsgQueueSize() {
finish_query(std::move(b));
}
void LiteQuery::perform_getDispatchQueueInfo(int mode, BlockIdExt blkid, StdSmcAddress after_addr, int max_accounts) {
LOG(INFO) << "started a getDispatchQueueInfo(" << blkid.to_str() << ", " << mode << ") liteserver query";
mode_ = mode;
if (!blkid.is_valid_full()) {
fatal_error("invalid BlockIdExt");
return;
}
if (max_accounts <= 0) {
fatal_error("invalid max_accounts");
return;
}
set_continuation([=]() -> void { finish_getDispatchQueueInfo(after_addr, max_accounts); });
request_block_data_state(blkid);
}
void LiteQuery::finish_getDispatchQueueInfo(StdSmcAddress after_addr, int max_accounts) {
LOG(INFO) << "completing getDispatchQueueInfo() query";
bool with_proof = mode_ & 1;
Ref<vm::Cell> state_root = state_->root_cell();
vm::MerkleProofBuilder pb;
if (with_proof) {
pb = vm::MerkleProofBuilder{state_root};
state_root = pb.root();
}
std::unique_ptr<vm::AugmentedDictionary> dispatch_queue;
block::gen::ShardStateUnsplit::Record sstate;
block::gen::OutMsgQueueInfo::Record out_msg_queue_info;
block::gen::OutMsgQueueExtra::Record out_msg_queue_extra;
if (!tlb::unpack_cell(state_root, sstate) || !tlb::unpack_cell(sstate.out_msg_queue_info, out_msg_queue_info)) {
fatal_error("cannot unpack shard state");
return;
}
vm::CellSlice& extra_slice = out_msg_queue_info.extra.write();
if (extra_slice.fetch_long(1)) {
if (!tlb::unpack(extra_slice, out_msg_queue_extra)) {
fatal_error("cannot unpack OutMsgQueueExtra");
return;
}
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(out_msg_queue_extra.dispatch_queue, 256,
block::tlb::aug_DispatchQueue);
} else {
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(256, block::tlb::aug_DispatchQueue);
}
int remaining = std::min(max_accounts, 64);
bool complete = false;
std::vector<tl_object_ptr<lite_api::liteServer_accountDispatchQueueInfo>> result;
bool allow_eq;
if (mode_ & 2) {
allow_eq = false;
} else {
allow_eq = true;
after_addr = td::Bits256::zero();
}
while (true) {
auto value = dispatch_queue->extract_value(dispatch_queue->lookup_nearest_key(after_addr, true, allow_eq));
allow_eq = false;
if (value.is_null()) {
complete = true;
break;
}
if (remaining == 0) {
break;
}
--remaining;
StdSmcAddress addr = after_addr;
vm::Dictionary dict{64};
td::uint64 dict_size;
if (!block::unpack_account_dispatch_queue(value, dict, dict_size)) {
fatal_error(PSTRING() << "invalid account dispatch queue for account " << addr.to_hex());
return;
}
CHECK(dict_size > 0);
td::BitArray<64> min_lt, max_lt;
dict.get_minmax_key(min_lt.bits(), 64, false, false);
dict.get_minmax_key(max_lt.bits(), 64, true, false);
result.push_back(create_tl_object<lite_api::liteServer_accountDispatchQueueInfo>(addr, dict_size, min_lt.to_ulong(),
max_lt.to_ulong()));
}
td::BufferSlice proof;
if (with_proof) {
Ref<vm::Cell> proof1, proof2;
if (!make_state_root_proof(proof1)) {
return;
}
if (!pb.extract_proof_to(proof2)) {
fatal_error("unknown error creating Merkle proof");
return;
}
auto r_proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
if (r_proof.is_error()) {
fatal_error(r_proof.move_as_error());
return;
}
proof = r_proof.move_as_ok();
}
LOG(INFO) << "getDispatchQueueInfo(" << blk_id_.to_str() << ", " << mode_ << ") query completed";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_dispatchQueueInfo>(
mode_, ton::create_tl_lite_block_id(blk_id_), std::move(result), complete, std::move(proof));
finish_query(std::move(b));
}
void LiteQuery::perform_getDispatchQueueMessages(int mode, BlockIdExt blkid, StdSmcAddress addr, LogicalTime lt,
int max_messages) {
LOG(INFO) << "started a getDispatchQueueMessages(" << blkid.to_str() << ", " << mode << ") liteserver query";
mode_ = mode;
if (!blkid.is_valid_full()) {
fatal_error("invalid BlockIdExt");
return;
}
if (max_messages <= 0) {
fatal_error("invalid max_messages");
return;
}
set_continuation([=]() -> void { finish_getDispatchQueueMessages(addr, lt, max_messages); });
request_block_data_state(blkid);
}
void LiteQuery::finish_getDispatchQueueMessages(StdSmcAddress addr, LogicalTime lt, int max_messages) {
LOG(INFO) << "completing getDispatchQueueMessages() query";
bool with_proof = mode_ & lite_api::liteServer_getDispatchQueueMessages::WANT_PROOF_MASK;
bool one_account = mode_ & lite_api::liteServer_getDispatchQueueMessages::ONE_ACCOUNT_MASK;
bool with_messages_boc = mode_ & lite_api::liteServer_getDispatchQueueMessages::MESSAGES_BOC_MASK;
Ref<vm::Cell> state_root = state_->root_cell();
vm::MerkleProofBuilder pb;
if (with_proof) {
pb = vm::MerkleProofBuilder{state_root};
state_root = pb.root();
}
std::unique_ptr<vm::AugmentedDictionary> dispatch_queue;
block::gen::ShardStateUnsplit::Record sstate;
block::gen::OutMsgQueueInfo::Record out_msg_queue_info;
block::gen::OutMsgQueueExtra::Record out_msg_queue_extra;
if (!tlb::unpack_cell(state_root, sstate) || !tlb::unpack_cell(sstate.out_msg_queue_info, out_msg_queue_info)) {
fatal_error("cannot unpack shard state");
return;
}
vm::CellSlice& extra_slice = out_msg_queue_info.extra.write();
if (extra_slice.fetch_long(1)) {
if (!tlb::unpack(extra_slice, out_msg_queue_extra)) {
fatal_error("cannot unpack OutMsgQueueExtra");
return;
}
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(out_msg_queue_extra.dispatch_queue, 256,
block::tlb::aug_DispatchQueue);
} else {
dispatch_queue = std::make_unique<vm::AugmentedDictionary>(256, block::tlb::aug_DispatchQueue);
}
int remaining = std::min(max_messages, with_messages_boc ? 16 : 64);
bool complete = false;
std::vector<tl_object_ptr<lite_api::liteServer_dispatchQueueMessage>> result;
std::vector<td::Ref<vm::Cell>> message_roots;
td::Bits256 orig_addr = addr;
bool first = true;
while (remaining > 0) {
auto value = dispatch_queue->extract_value(dispatch_queue->lookup_nearest_key(addr, true, first));
if (value.is_null() || (one_account && addr != orig_addr)) {
complete = true;
break;
}
vm::Dictionary account_queue{64};
td::uint64 dict_size;
if (!block::unpack_account_dispatch_queue(value, account_queue, dict_size)) {
fatal_error(PSTRING() << "invalid account dispatch queue for account " << addr.to_hex());
return;
}
CHECK(dict_size > 0);
while (true) {
td::BitArray<64> lt_key;
lt_key.store_ulong(lt);
auto value2 = account_queue.lookup_nearest_key(lt_key, true, false);
if (value2.is_null()) {
break;
}
lt = lt_key.to_ulong();
if (remaining == 0) {
break;
}
--remaining;
auto msg_env = value2->prefetch_ref();
block::tlb::MsgEnvelope::Record_std env;
if (msg_env.is_null() || !tlb::unpack_cell(msg_env, env)) {
fatal_error(PSTRING() << "invalid message in dispatch queue for account " << addr.to_hex() << ", lt " << lt);
return;
}
message_roots.push_back(env.msg);
tl_object_ptr<lite_api::liteServer_transactionMetadata> metadata_tl;
if (env.metadata) {
auto& metadata = env.metadata.value();
metadata_tl = create_tl_object<lite_api::liteServer_transactionMetadata>(
0, metadata.depth,
create_tl_object<lite_api::liteServer_accountId>(metadata.initiator_wc, metadata.initiator_addr),
metadata.initiator_lt);
} else {
metadata_tl = create_tl_object<lite_api::liteServer_transactionMetadata>(
0, -1, create_tl_object<lite_api::liteServer_accountId>(workchainInvalid, td::Bits256::zero()), -1);
}
result.push_back(create_tl_object<lite_api::liteServer_dispatchQueueMessage>(addr, lt, env.msg->get_hash().bits(),
std::move(metadata_tl)));
}
first = false;
lt = 0;
}
td::BufferSlice proof;
if (with_proof) {
Ref<vm::Cell> proof1, proof2;
if (!make_state_root_proof(proof1)) {
return;
}
if (!pb.extract_proof_to(proof2)) {
fatal_error("unknown error creating Merkle proof");
return;
}
auto r_proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)});
if (r_proof.is_error()) {
fatal_error(r_proof.move_as_error());
return;
}
proof = r_proof.move_as_ok();
}
td::BufferSlice messages_boc;
if (with_messages_boc) {
auto r_messages_boc = vm::std_boc_serialize_multi(std::move(message_roots));
if (r_messages_boc.is_error()) {
fatal_error(r_messages_boc.move_as_error());
return;
}
messages_boc = std::move(messages_boc);
}
LOG(INFO) << "getDispatchQueueMessages(" << blk_id_.to_str() << ", " << mode_ << ") query completed";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_dispatchQueueMessages>(
mode_, ton::create_tl_lite_block_id(blk_id_), std::move(result), complete, std::move(proof),
std::move(messages_boc));
finish_query(std::move(b));
}
void LiteQuery::perform_nonfinal_getCandidate(td::Bits256 source, BlockIdExt blkid, td::Bits256 collated_data_hash) {
LOG(INFO) << "started a nonfinal.getCandidate liteserver query";