From ae08aff812fbd205a78354a0dcd31f7fe850670d Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Thu, 26 Dec 2024 14:44:33 -0300 Subject: [PATCH] fix(levm): move insufficient max fee per blob gas check in `prepare_execution` (#1564) **Motivation** Currently we are charging the sender the entire upfront cost, even when there are not enough funds to pay for the provided amount of blobhashes. This returns a `TxValidation` error of type `InsufficientAccountFunds`, when in reality the error we should be raising is `InsufficientMaxFeePerBlobGas`. **Description** This patch moves the insufficient max fee per blob gas check up. Now, before the user is charged with the entire `upfront cost`, it is checked if the provided max fee per blob gas will cover the blobhash cost. If not, we return a `InsufficientMaxFeePerBlobGas` error, before even trying to charge for the upfront cost. --- crates/vm/levm/src/vm.rs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 846d98a05..e713080b0 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -711,6 +711,15 @@ impl VM { let blob_gas_cost = self.get_blob_gas_price()?; + // (2) INSUFFICIENT_MAX_FEE_PER_BLOB_GAS + if let Some(tx_max_fee_per_blob_gas) = self.env.tx_max_fee_per_blob_gas { + if tx_max_fee_per_blob_gas < self.get_base_fee_per_blob_gas()? { + return Err(VMError::TxValidation( + TxValidationError::InsufficientMaxFeePerBlobGas, + )); + } + } + // The real cost to deduct is calculated as effective_gas_price * gas_limit + value + blob_gas_cost let up_front_cost = gaslimit_price_product .checked_add(value) @@ -721,9 +730,12 @@ impl VM { .ok_or(VMError::TxValidation( TxValidationError::InsufficientAccountFunds, ))?; - // There is no error specified for overflow in up_front_cost in ef_tests. Maybe we can go with GasLimitPriceProductOverflow or InsufficientAccountFunds. + // There is no error specified for overflow in up_front_cost + // in ef_tests. We went for "InsufficientAccountFunds" simply + // because if the upfront cost is bigger than U256, then, + // technically, the sender will not be able to pay it. - // (2) INSUFFICIENT_ACCOUNT_FUNDS + // (3) INSUFFICIENT_ACCOUNT_FUNDS self.decrease_account_balance(sender_address, up_front_cost) .map_err(|_| TxValidationError::InsufficientAccountFunds)?; @@ -734,14 +746,14 @@ impl VM { self.increase_account_balance(receiver_address, initial_call_frame.msg_value)?; } - // (3) INSUFFICIENT_MAX_FEE_PER_GAS + // (4) INSUFFICIENT_MAX_FEE_PER_GAS if self.env.tx_max_fee_per_gas.unwrap_or(self.env.gas_price) < self.env.base_fee_per_gas { return Err(VMError::TxValidation( TxValidationError::InsufficientMaxFeePerGas, )); } - // (4) INITCODE_SIZE_EXCEEDED + // (5) INITCODE_SIZE_EXCEEDED if self.is_create() { // INITCODE_SIZE_EXCEEDED if initial_call_frame.calldata.len() > INIT_CODE_MAX_SIZE { @@ -751,14 +763,14 @@ impl VM { } } - // (5) INTRINSIC_GAS_TOO_LOW + // (6) INTRINSIC_GAS_TOO_LOW self.add_intrinsic_gas(initial_call_frame)?; - // (6) NONCE_IS_MAX + // (7) NONCE_IS_MAX self.increment_account_nonce(sender_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; - // (7) PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS + // (8) PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS if let (Some(tx_max_priority_fee), Some(tx_max_fee_per_gas)) = ( self.env.tx_max_priority_fee_per_gas, self.env.tx_max_fee_per_gas, @@ -770,27 +782,18 @@ impl VM { } } - // (8) SENDER_NOT_EOA + // (9) SENDER_NOT_EOA if sender_account.has_code() { return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); } - // (9) GAS_ALLOWANCE_EXCEEDED + // (10) GAS_ALLOWANCE_EXCEEDED if self.env.gas_limit > self.env.block_gas_limit { return Err(VMError::TxValidation( TxValidationError::GasAllowanceExceeded, )); } - // (10) INSUFFICIENT_MAX_FEE_PER_BLOB_GAS - if let Some(tx_max_fee_per_blob_gas) = self.env.tx_max_fee_per_blob_gas { - if tx_max_fee_per_blob_gas < self.get_base_fee_per_blob_gas()? { - return Err(VMError::TxValidation( - TxValidationError::InsufficientMaxFeePerBlobGas, - )); - } - } - // Transaction is type 3 if tx_max_fee_per_blob_gas is Some if self.env.tx_max_fee_per_blob_gas.is_some() { let blob_hashes = &self.env.tx_blob_hashes;