diff --git a/crates/rpc/rpc-eth-types/src/revm_utils.rs b/crates/rpc/rpc-eth-types/src/revm_utils.rs index 53a75ebbb0..c4125bfb51 100644 --- a/crates/rpc/rpc-eth-types/src/revm_utils.rs +++ b/crates/rpc/rpc-eth-types/src/revm_utils.rs @@ -12,13 +12,12 @@ use revm::{ state::{Account, AccountStatus, Bytecode, EvmStorageSlot}, Database, DatabaseCommit, }; -use std::{ - cmp::min, - collections::{BTreeMap, HashMap}, -}; +use std::collections::{BTreeMap, HashMap}; use super::{EthApiError, EthResult, RpcInvalidTransactionError}; +pub use reth_rpc_types_compat::CallFees; + /// Calculates the caller gas allowance. /// /// `allowance = (account.balance - tx.value) / tx.gas_price` @@ -53,146 +52,6 @@ where .saturating_to()) } -/// Helper type for representing the fees of a `TransactionRequest` -#[derive(Debug)] -pub struct CallFees { - /// EIP-1559 priority fee - pub max_priority_fee_per_gas: Option, - /// Unified gas price setting - /// - /// Will be the configured `basefee` if unset in the request - /// - /// `gasPrice` for legacy, - /// `maxFeePerGas` for EIP-1559 - pub gas_price: U256, - /// Max Fee per Blob gas for EIP-4844 transactions - pub max_fee_per_blob_gas: Option, -} - -// === impl CallFees === - -impl CallFees { - /// Ensures the fields of a `TransactionRequest` are not conflicting. - /// - /// # EIP-4844 transactions - /// - /// Blob transactions have an additional fee parameter `maxFeePerBlobGas`. - /// If the `maxFeePerBlobGas` or `blobVersionedHashes` are set we treat it as an EIP-4844 - /// transaction. - /// - /// Note: Due to the `Default` impl of [`BlockEnv`] (Some(0)) this assumes the `block_blob_fee` - /// is always `Some` - /// - /// ## Notable design decisions - /// - /// For compatibility reasons, this contains several exceptions when fee values are validated: - /// - If both `maxFeePerGas` and `maxPriorityFeePerGas` are set to `0` they are treated as - /// missing values, bypassing fee checks wrt. `baseFeePerGas`. - /// - /// This mirrors geth's behaviour when transaction requests are executed: - pub fn ensure_fees( - call_gas_price: Option, - call_max_fee: Option, - call_priority_fee: Option, - block_base_fee: U256, - blob_versioned_hashes: Option<&[B256]>, - max_fee_per_blob_gas: Option, - block_blob_fee: Option, - ) -> EthResult { - /// Get the effective gas price of a transaction as specfified in EIP-1559 with relevant - /// checks. - fn get_effective_gas_price( - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - block_base_fee: U256, - ) -> EthResult { - match max_fee_per_gas { - Some(max_fee) => { - let max_priority_fee_per_gas = max_priority_fee_per_gas.unwrap_or(U256::ZERO); - - // only enforce the fee cap if provided input is not zero - if !(max_fee.is_zero() && max_priority_fee_per_gas.is_zero()) && - max_fee < block_base_fee - { - // `base_fee_per_gas` is greater than the `max_fee_per_gas` - return Err(RpcInvalidTransactionError::FeeCapTooLow.into()) - } - if max_fee < max_priority_fee_per_gas { - return Err( - // `max_priority_fee_per_gas` is greater than the `max_fee_per_gas` - RpcInvalidTransactionError::TipAboveFeeCap.into(), - ) - } - // ref - Ok(min( - max_fee, - block_base_fee.checked_add(max_priority_fee_per_gas).ok_or_else(|| { - EthApiError::from(RpcInvalidTransactionError::TipVeryHigh) - })?, - )) - } - None => Ok(block_base_fee - .checked_add(max_priority_fee_per_gas.unwrap_or(U256::ZERO)) - .ok_or(EthApiError::from(RpcInvalidTransactionError::TipVeryHigh))?), - } - } - - let has_blob_hashes = - blob_versioned_hashes.as_ref().map(|blobs| !blobs.is_empty()).unwrap_or(false); - - match (call_gas_price, call_max_fee, call_priority_fee, max_fee_per_blob_gas) { - (gas_price, None, None, None) => { - // either legacy transaction or no fee fields are specified - // when no fields are specified, set gas price to zero - let gas_price = gas_price.unwrap_or(U256::ZERO); - Ok(Self { - gas_price, - max_priority_fee_per_gas: None, - max_fee_per_blob_gas: has_blob_hashes.then_some(block_blob_fee).flatten(), - }) - } - (None, max_fee_per_gas, max_priority_fee_per_gas, None) => { - // request for eip-1559 transaction - let effective_gas_price = get_effective_gas_price( - max_fee_per_gas, - max_priority_fee_per_gas, - block_base_fee, - )?; - let max_fee_per_blob_gas = has_blob_hashes.then_some(block_blob_fee).flatten(); - - Ok(Self { - gas_price: effective_gas_price, - max_priority_fee_per_gas, - max_fee_per_blob_gas, - }) - } - (None, max_fee_per_gas, max_priority_fee_per_gas, Some(max_fee_per_blob_gas)) => { - // request for eip-4844 transaction - let effective_gas_price = get_effective_gas_price( - max_fee_per_gas, - max_priority_fee_per_gas, - block_base_fee, - )?; - // Ensure blob_hashes are present - if !has_blob_hashes { - // Blob transaction but no blob hashes - return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into()) - } - - Ok(Self { - gas_price: effective_gas_price, - max_priority_fee_per_gas, - max_fee_per_blob_gas: Some(max_fee_per_blob_gas), - }) - } - _ => { - // this fallback covers incompatible combinations of fields - Err(EthApiError::ConflictingFeeFieldsInRequest) - } - } - } -} - /// Helper trait implemented for databases that support overriding block hashes. /// /// Used for applying [`BlockOverrides::block_hash`]