From 2e231ec2ff74b950dabccdf490d9fcf8ea97ea27 Mon Sep 17 00:00:00 2001 From: EmelyanenkoK Date: Mon, 22 Jan 2024 21:56:11 +0300 Subject: [PATCH] Count gas usage for ordinar transactions on special accounts in separate counter (#872) * Improve checking total gas usage in collator and validator --------- Co-authored-by: SpyCheese --- validator/impl/collator-impl.h | 2 +- validator/impl/collator.cpp | 10 +++++----- validator/impl/validate-query.cpp | 28 +++++++++++++++++++++------- validator/impl/validate-query.hpp | 1 + 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/validator/impl/collator-impl.h b/validator/impl/collator-impl.h index fe931cd6..c6ba27b4 100644 --- a/validator/impl/collator-impl.h +++ b/validator/impl/collator-impl.h @@ -244,7 +244,7 @@ class Collator final : public td::actor::Actor { Ref& in_msg); bool create_ticktock_transactions(int mask); bool create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, ton::LogicalTime req_start_lt, int mask); - Ref create_ordinary_transaction(Ref msg_root); + Ref create_ordinary_transaction(Ref msg_root, bool is_special_tx = false); bool check_cur_validator_set(); bool unpack_last_mc_state(); bool unpack_last_state(); diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 1b7991f6..413c5be9 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -2667,8 +2667,7 @@ bool Collator::create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, t return fatal_error(td::Status::Error( -666, std::string{"cannot serialize new transaction for smart contract "} + smc_addr.to_hex())); } - if (!trans->update_limits(*block_limit_status_, - /* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) { + if (!trans->update_limits(*block_limit_status_, /* with_gas = */ false)) { return fatal_error(-666, "cannot update block limit status to include the new transaction"); } if (trans->commit(*acc).is_null()) { @@ -2684,10 +2683,11 @@ bool Collator::create_ticktock_transaction(const ton::StdSmcAddress& smc_addr, t * Creates an ordinary transaction using a given message. * * @param msg_root The root of the message to be processed serialized using Message TLB-scheme. + * @param is_special_tx True if creating a special transaction (mint/recover), false otherwise. * * @returns The root of the serialized transaction, or an empty reference if the transaction creation fails. */ -Ref Collator::create_ordinary_transaction(Ref msg_root) { +Ref Collator::create_ordinary_transaction(Ref msg_root, bool is_special_tx) { ton::StdSmcAddress addr; auto cs = vm::load_cell_slice(msg_root); bool external; @@ -2746,7 +2746,7 @@ Ref Collator::create_ordinary_transaction(Ref msg_root) { std::unique_ptr trans = res.move_as_ok(); if (!trans->update_limits(*block_limit_status_, - /* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) { + /* with_gas = */ !(is_special_tx && compute_phase_cfg_.special_gas_full))) { fatal_error("cannot update block limit status to include the new transaction"); return {}; } @@ -3019,7 +3019,7 @@ int Collator::process_one_new_message(block::NewOutMsg msg, bool enqueue_only, R return -1; } // 1. create a Transaction processing this Message - auto trans_root = create_ordinary_transaction(msg.msg); + auto trans_root = create_ordinary_transaction(msg.msg, is_special != nullptr); if (trans_root.is_null()) { fatal_error("cannot create transaction for re-processing output message"); return -1; diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index f5dc28e2..2b3ccd85 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -4685,6 +4685,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT bool external{false}, ihr_delivered{false}, need_credit_phase{false}; // check input message block::CurrencyCollection money_imported(0), money_exported(0); + bool is_special_tx = false; // recover/mint transaction if (in_msg_root.not_null()) { auto in_descr_cs = in_msg_dict_->lookup(in_msg_root->get_hash().as_bitslice()); if (in_descr_cs.is_null()) { @@ -4700,6 +4701,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT << " has an invalid InMsg record (not one of msg_import_ext, msg_import_fin, " "msg_import_imm or msg_import_ihr)"); } + is_special_tx = is_special_in_msg(*in_descr_cs); // once we know there is a InMsg with correct hash, we already know that it contains a message with this hash (by the verification of InMsg), so it is our message // have still to check its destination address and imported value // and that it refers to this transaction @@ -4717,7 +4719,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT << " processed inbound message created later at logical time " << info.created_lt); } - if (info.created_lt != start_lt_ || !is_special_in_msg(*in_descr_cs)) { + if (info.created_lt != start_lt_ || !is_special_tx) { msg_proc_lt_.emplace_back(addr, lt, info.created_lt); } dest = std::move(info.dest); @@ -5057,19 +5059,31 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt << " for smart contract " << addr.to_hex()); } - if (!trs->update_limits(*block_limit_status_, - /* with_gas = */ !account.is_special && !trs->gas_limit_overridden, - /* with_size = */ false)) { + if (!trs->update_limits(*block_limit_status_, /* with_gas = */ false, /* with_size = */ false)) { return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account " << addr.to_hex()); } - if (block_limit_status_->gas_used > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) { - // Note that block_limit_status_->gas_used does not include transactions in special accounts + + // Collator should stop if total gas usage exceeds limits, including transactions on special accounts, but without + // ticktocks and mint/recover. + // Here Validator checks a weaker condition + if (!is_special_tx && !trs->gas_limit_overridden && trans_type == block::transaction::Transaction::tr_ord) { + (account.is_special ? total_special_gas_used_ : total_gas_used_) += trs->gas_used(); + } + if (total_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) { return reject_query(PSTRING() << "gas block limits are exceeded: total_gas_used > gas_limit_hard + trx_gas_limit (" - << "total_gas_used=" << block_limit_status_->gas_used + << "total_gas_used=" << total_gas_used_ << ", gas_limit_hard=" << block_limits_->gas.hard() << ", trx_gas_limit=" << compute_phase_cfg_.gas_limit << ")"); } + if (total_special_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.special_gas_limit) { + return reject_query( + PSTRING() << "gas block limits are exceeded: total_special_gas_used > gas_limit_hard + special_gas_limit (" + << "total_special_gas_used=" << total_special_gas_used_ + << ", gas_limit_hard=" << block_limits_->gas.hard() + << ", special_gas_limit=" << compute_phase_cfg_.special_gas_limit << ")"); + } + auto trans_root2 = trs->commit(account); if (trans_root2.is_null()) { return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex() diff --git a/validator/impl/validate-query.hpp b/validator/impl/validate-query.hpp index ff8cc83c..8829ac61 100644 --- a/validator/impl/validate-query.hpp +++ b/validator/impl/validate-query.hpp @@ -195,6 +195,7 @@ class ValidateQuery : public td::actor::Actor { ton::LogicalTime prev_key_block_lt_; std::unique_ptr block_limits_; std::unique_ptr block_limit_status_; + td::uint64 total_gas_used_{0}, total_special_gas_used_{0}; LogicalTime start_lt_, end_lt_; UnixTime prev_now_{~0u}, now_{~0u};