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

Merge message dispatch queue (#1030)

* Deferred messages and msg metadata

* Store out msg queue size in state

* Add checks for queue processing

1. Collator must process at least one message from AccountDispatchQueue (unless block is full)
2. The first message from a transaction is not counted, it cannot be deferred (unless AccountDispatchQueue is not empty)

* Return msg metadata from LS in listBlockTransactions[Ext]

* Enable new features by capabilities

* Changes in deferred messages

* Process deferred messages via new_msgs in collator
* Rework setting deferred_lt, bring back check_message_processing_order, check order of deferred_lt in validator

* Use have_unprocessed_account_dispatch_queue_ in collator

* Fix setting transaction lt for deferred messages

* Fix lite-client compilation error

* Changes in process_dispatch_queue, rename deferred_lt -> emitted_lt

* Fix compilation error

* Use uint64 for msg queue size

* Add liteServer.getBlockOutMsgQueueSize

* Fix compilation error

* Fix typos in comments

---------

Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
EmelyanenkoK 2024-06-27 16:12:23 +03:00 committed by GitHub
parent 38fc1d5456
commit 0daee1d887
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 1889 additions and 318 deletions

View file

@ -287,6 +287,9 @@ void LiteQuery::perform() {
[&](lite_api::liteServer_getOutMsgQueueSizes& q) {
this->perform_getOutMsgQueueSizes(q.mode_ & 1 ? ShardIdFull(q.wc_, q.shard_) : td::optional<ShardIdFull>());
},
[&](lite_api::liteServer_getBlockOutMsgQueueSize& q) {
this->perform_getBlockOutMsgQueueSize(q.mode_, create_block_id(q.id_));
},
[&](auto& obj) { this->abort_query(td::Status::Error(ErrorCode::protoviolation, "unknown query")); }));
}
@ -2376,6 +2379,45 @@ void LiteQuery::perform_listBlockTransactions(BlockIdExt blkid, int mode, int co
request_block_data(blkid);
}
static td::Result<tl_object_ptr<lite_api::liteServer_transactionMetadata>> get_in_msg_metadata(
const Ref<vm::Cell>& in_msg_descr_root, const Ref<vm::Cell>& trans_root) {
vm::AugmentedDictionary in_msg_descr{vm::load_cell_slice_ref(in_msg_descr_root), 256, block::tlb::aug_InMsgDescr};
block::gen::Transaction::Record transaction;
if (!block::tlb::unpack_cell(trans_root, transaction)) {
return td::Status::Error("invalid Transaction in block");
}
Ref<vm::Cell> msg = transaction.r1.in_msg->prefetch_ref();
if (msg.is_null()) {
return nullptr;
}
td::Bits256 in_msg_hash = msg->get_hash().bits();
Ref<vm::CellSlice> in_msg = in_msg_descr.lookup(in_msg_hash);
if (in_msg.is_null()) {
return td::Status::Error(PSTRING() << "no InMsg in InMsgDescr for message with hash " << in_msg_hash.to_hex());
}
int tag = block::gen::t_InMsg.get_tag(*in_msg);
if (tag != block::gen::InMsg::msg_import_imm && tag != block::gen::InMsg::msg_import_fin &&
tag != block::gen::InMsg::msg_import_deferred_fin) {
return nullptr;
}
Ref<vm::Cell> msg_env = in_msg->prefetch_ref();
if (msg_env.is_null()) {
return td::Status::Error(PSTRING() << "no MsgEnvelope in InMsg for message with hash " << in_msg_hash.to_hex());
}
block::tlb::MsgEnvelope::Record_std env;
if (!block::tlb::unpack_cell(std::move(msg_env), env)) {
return td::Status::Error(PSTRING() << "failed to unpack MsgEnvelope for message with hash " << in_msg_hash.to_hex());
}
if (!env.metadata) {
return nullptr;
}
block::MsgMetadata& metadata = env.metadata.value();
return 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);
}
void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
LOG(INFO) << "completing a listBlockTransactions(" << base_blk_id_.to_str() << ", " << mode << ", " << req_count
<< ", " << acc_addr_.to_hex() << ", " << trans_lt_ << ") liteserver query";
@ -2395,6 +2437,8 @@ void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
acc_addr_.set_ones();
trans_lt_ = ~0ULL;
}
bool with_metadata = mode & 256;
mode &= ~256;
std::vector<tl_object_ptr<lite_api::liteServer_transactionId>> result;
bool eof = false;
ton::LogicalTime reverse = (mode & 64) ? ~0ULL : 0;
@ -2448,8 +2492,18 @@ void LiteQuery::finish_listBlockTransactions(int mode, int req_count) {
trans_lt_ = reverse;
break;
}
result.push_back(create_tl_object<lite_api::liteServer_transactionId>(mode, cur_addr, cur_trans.to_long(),
tvalue->get_hash().bits()));
tl_object_ptr<lite_api::liteServer_transactionMetadata> metadata;
if (with_metadata) {
auto r_metadata = get_in_msg_metadata(extra.in_msg_descr, tvalue);
if (r_metadata.is_error()) {
fatal_error(r_metadata.move_as_error());
return;
}
metadata = r_metadata.move_as_ok();
}
result.push_back(create_tl_object<lite_api::liteServer_transactionId>(
mode | (metadata ? 256 : 0), cur_addr, cur_trans.to_long(), tvalue->get_hash().bits(),
std::move(metadata)));
++count;
}
}
@ -2484,6 +2538,36 @@ void LiteQuery::perform_listBlockTransactionsExt(BlockIdExt blkid, int mode, int
request_block_data(blkid);
}
static td::Status process_all_in_msg_metadata(const Ref<vm::Cell>& in_msg_descr_root,
const std::vector<Ref<vm::Cell>>& trans_roots) {
vm::AugmentedDictionary in_msg_descr{vm::load_cell_slice_ref(in_msg_descr_root), 256, block::tlb::aug_InMsgDescr};
for (const Ref<vm::Cell>& trans_root : trans_roots) {
block::gen::Transaction::Record transaction;
if (!block::tlb::unpack_cell(trans_root, transaction)) {
return td::Status::Error("invalid Transaction in block");
}
Ref<vm::Cell> msg = transaction.r1.in_msg->prefetch_ref();
if (msg.is_null()) {
continue;
}
td::Bits256 in_msg_hash = msg->get_hash().bits();
Ref<vm::CellSlice> in_msg = in_msg_descr.lookup(in_msg_hash);
if (in_msg.is_null()) {
return td::Status::Error(PSTRING() << "no InMsg in InMsgDescr for message with hash " << in_msg_hash.to_hex());
}
int tag = block::gen::t_InMsg.get_tag(*in_msg);
if (tag == block::gen::InMsg::msg_import_imm || tag == block::gen::InMsg::msg_import_fin ||
tag == block::gen::InMsg::msg_import_deferred_fin) {
Ref<vm::Cell> msg_env = in_msg->prefetch_ref();
if (msg_env.is_null()) {
return td::Status::Error(PSTRING() << "no MsgEnvelope in InMsg for message with hash " << in_msg_hash.to_hex());
}
vm::load_cell_slice(msg_env);
}
}
return td::Status::OK();
}
void LiteQuery::finish_listBlockTransactionsExt(int mode, int req_count) {
LOG(INFO) << "completing a listBlockTransactionsExt(" << base_blk_id_.to_str() << ", " << mode << ", " << req_count
<< ", " << acc_addr_.to_hex() << ", " << trans_lt_ << ") liteserver query";
@ -2495,6 +2579,10 @@ void LiteQuery::finish_listBlockTransactionsExt(int mode, int req_count) {
CHECK(rhash == base_blk_id_.root_hash);
vm::MerkleProofBuilder pb;
auto virt_root = block_root;
if (mode & 256) {
// with msg metadata in proof
mode |= 32;
}
if (mode & 32) {
// proof requested
virt_root = pb.init(std::move(virt_root));
@ -2560,6 +2648,13 @@ void LiteQuery::finish_listBlockTransactionsExt(int mode, int req_count) {
++count;
}
}
if (mode & 256) {
td::Status S = process_all_in_msg_metadata(extra.in_msg_descr, trans_roots);
if (S.is_error()) {
fatal_error(S.move_as_error());
return;
}
}
} catch (vm::VmError err) {
fatal_error("error while parsing AccountBlocks of block "s + base_blk_id_.to_str() + " : " + err.get_msg());
return;
@ -3252,7 +3347,7 @@ void LiteQuery::continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Re
auto ig = mp.init_guard();
for (size_t i = 0; i < blocks.size(); ++i) {
td::actor::send_closure(manager_, &ValidatorManager::get_out_msg_queue_size, blocks[i],
[promise = ig.get_promise(), res, i, id = blocks[i]](td::Result<td::uint32> R) mutable {
[promise = ig.get_promise(), res, i, id = blocks[i]](td::Result<td::uint64> R) mutable {
TRY_RESULT_PROMISE(promise, value, std::move(R));
res->at(i) = create_tl_object<lite_api::liteServer_outMsgQueueSize>(
create_tl_lite_block_id(id), value);
@ -3271,6 +3366,73 @@ void LiteQuery::continue_getOutMsgQueueSizes(td::optional<ShardIdFull> shard, Re
});
}
void LiteQuery::perform_getBlockOutMsgQueueSize(int mode, BlockIdExt blkid) {
LOG(INFO) << "started a getBlockOutMsgQueueSize(" << blkid.to_str() << ", " << mode << ") liteserver query";
mode_ = mode;
if (!blkid.is_valid_full()) {
fatal_error("invalid BlockIdExt");
return;
}
set_continuation([=]() -> void { finish_getBlockOutMsgQueueSize(); });
request_block_data_state(blkid);
}
void LiteQuery::finish_getBlockOutMsgQueueSize() {
LOG(INFO) << "completing getBlockOutNsgQueueSize() 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();
}
block::gen::ShardStateUnsplit::Record sstate;
block::gen::OutMsgQueueInfo::Record out_msg_queue_info;
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) == 0) {
fatal_error("no out_msg_queue_size in shard state");
return;
}
block::gen::OutMsgQueueExtra::Record out_msg_queue_extra;
if (!tlb::unpack(extra_slice, out_msg_queue_extra)) {
fatal_error("cannot unpack OutMsgQueueExtra");
return;
}
vm::CellSlice& size_slice = out_msg_queue_extra.out_queue_size.write();
if (size_slice.fetch_long(1) == 0) {
fatal_error("no out_msg_queue_size in shard state");
return;
}
td::uint64 size = size_slice.prefetch_ulong(48);
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) << "getBlockOutMsgQueueSize(" << blk_id_.to_str() << ", " << mode_ << ") query completed";
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_blockOutMsgQueueSize>(
mode_, ton::create_tl_lite_block_id(blk_id_), size, std::move(proof));
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";
td::actor::send_closure_later(