From 07b121042ffaf53cee6a3e956525bc184da4f6d8 Mon Sep 17 00:00:00 2001 From: dancoombs Date: Sat, 23 Sep 2023 09:45:36 -0400 Subject: [PATCH] refactor(provider): crate provider error enum --- Cargo.lock | 2 + crates/builder/src/bundle_proposer.rs | 10 +- crates/provider/Cargo.toml | 1 + crates/provider/src/ethers/provider.rs | 128 +++++++++++++----------- crates/provider/src/lib.rs | 5 +- crates/provider/src/traits/error.rs | 15 +++ crates/provider/src/traits/mod.rs | 5 +- crates/provider/src/traits/provider.rs | 58 ++++++----- crates/rpc/src/eth/error.rs | 11 +- crates/sim/Cargo.toml | 1 + crates/sim/src/estimation/estimation.rs | 47 +++------ crates/sim/src/gas/gas.rs | 7 +- crates/sim/src/gas/polygon.rs | 47 ++++----- crates/sim/src/simulation/simulation.rs | 19 ++-- crates/sim/src/utils.rs | 10 +- 15 files changed, 190 insertions(+), 176 deletions(-) create mode 100644 crates/provider/src/traits/error.rs diff --git a/Cargo.lock b/Cargo.lock index bced7abe7..c40ff4945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4062,6 +4062,7 @@ dependencies = [ "rundler-types", "rundler-utils", "serde", + "thiserror", "tokio", ] @@ -4100,6 +4101,7 @@ dependencies = [ "arrayvec", "async-trait", "ethers", + "futures-util", "indexmap 2.0.0", "mockall", "parse-display", diff --git a/crates/builder/src/bundle_proposer.rs b/crates/builder/src/bundle_proposer.rs index 573d10575..b5dc4af6c 100644 --- a/crates/builder/src/bundle_proposer.rs +++ b/crates/builder/src/bundle_proposer.rs @@ -9,6 +9,7 @@ use anyhow::Context; use async_trait::async_trait; use ethers::types::{Address, BlockId, Bytes, H256, U256}; use futures::future; +use futures_util::TryFutureExt; use linked_hash_map::LinkedHashMap; #[cfg(test)] use mockall::automock; @@ -105,7 +106,9 @@ where async fn make_bundle(&self, required_fees: Option) -> anyhow::Result { let (ops, block_hash, bundle_fees) = try_join!( self.get_ops_from_pool(), - self.provider.get_latest_block_hash(), + self.provider + .get_latest_block_hash() + .map_err(anyhow::Error::from), self.fee_estimator.required_bundle_fees(required_fees) )?; @@ -475,7 +478,8 @@ where .collect(); let result = Arc::clone(&self.provider) .aggregate_signatures(aggregator, ops) - .await; + .await + .map_err(anyhow::Error::from); (aggregator, result) } @@ -1282,7 +1286,7 @@ mod tests { .returning(move || Ok(max_priority_fee_per_gas)); provider .expect_aggregate_signatures() - .returning(move |address, _| signatures_by_aggregator[&address]()); + .returning(move |address, _| Ok(signatures_by_aggregator[&address]()?)); let (event_sender, _) = broadcast::channel(16); let proposer = BundleProposerImpl::new( 0, diff --git a/crates/provider/Cargo.toml b/crates/provider/Cargo.toml index 031a8af35..d4d40c9ec 100644 --- a/crates/provider/Cargo.toml +++ b/crates/provider/Cargo.toml @@ -15,6 +15,7 @@ async-trait.workspace = true ethers.workspace = true serde.workspace = true tokio.workspace = true +thiserror.workspace = true mockall = {workspace = true, optional = true } diff --git a/crates/provider/src/ethers/provider.rs b/crates/provider/src/ethers/provider.rs index 2aa118280..8a60fd6e4 100644 --- a/crates/provider/src/ethers/provider.rs +++ b/crates/provider/src/ethers/provider.rs @@ -3,7 +3,10 @@ use std::{fmt::Debug, sync::Arc}; use anyhow::Context; use ethers::{ contract::ContractError, - providers::{JsonRpcClient, Middleware, Provider as EthersProvider, ProviderError}, + prelude::ContractError as EthersContractError, + providers::{ + JsonRpcClient, Middleware, Provider as EthersProvider, ProviderError as EthersProviderError, + }, types::{ transaction::eip2718::TypedTransaction, Address, Block, BlockId, BlockNumber, Bytes, Eip1559TransactionRequest, FeeHistory, Filter, GethDebugTracingCallOptions, @@ -20,7 +23,7 @@ use rundler_types::{ }; use serde::{de::DeserializeOwned, Serialize}; -use crate::{AggregatorOut, AggregatorSimOut, Provider}; +use crate::{AggregatorOut, AggregatorSimOut, Provider, ProviderError, ProviderResult}; const ARBITRUM_NITRO_NODE_INTERFACE_ADDRESS: Address = H160([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc8, @@ -36,20 +39,16 @@ impl Provider for EthersProvider { // `Middleware` because forming a `PendingTransaction` specifically requires // a `Provider`. - async fn request(&self, method: &str, params: T) -> Result + async fn request(&self, method: &str, params: T) -> ProviderResult where T: Debug + Serialize + Send + Sync + 'static, R: Serialize + DeserializeOwned + Debug + Send + 'static, { - EthersProvider::request(self, method, params).await + Ok(EthersProvider::request(self, method, params).await?) } - async fn call( - &self, - tx: &TypedTransaction, - block: Option, - ) -> Result { - Middleware::call(self, tx, block).await + async fn call(&self, tx: &TypedTransaction, block: Option) -> ProviderResult { + Ok(Middleware::call(self, tx, block).await?) } async fn fee_history + Send + Sync + Serialize + 'static>( @@ -57,11 +56,11 @@ impl Provider for EthersProvider { t: T, block_number: BlockNumber, reward_percentiles: &[f64], - ) -> Result { - Middleware::fee_history(self, t, block_number, reward_percentiles).await + ) -> ProviderResult { + Ok(Middleware::fee_history(self, t, block_number, reward_percentiles).await?) } - async fn get_block_number(&self) -> anyhow::Result { + async fn get_block_number(&self) -> ProviderResult { Ok(Middleware::get_block_number(self) .await .context("should get block number from provider")? @@ -71,32 +70,30 @@ impl Provider for EthersProvider { async fn get_block + Send + Sync + 'static>( &self, block_hash_or_number: T, - ) -> anyhow::Result>> { - Middleware::get_block(self, block_hash_or_number) - .await - .context("should get block from provider") + ) -> ProviderResult>> { + Ok(Middleware::get_block(self, block_hash_or_number).await?) } async fn get_transaction>( &self, transaction_hash: T, - ) -> Result, ProviderError> { - Middleware::get_transaction(self, transaction_hash).await + ) -> ProviderResult> { + Ok(Middleware::get_transaction(self, transaction_hash).await?) } async fn get_transaction_receipt + 'static>( &self, transaction_hash: T, - ) -> Result, ProviderError> { - Middleware::get_transaction_receipt(self, transaction_hash).await + ) -> ProviderResult> { + Ok(Middleware::get_transaction_receipt(self, transaction_hash).await?) } async fn debug_trace_transaction( &self, tx_hash: TxHash, trace_options: GethDebugTracingOptions, - ) -> Result { - Middleware::debug_trace_transaction(self, tx_hash, trace_options).await + ) -> ProviderResult { + Ok(Middleware::debug_trace_transaction(self, tx_hash, trace_options).await?) } async fn debug_trace_call( @@ -104,51 +101,47 @@ impl Provider for EthersProvider { tx: TypedTransaction, block_id: Option, trace_options: GethDebugTracingCallOptions, - ) -> Result { - Middleware::debug_trace_call(self, tx, block_id, trace_options).await + ) -> ProviderResult { + Ok(Middleware::debug_trace_call(self, tx, block_id, trace_options).await?) } - async fn get_balance(&self, address: Address, block: Option) -> anyhow::Result { - Middleware::get_balance(self, address, block) - .await - .context("should get balance from provider") + async fn get_balance(&self, address: Address, block: Option) -> ProviderResult { + Ok(Middleware::get_balance(self, address, block).await?) } - async fn get_latest_block_hash(&self) -> anyhow::Result { - Middleware::get_block(self, BlockId::Number(BlockNumber::Latest)) - .await - .context("should load block to get hash")? - .context("block should exist to get latest hash")? - .hash - .context("hash should be present on block") + async fn get_latest_block_hash(&self) -> ProviderResult { + Ok( + Middleware::get_block(self, BlockId::Number(BlockNumber::Latest)) + .await + .context("should load block to get hash")? + .context("block should exist to get latest hash")? + .hash + .context("hash should be present on block")?, + ) } - async fn get_base_fee(&self) -> anyhow::Result { - Middleware::get_block(self, BlockNumber::Pending) + async fn get_base_fee(&self) -> ProviderResult { + Ok(Middleware::get_block(self, BlockNumber::Pending) .await .context("should load pending block to get base fee")? .context("pending block should exist")? .base_fee_per_gas - .context("pending block should have a nonempty base fee") + .context("pending block should have a nonempty base fee")?) } - async fn get_max_priority_fee(&self) -> anyhow::Result { - self.request("eth_maxPriorityFeePerGas", ()) - .await - .context("should get max priority fee from provider") + async fn get_max_priority_fee(&self) -> ProviderResult { + Ok(self.request("eth_maxPriorityFeePerGas", ()).await?) } - async fn get_logs(&self, filter: &Filter) -> anyhow::Result> { - Middleware::get_logs(self, filter) - .await - .context("provider should get logs") + async fn get_logs(&self, filter: &Filter) -> ProviderResult> { + Ok(Middleware::get_logs(self, filter).await?) } async fn aggregate_signatures( self: Arc, aggregator_address: Address, ops: Vec, - ) -> anyhow::Result> { + ) -> ProviderResult> { let aggregator = IAggregator::new(aggregator_address, self); // TODO: Cap the gas here. let result = aggregator.aggregate_signatures(ops).call().await; @@ -164,7 +157,7 @@ impl Provider for EthersProvider { aggregator_address: Address, user_op: UserOperation, gas_cap: u64, - ) -> anyhow::Result { + ) -> ProviderResult { let aggregator = IAggregator::new(aggregator_address, self); let result = aggregator .validate_user_op_signature(user_op) @@ -182,23 +175,19 @@ impl Provider for EthersProvider { } } - async fn get_code(&self, address: Address, block_hash: Option) -> anyhow::Result { - Middleware::get_code(self, address, block_hash.map(|b| b.into())) - .await - .context("provider should get contract code") + async fn get_code(&self, address: Address, block_hash: Option) -> ProviderResult { + Ok(Middleware::get_code(self, address, block_hash.map(|b| b.into())).await?) } - async fn get_transaction_count(&self, address: Address) -> anyhow::Result { - Middleware::get_transaction_count(self, address, None) - .await - .context("provider should get transaction count") + async fn get_transaction_count(&self, address: Address) -> ProviderResult { + Ok(Middleware::get_transaction_count(self, address, None).await?) } async fn calc_arbitrum_l1_gas( self: Arc, entry_point_address: Address, op: UserOperation, - ) -> anyhow::Result { + ) -> ProviderResult { let entry_point = IEntryPoint::new(entry_point_address, Arc::clone(&self)); let data = entry_point .handle_ops(vec![op], Address::random()) @@ -217,7 +206,7 @@ impl Provider for EthersProvider { self: Arc, entry_point_address: Address, op: UserOperation, - ) -> anyhow::Result { + ) -> ProviderResult { let entry_point = IEntryPoint::new(entry_point_address, Arc::clone(&self)); let data = entry_point .handle_ops(vec![op], Address::random()) @@ -252,3 +241,24 @@ impl Provider for EthersProvider { Ok(l1_fee / (l2_base_fee + l2_priority_fee)) } } + +impl From for ProviderError { + fn from(e: EthersProviderError) -> Self { + match e { + EthersProviderError::JsonRpcClientError(e) => { + if let Some(jsonrpc_error) = e.as_error_response() { + ProviderError::JsonRpcError(jsonrpc_error.clone()) + } else { + ProviderError::Other(anyhow::anyhow!(e.to_string())) + } + } + _ => ProviderError::Other(anyhow::anyhow!(e.to_string())), + } + } +} + +impl From> for ProviderError { + fn from(e: EthersContractError) -> Self { + ProviderError::ContractError(e.to_string()) + } +} diff --git a/crates/provider/src/lib.rs b/crates/provider/src/lib.rs index abc0c2454..df436bf53 100644 --- a/crates/provider/src/lib.rs +++ b/crates/provider/src/lib.rs @@ -11,6 +11,9 @@ mod ethers; mod traits; -pub use traits::{AggregatorOut, AggregatorSimOut, EntryPoint, HandleOpsOut, Provider}; +pub use traits::{ + AggregatorOut, AggregatorSimOut, EntryPoint, HandleOpsOut, Provider, ProviderError, + ProviderResult, +}; #[cfg(any(test, feature = "test-utils"))] pub use traits::{MockEntryPoint, MockProvider}; diff --git a/crates/provider/src/traits/error.rs b/crates/provider/src/traits/error.rs new file mode 100644 index 000000000..a95661f14 --- /dev/null +++ b/crates/provider/src/traits/error.rs @@ -0,0 +1,15 @@ +use ethers::providers::JsonRpcError; + +/// Error enumeration for the Provider trait +#[derive(Debug, thiserror::Error)] +pub enum ProviderError { + /// JSON-RPC error + #[error(transparent)] + JsonRpcError(#[from] JsonRpcError), + /// Contract Error + #[error("Contract Error: {0}")] + ContractError(String), + /// Internal errors + #[error(transparent)] + Other(#[from] anyhow::Error), +} diff --git a/crates/provider/src/traits/mod.rs b/crates/provider/src/traits/mod.rs index ac210b529..9b42760b9 100644 --- a/crates/provider/src/traits/mod.rs +++ b/crates/provider/src/traits/mod.rs @@ -1,5 +1,8 @@ //! Traits for the provider module. +mod error; +pub use error::ProviderError; + mod entry_point; #[cfg(feature = "test-utils")] pub use entry_point::MockEntryPoint; @@ -8,4 +11,4 @@ pub use entry_point::{EntryPoint, HandleOpsOut}; mod provider; #[cfg(feature = "test-utils")] pub use provider::MockProvider; -pub use provider::{AggregatorOut, AggregatorSimOut, Provider}; +pub use provider::{AggregatorOut, AggregatorSimOut, Provider, ProviderResult}; diff --git a/crates/provider/src/traits/provider.rs b/crates/provider/src/traits/provider.rs index 574d5ac65..f3177da46 100644 --- a/crates/provider/src/traits/provider.rs +++ b/crates/provider/src/traits/provider.rs @@ -2,19 +2,18 @@ use std::{fmt::Debug, sync::Arc}; -use ethers::{ - providers::ProviderError, - types::{ - transaction::eip2718::TypedTransaction, Address, Block, BlockId, BlockNumber, Bytes, - FeeHistory, Filter, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, Log, - Transaction, TransactionReceipt, TxHash, H256, U256, - }, +use ethers::types::{ + transaction::eip2718::TypedTransaction, Address, Block, BlockId, BlockNumber, Bytes, + FeeHistory, Filter, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, Log, + Transaction, TransactionReceipt, TxHash, H256, U256, }; #[cfg(feature = "test-utils")] use mockall::automock; use rundler_types::UserOperation; use serde::{de::DeserializeOwned, Serialize}; +use super::error::ProviderError; + /// Output of a successful signature aggregator simulation call #[derive(Clone, Debug, Default)] pub struct AggregatorSimOut { @@ -35,12 +34,15 @@ pub enum AggregatorOut { ValidationReverted, } +/// Result of a provider method call +pub type ProviderResult = Result; + /// Trait for interacting with chain data and contracts. #[cfg_attr(feature = "test-utils", automock)] #[async_trait::async_trait] pub trait Provider: Send + Sync + 'static { /// Make an arbitrary JSON RPC request to the provider - async fn request(&self, method: &str, params: T) -> Result + async fn request(&self, method: &str, params: T) -> ProviderResult where T: Debug + Serialize + Send + Sync + 'static, R: Serialize + DeserializeOwned + Debug + Send + 'static; @@ -54,42 +56,38 @@ pub trait Provider: Send + Sync + 'static { ) -> Result; /// Simulate a transaction via an eth_call - async fn call( - &self, - tx: &TypedTransaction, - block: Option, - ) -> Result; + async fn call(&self, tx: &TypedTransaction, block: Option) -> ProviderResult; /// Get the current block number - async fn get_block_number(&self) -> anyhow::Result; + async fn get_block_number(&self) -> ProviderResult; /// Get a block by its hash or number async fn get_block + Send + Sync + 'static>( &self, block_hash_or_number: T, - ) -> anyhow::Result>>; + ) -> ProviderResult>>; /// Get the balance of an address - async fn get_balance(&self, address: Address, block: Option) -> anyhow::Result; + async fn get_balance(&self, address: Address, block: Option) -> ProviderResult; /// Get transaction by hash async fn get_transaction + 'static>( &self, tx: T, - ) -> Result, ProviderError>; + ) -> ProviderResult>; /// Get transaction receipt by hash async fn get_transaction_receipt + 'static>( &self, transaction_hash: T, - ) -> Result, ProviderError>; + ) -> ProviderResult>; /// Debug trace a transaction async fn debug_trace_transaction( &self, tx_hash: TxHash, trace_options: GethDebugTracingOptions, - ) -> Result; + ) -> ProviderResult; /// Debug trace a call async fn debug_trace_call( @@ -97,32 +95,32 @@ pub trait Provider: Send + Sync + 'static { tx: TypedTransaction, block_id: Option, trace_options: GethDebugTracingCallOptions, - ) -> Result; + ) -> ProviderResult; /// Get the latest block hash - async fn get_latest_block_hash(&self) -> anyhow::Result; + async fn get_latest_block_hash(&self) -> ProviderResult; /// Get the base fee per gas of the pending block - async fn get_base_fee(&self) -> anyhow::Result; + async fn get_base_fee(&self) -> ProviderResult; /// Get the max fee per gas as reported by the node's RPC - async fn get_max_priority_fee(&self) -> anyhow::Result; + async fn get_max_priority_fee(&self) -> ProviderResult; /// Get the code at an address - async fn get_code(&self, address: Address, block_hash: Option) -> anyhow::Result; + async fn get_code(&self, address: Address, block_hash: Option) -> ProviderResult; /// Get the nonce/transaction count of an address - async fn get_transaction_count(&self, address: Address) -> anyhow::Result; + async fn get_transaction_count(&self, address: Address) -> ProviderResult; /// Get the logs matching a filter - async fn get_logs(&self, filter: &Filter) -> anyhow::Result>; + async fn get_logs(&self, filter: &Filter) -> ProviderResult>; /// Call an aggregator to aggregate signatures for a set of operations async fn aggregate_signatures( self: Arc, aggregator_address: Address, ops: Vec, - ) -> anyhow::Result>; + ) -> ProviderResult>; /// Validate a user operation signature using an aggregator async fn validate_user_op_signature( @@ -130,19 +128,19 @@ pub trait Provider: Send + Sync + 'static { aggregator_address: Address, user_op: UserOperation, gas_cap: u64, - ) -> anyhow::Result; + ) -> ProviderResult; /// Calculate the L1 portion of the gas for a user operation on Arbitrum async fn calc_arbitrum_l1_gas( self: Arc, entry_point_address: Address, op: UserOperation, - ) -> anyhow::Result; + ) -> ProviderResult; /// Calculate the L1 portion of the gas for a user operation on optimism async fn calc_optimism_l1_gas( self: Arc, entry_point_address: Address, op: UserOperation, - ) -> anyhow::Result; + ) -> ProviderResult; } diff --git a/crates/rpc/src/eth/error.rs b/crates/rpc/src/eth/error.rs index 468c7bc1c..84aaebec4 100644 --- a/crates/rpc/src/eth/error.rs +++ b/crates/rpc/src/eth/error.rs @@ -4,6 +4,7 @@ use jsonrpsee::types::{ ErrorObjectOwned, }; use rundler_pool::{MempoolError, PoolServerError}; +use rundler_provider::ProviderError; use rundler_sim::{PrecheckViolation, SimulationViolation}; use rundler_types::{Entity, EntityType, Timestamp}; use serde::Serialize; @@ -263,10 +264,16 @@ impl From for ErrorObjectOwned { impl From for EthRpcError { fn from(status: tonic::Status) -> Self { - EthRpcError::Internal(anyhow::anyhow!(format!( + EthRpcError::Internal(anyhow::anyhow!( "internal server error code: {} message: {}", status.code(), status.message() - ))) + )) + } +} + +impl From for EthRpcError { + fn from(e: ProviderError) -> Self { + EthRpcError::Internal(anyhow::anyhow!("provider error: {e:?}")) } } diff --git a/crates/sim/Cargo.toml b/crates/sim/Cargo.toml index 47c54ab62..a5835b7d1 100644 --- a/crates/sim/Cargo.toml +++ b/crates/sim/Cargo.toml @@ -15,6 +15,7 @@ anyhow.workspace = true arrayvec = "0.7.2" async-trait.workspace = true ethers.workspace = true +futures-util.workspace = true indexmap = "2.0.0" parse-display.workspace = true thiserror.workspace = true diff --git a/crates/sim/src/estimation/estimation.rs b/crates/sim/src/estimation/estimation.rs index 9c11bf23c..51b32a797 100644 --- a/crates/sim/src/estimation/estimation.rs +++ b/crates/sim/src/estimation/estimation.rs @@ -100,7 +100,10 @@ impl GasEstimator for GasEstimatorImpl { provider, settings, .. } = self; - let block_hash = provider.get_latest_block_hash().await?; + let block_hash = provider + .get_latest_block_hash() + .await + .map_err(anyhow::Error::from)?; // Estimate pre verification gas let pre_verification_gas = self.calc_pre_verification_gas(&op).await?; @@ -263,7 +266,8 @@ impl GasEstimatorImpl { let entry_point_code = self .provider .get_code(self.entry_point.address(), Some(block_hash)) - .await?; + .await + .map_err(anyhow::Error::from)?; // Use a random address for the moved entry point so that users can't // intentionally get bad estimates by interacting with the hardcoded // address. @@ -376,11 +380,11 @@ fn estimation_proxy_bytecode_with_target(target: Address) -> Bytes { mod tests { use ethers::{ abi::{AbiEncode, Address}, - providers::{JsonRpcError, MockError, ProviderError}, + providers::JsonRpcError, types::Chain, utils::hex, }; - use rundler_provider::{MockEntryPoint, MockProvider}; + use rundler_provider::{MockEntryPoint, MockProvider, ProviderError}; use rundler_types::contracts::{get_gas_used::GasUsedResult, i_entry_point::ExecutionResult}; use super::*; @@ -621,10 +625,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -690,10 +691,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -757,10 +755,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -810,10 +805,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -862,10 +854,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -1104,10 +1093,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); let (estimator, _) = create_estimator(entry, provider); @@ -1178,10 +1164,7 @@ mod tests { message: "execution reverted".to_string(), data: Some(serde_json::Value::String(result_data.to_string())), }; - - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); //max_call_gas is less than MIN_CALL_GAS_LIMIT diff --git a/crates/sim/src/gas/gas.rs b/crates/sim/src/gas/gas.rs index df2c88f19..3b4d18d22 100644 --- a/crates/sim/src/gas/gas.rs +++ b/crates/sim/src/gas/gas.rs @@ -267,17 +267,16 @@ impl FeeEstimator

{ } async fn get_base_fee(&self) -> anyhow::Result { - self.provider.get_base_fee().await + Ok(self.provider.get_base_fee().await?) } async fn get_priority_fee(&self) -> anyhow::Result { if POLYGON_CHAIN_IDS.contains(&self.chain_id) { let gas_oracle = Polygon::new(Arc::clone(&self.provider), self.chain_id).category(GasCategory::Fast); - let fees = gas_oracle.estimate_eip1559_fees().await?; - Ok(fees.1) + Ok(gas_oracle.estimate_priority_fee().await?) } else if self.use_bundle_priority_fee { - self.provider.get_max_priority_fee().await + Ok(self.provider.get_max_priority_fee().await?) } else { Ok(U256::zero()) } diff --git a/crates/sim/src/gas/polygon.rs b/crates/sim/src/gas/polygon.rs index 66109be98..51548b7ae 100644 --- a/crates/sim/src/gas/polygon.rs +++ b/crates/sim/src/gas/polygon.rs @@ -1,12 +1,13 @@ -use std::sync::Arc; +use std::{cmp, sync::Arc}; use ethers::{ - prelude::gas_oracle::{GasCategory, Result}, - providers::ProviderError, + prelude::gas_oracle::GasCategory, types::{BlockNumber, Chain, U256}, }; +use futures_util::TryFutureExt; use rundler_provider::Provider; use serde::Deserialize; +use tokio::try_join; const MUMBAI_MAX_PRIORITY_FEE_DEFAULT: u64 = 1_500_000_000; const MAINNET_MAX_PRIORITY_FEE_DEFAULT: u64 = 30_000_000_000; @@ -51,41 +52,32 @@ where } /// Estimates max and priority gas and converts to U256 - pub(crate) async fn estimate_eip1559_fees(&self) -> Result<(U256, U256), ProviderError> { - let estimate = self.calculate_fees().await?; - let max = estimate.max_fee; - let prio = estimate.max_priority_fee; - Ok((max, prio)) + pub(crate) async fn estimate_priority_fee(&self) -> anyhow::Result { + let (provider_estiamte, fee_history_estimate) = try_join!( + self.provider.get_max_priority_fee().map_err(|e| e.into()), + self.calculate_fees() + )?; + + Ok(cmp::max(provider_estiamte, fee_history_estimate)) } /// Perform a request to the gas price API and deserialize the response. - pub(crate) async fn calculate_fees(&self) -> Result { + async fn calculate_fees(&self) -> anyhow::Result { let gas_percentile = self.gas_category_percentile(); let fee_history = self .provider .fee_history(15, BlockNumber::Latest, &[gas_percentile]) .await?; - - let (base_fee_per_gas, _mod) = fee_history - .base_fee_per_gas - .iter() - .fold(U256::from(0), |acc, val| acc.saturating_add(*val)) - .div_mod(U256::from(fee_history.base_fee_per_gas.len())); - - let estimate = - calculate_estimate_from_rewards(&fee_history.reward, base_fee_per_gas, self.chain_id); - - Ok(estimate) + Ok(calculate_estimate_from_rewards( + &fee_history.reward, + self.chain_id, + )) } } /// Calculates the estimate based on the index of inner vector /// and skips the average if block is empty -fn calculate_estimate_from_rewards( - reward: &[Vec], - base_fee_per_gas: U256, - chain_id: u64, -) -> GasEstimate { +fn calculate_estimate_from_rewards(reward: &[Vec], chain_id: u64) -> U256 { let (sum, count): (U256, U256) = reward .iter() .filter(|b| !b[0].is_zero()) @@ -108,8 +100,5 @@ fn calculate_estimate_from_rewards( average = fallback; } - GasEstimate { - max_priority_fee: average, - max_fee: base_fee_per_gas + average, - } + average } diff --git a/crates/sim/src/simulation/simulation.rs b/crates/sim/src/simulation/simulation.rs index c857a6967..df607fcd7 100644 --- a/crates/sim/src/simulation/simulation.rs +++ b/crates/sim/src/simulation/simulation.rs @@ -214,10 +214,11 @@ where return Ok(AggregatorOut::NotNeeded); }; - self.provider + Ok(self + .provider .clone() .validate_user_op_signature(aggregator_address, op, gas_cap) - .await + .await?) } // Parse the output from tracing and return a list of violations. @@ -443,7 +444,11 @@ where ) -> Result { let block_hash = match block_hash { Some(block_hash) => block_hash, - None => self.provider.get_latest_block_hash().await?, + None => self + .provider + .get_latest_block_hash() + .await + .map_err(anyhow::Error::from)?, }; let block_id = block_hash.into(); let mut context = match self.create_context(op.clone(), block_id).await { @@ -760,11 +765,11 @@ mod tests { use ethers::{ abi::AbiEncode, - providers::{JsonRpcError, MockError, ProviderError}, + providers::JsonRpcError, types::{Address, BlockNumber, Bytes}, utils::hex, }; - use rundler_provider::{AggregatorOut, MockProvider}; + use rundler_provider::{AggregatorOut, MockProvider, ProviderError}; use super::*; use crate::simulation::tracer::{MockSimulateValidationTracer, Phase}; @@ -905,9 +910,7 @@ mod tests { .to_string(), )), }; - Err(ProviderError::JsonRpcClientError(Box::new( - MockError::JsonRpcError(json_rpc_error), - ))) + Err(ProviderError::JsonRpcError(json_rpc_error)) }); provider diff --git a/crates/sim/src/utils.rs b/crates/sim/src/utils.rs index c40022d50..a68485813 100644 --- a/crates/sim/src/utils.rs +++ b/crates/sim/src/utils.rs @@ -1,10 +1,9 @@ use anyhow::Context; use ethers::{ abi::{AbiDecode, AbiEncode}, - providers::ProviderError, types::{Address, BlockId, Bytes, Eip1559TransactionRequest, Selector, H256, U256}, }; -use rundler_provider::Provider; +use rundler_provider::{Provider, ProviderError}; use rundler_types::contracts::{ get_code_hashes::{CodeHashesResult, GETCODEHASHES_BYTECODE}, get_gas_used::{GasUsedResult, GETGASUSED_BYTECODE}, @@ -67,11 +66,8 @@ async fn call_constructor( } // Gets and decodes the revert data from a provider error, if it is a revert error. -fn get_revert_data(mut error: ProviderError) -> Result { - let ProviderError::JsonRpcClientError(dyn_error) = &mut error else { - return Err(error); - }; - let Some(jsonrpc_error) = dyn_error.as_error_response() else { +fn get_revert_data(error: ProviderError) -> Result { + let ProviderError::JsonRpcError(jsonrpc_error) = &error else { return Err(error); }; if !jsonrpc_error.is_revert() {