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:
parent
38fc1d5456
commit
0daee1d887
29 changed files with 1889 additions and 318 deletions
|
@ -813,19 +813,45 @@ int IntermediateAddress::get_size(const vm::CellSlice& cs) const {
|
|||
const IntermediateAddress t_IntermediateAddress;
|
||||
|
||||
bool MsgEnvelope::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // next_addr:IntermediateAddress
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak); // msg:^Message
|
||||
switch (get_tag(cs)) {
|
||||
case 4:
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // next_addr:IntermediateAddress
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak); // msg:^Message
|
||||
case 5:
|
||||
return cs.fetch_ulong(4) == 5 // msg_envelope_v2#5
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // next_addr:IntermediateAddress
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message
|
||||
&& Maybe<UInt>(64).validate_skip(ops, cs, weak) // emitted_lt:(Maybe uint64)
|
||||
&& Maybe<gen::MsgMetadata>().validate_skip(ops, cs, weak); // metadata:(Maybe MsgMetadata)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MsgEnvelope::skip(vm::CellSlice& cs) const {
|
||||
return cs.advance(4) // msg_envelope#4
|
||||
&& t_IntermediateAddress.skip(cs) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.skip(cs) // next_addr:IntermediateAddress
|
||||
&& t_Grams.skip(cs) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.skip(cs); // msg:^Message
|
||||
switch (get_tag(cs)) {
|
||||
case 4:
|
||||
return cs.advance(4) // msg_envelope#4
|
||||
&& t_IntermediateAddress.skip(cs) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.skip(cs) // next_addr:IntermediateAddress
|
||||
&& t_Grams.skip(cs) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.skip(cs); // msg:^Message
|
||||
case 5:
|
||||
return cs.advance(4) // msg_envelope_v2#5
|
||||
&& t_IntermediateAddress.skip(cs) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.skip(cs) // next_addr:IntermediateAddress
|
||||
&& t_Grams.skip(cs) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.skip(cs) // msg:^Message
|
||||
&& Maybe<UInt>(64).skip(cs) // emitted_lt:(Maybe uint64)
|
||||
&& Maybe<gen::MsgMetadata>().skip(cs); // metadata:(Maybe MsgMetadata)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MsgEnvelope::extract_fwd_fees_remaining(vm::CellSlice& cs) const {
|
||||
|
@ -833,34 +859,101 @@ bool MsgEnvelope::extract_fwd_fees_remaining(vm::CellSlice& cs) const {
|
|||
}
|
||||
|
||||
bool MsgEnvelope::unpack(vm::CellSlice& cs, MsgEnvelope::Record& data) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.fetch_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg); // msg:^Message
|
||||
switch (get_tag(cs)) {
|
||||
case 4:
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.fetch_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg); // msg:^Message
|
||||
case 5:
|
||||
return cs.fetch_ulong(4) == 5 // msg_envelope_v2#5
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_to(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.fetch_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg) // msg:^Message
|
||||
&& Maybe<UInt>(64).skip(cs) // emitted_lt:(Maybe uint64)
|
||||
&& Maybe<gen::MsgMetadata>().skip(cs); // metadata:(Maybe MsgMetadata)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MsgEnvelope::unpack(vm::CellSlice& cs, MsgEnvelope::Record_std& data) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.as_integer_skip_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg); // msg:^Message
|
||||
data.emitted_lt = {};
|
||||
data.metadata = {};
|
||||
switch (get_tag(cs)) {
|
||||
case 4:
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.as_integer_skip_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg); // msg:^Message
|
||||
case 5: {
|
||||
bool with_metadata, with_emitted_lt;
|
||||
return cs.fetch_ulong(4) == 5 // msg_envelope_v2#5
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.cur_addr) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_regular(cs, data.next_addr) // next_addr:IntermediateAddress
|
||||
&& t_Grams.as_integer_skip_to(cs, data.fwd_fee_remaining) // fwd_fee_remaining:Grams
|
||||
&& cs.fetch_ref_to(data.msg) // msg:^Message
|
||||
&& cs.fetch_bool_to(with_emitted_lt) &&
|
||||
(!with_emitted_lt || cs.fetch_uint_to(64, data.emitted_lt.value_force())) // emitted_lt:(Maybe uint64)
|
||||
&& cs.fetch_bool_to(with_metadata) &&
|
||||
(!with_metadata || data.metadata.value_force().unpack(cs)); // metadata:(Maybe MsgMetadata)
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MsgEnvelope::unpack_std(vm::CellSlice& cs, int& cur_a, int& nhop_a, Ref<vm::Cell>& msg) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.fetch_regular(cs, cur_a) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.fetch_regular(cs, nhop_a) // next_addr:IntermediateAddress
|
||||
&& cs.fetch_ref_to(msg);
|
||||
bool MsgEnvelope::pack(vm::CellBuilder& cb, const Record_std& data) const {
|
||||
bool v2 = (bool)data.metadata || (bool)data.emitted_lt;
|
||||
if (!(cb.store_long_bool(v2 ? 5 : 4, 4) && // msg_envelope#4 / msg_envelope_v2#5
|
||||
cb.store_long_bool(data.cur_addr, 8) && // cur_addr:IntermediateAddress
|
||||
cb.store_long_bool(data.next_addr, 8) && // next_addr:IntermediateAddress
|
||||
t_Grams.store_integer_ref(cb, data.fwd_fee_remaining) && // fwd_fee_remaining:Grams
|
||||
cb.store_ref_bool(data.msg))) { // msg:^Message
|
||||
return false;
|
||||
}
|
||||
if (v2) {
|
||||
if (!(cb.store_bool_bool((bool)data.emitted_lt) &&
|
||||
(!data.emitted_lt || cb.store_long_bool(data.emitted_lt.value(), 64)))) { // emitted_lt:(Maybe uint64)
|
||||
return false;
|
||||
}
|
||||
if (!(cb.store_bool_bool((bool)data.metadata) &&
|
||||
(!data.metadata || data.metadata.value().pack(cb)))) { // metadata:(Maybe MsgMetadata)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MsgEnvelope::get_created_lt(const vm::CellSlice& cs, unsigned long long& created_lt) const {
|
||||
bool MsgEnvelope::pack_cell(td::Ref<vm::Cell>& cell, const Record_std& data) const {
|
||||
vm::CellBuilder cb;
|
||||
return pack(cb, data) && cb.finalize_to(cell);
|
||||
}
|
||||
|
||||
bool MsgEnvelope::get_emitted_lt(const vm::CellSlice& cs, unsigned long long& emitted_lt) const {
|
||||
// Emitted lt is emitted_lt from MsgEnvelope (if present), otherwise created_lt
|
||||
if (!cs.size_refs()) {
|
||||
return false;
|
||||
}
|
||||
if (get_tag(cs) == 5) {
|
||||
vm::CellSlice cs2 = cs;
|
||||
// msg_envelope_v2#5 cur_addr:IntermediateAddress
|
||||
// next_addr:IntermediateAddress fwd_fee_remaining:Grams
|
||||
// msg:^(Message Any) emitted_lt:(Maybe uint64) ...
|
||||
bool have_emitted_lt;
|
||||
if (!(cs2.skip_first(4) && t_IntermediateAddress.skip(cs2) && t_IntermediateAddress.skip(cs2) &&
|
||||
t_Grams.skip(cs2) && t_Ref_Message.skip(cs2) && cs2.fetch_bool_to(have_emitted_lt))) {
|
||||
return false;
|
||||
}
|
||||
if (have_emitted_lt) {
|
||||
return cs2.fetch_ulong_bool(64, emitted_lt);
|
||||
}
|
||||
}
|
||||
auto msg_cs = load_cell_slice(cs.prefetch_ref());
|
||||
return t_Message.get_created_lt(msg_cs, created_lt);
|
||||
return t_Message.get_created_lt(msg_cs, emitted_lt);
|
||||
}
|
||||
|
||||
const MsgEnvelope t_MsgEnvelope;
|
||||
|
@ -1692,6 +1785,15 @@ bool InMsg::skip(vm::CellSlice& cs) const {
|
|||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.skip(cs) // fwd_fee:Grams
|
||||
&& t_RefCell.skip(cs); // proof_delivered:^Cell
|
||||
case msg_import_deferred_fin:
|
||||
return cs.advance(5) // msg_import_deferred_fin$00100
|
||||
&& t_Ref_MsgEnvelope.skip(cs) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.skip(cs) // transaction:^Transaction
|
||||
&& t_Grams.skip(cs); // fwd_fee:Grams
|
||||
case msg_import_deferred_tr:
|
||||
return cs.advance(5) // msg_import_deferred_tr$00101
|
||||
&& t_Ref_MsgEnvelope.skip(cs) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_MsgEnvelope.skip(cs); // out_msg:^MsgEnvelope
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1734,12 +1836,22 @@ bool InMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
|||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee:Grams
|
||||
&& t_RefCell.validate_skip(ops, cs, weak); // proof_delivered:^Cell
|
||||
case msg_import_deferred_fin:
|
||||
return cs.advance(5) // msg_import_deferred_fin$00100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams
|
||||
case msg_import_deferred_tr:
|
||||
return cs.advance(5) // msg_import_deferred_tr$00101
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak); // out_msg:^MsgEnvelope
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InMsg::get_import_fees(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
||||
switch (get_tag(cs)) {
|
||||
int tag = get_tag(cs);
|
||||
switch (tag) {
|
||||
case msg_import_ext: // inbound external message
|
||||
return t_ImportFees.null_value(cb); // external messages have no value and no import fees
|
||||
case msg_import_ihr: // IHR-forwarded internal message to its final destination
|
||||
|
@ -1765,8 +1877,9 @@ bool InMsg::get_import_fees(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
|||
&& t_CurrencyCollection.null_value(cb); // value_imported := 0
|
||||
}
|
||||
return false;
|
||||
case msg_import_fin: // internal message delivered to its final destination in this block
|
||||
if (cs.advance(3) && cs.size_refs() >= 2) {
|
||||
case msg_import_fin: // internal message delivered to its final destination in this block
|
||||
case msg_import_deferred_fin: // internal message from DispatchQueue to its final destination in this block
|
||||
if (cs.advance(tag == msg_import_fin ? 3 : 5) && cs.size_refs() >= 2) {
|
||||
auto msg_env_cs = load_cell_slice(cs.fetch_ref());
|
||||
MsgEnvelope::Record in_msg;
|
||||
td::RefInt256 fwd_fee, fwd_fee_remaining, value_grams, ihr_fee;
|
||||
|
@ -1787,13 +1900,14 @@ bool InMsg::get_import_fees(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
|||
msg_info.value.write()); // value_imported = msg.value + msg.ihr_fee + fwd_fee_remaining
|
||||
}
|
||||
return false;
|
||||
case msg_import_tr: // transit internal message
|
||||
if (cs.advance(3) && cs.size_refs() >= 2) {
|
||||
case msg_import_tr: // transit internal message
|
||||
case msg_import_deferred_tr: // internal message from DispatchQueue to OutMsgQueue
|
||||
if (cs.advance(tag == msg_import_tr ? 3 : 5) && cs.size_refs() >= 2) {
|
||||
auto msg_env_cs = load_cell_slice(cs.fetch_ref());
|
||||
MsgEnvelope::Record in_msg;
|
||||
td::RefInt256 transit_fee, fwd_fee_remaining, value_grams, ihr_fee;
|
||||
td::RefInt256 transit_fee = td::zero_refint(), fwd_fee_remaining, value_grams, ihr_fee;
|
||||
if (!(t_MsgEnvelope.unpack(msg_env_cs, in_msg) && cs.fetch_ref().not_null() &&
|
||||
t_Grams.as_integer_skip_to(cs, transit_fee) &&
|
||||
(tag == msg_import_deferred_tr || t_Grams.as_integer_skip_to(cs, transit_fee)) &&
|
||||
(fwd_fee_remaining = t_Grams.as_integer(in_msg.fwd_fee_remaining)).not_null() &&
|
||||
cmp(transit_fee, fwd_fee_remaining) <= 0)) {
|
||||
return false;
|
||||
|
@ -1871,6 +1985,14 @@ bool OutMsg::skip(vm::CellSlice& cs) const {
|
|||
return cs.advance(3) // msg_export_tr_req$111
|
||||
&& t_Ref_MsgEnvelope.skip(cs) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.skip(cs); // imported:^InMsg
|
||||
case msg_export_new_defer:
|
||||
return cs.advance(5) // msg_export_new_defer$10100
|
||||
&& t_Ref_MsgEnvelope.skip(cs) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.skip(cs); // transaction:^Transaction
|
||||
case msg_export_deferred_tr:
|
||||
return cs.advance(5) // msg_export_deferred_tr$10101
|
||||
&& t_Ref_MsgEnvelope.skip(cs) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.skip(cs); // imported:^InMsg
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1910,12 +2032,21 @@ bool OutMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
|||
return cs.advance(3) // msg_export_tr_req$111
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // imported:^InMsg
|
||||
case msg_export_new_defer:
|
||||
return cs.advance(5) // msg_export_new_defer$10100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction
|
||||
case msg_export_deferred_tr:
|
||||
return cs.advance(5) // msg_export_deferred_tr$10101
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // imported:^InMsg
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OutMsg::get_export_value(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
||||
switch (get_tag(cs)) {
|
||||
auto tag = get_tag(cs);
|
||||
switch (tag) {
|
||||
case msg_export_ext: // external outbound message carries no value
|
||||
if (cs.have(3, 2)) {
|
||||
return t_CurrencyCollection.null_value(cb);
|
||||
|
@ -1929,10 +2060,13 @@ bool OutMsg::get_export_value(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
|||
return cs.have(4 + 63, 1) && t_CurrencyCollection.null_value(cb);
|
||||
case msg_export_deq_short: // dequeueing record for outbound message, no exported value
|
||||
return cs.have(4 + 256 + 32 + 64 + 64) && t_CurrencyCollection.null_value(cb);
|
||||
case msg_export_new: // newly-generated outbound internal message, queued
|
||||
case msg_export_tr: // transit internal message, queued
|
||||
case msg_export_tr_req: // transit internal message, re-queued from this shardchain
|
||||
if (cs.advance(3) && cs.size_refs() >= 2) {
|
||||
case msg_export_new: // newly-generated outbound internal message, queued
|
||||
case msg_export_tr: // transit internal message, queued
|
||||
case msg_export_tr_req: // transit internal message, re-queued from this shardchain
|
||||
case msg_export_new_defer: // newly-generated outbound internal message, deferred
|
||||
case msg_export_deferred_tr: // internal message from DispatchQueue, queued
|
||||
int tag_len = (tag == msg_export_new_defer || tag == msg_export_deferred_tr) ? 5 : 3;
|
||||
if (cs.advance(tag_len) && cs.size_refs() >= 2) {
|
||||
auto msg_env_cs = load_cell_slice(cs.fetch_ref());
|
||||
MsgEnvelope::Record out_msg;
|
||||
if (!(cs.fetch_ref().not_null() && t_MsgEnvelope.unpack(msg_env_cs, out_msg))) {
|
||||
|
@ -1954,12 +2088,12 @@ bool OutMsg::get_export_value(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool OutMsg::get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const {
|
||||
bool OutMsg::get_emitted_lt(vm::CellSlice& cs, unsigned long long& emitted_lt) const {
|
||||
switch (get_tag(cs)) {
|
||||
case msg_export_ext:
|
||||
if (cs.have(3, 1)) {
|
||||
auto msg_cs = load_cell_slice(cs.prefetch_ref());
|
||||
return t_Message.get_created_lt(msg_cs, created_lt);
|
||||
return t_Message.get_created_lt(msg_cs, emitted_lt);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1970,9 +2104,11 @@ bool OutMsg::get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) c
|
|||
case msg_export_deq_short:
|
||||
case msg_export_deq_imm:
|
||||
case msg_export_tr_req:
|
||||
case msg_export_new_defer:
|
||||
case msg_export_deferred_tr:
|
||||
if (cs.have(3, 1)) {
|
||||
auto out_msg_cs = load_cell_slice(cs.prefetch_ref());
|
||||
return t_MsgEnvelope.get_created_lt(out_msg_cs, created_lt);
|
||||
return t_MsgEnvelope.get_emitted_lt(out_msg_cs, emitted_lt);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -2003,26 +2139,53 @@ bool Aug_OutMsgQueue::eval_empty(vm::CellBuilder& cb) const {
|
|||
|
||||
bool Aug_OutMsgQueue::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
||||
Ref<vm::Cell> msg_env;
|
||||
unsigned long long created_lt;
|
||||
return cs.fetch_ref_to(msg_env) && t_MsgEnvelope.get_created_lt(load_cell_slice(std::move(msg_env)), created_lt) &&
|
||||
cb.store_ulong_rchk_bool(created_lt, 64);
|
||||
unsigned long long emitted_lt;
|
||||
return cs.fetch_ref_to(msg_env) && t_MsgEnvelope.get_emitted_lt(load_cell_slice(std::move(msg_env)), emitted_lt) &&
|
||||
cb.store_ulong_rchk_bool(emitted_lt, 64);
|
||||
}
|
||||
|
||||
bool Aug_DispatchQueue::eval_fork(vm::CellBuilder& cb, vm::CellSlice& left_cs, vm::CellSlice& right_cs) const {
|
||||
unsigned long long x, y;
|
||||
return left_cs.fetch_ulong_bool(64, x) && right_cs.fetch_ulong_bool(64, y) &&
|
||||
cb.store_ulong_rchk_bool(std::min(x, y), 64);
|
||||
}
|
||||
|
||||
bool Aug_DispatchQueue::eval_empty(vm::CellBuilder& cb) const {
|
||||
return cb.store_long_bool(0, 64);
|
||||
}
|
||||
|
||||
bool Aug_DispatchQueue::eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
||||
Ref<vm::Cell> messages_root;
|
||||
if (!cs.fetch_maybe_ref(messages_root)) {
|
||||
return false;
|
||||
}
|
||||
vm::Dictionary messages{std::move(messages_root), 64};
|
||||
td::BitArray<64> key_buffer;
|
||||
td::uint64 key;
|
||||
if (messages.get_minmax_key(key_buffer.bits(), 64).is_null()) {
|
||||
key = (td::uint64)-1;
|
||||
} else {
|
||||
key = key_buffer.to_ulong();
|
||||
}
|
||||
return cb.store_long_bool(key, 64);
|
||||
}
|
||||
|
||||
const Aug_OutMsgQueue aug_OutMsgQueue;
|
||||
const Aug_DispatchQueue aug_DispatchQueue;
|
||||
const OutMsgQueue t_OutMsgQueue;
|
||||
|
||||
const ProcessedUpto t_ProcessedUpto;
|
||||
const HashmapE t_ProcessedInfo{96, t_ProcessedUpto};
|
||||
const HashmapE t_IhrPendingInfo{256, t_uint128};
|
||||
|
||||
// _ out_queue:OutMsgQueue proc_info:ProcessedInfo = OutMsgQueueInfo;
|
||||
// _ out_queue:OutMsgQueue proc_info:ProcessedInfo extra:(Maybe OutMsgQueueExtra) = OutMsgQueueInfo;
|
||||
bool OutMsgQueueInfo::skip(vm::CellSlice& cs) const {
|
||||
return t_OutMsgQueue.skip(cs) && t_ProcessedInfo.skip(cs) && t_IhrPendingInfo.skip(cs);
|
||||
return t_OutMsgQueue.skip(cs) && t_ProcessedInfo.skip(cs) && Maybe<gen::OutMsgQueueExtra>().skip(cs);
|
||||
}
|
||||
|
||||
bool OutMsgQueueInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_OutMsgQueue.validate_skip(ops, cs, weak) && t_ProcessedInfo.validate_skip(ops, cs, weak) &&
|
||||
t_IhrPendingInfo.validate_skip(ops, cs, weak);
|
||||
Maybe<gen::OutMsgQueueExtra>().validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
const OutMsgQueueInfo t_OutMsgQueueInfo;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "td/utils/bits.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "block-auto.h"
|
||||
|
||||
namespace block {
|
||||
|
||||
|
@ -469,11 +470,17 @@ struct MsgEnvelope final : TLB_Complex {
|
|||
int cur_addr, next_addr;
|
||||
td::RefInt256 fwd_fee_remaining;
|
||||
Ref<vm::Cell> msg;
|
||||
td::optional<ton::LogicalTime> emitted_lt;
|
||||
td::optional<MsgMetadata> metadata;
|
||||
};
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_std& data) const;
|
||||
bool unpack_std(vm::CellSlice& cs, int& cur_a, int& nhop_a, Ref<vm::Cell>& msg) const;
|
||||
bool get_created_lt(const vm::CellSlice& cs, unsigned long long& created_lt) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_std& data) const;
|
||||
bool pack_cell(td::Ref<vm::Cell>& cell, const Record_std& data) const;
|
||||
bool get_emitted_lt(const vm::CellSlice& cs, unsigned long long& emitted_lt) const;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(4);
|
||||
}
|
||||
};
|
||||
|
||||
extern const MsgEnvelope t_MsgEnvelope;
|
||||
|
@ -801,12 +808,18 @@ struct InMsg final : TLB_Complex {
|
|||
msg_import_fin = 4,
|
||||
msg_import_tr = 5,
|
||||
msg_discard_fin = 6,
|
||||
msg_discard_tr = 7
|
||||
msg_discard_tr = 7,
|
||||
msg_import_deferred_fin = 8,
|
||||
msg_import_deferred_tr = 9
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(3);
|
||||
int tag = (int)cs.prefetch_ulong(3);
|
||||
if (tag != 1) {
|
||||
return tag;
|
||||
}
|
||||
return (int)cs.prefetch_ulong(5) - 0b00100 + 8;
|
||||
}
|
||||
bool get_import_fees(vm::CellBuilder& cb, vm::CellSlice& cs) const;
|
||||
};
|
||||
|
@ -822,16 +835,24 @@ struct OutMsg final : TLB_Complex {
|
|||
msg_export_deq_imm = 4,
|
||||
msg_export_deq = 12,
|
||||
msg_export_deq_short = 13,
|
||||
msg_export_tr_req = 7
|
||||
msg_export_tr_req = 7,
|
||||
msg_export_new_defer = 20, // 0b10100
|
||||
msg_export_deferred_tr = 21 // 0b10101
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
int t = (int)cs.prefetch_ulong(3);
|
||||
return t != 6 ? t : (int)cs.prefetch_ulong(4);
|
||||
if (t == 6) {
|
||||
return (int)cs.prefetch_ulong(4);
|
||||
}
|
||||
if (t == 5) {
|
||||
return (int)cs.prefetch_ulong(5);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
bool get_export_value(vm::CellBuilder& cb, vm::CellSlice& cs) const;
|
||||
bool get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const;
|
||||
bool get_emitted_lt(vm::CellSlice& cs, unsigned long long& emitted_lt) const;
|
||||
};
|
||||
|
||||
extern const OutMsg t_OutMsg;
|
||||
|
@ -909,6 +930,16 @@ struct Aug_OutMsgQueue final : AugmentationCheckData {
|
|||
|
||||
extern const Aug_OutMsgQueue aug_OutMsgQueue;
|
||||
|
||||
struct Aug_DispatchQueue final : AugmentationCheckData {
|
||||
Aug_DispatchQueue() : AugmentationCheckData(gen::t_AccountDispatchQueue, t_uint64) {
|
||||
}
|
||||
bool eval_fork(vm::CellBuilder& cb, vm::CellSlice& left_cs, vm::CellSlice& right_cs) const override;
|
||||
bool eval_empty(vm::CellBuilder& cb) const override;
|
||||
bool eval_leaf(vm::CellBuilder& cb, vm::CellSlice& cs) const override;
|
||||
};
|
||||
|
||||
extern const Aug_DispatchQueue aug_DispatchQueue;
|
||||
|
||||
struct OutMsgQueue final : TLB_Complex {
|
||||
HashmapAugE dict_type;
|
||||
OutMsgQueue() : dict_type(32 + 64 + 256, aug_OutMsgQueue){};
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "td/utils/tl_storers.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "vm/fmt.hpp"
|
||||
|
||||
namespace block {
|
||||
using namespace std::literals::string_literals;
|
||||
|
@ -642,7 +643,11 @@ bool EnqueuedMsgDescr::unpack(vm::CellSlice& cs) {
|
|||
}
|
||||
cur_prefix_ = interpolate_addr(src_prefix_, dest_prefix_, env.cur_addr);
|
||||
next_prefix_ = interpolate_addr(src_prefix_, dest_prefix_, env.next_addr);
|
||||
lt_ = info.created_lt;
|
||||
unsigned long long lt;
|
||||
if (!tlb::t_MsgEnvelope.get_emitted_lt(vm::load_cell_slice(enq.out_msg), lt)) {
|
||||
return invalidate();
|
||||
}
|
||||
lt_ = lt;
|
||||
enqueued_lt_ = enq.enqueued_lt;
|
||||
hash_ = env.msg->get_hash().bits();
|
||||
msg_ = std::move(env.msg);
|
||||
|
@ -858,12 +863,20 @@ td::Status ShardState::unpack_out_msg_queue_info(Ref<vm::Cell> out_msg_queue_inf
|
|||
return td::Status::Error(
|
||||
-666, "ProcessedInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks");
|
||||
}
|
||||
if (!block::gen::t_IhrPendingInfo.validate_csr(1024, qinfo.ihr_pending)) {
|
||||
return td::Status::Error(
|
||||
-666, "IhrPendingInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks");
|
||||
}
|
||||
processed_upto_ = block::MsgProcessedUptoCollection::unpack(ton::ShardIdFull(id_), std::move(qinfo.proc_info));
|
||||
ihr_pending_ = std::make_unique<vm::Dictionary>(std::move(qinfo.ihr_pending), 320);
|
||||
ihr_pending_ = std::make_unique<vm::Dictionary>(320);
|
||||
if (qinfo.extra.write().fetch_long(1)) {
|
||||
block::gen::OutMsgQueueExtra::Record extra;
|
||||
if (!block::tlb::csr_unpack(qinfo.extra, extra)) {
|
||||
return td::Status::Error(-666, "cannot unpack OutMsgQueueExtre in the state of "s + id_.to_str());
|
||||
}
|
||||
dispatch_queue_ = std::make_unique<vm::AugmentedDictionary>(extra.dispatch_queue, 256, tlb::aug_DispatchQueue);
|
||||
if (extra.out_queue_size.write().fetch_long(1)) {
|
||||
out_msg_queue_size_ = extra.out_queue_size->prefetch_ulong(48);
|
||||
}
|
||||
} else {
|
||||
dispatch_queue_ = std::make_unique<vm::AugmentedDictionary>(256, tlb::aug_DispatchQueue);
|
||||
}
|
||||
auto shard1 = id_.shard_full();
|
||||
td::BitArray<64> pfx{(long long)shard1.shard};
|
||||
int pfx_len = shard_prefix_length(shard1);
|
||||
|
@ -994,6 +1007,17 @@ td::Status ShardState::merge_with(ShardState& sib) {
|
|||
underload_history_ = overload_history_ = 0;
|
||||
// 10. compute vert_seqno
|
||||
vert_seqno_ = std::max(vert_seqno_, sib.vert_seqno_);
|
||||
// 11. merge dispatch_queue (same as account dict)
|
||||
if (!dispatch_queue_->combine_with(*sib.dispatch_queue_)) {
|
||||
return td::Status::Error(-666, "cannot merge dispatch queues of the two ancestors");
|
||||
}
|
||||
sib.dispatch_queue_.reset();
|
||||
// 11. merge out_msg_queue_size
|
||||
if (out_msg_queue_size_ && sib.out_msg_queue_size_) {
|
||||
out_msg_queue_size_.value() += sib.out_msg_queue_size_.value();
|
||||
} else {
|
||||
out_msg_queue_size_ = {};
|
||||
}
|
||||
// Anything else? add here
|
||||
// ...
|
||||
|
||||
|
@ -1009,8 +1033,8 @@ td::Status ShardState::merge_with(ShardState& sib) {
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<std::unique_ptr<vm::AugmentedDictionary>> ShardState::compute_split_out_msg_queue(ton::ShardIdFull subshard,
|
||||
td::uint32* queue_size) {
|
||||
td::Result<std::unique_ptr<vm::AugmentedDictionary>> ShardState::compute_split_out_msg_queue(
|
||||
ton::ShardIdFull subshard) {
|
||||
auto shard = id_.shard_full();
|
||||
if (!ton::shard_is_parent(shard, subshard)) {
|
||||
return td::Status::Error(-666, "cannot split subshard "s + subshard.to_str() + " from state of " + id_.to_str() +
|
||||
|
@ -1018,7 +1042,7 @@ td::Result<std::unique_ptr<vm::AugmentedDictionary>> ShardState::compute_split_o
|
|||
}
|
||||
CHECK(out_msg_queue_);
|
||||
auto subqueue = std::make_unique<vm::AugmentedDictionary>(*out_msg_queue_);
|
||||
int res = block::filter_out_msg_queue(*subqueue, shard, subshard, queue_size);
|
||||
int res = block::filter_out_msg_queue(*subqueue, shard, subshard);
|
||||
if (res < 0) {
|
||||
return td::Status::Error(-666, "error splitting OutMsgQueue of "s + id_.to_str());
|
||||
}
|
||||
|
@ -1040,7 +1064,7 @@ td::Result<std::shared_ptr<block::MsgProcessedUptoCollection>> ShardState::compu
|
|||
return std::move(sub_processed_upto);
|
||||
}
|
||||
|
||||
td::Status ShardState::split(ton::ShardIdFull subshard, td::uint32* queue_size) {
|
||||
td::Status ShardState::split(ton::ShardIdFull subshard) {
|
||||
if (!ton::shard_is_parent(id_.shard_full(), subshard)) {
|
||||
return td::Status::Error(-666, "cannot split subshard "s + subshard.to_str() + " from state of " + id_.to_str() +
|
||||
" because it is not a parent");
|
||||
|
@ -1058,10 +1082,12 @@ td::Status ShardState::split(ton::ShardIdFull subshard, td::uint32* queue_size)
|
|||
auto shard1 = id_.shard_full();
|
||||
CHECK(ton::shard_is_parent(shard1, subshard));
|
||||
CHECK(out_msg_queue_);
|
||||
int res1 = block::filter_out_msg_queue(*out_msg_queue_, shard1, subshard, queue_size);
|
||||
td::uint64 queue_size;
|
||||
int res1 = block::filter_out_msg_queue(*out_msg_queue_, shard1, subshard, &queue_size);
|
||||
if (res1 < 0) {
|
||||
return td::Status::Error(-666, "error splitting OutMsgQueue of "s + id_.to_str());
|
||||
}
|
||||
out_msg_queue_size_ = queue_size;
|
||||
LOG(DEBUG) << "split counters: " << res1;
|
||||
// 3. processed_upto
|
||||
LOG(DEBUG) << "splitting ProcessedUpto";
|
||||
|
@ -1091,6 +1117,11 @@ td::Status ShardState::split(ton::ShardIdFull subshard, td::uint32* queue_size)
|
|||
// NB: if total_fees_extra will be allowed to be non-empty, split it here too
|
||||
// 7. reset overload/underload history
|
||||
overload_history_ = underload_history_ = 0;
|
||||
// 8. split dispatch_queue (same as account dict)
|
||||
LOG(DEBUG) << "splitting dispatch_queue";
|
||||
CHECK(dispatch_queue_);
|
||||
CHECK(dispatch_queue_->cut_prefix_subdict(pfx.bits(), pfx_len));
|
||||
CHECK(dispatch_queue_->has_common_prefix(pfx.bits(), pfx_len));
|
||||
// 999. anything else?
|
||||
id_.id.shard = subshard.shard;
|
||||
id_.file_hash.set_zero();
|
||||
|
@ -1099,7 +1130,7 @@ td::Status ShardState::split(ton::ShardIdFull subshard, td::uint32* queue_size)
|
|||
}
|
||||
|
||||
int filter_out_msg_queue(vm::AugmentedDictionary& out_queue, ton::ShardIdFull old_shard, ton::ShardIdFull subshard,
|
||||
td::uint32* queue_size) {
|
||||
td::uint64* queue_size) {
|
||||
if (queue_size) {
|
||||
*queue_size = 0;
|
||||
}
|
||||
|
@ -1390,7 +1421,7 @@ bool ValueFlow::store(vm::CellBuilder& cb) const {
|
|||
&& exported.store(cb2) // exported:CurrencyCollection
|
||||
&& cb.store_ref_bool(cb2.finalize()) // ]
|
||||
&& fees_collected.store(cb) // fees_collected:CurrencyCollection
|
||||
&& (burned.is_zero() || burned.store(cb)) // fees_burned:CurrencyCollection
|
||||
&& (burned.is_zero() || burned.store(cb)) // fees_burned:CurrencyCollection
|
||||
&& fees_imported.store(cb2) // ^[ fees_imported:CurrencyCollection
|
||||
&& recovered.store(cb2) // recovered:CurrencyCollection
|
||||
&& created.store(cb2) // created:CurrencyCollection
|
||||
|
@ -1419,8 +1450,7 @@ bool ValueFlow::fetch(vm::CellSlice& cs) {
|
|||
from_prev_blk.validate_unpack(std::move(f2.r1.from_prev_blk)) &&
|
||||
to_next_blk.validate_unpack(std::move(f2.r1.to_next_blk)) &&
|
||||
imported.validate_unpack(std::move(f2.r1.imported)) && exported.validate_unpack(std::move(f2.r1.exported)) &&
|
||||
fees_collected.validate_unpack(std::move(f2.fees_collected)) &&
|
||||
burned.validate_unpack(std::move(f2.burned)) &&
|
||||
fees_collected.validate_unpack(std::move(f2.fees_collected)) && burned.validate_unpack(std::move(f2.burned)) &&
|
||||
fees_imported.validate_unpack(std::move(f2.r2.fees_imported)) &&
|
||||
recovered.validate_unpack(std::move(f2.r2.recovered)) && created.validate_unpack(std::move(f2.r2.created)) &&
|
||||
minted.validate_unpack(std::move(f2.r2.minted))) {
|
||||
|
@ -2305,4 +2335,132 @@ bool parse_block_id_ext(td::Slice str, ton::BlockIdExt& blkid) {
|
|||
return parse_block_id_ext(str.begin(), str.end(), blkid);
|
||||
}
|
||||
|
||||
bool unpack_account_dispatch_queue(Ref<vm::CellSlice> csr, vm::Dictionary& dict, td::uint64& dict_size) {
|
||||
if (csr.not_null()) {
|
||||
block::gen::AccountDispatchQueue::Record rec;
|
||||
if (!block::tlb::csr_unpack(std::move(csr), rec)) {
|
||||
return false;
|
||||
}
|
||||
dict = vm::Dictionary{rec.messages, 64};
|
||||
dict_size = rec.count;
|
||||
if (dict_size == 0 || dict.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
dict = vm::Dictionary{64};
|
||||
dict_size = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<vm::CellSlice> pack_account_dispatch_queue(const vm::Dictionary& dict, td::uint64 dict_size) {
|
||||
if (dict_size == 0) {
|
||||
return {};
|
||||
}
|
||||
// _ messages:(HashmapE 64 EnqueuedMsg) count:uint48 = AccountDispatchQueue;
|
||||
vm::CellBuilder cb;
|
||||
CHECK(dict.append_dict_to_bool(cb));
|
||||
cb.store_long(dict_size, 48);
|
||||
return cb.as_cellslice_ref();
|
||||
}
|
||||
|
||||
Ref<vm::CellSlice> get_dispatch_queue_min_lt_account(const vm::AugmentedDictionary& dispatch_queue,
|
||||
ton::StdSmcAddress& addr) {
|
||||
// TODO: This can be done more effectively
|
||||
vm::AugmentedDictionary queue{dispatch_queue.get_root(), 256, tlb::aug_DispatchQueue};
|
||||
if (queue.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
auto root_extra = queue.get_root_extra();
|
||||
if (root_extra.is_null()) {
|
||||
return {};
|
||||
}
|
||||
ton::LogicalTime min_lt = root_extra->prefetch_long(64);
|
||||
while (true) {
|
||||
td::Bits256 key;
|
||||
int pfx_len = queue.get_common_prefix(key.bits(), 256);
|
||||
if (pfx_len < 0) {
|
||||
return {};
|
||||
}
|
||||
if (pfx_len == 256) {
|
||||
addr = key;
|
||||
return queue.lookup(key);
|
||||
}
|
||||
key[pfx_len] = false;
|
||||
vm::AugmentedDictionary queue_cut{queue.get_root(), 256, tlb::aug_DispatchQueue};
|
||||
if (!queue_cut.cut_prefix_subdict(key.bits(), pfx_len + 1)) {
|
||||
return {};
|
||||
}
|
||||
root_extra = queue_cut.get_root_extra();
|
||||
if (root_extra.is_null()) {
|
||||
return {};
|
||||
}
|
||||
ton::LogicalTime cut_min_lt = root_extra->prefetch_long(64);
|
||||
if (cut_min_lt != min_lt) {
|
||||
key[pfx_len] = true;
|
||||
}
|
||||
if (!queue.cut_prefix_subdict(key.bits(), pfx_len + 1)) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool remove_dispatch_queue_entry(vm::AugmentedDictionary& dispatch_queue, const ton::StdSmcAddress& addr,
|
||||
ton::LogicalTime lt) {
|
||||
auto account_dispatch_queue = dispatch_queue.lookup(addr);
|
||||
if (account_dispatch_queue.is_null()) {
|
||||
return false;
|
||||
}
|
||||
vm::Dictionary dict{64};
|
||||
td::uint64 dict_size;
|
||||
if (!unpack_account_dispatch_queue(std::move(account_dispatch_queue), dict, dict_size)) {
|
||||
return false;
|
||||
}
|
||||
td::BitArray<64> key;
|
||||
key.store_ulong(lt);
|
||||
auto entry = dict.lookup_delete(key);
|
||||
if (entry.is_null()) {
|
||||
return false;
|
||||
}
|
||||
--dict_size;
|
||||
account_dispatch_queue = pack_account_dispatch_queue(dict, dict_size);
|
||||
if (account_dispatch_queue.not_null()) {
|
||||
dispatch_queue.set(addr, account_dispatch_queue);
|
||||
} else {
|
||||
dispatch_queue.lookup_delete(addr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MsgMetadata::unpack(vm::CellSlice& cs) {
|
||||
// msg_metadata#0 depth:uint32 initiator_addr:MsgAddressInt initiator_lt:uint64 = MsgMetadata;
|
||||
int tag;
|
||||
return cs.fetch_int_to(4, tag) && tag == 0 && cs.fetch_uint_to(32, depth) &&
|
||||
cs.prefetch_ulong(3) == 0b100 && // std address, no anycast
|
||||
tlb::t_MsgAddressInt.extract_std_address(cs, initiator_wc, initiator_addr) &&
|
||||
cs.fetch_uint_to(64, initiator_lt);
|
||||
}
|
||||
|
||||
bool MsgMetadata::pack(vm::CellBuilder& cb) const {
|
||||
// msg_metadata#0 depth:uint32 initiator_addr:MsgAddressInt initiator_lt:uint64 = MsgMetadata;
|
||||
return cb.store_long_bool(0, 4) && cb.store_long_bool(depth, 32) &&
|
||||
tlb::t_MsgAddressInt.store_std_address(cb, initiator_wc, initiator_addr) &&
|
||||
cb.store_long_bool(initiator_lt, 64);
|
||||
}
|
||||
|
||||
std::string MsgMetadata::to_str() const {
|
||||
return PSTRING() << "[ depth=" << depth << " init=" << initiator_wc << ":" << initiator_addr.to_hex() << ":"
|
||||
<< initiator_lt << " ]";
|
||||
}
|
||||
|
||||
bool MsgMetadata::operator==(const MsgMetadata& other) const {
|
||||
return depth == other.depth && initiator_wc == other.initiator_wc && initiator_addr == other.initiator_addr &&
|
||||
initiator_lt == other.initiator_lt;
|
||||
}
|
||||
|
||||
bool MsgMetadata::operator!=(const MsgMetadata& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
} // namespace block
|
||||
|
|
|
@ -417,6 +417,8 @@ struct ShardState {
|
|||
std::unique_ptr<vm::Dictionary> ihr_pending_;
|
||||
std::unique_ptr<vm::Dictionary> block_create_stats_;
|
||||
std::shared_ptr<block::MsgProcessedUptoCollection> processed_upto_;
|
||||
std::unique_ptr<vm::AugmentedDictionary> dispatch_queue_;
|
||||
td::optional<td::uint64> out_msg_queue_size_;
|
||||
|
||||
bool is_valid() const {
|
||||
return id_.is_valid();
|
||||
|
@ -433,11 +435,10 @@ struct ShardState {
|
|||
ton::BlockSeqno prev_mc_block_seqno, bool after_split, bool clear_history,
|
||||
std::function<bool(ton::BlockSeqno)> for_each_mcseqno);
|
||||
td::Status merge_with(ShardState& sib);
|
||||
td::Result<std::unique_ptr<vm::AugmentedDictionary>> compute_split_out_msg_queue(ton::ShardIdFull subshard,
|
||||
td::uint32* queue_size = nullptr);
|
||||
td::Result<std::unique_ptr<vm::AugmentedDictionary>> compute_split_out_msg_queue(ton::ShardIdFull subshard);
|
||||
td::Result<std::shared_ptr<block::MsgProcessedUptoCollection>> compute_split_processed_upto(
|
||||
ton::ShardIdFull subshard);
|
||||
td::Status split(ton::ShardIdFull subshard, td::uint32* queue_size = nullptr);
|
||||
td::Status split(ton::ShardIdFull subshard);
|
||||
td::Status unpack_out_msg_queue_info(Ref<vm::Cell> out_msg_queue_info);
|
||||
bool clear_load_history() {
|
||||
overload_history_ = underload_history_ = 0;
|
||||
|
@ -658,7 +659,7 @@ class MtCarloComputeShare {
|
|||
};
|
||||
|
||||
int filter_out_msg_queue(vm::AugmentedDictionary& out_queue, ton::ShardIdFull old_shard, ton::ShardIdFull subshard,
|
||||
td::uint32* queue_size = nullptr);
|
||||
td::uint64* queue_size = nullptr);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ShardId& shard_id);
|
||||
|
||||
|
@ -749,4 +750,25 @@ bool parse_hex_hash(td::Slice str, td::Bits256& hash);
|
|||
bool parse_block_id_ext(const char* str, const char* end, ton::BlockIdExt& blkid);
|
||||
bool parse_block_id_ext(td::Slice str, ton::BlockIdExt& blkid);
|
||||
|
||||
bool unpack_account_dispatch_queue(Ref<vm::CellSlice> csr, vm::Dictionary& dict, td::uint64& dict_size);
|
||||
Ref<vm::CellSlice> pack_account_dispatch_queue(const vm::Dictionary& dict, td::uint64 dict_size);
|
||||
Ref<vm::CellSlice> get_dispatch_queue_min_lt_account(const vm::AugmentedDictionary& dispatch_queue,
|
||||
ton::StdSmcAddress& addr);
|
||||
bool remove_dispatch_queue_entry(vm::AugmentedDictionary& dispatch_queue, const ton::StdSmcAddress& addr,
|
||||
ton::LogicalTime lt);
|
||||
|
||||
struct MsgMetadata {
|
||||
td::uint32 depth;
|
||||
ton::WorkchainId initiator_wc;
|
||||
ton::StdSmcAddress initiator_addr;
|
||||
ton::LogicalTime initiator_lt;
|
||||
|
||||
bool unpack(vm::CellSlice& cs);
|
||||
bool pack(vm::CellBuilder& cb) const;
|
||||
std::string to_str() const;
|
||||
|
||||
bool operator==(const MsgMetadata& other) const;
|
||||
bool operator!=(const MsgMetadata& other) const;
|
||||
};
|
||||
|
||||
} // namespace block
|
||||
|
|
|
@ -172,6 +172,12 @@ interm_addr_ext$11 workchain_id:int32 addr_pfx:uint64
|
|||
msg_envelope#4 cur_addr:IntermediateAddress
|
||||
next_addr:IntermediateAddress fwd_fee_remaining:Grams
|
||||
msg:^(Message Any) = MsgEnvelope;
|
||||
msg_metadata#0 depth:uint32 initiator_addr:MsgAddressInt initiator_lt:uint64 = MsgMetadata;
|
||||
msg_envelope_v2#5 cur_addr:IntermediateAddress
|
||||
next_addr:IntermediateAddress fwd_fee_remaining:Grams
|
||||
msg:^(Message Any)
|
||||
emitted_lt:(Maybe uint64)
|
||||
metadata:(Maybe MsgMetadata) = MsgEnvelope;
|
||||
//
|
||||
msg_import_ext$000 msg:^(Message Any) transaction:^Transaction
|
||||
= InMsg;
|
||||
|
@ -187,6 +193,9 @@ msg_discard_fin$110 in_msg:^MsgEnvelope transaction_id:uint64
|
|||
fwd_fee:Grams = InMsg;
|
||||
msg_discard_tr$111 in_msg:^MsgEnvelope transaction_id:uint64
|
||||
fwd_fee:Grams proof_delivered:^Cell = InMsg;
|
||||
msg_import_deferred_fin$00100 in_msg:^MsgEnvelope
|
||||
transaction:^Transaction fwd_fee:Grams = InMsg;
|
||||
msg_import_deferred_tr$00101 in_msg:^MsgEnvelope out_msg:^MsgEnvelope = InMsg;
|
||||
//
|
||||
import_fees$_ fees_collected:Grams
|
||||
value_imported:CurrencyCollection = ImportFees;
|
||||
|
@ -210,6 +219,10 @@ msg_export_tr_req$111 out_msg:^MsgEnvelope
|
|||
imported:^InMsg = OutMsg;
|
||||
msg_export_deq_imm$100 out_msg:^MsgEnvelope
|
||||
reimport:^InMsg = OutMsg;
|
||||
msg_export_new_defer$10100 out_msg:^MsgEnvelope
|
||||
transaction:^Transaction = OutMsg;
|
||||
msg_export_deferred_tr$10101 out_msg:^MsgEnvelope
|
||||
imported:^InMsg = OutMsg;
|
||||
|
||||
_ enqueued_lt:uint64 out_msg:^MsgEnvelope = EnqueuedMsg;
|
||||
|
||||
|
@ -224,8 +237,15 @@ _ (HashmapE 96 ProcessedUpto) = ProcessedInfo;
|
|||
ihr_pending$_ import_lt:uint64 = IhrPendingSince;
|
||||
_ (HashmapE 320 IhrPendingSince) = IhrPendingInfo;
|
||||
|
||||
// key - created_lt
|
||||
_ messages:(HashmapE 64 EnqueuedMsg) count:uint48 = AccountDispatchQueue;
|
||||
// key - sender address, aug - min created_lt
|
||||
_ (HashmapAugE 256 AccountDispatchQueue uint64) = DispatchQueue;
|
||||
|
||||
out_msg_queue_extra#0 dispatch_queue:DispatchQueue out_queue_size:(Maybe uint48) = OutMsgQueueExtra;
|
||||
|
||||
_ out_queue:OutMsgQueue proc_info:ProcessedInfo
|
||||
ihr_pending:IhrPendingInfo = OutMsgQueueInfo;
|
||||
extra:(Maybe OutMsgQueueExtra) = OutMsgQueueInfo;
|
||||
//
|
||||
storage_used$_ cells:(VarUInteger 7) bits:(VarUInteger 7)
|
||||
public_cells:(VarUInteger 7) = StorageUsed;
|
||||
|
|
|
@ -3560,7 +3560,7 @@ LtCellRef Transaction::extract_out_msg(unsigned i) {
|
|||
* @returns A triple of the logical time, the extracted output message and the transaction root.
|
||||
*/
|
||||
NewOutMsg Transaction::extract_out_msg_ext(unsigned i) {
|
||||
return {start_lt + i + 1, std::move(out_msgs.at(i)), root};
|
||||
return {start_lt + i + 1, std::move(out_msgs.at(i)), root, i};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,8 +66,11 @@ struct NewOutMsg {
|
|||
ton::LogicalTime lt;
|
||||
Ref<vm::Cell> msg;
|
||||
Ref<vm::Cell> trans;
|
||||
NewOutMsg(ton::LogicalTime _lt, Ref<vm::Cell> _msg, Ref<vm::Cell> _trans)
|
||||
: lt(_lt), msg(std::move(_msg)), trans(std::move(_trans)) {
|
||||
unsigned msg_idx;
|
||||
td::optional<MsgMetadata> metadata;
|
||||
td::Ref<vm::Cell> msg_env_from_dispatch_queue; // Not null if from dispatch queue; in this case lt is emitted_lt
|
||||
NewOutMsg(ton::LogicalTime _lt, Ref<vm::Cell> _msg, Ref<vm::Cell> _trans, unsigned _msg_idx)
|
||||
: lt(_lt), msg(std::move(_msg)), trans(std::move(_trans)), msg_idx(_msg_idx) {
|
||||
}
|
||||
bool operator<(const NewOutMsg& other) const& {
|
||||
return lt < other.lt || (lt == other.lt && msg->get_hash() < other.msg->get_hash());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue