From b5adf24a65e83bc48da16fd722d369a28d12f644 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 20 Sep 2024 17:00:28 +0200 Subject: [PATCH] chore(rpc): remove use of extensible transaction + receipt types (#9774) --- Cargo.lock | 5 +- crates/e2e-test-utils/src/lib.rs | 14 +- crates/e2e-test-utils/src/node.rs | 20 +- crates/e2e-test-utils/src/rpc.rs | 11 +- crates/node/builder/Cargo.toml | 1 - crates/node/builder/src/builder/mod.rs | 21 +-- crates/node/builder/src/launch/engine.rs | 15 +- crates/node/builder/src/launch/mod.rs | 18 +- crates/node/builder/src/rpc.rs | 16 +- crates/optimism/rpc/Cargo.toml | 1 + crates/optimism/rpc/src/eth/block.rs | 46 ++--- crates/optimism/rpc/src/eth/mod.rs | 33 ++-- crates/optimism/rpc/src/eth/receipt.rs | 30 ++- crates/optimism/rpc/src/eth/transaction.rs | 39 +++- crates/optimism/rpc/src/lib.rs | 2 +- crates/rpc/rpc-api/src/debug.rs | 2 +- crates/rpc/rpc-api/src/otterscan.rs | 7 +- crates/rpc/rpc-api/src/txpool.rs | 15 +- crates/rpc/rpc-builder/Cargo.toml | 2 +- crates/rpc/rpc-builder/src/eth.rs | 36 ++-- crates/rpc/rpc-builder/src/lib.rs | 105 +++++------ crates/rpc/rpc-builder/tests/it/http.rs | 72 ++++--- crates/rpc/rpc-eth-api/src/core.rs | 11 +- crates/rpc/rpc-eth-api/src/helpers/block.rs | 24 ++- crates/rpc/rpc-eth-api/src/helpers/call.rs | 24 +-- crates/rpc/rpc-eth-api/src/helpers/fee.rs | 102 +++++----- crates/rpc/rpc-eth-api/src/helpers/mod.rs | 6 +- crates/rpc/rpc-eth-api/src/helpers/receipt.rs | 5 +- .../rpc-eth-api/src/helpers/transaction.rs | 24 ++- crates/rpc/rpc-eth-api/src/lib.rs | 4 +- crates/rpc/rpc-eth-api/src/types.rs | 27 ++- crates/rpc/rpc-eth-types/Cargo.toml | 2 + crates/rpc/rpc-eth-types/src/builder/ctx.rs | 22 ++- crates/rpc/rpc-eth-types/src/simulate.rs | 10 +- crates/rpc/rpc-eth-types/src/transaction.rs | 44 +++-- crates/rpc/rpc-types-compat/src/block.rs | 34 ++-- crates/rpc/rpc-types-compat/src/lib.rs | 2 + .../rpc-types-compat/src/transaction/mod.rs | 176 +++++++++--------- .../src/transaction/signature.rs | 6 +- crates/rpc/rpc/Cargo.toml | 1 - crates/rpc/rpc/src/engine.rs | 13 +- crates/rpc/rpc/src/eth/core.rs | 17 +- crates/rpc/rpc/src/eth/filter.rs | 123 +++++++----- crates/rpc/rpc/src/eth/helpers/block.rs | 22 ++- crates/rpc/rpc/src/eth/helpers/mod.rs | 1 + crates/rpc/rpc/src/eth/helpers/receipt.rs | 5 +- crates/rpc/rpc/src/eth/helpers/transaction.rs | 7 +- crates/rpc/rpc/src/eth/helpers/types.rs | 85 +++++++++ crates/rpc/rpc/src/eth/mod.rs | 2 +- crates/rpc/rpc/src/eth/pubsub.rs | 36 ++-- crates/rpc/rpc/src/otterscan.rs | 77 ++++---- crates/rpc/rpc/src/txpool.rs | 50 ++--- 52 files changed, 821 insertions(+), 652 deletions(-) create mode 100644 crates/rpc/rpc/src/eth/helpers/types.rs diff --git a/Cargo.lock b/Cargo.lock index e1a575bb3158..e7d594cec170 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7714,7 +7714,6 @@ dependencies = [ name = "reth-node-builder" version = "1.0.7" dependencies = [ - "alloy-network", "alloy-primitives", "aquamarine", "eyre", @@ -8086,6 +8085,7 @@ name = "reth-optimism-rpc" version = "1.0.7" dependencies = [ "alloy-primitives", + "derive_more", "jsonrpsee-types", "op-alloy-consensus", "op-alloy-network", @@ -8352,7 +8352,6 @@ name = "reth-rpc" version = "1.0.7" dependencies = [ "alloy-dyn-abi", - "alloy-eips", "alloy-genesis", "alloy-network", "alloy-primitives", @@ -8566,6 +8565,7 @@ version = "1.0.7" dependencies = [ "alloy-consensus", "alloy-primitives", + "alloy-rpc-types", "alloy-sol-types", "derive_more", "futures", @@ -8580,6 +8580,7 @@ dependencies = [ "reth-execution-types", "reth-metrics", "reth-primitives", + "reth-provider", "reth-revm", "reth-rpc-server-types", "reth-rpc-types", diff --git a/crates/e2e-test-utils/src/lib.rs b/crates/e2e-test-utils/src/lib.rs index 61c79968d0be..3d2961cf8cd9 100644 --- a/crates/e2e-test-utils/src/lib.rs +++ b/crates/e2e-test-utils/src/lib.rs @@ -2,16 +2,12 @@ use std::sync::Arc; -use alloy_network::Network; use node::NodeTestContext; use reth::{ args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, builder::{NodeBuilder, NodeConfig, NodeHandle}, network::PeersHandleProvider, - rpc::{ - api::eth::{helpers::AddDevSigners, FullEthApiServer}, - types::AnyTransactionReceipt, - }, + rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer}, tasks::TaskManager, }; use reth_chainspec::ChainSpec; @@ -62,13 +58,7 @@ where >, N::AddOns: NodeAddOns< Adapter, - EthApi: FullEthApiServer< - NetworkTypes: Network< - TransactionResponse = reth_rpc_types::WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + AddDevSigners - + EthApiBuilderProvider>, + EthApi: FullEthApiServer + AddDevSigners + EthApiBuilderProvider>, >, { let tasks = TaskManager::current(); diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index 93ba81d6776c..391a070df7dd 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -1,6 +1,5 @@ use std::{marker::PhantomData, pin::Pin}; -use alloy_network::Network; use alloy_primitives::{BlockHash, BlockNumber, Bytes, B256}; use alloy_rpc_types::BlockNumberOrTag; use eyre::Ok; @@ -11,13 +10,15 @@ use reth::{ network::PeersHandleProvider, providers::{BlockReader, BlockReaderIdExt, CanonStateSubscriptions, StageCheckpointReader}, rpc::{ - api::eth::helpers::{EthApiSpec, EthTransactions, TraceExt}, - types::{engine::PayloadStatusEnum, AnyTransactionReceipt}, + api::eth::{ + helpers::{EthApiSpec, EthTransactions, TraceExt}, + FullEthApiTypes, + }, + types::engine::PayloadStatusEnum, }, }; use reth_chainspec::ChainSpec; -use reth_node_builder::{EthApiTypes, NodeAddOns, NodeTypesWithEngine}; -use reth_rpc_types::WithOtherFields; +use reth_node_builder::{NodeAddOns, NodeTypesWithEngine}; use reth_stages_types::StageId; use tokio_stream::StreamExt; @@ -87,13 +88,8 @@ where attributes_generator: impl Fn(u64) -> Engine::PayloadBuilderAttributes + Copy, ) -> eyre::Result> where - ::ExecutionPayloadV3: - From + PayloadEnvelopeExt, - AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt, - ::NetworkTypes: Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, + Engine::ExecutionPayloadV3: From + PayloadEnvelopeExt, + AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt + FullEthApiTypes, { let mut chain = Vec::with_capacity(length as usize); for i in 0..length { diff --git a/crates/e2e-test-utils/src/rpc.rs b/crates/e2e-test-utils/src/rpc.rs index bcac7dcfed19..3ff378a08304 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -1,5 +1,5 @@ use alloy_consensus::TxEnvelope; -use alloy_network::{eip2718::Decodable2718, Network}; +use alloy_network::eip2718::Decodable2718; use alloy_primitives::{Bytes, B256}; use reth::{ builder::{rpc::RpcRegistry, FullNodeComponents}, @@ -10,7 +10,6 @@ use reth::{ }; use reth_chainspec::ChainSpec; use reth_node_builder::{EthApiTypes, NodeTypes}; -use reth_rpc_types::{AnyTransactionReceipt, WithOtherFields}; #[allow(missing_debug_implementations)] pub struct RpcTestContext { @@ -20,13 +19,7 @@ pub struct RpcTestContext { impl RpcTestContext where Node: FullNodeComponents>, - EthApi: EthApiSpec - + EthTransactions< - NetworkTypes: Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + TraceExt, + EthApi: EthApiSpec + EthTransactions + TraceExt, { /// Injects a raw transaction into the node tx pool via RPC server pub async fn inject_tx(&self, raw_tx: Bytes) -> Result { diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index 65b165617ff9..d5468f741d5b 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -60,7 +60,6 @@ reth-tracing.workspace = true reth-transaction-pool.workspace = true ## ethereum -alloy-network.workspace = true alloy-primitives.workspace = true ## async diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index 4255e7fdf51b..506603b84d61 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -5,7 +5,6 @@ pub mod add_ons; mod states; -use reth_rpc_types::WithOtherFields; pub use states::*; use std::sync::Arc; @@ -30,10 +29,7 @@ use reth_node_core::{ dirs::{ChainPath, DataDirPath}, node_config::NodeConfig, primitives::Head, - rpc::{ - eth::{helpers::AddDevSigners, FullEthApiServer}, - types::AnyTransactionReceipt, - }, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, }; use reth_primitives::revm_primitives::EnvKzgSettings; use reth_provider::{providers::BlockchainProvider, ChainSpecProvider, FullProvider}; @@ -346,12 +342,7 @@ where >>::Components, > > - + FullEthApiServer< - NetworkTypes: alloy_network::Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + + FullEthApiServer + AddDevSigners >, { @@ -497,12 +488,8 @@ where AO: NodeAddOns< NodeAdapter, CB::Components>, EthApi: EthApiBuilderProvider, CB::Components>> - + FullEthApiServer< - NetworkTypes: alloy_network::Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + AddDevSigners, + + FullEthApiServer + + AddDevSigners, >, { /// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc diff --git a/crates/node/builder/src/launch/engine.rs b/crates/node/builder/src/launch/engine.rs index 3bceef594971..d5f9e7673e85 100644 --- a/crates/node/builder/src/launch/engine.rs +++ b/crates/node/builder/src/launch/engine.rs @@ -24,17 +24,14 @@ use reth_node_core::{ dirs::{ChainPath, DataDirPath}, exit::NodeExitFuture, primitives::Head, - rpc::{ - eth::{helpers::AddDevSigners, FullEthApiServer}, - types::AnyTransactionReceipt, - }, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; use reth_payload_primitives::PayloadBuilder; use reth_provider::providers::BlockchainProvider2; use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; -use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields}; +use reth_rpc_types::engine::ClientVersionV1; use reth_tasks::TaskExecutor; use reth_tokio_util::EventSender; use reth_tracing::tracing::{debug, error, info}; @@ -81,12 +78,8 @@ where AO: NodeAddOns< NodeAdapter, EthApi: EthApiBuilderProvider> - + FullEthApiServer< - NetworkTypes: alloy_network::Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + AddDevSigners, + + FullEthApiServer + + AddDevSigners, >, { type Node = NodeHandle, AO>; diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index d8ebbfc03d2e..a0114bdad447 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -28,17 +28,14 @@ use reth_node_api::{ use reth_node_core::{ dirs::{ChainPath, DataDirPath}, exit::NodeExitFuture, - rpc::{ - eth::{helpers::AddDevSigners, FullEthApiServer}, - types::AnyTransactionReceipt, - }, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; use reth_primitives::format_ether; use reth_provider::providers::BlockchainProvider; use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; -use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields}; +use reth_rpc_types::engine::ClientVersionV1; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::TransactionPool; @@ -55,13 +52,14 @@ use crate::{ }; /// Alias for [`reth_rpc_eth_types::EthApiBuilderCtx`], adapter for [`FullNodeComponents`]. -pub type EthApiBuilderCtx = reth_rpc_eth_types::EthApiBuilderCtx< +pub type EthApiBuilderCtx = reth_rpc_eth_types::EthApiBuilderCtx< ::Provider, ::Pool, ::Evm, ::Network, TaskExecutor, ::Provider, + Eth, >; /// A general purpose trait that launches a new node of any kind. @@ -114,12 +112,8 @@ where AO: NodeAddOns< NodeAdapter, EthApi: EthApiBuilderProvider> - + FullEthApiServer< - NetworkTypes: alloy_network::Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + AddDevSigners, + + FullEthApiServer + + AddDevSigners, >, { type Node = NodeHandle, AO>; diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index 6b5818ff0c32..ada7437e8bd4 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -15,7 +15,6 @@ use reth_node_core::{ rpc::{ api::EngineApiServer, eth::{EthApiTypes, FullEthApiServer}, - types::AnyTransactionReceipt, }, }; use reth_payload_builder::PayloadBuilderHandle; @@ -25,7 +24,6 @@ use reth_rpc_builder::{ RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, }; use reth_rpc_layer::JwtSecret; -use reth_rpc_types::WithOtherFields; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; @@ -305,13 +303,7 @@ pub async fn launch_rpc_servers( where Node: FullNodeComponents> + Clone, Engine: EngineApiServer<::Engine>, - EthApi: EthApiBuilderProvider - + FullEthApiServer< - NetworkTypes: alloy_network::Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - >, + EthApi: EthApiBuilderProvider + FullEthApiServer, { let auth_config = config.rpc.auth_server_config(jwt_secret)?; let module_config = config.rpc.transport_rpc_module_config(); @@ -386,15 +378,15 @@ where pub trait EthApiBuilderProvider: BuilderProvider + EthApiTypes { /// Returns the eth api builder. #[allow(clippy::type_complexity)] - fn eth_api_builder() -> Box) -> Self + Send>; + fn eth_api_builder() -> Box) -> Self + Send>; } impl EthApiBuilderProvider for F where N: FullNodeComponents, - for<'a> F: BuilderProvider = &'a EthApiBuilderCtx> + EthApiTypes, + for<'a> F: BuilderProvider = &'a EthApiBuilderCtx> + EthApiTypes, { - fn eth_api_builder() -> Box) -> Self + Send> { + fn eth_api_builder() -> Box) -> Self + Send> { F::builder() } } diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 975379f43fcc..0f4b87d5302a 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -48,6 +48,7 @@ serde_json.workspace = true # misc thiserror.workspace = true tracing.workspace = true +derive_more.workspace = true [dev-dependencies] reth-optimism-chainspec.workspace = true diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index 6f60297de8cf..ac1a060f53a4 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -1,24 +1,26 @@ //! Loads and formats OP block RPC response. -use reth_chainspec::ChainSpec; +use op_alloy_network::Network; +use op_alloy_rpc_types::OpTransactionReceipt; +use reth_chainspec::{ChainSpec, ChainSpecProvider}; use reth_node_api::{FullNodeComponents, NodeTypes}; use reth_primitives::TransactionMeta; use reth_provider::{BlockReaderIdExt, HeaderProvider}; use reth_rpc_eth_api::{ - helpers::{ - EthApiSpec, EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, LoadTransaction, - SpawnBlocking, - }, - FromEthApiError, + helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, + RpcReceipt, }; -use reth_rpc_eth_types::{EthStateCache, ReceiptBuilder}; -use reth_rpc_types::{AnyTransactionReceipt, BlockId}; +use reth_rpc_eth_types::EthStateCache; +use reth_rpc_types::BlockId; -use crate::{OpEthApi, OpEthApiError}; +use crate::{OpEthApi, OpEthApiError, OpReceiptBuilder}; impl EthBlocks for OpEthApi where - Self: EthApiSpec + LoadBlock + LoadTransaction, + Self: LoadBlock< + Error = OpEthApiError, + NetworkTypes: Network, + >, N: FullNodeComponents>, { #[inline] @@ -29,7 +31,7 @@ where async fn block_receipts( &self, block_id: BlockId, - ) -> Result>, Self::Error> + ) -> Result>>, Self::Error> where Self: LoadReceipt, { @@ -44,7 +46,7 @@ where let l1_block_info = reth_evm_optimism::extract_l1_info(&block).map_err(OpEthApiError::from)?; - let receipts = block + return block .body .into_iter() .zip(receipts.iter()) @@ -60,16 +62,18 @@ where timestamp, }; - let op_tx_meta = - self.build_op_receipt_meta(tx, l1_block_info.clone(), receipt)?; - - Ok(ReceiptBuilder::new(tx, meta, receipt, &receipts) - .map_err(Self::Error::from_eth_err)? - .add_other_fields(op_tx_meta.into()) - .build()) + Ok(OpReceiptBuilder::new( + &self.inner.provider().chain_spec(), + tx, + meta, + receipt, + &receipts, + l1_block_info.clone(), + )? + .build()) }) - .collect::, Self::Error>>(); - return receipts.map(Some) + .collect::, Self::Error>>() + .map(Some) } Ok(None) diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index a7954792d63c..61166bc7efa3 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -12,7 +12,8 @@ pub use receipt::{OpReceiptBuilder, OpReceiptFieldsBuilder}; use std::{fmt, sync::Arc}; use alloy_primitives::U256; -use op_alloy_network::AnyNetwork; +use derive_more::Deref; +use op_alloy_network::Optimism; use reth_chainspec::ChainSpec; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; @@ -20,8 +21,8 @@ use reth_node_api::{BuilderProvider, FullNodeComponents, FullNodeTypes, NodeType use reth_node_builder::EthApiBuilderCtx; use reth_primitives::Header; use reth_provider::{ - BlockIdReader, BlockNumReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, - HeaderProvider, StageCheckpointReader, StateProviderFactory, + BlockIdReader, BlockNumReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider, + StageCheckpointReader, StateProviderFactory, }; use reth_rpc::eth::{core::EthApiInner, DevSigner}; use reth_rpc_eth_api::{ @@ -39,7 +40,7 @@ use reth_tasks::{ use reth_transaction_pool::TransactionPool; use tokio::sync::OnceCell; -use crate::{OpEthApiError, SequencerClient}; +use crate::{OpEthApiError, OpTxBuilder, SequencerClient}; /// Adapter for [`EthApiInner`], which holds all the data required to serve core `eth_` API. pub type EthApiNodeBackend = EthApiInner< @@ -59,24 +60,20 @@ pub type EthApiNodeBackend = EthApiInner< /// /// This type implements the [`FullEthApi`](reth_rpc_eth_api::helpers::FullEthApi) by implemented /// all the `Eth` helper traits and prerequisite traits. -#[derive(Clone)] +#[derive(Clone, Deref)] pub struct OpEthApi { /// Gateway to node's core components. + #[deref] inner: Arc>, /// Sequencer client, configured to forward submitted transactions to sequencer of given OP /// network. sequencer_client: OnceCell, } -impl OpEthApi -where - N: FullNodeComponents< - Provider: BlockReaderIdExt + ChainSpecProvider + CanonStateSubscriptions + Clone + 'static, - >, -{ +impl OpEthApi { /// Creates a new instance for given context. #[allow(clippy::type_complexity)] - pub fn with_spawner(ctx: &EthApiBuilderCtx) -> Self { + pub fn with_spawner(ctx: &EthApiBuilderCtx) -> Self { let blocking_task_pool = BlockingTaskPool::build().expect("failed to build blocking task pool"); @@ -106,7 +103,8 @@ where N: FullNodeComponents, { type Error = OpEthApiError; - type NetworkTypes = AnyNetwork; + type NetworkTypes = Optimism; + type TransactionCompat = OpTxBuilder; } impl EthApiSpec for OpEthApi @@ -189,7 +187,7 @@ where impl LoadState for OpEthApi where - Self: Send + Sync, + Self: Send + Sync + Clone, N: FullNodeComponents>, { #[inline] @@ -237,7 +235,10 @@ where } } -impl>> AddDevSigners for OpEthApi { +impl AddDevSigners for OpEthApi +where + N: FullNodeComponents>, +{ fn with_dev_accounts(&self) { *self.signers().write() = DevSigner::random_signers(20) } @@ -248,7 +249,7 @@ where Self: Send, N: FullNodeComponents, { - type Ctx<'a> = &'a EthApiBuilderCtx; + type Ctx<'a> = &'a EthApiBuilderCtx; fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { Box::new(Self::with_spawner) diff --git a/crates/optimism/rpc/src/eth/receipt.rs b/crates/optimism/rpc/src/eth/receipt.rs index 69723b1dce87..b02737d0f59b 100644 --- a/crates/optimism/rpc/src/eth/receipt.rs +++ b/crates/optimism/rpc/src/eth/receipt.rs @@ -9,18 +9,15 @@ use reth_evm_optimism::RethL1BlockInfo; use reth_node_api::{FullNodeComponents, NodeTypes}; use reth_primitives::{Receipt, TransactionMeta, TransactionSigned, TxType}; use reth_provider::ChainSpecProvider; -use reth_rpc_eth_api::{ - helpers::{EthApiSpec, LoadReceipt, LoadTransaction}, - FromEthApiError, -}; +use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt}; use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; -use reth_rpc_types::{AnyReceiptEnvelope, AnyTransactionReceipt, Log, TransactionReceipt}; +use reth_rpc_types::{AnyReceiptEnvelope, Log, TransactionReceipt}; use crate::{OpEthApi, OpEthApiError}; impl LoadReceipt for OpEthApi where - Self: EthApiSpec + LoadTransaction, + Self: Send + Sync, N: FullNodeComponents>, { #[inline] @@ -33,7 +30,7 @@ where tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> Result { + ) -> Result, Self::Error> { let (block, receipts) = LoadReceipt::cache(self) .get_block_and_receipts(meta.block_hash) .await @@ -46,16 +43,15 @@ where let l1_block_info = reth_evm_optimism::extract_l1_info(&block).map_err(OpEthApiError::from)?; - let op_receipt_meta = self - .build_op_receipt_meta(&tx, l1_block_info, &receipt) - .map_err(OpEthApiError::from)?; - - let receipt_resp = ReceiptBuilder::new(&tx, meta, &receipt, &receipts) - .map_err(Self::Error::from_eth_err)? - .add_other_fields(op_receipt_meta.into()) - .build(); - - Ok(receipt_resp) + Ok(OpReceiptBuilder::new( + &self.inner.provider().chain_spec(), + &tx, + meta, + &receipt, + &receipts, + l1_block_info, + )? + .build()) } } diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index 0a796151bf44..20809d6b00c2 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -1,13 +1,17 @@ //! Loads and formats OP transaction RPC response. use alloy_primitives::{Bytes, B256}; +use op_alloy_rpc_types::Transaction; use reth_node_api::FullNodeComponents; +use reth_primitives::TransactionSignedEcRecovered; use reth_provider::{BlockReaderIdExt, TransactionsProvider}; +use reth_rpc::eth::EthTxBuilder; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, - FromEthApiError, + FromEthApiError, FullEthApiTypes, TransactionCompat, }; use reth_rpc_eth_types::{utils::recover_raw_transaction, EthStateCache}; +use reth_rpc_types::TransactionInfo; use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; use crate::{OpEthApi, SequencerClient}; @@ -54,7 +58,7 @@ where impl LoadTransaction for OpEthApi where - Self: SpawnBlocking, + Self: SpawnBlocking + FullEthApiTypes, N: FullNodeComponents, { type Pool = N::Pool; @@ -89,3 +93,34 @@ where self.sequencer_client.get().cloned() } } + +/// Builds OP transaction response type. +#[derive(Clone, Debug, Copy)] +pub struct OpTxBuilder; + +impl TransactionCompat for OpTxBuilder { + type Transaction = Transaction; + + fn fill(tx: TransactionSignedEcRecovered, tx_info: TransactionInfo) -> Self::Transaction { + let signed_tx = tx.clone().into_signed(); + + let inner = EthTxBuilder::fill(tx, tx_info).inner; + + Transaction { + inner, + source_hash: signed_tx.source_hash(), + mint: signed_tx.mint(), + // only include is_system_tx if true: + is_system_tx: signed_tx.is_deposit().then_some(signed_tx.is_system_transaction()), + deposit_receipt_version: None, // todo: how to fill this field? + } + } + + fn otterscan_api_truncate_input(tx: &mut Self::Transaction) { + tx.inner.input = tx.inner.input.slice(..4); + } + + fn tx_type(tx: &Self::Transaction) -> u8 { + tx.inner.transaction_type.unwrap_or_default() + } +} diff --git a/crates/optimism/rpc/src/lib.rs b/crates/optimism/rpc/src/lib.rs index e8b7340b5dc5..e3fef7adb5b7 100644 --- a/crates/optimism/rpc/src/lib.rs +++ b/crates/optimism/rpc/src/lib.rs @@ -15,5 +15,5 @@ pub mod eth; pub mod sequencer; pub use error::{OpEthApiError, OptimismInvalidTransactionError, SequencerClientError}; -pub use eth::OpEthApi; +pub use eth::{transaction::OpTxBuilder, OpEthApi, OpReceiptBuilder}; pub use sequencer::SequencerClient; diff --git a/crates/rpc/rpc-api/src/debug.rs b/crates/rpc/rpc-api/src/debug.rs index 671ec82a029c..0876b464cf74 100644 --- a/crates/rpc/rpc-api/src/debug.rs +++ b/crates/rpc/rpc-api/src/debug.rs @@ -1,6 +1,6 @@ -use alloy_eips::{BlockId, BlockNumberOrTag}; use alloy_primitives::{Address, Bytes, B256}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use reth_primitives::{BlockId, BlockNumberOrTag}; use reth_rpc_types::{ debug::ExecutionWitness, trace::geth::{ diff --git a/crates/rpc/rpc-api/src/otterscan.rs b/crates/rpc/rpc-api/src/otterscan.rs index c025087ff53e..3fc4cd2b386f 100644 --- a/crates/rpc/rpc-api/src/otterscan.rs +++ b/crates/rpc/rpc-api/src/otterscan.rs @@ -1,3 +1,4 @@ +use alloy_json_rpc::RpcObject; use alloy_primitives::{Address, Bytes, TxHash, B256}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_primitives::BlockId; @@ -6,13 +7,13 @@ use reth_rpc_types::{ BlockDetails, ContractCreator, InternalOperation, OtsBlockTransactions, TraceEntry, TransactionsWithReceipts, }, - Header, Transaction, WithOtherFields, + Header, }; /// Otterscan rpc interface. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "ots"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "ots"))] -pub trait Otterscan { +pub trait Otterscan { /// Get the block header by block number, required by otterscan. /// Otterscan currently requires this endpoint, used as: /// @@ -62,7 +63,7 @@ pub trait Otterscan { block_number: u64, page_number: usize, page_size: usize, - ) -> RpcResult>>; + ) -> RpcResult>; /// Gets paginated inbound/outbound transaction calls for a certain address. #[method(name = "searchTransactionsBefore")] diff --git a/crates/rpc/rpc-api/src/txpool.rs b/crates/rpc/rpc-api/src/txpool.rs index 34591aa6d4d5..9ad21cf9c95e 100644 --- a/crates/rpc/rpc-api/src/txpool.rs +++ b/crates/rpc/rpc-api/src/txpool.rs @@ -1,14 +1,12 @@ +use alloy_json_rpc::RpcObject; use alloy_primitives::Address; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use reth_rpc_types::{ - txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus}, - Transaction, WithOtherFields, -}; +use reth_rpc_types::txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus}; /// Txpool rpc interface. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "txpool"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "txpool"))] -pub trait TxPoolApi { +pub trait TxPoolApi { /// Returns the number of transactions currently pending for inclusion in the next block(s), as /// well as the ones that are being scheduled for future execution only. /// @@ -28,15 +26,12 @@ pub trait TxPoolApi { /// /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details #[method(name = "contentFrom")] - async fn txpool_content_from( - &self, - from: Address, - ) -> RpcResult>>; + async fn txpool_content_from(&self, from: Address) -> RpcResult>; /// Returns the details of all transactions currently pending for inclusion in the next /// block(s), as well as the ones that are being scheduled for future execution only. /// /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details #[method(name = "content")] - async fn txpool_content(&self) -> RpcResult>>; + async fn txpool_content(&self) -> RpcResult>; } diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index af7096ac8684..03915881c868 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -62,11 +62,11 @@ reth-provider = { workspace = true, features = ["test-utils"] } reth-rpc-api = { workspace = true, features = ["client"] } reth-rpc-engine-api.workspace = true reth-rpc-types.workspace = true -reth-rpc-types-compat.workspace = true reth-tracing.workspace = true reth-transaction-pool = { workspace = true, features = ["test-utils"] } reth-tokio-util.workspace = true reth-node-api.workspace = true +reth-rpc-types-compat.workspace = true alloy-primitives.workspace = true diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 50f6ed8a0065..6cb655d70861 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -1,30 +1,37 @@ +use std::marker::PhantomData; + use reth_evm::ConfigureEvm; use reth_primitives::Header; use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory}; use reth_rpc::{EthFilter, EthPubSub}; +use reth_rpc_eth_api::EthApiTypes; use reth_rpc_eth_types::{ cache::cache_new_blocks_task, EthApiBuilderCtx, EthConfig, EthStateCache, }; use reth_tasks::TaskSpawner; /// Alias for `eth` namespace API builder. -pub type DynEthApiBuilder = - Box) -> EthApi>; +pub type DynEthApiBuilder = Box< + dyn Fn(&EthApiBuilderCtx) -> EthApi, +>; /// Handlers for core, filter and pubsub `eth` namespace APIs. #[derive(Debug, Clone)] -pub struct EthHandlers { +pub struct EthHandlers { /// Main `eth_` request handler pub api: EthApi, /// The async caching layer used by the eth handlers pub cache: EthStateCache, /// Polling based filter handler available on all transports - pub filter: EthFilter, + pub filter: EthFilter, /// Handler for subscriptions only available for transports that support it (ws, ipc) - pub pubsub: EthPubSub, + pub pubsub: EthPubSub, } -impl EthHandlers { +impl EthHandlers +where + EthApi: EthApiTypes, +{ /// Returns a new [`EthHandlers`] builder. #[allow(clippy::too_many_arguments)] pub fn builder( @@ -80,7 +87,7 @@ where Network: Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EthApi: 'static, + EthApi: EthApiTypes + 'static, { /// Returns a new instance with handlers for `eth` namespace. pub fn build(self) -> EthHandlers { @@ -112,6 +119,7 @@ where executor, events, cache, + _rpc_ty_builders: PhantomData, }; let api = eth_api_builder(&ctx); @@ -130,13 +138,14 @@ pub struct EthFilterApiBuilder; impl EthFilterApiBuilder { /// Builds the [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer), for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> EthFilter + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> EthFilter where Provider: Send + Sync + Clone + 'static, Pool: Send + Sync + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, + Eth: EthApiTypes + 'static, { EthFilter::new( ctx.provider.clone(), @@ -154,15 +163,16 @@ pub struct EthPubSubApiBuilder; impl EthPubSubApiBuilder { /// Builds the [`EthPubSubApiServer`](reth_rpc_eth_api::EthPubSubApiServer), for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> EthPubSub + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> EthPubSub where Provider: Clone, Pool: Clone, Events: Clone, Network: Clone, Tasks: TaskSpawner + Clone + 'static, + Eth: EthApiTypes + 'static, { EthPubSub::with_spawner( ctx.provider.clone(), diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 9e450356b004..38c505905016 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -168,11 +168,10 @@ use reth_rpc::{ use reth_rpc_api::servers::*; use reth_rpc_eth_api::{ helpers::{Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt}, - EthApiServer, EthApiTypes, FullEthApiServer, RpcReceipt, + EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcReceipt, RpcTransaction, }; use reth_rpc_eth_types::{EthConfig, EthStateCache, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret}; -use reth_rpc_types::WithOtherFields; use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; use serde::{Deserialize, Serialize}; @@ -210,7 +209,6 @@ pub use eth::EthHandlers; // Rpc server metrics mod metrics; pub use metrics::{MeteredRequestFuture, RpcRequestMetricsService}; -use reth_node_core::rpc::types::AnyTransactionReceipt; /// Convenience function for starting a server in one step. #[allow(clippy::too_many_arguments)] @@ -231,10 +229,8 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm
, - EthApi: FullEthApiServer< - NetworkTypes: alloy_network::Network, - >, + EvmConfig: ConfigureEvm
, + EthApi: FullEthApiServer, { let module_config = module_config.into(); server_config @@ -441,9 +437,7 @@ where where EngineT: EngineTypes, EngineApi: EngineApiServer, - EthApi: FullEthApiServer< - NetworkTypes: alloy_network::Network, - >, + EthApi: FullEthApiServer, { let Self { provider, pool, network, executor, events, evm_config } = self; @@ -496,7 +490,7 @@ where eth: DynEthApiBuilder, ) -> RpcRegistryInner where - EthApi: 'static, + EthApi: EthApiTypes + 'static, { let Self { provider, pool, network, executor, events, evm_config } = self; RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth) @@ -510,9 +504,7 @@ where eth: DynEthApiBuilder, ) -> TransportRpcModules<()> where - EthApi: FullEthApiServer< - NetworkTypes: alloy_network::Network, - >, + EthApi: FullEthApiServer, { let mut modules = TransportRpcModules::default(); @@ -618,7 +610,7 @@ impl RpcModuleConfigBuilder { /// A Helper type the holds instances of the configured modules. #[derive(Debug, Clone)] -pub struct RpcRegistryInner { +pub struct RpcRegistryInner { provider: Provider, pool: Pool, network: Network, @@ -642,7 +634,7 @@ where Network: Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, - EthApi: 'static, + EthApi: EthApiTypes + 'static, { /// Creates a new, empty instance. #[allow(clippy::too_many_arguments)] @@ -696,6 +688,8 @@ where impl RpcRegistryInner +where + EthApi: EthApiTypes, { /// Returns a reference to the installed [`EthApi`](reth_rpc::eth::EthApi). pub const fn eth_api(&self) -> &EthApi { @@ -754,6 +748,7 @@ impl RpcRegistryInner where Network: NetworkInfo + Clone + 'static, + EthApi: EthApiTypes, Provider: ChainSpecProvider, { /// Instantiates `AdminApi` @@ -793,23 +788,18 @@ where Provider: FullRpcProvider + AccountReader + ChangeSetReader, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, - EthApi: Clone, + EthApi: EthApiServer< + RpcTransaction, + RpcBlock, + RpcReceipt, + > + EthApiTypes, { /// Register Eth Namespace /// /// # Panics /// /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn register_eth(&mut self) -> &mut Self - where - EthApi: EthApiServer< - reth_rpc_types::Transaction, - reth_rpc_types::Block, - RpcReceipt, - > + EthApiTypes< - NetworkTypes: alloy_network::Network, - >, - { + pub fn register_eth(&mut self) -> &mut Self { let eth_api = self.eth_api().clone(); self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into()); self @@ -822,14 +812,14 @@ where /// If called outside of the tokio runtime. See also [`Self::eth_api`] pub fn register_ots(&mut self) -> &mut Self where - EthApi: EthApiServer< - WithOtherFields, - reth_rpc_types::Block>, - RpcReceipt, - > + EthApiTypes< - NetworkTypes: alloy_network::Network, - > + TraceExt - + EthTransactions, + EthApi: TraceExt + + EthTransactions< + NetworkTypes: alloy_network::Network< + TransactionResponse = reth_rpc_types::WithOtherFields< + reth_rpc_types::Transaction, + >, + >, + >, { let otterscan_api = self.otterscan_api(); self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into()); @@ -893,6 +883,25 @@ where self } + /// Instantiates `OtterscanApi` + /// + /// # Panics + /// + /// If called outside of the tokio runtime. See also [`Self::eth_api`] + pub fn otterscan_api(&self) -> OtterscanApi { + let eth_api = self.eth_api().clone(); + OtterscanApi::new(eth_api) + } +} + +impl + RpcRegistryInner +where + Provider: FullRpcProvider + AccountReader + ChangeSetReader, + Network: NetworkInfo + Peers + Clone + 'static, + Tasks: TaskSpawner + Clone + 'static, + EthApi: EthApiTypes, +{ /// Instantiates `TraceApi` /// /// # Panics @@ -922,26 +931,6 @@ where EthBundle::new(eth_api, self.blocking_pool_guard.clone()) } - /// Instantiates `OtterscanApi` - /// - /// # Panics - /// - /// If called outside of the tokio runtime. See also [`Self::eth_api`] - pub fn otterscan_api(&self) -> OtterscanApi - where - EthApi: EthApiServer< - WithOtherFields, - reth_rpc_types::Block>, - RpcReceipt, - > + EthApiTypes< - NetworkTypes: alloy_network::Network, - > + TraceExt - + EthTransactions, - { - let eth_api = self.eth_api().clone(); - OtterscanApi::new(eth_api) - } - /// Instantiates `DebugApi` /// /// # Panics @@ -982,9 +971,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EthApi: FullEthApiServer< - NetworkTypes: alloy_network::Network, - >, + EthApi: FullEthApiServer, { /// Configures the auth module that includes the /// * `engine_` namespace @@ -1109,7 +1096,7 @@ where .into(), RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(), RethRpcModule::Txpool => { - TxPoolApi::new(self.pool.clone()).into_rpc().into() + TxPoolApi::<_, EthApi>::new(self.pool.clone()).into_rpc().into() } RethRpcModule::Rpc => RPCApi::new( namespaces diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index 500631427cb2..d7289d217432 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -398,45 +398,69 @@ where let nonce = 1; let block_hash = B256::default(); - OtterscanClient::get_header_by_number(client, block_number).await.unwrap(); + OtterscanClient::::get_header_by_number(client, block_number).await.unwrap(); - OtterscanClient::has_code(client, address, None).await.unwrap(); - OtterscanClient::has_code(client, address, Some(block_number.into())).await.unwrap(); - - OtterscanClient::get_api_level(client).await.unwrap(); + OtterscanClient::::has_code(client, address, None).await.unwrap(); + OtterscanClient::::has_code(client, address, Some(block_number.into())) + .await + .unwrap(); - OtterscanClient::get_internal_operations(client, tx_hash).await.unwrap(); + OtterscanClient::::get_api_level(client).await.unwrap(); - OtterscanClient::get_transaction_error(client, tx_hash).await.unwrap(); + OtterscanClient::::get_internal_operations(client, tx_hash).await.unwrap(); - OtterscanClient::trace_transaction(client, tx_hash).await.unwrap(); + OtterscanClient::::get_transaction_error(client, tx_hash).await.unwrap(); - OtterscanClient::get_block_details(client, block_number).await.unwrap_err(); + OtterscanClient::::trace_transaction(client, tx_hash).await.unwrap(); - OtterscanClient::get_block_details_by_hash(client, block_hash).await.unwrap_err(); + OtterscanClient::::get_block_details(client, block_number).await.unwrap_err(); - OtterscanClient::get_block_transactions(client, block_number, page_number, page_size) + OtterscanClient::::get_block_details_by_hash(client, block_hash) .await - .err() - .unwrap(); + .unwrap_err(); + + OtterscanClient::::get_block_transactions( + client, + block_number, + page_number, + page_size, + ) + .await + .err() + .unwrap(); assert!(is_unimplemented( - OtterscanClient::search_transactions_before(client, address, block_number, page_size,) - .await - .err() - .unwrap() + OtterscanClient::::search_transactions_before( + client, + address, + block_number, + page_size, + ) + .await + .err() + .unwrap() )); assert!(is_unimplemented( - OtterscanClient::search_transactions_after(client, address, block_number, page_size,) - .await - .err() - .unwrap() - )); - assert!(OtterscanClient::get_transaction_by_sender_and_nonce(client, sender, nonce) + OtterscanClient::::search_transactions_after( + client, + address, + block_number, + page_size, + ) .await .err() + .unwrap() + )); + assert!(OtterscanClient::::get_transaction_by_sender_and_nonce( + client, sender, nonce + ) + .await + .err() + .is_none()); + assert!(OtterscanClient::::get_contract_creator(client, address) + .await + .unwrap() .is_none()); - assert!(OtterscanClient::get_contract_creator(client, address).await.unwrap().is_none()); } #[tokio::test(flavor = "multi_thread")] diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 60adae2a6ed4..0c040a312e1a 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -2,7 +2,6 @@ //! the `eth_` namespace. use alloy_dyn_abi::TypedData; use alloy_json_rpc::RpcObject; -use alloy_network::Network; use alloy_primitives::{Address, Bytes, B256, B64, U256, U64}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_primitives::{transaction::AccessListResult, BlockId, BlockNumberOrTag}; @@ -11,8 +10,8 @@ use reth_rpc_types::{ serde_helpers::JsonStorageKey, simulate::{SimulatePayload, SimulatedBlock}, state::{EvmOverrides, StateOverride}, - AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, - FeeHistory, Header, Index, StateContext, SyncStatus, TransactionRequest, Work, + BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, + Index, StateContext, SyncStatus, TransactionRequest, Work, }; use tracing::trace; @@ -368,7 +367,7 @@ impl RpcReceipt, > for T where - T: FullEthApi>, + T: FullEthApi, jsonrpsee_types::error::ErrorObject<'static>: From, { /// Handler for: `eth_protocolVersion` @@ -499,7 +498,9 @@ where hash: B256, ) -> RpcResult>> { trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash"); - Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into)) + Ok(EthTransactions::transaction_by_hash(self, hash) + .await? + .map(|tx| tx.into_transaction::())) } /// Handler for: `eth_getRawTransactionByBlockHashAndIndex` diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs index 877822394765..19e81e2703d4 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -6,10 +6,10 @@ use futures::Future; use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders}; use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider}; use reth_rpc_eth_types::{EthApiError, EthStateCache}; -use reth_rpc_types::{AnyTransactionReceipt, Header, Index}; +use reth_rpc_types::{Header, Index}; use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; -use crate::{FromEthApiError, RpcBlock}; +use crate::{FromEthApiError, FullEthApiTypes, RpcBlock, RpcReceipt}; use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking}; @@ -25,7 +25,10 @@ pub trait EthBlocks: LoadBlock { fn rpc_block_header( &self, block_id: BlockId, - ) -> impl Future, Self::Error>> + Send { + ) -> impl Future, Self::Error>> + Send + where + Self: FullEthApiTypes, + { async move { Ok(self.rpc_block(block_id, false).await?.map(|block| block.header)) } } @@ -38,6 +41,8 @@ pub trait EthBlocks: LoadBlock { block_id: BlockId, full: bool, ) -> impl Future>, Self::Error>> + Send + where + Self: FullEthApiTypes, { async move { let Some(block) = self.block_with_senders(block_id).await? else { return Ok(None) }; @@ -46,8 +51,13 @@ pub trait EthBlocks: LoadBlock { .header_td_by_number(block.number) .map_err(Self::Error::from_eth_err)? .ok_or(EthApiError::HeaderNotFound(block_id))?; - let block = from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash)) - .map_err(Self::Error::from_eth_err)?; + let block = from_block::( + block.unseal(), + total_difficulty, + full.into(), + Some(block_hash), + ) + .map_err(Self::Error::from_eth_err)?; Ok(Some(block)) } } @@ -65,7 +75,7 @@ pub trait EthBlocks: LoadBlock { return Ok(LoadBlock::provider(self) .pending_block() .map_err(Self::Error::from_eth_err)? - .map(|block| block.body.len())) + .map(|block| block.body.len())); } let block_hash = match LoadBlock::provider(self) @@ -91,7 +101,7 @@ pub trait EthBlocks: LoadBlock { fn block_receipts( &self, block_id: BlockId, - ) -> impl Future>, Self::Error>> + Send + ) -> impl Future>>, Self::Error>> + Send where Self: LoadReceipt; diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index 3bfcd5bd18ef..ee9dad9b6c34 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -1,7 +1,9 @@ //! Loads a pending block from database. Helper trait for `eth_` transaction, call and trace RPC //! methods. -use crate::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError}; +use crate::{ + AsEthApiError, FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError, RpcBlock, +}; use alloy_primitives::{Bytes, TxKind, B256, U256}; use futures::Future; use reth_chainspec::MIN_TRANSACTION_GAS; @@ -31,8 +33,7 @@ use reth_rpc_server_types::constants::gas_oracle::{CALL_STIPEND_GAS, ESTIMATE_GA use reth_rpc_types::{ simulate::{SimBlock, SimulatePayload, SimulatedBlock}, state::{EvmOverrides, StateOverride}, - Block, BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, TransactionRequest, - WithOtherFields, + BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, TransactionRequest, }; use revm::{Database, DatabaseCommit, GetInspector}; use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector}; @@ -61,14 +62,10 @@ pub trait EthCall: Call + LoadPendingBlock { &self, payload: SimulatePayload, block: Option, - ) -> impl Future< - Output = Result< - Vec>>>, - Self::Error, - >, - > + Send + ) -> impl Future>>, Self::Error>> + + Send where - Self: LoadBlock, + Self: LoadBlock + FullEthApiTypes, { async move { if payload.block_state_calls.len() > self.max_simulate_blocks() as usize { @@ -108,9 +105,8 @@ pub trait EthCall: Call + LoadPendingBlock { let this = self.clone(); self.spawn_with_state_at_block(block, move |state| { let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let mut blocks: Vec< - SimulatedBlock>>, - > = Vec::with_capacity(block_state_calls.len()); + let mut blocks: Vec>> = + Vec::with_capacity(block_state_calls.len()); let mut gas_used = 0; for block in block_state_calls { // Increase number and timestamp for every new block @@ -191,7 +187,7 @@ pub trait EthCall: Call + LoadPendingBlock { results.push((env.tx.caller, res.result)); } - let block = simulate::build_block( + let block = simulate::build_block::( results, transactions, &block_env, diff --git a/crates/rpc/rpc-eth-api/src/helpers/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs index c05b9881f971..43f202a7d009 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/fee.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -152,58 +152,64 @@ 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).map_err(Self::Error::from_eth_err)?; - if headers.len() != block_count as usize { - return Err(EthApiError::InvalidBlockRange.into()) - } - - for header in &headers { - base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128); - gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64); - base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default()); - blob_gas_used_ratio.push( - header.blob_gas_used.unwrap_or_default() as f64 / - reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, - ); + // read the requested header range + 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.into()) + } - // Percentiles were specified, so we need to collect reward percentile ino - if let Some(percentiles) = &reward_percentiles { - let (transactions, receipts) = LoadFee::cache(self) - .get_transactions_and_receipts(header.hash()) - .await.map_err(Self::Error::from_eth_err)? - .ok_or(EthApiError::InvalidBlockRange)?; - rewards.push( - calculate_reward_percentiles_for_block( - percentiles, - header.gas_used, - header.base_fee_per_gas.unwrap_or_default(), - &transactions, - &receipts, - ) - .unwrap_or_default(), + for header in &headers { + base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128); + gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64); + base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default()); + blob_gas_used_ratio.push( + header.blob_gas_used.unwrap_or_default() as f64 + / reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, ); + + // Percentiles were specified, so we need to collect reward percentile ino + if let Some(percentiles) = &reward_percentiles { + let (transactions, receipts) = LoadFee::cache(self) + .get_transactions_and_receipts(header.hash()) + .await + .map_err(Self::Error::from_eth_err)? + .ok_or(EthApiError::InvalidBlockRange)?; + rewards.push( + calculate_reward_percentiles_for_block( + percentiles, + header.gas_used, + header.base_fee_per_gas.unwrap_or_default(), + &transactions, + &receipts, + ) + .unwrap_or_default(), + ); + } } - } - // The spec states that `base_fee_per_gas` "[..] includes the next block after the - // newest of the returned range, because this value can be derived from the - // newest block" - // - // The unwrap is safe since we checked earlier that we got at least 1 header. - let last_header = headers.last().expect("is present"); - base_fee_per_gas.push( - LoadFee::provider(self).chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee( - last_header.gas_used as u128, - last_header.gas_limit as u128, - last_header.base_fee_per_gas.unwrap_or_default() as u128, - )); - - // Same goes for the `base_fee_per_blob_gas`: - // > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block. - base_fee_per_blob_gas - .push(last_header.next_block_blob_fee().unwrap_or_default()); - }; + // The spec states that `base_fee_per_gas` "[..] includes the next block after the + // newest of the returned range, because this value can be derived from the + // newest block" + // + // The unwrap is safe since we checked earlier that we got at least 1 header. + let last_header = headers.last().expect("is present"); + base_fee_per_gas.push( + LoadFee::provider(self) + .chain_spec() + .base_fee_params_at_timestamp(last_header.timestamp) + .next_block_base_fee( + last_header.gas_used as u128, + last_header.gas_limit as u128, + last_header.base_fee_per_gas.unwrap_or_default() as u128, + ), + ); + + // Same goes for the `base_fee_per_blob_gas`: + // > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block. + base_fee_per_blob_gas.push(last_header.next_block_blob_fee().unwrap_or_default()); + }; Ok(FeeHistory { base_fee_per_gas, diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs index 73a64078da54..8adb0e281e71 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -39,7 +39,7 @@ pub use state::{EthState, LoadState}; pub use trace::Trace; pub use transaction::{EthTransactions, LoadTransaction}; -use crate::EthApiTypes; +use crate::FullEthApiTypes; /// Extension trait that bundles traits needed for tracing transactions. pub trait TraceExt: @@ -53,7 +53,7 @@ impl TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock + /// /// This trait is automatically implemented for any type that implements all the `Eth` traits. pub trait FullEthApi: - EthApiTypes + FullEthApiTypes + EthApiSpec + EthTransactions + EthBlocks @@ -66,7 +66,7 @@ pub trait FullEthApi: } impl FullEthApi for T where - T: EthApiTypes + T: FullEthApiTypes + EthApiSpec + EthTransactions + EthBlocks diff --git a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs index fbd81e6fd7bb..eae99bbe45d8 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs @@ -4,9 +4,8 @@ use futures::Future; use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; use reth_rpc_eth_types::EthStateCache; -use reth_rpc_types::AnyTransactionReceipt; -use crate::EthApiTypes; +use crate::{EthApiTypes, RpcReceipt}; /// Assembles transaction receipt data w.r.t to network. /// @@ -23,5 +22,5 @@ pub trait LoadReceipt: EthApiTypes + Send + Sync { tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> impl Future> + Send; + ) -> impl Future, Self::Error>> + Send; } diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 37856f3e13f0..a12ef7012eb7 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -17,13 +17,12 @@ use reth_rpc_types::{ EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest, LegacyTransactionRequest, }, - AnyTransactionReceipt, BlockNumberOrTag, TransactionInfo, TransactionRequest, - TypedTransactionRequest, + BlockNumberOrTag, TransactionInfo, TransactionRequest, TypedTransactionRequest, }; use reth_rpc_types_compat::transaction::{from_recovered, from_recovered_with_block_context}; use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; -use crate::{FromEthApiError, IntoEthApiError, RpcTransaction}; +use crate::{FromEthApiError, FullEthApiTypes, IntoEthApiError, RpcReceipt, RpcTransaction}; use super::{ Call, EthApiSpec, EthSigner, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, LoadState, @@ -137,7 +136,7 @@ pub trait EthTransactions: LoadTransaction { fn transaction_receipt( &self, hash: B256, - ) -> impl Future, Self::Error>> + Send + ) -> impl Future>, Self::Error>> + Send where Self: LoadReceipt + 'static, { @@ -207,7 +206,10 @@ pub trait EthTransactions: LoadTransaction { base_fee: base_fee_per_gas.map(u128::from), index: Some(index as u64), }; - return Ok(Some(from_recovered_with_block_context(tx, tx_info))) + + return Ok(Some(from_recovered_with_block_context::( + tx, tx_info, + ))) } } @@ -223,7 +225,7 @@ pub trait EthTransactions: LoadTransaction { include_pending: bool, ) -> impl Future>, Self::Error>> + Send where - Self: LoadBlock + LoadState, + Self: LoadBlock + LoadState + FullEthApiTypes, { async move { // Check the pool first @@ -232,7 +234,7 @@ pub trait EthTransactions: LoadTransaction { LoadState::pool(self).get_transaction_by_sender_and_nonce(sender, nonce) { let transaction = tx.transaction.clone().into_consensus(); - return Ok(Some(from_recovered(transaction))); + return Ok(Some(from_recovered::(transaction))); } } @@ -283,7 +285,9 @@ pub trait EthTransactions: LoadTransaction { base_fee: base_fee_per_gas.map(u128::from), index: Some(index as u64), }; - from_recovered_with_block_context(tx, tx_info) + from_recovered_with_block_context::( + tx, tx_info, + ) }) }) .ok_or(EthApiError::HeaderNotFound(block_id).into()) @@ -352,7 +356,7 @@ pub trait EthTransactions: LoadTransaction { }; if self.find_signer(&from).is_err() { - return Err(SignError::NoAccount.into_eth_err()); + return Err(SignError::NoAccount.into_eth_err()) } // set nonce if not already set before @@ -605,7 +609,7 @@ pub trait EthTransactions: LoadTransaction { /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` transactions RPC /// methods. -pub trait LoadTransaction: SpawnBlocking { +pub trait LoadTransaction: SpawnBlocking + FullEthApiTypes { /// Transaction pool with pending transactions. [`TransactionPool::Transaction`] is the /// supported transaction type. type Pool: TransactionPool; diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs index ec6490917c33..849c8e2e4c8f 100644 --- a/crates/rpc/rpc-eth-api/src/lib.rs +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -19,12 +19,14 @@ pub mod helpers; pub mod pubsub; pub mod types; +pub use reth_rpc_types_compat::TransactionCompat; + pub use bundle::{EthBundleApiServer, EthCallBundleApiServer}; pub use core::{EthApiServer, FullEthApiServer}; pub use filter::EthFilterApiServer; pub use helpers::error::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError}; pub use pubsub::EthPubSubApiServer; -pub use types::{EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; +pub use types::{EthApiTypes, FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; #[cfg(feature = "client")] pub use bundle::{EthBundleApiClient, EthCallBundleApiClient}; diff --git a/crates/rpc/rpc-eth-api/src/types.rs b/crates/rpc/rpc-eth-api/src/types.rs index 91a9ffdc691a..900817964546 100644 --- a/crates/rpc/rpc-eth-api/src/types.rs +++ b/crates/rpc/rpc-eth-api/src/types.rs @@ -1,10 +1,11 @@ //! Trait for specifying `eth` network dependent API types. -use std::error::Error; +use std::{error::Error, fmt}; use alloy_network::{AnyNetwork, Network}; use reth_rpc_eth_types::EthApiError; -use reth_rpc_types::{Block, Transaction, WithOtherFields}; +use reth_rpc_types::Block; +use reth_rpc_types_compat::TransactionCompat; use crate::{AsEthApiError, FromEthApiError, FromEvmError}; @@ -19,16 +20,15 @@ pub trait EthApiTypes: Send + Sync + Clone { + Send + Sync; /// Blockchain primitive types, specific to network, e.g. block and transaction. - // todo: remove restriction [`reth_rpc_types::Transaction`] - type NetworkTypes: Network< - TransactionResponse = WithOtherFields, - HeaderResponse = reth_rpc_types::Header, - >; + type NetworkTypes: Network; + /// Conversion methods for transaction RPC type. + type TransactionCompat: Send + Sync + Clone + fmt::Debug; } impl EthApiTypes for () { type Error = EthApiError; type NetworkTypes = AnyNetwork; + type TransactionCompat = (); } /// Adapter for network specific transaction type. @@ -39,3 +39,16 @@ pub type RpcBlock = Block, ::HeaderResponse>; /// Adapter for network specific receipt type. pub type RpcReceipt = ::ReceiptResponse; + +/// Helper trait holds necessary trait bounds on [`EthApiTypes`] to implement `eth` API. +pub trait FullEthApiTypes: + EthApiTypes>> +{ +} + +impl FullEthApiTypes for T where + T: EthApiTypes< + TransactionCompat: TransactionCompat>, + > +{ +} diff --git a/crates/rpc/rpc-eth-types/Cargo.toml b/crates/rpc/rpc-eth-types/Cargo.toml index 18d8767f0527..30c7a7bc4c82 100644 --- a/crates/rpc/rpc-eth-types/Cargo.toml +++ b/crates/rpc/rpc-eth-types/Cargo.toml @@ -27,6 +27,7 @@ reth-rpc-types-compat.workspace = true reth-tasks.workspace = true reth-transaction-pool.workspace = true reth-trie.workspace = true +reth-provider.workspace = true # ethereum alloy-primitives.workspace = true @@ -35,6 +36,7 @@ alloy-sol-types.workspace = true revm.workspace = true revm-inspectors.workspace = true revm-primitives = { workspace = true, features = ["dev"] } +alloy-rpc-types.workspace = true # rpc jsonrpsee-core.workspace = true diff --git a/crates/rpc/rpc-eth-types/src/builder/ctx.rs b/crates/rpc/rpc-eth-types/src/builder/ctx.rs index cd585921155f..833f3e0f7022 100644 --- a/crates/rpc/rpc-eth-types/src/builder/ctx.rs +++ b/crates/rpc/rpc-eth-types/src/builder/ctx.rs @@ -1,8 +1,8 @@ //! Context required for building `eth` namespace APIs. -use reth_chain_state::CanonStateSubscriptions; -use reth_chainspec::ChainSpecProvider; -use reth_storage_api::BlockReaderIdExt; +use std::marker::PhantomData; + +use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; use reth_tasks::TaskSpawner; use crate::{ @@ -12,7 +12,7 @@ use crate::{ /// Context for building the `eth` namespace API. #[derive(Debug, Clone)] -pub struct EthApiBuilderCtx { +pub struct EthApiBuilderCtx { /// Database handle. pub provider: Provider, /// Mempool handle. @@ -29,10 +29,12 @@ pub struct EthApiBuilderCtx { pub events: Events, /// RPC cache handle. pub cache: EthStateCache, + /// RPC type builders. + pub _rpc_ty_builders: PhantomData, } -impl - EthApiBuilderCtx +impl + EthApiBuilderCtx where Provider: BlockReaderIdExt + Clone, { @@ -58,8 +60,8 @@ pub struct GasPriceOracleBuilder; impl GasPriceOracleBuilder { /// Builds a [`GasPriceOracle`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, + pub fn build( + ctx: &EthApiBuilderCtx, ) -> GasPriceOracle where Provider: BlockReaderIdExt + Clone, @@ -74,8 +76,8 @@ pub struct FeeHistoryCacheBuilder; impl FeeHistoryCacheBuilder { /// Builds a [`FeeHistoryCache`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, + pub fn build( + ctx: &EthApiBuilderCtx, ) -> FeeHistoryCache where Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, diff --git a/crates/rpc/rpc-eth-types/src/simulate.rs b/crates/rpc/rpc-eth-types/src/simulate.rs index c36f77599aa6..5160982ea313 100644 --- a/crates/rpc/rpc-eth-types/src/simulate.rs +++ b/crates/rpc/rpc-eth-types/src/simulate.rs @@ -11,9 +11,9 @@ use reth_revm::database::StateProviderDatabase; use reth_rpc_server_types::result::rpc_err; use reth_rpc_types::{ simulate::{SimCallResult, SimulateError, SimulatedBlock}, - Block, BlockTransactionsKind, ToRpcError, TransactionRequest, WithOtherFields, + Block, BlockTransactionsKind, ToRpcError, TransactionRequest, }; -use reth_rpc_types_compat::block::from_block; +use reth_rpc_types_compat::{block::from_block, TransactionCompat}; use reth_storage_api::StateRootProvider; use reth_trie::{HashedPostState, HashedStorage}; use revm::{db::CacheDB, Database}; @@ -168,7 +168,7 @@ where } /// Handles outputs of the calls execution and builds a [`SimulatedBlock`]. -pub fn build_block( +pub fn build_block( results: Vec<(Address, ExecutionResult)>, transactions: Vec, block_env: &BlockEnv, @@ -176,7 +176,7 @@ pub fn build_block( total_difficulty: U256, full_transactions: bool, db: &CacheDB>>, -) -> Result>>, EthApiError> { +) -> Result>, EthApiError> { let mut calls: Vec = Vec::with_capacity(results.len()); let mut senders = Vec::with_capacity(results.len()); let mut receipts = Vec::new(); @@ -297,6 +297,6 @@ pub fn build_block( let txs_kind = if full_transactions { BlockTransactionsKind::Full } else { BlockTransactionsKind::Hashes }; - let block = from_block(block, total_difficulty, txs_kind, None)?; + let block = from_block::(block, total_difficulty, txs_kind, None)?; Ok(SimulatedBlock { inner: block, calls }) } diff --git a/crates/rpc/rpc-eth-types/src/transaction.rs b/crates/rpc/rpc-eth-types/src/transaction.rs index 0ea37108282c..c3ca1b503aef 100644 --- a/crates/rpc/rpc-eth-types/src/transaction.rs +++ b/crates/rpc/rpc-eth-types/src/transaction.rs @@ -1,10 +1,14 @@ //! Helper types for `reth_rpc_eth_api::EthApiServer` implementation. //! //! Transaction wrapper that labels transaction with its origin. + use alloy_primitives::B256; +use alloy_rpc_types::TransactionInfo; use reth_primitives::TransactionSignedEcRecovered; -use reth_rpc_types::{Transaction, TransactionInfo, WithOtherFields}; -use reth_rpc_types_compat::transaction::from_recovered_with_block_context; +use reth_rpc_types_compat::{ + transaction::{from_recovered, from_recovered_with_block_context}, + TransactionCompat, +}; /// Represents from where a transaction was fetched. #[derive(Debug, Clone, Eq, PartialEq)] @@ -36,6 +40,24 @@ impl TransactionSource { self.into() } + /// Conversion into network specific transaction type. + pub fn into_transaction(self) -> T::Transaction { + match self { + Self::Pool(tx) => from_recovered::(tx), + Self::Block { transaction, index, block_hash, block_number, base_fee } => { + let tx_info = TransactionInfo { + hash: Some(transaction.hash()), + index: Some(index), + block_hash: Some(block_hash), + block_number: Some(block_number), + base_fee: base_fee.map(u128::from), + }; + + from_recovered_with_block_context::(transaction, tx_info) + } + } + } + /// Returns the transaction and block related info, if not pending pub fn split(self) -> (TransactionSignedEcRecovered, TransactionInfo) { match self { @@ -68,21 +90,3 @@ impl From for TransactionSignedEcRecovered { } } } - -impl From for WithOtherFields { - fn from(value: TransactionSource) -> Self { - match value { - TransactionSource::Pool(tx) => reth_rpc_types_compat::transaction::from_recovered(tx), - TransactionSource::Block { transaction, index, block_hash, block_number, base_fee } => { - let tx_info = TransactionInfo { - hash: Some(transaction.hash()), - block_hash: Some(block_hash), - block_number: Some(block_number), - base_fee: base_fee.map(u128::from), - index: Some(index), - }; - from_recovered_with_block_context(transaction, tx_info) - } - } - } -} diff --git a/crates/rpc/rpc-types-compat/src/block.rs b/crates/rpc/rpc-types-compat/src/block.rs index 1981c0555cf8..bf500a2090f4 100644 --- a/crates/rpc/rpc-types-compat/src/block.rs +++ b/crates/rpc/rpc-types-compat/src/block.rs @@ -1,31 +1,31 @@ //! Compatibility functions for rpc `Block` type. -use crate::transaction::from_recovered_with_block_context; use alloy_primitives::{B256, U256}; use alloy_rlp::Encodable; -use alloy_rpc_types::{Transaction, TransactionInfo}; use reth_primitives::{ Block as PrimitiveBlock, BlockWithSenders, Header as PrimitiveHeader, Withdrawals, }; use reth_rpc_types::{ - Block, BlockError, BlockTransactions, BlockTransactionsKind, Header, WithOtherFields, + Block, BlockError, BlockTransactions, BlockTransactionsKind, Header, TransactionInfo, }; +use crate::{transaction::from_recovered_with_block_context, TransactionCompat}; + /// Converts the given primitive block into a [`Block`] response with the given /// [`BlockTransactionsKind`] /// /// If a `block_hash` is provided, then this is used, otherwise the block hash is computed. -pub fn from_block( +pub fn from_block( block: BlockWithSenders, total_difficulty: U256, kind: BlockTransactionsKind, block_hash: Option, -) -> Result>, BlockError> { +) -> Result, BlockError> { match kind { BlockTransactionsKind::Hashes => { - Ok(from_block_with_tx_hashes(block, total_difficulty, block_hash)) + Ok(from_block_with_tx_hashes::(block, total_difficulty, block_hash)) } - BlockTransactionsKind::Full => from_block_full(block, total_difficulty, block_hash), + BlockTransactionsKind::Full => from_block_full::(block, total_difficulty, block_hash), } } @@ -34,11 +34,11 @@ pub fn from_block( /// /// This will populate the `transactions` field with only the hashes of the transactions in the /// block: [`BlockTransactions::Hashes`] -pub fn from_block_with_tx_hashes( +pub fn from_block_with_tx_hashes( block: BlockWithSenders, total_difficulty: U256, block_hash: Option, -) -> Block> { +) -> Block { let block_hash = block_hash.unwrap_or_else(|| block.header.hash_slow()); let transactions = block.body.iter().map(|tx| tx.hash()).collect(); @@ -55,12 +55,12 @@ pub fn from_block_with_tx_hashes( /// total difficulty to populate its field in the rpc response. /// /// This will populate the `transactions` field with the _full_ -/// [`Transaction`] objects: [`BlockTransactions::Full`] -pub fn from_block_full( +/// [`TransactionCompat::Transaction`] objects: [`BlockTransactions::Full`] +pub fn from_block_full( mut block: BlockWithSenders, total_difficulty: U256, block_hash: Option, -) -> Result>, BlockError> { +) -> Result, BlockError> { let block_hash = block_hash.unwrap_or_else(|| block.block.header.hash_slow()); let block_number = block.block.number; let base_fee_per_gas = block.block.base_fee_per_gas; @@ -83,7 +83,7 @@ pub fn from_block_full( index: Some(idx as u64), }; - from_recovered_with_block_context(signed_tx_ec_recovered, tx_info) + from_recovered_with_block_context::(signed_tx_ec_recovered, tx_info) }) .collect::>(); @@ -155,13 +155,13 @@ pub fn from_primitive_with_hash(primitive_header: reth_primitives::SealedHeader) } #[inline] -fn from_block_with_transactions( +fn from_block_with_transactions( block_length: usize, block_hash: B256, block: PrimitiveBlock, total_difficulty: U256, - transactions: BlockTransactions>, -) -> Block> { + transactions: BlockTransactions, +) -> Block { let uncles = block.ommers.into_iter().map(|h| h.hash_slow()).collect(); let mut header = from_primitive_with_hash(block.header.seal(block_hash)); header.total_difficulty = Some(total_difficulty); @@ -177,7 +177,7 @@ fn from_block_with_transactions( /// Build an RPC block response representing /// an Uncle from its header. -pub fn uncle_block_from_header(header: PrimitiveHeader) -> Block> { +pub fn uncle_block_from_header(header: PrimitiveHeader) -> Block { let hash = header.hash_slow(); let rpc_header = from_primitive_with_hash(header.clone().seal(hash)); let uncle_block = PrimitiveBlock { header, ..Default::default() }; diff --git a/crates/rpc/rpc-types-compat/src/lib.rs b/crates/rpc/rpc-types-compat/src/lib.rs index 99eff4fa7930..c324eebc8723 100644 --- a/crates/rpc/rpc-types-compat/src/lib.rs +++ b/crates/rpc/rpc-types-compat/src/lib.rs @@ -14,3 +14,5 @@ pub mod block; pub mod engine; pub mod proof; pub mod transaction; + +pub use transaction::TransactionCompat; diff --git a/crates/rpc/rpc-types-compat/src/transaction/mod.rs b/crates/rpc/rpc-types-compat/src/transaction/mod.rs index bc1c498d240f..8fd4860e1597 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/mod.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/mod.rs @@ -1,117 +1,107 @@ //! Compatibility functions for rpc `Transaction` type. -use alloy_primitives::{Address, TxKind}; +mod signature; +mod typed; + +pub use signature::*; +pub use typed::*; + +use std::fmt; + use alloy_rpc_types::{ request::{TransactionInput, TransactionRequest}, TransactionInfo, }; -use reth_primitives::{TransactionSignedEcRecovered, TxType}; +use reth_primitives::{TransactionSigned, TransactionSignedEcRecovered, TxType}; use reth_rpc_types::{Transaction, WithOtherFields}; -use signature::from_primitive_signature; -pub use typed::*; -mod signature; -mod typed; - -/// Create a new rpc transaction result for a mined transaction, using the given [`TransactionInfo`] -/// to populate the corresponding fields in the rpc result. -pub fn from_recovered_with_block_context( +/// Create a new rpc transaction result for a mined transaction, using the given block hash, +/// number, and tx index fields to populate the corresponding fields in the rpc result. +/// +/// The block hash, number, and tx index fields should be from the original block where the +/// transaction was mined. +pub fn from_recovered_with_block_context( tx: TransactionSignedEcRecovered, tx_info: TransactionInfo, -) -> WithOtherFields { - fill(tx, tx_info) +) -> T::Transaction { + T::fill(tx, tx_info) } /// Create a new rpc transaction result for a _pending_ signed transaction, setting block /// environment related fields to `None`. -pub fn from_recovered(tx: TransactionSignedEcRecovered) -> WithOtherFields { - fill(tx, TransactionInfo::default()) +pub fn from_recovered(tx: TransactionSignedEcRecovered) -> T::Transaction { + T::fill(tx, TransactionInfo::default()) } -/// Create a new rpc transaction result for a _pending_ signed transaction, setting block -/// environment related fields to `None`. -fn fill( - tx: TransactionSignedEcRecovered, - tx_info: TransactionInfo, -) -> WithOtherFields { - let signer = tx.signer(); - let signed_tx = tx.into_signed(); +/// Builds RPC transaction w.r.t. network. +pub trait TransactionCompat: Send + Sync + Unpin + Clone + fmt::Debug { + /// RPC transaction response type. + type Transaction: Send + Clone + Default + fmt::Debug; - let to: Option
= match signed_tx.kind() { - TxKind::Create => None, - TxKind::Call(to) => Some(Address(*to)), - }; + /// Formats gas price and max fee per gas for RPC transaction response w.r.t. network specific + /// transaction type. + fn gas_price(signed_tx: &TransactionSigned, base_fee: Option) -> GasPrice { + match signed_tx.tx_type() { + TxType::Legacy | TxType::Eip2930 => { + GasPrice { gas_price: Some(signed_tx.max_fee_per_gas()), max_fee_per_gas: None } + } + TxType::Eip1559 | TxType::Eip4844 => { + // the gas price field for EIP1559 is set to `min(tip, gasFeeCap - baseFee) + + // baseFee` + let gas_price = base_fee + .and_then(|base_fee| { + signed_tx + .effective_tip_per_gas(Some(base_fee)) + .map(|tip| tip + base_fee as u128) + }) + .unwrap_or_else(|| signed_tx.max_fee_per_gas()); - #[allow(unreachable_patterns)] - let (gas_price, max_fee_per_gas) = match signed_tx.tx_type() { - TxType::Legacy | TxType::Eip2930 => (Some(signed_tx.max_fee_per_gas()), None), - TxType::Eip1559 | TxType::Eip4844 | TxType::Eip7702 => { - // the gas price field for EIP1559 is set to `min(tip, gasFeeCap - baseFee) + - // baseFee` - let gas_price = tx_info - .base_fee - .and_then(|base_fee| { - signed_tx.effective_tip_per_gas(Some(base_fee as u64)).map(|tip| tip + base_fee) - }) - .unwrap_or_else(|| signed_tx.max_fee_per_gas()); - - (Some(gas_price), Some(signed_tx.max_fee_per_gas())) + GasPrice { + gas_price: Some(gas_price), + max_fee_per_gas: Some(signed_tx.max_fee_per_gas()), + } + } + _ => GasPrice::default(), } - _ => { - // OP-deposit - (Some(signed_tx.max_fee_per_gas()), None) - } - }; + } - // let chain_id = signed_tx.chain_id().map(U64::from); - let chain_id = signed_tx.chain_id(); - let blob_versioned_hashes = signed_tx.blob_versioned_hashes(); - let access_list = signed_tx.access_list().cloned(); - let authorization_list = signed_tx.authorization_list().map(|l| l.to_vec()); - - let signature = - from_primitive_signature(*signed_tx.signature(), signed_tx.tx_type(), signed_tx.chain_id()); - - WithOtherFields { - inner: Transaction { - hash: signed_tx.hash(), - nonce: signed_tx.nonce(), - from: signer, - to, - value: signed_tx.value(), - gas_price, - max_fee_per_gas, - max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas(), - signature: Some(signature), - gas: signed_tx.gas_limit() as u128, - input: signed_tx.input().clone(), - chain_id, - access_list, - transaction_type: Some(signed_tx.tx_type() as u8), - // These fields are set to None because they are not stored as part of the transaction - block_hash: tx_info.block_hash, - block_number: tx_info.block_number, - transaction_index: tx_info.index, - // EIP-4844 fields - max_fee_per_blob_gas: signed_tx.max_fee_per_blob_gas(), - blob_versioned_hashes, - // EIP-7702 fields - authorization_list, - }, - // Optimism fields - #[cfg(feature = "optimism")] - other: reth_rpc_types::optimism::OptimismTransactionFields { - source_hash: signed_tx.source_hash(), - mint: signed_tx.mint(), - // only include is_system_tx if true: - is_system_tx: (signed_tx.is_deposit() && signed_tx.is_system_transaction()) - .then_some(true), - deposit_receipt_version: None, - } - .into(), - #[cfg(not(feature = "optimism"))] - other: Default::default(), + /// Create a new rpc transaction result for a _pending_ signed transaction, setting block + /// environment related fields to `None`. + fn fill(tx: TransactionSignedEcRecovered, tx_inf: TransactionInfo) -> Self::Transaction; + + /// Truncates the input of a transaction to only the first 4 bytes. + // todo: remove in favour of using constructor on `TransactionResponse` or similar + // . + fn otterscan_api_truncate_input(tx: &mut Self::Transaction); + + /// Returns the transaction type. + // todo: remove when alloy TransactionResponse trait it updated. + fn tx_type(tx: &Self::Transaction) -> u8; +} + +impl TransactionCompat for () { + // this noop impl depends on integration in `reth_rpc_eth_api::EthApiTypes` noop impl, and + // `alloy_network::AnyNetwork` + type Transaction = WithOtherFields; + + fn fill(_tx: TransactionSignedEcRecovered, _tx_info: TransactionInfo) -> Self::Transaction { + WithOtherFields::default() } + + fn otterscan_api_truncate_input(_tx: &mut Self::Transaction) {} + + fn tx_type(_tx: &Self::Transaction) -> u8 { + 0 + } +} + +/// Gas price and max fee per gas for a transaction. Helper type to format transaction RPC response. +#[derive(Debug, Default)] +pub struct GasPrice { + /// Gas price for transaction. + pub gas_price: Option, + /// Max fee per gas for transaction. + pub max_fee_per_gas: Option, } /// Convert [`TransactionSignedEcRecovered`] to [`TransactionRequest`] diff --git a/crates/rpc/rpc-types-compat/src/transaction/signature.rs b/crates/rpc/rpc-types-compat/src/transaction/signature.rs index b68568ee5d4d..34866677d501 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/signature.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/signature.rs @@ -7,7 +7,7 @@ use reth_rpc_types::{Parity, Signature}; /// recovery id. /// /// If the chain id is `Some`, the recovery id is computed according to [EIP-155](https://eips.ethereum.org/EIPS/eip-155). -pub(crate) fn from_legacy_primitive_signature( +pub fn from_legacy_primitive_signature( signature: PrimitiveSignature, chain_id: Option, ) -> Signature { @@ -22,7 +22,7 @@ pub(crate) fn from_legacy_primitive_signature( /// Creates a new rpc signature from a non-legacy [primitive /// signature](reth_primitives::Signature). This sets the `v` value to `0` or `1` depending on /// the signature's `odd_y_parity`. -pub(crate) fn from_typed_primitive_signature(signature: PrimitiveSignature) -> Signature { +pub fn from_typed_primitive_signature(signature: PrimitiveSignature) -> Signature { Signature { r: signature.r, s: signature.s, @@ -40,7 +40,7 @@ pub(crate) fn from_typed_primitive_signature(signature: PrimitiveSignature) -> S /// If the transaction is a legacy transaction, it will use the `chain_id` to compute the /// signature's recovery id. If the transaction is a typed transaction, it will set the `v` /// value to `0` or `1` depending on the signature's `odd_y_parity`. -pub(crate) fn from_primitive_signature( +pub fn from_primitive_signature( signature: PrimitiveSignature, tx_type: TxType, chain_id: Option, diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 028ce238f761..9f8235725c8d 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -38,7 +38,6 @@ reth-trie.workspace = true # ethereum alloy-dyn-abi.workspace = true -alloy-eips.workspace = true alloy-genesis.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true diff --git a/crates/rpc/rpc/src/engine.rs b/crates/rpc/rpc/src/engine.rs index 53df19ff9ca9..c646d6809c40 100644 --- a/crates/rpc/rpc/src/engine.rs +++ b/crates/rpc/rpc/src/engine.rs @@ -1,14 +1,13 @@ -use alloy_eips::{BlockId, BlockNumberOrTag}; -use alloy_network::Network; use alloy_primitives::{Address, Bytes, B256, U256, U64}; use jsonrpsee::core::RpcResult as Result; +use reth_primitives::{BlockId, BlockNumberOrTag}; use reth_rpc_api::{EngineEthApiServer, EthApiServer, EthFilterApiServer}; /// Re-export for convenience pub use reth_rpc_engine_api::EngineApi; -use reth_rpc_eth_api::{EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; +use reth_rpc_eth_api::{FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; use reth_rpc_types::{ state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, JsonStorageKey, Log, - SyncStatus, TransactionRequest, WithOtherFields, + SyncStatus, TransactionRequest, }; use tracing_futures::Instrument; @@ -41,11 +40,7 @@ where RpcTransaction, RpcBlock, RpcReceipt, - > + EthApiTypes< - NetworkTypes: Network< - TransactionResponse = WithOtherFields, - >, - >, + > + FullEthApiTypes, EthFilter: EthFilterApiServer>, { /// Handler for: `eth_syncing` diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 3836ed0128e0..c70d16a0cafc 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -23,6 +23,8 @@ use reth_tasks::{ }; use tokio::sync::Mutex; +use crate::eth::EthTxBuilder; + /// `Eth` API implementation. /// /// This type provides the functionality for handling `eth_` related requests. @@ -93,7 +95,7 @@ where { /// Creates a new, shareable instance. pub fn with_spawner( - ctx: &EthApiBuilderCtx, + ctx: &EthApiBuilderCtx, ) -> Self where Tasks: TaskSpawner + Clone + 'static, @@ -127,7 +129,9 @@ where Self: Send + Sync, { type Error = EthApiError; + // todo: replace with alloy_network::Ethereum type NetworkTypes = AnyNetwork; + type TransactionCompat = EthTxBuilder; } impl std::fmt::Debug @@ -163,8 +167,15 @@ impl BuilderProvider for EthApi where N: FullNodeComponents, { - type Ctx<'a> = - &'a EthApiBuilderCtx; + type Ctx<'a> = &'a EthApiBuilderCtx< + N::Provider, + N::Pool, + N::Evm, + N::Network, + TaskExecutor, + N::Provider, + Self, + >; fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { Box::new(Self::with_spawner) diff --git a/crates/rpc/rpc/src/eth/filter.rs b/crates/rpc/rpc/src/eth/filter.rs index 8f905929b798..2b6a7f79796b 100644 --- a/crates/rpc/rpc/src/eth/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -4,6 +4,7 @@ use std::{ collections::HashMap, fmt, iter::StepBy, + marker::PhantomData, ops::RangeInclusive, sync::Arc, time::{Duration, Instant}, @@ -13,9 +14,10 @@ use alloy_primitives::TxHash; use async_trait::async_trait; use jsonrpsee::{core::RpcResult, server::IdProvider}; use reth_chainspec::ChainInfo; +use reth_node_api::EthApiTypes; use reth_primitives::{IntoRecoveredTransaction, TransactionSignedEcRecovered}; use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError}; -use reth_rpc_eth_api::EthFilterApiServer; +use reth_rpc_eth_api::{EthFilterApiServer, FullEthApiTypes, RpcTransaction, TransactionCompat}; use reth_rpc_eth_types::{ logs_utils::{self, append_matching_block_logs}, EthApiError, EthFilterConfig, EthFilterError, EthStateCache, EthSubscriptionIdProvider, @@ -23,8 +25,9 @@ use reth_rpc_eth_types::{ use reth_rpc_server_types::ToRpcResult; use reth_rpc_types::{ BlockNumHash, Filter, FilterBlockOption, FilterChanges, FilterId, FilteredParams, Log, - PendingTransactionFilterKind, Transaction, WithOtherFields, + PendingTransactionFilterKind, }; +use reth_rpc_types_compat::transaction::from_recovered; use reth_tasks::TaskSpawner; use reth_transaction_pool::{NewSubpoolTransactionStream, PoolTransaction, TransactionPool}; use tokio::{ @@ -37,15 +40,27 @@ use tracing::trace; const MAX_HEADERS_RANGE: u64 = 1_000; // with ~530bytes per header this is ~500kb /// `Eth` filter RPC implementation. -pub struct EthFilter { +pub struct EthFilter { /// All nested fields bundled together - inner: Arc>, + inner: Arc>>, + /// Assembles response data w.r.t. network. + _tx_resp_builder: PhantomData, } -impl EthFilter +impl Clone for EthFilter +where + Eth: EthApiTypes, +{ + fn clone(&self) -> Self { + Self { inner: self.inner.clone(), _tx_resp_builder: PhantomData } + } +} + +impl EthFilter where Provider: Send + Sync + 'static, Pool: Send + Sync + 'static, + Eth: EthApiTypes + 'static, { /// Creates a new, shareable instance. /// @@ -66,7 +81,7 @@ where config; let inner = EthFilterInner { provider, - active_filters: Default::default(), + active_filters: ActiveFilters::new(), pool, id_provider: Arc::new(EthSubscriptionIdProvider::default()), eth_cache, @@ -78,7 +93,7 @@ where max_logs_per_response: max_logs_per_response.unwrap_or(usize::MAX), }; - let eth_filter = Self { inner: Arc::new(inner) }; + let eth_filter = Self { inner: Arc::new(inner), _tx_resp_builder: PhantomData }; let this = eth_filter.clone(); eth_filter.inner.task_spawner.spawn_critical( @@ -92,7 +107,7 @@ where } /// Returns all currently active filters - pub fn active_filters(&self) -> &ActiveFilters { + pub fn active_filters(&self) -> &ActiveFilters> { &self.inner.active_filters } @@ -126,17 +141,18 @@ where } } -impl EthFilter +impl EthFilter where Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static, Pool: TransactionPool + 'static, ::Transaction: 'static, + Eth: FullEthApiTypes, { /// Returns all the filter changes for the given id, if any pub async fn filter_changes( &self, id: FilterId, - ) -> Result>, EthFilterError> { + ) -> Result>, EthFilterError> { let info = self.inner.provider.chain_info()?; let best_number = info.best_number; @@ -225,21 +241,25 @@ where } #[async_trait] -impl EthFilterApiServer> for EthFilter +impl EthFilterApiServer> + for EthFilter where Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static, Pool: TransactionPool + 'static, + Eth: FullEthApiTypes + 'static, { /// Handler for `eth_newFilter` async fn new_filter(&self, filter: Filter) -> RpcResult { trace!(target: "rpc::eth", "Serving eth_newFilter"); - self.inner.install_filter(FilterKind::Log(Box::new(filter))).await + self.inner + .install_filter(FilterKind::>::Log(Box::new(filter))) + .await } /// Handler for `eth_newBlockFilter` async fn new_block_filter(&self) -> RpcResult { trace!(target: "rpc::eth", "Serving eth_newBlockFilter"); - self.inner.install_filter(FilterKind::Block).await + self.inner.install_filter(FilterKind::>::Block).await } /// Handler for `eth_newPendingTransactionFilter` @@ -257,7 +277,8 @@ where } PendingTransactionFilterKind::Full => { let stream = self.inner.pool.new_pending_pool_transactions_listener(); - let full_txs_receiver = FullTransactionsReceiver::new(stream); + let full_txs_receiver = + FullTransactionsReceiver::<_, Eth::TransactionCompat>::new(stream); FilterKind::PendingTransaction(PendingTransactionKind::FullTransaction(Arc::new( full_txs_receiver, ))) @@ -274,7 +295,7 @@ where async fn filter_changes( &self, id: FilterId, - ) -> RpcResult>> { + ) -> RpcResult>> { trace!(target: "rpc::eth", "Serving eth_getFilterChanges"); Ok(Self::filter_changes(self, id).await?) } @@ -310,27 +331,24 @@ where } } -impl std::fmt::Debug for EthFilter { +impl std::fmt::Debug for EthFilter +where + Eth: EthApiTypes, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthFilter").finish_non_exhaustive() } } -impl Clone for EthFilter { - fn clone(&self) -> Self { - Self { inner: Arc::clone(&self.inner) } - } -} - /// Container type `EthFilter` #[derive(Debug)] -struct EthFilterInner { +struct EthFilterInner { /// The transaction pool. pool: Pool, /// The provider that can interact with the chain. provider: Provider, /// All currently installed filters. - active_filters: ActiveFilters, + active_filters: ActiveFilters, /// Provides ids to identify filters id_provider: Arc, /// Maximum number of blocks that could be scanned per filter @@ -347,7 +365,7 @@ struct EthFilterInner { stale_filter_ttl: Duration, } -impl EthFilterInner +impl EthFilterInner where Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static, Pool: TransactionPool + 'static, @@ -408,7 +426,7 @@ where } /// Installs a new filter and returns the new identifier. - async fn install_filter(&self, kind: FilterKind) -> RpcResult { + async fn install_filter(&self, kind: FilterKind) -> RpcResult { let last_poll_block_number = self.provider.best_block_number().to_rpc_result()?; let id = FilterId::from(self.id_provider.next_id()); let mut filters = self.active_filters.inner.lock().await; @@ -526,19 +544,26 @@ where /// All active filters #[derive(Debug, Clone, Default)] -pub struct ActiveFilters { - inner: Arc>>, +pub struct ActiveFilters { + inner: Arc>>>, +} + +impl ActiveFilters { + /// Returns an empty instance. + pub fn new() -> Self { + Self { inner: Arc::new(Mutex::new(HashMap::new())) } + } } /// An installed filter #[derive(Debug)] -struct ActiveFilter { +struct ActiveFilter { /// At which block the filter was polled last. block: u64, /// Last time this filter was polled. last_poll_timestamp: Instant, /// What kind of filter it is. - kind: FilterKind, + kind: FilterKind, } /// A receiver for pending transactions that returns all new transactions since the last poll. @@ -553,7 +578,7 @@ impl PendingTransactionsReceiver { } /// Returns all new pending transactions received since the last poll. - async fn drain(&self) -> FilterChanges> { + async fn drain(&self) -> FilterChanges { let mut pending_txs = Vec::new(); let mut prepared_stream = self.txs_receiver.lock().await; @@ -568,21 +593,23 @@ impl PendingTransactionsReceiver { /// A structure to manage and provide access to a stream of full transaction details. #[derive(Debug, Clone)] -struct FullTransactionsReceiver { +struct FullTransactionsReceiver { txs_stream: Arc>>, + _tx_resp_builder: PhantomData, } -impl FullTransactionsReceiver +impl FullTransactionsReceiver where T: PoolTransaction + 'static, + TxCompat: TransactionCompat, { /// Creates a new `FullTransactionsReceiver` encapsulating the provided transaction stream. fn new(stream: NewSubpoolTransactionStream) -> Self { - Self { txs_stream: Arc::new(Mutex::new(stream)) } + Self { txs_stream: Arc::new(Mutex::new(stream)), _tx_resp_builder: PhantomData } } /// Returns all new pending transactions received since the last poll. - async fn drain(&self) -> FilterChanges> + async fn drain(&self) -> FilterChanges where T: PoolTransaction, { @@ -590,9 +617,7 @@ where let mut prepared_stream = self.txs_stream.lock().await; while let Ok(tx) = prepared_stream.try_recv() { - pending_txs.push(reth_rpc_types_compat::transaction::from_recovered( - tx.transaction.to_recovered_transaction(), - )) + pending_txs.push(from_recovered::(tx.transaction.to_recovered_transaction())) } FilterChanges::Transactions(pending_txs) } @@ -600,16 +625,18 @@ where /// Helper trait for [FullTransactionsReceiver] to erase the `Transaction` type. #[async_trait] -trait FullTransactionsFilter: fmt::Debug + Send + Sync + Unpin + 'static { - async fn drain(&self) -> FilterChanges>; +trait FullTransactionsFilter: fmt::Debug + Send + Sync + Unpin + 'static { + async fn drain(&self) -> FilterChanges; } #[async_trait] -impl FullTransactionsFilter for FullTransactionsReceiver +impl FullTransactionsFilter + for FullTransactionsReceiver where T: PoolTransaction + 'static, + TxCompat: TransactionCompat + 'static, { - async fn drain(&self) -> FilterChanges> { + async fn drain(&self) -> FilterChanges { Self::drain(self).await } } @@ -620,13 +647,13 @@ where /// - Just the transaction hashes. /// - Full transaction details. #[derive(Debug, Clone)] -enum PendingTransactionKind { +enum PendingTransactionKind { Hashes(PendingTransactionsReceiver), - FullTransaction(Arc), + FullTransaction(Arc>), } -impl PendingTransactionKind { - async fn drain(&self) -> FilterChanges> { +impl PendingTransactionKind { + async fn drain(&self) -> FilterChanges { match self { Self::Hashes(receiver) => receiver.drain().await, Self::FullTransaction(receiver) => receiver.drain().await, @@ -635,10 +662,10 @@ impl PendingTransactionKind { } #[derive(Clone, Debug)] -enum FilterKind { +enum FilterKind { Log(Box), Block, - PendingTransaction(PendingTransactionKind), + PendingTransaction(PendingTransactionKind), } /// An iterator that yields _inclusive_ block ranges of a given step size diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs index 5e16ce64d819..3cc12c443d4a 100644 --- a/crates/rpc/rpc/src/eth/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -1,19 +1,22 @@ //! Contains RPC handler implementations specific to blocks. -use reth_primitives::{BlockId, TransactionMeta}; +use reth_primitives::TransactionMeta; use reth_provider::{BlockReaderIdExt, HeaderProvider}; use reth_rpc_eth_api::{ helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, - FromEthApiError, + RpcReceipt, }; -use reth_rpc_eth_types::{EthStateCache, ReceiptBuilder}; -use reth_rpc_types::AnyTransactionReceipt; +use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; +use reth_rpc_types::{AnyTransactionReceipt, BlockId}; use crate::EthApi; impl EthBlocks for EthApi where - Self: LoadBlock, + Self: LoadBlock< + Error = EthApiError, + NetworkTypes: alloy_network::Network, + >, Provider: HeaderProvider, { #[inline] @@ -24,7 +27,7 @@ where async fn block_receipts( &self, block_id: BlockId, - ) -> Result>, Self::Error> + ) -> Result>>, Self::Error> where Self: LoadReceipt, { @@ -36,7 +39,7 @@ where let timestamp = block.timestamp; let block = block.unseal(); - let receipts = block + return block .body .into_iter() .zip(receipts.iter()) @@ -54,10 +57,9 @@ where ReceiptBuilder::new(&tx, meta, receipt, &receipts) .map(|builder| builder.build()) - .map_err(Self::Error::from_eth_err) }) - .collect::, Self::Error>>(); - return receipts.map(Some) + .collect::, Self::Error>>() + .map(Some) } Ok(None) diff --git a/crates/rpc/rpc/src/eth/helpers/mod.rs b/crates/rpc/rpc/src/eth/helpers/mod.rs index f0a0cccb5536..03e0443a15bb 100644 --- a/crates/rpc/rpc/src/eth/helpers/mod.rs +++ b/crates/rpc/rpc/src/eth/helpers/mod.rs @@ -2,6 +2,7 @@ //! files. pub mod signer; +pub mod types; mod block; mod call; diff --git a/crates/rpc/rpc/src/eth/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs index 77a4058240e7..2ac360944943 100644 --- a/crates/rpc/rpc/src/eth/helpers/receipt.rs +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -1,9 +1,8 @@ //! Builds an RPC receipt response w.r.t. data layout of network. use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; -use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError}; +use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt}; use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder}; -use reth_rpc_types::AnyTransactionReceipt; use crate::EthApi; @@ -21,7 +20,7 @@ where tx: TransactionSigned, meta: TransactionMeta, receipt: Receipt, - ) -> Result { + ) -> Result, Self::Error> { let hash = meta.block_hash; // get all receipts for the block let all_receipts = self diff --git a/crates/rpc/rpc/src/eth/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs index 17eff7b35772..8bd9997f6e8a 100644 --- a/crates/rpc/rpc/src/eth/helpers/transaction.rs +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -1,7 +1,10 @@ //! Contains RPC handler implementations specific to transactions use reth_provider::{BlockReaderIdExt, TransactionsProvider}; -use reth_rpc_eth_api::helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}; +use reth_rpc_eth_api::{ + helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, + FullEthApiTypes, +}; use reth_rpc_eth_types::EthStateCache; use reth_transaction_pool::TransactionPool; @@ -28,7 +31,7 @@ where impl LoadTransaction for EthApi where - Self: SpawnBlocking, + Self: SpawnBlocking + FullEthApiTypes, Provider: TransactionsProvider, Pool: TransactionPool, { diff --git a/crates/rpc/rpc/src/eth/helpers/types.rs b/crates/rpc/rpc/src/eth/helpers/types.rs new file mode 100644 index 000000000000..0047f3636386 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/types.rs @@ -0,0 +1,85 @@ +//! L1 `eth` API types. + +use alloy_network::{AnyNetwork, Network}; +use reth_primitives::{Address, TransactionSignedEcRecovered, TxKind}; +use reth_rpc_types::{Transaction, TransactionInfo, WithOtherFields}; +use reth_rpc_types_compat::{ + transaction::{from_primitive_signature, GasPrice}, + TransactionCompat, +}; + +/// Builds RPC transaction response for l1. +#[derive(Debug, Clone, Copy)] +pub struct EthTxBuilder; + +impl TransactionCompat for EthTxBuilder +where + Self: Send + Sync, +{ + type Transaction = ::TransactionResponse; + + fn fill(tx: TransactionSignedEcRecovered, tx_info: TransactionInfo) -> Self::Transaction { + let signer = tx.signer(); + let signed_tx = tx.into_signed(); + + let to: Option
= match signed_tx.kind() { + TxKind::Create => None, + TxKind::Call(to) => Some(Address(*to)), + }; + + let TransactionInfo { + base_fee, block_hash, block_number, index: transaction_index, .. + } = tx_info; + + let GasPrice { gas_price, max_fee_per_gas } = + Self::gas_price(&signed_tx, base_fee.map(|fee| fee as u64)); + + let chain_id = signed_tx.chain_id(); + let blob_versioned_hashes = signed_tx.blob_versioned_hashes(); + let access_list = signed_tx.access_list().cloned(); + let authorization_list = signed_tx.authorization_list().map(|l| l.to_vec()); + + let signature = from_primitive_signature( + *signed_tx.signature(), + signed_tx.tx_type(), + signed_tx.chain_id(), + ); + + WithOtherFields { + inner: Transaction { + hash: signed_tx.hash(), + nonce: signed_tx.nonce(), + from: signer, + to, + value: signed_tx.value(), + gas_price, + max_fee_per_gas, + max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas(), + signature: Some(signature), + gas: signed_tx.gas_limit() as u128, + input: signed_tx.input().clone(), + chain_id, + access_list, + transaction_type: Some(signed_tx.tx_type() as u8), + // These fields are set to None because they are not stored as part of the + // transaction + block_hash, + block_number, + transaction_index, + // EIP-4844 fields + max_fee_per_blob_gas: signed_tx.max_fee_per_blob_gas(), + blob_versioned_hashes, + authorization_list, + }, + ..Default::default() + } + } + + fn otterscan_api_truncate_input(tx: &mut Self::Transaction) { + tx.inner.input = tx.inner.input.slice(..4); + } + + fn tx_type(tx: &Self::Transaction) -> u8 { + tx.inner.transaction_type.unwrap_or(0) + } +} diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs index 0addeb75ae77..83db119f8804 100644 --- a/crates/rpc/rpc/src/eth/mod.rs +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -12,6 +12,6 @@ pub use core::EthApi; pub use filter::EthFilter; pub use pubsub::EthPubSub; -pub use helpers::signer::DevSigner; +pub use helpers::{signer::DevSigner, types::EthTxBuilder}; pub use reth_rpc_eth_api::EthApiServer; diff --git a/crates/rpc/rpc/src/eth/pubsub.rs b/crates/rpc/rpc/src/eth/pubsub.rs index 64fe17e17167..e1ad6e853ae7 100644 --- a/crates/rpc/rpc/src/eth/pubsub.rs +++ b/crates/rpc/rpc/src/eth/pubsub.rs @@ -1,6 +1,6 @@ //! `eth_` `PubSub` RPC handler implementation -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use alloy_primitives::TxHash; use futures::StreamExt; @@ -10,7 +10,7 @@ use jsonrpsee::{ use reth_network_api::NetworkInfo; use reth_primitives::IntoRecoveredTransaction; use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider}; -use reth_rpc_eth_api::pubsub::EthPubSubApiServer; +use reth_rpc_eth_api::{pubsub::EthPubSubApiServer, FullEthApiTypes, RpcTransaction}; use reth_rpc_eth_types::logs_utils; use reth_rpc_server_types::result::{internal_rpc_err, invalid_params_rpc_err}; use reth_rpc_types::{ @@ -20,6 +20,7 @@ use reth_rpc_types::{ }, FilteredParams, Header, Log, Transaction, WithOtherFields, }; +use reth_rpc_types_compat::transaction::from_recovered; use reth_tasks::{TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{NewTransactionEvent, TransactionPool}; use serde::Serialize; @@ -32,16 +33,17 @@ use tokio_stream::{ /// /// This handles `eth_subscribe` RPC calls. #[derive(Clone)] -pub struct EthPubSub { +pub struct EthPubSub { /// All nested fields bundled together. inner: Arc>, /// The type that's used to spawn subscription tasks. subscription_task_spawner: Box, + _tx_resp_builder: PhantomData, } // === impl EthPubSub === -impl EthPubSub { +impl EthPubSub { /// Creates a new, shareable instance. /// /// Subscription tasks are spawned via [`tokio::task::spawn`] @@ -64,18 +66,19 @@ impl EthPubSub subscription_task_spawner: Box, ) -> Self { let inner = EthPubSubInner { provider, pool, chain_events, network }; - Self { inner: Arc::new(inner), subscription_task_spawner } + Self { inner: Arc::new(inner), subscription_task_spawner, _tx_resp_builder: PhantomData } } } #[async_trait::async_trait] -impl EthPubSubApiServer - for EthPubSub +impl EthPubSubApiServer> + for EthPubSub where Provider: BlockReader + EvmEnvProvider + Clone + 'static, Pool: TransactionPool + 'static, Events: CanonStateSubscriptions + Clone + 'static, Network: NetworkInfo + Clone + 'static, + Eth: FullEthApiTypes + 'static, { /// Handler for `eth_subscribe` async fn subscribe( @@ -87,7 +90,7 @@ where let sink = pending.accept().await?; let pubsub = self.inner.clone(); self.subscription_task_spawner.spawn(Box::pin(async move { - let _ = handle_accepted(pubsub, sink, kind, params).await; + let _ = handle_accepted::<_, _, _, _, Eth>(pubsub, sink, kind, params).await; })); Ok(()) @@ -95,7 +98,7 @@ where } /// The actual handler for an accepted [`EthPubSub::subscribe`] call. -async fn handle_accepted( +async fn handle_accepted( pubsub: Arc>, accepted_sink: SubscriptionSink, kind: SubscriptionKind, @@ -106,6 +109,7 @@ where Pool: TransactionPool + 'static, Events: CanonStateSubscriptions + Clone + 'static, Network: NetworkInfo + Clone + 'static, + Eth: FullEthApiTypes, { match kind { SubscriptionKind::NewHeads => { @@ -136,11 +140,11 @@ where Params::Bool(true) => { // full transaction objects requested let stream = pubsub.full_pending_transaction_stream().map(|tx| { - EthSubscriptionResult::FullTransaction(Box::new( - reth_rpc_types_compat::transaction::from_recovered( - tx.transaction.to_recovered_transaction(), - ), - )) + EthSubscriptionResult::FullTransaction(Box::new(from_recovered::< + Eth::TransactionCompat, + >( + tx.transaction.to_recovered_transaction(), + ))) }); return pipe_from_stream(accepted_sink, stream).await } @@ -246,8 +250,8 @@ where } } -impl std::fmt::Debug - for EthPubSub +impl std::fmt::Debug + for EthPubSub { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EthPubSub").finish_non_exhaustive() diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 94bc8c2d13d8..d88ec7a85322 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -1,12 +1,12 @@ -use alloy_eips::{BlockId, BlockNumberOrTag}; -use alloy_network::Network; +use alloy_network::{ReceiptResponse, TransactionResponse}; use alloy_primitives::{Address, Bytes, TxHash, B256, U256}; use async_trait::async_trait; use jsonrpsee::{core::RpcResult, types::ErrorObjectOwned}; +use reth_primitives::{BlockId, BlockNumberOrTag}; use reth_rpc_api::{EthApiServer, OtterscanServer}; use reth_rpc_eth_api::{ helpers::{EthTransactions, TraceExt}, - EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction, + FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction, TransactionCompat, }; use reth_rpc_eth_types::{utils::binary_search, EthApiError}; use reth_rpc_server_types::result::internal_rpc_err; @@ -18,13 +18,13 @@ use reth_rpc_types::{ }, parity::{Action, CreateAction, CreateOutput, TraceOutput}, }, - AnyTransactionReceipt, BlockTransactions, Header, Transaction, WithOtherFields, + BlockTransactions, Header, TransactionReceipt, }; use revm_inspectors::{ tracing::{types::CallTraceNode, TracingInspectorConfig}, transfer::{TransferInspector, TransferKind}, }; -use revm_primitives::ExecutionResult; +use revm_primitives::{ExecutionResult, SignedAuthorization}; const API_LEVEL: u64 = 8; @@ -43,12 +43,7 @@ impl OtterscanApi { impl OtterscanApi where - Eth: EthApiTypes< - NetworkTypes: Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - >, + Eth: FullEthApiTypes, { /// Constructs a `BlockDetails` from a block and its receipts. fn block_details( @@ -59,7 +54,7 @@ where // blob fee is burnt, so we don't need to calculate it let total_fees = receipts .iter() - .map(|receipt| receipt.gas_used.saturating_mul(receipt.effective_gas_price)) + .map(|receipt| receipt.gas_used().saturating_mul(receipt.effective_gas_price())) .sum::(); Ok(BlockDetails::new(block, Default::default(), U256::from(total_fees))) @@ -67,19 +62,14 @@ where } #[async_trait] -impl OtterscanServer for OtterscanApi +impl OtterscanServer> for OtterscanApi where Eth: EthApiServer< RpcTransaction, RpcBlock, RpcReceipt, - > + EthApiTypes< - NetworkTypes: Network< - TransactionResponse = WithOtherFields, - ReceiptResponse = AnyTransactionReceipt, - >, - > + TraceExt - + EthTransactions + > + EthTransactions + + TraceExt + 'static, { /// Handler for `{ots,erigon}_getHeaderByNumber` @@ -207,7 +197,7 @@ where block_number: u64, page_number: usize, page_size: usize, - ) -> RpcResult>> { + ) -> RpcResult>> { let block_id = block_number.into(); // retrieve full block and its receipts let block = self.eth.block_by_number(block_id, true); @@ -240,9 +230,9 @@ where // The input field returns only the 4 bytes method selector instead of the entire // calldata byte blob. - for tx in transactions { - if tx.input.len() > 4 { - tx.input = tx.input.slice(..4); + for tx in transactions.iter_mut() { + if tx.input().len() > 4 { + Eth::TransactionCompat::otterscan_api_truncate_input(tx); } } @@ -250,19 +240,34 @@ where let timestamp = Some(block.header.timestamp); let receipts = receipts .drain(page_start..page_end) - .map(|receipt| { - let receipt = receipt.inner.map_inner(|receipt| OtsReceipt { - status: receipt - .inner - .receipt - .status - .as_eip658() - .expect("ETH API returned pre-EIP-658 status"), - cumulative_gas_used: receipt.inner.receipt.cumulative_gas_used as u64, + .zip(transactions.iter().map(Eth::TransactionCompat::tx_type)) + .map(|(receipt, tx_ty)| { + let inner = OtsReceipt { + status: receipt.status(), + cumulative_gas_used: receipt.cumulative_gas_used() as u64, logs: None, logs_bloom: None, - r#type: receipt.r#type, - }); + r#type: tx_ty, + }; + + let receipt = TransactionReceipt { + inner, + transaction_hash: receipt.transaction_hash(), + transaction_index: receipt.transaction_index(), + block_hash: receipt.block_hash(), + block_number: receipt.block_number(), + gas_used: receipt.gas_used(), + effective_gas_price: receipt.effective_gas_price(), + blob_gas_used: receipt.blob_gas_used(), + blob_gas_price: receipt.blob_gas_price(), + from: receipt.from(), + to: receipt.to(), + contract_address: receipt.contract_address(), + state_root: receipt.state_root(), + authorization_list: receipt + .authorization_list() + .map(<[SignedAuthorization]>::to_vec), + }; OtsTransactionReceipt { receipt, timestamp } }) @@ -305,7 +310,7 @@ where .get_transaction_by_sender_and_nonce(sender, nonce, false) .await .map_err(Into::into)? - .map(|tx| tx.hash)) + .map(|tx| tx.tx_hash())) } /// Handler for `getContractCreator` diff --git a/crates/rpc/rpc/src/txpool.rs b/crates/rpc/rpc/src/txpool.rs index db63167e391d..4b1e43766a8a 100644 --- a/crates/rpc/rpc/src/txpool.rs +++ b/crates/rpc/rpc/src/txpool.rs @@ -1,56 +1,63 @@ +use std::{collections::BTreeMap, marker::PhantomData}; + use alloy_primitives::Address; use async_trait::async_trait; use jsonrpsee::core::RpcResult as Result; use reth_primitives::TransactionSignedEcRecovered; use reth_rpc_api::TxPoolApiServer; -use reth_rpc_types::{ - txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus}, - Transaction, WithOtherFields, +use reth_rpc_eth_api::{FullEthApiTypes, RpcTransaction}; +use reth_rpc_types::txpool::{ + TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus, }; +use reth_rpc_types_compat::{transaction::from_recovered, TransactionCompat}; use reth_transaction_pool::{AllPoolTransactions, PoolTransaction, TransactionPool}; -use std::collections::BTreeMap; use tracing::trace; /// `txpool` API implementation. /// /// This type provides the functionality for handling `txpool` related requests. #[derive(Clone)] -pub struct TxPoolApi { +pub struct TxPoolApi { /// An interface to interact with the pool pool: Pool, + _tx_resp_builder: PhantomData, } -impl TxPoolApi { +impl TxPoolApi { /// Creates a new instance of `TxpoolApi`. pub const fn new(pool: Pool) -> Self { - Self { pool } + Self { pool, _tx_resp_builder: PhantomData } } } -impl TxPoolApi +impl TxPoolApi where Pool: TransactionPool + 'static, + Eth: FullEthApiTypes, { - fn content(&self) -> TxpoolContent> { + fn content(&self) -> TxpoolContent> { #[inline] - fn insert>( - tx: &T, - content: &mut BTreeMap>>, - ) { + fn insert( + tx: &Tx, + content: &mut BTreeMap>, + ) where + Tx: PoolTransaction, + RpcTxB: TransactionCompat, + { content.entry(tx.sender()).or_default().insert( tx.nonce().to_string(), - reth_rpc_types_compat::transaction::from_recovered(tx.clone().into_consensus()), + from_recovered::(tx.clone().into_consensus()), ); } let AllPoolTransactions { pending, queued } = self.pool.all_transactions(); - let mut content = TxpoolContent::default(); + let mut content = TxpoolContent { pending: BTreeMap::new(), queued: BTreeMap::new() }; for pending in pending { - insert(&pending.transaction, &mut content.pending); + insert::<_, Eth::TransactionCompat>(&pending.transaction, &mut content.pending); } for queued in queued { - insert(&queued.transaction, &mut content.queued); + insert::<_, Eth::TransactionCompat>(&queued.transaction, &mut content.queued); } content @@ -58,9 +65,10 @@ where } #[async_trait] -impl TxPoolApiServer for TxPoolApi +impl TxPoolApiServer> for TxPoolApi where Pool: TransactionPool + 'static, + Eth: FullEthApiTypes + 'static, { /// Returns the number of transactions currently pending for inclusion in the next block(s), as /// well as the ones that are being scheduled for future execution only. @@ -122,7 +130,7 @@ where async fn txpool_content_from( &self, from: Address, - ) -> Result>> { + ) -> Result>> { trace!(target: "rpc::eth", ?from, "Serving txpool_contentFrom"); Ok(self.content().remove_from(&from)) } @@ -132,13 +140,13 @@ where /// /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details /// Handler for `txpool_content` - async fn txpool_content(&self) -> Result>> { + async fn txpool_content(&self) -> Result>> { trace!(target: "rpc::eth", "Serving txpool_content"); Ok(self.content()) } } -impl std::fmt::Debug for TxPoolApi { +impl std::fmt::Debug for TxPoolApi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TxpoolApi").finish_non_exhaustive() }