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:
parent
ff40c1f2a0
commit
388c8a6d86
3 changed files with 95 additions and 9 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in a new issue