1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +00:00

Increase gas limit for a specific wallet (enabled by config) (#859)

This commit is contained in:
SpyCheese 2024-01-15 23:43:11 +03:00 committed by GitHub
parent ff40c1f2a0
commit 388c8a6d86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 9 deletions

View file

@ -1081,6 +1081,25 @@ bool ComputePhaseConfig::is_address_suspended(ton::WorkchainId wc, td::Bits256 a
} }
} }
/**
* Computes the maximum gas fee based on the gas prices and limits.
*
* @param gas_price256 The gas price from config as RefInt256
* @param gas_limit The gas limit from config
* @param flat_gas_limit The flat gas limit from config
* @param flat_gas_price The flat gas price from config
*
* @returns The maximum gas fee.
*/
static td::RefInt256 compute_max_gas_threshold(const td::RefInt256& gas_price256, td::uint64 gas_limit,
td::uint64 flat_gas_limit, td::uint64 flat_gas_price) {
if (gas_limit > flat_gas_limit) {
return td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_bigint(flat_gas_price);
} else {
return td::make_refint(flat_gas_price);
}
}
/** /**
* Computes the maximum for gas fee based on the gas prices and limits. * Computes the maximum for gas fee based on the gas prices and limits.
* *
@ -1088,12 +1107,7 @@ bool ComputePhaseConfig::is_address_suspended(ton::WorkchainId wc, td::Bits256 a
*/ */
void ComputePhaseConfig::compute_threshold() { void ComputePhaseConfig::compute_threshold() {
gas_price256 = td::make_refint(gas_price); gas_price256 = td::make_refint(gas_price);
if (gas_limit > flat_gas_limit) { max_gas_threshold = compute_max_gas_threshold(gas_price256, gas_limit, flat_gas_limit, flat_gas_price);
max_gas_threshold =
td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_bigint(flat_gas_price);
} else {
max_gas_threshold = td::make_refint(flat_gas_price);
}
} }
/** /**
@ -1130,6 +1144,67 @@ td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
} }
namespace transaction { namespace transaction {
/**
* Checks if it is required to increase gas_limit (from GasLimitsPrices config) to special_gas_limit * 2
* from masterchain GasLimitsPrices config for the transaction.
*
* In January 2024 a highload wallet of @wallet Telegram bot in mainnet was stuck because current gas limit (1M) is
* not enough to clean up old queires, thus locking funds inside.
* See comment in crypto/smartcont/highload-wallet-v2-code.fc for details on why this happened.
* Account address: EQD_v9j1rlsuHHw2FIhcsCFFSD367ldfDdCKcsNmNpIRzUlu
* It was proposed to validators to increase gas limit for this account for a limited amount of time (until 2024-02-16).
* It is activated by setting gas_prices_v3 in ConfigParam 20 (config_mc_gas_prices).
* This config change also activates new behavior for special accounts in masterchain.
*
* @param cfg The compute phase configuration.
* @param now The Unix time of the transaction.
* @param account The account of the transaction.
*
* @returns True if gas_limit override is required, false otherwise
*/
static bool override_gas_limit(const ComputePhaseConfig& cfg, ton::UnixTime now, const Account& account) {
if (!cfg.mc_gas_prices.special_full_limit) {
return false;
}
ton::UnixTime until = 1708041600; // 2024-02-16 00:00:00 UTC
ton::WorkchainId wc = 0;
const char* addr_hex = "FFBFD8F5AE5B2E1C7C3614885CB02145483DFAEE575F0DD08A72C366369211CD";
return now < until && account.workchain == wc && account.addr.to_hex() == addr_hex;
}
/**
* Computes the amount of gas that can be bought for a given amount of nanograms.
* Usually equal to `cfg.gas_bought_for(nanograms)`
* However, it overrides gas_limit from config in special cases.
*
* @param cfg The compute phase configuration.
* @param nanograms The amount of nanograms to compute gas for.
*
* @returns The amount of gas.
*/
td::uint64 Transaction::gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms) {
if (override_gas_limit(cfg, now, account)) {
gas_limit_overridden = true;
// Same as ComputePhaseConfig::gas_bought for, but with other gas_limit and max_gas_threshold
auto gas_limit = cfg.mc_gas_prices.special_gas_limit * 2;
auto max_gas_threshold =
compute_max_gas_threshold(cfg.gas_price256, gas_limit, cfg.flat_gas_limit, cfg.flat_gas_price);
if (nanograms.is_null() || sgn(nanograms) < 0) {
return 0;
}
if (nanograms >= max_gas_threshold) {
return gas_limit;
}
if (nanograms < cfg.flat_gas_price) {
return 0;
}
auto res = td::div((std::move(nanograms) - cfg.flat_gas_price) << 16, cfg.gas_price256);
return res->to_long() + cfg.flat_gas_limit;
}
return cfg.gas_bought_for(nanograms);
}
/** /**
* Computes the gas limits for a transaction. * Computes the gas limits for a transaction.
* *
@ -1143,7 +1218,7 @@ bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig&
if (account.is_special) { if (account.is_special) {
cp.gas_max = cfg.special_gas_limit; cp.gas_max = cfg.special_gas_limit;
} else { } else {
cp.gas_max = cfg.gas_bought_for(balance.grams); cp.gas_max = gas_bought_for(cfg, balance.grams);
} }
cp.gas_credit = 0; cp.gas_credit = 0;
if (trans_type != tr_ord || (account.is_special && cfg.special_gas_full)) { if (trans_type != tr_ord || (account.is_special && cfg.special_gas_full)) {
@ -1152,7 +1227,7 @@ bool Transaction::compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig&
} else { } else {
// originally use only gas bought using remaining message balance // originally use only gas bought using remaining message balance
// if the message is "accepted" by the smart contract, the gas limit will be set to gas_max // if the message is "accepted" by the smart contract, the gas limit will be set to gas_max
cp.gas_limit = std::min(cfg.gas_bought_for(msg_balance_remaining.grams), cp.gas_max); cp.gas_limit = std::min(gas_bought_for(cfg, msg_balance_remaining.grams), cp.gas_max);
if (!block::tlb::t_Message.is_internal(in_msg)) { if (!block::tlb::t_Message.is_internal(in_msg)) {
// external messages carry no balance, give them some credit to check whether they are accepted // external messages carry no balance, give them some credit to check whether they are accepted
cp.gas_credit = std::min(cfg.gas_credit, cp.gas_max); cp.gas_credit = std::min(cfg.gas_credit, cp.gas_max);
@ -3454,6 +3529,9 @@ td::Status FetchConfigParams::fetch_config_params(
storage_phase_cfg->delete_due_limit)) { storage_phase_cfg->delete_due_limit)) {
return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration"); return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration");
} }
TRY_RESULT_PREFIX(mc_gas_prices, config.get_gas_limits_prices(true),
"cannot unpack masterchain gas prices and limits: ");
compute_phase_cfg->mc_gas_prices = std::move(mc_gas_prices);
storage_phase_cfg->enable_due_payment = config.get_global_version() >= 4; storage_phase_cfg->enable_due_payment = config.get_global_version() >= 4;
compute_phase_cfg->block_rand_seed = *rand_seed; compute_phase_cfg->block_rand_seed = *rand_seed;
compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth; compute_phase_cfg->max_vm_data_depth = size_limits.max_vm_data_depth;

View file

@ -105,6 +105,7 @@ struct ComputePhaseConfig {
td::uint64 flat_gas_limit = 0; td::uint64 flat_gas_limit = 0;
td::uint64 flat_gas_price = 0; td::uint64 flat_gas_price = 0;
bool special_gas_full = false; bool special_gas_full = false;
block::GasLimitsPrices mc_gas_prices;
static constexpr td::uint64 gas_infty = (1ULL << 63) - 1; static constexpr td::uint64 gas_infty = (1ULL << 63) - 1;
td::RefInt256 gas_price256; td::RefInt256 gas_price256;
td::RefInt256 max_gas_threshold; td::RefInt256 max_gas_threshold;
@ -358,12 +359,14 @@ struct Transaction {
std::unique_ptr<ActionPhase> action_phase; std::unique_ptr<ActionPhase> action_phase;
std::unique_ptr<BouncePhase> bounce_phase; std::unique_ptr<BouncePhase> bounce_phase;
vm::CellStorageStat new_storage_stat; vm::CellStorageStat new_storage_stat;
bool gas_limit_overridden{false};
Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now, Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
Ref<vm::Cell> _inmsg = {}); Ref<vm::Cell> _inmsg = {});
bool unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg); bool unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg);
bool check_in_msg_state_hash(); bool check_in_msg_state_hash();
bool prepare_storage_phase(const StoragePhaseConfig& cfg, bool force_collect = true, bool adjust_msg_value = false); bool prepare_storage_phase(const StoragePhaseConfig& cfg, bool force_collect = true, bool adjust_msg_value = false);
bool prepare_credit_phase(); bool prepare_credit_phase();
td::uint64 gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms);
bool compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cfg); bool compute_gas_limits(ComputePhase& cp, const ComputePhaseConfig& cfg);
Ref<vm::Stack> prepare_vm_stack(ComputePhase& cp); Ref<vm::Stack> prepare_vm_stack(ComputePhase& cp);
std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg); std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg);

View file

@ -940,6 +940,11 @@ bool ValidateQuery::fetch_config_params() {
storage_phase_cfg_.delete_due_limit)) { storage_phase_cfg_.delete_due_limit)) {
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration"); return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
} }
auto mc_gas_prices = config_->get_gas_limits_prices(true);
if (mc_gas_prices.is_error()) {
return fatal_error(mc_gas_prices.move_as_error_prefix("cannot unpack masterchain gas prices and limits: "));
}
compute_phase_cfg_.mc_gas_prices = mc_gas_prices.move_as_ok();
storage_phase_cfg_.enable_due_payment = config_->get_global_version() >= 4; storage_phase_cfg_.enable_due_payment = config_->get_global_version() >= 4;
compute_phase_cfg_.block_rand_seed = rand_seed_; compute_phase_cfg_.block_rand_seed = rand_seed_;
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256); compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
@ -5052,7 +5057,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
<< " for smart contract " << addr.to_hex()); << " for smart contract " << addr.to_hex());
} }
if (!trs->update_limits(*block_limit_status_, if (!trs->update_limits(*block_limit_status_,
/* with_gas = */ !account.is_special, /* with_gas = */ !account.is_special && !trs->gas_limit_overridden,
/* with_size = */ false)) { /* with_size = */ false)) {
return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account " return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
<< addr.to_hex()); << addr.to_hex());