mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(rpc): EthApiTypes trait for network specific error AT (#9523)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<B256> {
|
||||
pub async fn inject_tx(&mut self, raw_tx: Bytes) -> Result<B256, EthApi::Error> {
|
||||
let eth_api = self.inner.eth_api();
|
||||
eth_api.send_raw_transaction(raw_tx).await
|
||||
}
|
||||
|
||||
@ -84,7 +84,6 @@ optimism = [
|
||||
"reth-provider/optimism",
|
||||
"reth-rpc-types-compat/optimism",
|
||||
"reth-rpc-eth-api/optimism",
|
||||
"reth-rpc-eth-types/optimism",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -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"
|
||||
]
|
||||
@ -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<OpEthApiError> for EthApiError {
|
||||
impl From<OpEthApiError> 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<OptimismInvalidTransactionError> 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<InvalidTransaction> for OptimismInvalidTransactionError {
|
||||
type Error = InvalidTransaction;
|
||||
|
||||
fn try_from(err: InvalidTransaction) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
InvalidTransaction::OptimismError(err) => match err {
|
||||
OptimismInvalidTransaction::DepositSystemTxPostRegolith => {
|
||||
Ok(Self::DepositSystemTxPostRegolith)
|
||||
}
|
||||
OptimismInvalidTransaction::HaltedDepositPostRegolith => {
|
||||
Ok(Self::HaltedDepositPostRegolith)
|
||||
}
|
||||
},
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Option<Vec<AnyTransactionReceipt>>>
|
||||
) -> Result<Option<Vec<AnyTransactionReceipt>>, 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::<EthResult<Vec<_>>>();
|
||||
.collect::<Result<Vec<_>, Self::Error>>();
|
||||
return receipts.map(Some)
|
||||
}
|
||||
|
||||
|
||||
@ -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<Eth: Call> Call for OpEthApi<Eth> {
|
||||
impl<Eth: EthCall> EthCall for OpEthApi<Eth> where EthApiError: From<Eth::Error> {}
|
||||
|
||||
impl<Eth> Call for OpEthApi<Eth>
|
||||
where
|
||||
Eth: Call + EthApiTypes,
|
||||
EthApiError: From<Eth::Error>,
|
||||
{
|
||||
fn call_gas_limit(&self) -> u64 {
|
||||
self.inner.call_gas_limit()
|
||||
}
|
||||
@ -22,8 +31,9 @@ impl<Eth: Call> Call for OpEthApi<Eth> {
|
||||
&self,
|
||||
block_env: &BlockEnv,
|
||||
request: TransactionRequest,
|
||||
) -> EthResult<TxEnv> {
|
||||
let mut env = Eth::create_txn_env(&self.inner, block_env, request)?;
|
||||
) -> Result<TxEnv, Self::Error> {
|
||||
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() };
|
||||
|
||||
|
||||
@ -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<Eth> OpEthApi<Eth> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Eth> EthApiTypes for OpEthApi<Eth>
|
||||
where
|
||||
Eth: Send + Sync,
|
||||
{
|
||||
type Error = OpEthApiError;
|
||||
}
|
||||
|
||||
impl<Eth: EthApiSpec> EthApiSpec for OpEthApi<Eth> {
|
||||
fn protocol_version(&self) -> impl Future<Output = RethResult<U64>> + Send {
|
||||
self.inner.protocol_version()
|
||||
@ -142,8 +151,6 @@ impl<Eth: EthState> EthState for OpEthApi<Eth> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Eth: EthCall> EthCall for OpEthApi<Eth> {}
|
||||
|
||||
impl<Eth: EthFees> EthFees for OpEthApi<Eth> {}
|
||||
|
||||
impl<Eth: Trace> Trace for OpEthApi<Eth> {
|
||||
|
||||
@ -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<AnyTransactionReceipt> {
|
||||
) -> Result<AnyTransactionReceipt, Self::Error> {
|
||||
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())
|
||||
|
||||
@ -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<L1BlockInfo>,
|
||||
block_timestamp: u64,
|
||||
) -> EthResult<OptimismTxMeta> {
|
||||
) -> Result<OptimismTxMeta, <Self as EthApiTypes>::Error> {
|
||||
let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) };
|
||||
|
||||
let (l1_fee, l1_data_gas) = if !tx.is_deposit() {
|
||||
|
||||
@ -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"
|
||||
]
|
||||
|
||||
@ -334,7 +334,8 @@ pub trait EthApi {
|
||||
#[async_trait::async_trait]
|
||||
impl<T> EthApiServer for T
|
||||
where
|
||||
Self: FullEthApi,
|
||||
T: FullEthApi,
|
||||
jsonrpsee_types::error::ErrorObject<'static>: From<T::Error>,
|
||||
{
|
||||
/// Handler for: `eth_protocolVersion`
|
||||
async fn protocol_version(&self) -> RpcResult<U64> {
|
||||
|
||||
@ -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<Output = EthResult<Option<Header>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Header>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock + SpawnBlocking,
|
||||
{
|
||||
@ -38,7 +40,7 @@ pub trait EthBlocks: LoadBlock {
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
full: bool,
|
||||
) -> impl Future<Output = EthResult<Option<RichBlock>>> + Send
|
||||
) -> impl Future<Output = Result<Option<RichBlock>, 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<Output = EthResult<Option<usize>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<usize>, 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<Output = EthResult<Option<Vec<AnyTransactionReceipt>>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Vec<AnyTransactionReceipt>>, 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::<EthResult<Vec<_>>>();
|
||||
.collect::<Result<Vec<_>, 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<Output = EthResult<Option<(SealedBlock, Arc<Vec<Receipt>>)>>> + Send
|
||||
) -> impl Future<Output = Result<Option<(SealedBlock, Arc<Vec<Receipt>>)>, 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<Option<Vec<reth_primitives::Header>>> {
|
||||
Ok(LoadBlock::provider(self).ommers_by_id(block_id)?)
|
||||
fn ommers(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<Option<Vec<reth_primitives::Header>>, 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<Output = EthResult<Option<RichBlock>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<RichBlock>, 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<Output = EthResult<Option<SealedBlock>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<SealedBlock>, 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<Output = EthResult<Option<SealedBlockWithSenders>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<SealedBlockWithSenders>, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
|
||||
fn spawn_blocking_io<F, R>(&self, f: F) -> impl Future<Output = Result<R, Self::Error>> + Send
|
||||
where
|
||||
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
|
||||
F: FnOnce(Self) -> Result<R, Self::Error> + 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
|
||||
/// <https://ryhl.io/blog/async-what-is-blocking/>.
|
||||
fn spawn_tracing<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
|
||||
fn spawn_tracing<F, R>(&self, f: F) -> impl Future<Output = Result<R, Self::Error>> + Send
|
||||
where
|
||||
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
|
||||
F: FnOnce(Self) -> Result<R, Self::Error> + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let this = self.clone();
|
||||
|
||||
@ -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<StateOverride>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + Send {
|
||||
Call::estimate_gas_at(self, request, at, state_override)
|
||||
}
|
||||
|
||||
@ -54,12 +56,12 @@ pub trait EthCall: Call + LoadPendingBlock {
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
overrides: EvmOverrides,
|
||||
) -> impl Future<Output = EthResult<Bytes>> + Send {
|
||||
) -> impl Future<Output = Result<Bytes, Self::Error>> + 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<StateContext>,
|
||||
mut state_override: Option<StateOverride>,
|
||||
) -> impl Future<Output = EthResult<Vec<EthCallResponse>>> + Send
|
||||
) -> impl Future<Output = Result<Vec<EthCallResponse>, 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<BlockId>,
|
||||
) -> impl Future<Output = EthResult<AccessListWithGasUsed>> + Send
|
||||
) -> impl Future<Output = Result<AccessListWithGasUsed, Self::Error>> + Send
|
||||
where
|
||||
Self: Trace,
|
||||
{
|
||||
@ -202,7 +208,7 @@ pub trait EthCall: Call + LoadPendingBlock {
|
||||
block: BlockEnv,
|
||||
at: BlockId,
|
||||
mut request: TransactionRequest,
|
||||
) -> EthResult<AccessListWithGasUsed>
|
||||
) -> Result<AccessListWithGasUsed, Self::Error>
|
||||
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<F, T>(&self, at: BlockId, f: F) -> EthResult<T>
|
||||
fn with_state_at_block<F, R>(&self, at: BlockId, f: F) -> Result<R, Self::Error>
|
||||
where
|
||||
F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult<T>,
|
||||
F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error>,
|
||||
{
|
||||
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,
|
||||
<DB as Database>::Error: Into<EthApiError>,
|
||||
EthApiError: From<DB::Error>,
|
||||
{
|
||||
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<Output = EthResult<(ResultAndState, EnvWithHandlerCfg)>> + Send
|
||||
) -> impl Future<Output = Result<(ResultAndState, EnvWithHandlerCfg), Self::Error>> + 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<F, T>(
|
||||
fn spawn_with_state_at_block<F, R>(
|
||||
&self,
|
||||
at: BlockId,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<T>> + Send
|
||||
) -> impl Future<Output = Result<R, Self::Error>> + Send
|
||||
where
|
||||
F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult<T> + Send + 'static,
|
||||
T: Send + 'static,
|
||||
F: FnOnce(StateProviderTraitObjWrapper<'_>) -> Result<R, Self::Error> + 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<Output = EthResult<R>> + Send
|
||||
) -> impl Future<Output = Result<R, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock,
|
||||
F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> EthResult<R>
|
||||
F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> Result<R, Self::Error>
|
||||
+ 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<Output = EthResult<Option<R>>> + Send
|
||||
) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadBlock + LoadPendingBlock + LoadTransaction,
|
||||
F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> EthResult<R>
|
||||
F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
R: Send + 'static,
|
||||
@ -453,10 +461,10 @@ pub trait Call: LoadState + SpawnBlocking {
|
||||
block_env: BlockEnv,
|
||||
transactions: impl IntoIterator<Item = TransactionSignedEcRecovered>,
|
||||
target_tx_hash: B256,
|
||||
) -> Result<usize, EthApiError>
|
||||
) -> Result<usize, Self::Error>
|
||||
where
|
||||
DB: DatabaseRef,
|
||||
EthApiError: From<<DB as DatabaseRef>::Error>,
|
||||
EthApiError: From<DB::Error>,
|
||||
{
|
||||
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<StateOverride>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock,
|
||||
{
|
||||
@ -507,7 +515,7 @@ pub trait Call: LoadState + SpawnBlocking {
|
||||
request: TransactionRequest,
|
||||
state: S,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> EthResult<U256>
|
||||
) -> Result<U256, Self::Error>
|
||||
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<StateProviderDatabase<S>>,
|
||||
) -> 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<TxEnv> {
|
||||
) -> Result<TxEnv, Self::Error> {
|
||||
// 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<EnvWithHandlerCfg> {
|
||||
) -> Result<EnvWithHandlerCfg, Self::Error> {
|
||||
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<DB>,
|
||||
overrides: EvmOverrides,
|
||||
) -> EthResult<EnvWithHandlerCfg>
|
||||
) -> Result<EnvWithHandlerCfg, Self::Error>
|
||||
where
|
||||
DB: DatabaseRef,
|
||||
EthApiError: From<<DB as DatabaseRef>::Error>,
|
||||
|
||||
88
crates/rpc/rpc-eth-api/src/helpers/error.rs
Normal file
88
crates/rpc/rpc-eth-api/src/helpers/error.rs
Normal file
@ -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<EthApiError> {
|
||||
/// Converts from error via [`EthApiError`].
|
||||
fn from_eth_err<E>(err: E) -> Self
|
||||
where
|
||||
EthApiError: From<E>;
|
||||
}
|
||||
|
||||
impl<T> FromEthApiError for T
|
||||
where
|
||||
T: From<EthApiError>,
|
||||
{
|
||||
fn from_eth_err<E>(err: E) -> Self
|
||||
where
|
||||
EthApiError: From<E>,
|
||||
{
|
||||
T::from(EthApiError::from(err))
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait to wrap core [`EthApiError`].
|
||||
pub trait IntoEthApiError: Into<EthApiError> {
|
||||
/// Converts into error via [`EthApiError`].
|
||||
fn into_eth_err<E>(self) -> E
|
||||
where
|
||||
E: FromEthApiError;
|
||||
}
|
||||
|
||||
impl<T> IntoEthApiError for T
|
||||
where
|
||||
EthApiError: From<T>,
|
||||
{
|
||||
fn into_eth_err<E>(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<EthApiError> {
|
||||
/// Converts from a revm error.
|
||||
fn from_evm_err<E>(err: EVMError<E>) -> Self
|
||||
where
|
||||
EthApiError: From<E>;
|
||||
}
|
||||
|
||||
impl<T> FromEvmError for T
|
||||
where
|
||||
T: From<EthApiError>,
|
||||
{
|
||||
fn from_evm_err<E>(err: EVMError<E>) -> Self
|
||||
where
|
||||
EthApiError: From<E>,
|
||||
{
|
||||
err.into_eth_err()
|
||||
}
|
||||
}
|
||||
@ -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: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
|
||||
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send
|
||||
fn gas_price(&self) -> impl Future<Output = Result<U256, Self::Error>> + 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<Output = EthResult<U256>> + Send
|
||||
fn blob_base_fee(&self) -> impl Future<Output = Result<U256, Self::Error>> + 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<Output = EthResult<U256>> + Send
|
||||
fn suggested_priority_fee(&self) -> impl Future<Output = Result<U256, Self::Error>> + Send
|
||||
where
|
||||
Self: 'static,
|
||||
{
|
||||
@ -50,7 +52,7 @@ pub trait EthFees: LoadFee {
|
||||
mut block_count: u64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> impl Future<Output = EthResult<FeeHistory>> + Send {
|
||||
) -> impl Future<Output = Result<FeeHistory, Self::Error>> + 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<U256>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + 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<U256>,
|
||||
max_priority_fee_per_gas: Option<U256>,
|
||||
) -> impl Future<Output = EthResult<(U256, U256)>> + Send {
|
||||
) -> impl Future<Output = Result<(U256, U256), Self::Error>> + 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<U256>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + 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: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
|
||||
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
fn gas_price(&self) -> impl Future<Output = Result<U256, Self::Error>> + 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<Output = EthResult<U256>> + Send {
|
||||
fn blob_base_fee(&self) -> impl Future<Output = Result<U256, Self::Error>> + 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<Output = EthResult<U256>> + Send
|
||||
fn suggested_priority_fee(&self) -> impl Future<Output = Result<U256, Self::Error>> + 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) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<T> 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<T> FullEthApi for T where
|
||||
T: EthApiSpec
|
||||
T: EthApiTypes
|
||||
+ EthApiSpec
|
||||
+ EthTransactions
|
||||
+ EthBlocks
|
||||
+ EthState
|
||||
|
||||
@ -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<PendingBlockEnv> {
|
||||
fn pending_block_env_and_cfg(&self) -> Result<PendingBlockEnv, Self::Error> {
|
||||
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<Output = EthResult<Option<SealedBlockWithSenders>>> + Send
|
||||
) -> impl Future<Output = Result<Option<SealedBlockWithSenders>, 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<SealedBlockWithSenders> {
|
||||
fn build_block(&self, env: PendingBlockEnv) -> Result<SealedBlockWithSenders, Self::Error>
|
||||
where
|
||||
EthApiError: From<ProviderError>,
|
||||
{
|
||||
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);
|
||||
|
||||
@ -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<Output = EthResult<AnyTransactionReceipt>> + Send {
|
||||
) -> impl Future<Output = Result<AnyTransactionReceipt, Self::Error>> + 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())
|
||||
|
||||
@ -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<BlockId>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + Send {
|
||||
LoadState::transaction_count(self, address, block_id)
|
||||
}
|
||||
|
||||
@ -41,11 +41,12 @@ pub trait EthState: LoadState + SpawnBlocking {
|
||||
&self,
|
||||
address: Address,
|
||||
block_id: Option<BlockId>,
|
||||
) -> impl Future<Output = EthResult<Bytes>> + Send {
|
||||
) -> impl Future<Output = Result<Bytes, Self::Error>> + 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<BlockId>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + 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<BlockId>,
|
||||
) -> impl Future<Output = EthResult<B256>> + Send {
|
||||
) -> impl Future<Output = Result<B256, Self::Error>> + 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<JsonStorageKey>,
|
||||
block_id: Option<BlockId>,
|
||||
) -> EthResult<impl Future<Output = EthResult<EIP1186AccountProofResponse>> + Send>
|
||||
) -> Result<
|
||||
impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + 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::<Vec<_>>();
|
||||
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<StateProviderBox> {
|
||||
Ok(self.provider().history_by_block_hash(block_hash)?)
|
||||
fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
|
||||
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 <https://github.com/paradigmxyz/reth/issues/4515>
|
||||
fn state_at_block_id(&self, at: BlockId) -> EthResult<StateProviderBox> {
|
||||
Ok(self.provider().state_by_block_id(at)?)
|
||||
fn state_at_block_id(&self, at: BlockId) -> Result<StateProviderBox, Self::Error> {
|
||||
self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
|
||||
}
|
||||
|
||||
/// Returns the _latest_ state
|
||||
fn latest_state(&self) -> EthResult<StateProviderBox> {
|
||||
Ok(self.provider().latest()?)
|
||||
fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
|
||||
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<BlockId>,
|
||||
) -> EthResult<StateProviderBox> {
|
||||
) -> Result<StateProviderBox, Self::Error> {
|
||||
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<Output = EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)>> + Send
|
||||
) -> impl Future<Output = Result<(CfgEnvWithHandlerCfg, BlockEnv, BlockId), Self::Error>> + 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<Output = EthResult<(CfgEnvWithHandlerCfg, BlockEnv)>> + Send
|
||||
) -> impl Future<Output = Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock + SpawnBlocking,
|
||||
{
|
||||
@ -230,7 +244,7 @@ pub trait LoadState {
|
||||
&self,
|
||||
address: Address,
|
||||
block_id: Option<BlockId>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send
|
||||
) -> impl Future<Output = Result<U256, Self::Error>> + 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(),
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
<DB as Database>::Error: Into<EthApiError>,
|
||||
EthApiError: From<DB::Error>,
|
||||
I: GetInspector<DB>,
|
||||
{
|
||||
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,
|
||||
<DB as Database>::Error: Into<EthApiError>,
|
||||
EthApiError: From<DB::Error>,
|
||||
|
||||
I: GetInspector<DB>,
|
||||
{
|
||||
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<R>
|
||||
) -> Result<R, Self::Error>
|
||||
where
|
||||
Self: Call,
|
||||
F: FnOnce(TracingInspector, ResultAndState) -> EthResult<R>,
|
||||
F: FnOnce(TracingInspector, ResultAndState) -> Result<R, Self::Error>,
|
||||
{
|
||||
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<Output = EthResult<R>> + Send
|
||||
) -> impl Future<Output = Result<R, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock + Call,
|
||||
F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> EthResult<R>
|
||||
F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
R: Send + 'static,
|
||||
@ -130,7 +133,7 @@ pub trait Trace: LoadState {
|
||||
hash: B256,
|
||||
config: TracingInspectorConfig,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<R>>> + Send
|
||||
) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock + LoadTransaction + Call,
|
||||
F: FnOnce(
|
||||
@ -138,7 +141,7 @@ pub trait Trace: LoadState {
|
||||
TracingInspector,
|
||||
ResultAndState,
|
||||
StateCacheDb<'_>,
|
||||
) -> EthResult<R>
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
R: Send + 'static,
|
||||
@ -160,10 +163,15 @@ pub trait Trace: LoadState {
|
||||
hash: B256,
|
||||
mut inspector: Insp,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<R>>> + Send
|
||||
) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadPendingBlock + LoadTransaction + Call,
|
||||
F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDb<'_>) -> EthResult<R>
|
||||
F: FnOnce(
|
||||
TransactionInfo,
|
||||
Insp,
|
||||
ResultAndState,
|
||||
StateCacheDb<'_>,
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
Insp: for<'a, 'b> Inspector<StateCacheDbRefMutWrapper<'a, 'b>> + Send + 'static,
|
||||
@ -222,7 +230,7 @@ pub trait Trace: LoadState {
|
||||
highest_index: Option<u64>,
|
||||
config: TracingInspectorConfig,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<Vec<R>>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Vec<R>>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadBlock,
|
||||
F: Fn(
|
||||
@ -231,7 +239,7 @@ pub trait Trace: LoadState {
|
||||
ExecutionResult,
|
||||
&EvmState,
|
||||
&StateCacheDb<'_>,
|
||||
) -> EthResult<R>
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
R: Send + 'static,
|
||||
@ -260,10 +268,16 @@ pub trait Trace: LoadState {
|
||||
highest_index: Option<u64>,
|
||||
mut inspector_setup: Setup,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<Vec<R>>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Vec<R>>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadBlock,
|
||||
F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDb<'_>) -> EthResult<R>
|
||||
F: Fn(
|
||||
TransactionInfo,
|
||||
Insp,
|
||||
ExecutionResult,
|
||||
&EvmState,
|
||||
&StateCacheDb<'_>,
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
Setup: FnMut() -> Insp + Send + 'static,
|
||||
@ -360,7 +374,7 @@ pub trait Trace: LoadState {
|
||||
block_id: BlockId,
|
||||
config: TracingInspectorConfig,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<Vec<R>>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Vec<R>>, 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<R>
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
R: Send + 'static,
|
||||
@ -398,12 +412,18 @@ pub trait Trace: LoadState {
|
||||
block_id: BlockId,
|
||||
insp_setup: Setup,
|
||||
f: F,
|
||||
) -> impl Future<Output = EthResult<Option<Vec<R>>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Vec<R>>, 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<R>
|
||||
F: Fn(
|
||||
TransactionInfo,
|
||||
Insp,
|
||||
ExecutionResult,
|
||||
&EvmState,
|
||||
&StateCacheDb<'_>,
|
||||
) -> Result<R, Self::Error>
|
||||
+ Send
|
||||
+ 'static,
|
||||
Setup: FnMut() -> Insp + Send + 'static,
|
||||
|
||||
@ -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<Output = EthResult<Option<TransactionSource>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<TransactionSource>, 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<Output = EthResult<Option<Vec<TransactionSigned>>>> + Send {
|
||||
async move { Ok(self.cache().get_block_transactions(block).await?) }
|
||||
) -> impl Future<Output = Result<Option<Vec<TransactionSigned>>, 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<Output = EthResult<Option<Bytes>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<Bytes>, 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<Output = EthResult<Option<(TransactionSource, B256)>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<(TransactionSource, B256)>, 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<Output = EthResult<Option<AnyTransactionReceipt>>> + Send
|
||||
) -> impl Future<Output = Result<Option<AnyTransactionReceipt>, 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<Output = EthResult<Option<(TransactionSigned, TransactionMeta, Receipt)>>> + Send
|
||||
) -> impl Future<
|
||||
Output = Result<Option<(TransactionSigned, TransactionMeta, Receipt)>, 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<Output = EthResult<Option<Transaction>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Transaction>, Self::Error>> + Send
|
||||
where
|
||||
Self: LoadBlock,
|
||||
{
|
||||
@ -216,7 +228,7 @@ pub trait EthTransactions: LoadTransaction {
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
index: usize,
|
||||
) -> impl Future<Output = EthResult<Option<Bytes>>> + Send
|
||||
) -> impl Future<Output = Result<Option<Bytes>, 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<Output = EthResult<B256>> + Send {
|
||||
fn send_raw_transaction(
|
||||
&self,
|
||||
tx: Bytes,
|
||||
) -> impl Future<Output = Result<B256, Self::Error>> + 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<Output = EthResult<B256>> + Send
|
||||
) -> impl Future<Output = Result<B256, Self::Error>> + 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) => <<Self as LoadTransaction>::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<TransactionSigned> {
|
||||
) -> Result<TransactionSigned, Self::Error> {
|
||||
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<Output = EthResult<Bytes>> + Send {
|
||||
async move { Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes()) }
|
||||
) -> impl Future<Output = Result<Bytes, Self::Error>> + 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<Bytes> {
|
||||
Ok(self.find_signer(&account)?.sign_typed_data(account, data)?.to_hex_bytes())
|
||||
fn sign_typed_data(&self, data: &TypedData, account: Address) -> Result<Bytes, Self::Error> {
|
||||
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<Box<(dyn EthSigner + 'static)>, SignError> {
|
||||
fn find_signer(
|
||||
&self,
|
||||
account: &Address,
|
||||
) -> Result<Box<(dyn EthSigner + 'static)>, 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<Output = EthResult<Option<TransactionSource>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<TransactionSource>, 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<Output = EthResult<Option<(TransactionSource, BlockId)>>> + Send {
|
||||
) -> impl Future<Output = Result<Option<(TransactionSource, BlockId)>, 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<Output = EthResult<Option<(TransactionSource, SealedBlockWithSenders)>>> + Send
|
||||
{
|
||||
) -> impl Future<Output = Result<Option<(TransactionSource, SealedBlockWithSenders)>, 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))))
|
||||
}
|
||||
}
|
||||
|
||||
17
crates/rpc/rpc-eth-api/src/helpers/types.rs
Normal file
17
crates/rpc/rpc-eth-api/src/helpers/types.rs
Normal file
@ -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<jsonrpsee_types::error::ErrorObject<'static>>
|
||||
+ FromEthApiError
|
||||
+ AsEthApiError
|
||||
+ FromEvmError
|
||||
+ Error
|
||||
+ Send
|
||||
+ Sync;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
]
|
||||
@ -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<T> = Result<T, EthApiError>;
|
||||
@ -137,6 +138,11 @@ impl EthApiError {
|
||||
pub fn other<E: ToRpcError>(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<EthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
@ -372,6 +378,11 @@ pub enum RpcInvalidTransactionError {
|
||||
/// Any other error
|
||||
#[error("{0}")]
|
||||
Other(Box<dyn ToRpcError>),
|
||||
/// 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<revm::primitives::InvalidTransaction> 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<revm::primitives::InvalidTransaction> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,5 +90,4 @@ optimism = [
|
||||
"reth-provider/optimism",
|
||||
"reth-rpc-eth-api/optimism",
|
||||
"reth-revm/optimism",
|
||||
"reth-rpc-eth-types/optimism",
|
||||
]
|
||||
|
||||
@ -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<OwnedSemaphorePermit, AcquireError> {
|
||||
@ -83,7 +86,7 @@ where
|
||||
cfg: CfgEnvWithHandlerCfg,
|
||||
block_env: BlockEnv,
|
||||
opts: GethDebugTracingOptions,
|
||||
) -> EthResult<Vec<TraceResult>> {
|
||||
) -> Result<Vec<TraceResult>, 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<Vec<TraceResult>> {
|
||||
let block =
|
||||
Block::decode(&mut rlp_block.as_ref()).map_err(BlockError::RlpDecodeRawBlock)?;
|
||||
) -> Result<Vec<TraceResult>, 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::<EthResult<Vec<_>>>()?
|
||||
.collect::<Result<Vec<_>, 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::<EthResult<Vec<_>>>()?
|
||||
.collect::<Result<Vec<_>, 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<Vec<TraceResult>> {
|
||||
) -> Result<Vec<TraceResult>, 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<GethTrace> {
|
||||
) -> Result<GethTrace, Eth::Error> {
|
||||
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<BlockId>,
|
||||
opts: GethDebugTracingCallOptions,
|
||||
) -> EthResult<GethTrace> {
|
||||
) -> Result<GethTrace, Eth::Error> {
|
||||
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 <https://github.com/rust-lang/rust/issues/100013>
|
||||
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 <https://github.com/rust-lang/rust/issues/100013>
|
||||
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
|
||||
// <https://github.com/rust-lang/rust/issues/100013>
|
||||
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<Bundle>,
|
||||
state_context: Option<StateContext>,
|
||||
opts: Option<GethDebugTracingCallOptions>,
|
||||
) -> EthResult<Vec<Vec<GethTrace>>> {
|
||||
) -> Result<Vec<Vec<GethTrace>>, 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<TransactionContext>,
|
||||
) -> 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<Option<Bytes>> {
|
||||
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<GethDebugTracingOptions>,
|
||||
) -> RpcResult<Vec<TraceResult>> {
|
||||
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<GethDebugTracingOptions>,
|
||||
) -> RpcResult<Vec<TraceResult>> {
|
||||
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<GethDebugTracingOptions>,
|
||||
) -> RpcResult<Vec<TraceResult>> {
|
||||
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<GethDebugTracingOptions>,
|
||||
) -> RpcResult<GethTrace> {
|
||||
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<GethDebugTracingCallOptions>,
|
||||
) -> RpcResult<GethTrace> {
|
||||
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<GethDebugTracingCallOptions>,
|
||||
) -> RpcResult<Vec<Vec<GethTrace>>> {
|
||||
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<()> {
|
||||
|
||||
@ -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<Eth> {
|
||||
@ -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<EthCallBundleResponse> {
|
||||
pub async fn call_bundle(
|
||||
&self,
|
||||
bundle: EthCallBundle,
|
||||
) -> Result<EthCallBundleResponse, Eth::Error> {
|
||||
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::<u64>();
|
||||
// here we need to fetch the _next_ block's basefee based on the parent block <https://github.com/flashbots/mev-geth/blob/fddf97beec5877483f879a77b7dea2e58a58d653/internal/ethapi/api.go#L2130>
|
||||
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<EthCallBundleResponse> {
|
||||
Ok(Self::call_bundle(self, request).await?)
|
||||
Self::call_bundle(self, request).await.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<Provider, Pool, Network, EvmConfig> EthApiTypes for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Self: Send + Sync,
|
||||
{
|
||||
type Error = EthApiError;
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
{
|
||||
@ -131,7 +139,7 @@ impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Networ
|
||||
impl<Provider, Pool, Network, EvmConfig> SpawnBlocking
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Self: Clone + Send + Sync + 'static,
|
||||
Self: EthApiTypes + Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner {
|
||||
|
||||
@ -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<Provider, Pool, Network, EvmConfig> LoadReceipt for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Self: Send + Sync,
|
||||
Self: EthApiTypes,
|
||||
{
|
||||
#[inline]
|
||||
fn cache(&self) -> &EthStateCache {
|
||||
|
||||
@ -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<Provider, Pool, Network, EvmConfig> LoadState for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Self: EthApiTypes,
|
||||
Provider: StateProviderFactory + ChainSpecProvider,
|
||||
Pool: TransactionPool,
|
||||
{
|
||||
|
||||
@ -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<std::sync::Arc<dyn RawTransactionForwarder>> {
|
||||
fn raw_tx_forwarder(&self) -> Option<Arc<dyn RawTransactionForwarder>> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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<TraceResults> {
|
||||
pub async fn trace_call(
|
||||
&self,
|
||||
trace_request: TraceCallRequest,
|
||||
) -> Result<TraceResults, Eth::Error> {
|
||||
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<TraceType>,
|
||||
block_id: Option<BlockId>,
|
||||
) -> EthResult<TraceResults> {
|
||||
) -> Result<TraceResults, Eth::Error> {
|
||||
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<TraceType>)>,
|
||||
block_id: Option<BlockId>,
|
||||
) -> EthResult<Vec<TraceResults>> {
|
||||
) -> Result<Vec<TraceResults>, 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<TraceType>,
|
||||
) -> EthResult<TraceResults> {
|
||||
) -> Result<TraceResults, Eth::Error> {
|
||||
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<usize>,
|
||||
) -> EthResult<Option<LocalizedTransactionTrace>> {
|
||||
) -> Result<Option<LocalizedTransactionTrace>, 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<Option<LocalizedTransactionTrace>> {
|
||||
) -> Result<Option<LocalizedTransactionTrace>, 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<Vec<LocalizedTransactionTrace>> {
|
||||
) -> Result<Vec<LocalizedTransactionTrace>, 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<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
) -> Result<Option<Vec<LocalizedTransactionTrace>>, 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<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
) -> Result<Option<Vec<LocalizedTransactionTrace>>, 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<TraceType>,
|
||||
) -> EthResult<Option<Vec<TraceResultsWithTransactionHash>>> {
|
||||
) -> Result<Option<Vec<TraceResultsWithTransactionHash>>, 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<Option<TransactionOpcodeGas>> {
|
||||
) -> Result<Option<TransactionOpcodeGas>, 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<Option<BlockOpcodeGas>> {
|
||||
) -> Result<Option<BlockOpcodeGas>, 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<Option<u128>> {
|
||||
fn calculate_base_block_reward(&self, header: &Header) -> Result<Option<u128>, 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<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
block_overrides: Option<Box<BlockOverrides>>,
|
||||
) -> Result<TraceResults> {
|
||||
) -> RpcResult<TraceResults> {
|
||||
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<TraceType>)>,
|
||||
block_id: Option<BlockId>,
|
||||
) -> Result<Vec<TraceResults>> {
|
||||
) -> RpcResult<Vec<TraceResults>> {
|
||||
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<TraceType>,
|
||||
block_id: Option<BlockId>,
|
||||
) -> Result<TraceResults> {
|
||||
) -> RpcResult<TraceResults> {
|
||||
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<TraceType>,
|
||||
) -> Result<Option<Vec<TraceResultsWithTransactionHash>>> {
|
||||
) -> RpcResult<Option<Vec<TraceResultsWithTransactionHash>>> {
|
||||
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<TraceType>,
|
||||
) -> Result<TraceResults> {
|
||||
) -> RpcResult<TraceResults> {
|
||||
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<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
) -> RpcResult<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
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<Vec<LocalizedTransactionTrace>> {
|
||||
Ok(Self::trace_filter(self, filter).await?)
|
||||
async fn trace_filter(&self, filter: TraceFilter) -> RpcResult<Vec<LocalizedTransactionTrace>> {
|
||||
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<Index>,
|
||||
) -> Result<Option<LocalizedTransactionTrace>> {
|
||||
) -> RpcResult<Option<LocalizedTransactionTrace>> {
|
||||
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<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
) -> RpcResult<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
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<Option<TransactionOpcodeGas>> {
|
||||
) -> RpcResult<Option<TransactionOpcodeGas>> {
|
||||
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<Option<BlockOpcodeGas>> {
|
||||
async fn trace_block_opcode_gas(&self, block_id: BlockId) -> RpcResult<Option<BlockOpcodeGas>> {
|
||||
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)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<H, C, P>(
|
||||
cursor: &mut C,
|
||||
partial_key: P,
|
||||
|
||||
Reference in New Issue
Block a user