From c78effcb3f4f9f4c576b29716b78984e7e3908c0 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 14 Mar 2023 17:07:08 +0100 Subject: [PATCH] chore(rpc): more trace prep (#1752) --- crates/rpc/rpc-builder/src/lib.rs | 4 +- crates/rpc/rpc-builder/tests/it/http.rs | 3 - crates/rpc/rpc/src/eth/api/call.rs | 27 ++------ crates/rpc/rpc/src/eth/api/server.rs | 4 +- crates/rpc/rpc/src/eth/api/transactions.rs | 81 ++++++++++++++++++++-- crates/rpc/rpc/src/trace.rs | 29 +++++--- 6 files changed, 107 insertions(+), 41 deletions(-) diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 5d66e23870..c5b81b8a14 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -576,7 +576,9 @@ where NetApi::new(self.network.clone(), eth_api.clone()).into_rpc().into() } RethRpcModule::Trace => { - TraceApi::new(self.client.clone(), eth_cache.clone()).into_rpc().into() + TraceApi::new(self.client.clone(), eth_api.clone(), eth_cache.clone()) + .into_rpc() + .into() } RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(), }) diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index f55d4bcbf0..6d4cc66df0 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -198,9 +198,6 @@ where assert!(is_unimplemented( TraceApiClient::trace_get(client, H256::default(), vec![]).await.err().unwrap() )); - assert!(is_unimplemented( - TraceApiClient::trace_transaction(client, H256::default()).await.err().unwrap() - )); } async fn test_basic_web3_calls(client: &C) diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs index 6c43da516f..db76bfb812 100644 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ b/crates/rpc/rpc/src/eth/api/call.rs @@ -4,6 +4,7 @@ use crate::{ eth::{ error::{EthApiError, EthResult, InvalidTransactionError, RevertError}, revm_utils::{build_call_evm_env, get_precompiles, inspect, transact}, + EthTransactions, }, EthApi, }; @@ -18,6 +19,7 @@ use reth_rpc_types::{ state::{AccountOverride, StateOverride}, CallRequest, }; +use reth_transaction_pool::TransactionPool; use revm::{ db::{CacheDB, DatabaseRef}, primitives::{ @@ -33,31 +35,10 @@ const MIN_CREATE_GAS: u64 = 53_000u64; impl EthApi where + Pool: TransactionPool + Clone + 'static, Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static, + Network: Send + Sync + 'static, { - /// Returns the revm evm env for the requested [BlockId] - /// - /// If the [BlockId] this will return the [BlockId::Hash] of the block the env was configured - /// for. - async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)> { - // TODO handle Pending state's env - match at { - BlockId::Number(BlockNumberOrTag::Pending) => { - // This should perhaps use the latest env settings and update block specific - // settings like basefee/number - unimplemented!("support pending state env") - } - hash_or_num => { - let block_hash = self - .client() - .block_hash_for_id(hash_or_num)? - .ok_or_else(|| EthApiError::UnknownBlockNumber)?; - let (cfg, env) = self.cache().get_evm_env(block_hash).await?; - Ok((cfg, env, block_hash.into())) - } - } - } - /// Executes the call request at the given [BlockId] pub(crate) async fn call_at( &self, diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 9a6f4f7d5e..4e676713a4 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -27,10 +27,10 @@ use std::collections::BTreeMap; #[async_trait::async_trait] impl EthApiServer for EthApi where - Self: EthApiSpec, + Self: EthApiSpec + EthTransactions, Pool: TransactionPool + 'static, Client: BlockProvider + HeaderProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: 'static, + Network: Send + Sync + 'static, { /// Handler for: `eth_protocolVersion` async fn protocol_version(&self) -> Result { diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 416a97c1d6..16d898e48a 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -5,32 +5,64 @@ use crate::{ }; use async_trait::async_trait; use reth_primitives::{ - BlockId, Bytes, FromRecoveredTransaction, IntoRecoveredTransaction, TransactionSigned, - TransactionSignedEcRecovered, H256, U256, + BlockId, BlockNumberOrTag, Bytes, FromRecoveredTransaction, IntoRecoveredTransaction, + TransactionSigned, TransactionSignedEcRecovered, H256, U256, }; -use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory, TransactionsProvider}; +use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory}; use reth_rlp::Decodable; use reth_rpc_types::{Index, Transaction, TransactionRequest}; use reth_transaction_pool::{TransactionOrigin, TransactionPool}; +use revm::primitives::{BlockEnv, CfgEnv}; /// Commonly used transaction related functions for the [EthApi] type in the `eth_` namespace #[async_trait::async_trait] pub trait EthTransactions: Send + Sync { + /// Returns the revm evm env for the requested [BlockId] + /// + /// If the [BlockId] this will return the [BlockId::Hash] of the block the env was configured + /// for. + async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)>; + /// Returns the transaction by hash. /// /// Checks the pool and state. /// /// Returns `Ok(None)` if no matching transaction was found. async fn transaction_by_hash(&self, hash: H256) -> EthResult>; + + /// Returns the transaction by including its corresponding [BlockId] + async fn transaction_by_hash_at( + &self, + hash: H256, + ) -> EthResult>; } #[async_trait] impl EthTransactions for EthApi where Pool: TransactionPool + Clone + 'static, - Client: TransactionsProvider + 'static, + Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static, Network: Send + Sync + 'static, { + async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)> { + // TODO handle Pending state's env + match at { + BlockId::Number(BlockNumberOrTag::Pending) => { + // This should perhaps use the latest env settings and update block specific + // settings like basefee/number + unimplemented!("support pending state env") + } + hash_or_num => { + let block_hash = self + .client() + .block_hash_for_id(hash_or_num)? + .ok_or_else(|| EthApiError::UnknownBlockNumber)?; + let (cfg, env) = self.cache().get_evm_env(block_hash).await?; + Ok((cfg, env, block_hash.into())) + } + } + } + async fn transaction_by_hash(&self, hash: H256) -> EthResult> { if let Some(tx) = self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction()) { @@ -55,6 +87,38 @@ where } } } + + async fn transaction_by_hash_at( + &self, + hash: H256, + ) -> EthResult> { + match self.transaction_by_hash(hash).await? { + None => return Ok(None), + Some(tx) => { + let res = match tx { + tx @ TransactionSource::Pool(_) => { + (tx, BlockId::Number(BlockNumberOrTag::Pending)) + } + TransactionSource::Database { + transaction, + index, + block_hash, + block_number, + } => { + let at = BlockId::Hash(block_hash.into()); + let tx = TransactionSource::Database { + transaction, + index, + block_hash, + block_number, + }; + (tx, at) + } + }; + Ok(Some(res)) + } + } + } } // === impl EthApi === @@ -140,6 +204,15 @@ pub enum TransactionSource { }, } +impl From for TransactionSignedEcRecovered { + fn from(value: TransactionSource) -> Self { + match value { + TransactionSource::Pool(tx) => tx, + TransactionSource::Database { transaction, .. } => transaction, + } + } +} + impl From for Transaction { fn from(value: TransactionSource) -> Self { match value { diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index d2e46474df..b33dbb4119 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,4 +1,7 @@ -use crate::{eth::cache::EthStateCache, result::internal_rpc_err}; +use crate::{ + eth::{cache::EthStateCache, EthTransactions}, + result::internal_rpc_err, +}; use async_trait::async_trait; use jsonrpsee::core::RpcResult as Result; use reth_primitives::{BlockId, Bytes, H256}; @@ -14,26 +17,29 @@ use std::collections::HashSet; /// /// This type provides the functionality for handling `trace` related requests. #[derive(Clone)] -pub struct TraceApi { +pub struct TraceApi { /// The client that can interact with the chain. client: Client, + /// Access to commonly used code of the `eth` namespace + eth_api: Eth, /// The async cache frontend for eth related data eth_cache: EthStateCache, } // === impl TraceApi === -impl TraceApi { +impl TraceApi { /// Create a new instance of the [TraceApi] - pub fn new(client: Client, eth_cache: EthStateCache) -> Self { - Self { client, eth_cache } + pub fn new(client: Client, eth_api: Eth, eth_cache: EthStateCache) -> Self { + Self { client, eth_api, eth_cache } } } #[async_trait] -impl TraceApiServer for TraceApi +impl TraceApiServer for TraceApi where Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static, + Eth: EthTransactions + 'static, { /// Handler for `trace_call` async fn trace_call( @@ -107,13 +113,20 @@ where /// Handler for `trace_transaction` async fn trace_transaction( &self, - _hash: H256, + hash: H256, ) -> Result>> { + let (_transaction, at) = match self.eth_api.transaction_by_hash_at(hash).await? { + None => return Ok(None), + Some(res) => res, + }; + + let (_cfg, _block_env, _at) = self.eth_api.evm_env_at(at).await?; + Err(internal_rpc_err("unimplemented")) } } -impl std::fmt::Debug for TraceApi { +impl std::fmt::Debug for TraceApi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TraceApi").finish_non_exhaustive() }