Skip to content

Commit

Permalink
refactor(provider): crate provider error enum
Browse files Browse the repository at this point in the history
  • Loading branch information
dancoombs committed Sep 24, 2023
1 parent c385f93 commit 637805a
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 176 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions crates/builder/src/bundle_proposer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,7 +106,9 @@ where
async fn make_bundle(&self, required_fees: Option<GasFees>) -> anyhow::Result<Bundle> {
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)
)?;

Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
128 changes: 69 additions & 59 deletions crates/provider/src/ethers/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -36,32 +39,28 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
// `Middleware` because forming a `PendingTransaction` specifically requires
// a `Provider`.

async fn request<T, R>(&self, method: &str, params: T) -> Result<R, ProviderError>
async fn request<T, R>(&self, method: &str, params: T) -> ProviderResult<R>
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<BlockId>,
) -> Result<Bytes, ProviderError> {
Middleware::call(self, tx, block).await
async fn call(&self, tx: &TypedTransaction, block: Option<BlockId>) -> ProviderResult<Bytes> {
Ok(Middleware::call(self, tx, block).await?)
}

async fn fee_history<T: Into<U256> + Send + Sync + Serialize + 'static>(
&self,
t: T,
block_number: BlockNumber,
reward_percentiles: &[f64],
) -> Result<FeeHistory, ProviderError> {
Middleware::fee_history(self, t, block_number, reward_percentiles).await
) -> ProviderResult<FeeHistory> {
Ok(Middleware::fee_history(self, t, block_number, reward_percentiles).await?)
}

async fn get_block_number(&self) -> anyhow::Result<u64> {
async fn get_block_number(&self) -> ProviderResult<u64> {
Ok(Middleware::get_block_number(self)
.await
.context("should get block number from provider")?
Expand All @@ -71,84 +70,78 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
async fn get_block<T: Into<BlockId> + Send + Sync + 'static>(
&self,
block_hash_or_number: T,
) -> anyhow::Result<Option<Block<H256>>> {
Middleware::get_block(self, block_hash_or_number)
.await
.context("should get block from provider")
) -> ProviderResult<Option<Block<H256>>> {
Ok(Middleware::get_block(self, block_hash_or_number).await?)
}

async fn get_transaction<T: Send + Sync + Into<TxHash>>(
&self,
transaction_hash: T,
) -> Result<Option<Transaction>, ProviderError> {
Middleware::get_transaction(self, transaction_hash).await
) -> ProviderResult<Option<Transaction>> {
Ok(Middleware::get_transaction(self, transaction_hash).await?)
}

async fn get_transaction_receipt<T: Send + Sync + Into<TxHash> + 'static>(
&self,
transaction_hash: T,
) -> Result<Option<TransactionReceipt>, ProviderError> {
Middleware::get_transaction_receipt(self, transaction_hash).await
) -> ProviderResult<Option<TransactionReceipt>> {
Ok(Middleware::get_transaction_receipt(self, transaction_hash).await?)
}

async fn debug_trace_transaction(
&self,
tx_hash: TxHash,
trace_options: GethDebugTracingOptions,
) -> Result<GethTrace, ProviderError> {
Middleware::debug_trace_transaction(self, tx_hash, trace_options).await
) -> ProviderResult<GethTrace> {
Ok(Middleware::debug_trace_transaction(self, tx_hash, trace_options).await?)
}

async fn debug_trace_call(
&self,
tx: TypedTransaction,
block_id: Option<BlockId>,
trace_options: GethDebugTracingCallOptions,
) -> Result<GethTrace, ProviderError> {
Middleware::debug_trace_call(self, tx, block_id, trace_options).await
) -> ProviderResult<GethTrace> {
Ok(Middleware::debug_trace_call(self, tx, block_id, trace_options).await?)
}

async fn get_balance(&self, address: Address, block: Option<BlockId>) -> anyhow::Result<U256> {
Middleware::get_balance(self, address, block)
.await
.context("should get balance from provider")
async fn get_balance(&self, address: Address, block: Option<BlockId>) -> ProviderResult<U256> {
Ok(Middleware::get_balance(self, address, block).await?)
}

async fn get_latest_block_hash(&self) -> anyhow::Result<H256> {
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<H256> {
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<U256> {
Middleware::get_block(self, BlockNumber::Pending)
async fn get_base_fee(&self) -> ProviderResult<U256> {
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<U256> {
self.request("eth_maxPriorityFeePerGas", ())
.await
.context("should get max priority fee from provider")
async fn get_max_priority_fee(&self) -> ProviderResult<U256> {
Ok(self.request("eth_maxPriorityFeePerGas", ()).await?)
}

async fn get_logs(&self, filter: &Filter) -> anyhow::Result<Vec<Log>> {
Middleware::get_logs(self, filter)
.await
.context("provider should get logs")
async fn get_logs(&self, filter: &Filter) -> ProviderResult<Vec<Log>> {
Ok(Middleware::get_logs(self, filter).await?)
}

async fn aggregate_signatures(
self: Arc<Self>,
aggregator_address: Address,
ops: Vec<UserOperation>,
) -> anyhow::Result<Option<Bytes>> {
) -> ProviderResult<Option<Bytes>> {
let aggregator = IAggregator::new(aggregator_address, self);
// TODO: Cap the gas here.
let result = aggregator.aggregate_signatures(ops).call().await;
Expand All @@ -164,7 +157,7 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
aggregator_address: Address,
user_op: UserOperation,
gas_cap: u64,
) -> anyhow::Result<AggregatorOut> {
) -> ProviderResult<AggregatorOut> {
let aggregator = IAggregator::new(aggregator_address, self);
let result = aggregator
.validate_user_op_signature(user_op)
Expand All @@ -182,23 +175,19 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
}
}

async fn get_code(&self, address: Address, block_hash: Option<H256>) -> anyhow::Result<Bytes> {
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<H256>) -> ProviderResult<Bytes> {
Ok(Middleware::get_code(self, address, block_hash.map(|b| b.into())).await?)
}

async fn get_transaction_count(&self, address: Address) -> anyhow::Result<U256> {
Middleware::get_transaction_count(self, address, None)
.await
.context("provider should get transaction count")
async fn get_transaction_count(&self, address: Address) -> ProviderResult<U256> {
Ok(Middleware::get_transaction_count(self, address, None).await?)
}

async fn calc_arbitrum_l1_gas(
self: Arc<Self>,
entry_point_address: Address,
op: UserOperation,
) -> anyhow::Result<U256> {
) -> ProviderResult<U256> {
let entry_point = IEntryPoint::new(entry_point_address, Arc::clone(&self));
let data = entry_point
.handle_ops(vec![op], Address::random())
Expand All @@ -217,7 +206,7 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
self: Arc<Self>,
entry_point_address: Address,
op: UserOperation,
) -> anyhow::Result<U256> {
) -> ProviderResult<U256> {
let entry_point = IEntryPoint::new(entry_point_address, Arc::clone(&self));
let data = entry_point
.handle_ops(vec![op], Address::random())
Expand Down Expand Up @@ -252,3 +241,24 @@ impl<C: JsonRpcClient + 'static> Provider for EthersProvider<C> {
Ok(l1_fee / (l2_base_fee + l2_priority_fee))
}
}

impl From<EthersProviderError> 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<M: Middleware> From<EthersContractError<M>> for ProviderError {
fn from(e: EthersContractError<M>) -> Self {
ProviderError::ContractError(e.to_string())
}
}
5 changes: 4 additions & 1 deletion crates/provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
15 changes: 15 additions & 0 deletions crates/provider/src/traits/error.rs
Original file line number Diff line number Diff line change
@@ -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),
}
5 changes: 4 additions & 1 deletion crates/provider/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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};
Loading

0 comments on commit 637805a

Please sign in to comment.