diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb index 4b36f13b..eb1f8b94 100644 --- a/crypto/block/block.tlb +++ b/crypto/block/block.tlb @@ -696,6 +696,11 @@ gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 = GasLimitsPrices; +// same fields as gas_prices_ext; behavior differs +gas_prices_v3#df gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas_credit:uint64 + block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 + = GasLimitsPrices; + gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices = GasLimitsPrices; diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index 08be5c88..51402142 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -654,11 +654,16 @@ td::Result Config::do_get_gas_limits_prices(td::Ref c res.delete_due_limit = r.delete_due_limit; }; block::gen::GasLimitsPrices::Record_gas_prices_ext rec; + block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3; + vm::CellSlice cs0 = cs; if (tlb::unpack(cs, rec)) { f(rec, rec.special_gas_limit); + } else if (tlb::unpack(cs = cs0, rec_v3)) { + f(rec_v3, rec_v3.special_gas_limit); + res.special_full_limit = true; } else { block::gen::GasLimitsPrices::Record_gas_prices rec0; - if (tlb::unpack(cs, rec0)) { + if (tlb::unpack(cs = cs0, rec0)) { f(rec0, rec0.gas_limit); } else { return td::Status::Error(PSLICE() << "configuration parameter " << id diff --git a/crypto/block/mc-config.h b/crypto/block/mc-config.h index caab93f3..dcc48b4b 100644 --- a/crypto/block/mc-config.h +++ b/crypto/block/mc-config.h @@ -349,6 +349,7 @@ struct GasLimitsPrices { td::uint64 block_gas_limit{0}; td::uint64 freeze_due_limit{0}; td::uint64 delete_due_limit{0}; + bool special_full_limit{false}; td::RefInt256 compute_gas_price(td::uint64 gas_used) const; }; diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index 7a907337..5955dd6e 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -1039,8 +1039,12 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref cs, t delete_due_limit = td::make_refint(r.delete_due_limit); }; block::gen::GasLimitsPrices::Record_gas_prices_ext rec; + block::gen::GasLimitsPrices::Record_gas_prices_v3 rec_v3; if (tlb::csr_unpack(cs, rec)) { f(rec, rec.special_gas_limit); + } else if (tlb::csr_unpack(cs, rec_v3)) { + f(rec_v3, rec_v3.special_gas_limit); + special_gas_full = true; } else { block::gen::GasLimitsPrices::Record_gas_prices rec0; if (tlb::csr_unpack(std::move(cs), rec0)) { @@ -1142,7 +1146,7 @@ bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cp.gas_max = cfg.gas_bought_for(balance.grams); } cp.gas_credit = 0; - if (trans_type != tr_ord) { + if (trans_type != tr_ord || (account.is_special && cfg.special_gas_full)) { // may use all gas that can be bought using remaining balance cp.gas_limit = cp.gas_max; } else { @@ -3203,8 +3207,8 @@ td::Result Transaction::estimate_block_storage_pro * * @returns True if the limits were successfully updated, False otherwise. */ -bool Transaction::update_limits(block::BlockLimitStatus& blimst, bool with_size) const { - if (!(blimst.update_lt(end_lt) && blimst.update_gas(gas_used()))) { +bool Transaction::update_limits(block::BlockLimitStatus& blimst, bool with_gas, bool with_size) const { + if (!(blimst.update_lt(end_lt) && blimst.update_gas(with_gas ? gas_used() : 0))) { return false; } if (with_size) { diff --git a/crypto/block/transaction.h b/crypto/block/transaction.h index d7cb95d1..deb71a40 100644 --- a/crypto/block/transaction.h +++ b/crypto/block/transaction.h @@ -104,6 +104,7 @@ struct ComputePhaseConfig { td::uint64 gas_credit; td::uint64 flat_gas_limit = 0; td::uint64 flat_gas_price = 0; + bool special_gas_full = false; static constexpr td::uint64 gas_infty = (1ULL << 63) - 1; td::RefInt256 gas_price256; td::RefInt256 max_gas_threshold; @@ -119,12 +120,7 @@ struct ComputePhaseConfig { SizeLimitsConfig size_limits; int vm_log_verbosity = 0; - ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0) - : gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_gas_limit), gas_credit(_gas_credit) { - compute_threshold(); - } - ComputePhaseConfig(td::uint64 _gas_price, td::uint64 _gas_limit, td::uint64 _spec_gas_limit, td::uint64 _gas_credit) - : gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_spec_gas_limit), gas_credit(_gas_credit) { + ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) { compute_threshold(); } void compute_threshold(); @@ -383,7 +379,7 @@ struct Transaction { td::Result estimate_block_storage_profile_incr( const vm::NewCellStorageStat& store_stat, const vm::CellUsageTree* usage_tree) const; - bool update_limits(block::BlockLimitStatus& blk_lim_st, bool with_size = true) const; + bool update_limits(block::BlockLimitStatus& blk_lim_st, bool with_gas = true, bool with_size = true) const; Ref commit(Account& _account); // _account should point to the same account LtCellRef extract_out_msg(unsigned i); diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 1d277048..1b7991f6 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -2667,7 +2667,8 @@ 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_)) { + if (!trans->update_limits(*block_limit_status_, + /* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) { return fatal_error(-666, "cannot update block limit status to include the new transaction"); } if (trans->commit(*acc).is_null()) { @@ -2744,7 +2745,8 @@ Ref Collator::create_ordinary_transaction(Ref msg_root) { } std::unique_ptr trans = res.move_as_ok(); - if (!trans->update_limits(*block_limit_status_)) { + if (!trans->update_limits(*block_limit_status_, + /* with_gas = */ !(acc->is_special && compute_phase_cfg_.special_gas_full))) { fatal_error("cannot update block limit status to include the new transaction"); return {}; } diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index d5f489a3..0a22fa14 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -4904,13 +4904,6 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT int trans_type = block::transaction::Transaction::tr_none; switch (tag) { case block::gen::TransactionDescr::trans_ord: { - if (!block_limit_status_->fits(block::ParamLimits::cl_medium)) { - return reject_query(PSTRING() << "cannod add ordinary transaction because hard block limits are exceeded: " - << "gas_used=" << block_limit_status_->gas_used - << "(limit=" << block_limits_->gas.hard() << "), " - << "lt_delta=" << block_limit_status_->cur_lt - block_limits_->start_lt - << "(limit=" << block_limits_->lt_delta.hard() << ")"); - } trans_type = block::transaction::Transaction::tr_ord; if (in_msg_root.is_null()) { return reject_query(PSTRING() << "ordinary transaction " << lt << " of account " << addr.to_hex() @@ -5058,10 +5051,19 @@ 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_, false)) { + if (!trs->update_limits(*block_limit_status_, + /* with_gas = */ !account.is_special, + /* 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 + 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 + << ", gas_limit_hard=" << block_limits_->gas.hard() + << ", trx_gas_limit=" << compute_phase_cfg_.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()