From 43e3621115b951b3d1e60876d22fa75c4c99899a Mon Sep 17 00:00:00 2001 From: GianfrancoBazzani <55500596+GianfrancoBazzani@users.noreply.github.com> Date: Wed, 15 Mar 2023 11:49:58 +0100 Subject: [PATCH] Improve revm halt out of gas error handling (#1725) Co-authored-by: Matthias Seitz --- crates/rpc/rpc/src/eth/api/call.rs | 7 +++++-- crates/rpc/rpc/src/eth/error.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index db76bfb812..4ca5c0748a 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -168,7 +168,9 @@ where } ExecutionResult::Halt { reason, .. } => { return match reason { - Halt::OutOfGas(_) => Err(InvalidTransactionError::OutOfGas(gas_limit).into()), + Halt::OutOfGas(err) => { + Err(InvalidTransactionError::out_of_gas(err, gas_limit).into()) + } Halt::NonceOverflow => Err(InvalidTransactionError::NonceMaxValue.into()), err => Err(InvalidTransactionError::EvmHalt(err).into()), } @@ -184,7 +186,8 @@ where ExecutionResult::Success { .. } => { // transaction succeeded by manually increasing the gas limit to // highest, which means the caller lacks funds to pay for the tx - Err(InvalidTransactionError::OutOfGas(U256::from(req_gas_limit)).into()) + Err(InvalidTransactionError::BasicOutOfGas(U256::from(req_gas_limit)) + .into()) } ExecutionResult::Revert { .. } => { // reverted again after bumping the limit diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index c95abea25b..0ea30bfe5f 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -5,7 +5,7 @@ use jsonrpsee::{core::Error as RpcError, types::error::INVALID_PARAMS_CODE}; use reth_primitives::{constants::SELECTOR_LEN, Address, U128, U256}; use reth_rpc_types::{error::EthRpcErrorCode, BlockError}; use reth_transaction_pool::error::{InvalidPoolTransactionError, PoolError}; -use revm::primitives::{EVMError, Halt}; +use revm::primitives::{EVMError, Halt, OutOfGasError}; /// Result alias pub type EthResult = Result; @@ -158,7 +158,16 @@ pub enum InvalidTransactionError { SenderNoEOA, /// Thrown during estimate if caller has insufficient funds to cover the tx. #[error("Out of gas: gas required exceeds allowance: {0:?}")] - OutOfGas(U256), + BasicOutOfGas(U256), + /// As BasicOutOfGas but thrown when gas exhausts during memory expansion. + #[error("Out of gas: gas exhausts during memory expansion: {0:?}")] + MemoryOutOfGas(U256), + /// As BasicOutOfGas but thrown when gas exhausts during precompiled contract execution. + #[error("Out of gas: gas exhausts during precompiled contract execution: {0:?}")] + PrecompileOutOfGas(U256), + /// revm's Type cast error, U256 casts down to a u64 with overflow + #[error("Out of gas: revm's Type cast error, U256 casts down to a u64 with overflow {0:?}")] + InvalidOperandOutOfGas(U256), /// Thrown if executing a transaction failed during estimate/call #[error("{0}")] Revert(RevertError), @@ -181,6 +190,19 @@ impl InvalidTransactionError { _ => EthRpcErrorCode::TransactionRejected.code(), } } + + /// Converts the out of gas error + pub(crate) fn out_of_gas(reason: OutOfGasError, gas_limit: U256) -> Self { + match reason { + OutOfGasError::BasicOutOfGas => InvalidTransactionError::BasicOutOfGas(gas_limit), + OutOfGasError::Memory => InvalidTransactionError::MemoryOutOfGas(gas_limit), + OutOfGasError::Precompile => InvalidTransactionError::PrecompileOutOfGas(gas_limit), + OutOfGasError::InvalidOperand => { + InvalidTransactionError::InvalidOperandOutOfGas(gas_limit) + } + OutOfGasError::MemoryLimit => InvalidTransactionError::MemoryOutOfGas(gas_limit), + } + } } impl From for RpcError {