From 0be2c17a9f183fa5923917f32d1f4ba56e1d55f2 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 25 Jul 2024 19:30:30 +0200 Subject: [PATCH] chore(rpc): `EthApiTypes` trait for network specific error AT (#9523) Co-authored-by: Matthias Seitz --- Cargo.lock | 2 + bin/reth/Cargo.toml | 1 - crates/e2e-test-utils/src/rpc.rs | 11 +- crates/node/core/Cargo.toml | 1 - crates/optimism/node/Cargo.toml | 1 - crates/optimism/rpc/Cargo.toml | 2 +- crates/optimism/rpc/src/error.rs | 70 +++++++- crates/optimism/rpc/src/eth/block.rs | 19 ++- crates/optimism/rpc/src/eth/call.rs | 20 ++- crates/optimism/rpc/src/eth/mod.rs | 17 +- crates/optimism/rpc/src/eth/receipt.rs | 17 +- crates/optimism/rpc/src/eth/transaction.rs | 6 +- crates/rpc/rpc-eth-api/Cargo.toml | 2 +- crates/rpc/rpc-eth-api/src/core.rs | 3 +- crates/rpc/rpc-eth-api/src/helpers/block.rs | 91 +++++++---- .../rpc-eth-api/src/helpers/blocking_task.rs | 14 +- crates/rpc/rpc-eth-api/src/helpers/call.rs | 131 ++++++++------- crates/rpc/rpc-eth-api/src/helpers/error.rs | 88 +++++++++++ crates/rpc/rpc-eth-api/src/helpers/fee.rs | 45 +++--- crates/rpc/rpc-eth-api/src/helpers/mod.rs | 17 +- .../rpc-eth-api/src/helpers/pending_block.rs | 57 ++++--- crates/rpc/rpc-eth-api/src/helpers/receipt.rs | 18 ++- crates/rpc/rpc-eth-api/src/helpers/state.rs | 83 ++++++---- crates/rpc/rpc-eth-api/src/helpers/trace.rs | 64 +++++--- .../rpc-eth-api/src/helpers/transaction.rs | 126 ++++++++++----- crates/rpc/rpc-eth-api/src/helpers/types.rs | 17 ++ crates/rpc/rpc-eth-api/src/lib.rs | 4 + crates/rpc/rpc-eth-types/Cargo.toml | 11 -- crates/rpc/rpc-eth-types/src/error.rs | 56 +++---- crates/rpc/rpc/Cargo.toml | 1 - crates/rpc/rpc/src/debug.rs | 130 +++++++++------ crates/rpc/rpc/src/eth/bundle.rs | 38 +++-- crates/rpc/rpc/src/eth/core.rs | 14 +- crates/rpc/rpc/src/eth/helpers/receipt.rs | 4 +- crates/rpc/rpc/src/eth/helpers/state.rs | 6 +- crates/rpc/rpc/src/eth/helpers/transaction.rs | 6 +- crates/rpc/rpc/src/otterscan.rs | 12 +- crates/rpc/rpc/src/trace.rs | 149 ++++++++++-------- crates/stages/stages/src/stages/utils.rs | 2 +- 39 files changed, 878 insertions(+), 478 deletions(-) create mode 100644 crates/rpc/rpc-eth-api/src/helpers/error.rs create mode 100644 crates/rpc/rpc-eth-api/src/helpers/types.rs diff --git a/Cargo.lock b/Cargo.lock index f265e0428..1ba16db4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7973,6 +7973,7 @@ version = "1.0.3" dependencies = [ "alloy-primitives", "jsonrpsee", + "jsonrpsee-types", "parking_lot 0.12.3", "reth-chainspec", "reth-errors", @@ -8393,6 +8394,7 @@ dependencies = [ "dyn-clone", "futures", "jsonrpsee", + "jsonrpsee-types", "parking_lot 0.12.3", "reth-chainspec", "reth-errors", diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 3b7862bfb..808390967 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -144,7 +144,6 @@ optimism = [ "reth-blockchain-tree/optimism", "dep:reth-node-optimism", "reth-node-core/optimism", - "reth-rpc-eth-types/optimism", ] # no-op feature flag for switching between the `optimism` and default functionality in CI matrices diff --git a/crates/e2e-test-utils/src/rpc.rs b/crates/e2e-test-utils/src/rpc.rs index 8e499bcca..77f4b27e2 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -2,12 +2,9 @@ use alloy_consensus::TxEnvelope; use alloy_network::eip2718::Decodable2718; use reth::{ builder::{rpc::RpcRegistry, FullNodeComponents}, - rpc::{ - api::{ - eth::helpers::{EthApiSpec, EthTransactions, TraceExt}, - DebugApiServer, - }, - server_types::eth::EthResult, + rpc::api::{ + eth::helpers::{EthApiSpec, EthTransactions, TraceExt}, + DebugApiServer, }, }; use reth_primitives::{Bytes, B256}; @@ -21,7 +18,7 @@ where EthApi: EthApiSpec + EthTransactions + TraceExt, { /// Injects a raw transaction into the node tx pool via RPC server - pub async fn inject_tx(&mut self, raw_tx: Bytes) -> EthResult { + pub async fn inject_tx(&mut self, raw_tx: Bytes) -> Result { let eth_api = self.inner.eth_api(); eth_api.send_raw_transaction(raw_tx).await } diff --git a/crates/node/core/Cargo.toml b/crates/node/core/Cargo.toml index ecc710115..b4317c6b1 100644 --- a/crates/node/core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -84,7 +84,6 @@ optimism = [ "reth-provider/optimism", "reth-rpc-types-compat/optimism", "reth-rpc-eth-api/optimism", - "reth-rpc-eth-types/optimism", ] diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index ddbc49166..0b163a571 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -80,7 +80,6 @@ optimism = [ "reth-beacon-consensus/optimism", "reth-revm/optimism", "reth-auto-seal-consensus/optimism", - "reth-rpc-eth-types/optimism", "reth-optimism-rpc/optimism" ] test-utils = ["reth-node-builder/test-utils"] diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 26d1ab577..1f0b15b6e 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -38,6 +38,7 @@ tokio.workspace = true # rpc jsonrpsee.workspace = true +jsonrpsee-types.workspace = true # misc thiserror.workspace = true @@ -59,6 +60,5 @@ optimism = [ "reth-primitives/optimism", "reth-provider/optimism", "reth-rpc-eth-api/optimism", - "reth-rpc-eth-types/optimism", "revm/optimism" ] \ No newline at end of file diff --git a/crates/optimism/rpc/src/error.rs b/crates/optimism/rpc/src/error.rs index 7b7d3bed9..29a348ab7 100644 --- a/crates/optimism/rpc/src/error.rs +++ b/crates/optimism/rpc/src/error.rs @@ -1,31 +1,85 @@ //! RPC errors specific to OP. -use jsonrpsee::types::ErrorObject; +use reth_primitives::revm_primitives::{InvalidTransaction, OptimismInvalidTransaction}; +use reth_rpc_eth_api::AsEthApiError; use reth_rpc_eth_types::EthApiError; -use reth_rpc_server_types::result::internal_rpc_err; -use reth_rpc_types::ToRpcError; +use reth_rpc_server_types::result::{internal_rpc_err, rpc_err}; +use reth_rpc_types::error::EthRpcErrorCode; /// Optimism specific errors, that extend [`EthApiError`]. #[derive(Debug, thiserror::Error)] pub enum OpEthApiError { + /// L1 ethereum error. + #[error(transparent)] + Eth(#[from] EthApiError), /// Thrown when calculating L1 gas fee. #[error("failed to calculate l1 gas fee")] L1BlockFeeError, /// Thrown when calculating L1 gas used #[error("failed to calculate l1 gas used")] L1BlockGasError, + /// Wrapper for [`revm_primitives::InvalidTransaction`](InvalidTransaction). + #[error(transparent)] + InvalidTransaction(OptimismInvalidTransactionError), } -impl ToRpcError for OpEthApiError { - fn to_rpc_error(&self) -> ErrorObject<'static> { +impl AsEthApiError for OpEthApiError { + fn as_err(&self) -> Option<&EthApiError> { match self { - Self::L1BlockFeeError | Self::L1BlockGasError => internal_rpc_err(self.to_string()), + Self::Eth(err) => Some(err), + _ => None, } } } -impl From for EthApiError { +impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(err: OpEthApiError) -> Self { - Self::other(err) + match err { + OpEthApiError::Eth(err) => err.into(), + OpEthApiError::L1BlockFeeError | OpEthApiError::L1BlockGasError => { + internal_rpc_err(err.to_string()) + } + OpEthApiError::InvalidTransaction(err) => err.into(), + } + } +} + +/// Optimism specific invalid transaction errors +#[derive(thiserror::Error, Debug)] +pub enum OptimismInvalidTransactionError { + /// A deposit transaction was submitted as a system transaction post-regolith. + #[error("no system transactions allowed after regolith")] + DepositSystemTxPostRegolith, + /// A deposit transaction halted post-regolith + #[error("deposit transaction halted after regolith")] + HaltedDepositPostRegolith, +} + +impl From for jsonrpsee_types::error::ErrorObject<'static> { + fn from(err: OptimismInvalidTransactionError) -> Self { + match err { + OptimismInvalidTransactionError::DepositSystemTxPostRegolith | + OptimismInvalidTransactionError::HaltedDepositPostRegolith => { + rpc_err(EthRpcErrorCode::TransactionRejected.code(), err.to_string(), None) + } + } + } +} + +impl TryFrom for OptimismInvalidTransactionError { + type Error = InvalidTransaction; + + fn try_from(err: InvalidTransaction) -> Result { + match err { + InvalidTransaction::OptimismError(err) => match err { + OptimismInvalidTransaction::DepositSystemTxPostRegolith => { + Ok(Self::DepositSystemTxPostRegolith) + } + OptimismInvalidTransaction::HaltedDepositPostRegolith => { + Ok(Self::HaltedDepositPostRegolith) + } + }, + _ => Err(err), + } } } diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index c48d70907..c1bdc6098 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -2,8 +2,11 @@ use reth_primitives::TransactionMeta; use reth_provider::{BlockReaderIdExt, HeaderProvider}; -use reth_rpc_eth_api::helpers::{EthApiSpec, EthBlocks, LoadBlock, LoadReceipt, LoadTransaction}; -use reth_rpc_eth_types::{EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_eth_api::{ + helpers::{EthApiSpec, EthBlocks, LoadBlock, LoadReceipt, LoadTransaction}, + FromEthApiError, +}; +use reth_rpc_eth_types::{EthStateCache, ReceiptBuilder}; use reth_rpc_types::{AnyTransactionReceipt, BlockId}; use crate::{op_receipt_fields, OpEthApi}; @@ -19,7 +22,7 @@ where async fn block_receipts( &self, block_id: BlockId, - ) -> EthResult>> + ) -> Result>, Self::Error> where Self: LoadReceipt, { @@ -52,11 +55,13 @@ where let optimism_tx_meta = self.build_op_tx_meta(tx, l1_block_info.clone(), timestamp)?; - ReceiptBuilder::new(tx, meta, receipt, &receipts).map(|builder| { - op_receipt_fields(builder, tx, receipt, optimism_tx_meta).build() - }) + ReceiptBuilder::new(tx, meta, receipt, &receipts) + .map(|builder| { + op_receipt_fields(builder, tx, receipt, optimism_tx_meta).build() + }) + .map_err(Self::Error::from_eth_err) }) - .collect::>>(); + .collect::, Self::Error>>(); return receipts.map(Some) } diff --git a/crates/optimism/rpc/src/eth/call.rs b/crates/optimism/rpc/src/eth/call.rs index 03aa9a1f4..d3bea8dec 100644 --- a/crates/optimism/rpc/src/eth/call.rs +++ b/crates/optimism/rpc/src/eth/call.rs @@ -3,13 +3,22 @@ use reth_primitives::{ revm_primitives::{BlockEnv, OptimismFields, TxEnv}, Bytes, }; -use reth_rpc_eth_api::helpers::Call; -use reth_rpc_eth_types::EthResult; +use reth_rpc_eth_api::{ + helpers::{Call, EthCall}, + EthApiTypes, FromEthApiError, +}; +use reth_rpc_eth_types::EthApiError; use reth_rpc_types::TransactionRequest; use crate::OpEthApi; -impl Call for OpEthApi { +impl EthCall for OpEthApi where EthApiError: From {} + +impl Call for OpEthApi +where + Eth: Call + EthApiTypes, + EthApiError: From, +{ fn call_gas_limit(&self) -> u64 { self.inner.call_gas_limit() } @@ -22,8 +31,9 @@ impl Call for OpEthApi { &self, block_env: &BlockEnv, request: TransactionRequest, - ) -> EthResult { - let mut env = Eth::create_txn_env(&self.inner, block_env, request)?; + ) -> Result { + let mut env = + self.inner.create_txn_env(block_env, request).map_err(Self::Error::from_eth_err)?; env.optimism = OptimismFields { enveloped_tx: Some(Bytes::new()), ..Default::default() }; diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 1178ac1a7..1f2b27c86 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -18,10 +18,10 @@ use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StatePr use reth_rpc::eth::DevSigner; use reth_rpc_eth_api::{ helpers::{ - AddDevSigners, EthApiSpec, EthCall, EthFees, EthSigner, EthState, LoadFee, LoadState, - SpawnBlocking, Trace, UpdateRawTxForwarder, + AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadFee, LoadState, SpawnBlocking, + Trace, UpdateRawTxForwarder, }, - RawTransactionForwarder, + EthApiTypes, RawTransactionForwarder, }; use reth_rpc_eth_types::EthStateCache; use reth_rpc_types::SyncStatus; @@ -29,6 +29,8 @@ use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; use reth_transaction_pool::TransactionPool; use tokio::sync::{AcquireError, OwnedSemaphorePermit}; +use crate::OpEthApiError; + /// OP-Reth `Eth` API implementation. /// /// This type provides the functionality for handling `eth_` related requests. @@ -51,6 +53,13 @@ impl OpEthApi { } } +impl EthApiTypes for OpEthApi +where + Eth: Send + Sync, +{ + type Error = OpEthApiError; +} + impl EthApiSpec for OpEthApi { fn protocol_version(&self) -> impl Future> + Send { self.inner.protocol_version() @@ -142,8 +151,6 @@ impl EthState for OpEthApi { } } -impl EthCall for OpEthApi {} - impl EthFees for OpEthApi {} impl Trace for OpEthApi { diff --git a/crates/optimism/rpc/src/eth/receipt.rs b/crates/optimism/rpc/src/eth/receipt.rs index f11771d61..bef18a716 100644 --- a/crates/optimism/rpc/src/eth/receipt.rs +++ b/crates/optimism/rpc/src/eth/receipt.rs @@ -1,8 +1,11 @@ //! Loads and formats OP receipt RPC response. use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; -use reth_rpc_eth_api::helpers::{EthApiSpec, LoadReceipt, LoadTransaction}; -use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_eth_api::{ + helpers::{EthApiSpec, LoadReceipt, LoadTransaction}, + FromEthApiError, +}; +use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; use reth_rpc_types::{AnyTransactionReceipt, OptimismTransactionReceiptFields}; use crate::{OpEthApi, OptimismTxMeta}; @@ -21,17 +24,19 @@ where tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> EthResult { + ) -> Result { let (block, receipts) = LoadReceipt::cache(self) .get_block_and_receipts(meta.block_hash) - .await? - .ok_or(EthApiError::UnknownBlockNumber)?; + .await + .map_err(Self::Error::from_eth_err)? + .ok_or(Self::Error::from_eth_err(EthApiError::UnknownBlockNumber))?; let block = block.unseal(); let l1_block_info = reth_evm_optimism::extract_l1_info(&block).ok(); let optimism_tx_meta = self.build_op_tx_meta(&tx, l1_block_info, block.timestamp)?; - let resp_builder = ReceiptBuilder::new(&tx, meta, &receipt, &receipts)?; + let resp_builder = ReceiptBuilder::new(&tx, meta, &receipt, &receipts) + .map_err(Self::Error::from_eth_err)?; let resp_builder = op_receipt_fields(resp_builder, &tx, &receipt, optimism_tx_meta); Ok(resp_builder.build()) diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index 326c3c73d..6689e230f 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -7,9 +7,9 @@ use reth_primitives::TransactionSigned; use reth_provider::{BlockReaderIdExt, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthApiSpec, EthSigner, EthTransactions, LoadTransaction}, - RawTransactionForwarder, + EthApiTypes, RawTransactionForwarder, }; -use reth_rpc_eth_types::{EthResult, EthStateCache}; +use reth_rpc_eth_types::EthStateCache; use revm::L1BlockInfo; use crate::{OpEthApi, OpEthApiError}; @@ -79,7 +79,7 @@ where tx: &TransactionSigned, l1_block_info: Option, block_timestamp: u64, - ) -> EthResult { + ) -> Result::Error> { let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) }; let (l1_fee, l1_data_gas) = if !tx.is_deposit() { diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml index b1295d69e..20e73908b 100644 --- a/crates/rpc/rpc-eth-api/Cargo.toml +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -35,6 +35,7 @@ alloy-dyn-abi = { workspace = true, features = ["eip712"] } # rpc jsonrpsee = { workspace = true, features = ["server", "macros"] } +jsonrpsee-types.workspace = true # async async-trait.workspace = true @@ -53,5 +54,4 @@ optimism = [ "reth-primitives/optimism", "revm/optimism", "reth-provider/optimism", - "reth-rpc-eth-types/optimism" ] diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index a0c40490a..a86b5c956 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -334,7 +334,8 @@ pub trait EthApi { #[async_trait::async_trait] impl EthApiServer for T where - Self: FullEthApi, + T: FullEthApi, + jsonrpsee_types::error::ErrorObject<'static>: From, { /// Handler for: `eth_protocolVersion` async fn protocol_version(&self) -> RpcResult { diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs index 78f1ef9da..837006a97 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -5,10 +5,12 @@ use std::sync::Arc; use futures::Future; use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta}; use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider}; -use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock}; use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; +use crate::FromEthApiError; + use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking}; /// Block related functions for the [`EthApiServer`](crate::EthApiServer) trait in the @@ -23,7 +25,7 @@ pub trait EthBlocks: LoadBlock { fn rpc_block_header( &self, block_id: BlockId, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadPendingBlock + SpawnBlocking, { @@ -38,7 +40,7 @@ pub trait EthBlocks: LoadBlock { &self, block_id: BlockId, full: bool, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadPendingBlock + SpawnBlocking, { @@ -49,10 +51,11 @@ pub trait EthBlocks: LoadBlock { }; let block_hash = block.hash(); let total_difficulty = EthBlocks::provider(self) - .header_td_by_number(block.number)? + .header_td_by_number(block.number) + .map_err(Self::Error::from_eth_err)? .ok_or(EthApiError::UnknownBlockNumber)?; - let block = - from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))?; + let block = from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash)) + .map_err(Self::Error::from_eth_err)?; Ok(Some(block.into())) } } @@ -63,19 +66,30 @@ pub trait EthBlocks: LoadBlock { fn block_transaction_count( &self, block_id: BlockId, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { if block_id.is_pending() { // Pending block can be fetched directly without need for caching - return Ok(LoadBlock::provider(self).pending_block()?.map(|block| block.body.len())) + return Ok(LoadBlock::provider(self) + .pending_block() + .map_err(Self::Error::from_eth_err)? + .map(|block| block.body.len())) } - let block_hash = match LoadBlock::provider(self).block_hash_for_id(block_id)? { + let block_hash = match LoadBlock::provider(self) + .block_hash_for_id(block_id) + .map_err(Self::Error::from_eth_err)? + { Some(block_hash) => block_hash, None => return Ok(None), }; - Ok(self.cache().get_block_transactions(block_hash).await?.map(|txs| txs.len())) + Ok(self + .cache() + .get_block_transactions(block_hash) + .await + .map_err(Self::Error::from_eth_err)? + .map(|txs| txs.len())) } } @@ -85,7 +99,7 @@ pub trait EthBlocks: LoadBlock { fn block_receipts( &self, block_id: BlockId, - ) -> impl Future>>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadReceipt, { @@ -116,8 +130,9 @@ pub trait EthBlocks: LoadBlock { ReceiptBuilder::new(&tx, meta, receipt, &receipts) .map(|builder| builder.build()) + .map_err(Self::Error::from_eth_err) }) - .collect::>>(); + .collect::, Self::Error>>(); return receipts.map(Some) } @@ -129,19 +144,26 @@ pub trait EthBlocks: LoadBlock { fn load_block_and_receipts( &self, block_id: BlockId, - ) -> impl Future>)>>> + Send + ) -> impl Future>)>, Self::Error>> + Send where Self: LoadReceipt, { async move { if block_id.is_pending() { return Ok(LoadBlock::provider(self) - .pending_block_and_receipts()? + .pending_block_and_receipts() + .map_err(Self::Error::from_eth_err)? .map(|(sb, receipts)| (sb, Arc::new(receipts)))) } - if let Some(block_hash) = LoadBlock::provider(self).block_hash_for_id(block_id)? { - return Ok(LoadReceipt::cache(self).get_block_and_receipts(block_hash).await?) + if let Some(block_hash) = LoadBlock::provider(self) + .block_hash_for_id(block_id) + .map_err(Self::Error::from_eth_err)? + { + return LoadReceipt::cache(self) + .get_block_and_receipts(block_hash) + .await + .map_err(Self::Error::from_eth_err) } Ok(None) @@ -151,8 +173,11 @@ pub trait EthBlocks: LoadBlock { /// Returns uncle headers of given block. /// /// Returns an empty vec if there are none. - fn ommers(&self, block_id: BlockId) -> EthResult>> { - Ok(LoadBlock::provider(self).ommers_by_id(block_id)?) + fn ommers( + &self, + block_id: BlockId, + ) -> Result>, Self::Error> { + LoadBlock::provider(self).ommers_by_id(block_id).map_err(Self::Error::from_eth_err) } /// Returns uncle block at given index in given block. @@ -162,13 +187,18 @@ pub trait EthBlocks: LoadBlock { &self, block_id: BlockId, index: Index, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { let uncles = if block_id.is_pending() { // Pending block can be fetched directly without need for caching - LoadBlock::provider(self).pending_block()?.map(|block| block.ommers) + LoadBlock::provider(self) + .pending_block() + .map_err(Self::Error::from_eth_err)? + .map(|block| block.ommers) } else { - LoadBlock::provider(self).ommers_by_id(block_id)? + LoadBlock::provider(self) + .ommers_by_id(block_id) + .map_err(Self::Error::from_eth_err)? } .unwrap_or_default(); @@ -198,7 +228,7 @@ pub trait LoadBlock: LoadPendingBlock + SpawnBlocking { fn block( &self, block_id: BlockId, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { self.block_with_senders(block_id) .await @@ -210,12 +240,13 @@ pub trait LoadBlock: LoadPendingBlock + SpawnBlocking { fn block_with_senders( &self, block_id: BlockId, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { if block_id.is_pending() { // Pending block can be fetched directly without need for caching - let maybe_pending = - LoadPendingBlock::provider(self).pending_block_with_senders()?; + let maybe_pending = LoadPendingBlock::provider(self) + .pending_block_with_senders() + .map_err(Self::Error::from_eth_err)?; return if maybe_pending.is_some() { Ok(maybe_pending) } else { @@ -223,12 +254,18 @@ pub trait LoadBlock: LoadPendingBlock + SpawnBlocking { } } - let block_hash = match LoadPendingBlock::provider(self).block_hash_for_id(block_id)? { + let block_hash = match LoadPendingBlock::provider(self) + .block_hash_for_id(block_id) + .map_err(Self::Error::from_eth_err)? + { Some(block_hash) => block_hash, None => return Ok(None), }; - Ok(self.cache().get_sealed_block_with_senders(block_hash).await?) + self.cache() + .get_sealed_block_with_senders(block_hash) + .await + .map_err(Self::Error::from_eth_err) } } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs index 4a2c81b0f..d23453b5e 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs @@ -2,12 +2,14 @@ //! are executed on the `tokio` runtime. use futures::Future; -use reth_rpc_eth_types::{EthApiError, EthResult}; +use reth_rpc_eth_types::EthApiError; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; use tokio::sync::{oneshot, AcquireError, OwnedSemaphorePermit}; +use crate::EthApiTypes; + /// Executes code on a blocking thread. -pub trait SpawnBlocking: Clone + Send + Sync + 'static { +pub trait SpawnBlocking: EthApiTypes + Clone + Send + Sync + 'static { /// Returns a handle for spawning IO heavy blocking tasks. /// /// Runtime access in default trait method implementations. @@ -33,9 +35,9 @@ pub trait SpawnBlocking: Clone + Send + Sync + 'static { /// /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). - fn spawn_blocking_io(&self, f: F) -> impl Future> + Send + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send where - F: FnOnce(Self) -> EthResult + Send + 'static, + F: FnOnce(Self) -> Result + Send + 'static, R: Send + 'static, { let (tx, rx) = oneshot::channel(); @@ -53,9 +55,9 @@ pub trait SpawnBlocking: Clone + Send + Sync + 'static { /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` /// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See /// . - fn spawn_tracing(&self, f: F) -> impl Future> + Send + fn spawn_tracing(&self, f: F) -> impl Future> + Send where - F: FnOnce(Self) -> EthResult + Send + 'static, + F: FnOnce(Self) -> Result + Send + 'static, R: Send + 'static, { let this = self.clone(); diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index 66d053e40..aaf75a827 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -19,7 +19,7 @@ use reth_rpc_eth_types::{ apply_block_overrides, apply_state_overrides, caller_gas_allowance, cap_tx_gas_limit_with_caller_allowance, get_precompiles, CallFees, }, - EthApiError, EthResult, RevertError, RpcInvalidTransactionError, StateCacheDb, + EthApiError, RevertError, RpcInvalidTransactionError, StateCacheDb, }; use reth_rpc_server_types::constants::gas_oracle::{ CALL_STIPEND_GAS, ESTIMATE_GAS_ERROR_RATIO, MIN_TRANSACTION_GAS, @@ -33,6 +33,8 @@ use revm::{Database, DatabaseCommit}; use revm_inspectors::access_list::AccessListInspector; use tracing::trace; +use crate::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError}; + use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace}; /// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in @@ -44,7 +46,7 @@ pub trait EthCall: Call + LoadPendingBlock { request: TransactionRequest, at: BlockId, state_override: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { Call::estimate_gas_at(self, request, at, state_override) } @@ -54,12 +56,12 @@ pub trait EthCall: Call + LoadPendingBlock { request: TransactionRequest, block_number: Option, overrides: EvmOverrides, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { let (res, _env) = self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?; - ensure_success(res.result) + ensure_success(res.result).map_err(Self::Error::from_eth_err) } } @@ -70,14 +72,16 @@ pub trait EthCall: Call + LoadPendingBlock { bundle: Bundle, state_context: Option, mut state_override: Option, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadBlock, { async move { let Bundle { transactions, block_override } = bundle; if transactions.is_empty() { - return Err(EthApiError::InvalidParams(String::from("transactions are empty."))) + return Err( + EthApiError::InvalidParams(String::from("transactions are empty.")).into() + ) } let StateContext { transaction_index, block_number } = @@ -92,7 +96,7 @@ pub trait EthCall: Call + LoadPendingBlock { self.block_with_senders(target_block) )?; - let Some(block) = block else { return Err(EthApiError::UnknownBlockNumber) }; + let Some(block) = block else { return Err(EthApiError::UnknownBlockNumber.into()) }; let gas_limit = self.call_gas_limit(); // we're essentially replaying the transactions in the block here, hence we need the @@ -138,14 +142,16 @@ pub trait EthCall: Call + LoadPendingBlock { let state_overrides = state_override.take(); let overrides = EvmOverrides::new(state_overrides, block_overrides.clone()); - let env = this.prepare_call_env( - cfg.clone(), - block_env.clone(), - tx, - gas_limit, - &mut db, - overrides, - )?; + let env = this + .prepare_call_env( + cfg.clone(), + block_env.clone(), + tx, + gas_limit, + &mut db, + overrides, + ) + .map(Into::into)?; let (res, _) = this.transact(&mut db, env)?; match ensure_success(res.result) { @@ -179,7 +185,7 @@ pub trait EthCall: Call + LoadPendingBlock { &self, request: TransactionRequest, block_number: Option, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: Trace, { @@ -202,7 +208,7 @@ pub trait EthCall: Call + LoadPendingBlock { block: BlockEnv, at: BlockId, mut request: TransactionRequest, - ) -> EthResult + ) -> Result where Self: Trace, { @@ -230,7 +236,8 @@ pub trait EthCall: Call + LoadPendingBlock { let to = if let Some(TxKind::Call(to)) = request.to { to } else { - let nonce = db.basic_ref(from)?.unwrap_or_default().nonce; + let nonce = + db.basic_ref(from).map_err(Self::Error::from_eth_err)?.unwrap_or_default().nonce; from.create(nonce) }; @@ -250,7 +257,8 @@ pub trait EthCall: Call + LoadPendingBlock { Err(RpcInvalidTransactionError::Revert(RevertError::new(output))) } ExecutionResult::Success { .. } => Ok(()), - }?; + } + .map_err(Self::Error::from_eth_err)?; let access_list = inspector.into_access_list(); @@ -279,9 +287,9 @@ pub trait Call: LoadState + SpawnBlocking { fn evm_config(&self) -> &impl ConfigureEvm; /// Executes the closure with the state that corresponds to the given [`BlockId`]. - fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult + fn with_state_at_block(&self, at: BlockId, f: F) -> Result where - F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult, + F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result, { let state = self.state_at_block_id(at)?; f(StateProviderTraitObjWrapper(&state)) @@ -293,13 +301,13 @@ pub trait Call: LoadState + SpawnBlocking { &self, db: DB, env: EnvWithHandlerCfg, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + ) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error> where DB: Database, - ::Error: Into, + EthApiError: From, { let mut evm = self.evm_config().evm_with_env(db, env); - let res = evm.transact()?; + let res = evm.transact().map_err(Self::Error::from_evm_err)?; let (_, env) = evm.into_db_and_env_with_handler_cfg(); Ok((res, env)) } @@ -310,7 +318,7 @@ pub trait Call: LoadState + SpawnBlocking { request: TransactionRequest, at: BlockId, overrides: EvmOverrides, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock, { @@ -319,14 +327,14 @@ pub trait Call: LoadState + SpawnBlocking { } /// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task - fn spawn_with_state_at_block( + fn spawn_with_state_at_block( &self, at: BlockId, f: F, - ) -> impl Future> + Send + ) -> impl Future> + Send where - F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult + Send + 'static, - T: Send + 'static, + F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result + Send + 'static, + R: Send + 'static, { self.spawn_tracing(move |this| { let state = this.state_at_block_id(at)?; @@ -345,10 +353,10 @@ pub trait Call: LoadState + SpawnBlocking { at: BlockId, overrides: EvmOverrides, f: F, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock, - F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> EthResult + F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> Result + Send + 'static, R: Send + 'static, @@ -373,7 +381,7 @@ pub trait Call: LoadState + SpawnBlocking { f(StateCacheDbRefMutWrapper(&mut db), env) }) .await - .map_err(|_| EthApiError::InternalBlockingTaskError) + .map_err(|_| EthApiError::InternalBlockingTaskError.into()) } } @@ -390,10 +398,10 @@ pub trait Call: LoadState + SpawnBlocking { &self, hash: B256, f: F, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadBlock + LoadPendingBlock + LoadTransaction, - F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> EthResult + F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> Result + Send + 'static, R: Send + 'static, @@ -453,10 +461,10 @@ pub trait Call: LoadState + SpawnBlocking { block_env: BlockEnv, transactions: impl IntoIterator, target_tx_hash: B256, - ) -> Result + ) -> Result where DB: DatabaseRef, - EthApiError: From<::Error>, + EthApiError: From, { let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); @@ -470,7 +478,7 @@ pub trait Call: LoadState + SpawnBlocking { let sender = tx.signer(); self.evm_config().fill_tx_env(evm.tx_mut(), &tx.into_signed(), sender); - evm.transact_commit()?; + evm.transact_commit().map_err(Self::Error::from_evm_err)?; index += 1; } Ok(index) @@ -482,7 +490,7 @@ pub trait Call: LoadState + SpawnBlocking { request: TransactionRequest, at: BlockId, state_override: Option, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock, { @@ -507,7 +515,7 @@ pub trait Call: LoadState + SpawnBlocking { request: TransactionRequest, state: S, state_override: Option, - ) -> EthResult + ) -> Result where S: StateProvider, { @@ -537,7 +545,7 @@ pub trait Call: LoadState + SpawnBlocking { // Apply any state overrides if specified. if let Some(state_override) = state_override { - apply_state_overrides(state_override, &mut db)?; + apply_state_overrides(state_override, &mut db).map_err(Self::Error::from_eth_err)?; } // Optimize for simple transfer transactions, potentially reducing the gas estimate. @@ -568,7 +576,8 @@ pub trait Call: LoadState + SpawnBlocking { // The caller allowance is check by doing `(account.balance - tx.value) / tx.gas_price` if env.tx.gas_price > U256::ZERO { // cap the highest gas limit by max gas caller can afford with given gas price - highest_gas_limit = highest_gas_limit.min(caller_gas_allowance(&mut db, &env.tx)?); + highest_gas_limit = highest_gas_limit + .min(caller_gas_allowance(&mut db, &env.tx).map_err(Self::Error::from_eth_err)?); } // We can now normalize the highest gas limit to a u64 @@ -586,8 +595,9 @@ pub trait Call: LoadState + SpawnBlocking { // If the gas price or gas limit was specified in the request, retry the transaction // with the block's gas limit to determine if the failure was due to // insufficient gas. - Err(EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) - if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() => + Err(err) + if err.is_gas_too_high() && + (tx_request_gas_limit.is_some() || tx_request_gas_price.is_some()) => { return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) } @@ -600,7 +610,7 @@ pub trait Call: LoadState + SpawnBlocking { ExecutionResult::Halt { reason, gas_used } => { // here we don't check for invalid opcode because already executed with highest gas // limit - return Err(RpcInvalidTransactionError::halt(reason, gas_used).into()) + return Err(RpcInvalidTransactionError::halt(reason, gas_used).into_eth_err()) } ExecutionResult::Revert { output, .. } => { // if price or limit was included in the request then we can execute the request @@ -609,7 +619,7 @@ pub trait Call: LoadState + SpawnBlocking { Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) } else { // the transaction did revert - Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into()) + Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into_eth_err()) } } }; @@ -675,8 +685,7 @@ pub trait Call: LoadState + SpawnBlocking { // Execute transaction and handle potential gas errors, adjusting limits accordingly. match self.transact(&mut db, env.clone()) { - // Check if the error is due to gas being too high. - Err(EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) => { + Err(err) if err.is_gas_too_high() => { // Increase the lowest gas limit if gas is too high lowest_gas_limit = mid_gas_limit; } @@ -713,7 +722,7 @@ pub trait Call: LoadState + SpawnBlocking { tx_gas_limit: u64, highest_gas_limit: &mut u64, lowest_gas_limit: &mut u64, - ) -> EthResult<()> { + ) -> Result<(), Self::Error> { match result { ExecutionResult::Success { .. } => { // Cap the highest gas limit with the succeeding gas limit. @@ -741,7 +750,7 @@ pub trait Call: LoadState + SpawnBlocking { // These cases should be unreachable because we know the transaction // succeeds, but if they occur, treat them as an // error. - return Err(RpcInvalidTransactionError::EvmHalt(err).into()) + return Err(RpcInvalidTransactionError::EvmHalt(err).into_eth_err()) } } } @@ -758,7 +767,7 @@ pub trait Call: LoadState + SpawnBlocking { env_gas_limit: U256, mut env: EnvWithHandlerCfg, db: &mut CacheDB>, - ) -> EthApiError + ) -> Self::Error where S: StateProvider, { @@ -772,14 +781,14 @@ pub trait Call: LoadState + SpawnBlocking { ExecutionResult::Success { .. } => { // transaction succeeded by manually increasing the gas limit to // highest, which means the caller lacks funds to pay for the tx - RpcInvalidTransactionError::BasicOutOfGas(req_gas_limit).into() + RpcInvalidTransactionError::BasicOutOfGas(req_gas_limit).into_eth_err() } ExecutionResult::Revert { output, .. } => { // reverted again after bumping the limit - RpcInvalidTransactionError::Revert(RevertError::new(output)).into() + RpcInvalidTransactionError::Revert(RevertError::new(output)).into_eth_err() } ExecutionResult::Halt { reason, .. } => { - RpcInvalidTransactionError::EvmHalt(reason).into() + RpcInvalidTransactionError::EvmHalt(reason).into_eth_err() } } } @@ -792,10 +801,10 @@ pub trait Call: LoadState + SpawnBlocking { &self, block_env: &BlockEnv, request: TransactionRequest, - ) -> EthResult { + ) -> Result { // Ensure that if versioned hashes are set, they're not empty if request.blob_versioned_hashes.as_ref().map_or(false, |hashes| hashes.is_empty()) { - return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into()) + return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into_eth_err()) } let TransactionRequest { @@ -833,14 +842,18 @@ pub trait Call: LoadState + SpawnBlocking { let env = TxEnv { gas_limit: gas_limit .try_into() - .map_err(|_| RpcInvalidTransactionError::GasUintOverflow)?, + .map_err(|_| RpcInvalidTransactionError::GasUintOverflow) + .map_err(Self::Error::from_eth_err)?, nonce, caller: from.unwrap_or_default(), gas_price, gas_priority_fee: max_priority_fee_per_gas, transact_to: to.unwrap_or(TxKind::Create), value: value.unwrap_or_default(), - data: input.try_into_unique_input()?.unwrap_or_default(), + data: input + .try_into_unique_input() + .map_err(Self::Error::from_eth_err)? + .unwrap_or_default(), chain_id, access_list: access_list.unwrap_or_default().into(), // EIP-4844 fields @@ -863,7 +876,7 @@ pub trait Call: LoadState + SpawnBlocking { cfg: CfgEnvWithHandlerCfg, block: BlockEnv, request: TransactionRequest, - ) -> EthResult { + ) -> Result { let tx = self.create_txn_env(&block, request)?; Ok(EnvWithHandlerCfg::new_with_cfg_env(cfg, block, tx)) } @@ -885,7 +898,7 @@ pub trait Call: LoadState + SpawnBlocking { gas_limit: u64, db: &mut CacheDB, overrides: EvmOverrides, - ) -> EthResult + ) -> Result where DB: DatabaseRef, EthApiError: From<::Error>, diff --git a/crates/rpc/rpc-eth-api/src/helpers/error.rs b/crates/rpc/rpc-eth-api/src/helpers/error.rs new file mode 100644 index 000000000..041a01905 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/error.rs @@ -0,0 +1,88 @@ +//! Helper traits to wrap generic l1 errors, in network specific error type configured in +//! [`EthApiTypes`](crate::EthApiTypes). + +use reth_rpc_eth_types::EthApiError; +use revm_primitives::EVMError; + +/// Helper trait to wrap core [`EthApiError`]. +pub trait FromEthApiError: From { + /// Converts from error via [`EthApiError`]. + fn from_eth_err(err: E) -> Self + where + EthApiError: From; +} + +impl FromEthApiError for T +where + T: From, +{ + fn from_eth_err(err: E) -> Self + where + EthApiError: From, + { + T::from(EthApiError::from(err)) + } +} + +/// Helper trait to wrap core [`EthApiError`]. +pub trait IntoEthApiError: Into { + /// Converts into error via [`EthApiError`]. + fn into_eth_err(self) -> E + where + E: FromEthApiError; +} + +impl IntoEthApiError for T +where + EthApiError: From, +{ + fn into_eth_err(self) -> E + where + E: FromEthApiError, + { + E::from_eth_err(self) + } +} + +/// Helper trait to access wrapped core error. +pub trait AsEthApiError { + /// Returns reference to [`EthApiError`], if this an error variant inherited from core + /// functionality. + fn as_err(&self) -> Option<&EthApiError>; + + /// Returns `true` if error is + /// [`RpcInvalidTransactionError::GasTooHigh`](reth_rpc_eth_types::RpcInvalidTransactionError::GasTooHigh). + fn is_gas_too_high(&self) -> bool { + if let Some(err) = self.as_err() { + return err.is_gas_too_high() + } + + false + } +} + +impl AsEthApiError for EthApiError { + fn as_err(&self) -> Option<&EthApiError> { + Some(self) + } +} + +/// Helper trait to convert from revm errors. +pub trait FromEvmError: From { + /// Converts from a revm error. + fn from_evm_err(err: EVMError) -> Self + where + EthApiError: From; +} + +impl FromEvmError for T +where + T: From, +{ + fn from_evm_err(err: EVMError) -> Self + where + EthApiError: From, + { + err.into_eth_err() + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs index 54c577ea2..290833eec 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/fee.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -4,12 +4,14 @@ use futures::Future; use reth_primitives::U256; use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider}; use reth_rpc_eth_types::{ - fee_history::calculate_reward_percentiles_for_block, EthApiError, EthResult, EthStateCache, + fee_history::calculate_reward_percentiles_for_block, EthApiError, EthStateCache, FeeHistoryCache, FeeHistoryEntry, GasPriceOracle, RpcInvalidTransactionError, }; use reth_rpc_types::{BlockNumberOrTag, FeeHistory}; use tracing::debug; +use crate::FromEthApiError; + use super::LoadBlock; /// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the @@ -18,7 +20,7 @@ pub trait EthFees: LoadFee { /// Returns a suggestion for a gas price for legacy transactions. /// /// See also: - fn gas_price(&self) -> impl Future> + Send + fn gas_price(&self) -> impl Future> + Send where Self: LoadBlock, { @@ -26,7 +28,7 @@ pub trait EthFees: LoadFee { } /// Returns a suggestion for a base fee for blob transactions. - fn blob_base_fee(&self) -> impl Future> + Send + fn blob_base_fee(&self) -> impl Future> + Send where Self: LoadBlock, { @@ -34,7 +36,7 @@ pub trait EthFees: LoadFee { } /// Returns a suggestion for the priority fee (the tip) - fn suggested_priority_fee(&self) -> impl Future> + Send + fn suggested_priority_fee(&self) -> impl Future> + Send where Self: 'static, { @@ -50,7 +52,7 @@ pub trait EthFees: LoadFee { mut block_count: u64, newest_block: BlockNumberOrTag, reward_percentiles: Option>, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { if block_count == 0 { return Ok(FeeHistory::default()) @@ -72,10 +74,11 @@ pub trait EthFees: LoadFee { block_count = max_fee_history } - let Some(end_block) = - LoadFee::provider(self).block_number_for_id(newest_block.into())? + let Some(end_block) = LoadFee::provider(self) + .block_number_for_id(newest_block.into()) + .map_err(Self::Error::from_eth_err)? else { - return Err(EthApiError::UnknownBlockNumber) + return Err(EthApiError::UnknownBlockNumber.into()) }; // need to add 1 to the end block to get the correct (inclusive) range @@ -91,7 +94,7 @@ pub trait EthFees: LoadFee { // Note: The types used ensure that the percentiles are never < 0 if let Some(percentiles) = &reward_percentiles { if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) { - return Err(EthApiError::InvalidRewardPercentiles) + return Err(EthApiError::InvalidRewardPercentiles.into()) } } @@ -116,7 +119,7 @@ pub trait EthFees: LoadFee { if let Some(fee_entries) = fee_entries { if fee_entries.len() != block_count as usize { - return Err(EthApiError::InvalidBlockRange) + return Err(EthApiError::InvalidBlockRange.into()) } for entry in &fee_entries { @@ -144,9 +147,9 @@ pub trait EthFees: LoadFee { base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default()); } else { // read the requested header range - let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block)?; + let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block).map_err(Self::Error::from_eth_err)?; if headers.len() != block_count as usize { - return Err(EthApiError::InvalidBlockRange) + return Err(EthApiError::InvalidBlockRange.into()) } for header in &headers { @@ -162,7 +165,7 @@ pub trait EthFees: LoadFee { if let Some(percentiles) = &reward_percentiles { let (transactions, receipts) = LoadFee::cache(self) .get_transactions_and_receipts(header.hash()) - .await? + .await.map_err(Self::Error::from_eth_err)? .ok_or(EthApiError::InvalidBlockRange)?; rewards.push( calculate_reward_percentiles_for_block( @@ -251,7 +254,7 @@ pub trait LoadFee: LoadBlock { fn legacy_gas_price( &self, gas_price: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { match gas_price { Some(gas_price) => Ok(gas_price), @@ -271,7 +274,7 @@ pub trait LoadFee: LoadBlock { &self, max_fee_per_gas: Option, max_priority_fee_per_gas: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { let max_fee_per_gas = match max_fee_per_gas { Some(max_fee_per_gas) => max_fee_per_gas, @@ -303,7 +306,7 @@ pub trait LoadFee: LoadBlock { fn eip4844_blob_fee( &self, blob_fee: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { match blob_fee { Some(blob_fee) => Ok(blob_fee), @@ -315,7 +318,7 @@ pub trait LoadFee: LoadBlock { /// Returns a suggestion for a gas price for legacy transactions. /// /// See also: - fn gas_price(&self) -> impl Future> + Send { + fn gas_price(&self) -> impl Future> + Send { let header = self.block(BlockNumberOrTag::Latest.into()); let suggested_tip = self.suggested_priority_fee(); async move { @@ -326,21 +329,21 @@ pub trait LoadFee: LoadBlock { } /// Returns a suggestion for a base fee for blob transactions. - fn blob_base_fee(&self) -> impl Future> + Send { + fn blob_base_fee(&self) -> impl Future> + Send { async move { self.block(BlockNumberOrTag::Latest.into()) .await? .and_then(|h: reth_primitives::SealedBlock| h.next_block_blob_fee()) - .ok_or(EthApiError::ExcessBlobGasNotSet) + .ok_or(EthApiError::ExcessBlobGasNotSet.into()) .map(U256::from) } } /// Returns a suggestion for the priority fee (the tip) - fn suggested_priority_fee(&self) -> impl Future> + Send + fn suggested_priority_fee(&self) -> impl Future> + Send where Self: 'static, { - self.gas_oracle().suggest_tip_cap() + async move { self.gas_oracle().suggest_tip_cap().await.map_err(Self::Error::from_eth_err) } } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs index b82a621ac..ecfd63388 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -17,6 +17,7 @@ pub mod block; pub mod blocking_task; pub mod call; +pub mod error; pub mod fee; pub mod pending_block; pub mod receipt; @@ -25,6 +26,7 @@ pub mod spec; pub mod state; pub mod trace; pub mod transaction; +pub mod types; pub use block::{EthBlocks, LoadBlock}; pub use blocking_task::SpawnBlocking; @@ -38,6 +40,8 @@ pub use state::{EthState, LoadState}; pub use trace::Trace; pub use transaction::{EthTransactions, LoadTransaction, UpdateRawTxForwarder}; +use crate::EthApiTypes; + /// Extension trait that bundles traits needed for tracing transactions. pub trait TraceExt: LoadTransaction + LoadBlock + LoadPendingBlock + SpawnBlocking + Trace + Call @@ -50,12 +54,21 @@ impl TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock + /// /// This trait is automatically implemented for any type that implements all the `Eth` traits. pub trait FullEthApi: - EthApiSpec + EthTransactions + EthBlocks + EthState + EthCall + EthFees + Trace + LoadReceipt + EthApiTypes + + EthApiSpec + + EthTransactions + + EthBlocks + + EthState + + EthCall + + EthFees + + Trace + + LoadReceipt { } impl FullEthApi for T where - T: EthApiSpec + T: EthApiTypes + + EthApiSpec + EthTransactions + EthBlocks + EthState diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index a17fbb43f..183b1c791 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -19,27 +19,29 @@ use reth_primitives::{ EMPTY_OMMER_ROOT_HASH, U256, }; use reth_provider::{ - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError, + StateProviderFactory, }; use reth_revm::{ database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments, }; use reth_rpc_eth_types::{ - pending_block::pre_block_blockhashes_update, EthApiError, EthResult, PendingBlock, - PendingBlockEnv, PendingBlockEnvOrigin, + pending_block::pre_block_blockhashes_update, EthApiError, PendingBlock, PendingBlockEnv, + PendingBlockEnvOrigin, }; use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State}; use tokio::sync::Mutex; use tracing::debug; +use crate::{EthApiTypes, FromEthApiError, FromEvmError}; + use super::SpawnBlocking; /// Loads a pending block from database. /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. -#[auto_impl::auto_impl(&, Arc)] -pub trait LoadPendingBlock { +pub trait LoadPendingBlock: EthApiTypes { /// Returns a handle for reading data from disk. /// /// Data access in default (L1) trait method implementations. @@ -65,16 +67,19 @@ pub trait LoadPendingBlock { /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block /// /// If no pending block is available, this will derive it from the `latest` block - fn pending_block_env_and_cfg(&self) -> EthResult { + fn pending_block_env_and_cfg(&self) -> Result { let origin: PendingBlockEnvOrigin = if let Some(pending) = - self.provider().pending_block_with_senders()? + self.provider().pending_block_with_senders().map_err(Self::Error::from_eth_err)? { PendingBlockEnvOrigin::ActualPending(pending) } else { // no pending block from the CL yet, so we use the latest block and modify the env // values that we can - let latest = - self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?; + let latest = self + .provider() + .latest_header() + .map_err(Self::Error::from_eth_err)? + .ok_or_else(|| EthApiError::UnknownBlockNumber)?; let (mut latest_header, block_hash) = latest.split(); // child block @@ -102,12 +107,14 @@ pub trait LoadPendingBlock { let mut block_env = BlockEnv::default(); // Note: for the PENDING block we assume it is past the known merge block and thus this will // not fail when looking up the total difficulty value for the blockenv. - self.provider().fill_env_with_header( - &mut cfg, - &mut block_env, - origin.header(), - self.evm_config().clone(), - )?; + self.provider() + .fill_env_with_header( + &mut cfg, + &mut block_env, + origin.header(), + self.evm_config().clone(), + ) + .map_err(Self::Error::from_eth_err)?; Ok(PendingBlockEnv::new(cfg, block_env, origin)) } @@ -115,7 +122,7 @@ pub trait LoadPendingBlock { /// Returns the locally built pending block fn local_pending_block( &self, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: SpawnBlocking, { @@ -197,11 +204,17 @@ pub trait LoadPendingBlock { /// /// After Cancun, if the origin is the actual pending block, the block includes the EIP-4788 pre /// block contract call using the parent beacon block root received from the CL. - fn build_block(&self, env: PendingBlockEnv) -> EthResult { + fn build_block(&self, env: PendingBlockEnv) -> Result + where + EthApiError: From, + { let PendingBlockEnv { cfg, block_env, origin } = env; let parent_hash = origin.build_target_hash(); - let state_provider = self.provider().history_by_block_hash(parent_hash)?; + let state_provider = self + .provider() + .history_by_block_hash(parent_hash) + .map_err(Self::Error::from_eth_err)?; let state = StateProviderDatabase::new(state_provider); let mut db = State::builder().with_database(state).with_bundle_update().build(); @@ -316,7 +329,7 @@ pub trait LoadPendingBlock { } err => { // this is an error that we should treat as fatal for this attempt - return Err(err.into()) + return Err(Self::Error::from_evm_err(err)) } } } @@ -359,7 +372,7 @@ pub trait LoadPendingBlock { ); // increment account balances for withdrawals - db.increment_balances(balance_increments)?; + db.increment_balances(balance_increments).map_err(Self::Error::from_eth_err)?; // merge all transitions into bundle state. db.merge_transitions(BundleRetention::PlainState); @@ -378,7 +391,9 @@ pub trait LoadPendingBlock { // calculate the state root let state_provider = &db.database; - let state_root = state_provider.state_root(execution_outcome.state())?; + let state_root = state_provider + .state_root(execution_outcome.state()) + .map_err(Self::Error::from_eth_err)?; // create the block header let transactions_root = calculate_transaction_root(&executed_txs); diff --git a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs index 5cd6c03c4..63016e3d2 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs @@ -3,14 +3,15 @@ use futures::Future; use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; -use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; use reth_rpc_types::AnyTransactionReceipt; +use crate::{EthApiTypes, FromEthApiError}; + /// Assembles transaction receipt data w.r.t to network. /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods. -#[auto_impl::auto_impl(&, Arc)] -pub trait LoadReceipt: Send + Sync { +pub trait LoadReceipt: EthApiTypes + Send + Sync { /// Returns a handle for reading data from memory. /// /// Data access in default (L1) trait method implementations. @@ -22,12 +23,17 @@ pub trait LoadReceipt: Send + Sync { tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> impl Future> + Send { + ) -> impl Future> + Send { async move { // get all receipts for the block - let all_receipts = match self.cache().get_receipts(meta.block_hash).await? { + let all_receipts = match self + .cache() + .get_receipts(meta.block_hash) + .await + .map_err(Self::Error::from_eth_err)? + { Some(recpts) => recpts, - None => return Err(EthApiError::UnknownBlockNumber), + None => return Err(EthApiError::UnknownBlockNumber.into()), }; Ok(ReceiptBuilder::new(&tx, meta, &receipt, &all_receipts)?.build()) diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index 0da2a49c3..48d350e0e 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -8,15 +8,15 @@ use reth_primitives::{Address, BlockId, Bytes, Header, B256, U256}; use reth_provider::{ BlockIdReader, ChainSpecProvider, StateProvider, StateProviderBox, StateProviderFactory, }; -use reth_rpc_eth_types::{ - EthApiError, EthResult, EthStateCache, PendingBlockEnv, RpcInvalidTransactionError, -}; +use reth_rpc_eth_types::{EthApiError, EthStateCache, PendingBlockEnv, RpcInvalidTransactionError}; use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_transaction_pool::{PoolTransaction, TransactionPool}; use revm::db::BundleState; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId}; +use crate::{EthApiTypes, FromEthApiError}; + use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking}; /// Helper methods for `eth_` methods relating to state (accounts). @@ -32,7 +32,7 @@ pub trait EthState: LoadState + SpawnBlocking { &self, address: Address, block_id: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { LoadState::transaction_count(self, address, block_id) } @@ -41,11 +41,12 @@ pub trait EthState: LoadState + SpawnBlocking { &self, address: Address, block_id: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { self.spawn_blocking_io(move |this| { Ok(this .state_at_block_id_or_latest(block_id)? - .account_code(address)? + .account_code(address) + .map_err(Self::Error::from_eth_err)? .unwrap_or_default() .original_bytes()) }) @@ -56,11 +57,12 @@ pub trait EthState: LoadState + SpawnBlocking { &self, address: Address, block_id: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { self.spawn_blocking_io(move |this| { Ok(this .state_at_block_id_or_latest(block_id)? - .account_balance(address)? + .account_balance(address) + .map_err(Self::Error::from_eth_err)? .unwrap_or_default()) }) } @@ -71,11 +73,12 @@ pub trait EthState: LoadState + SpawnBlocking { address: Address, index: JsonStorageKey, block_id: Option, - ) -> impl Future> + Send { + ) -> impl Future> + Send { self.spawn_blocking_io(move |this| { Ok(B256::new( this.state_at_block_id_or_latest(block_id)? - .storage(address, index.0)? + .storage(address, index.0) + .map_err(Self::Error::from_eth_err)? .unwrap_or_default() .to_be_bytes(), )) @@ -88,21 +91,25 @@ pub trait EthState: LoadState + SpawnBlocking { address: Address, keys: Vec, block_id: Option, - ) -> EthResult> + Send> + ) -> Result< + impl Future> + Send, + Self::Error, + > where Self: EthApiSpec, { - let chain_info = self.chain_info()?; + let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?; let block_id = block_id.unwrap_or_default(); // Check whether the distance to the block exceeds the maximum configured window. let block_number = self .provider() - .block_number_for_id(block_id)? + .block_number_for_id(block_id) + .map_err(Self::Error::from_eth_err)? .ok_or(EthApiError::UnknownBlockNumber)?; let max_window = self.max_proof_window(); if chain_info.best_number.saturating_sub(block_number) > max_window { - return Err(EthApiError::ExceedsMaxProofWindow) + return Err(EthApiError::ExceedsMaxProofWindow.into()) } Ok(async move { @@ -113,7 +120,9 @@ pub trait EthState: LoadState + SpawnBlocking { self.spawn_blocking_io(move |this| { let state = this.state_at_block_id(block_id)?; let storage_keys = keys.iter().map(|key| key.0).collect::>(); - let proof = state.proof(&BundleState::default(), address, &storage_keys)?; + let proof = state + .proof(&BundleState::default(), address, &storage_keys) + .map_err(Self::Error::from_eth_err)?; Ok(from_primitive_account_proof(proof)) }) .await @@ -124,7 +133,7 @@ pub trait EthState: LoadState + SpawnBlocking { /// Loads state from database. /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` state RPC methods. -pub trait LoadState { +pub trait LoadState: EthApiTypes { /// Returns a handle for reading state from database. /// /// Data access in default trait method implementations. @@ -141,21 +150,21 @@ pub trait LoadState { fn pool(&self) -> impl TransactionPool; /// Returns the state at the given block number - fn state_at_hash(&self, block_hash: B256) -> EthResult { - Ok(self.provider().history_by_block_hash(block_hash)?) + fn state_at_hash(&self, block_hash: B256) -> Result { + self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err) } /// Returns the state at the given [`BlockId`] enum. /// /// Note: if not [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this /// will only return canonical state. See also - fn state_at_block_id(&self, at: BlockId) -> EthResult { - Ok(self.provider().state_by_block_id(at)?) + fn state_at_block_id(&self, at: BlockId) -> Result { + self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err) } /// Returns the _latest_ state - fn latest_state(&self) -> EthResult { - Ok(self.provider().latest()?) + fn latest_state(&self) -> Result { + self.provider().latest().map_err(Self::Error::from_eth_err) } /// Returns the state at the given [`BlockId`] enum or the latest. @@ -164,7 +173,7 @@ pub trait LoadState { fn state_at_block_id_or_latest( &self, block_id: Option, - ) -> EthResult { + ) -> Result { if let Some(block_id) = block_id { self.state_at_block_id(block_id) } else { @@ -181,7 +190,7 @@ pub trait LoadState { fn evm_env_at( &self, at: BlockId, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock + SpawnBlocking, { @@ -193,9 +202,14 @@ pub trait LoadState { } else { // Use cached values if there is no pending block let block_hash = LoadPendingBlock::provider(self) - .block_hash_for_id(at)? + .block_hash_for_id(at) + .map_err(Self::Error::from_eth_err)? .ok_or_else(|| EthApiError::UnknownBlockNumber)?; - let (cfg, env) = self.cache().get_evm_env(block_hash).await?; + let (cfg, env) = self + .cache() + .get_evm_env(block_hash) + .await + .map_err(Self::Error::from_eth_err)?; Ok((cfg, env, block_hash.into())) } } @@ -207,7 +221,7 @@ pub trait LoadState { fn evm_env_for_raw_block( &self, header: &Header, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock + SpawnBlocking, { @@ -230,7 +244,7 @@ pub trait LoadState { &self, address: Address, block_id: Option, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: SpawnBlocking, { @@ -240,15 +254,20 @@ pub trait LoadState { if let Some(highest_nonce) = address_txs.iter().map(|item| item.transaction.nonce()).max() { - let tx_count = highest_nonce - .checked_add(1) - .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; + let tx_count = highest_nonce.checked_add(1).ok_or(Self::Error::from( + EthApiError::InvalidTransaction(RpcInvalidTransactionError::NonceMaxValue), + ))?; return Ok(U256::from(tx_count)) } } let state = this.state_at_block_id_or_latest(block_id)?; - Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) + Ok(U256::from( + state + .account_nonce(address) + .map_err(Self::Error::from_eth_err)? + .unwrap_or_default(), + )) }) } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index d48e566ed..09ad7f22f 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -6,13 +6,15 @@ use reth_primitives::B256; use reth_revm::database::StateProviderDatabase; use reth_rpc_eth_types::{ cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, - EthApiError, EthResult, + EthApiError, }; use reth_rpc_types::{BlockId, TransactionInfo}; use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector}; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use revm_primitives::{EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState}; +use crate::FromEvmError; + use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction}; /// Executes CPU heavy tasks. @@ -29,10 +31,10 @@ pub trait Trace: LoadState { db: DB, env: EnvWithHandlerCfg, inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + ) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error> where DB: Database, - ::Error: Into, + EthApiError: From, I: GetInspector, { self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env)) @@ -48,14 +50,15 @@ pub trait Trace: LoadState { db: DB, env: EnvWithHandlerCfg, inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg, DB)> + ) -> Result<(ResultAndState, EnvWithHandlerCfg, DB), Self::Error> where DB: Database, - ::Error: Into, + EthApiError: From, + I: GetInspector, { let mut evm = self.evm_config().evm_with_env_and_inspector(db, env, inspector); - let res = evm.transact()?; + let res = evm.transact().map_err(Self::Error::from_evm_err)?; let (db, env) = evm.into_db_and_env_with_handler_cfg(); Ok((res, env, db)) } @@ -73,10 +76,10 @@ pub trait Trace: LoadState { config: TracingInspectorConfig, at: BlockId, f: F, - ) -> EthResult + ) -> Result where Self: Call, - F: FnOnce(TracingInspector, ResultAndState) -> EthResult, + F: FnOnce(TracingInspector, ResultAndState) -> Result, { self.with_state_at_block(at, |state| { let mut db = CacheDB::new(StateProviderDatabase::new(state)); @@ -99,10 +102,10 @@ pub trait Trace: LoadState { config: TracingInspectorConfig, at: BlockId, f: F, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: LoadPendingBlock + Call, - F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> EthResult + F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> Result + Send + 'static, R: Send + 'static, @@ -130,7 +133,7 @@ pub trait Trace: LoadState { hash: B256, config: TracingInspectorConfig, f: F, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadPendingBlock + LoadTransaction + Call, F: FnOnce( @@ -138,7 +141,7 @@ pub trait Trace: LoadState { TracingInspector, ResultAndState, StateCacheDb<'_>, - ) -> EthResult + ) -> Result + Send + 'static, R: Send + 'static, @@ -160,10 +163,15 @@ pub trait Trace: LoadState { hash: B256, mut inspector: Insp, f: F, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadPendingBlock + LoadTransaction + Call, - F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDb<'_>) -> EthResult + F: FnOnce( + TransactionInfo, + Insp, + ResultAndState, + StateCacheDb<'_>, + ) -> Result + Send + 'static, Insp: for<'a, 'b> Inspector> + Send + 'static, @@ -222,7 +230,7 @@ pub trait Trace: LoadState { highest_index: Option, config: TracingInspectorConfig, f: F, - ) -> impl Future>>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadBlock, F: Fn( @@ -231,7 +239,7 @@ pub trait Trace: LoadState { ExecutionResult, &EvmState, &StateCacheDb<'_>, - ) -> EthResult + ) -> Result + Send + 'static, R: Send + 'static, @@ -260,10 +268,16 @@ pub trait Trace: LoadState { highest_index: Option, mut inspector_setup: Setup, f: F, - ) -> impl Future>>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadBlock, - F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDb<'_>) -> EthResult + F: Fn( + TransactionInfo, + Insp, + ExecutionResult, + &EvmState, + &StateCacheDb<'_>, + ) -> Result + Send + 'static, Setup: FnMut() -> Insp + Send + 'static, @@ -360,7 +374,7 @@ pub trait Trace: LoadState { block_id: BlockId, config: TracingInspectorConfig, f: F, - ) -> impl Future>>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadBlock, // This is the callback that's invoked for each transaction with the inspector, the result, @@ -371,7 +385,7 @@ pub trait Trace: LoadState { ExecutionResult, &EvmState, &StateCacheDb<'_>, - ) -> EthResult + ) -> Result + Send + 'static, R: Send + 'static, @@ -398,12 +412,18 @@ pub trait Trace: LoadState { block_id: BlockId, insp_setup: Setup, f: F, - ) -> impl Future>>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadBlock, // This is the callback that's invoked for each transaction with the inspector, the result, // state and db - F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDb<'_>) -> EthResult + F: Fn( + TransactionInfo, + Insp, + ExecutionResult, + &EvmState, + &StateCacheDb<'_>, + ) -> Result + Send + 'static, Setup: FnMut() -> Insp + Send + 'static, diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index fa4c9be30..bd2b2ffd5 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -24,9 +24,11 @@ use reth_rpc_types::{ use reth_rpc_types_compat::transaction::from_recovered_with_block_context; use reth_transaction_pool::{TransactionOrigin, TransactionPool}; -use super::EthSigner; +use crate::{FromEthApiError, IntoEthApiError}; -use super::{Call, EthApiSpec, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, SpawnBlocking}; +use super::{ + Call, EthApiSpec, EthSigner, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, SpawnBlocking, +}; /// Transaction related functions for the [`EthApiServer`](crate::EthApiServer) trait in /// the `eth_` namespace. @@ -75,7 +77,7 @@ pub trait EthTransactions: LoadTransaction { fn transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { LoadTransaction::transaction_by_hash(self, hash) } @@ -85,8 +87,10 @@ pub trait EthTransactions: LoadTransaction { fn transactions_by_block( &self, block: B256, - ) -> impl Future>>> + Send { - async move { Ok(self.cache().get_block_transactions(block).await?) } + ) -> impl Future>, Self::Error>> + Send { + async move { + self.cache().get_block_transactions(block).await.map_err(Self::Error::from_eth_err) + } } /// Returns the EIP-2718 encoded transaction by hash. @@ -99,7 +103,7 @@ pub trait EthTransactions: LoadTransaction { fn raw_transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { // Note: this is mostly used to fetch pooled transactions so we check the pool first if let Some(tx) = @@ -110,7 +114,8 @@ pub trait EthTransactions: LoadTransaction { self.spawn_blocking_io(move |ref this| { Ok(LoadTransaction::provider(this) - .transaction_by_hash(hash)? + .transaction_by_hash(hash) + .map_err(Self::Error::from_eth_err)? .map(|tx| tx.envelope_encoded())) }) .await @@ -121,7 +126,7 @@ pub trait EthTransactions: LoadTransaction { fn historical_transaction_by_hash_at( &self, hash: B256, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { match self.transaction_by_hash_at(hash).await? { None => Ok(None), @@ -137,7 +142,7 @@ pub trait EthTransactions: LoadTransaction { fn transaction_receipt( &self, hash: B256, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadReceipt + 'static, { @@ -157,19 +162,26 @@ pub trait EthTransactions: LoadTransaction { fn load_transaction_and_receipt( &self, hash: TxHash, - ) -> impl Future>> + Send + ) -> impl Future< + Output = Result, Self::Error>, + > + Send where Self: 'static, { let this = self.clone(); self.spawn_blocking_io(move |_| { - let (tx, meta) = - match LoadTransaction::provider(&this).transaction_by_hash_with_meta(hash)? { - Some((tx, meta)) => (tx, meta), - None => return Ok(None), - }; + let (tx, meta) = match LoadTransaction::provider(&this) + .transaction_by_hash_with_meta(hash) + .map_err(Self::Error::from_eth_err)? + { + Some((tx, meta)) => (tx, meta), + None => return Ok(None), + }; - let receipt = match EthTransactions::provider(&this).receipt_by_hash(hash)? { + let receipt = match EthTransactions::provider(&this) + .receipt_by_hash(hash) + .map_err(Self::Error::from_eth_err)? + { Some(recpt) => recpt, None => return Ok(None), }; @@ -185,7 +197,7 @@ pub trait EthTransactions: LoadTransaction { &self, block_id: BlockId, index: usize, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadBlock, { @@ -216,7 +228,7 @@ pub trait EthTransactions: LoadTransaction { &self, block_id: BlockId, index: usize, - ) -> impl Future>> + Send + ) -> impl Future, Self::Error>> + Send where Self: LoadBlock, { @@ -234,7 +246,10 @@ pub trait EthTransactions: LoadTransaction { /// Decodes and recovers the transaction and submits it to the pool. /// /// Returns the hash of the transaction. - fn send_raw_transaction(&self, tx: Bytes) -> impl Future> + Send { + fn send_raw_transaction( + &self, + tx: Bytes, + ) -> impl Future> + Send { async move { // On optimism, transactions are forwarded directly to the sequencer to be included in // blocks that it builds. @@ -250,8 +265,11 @@ pub trait EthTransactions: LoadTransaction { ); // submit the transaction to the pool with a `Local` origin - let hash = - self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; + let hash = self + .pool() + .add_transaction(TransactionOrigin::Local, pool_transaction) + .await + .map_err(Self::Error::from_eth_err)?; Ok(hash) } @@ -262,18 +280,18 @@ pub trait EthTransactions: LoadTransaction { fn send_transaction( &self, mut request: TransactionRequest, - ) -> impl Future> + Send + ) -> impl Future> + Send where Self: EthApiSpec + LoadBlock + LoadPendingBlock + LoadFee + Call, { async move { let from = match request.from { Some(from) => from, - None => return Err(SignError::NoAccount.into()), + None => return Err(SignError::NoAccount.into_eth_err()), }; if self.find_signer(&from).is_err() { - return Err(SignError::NoAccount.into()); + return Err(SignError::NoAccount.into_eth_err()); } // set nonce if not already set before @@ -447,7 +465,7 @@ pub trait EthTransactions: LoadTransaction { TypedTransactionRequest::EIP4844(req) } - None => return Err(EthApiError::ConflictingFeeFieldsInRequest), + None => return Err(EthApiError::ConflictingFeeFieldsInRequest.into()), }; let signed_tx = self.sign_request(&from, transaction)?; @@ -457,13 +475,14 @@ pub trait EthTransactions: LoadTransaction { let pool_transaction = match recovered.try_into() { Ok(converted) => <::Pool as TransactionPool>::Transaction::from_recovered_pooled_transaction(converted), - Err(_) => return Err(EthApiError::TransactionConversionError), + Err(_) => return Err(EthApiError::TransactionConversionError.into()), }; // submit the transaction to the pool with a `Local` origin let hash = LoadTransaction::pool(self) .add_transaction(TransactionOrigin::Local, pool_transaction) - .await?; + .await + .map_err(Self::Error::from_eth_err)?; Ok(hash) } @@ -474,16 +493,16 @@ pub trait EthTransactions: LoadTransaction { &self, from: &Address, request: TypedTransactionRequest, - ) -> EthResult { + ) -> Result { for signer in self.signers().read().iter() { if signer.is_signer_for(from) { return match signer.sign_transaction(request, from) { Ok(tx) => Ok(tx), - Err(e) => Err(e.into()), + Err(e) => Err(e.into_eth_err()), } } } - Err(EthApiError::InvalidTransactionSignature) + Err(EthApiError::InvalidTransactionSignature.into()) } /// Signs given message. Returns the signature. @@ -491,23 +510,37 @@ pub trait EthTransactions: LoadTransaction { &self, account: Address, message: Bytes, - ) -> impl Future> + Send { - async move { Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes()) } + ) -> impl Future> + Send { + async move { + Ok(self + .find_signer(&account)? + .sign(account, &message) + .await + .map_err(Self::Error::from_eth_err)? + .to_hex_bytes()) + } } /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. - fn sign_typed_data(&self, data: &TypedData, account: Address) -> EthResult { - Ok(self.find_signer(&account)?.sign_typed_data(account, data)?.to_hex_bytes()) + fn sign_typed_data(&self, data: &TypedData, account: Address) -> Result { + Ok(self + .find_signer(&account)? + .sign_typed_data(account, data) + .map_err(Self::Error::from_eth_err)? + .to_hex_bytes()) } /// Returns the signer for the given account, if found in configured signers. - fn find_signer(&self, account: &Address) -> Result, SignError> { + fn find_signer( + &self, + account: &Address, + ) -> Result, Self::Error> { self.signers() .read() .iter() .find(|signer| signer.is_signer_for(account)) .map(|signer| dyn_clone::clone_box(&**signer)) - .ok_or(SignError::NoAccount) + .ok_or_else(|| SignError::NoAccount.into_eth_err()) } } @@ -543,12 +576,16 @@ pub trait LoadTransaction: SpawnBlocking { fn transaction_by_hash( &self, hash: B256, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send { async move { // Try to find the transaction on disk let mut resp = self .spawn_blocking_io(move |this| { - match this.provider().transaction_by_hash_with_meta(hash)? { + match this + .provider() + .transaction_by_hash_with_meta(hash) + .map_err(Self::Error::from_eth_err)? + { None => Ok(None), Some((tx, meta)) => { // Note: we assume this transaction is valid, because it's mined (or @@ -590,7 +627,8 @@ pub trait LoadTransaction: SpawnBlocking { fn transaction_by_hash_at( &self, transaction_hash: B256, - ) -> impl Future>> + Send { + ) -> impl Future, Self::Error>> + Send + { async move { match self.transaction_by_hash(transaction_hash).await? { None => Ok(None), @@ -625,8 +663,8 @@ pub trait LoadTransaction: SpawnBlocking { fn transaction_and_block( &self, hash: B256, - ) -> impl Future>> + Send - { + ) -> impl Future, Self::Error>> + + Send { async move { let (transaction, at) = match self.transaction_by_hash_at(hash).await? { None => return Ok(None), @@ -638,7 +676,11 @@ pub trait LoadTransaction: SpawnBlocking { BlockId::Hash(hash) => hash.block_hash, _ => return Ok(None), }; - let block = self.cache().get_block_with_senders(block_hash).await?; + let block = self + .cache() + .get_block_with_senders(block_hash) + .await + .map_err(Self::Error::from_eth_err)?; Ok(block.map(|block| (transaction, block.seal(block_hash)))) } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/types.rs b/crates/rpc/rpc-eth-api/src/helpers/types.rs new file mode 100644 index 000000000..088f9d9b6 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/types.rs @@ -0,0 +1,17 @@ +//! Trait for specifying `eth` API types that may be network dependent. + +use std::error::Error; + +use crate::{AsEthApiError, FromEthApiError, FromEvmError}; + +/// Network specific `eth` API types. +pub trait EthApiTypes: Send + Sync { + /// Extension of [`EthApiError`](reth_rpc_eth_types::EthApiError), with network specific errors. + type Error: Into> + + FromEthApiError + + AsEthApiError + + FromEvmError + + Error + + Send + + Sync; +} diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs index 1aed94d5c..c707a94ee 100644 --- a/crates/rpc/rpc-eth-api/src/lib.rs +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -21,6 +21,10 @@ pub mod pubsub; pub use bundle::{EthBundleApiServer, EthCallBundleApiServer}; pub use core::{EthApiServer, FullEthApiServer}; pub use filter::EthFilterApiServer; +pub use helpers::{ + error::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError}, + types::EthApiTypes, +}; pub use pubsub::EthPubSubApiServer; pub use helpers::transaction::RawTransactionForwarder; diff --git a/crates/rpc/rpc-eth-types/Cargo.toml b/crates/rpc/rpc-eth-types/Cargo.toml index b1c307191..3fb20836e 100644 --- a/crates/rpc/rpc-eth-types/Cargo.toml +++ b/crates/rpc/rpc-eth-types/Cargo.toml @@ -55,14 +55,3 @@ tracing.workspace = true [dev-dependencies] serde_json.workspace = true - -[features] -optimism = [ - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-revm/optimism", - "reth-chainspec/optimism", - "reth-execution-types/optimism", - "reth-revm/optimism", - "revm/optimism" -] \ No newline at end of file diff --git a/crates/rpc/rpc-eth-types/src/error.rs b/crates/rpc/rpc-eth-types/src/error.rs index 67fd11eae..62e5d9d97 100644 --- a/crates/rpc/rpc-eth-types/src/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -17,6 +17,7 @@ use reth_transaction_pool::error::{ }; use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError}; use revm_inspectors::tracing::{js::JsInspectorError, MuxError}; +use tracing::error; /// Result alias pub type EthResult = Result; @@ -137,6 +138,11 @@ impl EthApiError { pub fn other(err: E) -> Self { Self::Other(Box::new(err)) } + + /// Returns `true` if error is [`RpcInvalidTransactionError::GasTooHigh`] + pub const fn is_gas_too_high(&self) -> bool { + matches!(self, Self::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) + } } impl From for jsonrpsee_types::error::ErrorObject<'static> { @@ -372,6 +378,11 @@ pub enum RpcInvalidTransactionError { /// Any other error #[error("{0}")] Other(Box), + /// Unexpected [`InvalidTransaction`](revm::primitives::InvalidTransaction) error, Optimism + /// errors should not be handled on this level. + // TODO: Remove when optimism feature removed in revm + #[error("unexpected transaction error")] + UnexpectedTransactionError, } impl RpcInvalidTransactionError { @@ -381,29 +392,6 @@ impl RpcInvalidTransactionError { } } -/// Optimism specific invalid transaction errors -#[cfg(feature = "optimism")] -#[derive(thiserror::Error, Debug)] -pub enum OptimismInvalidTransactionError { - /// A deposit transaction was submitted as a system transaction post-regolith. - #[error("no system transactions allowed after regolith")] - DepositSystemTxPostRegolith, - /// A deposit transaction halted post-regolith - #[error("deposit transaction halted after regolith")] - HaltedDepositPostRegolith, -} - -#[cfg(feature = "optimism")] -impl ToRpcError for OptimismInvalidTransactionError { - fn to_rpc_error(&self) -> jsonrpsee_types::error::ErrorObject<'static> { - match self { - Self::DepositSystemTxPostRegolith | Self::HaltedDepositPostRegolith => { - rpc_err(EthRpcErrorCode::TransactionRejected.code(), self.to_string(), None) - } - } - } -} - impl RpcInvalidTransactionError { /// Returns the rpc error code for this error. const fn error_code(&self) -> i32 { @@ -462,7 +450,7 @@ impl From for RpcInvalidTransactionError { InvalidTransaction::InvalidChainId => Self::InvalidChainId, InvalidTransaction::PriorityFeeGreaterThanMaxFee => Self::TipAboveFeeCap, InvalidTransaction::GasPriceLessThanBasefee => Self::FeeCapTooLow, - InvalidTransaction::CallerGasLimitMoreThanBlock => Self::GasTooHigh, + InvalidTransaction::CallerGasLimitMoreThanBlock | InvalidTransaction::CallGasCostMoreThanGasLimit => Self::GasTooHigh, InvalidTransaction::RejectCallerWithCode => Self::SenderNoEOA, InvalidTransaction::LackOfFundForMaxFee { .. } => Self::InsufficientFunds, @@ -488,17 +476,15 @@ impl From for RpcInvalidTransactionError { InvalidTransaction::AuthorizationListInvalidFields => { Self::AuthorizationListInvalidFields } - #[cfg(feature = "optimism")] - InvalidTransaction::OptimismError(err) => match err { - revm_primitives::OptimismInvalidTransaction::DepositSystemTxPostRegolith => { - Self::other(OptimismInvalidTransactionError::DepositSystemTxPostRegolith) - } - revm_primitives::OptimismInvalidTransaction::HaltedDepositPostRegolith => { - Self::Other(Box::new( - OptimismInvalidTransactionError::HaltedDepositPostRegolith, - )) - } - }, + #[allow(unreachable_patterns)] + _ => { + error!(target: "rpc", + ?err, + "unexpected transaction error" + ); + + Self::UnexpectedTransactionError + } } } } diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 5c2ebaa23..78db90e81 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -90,5 +90,4 @@ optimism = [ "reth-provider/optimism", "reth-rpc-eth-api/optimism", "reth-revm/optimism", - "reth-rpc-eth-types/optimism", ] diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 847ab6ae5..30ad448e8 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -14,8 +14,11 @@ use reth_provider::{ }; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::DebugApiServer; -use reth_rpc_eth_api::helpers::{Call, EthApiSpec, EthTransactions, TraceExt}; -use reth_rpc_eth_types::{EthApiError, EthResult, StateCacheDb}; +use reth_rpc_eth_api::{ + helpers::{Call, EthApiSpec, EthTransactions, TraceExt}, + EthApiTypes, FromEthApiError, +}; +use reth_rpc_eth_types::{EthApiError, StateCacheDb}; use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult}; use reth_rpc_types::{ state::EvmOverrides, @@ -68,7 +71,7 @@ where + StateProviderFactory + EvmEnvProvider + 'static, - Eth: TraceExt + 'static, + Eth: EthApiTypes + TraceExt + 'static, { /// Acquires a permit to execute a tracing call. async fn acquire_trace_permit(&self) -> Result { @@ -83,7 +86,7 @@ where cfg: CfgEnvWithHandlerCfg, block_env: BlockEnv, opts: GethDebugTracingOptions, - ) -> EthResult> { + ) -> Result, Eth::Error> { if transactions.is_empty() { // nothing to trace return Ok(Vec::new()) @@ -141,9 +144,10 @@ where &self, rlp_block: Bytes, opts: GethDebugTracingOptions, - ) -> EthResult> { - let block = - Block::decode(&mut rlp_block.as_ref()).map_err(BlockError::RlpDecodeRawBlock)?; + ) -> Result, Eth::Error> { + let block = Block::decode(&mut rlp_block.as_ref()) + .map_err(BlockError::RlpDecodeRawBlock) + .map_err(Eth::Error::from_eth_err)?; let (cfg, block_env) = self.eth_api().evm_env_for_raw_block(&block.header).await?; // we trace on top the block's parent block @@ -158,8 +162,9 @@ where .map(|tx| { tx.into_ecrecovered() .ok_or_else(|| EthApiError::InvalidTransactionSignature) + .map_err(Eth::Error::from_eth_err) }) - .collect::>>()? + .collect::, Eth::Error>>()? } else { block .body @@ -167,8 +172,9 @@ where .map(|tx| { tx.into_ecrecovered_unchecked() .ok_or_else(|| EthApiError::InvalidTransactionSignature) + .map_err(Eth::Error::from_eth_err) }) - .collect::>>()? + .collect::, Eth::Error>>()? }; self.trace_block(parent.into(), transactions, cfg, block_env, opts).await @@ -179,11 +185,12 @@ where &self, block_id: BlockId, opts: GethDebugTracingOptions, - ) -> EthResult> { + ) -> Result, Eth::Error> { let block_hash = self .inner .provider - .block_hash_for_id(block_id)? + .block_hash_for_id(block_id) + .map_err(Eth::Error::from_eth_err)? .ok_or_else(|| EthApiError::UnknownBlockNumber)?; let ((cfg, block_env, _), block) = futures::try_join!( @@ -213,9 +220,9 @@ where &self, tx_hash: B256, opts: GethDebugTracingOptions, - ) -> EthResult { + ) -> Result { let (transaction, block) = match self.inner.eth_api.transaction_and_block(tx_hash).await? { - None => return Err(EthApiError::TransactionNotFound), + None => return Err(EthApiError::TransactionNotFound.into()), Some(res) => res, }; let (cfg, block_env, _) = self.inner.eth_api.evm_env_at(block.hash().into()).await?; @@ -277,7 +284,7 @@ where call: TransactionRequest, block_id: Option, opts: GethDebugTracingCallOptions, - ) -> EthResult { + ) -> Result { let at = block_id.unwrap_or_default(); let GethDebugTracingCallOptions { tracing_options, state_overrides, block_overrides } = opts; @@ -330,22 +337,23 @@ where TracingInspectorConfig::from_geth_prestate_config(&prestate_config), ); - let frame = - self.inner - .eth_api - .spawn_with_call_at(call, at, overrides, move |db, env| { - // wrapper is hack to get around 'higher-ranked lifetime error', - // see - let db = db.0; + let frame = self + .inner + .eth_api + .spawn_with_call_at(call, at, overrides, move |db, env| { + // wrapper is hack to get around 'higher-ranked lifetime error', + // see + let db = db.0; - let (res, _) = - this.eth_api().inspect(&mut *db, env, &mut inspector)?; - let frame = inspector - .into_geth_builder() - .geth_prestate_traces(&res, prestate_config, db)?; - Ok(frame) - }) - .await?; + let (res, _) = + this.eth_api().inspect(&mut *db, env, &mut inspector)?; + let frame = inspector + .into_geth_builder() + .geth_prestate_traces(&res, prestate_config, db) + .map_err(Eth::Error::from_eth_err)?; + Ok(frame) + }) + .await?; return Ok(frame.into()) } GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()), @@ -354,7 +362,8 @@ where .into_mux_config() .map_err(|_| EthApiError::InvalidTracerConfig)?; - let mut inspector = MuxInspector::try_from_config(mux_config)?; + let mut inspector = MuxInspector::try_from_config(mux_config) + .map_err(Eth::Error::from_eth_err)?; let frame = self .inner @@ -366,7 +375,9 @@ where let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?; - let frame = inspector.try_into_mux_frame(&res, db)?; + let frame = inspector + .try_into_mux_frame(&res, db) + .map_err(Eth::Error::from_eth_err)?; Ok(frame.into()) }) .await?; @@ -386,10 +397,11 @@ where // let db = db.0; - let mut inspector = JsInspector::new(code, config)?; + let mut inspector = + JsInspector::new(code, config).map_err(Eth::Error::from_eth_err)?; let (res, _) = this.eth_api().inspect(&mut *db, env.clone(), &mut inspector)?; - Ok(inspector.json_result(res, &env, db)?) + inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err) }) .await?; @@ -426,9 +438,9 @@ where bundles: Vec, state_context: Option, opts: Option, - ) -> EthResult>> { + ) -> Result>, Eth::Error> { if bundles.is_empty() { - return Err(EthApiError::InvalidParams(String::from("bundles are empty."))) + return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into()) } let StateContext { transaction_index, block_number } = state_context.unwrap_or_default(); @@ -546,7 +558,7 @@ where env: EnvWithHandlerCfg, db: &mut StateCacheDb<'_>, transaction_context: Option, - ) -> EthResult<(GethTrace, revm_primitives::EvmState)> { + ) -> Result<(GethTrace, revm_primitives::EvmState), Eth::Error> { let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts; if let Some(tracer) = tracer { @@ -584,11 +596,10 @@ where ); let (res, _) = self.eth_api().inspect(&mut *db, env, &mut inspector)?; - let frame = inspector.into_geth_builder().geth_prestate_traces( - &res, - prestate_config, - db, - )?; + let frame = inspector + .into_geth_builder() + .geth_prestate_traces(&res, prestate_config, db) + .map_err(Eth::Error::from_eth_err)?; return Ok((frame.into(), res.state)) } @@ -600,10 +611,13 @@ where .into_mux_config() .map_err(|_| EthApiError::InvalidTracerConfig)?; - let mut inspector = MuxInspector::try_from_config(mux_config)?; + let mut inspector = MuxInspector::try_from_config(mux_config) + .map_err(Eth::Error::from_eth_err)?; let (res, _) = self.eth_api().inspect(&mut *db, env, &mut inspector)?; - let frame = inspector.try_into_mux_frame(&res, db)?; + let frame = inspector + .try_into_mux_frame(&res, db) + .map_err(Eth::Error::from_eth_err)?; return Ok((frame.into(), res.state)) } }, @@ -613,11 +627,13 @@ where code, config, transaction_context.unwrap_or_default(), - )?; + ) + .map_err(Eth::Error::from_eth_err)?; let (res, env) = self.eth_api().inspect(&mut *db, env, &mut inspector)?; let state = res.state.clone(); - let result = inspector.json_result(res, &env, db)?; + let result = + inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err)?; Ok((GethTrace::JS(result), state)) } } @@ -690,7 +706,7 @@ where /// /// Returns the bytes of the transaction for the given hash. async fn raw_transaction(&self, hash: B256) -> RpcResult> { - Ok(self.inner.eth_api.raw_transaction_by_hash(hash).await?) + self.inner.eth_api.raw_transaction_by_hash(hash).await.map_err(Into::into) } /// Handler for `debug_getRawTransactions` @@ -739,7 +755,9 @@ where opts: Option, ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default()).await?) + Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default()) + .await + .map_err(Into::into) } /// Handler for `debug_traceBlockByHash` @@ -749,7 +767,9 @@ where opts: Option, ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_block(self, block.into(), opts.unwrap_or_default()).await?) + Self::debug_trace_block(self, block.into(), opts.unwrap_or_default()) + .await + .map_err(Into::into) } /// Handler for `debug_traceBlockByNumber` @@ -759,7 +779,9 @@ where opts: Option, ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_block(self, block.into(), opts.unwrap_or_default()).await?) + Self::debug_trace_block(self, block.into(), opts.unwrap_or_default()) + .await + .map_err(Into::into) } /// Handler for `debug_traceTransaction` @@ -769,7 +791,9 @@ where opts: Option, ) -> RpcResult { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default()).await?) + Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default()) + .await + .map_err(Into::into) } /// Handler for `debug_traceCall` @@ -780,7 +804,9 @@ where opts: Option, ) -> RpcResult { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_call(self, request, block_number, opts.unwrap_or_default()).await?) + Self::debug_trace_call(self, request, block_number, opts.unwrap_or_default()) + .await + .map_err(Into::into) } async fn debug_trace_call_many( @@ -790,7 +816,7 @@ where opts: Option, ) -> RpcResult>> { let _permit = self.acquire_trace_permit().await; - Ok(Self::debug_trace_call_many(self, bundles, state_context, opts).await?) + Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into) } async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> { diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index d28013822..9cabc1f6f 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -10,6 +10,7 @@ use reth_primitives::{ PooledTransactionsElement, U256, }; use reth_revm::database::StateProviderDatabase; +use reth_rpc_eth_api::{FromEthApiError, FromEvmError}; use reth_rpc_types::mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult}; use reth_tasks::pool::BlockingTaskGuard; use revm::{ @@ -23,9 +24,7 @@ use reth_rpc_eth_api::{ helpers::{Call, EthTransactions, LoadPendingBlock}, EthCallBundleApiServer, }; -use reth_rpc_eth_types::{ - utils::recover_raw_transaction, EthApiError, EthResult, RpcInvalidTransactionError, -}; +use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError, RpcInvalidTransactionError}; /// `Eth` bundle implementation. pub struct EthBundle { @@ -48,7 +47,10 @@ where /// another (or the same) block. This can be used to simulate future blocks with the current /// state, or it can be used to simulate a past block. The sender is responsible for signing the /// transactions and using the correct nonce and ensuring validity - pub async fn call_bundle(&self, bundle: EthCallBundle) -> EthResult { + pub async fn call_bundle( + &self, + bundle: EthCallBundle, + ) -> Result { let EthCallBundle { txs, block_number, @@ -61,12 +63,14 @@ where if txs.is_empty() { return Err(EthApiError::InvalidParams( EthBundleError::EmptyBundleTransactions.to_string(), - )) + ) + .into()) } if block_number == 0 { return Err(EthApiError::InvalidParams( EthBundleError::BundleMissingBlockNumber.to_string(), - )) + ) + .into()) } let transactions = txs @@ -93,7 +97,8 @@ where { return Err(EthApiError::InvalidParams( EthBundleError::Eip4844BlobGasExceeded.to_string(), - )) + ) + .into()) } let block_id: reth_rpc_types::BlockId = state_block_number.into(); @@ -121,7 +126,8 @@ where let parent_block = block_env.number.saturating_to::(); // here we need to fetch the _next_ block's basefee based on the parent block let parent = LoadPendingBlock::provider(&self.inner.eth_api) - .header_by_number(parent_block)? + .header_by_number(parent_block) + .map_err(Eth::Error::from_eth_err)? .ok_or_else(|| EthApiError::UnknownBlockNumber)?; if let Some(base_fee) = parent.next_block_base_fee( LoadPendingBlock::provider(&self.inner.eth_api) @@ -146,7 +152,8 @@ where let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, TxEnv::default()); let db = CacheDB::new(StateProviderDatabase::new(state)); - let initial_coinbase = DatabaseRef::basic_ref(&db, coinbase)? + let initial_coinbase = DatabaseRef::basic_ref(&db, coinbase) + .map_err(Eth::Error::from_eth_err)? .map(|acc| acc.balance) .unwrap_or_default(); let mut coinbase_balance_before_tx = initial_coinbase; @@ -164,8 +171,9 @@ where // Verify that the given blob data, commitments, and proofs are all valid for // this transaction. if let PooledTransactionsElement::BlobTransaction(ref tx) = tx { - tx.validate(EnvKzgSettings::Default.get()) - .map_err(|e| EthApiError::InvalidParams(e.to_string()))?; + tx.validate(EnvKzgSettings::Default.get()).map_err(|e| { + Eth::Error::from_eth_err(EthApiError::InvalidParams(e.to_string())) + })?; } let tx = tx.into_transaction(); @@ -173,9 +181,11 @@ where hash_bytes.extend_from_slice(tx.hash().as_slice()); let gas_price = tx .effective_tip_per_gas(basefee) - .ok_or_else(|| RpcInvalidTransactionError::FeeCapTooLow)?; + .ok_or_else(|| RpcInvalidTransactionError::FeeCapTooLow) + .map_err(Eth::Error::from_eth_err)?; Call::evm_config(ð_api).fill_tx_env(evm.tx_mut(), &tx, signer); - let ResultAndState { result, state } = evm.transact()?; + let ResultAndState { result, state } = + evm.transact().map_err(Eth::Error::from_evm_err)?; let gas_used = result.gas_used(); total_gas_used += gas_used; @@ -254,7 +264,7 @@ where Eth: EthTransactions + LoadPendingBlock + Call + 'static, { async fn call_bundle(&self, request: EthCallBundle) -> RpcResult { - Ok(Self::call_bundle(self, request).await?) + Self::call_bundle(self, request).await.map_err(Into::into) } } diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 09065dfc1..590d73f7f 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -10,10 +10,11 @@ use reth_primitives::{BlockNumberOrTag, U256}; use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; use reth_rpc_eth_api::{ helpers::{transaction::UpdateRawTxForwarder, EthSigner, SpawnBlocking}, - RawTransactionForwarder, + EthApiTypes, RawTransactionForwarder, }; use reth_rpc_eth_types::{ - EthApiBuilderCtx, EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock, + EthApiBuilderCtx, EthApiError, EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, + PendingBlock, }; use reth_tasks::{ pool::{BlockingTaskGuard, BlockingTaskPool}, @@ -114,6 +115,13 @@ where } } +impl EthApiTypes for EthApi +where + Self: Send + Sync, +{ + type Error = EthApiError; +} + impl std::fmt::Debug for EthApi { @@ -131,7 +139,7 @@ impl Clone for EthApi SpawnBlocking for EthApi where - Self: Clone + Send + Sync + 'static, + Self: EthApiTypes + Clone + Send + Sync + 'static, { #[inline] fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner { diff --git a/crates/rpc/rpc/src/eth/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs index db1fee781..eb4483705 100644 --- a/crates/rpc/rpc/src/eth/helpers/receipt.rs +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -1,13 +1,13 @@ //! Builds an RPC receipt response w.r.t. data layout of network. -use reth_rpc_eth_api::helpers::LoadReceipt; +use reth_rpc_eth_api::{helpers::LoadReceipt, EthApiTypes}; use reth_rpc_eth_types::EthStateCache; use crate::EthApi; impl LoadReceipt for EthApi where - Self: Send + Sync, + Self: EthApiTypes, { #[inline] fn cache(&self) -> &EthStateCache { diff --git a/crates/rpc/rpc/src/eth/helpers/state.rs b/crates/rpc/rpc/src/eth/helpers/state.rs index b291eb8a2..f76be9d88 100644 --- a/crates/rpc/rpc/src/eth/helpers/state.rs +++ b/crates/rpc/rpc/src/eth/helpers/state.rs @@ -3,7 +3,10 @@ use reth_provider::{ChainSpecProvider, StateProviderFactory}; use reth_transaction_pool::TransactionPool; -use reth_rpc_eth_api::helpers::{EthState, LoadState, SpawnBlocking}; +use reth_rpc_eth_api::{ + helpers::{EthState, LoadState, SpawnBlocking}, + EthApiTypes, +}; use reth_rpc_eth_types::EthStateCache; use crate::EthApi; @@ -19,6 +22,7 @@ where impl LoadState for EthApi where + Self: EthApiTypes, Provider: StateProviderFactory + ChainSpecProvider, Pool: TransactionPool, { diff --git a/crates/rpc/rpc/src/eth/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs index 872af0cee..635281c08 100644 --- a/crates/rpc/rpc/src/eth/helpers/transaction.rs +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -1,5 +1,7 @@ //! Contains RPC handler implementations specific to transactions +use std::sync::Arc; + use reth_provider::{BlockReaderIdExt, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, @@ -23,7 +25,7 @@ where } #[inline] - fn raw_tx_forwarder(&self) -> Option> { + fn raw_tx_forwarder(&self) -> Option> { self.inner.raw_tx_forwarder() } @@ -43,7 +45,7 @@ where type Pool = Pool; #[inline] - fn provider(&self) -> impl reth_provider::TransactionsProvider { + fn provider(&self) -> impl TransactionsProvider { self.inner.provider() } diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 320c6856d..bf8279719 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -85,7 +85,8 @@ where TransferInspector::new(false), |_tx_info, inspector, _, _| Ok(inspector.into_transfers()), ) - .await? + .await + .map_err(Into::into)? .map(|transfer_operations| { transfer_operations .iter() @@ -115,7 +116,8 @@ where _ => Ok(None), }) .await - .map(Option::flatten)?; + .map(Option::flatten) + .map_err(Into::into)?; Ok(maybe_revert) } @@ -128,7 +130,8 @@ where TracingInspectorConfig::default_parity(), move |_tx_info, inspector, _, _| Ok(inspector.into_traces().into_nodes()), ) - .await? + .await + .map_err(Into::into)? .map(|traces| { traces .into_iter() @@ -325,7 +328,8 @@ where Ok(inspector.into_parity_builder().into_localized_transaction_traces(tx_info)) }, ) - .await? + .await + .map_err(Into::into)? .map(|traces| { traces .into_iter() diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 57a557634..a69eb2d45 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, sync::Arc}; use async_trait::async_trait; -use jsonrpsee::core::RpcResult as Result; +use jsonrpsee::core::RpcResult; use reth_chainspec::EthereumHardforks; use reth_consensus_common::calc::{ base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward, @@ -11,11 +11,11 @@ use reth_primitives::{BlockId, Bytes, Header, B256, U256}; use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::TraceApiServer; -use reth_rpc_eth_api::helpers::{Call, TraceExt}; -use reth_rpc_eth_types::{ - error::{EthApiError, EthResult}, - utils::recover_raw_transaction, +use reth_rpc_eth_api::{ + helpers::{Call, TraceExt}, + FromEthApiError, }; +use reth_rpc_eth_types::{error::EthApiError, utils::recover_raw_transaction}; use reth_rpc_types::{ state::{EvmOverrides, StateOverride}, trace::{ @@ -79,7 +79,10 @@ where Eth: TraceExt + 'static, { /// Executes the given call and returns a number of possible traces for it. - pub async fn trace_call(&self, trace_request: TraceCallRequest) -> EthResult { + pub async fn trace_call( + &self, + trace_request: TraceCallRequest, + ) -> Result { let at = trace_request.block_id.unwrap_or_default(); let config = TracingInspectorConfig::from_parity_config(&trace_request.trace_types); let overrides = @@ -93,11 +96,10 @@ where let db = db.0; let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?; - let trace_res = inspector.into_parity_builder().into_trace_results_with_state( - &res, - &trace_request.trace_types, - &db, - )?; + let trace_res = inspector + .into_parity_builder() + .into_trace_results_with_state(&res, &trace_request.trace_types, &db) + .map_err(Eth::Error::from_eth_err)?; Ok(trace_res) }) .await @@ -109,7 +111,7 @@ where tx: Bytes, trace_types: HashSet, block_id: Option, - ) -> EthResult { + ) -> Result { let tx = recover_raw_transaction(tx)?; let (cfg, block, at) = self.inner.eth_api.evm_env_at(block_id.unwrap_or_default()).await?; @@ -125,11 +127,10 @@ where self.inner .eth_api .spawn_trace_at_with_state(env, config, at, move |inspector, res, db| { - Ok(inspector.into_parity_builder().into_trace_results_with_state( - &res, - &trace_types, - &db, - )?) + inspector + .into_parity_builder() + .into_trace_results_with_state(&res, &trace_types, &db) + .map_err(Eth::Error::from_eth_err) }) .await } @@ -142,7 +143,7 @@ where &self, calls: Vec<(TransactionRequest, HashSet)>, block_id: Option, - ) -> EthResult> { + ) -> Result, Eth::Error> { let at = block_id.unwrap_or(BlockId::pending()); let (cfg, block_env, at) = self.inner.eth_api.evm_env_at(at).await?; @@ -169,11 +170,10 @@ where let mut inspector = TracingInspector::new(config); let (res, _) = this.eth_api().inspect(&mut db, env, &mut inspector)?; - let trace_res = inspector.into_parity_builder().into_trace_results_with_state( - &res, - &trace_types, - &db, - )?; + let trace_res = inspector + .into_parity_builder() + .into_trace_results_with_state(&res, &trace_types, &db) + .map_err(Eth::Error::from_eth_err)?; results.push(trace_res); @@ -196,16 +196,15 @@ where &self, hash: B256, trace_types: HashSet, - ) -> EthResult { + ) -> Result { let config = TracingInspectorConfig::from_parity_config(&trace_types); self.inner .eth_api .spawn_trace_transaction_in_block(hash, config, move |_, inspector, res, db| { - let trace_res = inspector.into_parity_builder().into_trace_results_with_state( - &res, - &trace_types, - &db, - )?; + let trace_res = inspector + .into_parity_builder() + .into_trace_results_with_state(&res, &trace_types, &db) + .map_err(Eth::Error::from_eth_err)?; Ok(trace_res) }) .await @@ -223,7 +222,7 @@ where &self, hash: B256, indices: Vec, - ) -> EthResult> { + ) -> Result, Eth::Error> { if indices.len() != 1 { // The OG impl failed if it gets more than a single index return Ok(None) @@ -238,7 +237,7 @@ where &self, hash: B256, index: usize, - ) -> EthResult> { + ) -> Result, Eth::Error> { Ok(self.trace_transaction(hash).await?.and_then(|traces| traces.into_iter().nth(index))) } @@ -249,20 +248,21 @@ where pub async fn trace_filter( &self, filter: TraceFilter, - ) -> EthResult> { + ) -> Result, Eth::Error> { let matcher = filter.matcher(); let TraceFilter { from_block, to_block, after, count, .. } = filter; let start = from_block.unwrap_or(0); let end = if let Some(to_block) = to_block { to_block } else { - self.provider().best_block_number()? + self.provider().best_block_number().map_err(Eth::Error::from_eth_err)? }; if start > end { return Err(EthApiError::InvalidParams( "invalid parameters: fromBlock cannot be greater than toBlock".to_string(), - )) + ) + .into()) } // ensure that the range is not too large, since we need to fetch all blocks in the range @@ -270,11 +270,12 @@ where if distance > 100 { return Err(EthApiError::InvalidParams( "Block range too large; currently limited to 100 blocks".to_string(), - )) + ) + .into()) } // fetch all blocks in that range - let blocks = self.provider().block_range(start..=end)?; + let blocks = self.provider().block_range(start..=end).map_err(Eth::Error::from_eth_err)?; // find relevant blocks to trace let mut target_blocks = Vec::new(); @@ -282,7 +283,10 @@ where let mut transaction_indices = HashSet::new(); let mut highest_matching_index = 0; for (tx_idx, tx) in block.body.iter().enumerate() { - let from = tx.recover_signer_unchecked().ok_or(BlockError::InvalidSignature)?; + let from = tx + .recover_signer_unchecked() + .ok_or(BlockError::InvalidSignature) + .map_err(Eth::Error::from_eth_err)?; let to = tx.to(); if matcher.matches(from, to) { let idx = tx_idx as u64; @@ -362,7 +366,7 @@ where pub async fn trace_transaction( &self, hash: B256, - ) -> EthResult>> { + ) -> Result>, Eth::Error> { self.inner .eth_api .spawn_trace_transaction_in_block( @@ -383,7 +387,7 @@ where pub async fn trace_block( &self, block_id: BlockId, - ) -> EthResult>> { + ) -> Result>, Eth::Error> { let traces = self.inner.eth_api.trace_block_with( block_id, TracingInspectorConfig::default_parity(), @@ -420,7 +424,7 @@ where &self, block_id: BlockId, trace_types: HashSet, - ) -> EthResult>> { + ) -> Result>, Eth::Error> { self.inner .eth_api .trace_block_with( @@ -433,7 +437,8 @@ where // If statediffs were requested, populate them with the account balance and // nonce from pre-state if let Some(ref mut state_diff) = full_trace.state_diff { - populate_state_diff(state_diff, db, state.iter())?; + populate_state_diff(state_diff, db, state.iter()) + .map_err(Eth::Error::from_eth_err)?; } let trace = TraceResultsWithTransactionHash { @@ -451,7 +456,7 @@ where pub async fn trace_transaction_opcode_gas( &self, tx_hash: B256, - ) -> EthResult> { + ) -> Result, Eth::Error> { self.inner .eth_api .spawn_trace_transaction_in_block_with_inspector( @@ -475,7 +480,7 @@ where pub async fn trace_block_opcode_gas( &self, block_id: BlockId, - ) -> EthResult> { + ) -> Result, Eth::Error> { let res = self .inner .eth_api @@ -508,7 +513,7 @@ where /// - if Paris hardfork is activated, no block rewards are given /// - if Paris hardfork is not activated, calculate block rewards with block number only /// - if Paris hardfork is unknown, calculate block rewards with block number and ttd - fn calculate_base_block_reward(&self, header: &Header) -> EthResult> { + fn calculate_base_block_reward(&self, header: &Header) -> Result, Eth::Error> { let chain_spec = self.provider().chain_spec(); let is_paris_activated = chain_spec.is_paris_active_at_block(header.number); @@ -518,7 +523,11 @@ where None => { // if Paris hardfork is unknown, we need to fetch the total difficulty at the // block's height and check if it is pre-merge to calculate the base block reward - if let Some(header_td) = self.provider().header_td_by_number(header.number)? { + if let Some(header_td) = self + .provider() + .header_td_by_number(header.number) + .map_err(Eth::Error::from_eth_err)? + { base_block_reward( chain_spec.as_ref(), header.number, @@ -584,11 +593,11 @@ where block_id: Option, state_overrides: Option, block_overrides: Option>, - ) -> Result { + ) -> RpcResult { let _permit = self.acquire_trace_permit().await; let request = TraceCallRequest { call, trace_types, block_id, state_overrides, block_overrides }; - Ok(Self::trace_call(self, request).await?) + Ok(Self::trace_call(self, request).await.map_err(Into::into)?) } /// Handler for `trace_callMany` @@ -596,9 +605,9 @@ where &self, calls: Vec<(TransactionRequest, HashSet)>, block_id: Option, - ) -> Result> { + ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_call_many(self, calls, block_id).await?) + Ok(Self::trace_call_many(self, calls, block_id).await.map_err(Into::into)?) } /// Handler for `trace_rawTransaction` @@ -607,9 +616,11 @@ where data: Bytes, trace_types: HashSet, block_id: Option, - ) -> Result { + ) -> RpcResult { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_raw_transaction(self, data, trace_types, block_id).await?) + Ok(Self::trace_raw_transaction(self, data, trace_types, block_id) + .await + .map_err(Into::into)?) } /// Handler for `trace_replayBlockTransactions` @@ -617,9 +628,11 @@ where &self, block_id: BlockId, trace_types: HashSet, - ) -> Result>> { + ) -> RpcResult>> { let _permit = self.acquire_trace_permit().await; - Ok(Self::replay_block_transactions(self, block_id, trace_types).await?) + Ok(Self::replay_block_transactions(self, block_id, trace_types) + .await + .map_err(Into::into)?) } /// Handler for `trace_replayTransaction` @@ -627,18 +640,18 @@ where &self, transaction: B256, trace_types: HashSet, - ) -> Result { + ) -> RpcResult { let _permit = self.acquire_trace_permit().await; - Ok(Self::replay_transaction(self, transaction, trace_types).await?) + Ok(Self::replay_transaction(self, transaction, trace_types).await.map_err(Into::into)?) } /// Handler for `trace_block` async fn trace_block( &self, block_id: BlockId, - ) -> Result>> { + ) -> RpcResult>> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_block(self, block_id).await?) + Ok(Self::trace_block(self, block_id).await.map_err(Into::into)?) } /// Handler for `trace_filter` @@ -647,8 +660,8 @@ where /// /// # Limitations /// This currently requires block filter fields, since reth does not have address indices yet. - async fn trace_filter(&self, filter: TraceFilter) -> Result> { - Ok(Self::trace_filter(self, filter).await?) + async fn trace_filter(&self, filter: TraceFilter) -> RpcResult> { + Ok(Self::trace_filter(self, filter).await.map_err(Into::into)?) } /// Returns transaction trace at given index. @@ -657,33 +670,35 @@ where &self, hash: B256, indices: Vec, - ) -> Result> { + ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_get(self, hash, indices.into_iter().map(Into::into).collect()).await?) + Ok(Self::trace_get(self, hash, indices.into_iter().map(Into::into).collect()) + .await + .map_err(Into::into)?) } /// Handler for `trace_transaction` async fn trace_transaction( &self, hash: B256, - ) -> Result>> { + ) -> RpcResult>> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_transaction(self, hash).await?) + Ok(Self::trace_transaction(self, hash).await.map_err(Into::into)?) } /// Handler for `trace_transactionOpcodeGas` async fn trace_transaction_opcode_gas( &self, tx_hash: B256, - ) -> Result> { + ) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_transaction_opcode_gas(self, tx_hash).await?) + Ok(Self::trace_transaction_opcode_gas(self, tx_hash).await.map_err(Into::into)?) } /// Handler for `trace_blockOpcodeGas` - async fn trace_block_opcode_gas(&self, block_id: BlockId) -> Result> { + async fn trace_block_opcode_gas(&self, block_id: BlockId) -> RpcResult> { let _permit = self.acquire_trace_permit().await; - Ok(Self::trace_block_opcode_gas(self, block_id).await?) + Ok(Self::trace_block_opcode_gas(self, block_id).await.map_err(Into::into)?) } } diff --git a/crates/stages/stages/src/stages/utils.rs b/crates/stages/stages/src/stages/utils.rs index 3b623c358..15e88a284 100644 --- a/crates/stages/stages/src/stages/utils.rs +++ b/crates/stages/stages/src/stages/utils.rs @@ -186,7 +186,7 @@ where Ok(()) } -/// Shard and insert the indice list according to [`LoadMode`] and its length. +/// Shard and insert the indices list according to [`LoadMode`] and its length. pub(crate) fn load_indices( cursor: &mut C, partial_key: P,