diff --git a/Cargo.lock b/Cargo.lock index 867a8cdc6afb..06c419a21330 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6837,6 +6837,7 @@ dependencies = [ "reth-db", "reth-network-peers", "reth-node-builder", + "reth-node-ethereum", "reth-payload-builder", "reth-primitives", "reth-provider", @@ -7581,6 +7582,7 @@ dependencies = [ "reth-rpc", "reth-rpc-builder", "reth-rpc-engine-api", + "reth-rpc-eth-types", "reth-rpc-layer", "reth-rpc-types", "reth-stages", @@ -7683,6 +7685,7 @@ dependencies = [ "reth-node-core", "reth-payload-builder", "reth-provider", + "reth-rpc", "reth-tracing", "reth-transaction-pool", "serde_json", @@ -7740,6 +7743,7 @@ dependencies = [ "reth-node-builder", "reth-optimism-consensus", "reth-optimism-payload-builder", + "reth-optimism-rpc", "reth-payload-builder", "reth-primitives", "reth-provider", @@ -7749,6 +7753,7 @@ dependencies = [ "reth-rpc-eth-types", "reth-rpc-types", "reth-rpc-types-compat", + "reth-tasks", "reth-tracing", "reth-transaction-pool", "revm-primitives", @@ -7848,8 +7853,10 @@ dependencies = [ "reth-errors", "reth-evm", "reth-evm-optimism", + "reth-node-api", "reth-primitives", "reth-provider", + "reth-rpc", "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-server-types", @@ -8119,6 +8126,7 @@ dependencies = [ "reth-evm-optimism", "reth-network-api", "reth-network-peers", + "reth-node-api", "reth-primitives", "reth-provider", "reth-revm", @@ -8195,6 +8203,7 @@ dependencies = [ "reth-metrics", "reth-network-api", "reth-network-peers", + "reth-node-api", "reth-node-core", "reth-payload-builder", "reth-primitives", diff --git a/crates/e2e-test-utils/Cargo.toml b/crates/e2e-test-utils/Cargo.toml index f472da06bc12..2136327ac1bc 100644 --- a/crates/e2e-test-utils/Cargo.toml +++ b/crates/e2e-test-utils/Cargo.toml @@ -22,6 +22,7 @@ reth-node-builder = { workspace = true, features = ["test-utils"] } reth-tokio-util.workspace = true reth-stages-types.workspace = true reth-network-peers.workspace = true +reth-node-ethereum.workspace = true jsonrpsee.workspace = true diff --git a/crates/e2e-test-utils/src/lib.rs b/crates/e2e-test-utils/src/lib.rs index e55a9a24ba2e..5cc6850106d7 100644 --- a/crates/e2e-test-utils/src/lib.rs +++ b/crates/e2e-test-utils/src/lib.rs @@ -1,16 +1,19 @@ +use std::sync::Arc; + use node::NodeTestContext; use reth::{ args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, builder::{NodeBuilder, NodeConfig, NodeHandle}, + rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer}, tasks::TaskManager, }; use reth_chainspec::ChainSpec; use reth_db::{test_utils::TempDatabase, DatabaseEnv}; use reth_node_builder::{ - components::NodeComponentsBuilder, FullNodeTypesAdapter, Node, NodeAdapter, RethFullAdapter, + components::NodeComponentsBuilder, rpc::EthApiBuilderProvider, FullNodeTypesAdapter, Node, + NodeAdapter, NodeAddOns, RethFullAdapter, }; use reth_provider::providers::BlockchainProvider; -use std::sync::Arc; use tracing::{span, Level}; use wallet::Wallet; @@ -42,9 +45,11 @@ pub async fn setup( num_nodes: usize, chain_spec: Arc, is_dev: bool, -) -> eyre::Result<(Vec>, TaskManager, Wallet)> +) -> eyre::Result<(Vec>, TaskManager, Wallet)> where N: Default + Node>, + >>::EthApi: + FullEthApiServer + AddDevSigners + EthApiBuilderProvider>, { let tasks = TaskManager::current(); let exec = tasks.executor(); @@ -55,7 +60,7 @@ where }; // Create nodes and peer them - let mut nodes: Vec> = Vec::with_capacity(num_nodes); + let mut nodes: Vec> = Vec::with_capacity(num_nodes); for idx in 0..num_nodes { let node_config = NodeConfig::test() @@ -106,4 +111,4 @@ type Adapter = NodeAdapter< >; /// Type alias for a type of NodeHelper -pub type NodeHelperType = NodeTestContext>; +pub type NodeHelperType = NodeTestContext, AO>; diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index 684e0f401c1b..05d0a5f97854 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -1,7 +1,4 @@ -use crate::{ - engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext, - rpc::RpcTestContext, traits::PayloadEnvelopeExt, -}; +use std::{marker::PhantomData, pin::Pin}; use alloy_rpc_types::BlockNumberOrTag; use eyre::Ok; @@ -11,32 +8,41 @@ use reth::{ builder::FullNode, payload::PayloadTypes, providers::{BlockReader, BlockReaderIdExt, CanonStateSubscriptions, StageCheckpointReader}, - rpc::types::engine::PayloadStatusEnum, + rpc::{ + api::eth::helpers::{EthApiSpec, EthTransactions, TraceExt}, + types::engine::PayloadStatusEnum, + }, }; -use reth_node_builder::NodeTypes; +use reth_node_builder::{NodeAddOns, NodeTypes}; use reth_primitives::{BlockHash, BlockNumber, Bytes, B256}; use reth_stages_types::StageId; -use std::{marker::PhantomData, pin::Pin}; use tokio_stream::StreamExt; +use crate::{ + engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext, + rpc::RpcTestContext, traits::PayloadEnvelopeExt, +}; + /// An helper struct to handle node actions -pub struct NodeTestContext +pub struct NodeTestContext where Node: FullNodeComponents, + AddOns: NodeAddOns, { - pub inner: FullNode, + pub inner: FullNode, pub payload: PayloadTestContext, pub network: NetworkTestContext, pub engine_api: EngineApiTestContext, - pub rpc: RpcTestContext, + pub rpc: RpcTestContext, } -impl NodeTestContext +impl NodeTestContext where Node: FullNodeComponents, + AddOns: NodeAddOns, { /// Creates a new test node - pub async fn new(node: FullNode) -> eyre::Result { + pub async fn new(node: FullNode) -> eyre::Result { let builder = node.payload_builder.clone(); Ok(Self { @@ -53,7 +59,7 @@ where } /// Establish a connection to the node - pub async fn connect(&mut self, node: &mut NodeTestContext) { + pub async fn connect(&mut self, node: &mut NodeTestContext) { self.network.add_peer(node.network.record()).await; node.network.next_session_established().await; self.network.next_session_established().await; @@ -77,6 +83,7 @@ where where ::ExecutionPayloadV3: From<::BuiltPayload> + PayloadEnvelopeExt, + AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt, { 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 b05d5df895a0..8e499bcca60c 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -3,17 +3,23 @@ use alloy_network::eip2718::Decodable2718; use reth::{ builder::{rpc::RpcRegistry, FullNodeComponents}, rpc::{ - api::{eth::helpers::EthTransactions, DebugApiServer}, + api::{ + eth::helpers::{EthApiSpec, EthTransactions, TraceExt}, + DebugApiServer, + }, server_types::eth::EthResult, }, }; use reth_primitives::{Bytes, B256}; -pub struct RpcTestContext { - pub inner: RpcRegistry, +pub struct RpcTestContext { + pub inner: RpcRegistry, } -impl RpcTestContext { +impl RpcTestContext +where + EthApi: EthApiSpec + EthTransactions + TraceExt, +{ /// Injects a raw transaction into the node tx pool via RPC server pub async fn inject_tx(&mut self, raw_tx: Bytes) -> EthResult { let eth_api = self.inner.eth_api(); diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index f053b35b911c..e333c7245722 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -25,6 +25,8 @@ reth-evm-ethereum.workspace = true reth-consensus.workspace = true reth-auto-seal-consensus.workspace = true reth-beacon-consensus.workspace = true +reth-rpc.workspace = true +reth-node-api.workspace = true # misc eyre.workspace = true diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index c3d8a9af55f4..264297bc406a 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -1,6 +1,7 @@ //! Ethereum Node types config. -use crate::{EthEngineTypes, EthEvmConfig}; +use std::sync::Arc; + use reth_auto_seal_consensus::AutoSealConsensus; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_beacon_consensus::EthBeaconConsensus; @@ -9,6 +10,7 @@ use reth_ethereum_engine_primitives::{ }; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_network::NetworkHandle; +use reth_node_api::{FullNodeComponents, NodeAddOns}; use reth_node_builder::{ components::{ ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, @@ -19,12 +21,14 @@ use reth_node_builder::{ }; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_provider::CanonStateSubscriptions; +use reth_rpc::EthApi; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::{ blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool, TransactionValidationTaskExecutor, }; -use std::sync::Arc; + +use crate::{EthEngineTypes, EthEvmConfig}; /// Type configuration for a regular Ethereum node. #[derive(Debug, Default, Clone, Copy)] @@ -64,6 +68,14 @@ impl NodeTypes for EthereumNode { type Engine = EthEngineTypes; } +/// Add-ons w.r.t. l1 ethereum. +#[derive(Debug, Clone)] +pub struct EthereumAddOns; + +impl NodeAddOns for EthereumAddOns { + type EthApi = EthApi; +} + impl Node for EthereumNode where N: FullNodeTypes, @@ -77,7 +89,9 @@ where EthereumConsensusBuilder, >; - fn components_builder(self) -> Self::ComponentsBuilder { + type AddOns = EthereumAddOns; + + fn components_builder(&self) -> Self::ComponentsBuilder { Self::components() } } diff --git a/crates/ethereum/node/tests/e2e/dev.rs b/crates/ethereum/node/tests/e2e/dev.rs index 0e289cfd3b75..894d76a71538 100644 --- a/crates/ethereum/node/tests/e2e/dev.rs +++ b/crates/ethereum/node/tests/e2e/dev.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use alloy_genesis::Genesis; use alloy_primitives::{b256, hex}; use futures::StreamExt; -use reth::rpc::api::eth::helpers::EthTransactions; +use reth::core::rpc::eth::helpers::EthTransactions; use reth_chainspec::ChainSpec; use reth_e2e_test_utils::setup; use reth_provider::CanonStateSubscriptions; diff --git a/crates/ethereum/node/tests/e2e/utils.rs b/crates/ethereum/node/tests/e2e/utils.rs index 001cf02ce017..5a7950999189 100644 --- a/crates/ethereum/node/tests/e2e/utils.rs +++ b/crates/ethereum/node/tests/e2e/utils.rs @@ -1,11 +1,11 @@ use alloy_primitives::{Address, B256}; use reth::rpc::types::engine::PayloadAttributes; use reth_e2e_test_utils::NodeHelperType; -use reth_node_ethereum::EthereumNode; +use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use reth_payload_builder::EthPayloadBuilderAttributes; /// Ethereum Node Helper type -pub(crate) type EthNode = NodeHelperType; +pub(crate) type EthNode = NodeHelperType; /// Helper function to create a new eth payload attributes pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes { diff --git a/crates/ethereum/node/tests/it/builder.rs b/crates/ethereum/node/tests/it/builder.rs index b48e58679bd9..8d97db46c5ea 100644 --- a/crates/ethereum/node/tests/it/builder.rs +++ b/crates/ethereum/node/tests/it/builder.rs @@ -1,9 +1,8 @@ //! Node builder setup tests. use reth_db::test_utils::create_test_rw_db; -use reth_node_api::FullNodeComponents; -use reth_node_builder::{NodeBuilder, NodeConfig}; -use reth_node_ethereum::node::EthereumNode; +use reth_node_builder::{FullNodeComponents, NodeBuilder, NodeConfig}; +use reth_node_ethereum::node::{EthereumAddOns, EthereumNode}; #[test] fn test_basic_setup() { @@ -15,6 +14,7 @@ fn test_basic_setup() { .with_database(db) .with_types::() .with_components(EthereumNode::components()) + .with_add_ons::() .on_component_initialized(move |ctx| { let _provider = ctx.provider(); println!("{msg}"); diff --git a/crates/ethereum/node/tests/it/exex.rs b/crates/ethereum/node/tests/it/exex.rs index 80366ba23db5..db19aaaf3612 100644 --- a/crates/ethereum/node/tests/it/exex.rs +++ b/crates/ethereum/node/tests/it/exex.rs @@ -3,7 +3,7 @@ use reth_db::test_utils::create_test_rw_db; use reth_exex::ExExContext; use reth_node_api::FullNodeComponents; use reth_node_builder::{NodeBuilder, NodeConfig}; -use reth_node_ethereum::EthereumNode; +use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use std::{ future::Future, pin::Pin, @@ -33,6 +33,7 @@ fn basic_exex() { .with_database(db) .with_types::() .with_components(EthereumNode::components()) + .with_add_ons::() .install_exex("dummy", move |ctx| future::ok(DummyExEx { _ctx: ctx })) .check_launch(); } diff --git a/crates/exex/test-utils/src/lib.rs b/crates/exex/test-utils/src/lib.rs index cba6e01246e6..aea6ff7ff641 100644 --- a/crates/exex/test-utils/src/lib.rs +++ b/crates/exex/test-utils/src/lib.rs @@ -28,7 +28,7 @@ use reth_node_builder::{ }; use reth_node_core::node_config::NodeConfig; use reth_node_ethereum::{ - node::{EthereumNetworkBuilder, EthereumPayloadBuilder}, + node::{EthereumAddOns, EthereumNetworkBuilder, EthereumPayloadBuilder}, EthEngineTypes, EthEvmConfig, }; use reth_payload_builder::noop::NoopPayloadBuilderService; @@ -125,8 +125,9 @@ where TestExecutorBuilder, TestConsensusBuilder, >; + type AddOns = EthereumAddOns; - fn components_builder(self) -> Self::ComponentsBuilder { + fn components_builder(&self) -> Self::ComponentsBuilder { ComponentsBuilder::default() .node_types::() .pool(TestPoolBuilder::default()) diff --git a/crates/node/api/src/node.rs b/crates/node/api/src/node.rs index 15345c49b6c0..22db838c8a66 100644 --- a/crates/node/api/src/node.rs +++ b/crates/node/api/src/node.rs @@ -1,6 +1,7 @@ //! Traits for configuring a node. -use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes}; +use std::marker::PhantomData; + use reth_db_api::{ database::Database, database_metrics::{DatabaseMetadata, DatabaseMetrics}, @@ -11,7 +12,8 @@ use reth_payload_builder::PayloadBuilderHandle; use reth_provider::FullProvider; use reth_tasks::TaskExecutor; use reth_transaction_pool::TransactionPool; -use std::marker::PhantomData; + +use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes}; /// The type that configures the essential types of an ethereum like node. /// @@ -145,3 +147,34 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { /// Returns the task executor. fn task_executor(&self) -> &TaskExecutor; } + +/// Customizable node add-on types. +pub trait NodeAddOns: Send + Sync + Unpin + Clone + 'static { + /// The core `eth` namespace API type to install on the RPC server (see + /// `reth_rpc_eth_api::EthApiServer`). + type EthApi: Send + Clone; +} + +impl NodeAddOns for () { + type EthApi = (); +} + +/// Returns the builder for type. +pub trait BuilderProvider: Send { + /// Context required to build type. + type Ctx<'a>; + + /// Returns builder for type. + #[allow(clippy::type_complexity)] + fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send>; +} + +impl BuilderProvider for () { + type Ctx<'a> = (); + + fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { + Box::new(noop_builder) + } +} + +const fn noop_builder(_: ()) {} diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index 5a29b6e778a4..5fc3da56a7d2 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -47,6 +47,7 @@ reth-consensus-debug-client.workspace = true reth-rpc-types.workspace = true reth-engine-util.workspace = true reth-cli-util.workspace = true +reth-rpc-eth-types.workspace = true ## async futures.workspace = true diff --git a/crates/node/builder/src/builder/add_ons.rs b/crates/node/builder/src/builder/add_ons.rs new file mode 100644 index 000000000000..54a776fd69aa --- /dev/null +++ b/crates/node/builder/src/builder/add_ons.rs @@ -0,0 +1,29 @@ +//! Node add-ons. Depend on core [`NodeComponents`](crate::NodeComponents). + +use std::marker::PhantomData; + +use reth_node_api::{FullNodeComponents, NodeAddOns}; + +use crate::{exex::BoxedLaunchExEx, hooks::NodeHooks, rpc::RpcHooks}; + +/// Additional node extensions. +/// +/// At this point we consider all necessary components defined. +pub struct AddOns> { + /// Additional `NodeHooks` that are called at specific points in the node's launch lifecycle. + pub hooks: NodeHooks, + /// The `ExExs` (execution extensions) of the node. + pub exexs: Vec<(String, Box>)>, + /// Additional RPC add-ons. + pub rpc: RpcAddOns, +} + +/// Captures node specific addons that can be installed on top of the type configured node and are +/// required for launching the node, such as RPC. +#[derive(Default)] +pub struct RpcAddOns { + /// Core `eth` API type to install on the RPC server, configured w.r.t. network. + pub _eth_api: PhantomData, + /// Additional RPC hooks. + pub hooks: RpcHooks, +} diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index a6b723d3e513..f3c8889ea348 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -2,13 +2,13 @@ #![allow(clippy::type_complexity, missing_debug_implementations)] -use crate::{ - common::WithConfigs, - components::NodeComponentsBuilder, - node::FullNode, - rpc::{RethRpcServerHandles, RpcContext}, - DefaultNodeLauncher, Node, NodeHandle, -}; +pub mod add_ons; +mod states; + +pub use states::*; + +use std::sync::Arc; + use futures::Future; use reth_chainspec::ChainSpec; use reth_cli_util::get_secret_key; @@ -20,23 +20,28 @@ use reth_exex::ExExContext; use reth_network::{ NetworkBuilder, NetworkConfig, NetworkConfigBuilder, NetworkHandle, NetworkManager, }; -use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeTypes}; +use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes}; use reth_node_core::{ cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig}, dirs::{ChainPath, DataDirPath}, node_config::NodeConfig, primitives::Head, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, }; use reth_primitives::revm_primitives::EnvKzgSettings; use reth_provider::{providers::BlockchainProvider, ChainSpecProvider}; use reth_tasks::TaskExecutor; use reth_transaction_pool::{PoolConfig, TransactionPool}; use secp256k1::SecretKey; -pub use states::*; -use std::sync::Arc; use tracing::{info, trace, warn}; -mod states; +use crate::{ + common::WithConfigs, + components::NodeComponentsBuilder, + node::FullNode, + rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext}, + DefaultNodeLauncher, Node, NodeHandle, +}; /// The adapter type for a reth node with the builtin provider type // Note: we need to hardcode this because custom components might depend on it in associated types. @@ -212,11 +217,11 @@ where pub fn node( self, node: N, - ) -> NodeBuilderWithComponents, N::ComponentsBuilder> + ) -> NodeBuilderWithComponents, N::ComponentsBuilder, N::AddOns> where N: Node>, { - self.with_types().with_components(node.components_builder()) + self.with_types().with_components(node.components_builder()).with_add_ons::() } } @@ -259,11 +264,13 @@ where pub fn node( self, node: N, - ) -> WithLaunchContext, N::ComponentsBuilder>> + ) -> WithLaunchContext< + NodeBuilderWithComponents, N::ComponentsBuilder, N::AddOns>, + > where N: Node>, { - self.with_types().with_components(node.components_builder()) + self.with_types().with_components(node.components_builder()).with_add_ons::() } /// Launches a preconfigured [Node] @@ -280,10 +287,22 @@ where RethFullAdapter, >>::Components, >, + N::AddOns, >, > where N: Node>, + , + >>::Components, + >, + >>::EthApi: EthApiBuilderProvider< + NodeAdapter< + RethFullAdapter, + >>::Components, + >, + > + FullEthApiServer + AddDevSigners, { self.node(node).launch().await } @@ -298,7 +317,7 @@ where pub fn with_components( self, components_builder: CB, - ) -> WithLaunchContext, CB>> + ) -> WithLaunchContext, CB, ()>> where CB: NodeComponentsBuilder>, { @@ -309,11 +328,35 @@ where } } -impl WithLaunchContext, CB>> +impl WithLaunchContext, CB, ()>> where DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, T: NodeTypes, CB: NodeComponentsBuilder>, +{ + /// Advances the state of the node builder to the next state where all customizable + /// [`NodeAddOns`] types are configured. + pub fn with_add_ons( + self, + ) -> WithLaunchContext, CB, AO>> + where + CB: NodeComponentsBuilder>, + AO: NodeAddOns, CB::Components>>, + { + WithLaunchContext { + builder: self.builder.with_add_ons::(), + task_executor: self.task_executor, + } + } +} + +impl WithLaunchContext, CB, AO>> +where + DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, + T: NodeTypes, + CB: NodeComponentsBuilder>, + AO: NodeAddOns, CB::Components>>, + AO::EthApi: FullEthApiServer + AddDevSigners, { /// Sets the hook that is run once the node's components are initialized. pub fn on_component_initialized(self, hook: F) -> Self @@ -332,7 +375,7 @@ where pub fn on_node_started(self, hook: F) -> Self where F: FnOnce( - FullNode, CB::Components>>, + FullNode, CB::Components>, AO>, ) -> eyre::Result<()> + Send + 'static, @@ -344,7 +387,7 @@ where pub fn on_rpc_started(self, hook: F) -> Self where F: FnOnce( - RpcContext<'_, NodeAdapter, CB::Components>>, + RpcContext<'_, NodeAdapter, CB::Components>, AO::EthApi>, RethRpcServerHandles, ) -> eyre::Result<()> + Send @@ -357,7 +400,7 @@ where pub fn extend_rpc_modules(self, hook: F) -> Self where F: FnOnce( - RpcContext<'_, NodeAdapter, CB::Components>>, + RpcContext<'_, NodeAdapter, CB::Components>, AO::EthApi>, ) -> eyre::Result<()> + Send + 'static, @@ -384,22 +427,33 @@ where } } - /// Launches the node and returns a handle to it. + /// Check that the builder can be launched + /// + /// This is useful when writing tests to ensure that the builder is configured correctly. + pub const fn check_launch(self) -> Self { + self + } +} + +impl WithLaunchContext, CB, AO>> +where + DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, + T: NodeTypes, + CB: NodeComponentsBuilder>, + AO: NodeAddOns, CB::Components>>, + AO::EthApi: EthApiBuilderProvider, CB::Components>> + + FullEthApiServer + + AddDevSigners, +{ + /// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc pub async fn launch( self, - ) -> eyre::Result, CB::Components>>> { + ) -> eyre::Result, CB::Components>, AO>> { let Self { builder, task_executor } = self; let launcher = DefaultNodeLauncher::new(task_executor, builder.config.datadir()); builder.launch_with(launcher).await } - - /// Check that the builder can be launched - /// - /// This is useful when writing tests to ensure that the builder is configured correctly. - pub const fn check_launch(self) -> Self { - self - } } /// Captures the necessary context for building the components of the node. diff --git a/crates/node/builder/src/builder/states.rs b/crates/node/builder/src/builder/states.rs index 8f09d5edd94b..0a357cf05674 100644 --- a/crates/node/builder/src/builder/states.rs +++ b/crates/node/builder/src/builder/states.rs @@ -5,21 +5,25 @@ //! The node builder process is essentially a state machine that transitions through various states //! before the node can be launched. +use std::{fmt, future::Future, marker::PhantomData}; + +use reth_exex::ExExContext; +use reth_network::NetworkHandle; +use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypes}; +use reth_node_core::{ + node_config::NodeConfig, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, +}; +use reth_payload_builder::PayloadBuilderHandle; +use reth_tasks::TaskExecutor; + use crate::{ components::{NodeComponents, NodeComponentsBuilder}, - exex::BoxedLaunchExEx, hooks::NodeHooks, launch::LaunchNode, - rpc::{RethRpcServerHandles, RpcContext, RpcHooks}, - FullNode, + rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext, RpcHooks}, + AddOns, FullNode, RpcAddOns, }; -use reth_exex::ExExContext; -use reth_network::NetworkHandle; -use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes}; -use reth_node_core::node_config::NodeConfig; -use reth_payload_builder::PayloadBuilderHandle; -use reth_tasks::TaskExecutor; -use std::{fmt, future::Future}; /// A node builder that also has the configured types. pub struct NodeBuilderWithTypes { @@ -36,7 +40,7 @@ impl NodeBuilderWithTypes { } /// Advances the state of the node builder to the next state where all components are configured - pub fn with_components(self, components_builder: CB) -> NodeBuilderWithComponents + pub fn with_components(self, components_builder: CB) -> NodeBuilderWithComponents where CB: NodeComponentsBuilder, { @@ -46,9 +50,9 @@ impl NodeBuilderWithTypes { config, adapter, components_builder, - add_ons: NodeAddOns { + add_ons: AddOns { hooks: NodeHooks::default(), - rpc: RpcHooks::new(), + rpc: RpcAddOns { _eth_api: PhantomData::<()>, hooks: RpcHooks::default() }, exexs: Vec::new(), }, } @@ -142,7 +146,11 @@ impl> Clone for NodeAdapter { /// A fully type configured node builder. /// /// Supports adding additional addons to the node. -pub struct NodeBuilderWithComponents> { +pub struct NodeBuilderWithComponents< + T: FullNodeTypes, + CB: NodeComponentsBuilder, + AO: NodeAddOns>, +> { /// All settings for how the node should be configured. pub(crate) config: NodeConfig, /// Adapter for the underlying node types and database @@ -150,10 +158,41 @@ pub struct NodeBuilderWithComponents>, + pub(crate) add_ons: AddOns, AO>, +} + +impl NodeBuilderWithComponents +where + T: FullNodeTypes, + CB: NodeComponentsBuilder, +{ + /// Advances the state of the node builder to the next state where all customizable + /// [`NodeAddOns`] types are configured. + pub fn with_add_ons(self) -> NodeBuilderWithComponents + where + AO: NodeAddOns>, + { + let Self { config, adapter, components_builder, .. } = self; + + NodeBuilderWithComponents { + config, + adapter, + components_builder, + add_ons: AddOns { + hooks: NodeHooks::default(), + rpc: RpcAddOns { _eth_api: PhantomData::, hooks: RpcHooks::default() }, + exexs: Vec::new(), + }, + } + } } -impl> NodeBuilderWithComponents { +impl NodeBuilderWithComponents +where + T: FullNodeTypes, + CB: NodeComponentsBuilder, + AO: NodeAddOns>, +{ /// Sets the hook that is run once the node's components are initialized. pub fn on_component_initialized(mut self, hook: F) -> Self where @@ -166,7 +205,9 @@ impl> NodeBuilderWithComponents(mut self, hook: F) -> Self where - F: FnOnce(FullNode>) -> eyre::Result<()> + Send + 'static, + F: FnOnce(FullNode, AO>) -> eyre::Result<()> + + Send + + 'static, { self.add_ons.hooks.set_on_node_started(hook); self @@ -176,24 +217,24 @@ impl> NodeBuilderWithComponents(mut self, hook: F) -> Self where F: FnOnce( - RpcContext<'_, NodeAdapter>, + RpcContext<'_, NodeAdapter, AO::EthApi>, RethRpcServerHandles, ) -> eyre::Result<()> + Send + 'static, { - self.add_ons.rpc.set_on_rpc_started(hook); + self.add_ons.rpc.hooks.set_on_rpc_started(hook); self } /// Sets the hook that is run to configure the rpc modules. pub fn extend_rpc_modules(mut self, hook: F) -> Self where - F: FnOnce(RpcContext<'_, NodeAdapter>) -> eyre::Result<()> + F: FnOnce(RpcContext<'_, NodeAdapter, AO::EthApi>) -> eyre::Result<()> + Send + 'static, { - self.add_ons.rpc.set_extend_rpc_modules(hook); + self.add_ons.rpc.hooks.set_extend_rpc_modules(hook); self } @@ -212,14 +253,6 @@ impl> NodeBuilderWithComponents(self, launcher: L) -> eyre::Result - where - L: LaunchNode, - { - launcher.launch_node(self).await - } - /// Launches the node with the given closure. pub fn launch_with_fn(self, launcher: L) -> R where @@ -236,12 +269,19 @@ impl> NodeBuilderWithComponents { - /// Additional `NodeHooks` that are called at specific points in the node's launch lifecycle. - pub(crate) hooks: NodeHooks, - /// Additional RPC hooks. - pub(crate) rpc: RpcHooks, - /// The `ExExs` (execution extensions) of the node. - pub(crate) exexs: Vec<(String, Box>)>, +impl NodeBuilderWithComponents +where + T: FullNodeTypes, + CB: NodeComponentsBuilder, + AO: NodeAddOns>, + AO::EthApi: + EthApiBuilderProvider> + FullEthApiServer + AddDevSigners, +{ + /// Launches the node with the given launcher. + pub async fn launch_with(self, launcher: L) -> eyre::Result + where + L: LaunchNode, + { + launcher.launch_node(self).await + } } diff --git a/crates/node/builder/src/components/builder.rs b/crates/node/builder/src/components/builder.rs index 72d2e6933da5..650ab24abc13 100644 --- a/crates/node/builder/src/components/builder.rs +++ b/crates/node/builder/src/components/builder.rs @@ -1,5 +1,11 @@ //! A generic [`NodeComponentsBuilder`] +use std::{future::Future, marker::PhantomData}; + +use reth_consensus::Consensus; +use reth_evm::execute::BlockExecutorProvider; +use reth_transaction_pool::TransactionPool; + use crate::{ components::{ Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents, @@ -7,10 +13,6 @@ use crate::{ }, BuilderContext, ConfigureEvm, FullNodeTypes, }; -use reth_consensus::Consensus; -use reth_evm::execute::BlockExecutorProvider; -use reth_transaction_pool::TransactionPool; -use std::{future::Future, marker::PhantomData}; /// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation. /// diff --git a/crates/node/builder/src/handle.rs b/crates/node/builder/src/handle.rs index cbdce0c8b59f..c81aa9420dde 100644 --- a/crates/node/builder/src/handle.rs +++ b/crates/node/builder/src/handle.rs @@ -1,25 +1,35 @@ -use crate::node::FullNode; -use reth_node_api::FullNodeComponents; -use reth_node_core::exit::NodeExitFuture; use std::fmt; +use reth_node_api::{FullNodeComponents, NodeAddOns}; +use reth_node_core::exit::NodeExitFuture; + +use crate::node::FullNode; + /// A Handle to the launched node. #[must_use = "Needs to await the node exit future"] -pub struct NodeHandle { +pub struct NodeHandle> { /// All node components. - pub node: FullNode, + pub node: FullNode, /// The exit future of the node. pub node_exit_future: NodeExitFuture, } -impl NodeHandle { +impl NodeHandle +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ /// Waits for the node to exit, if it was configured to exit. pub async fn wait_for_node_exit(self) -> eyre::Result<()> { self.node_exit_future.await } } -impl fmt::Debug for NodeHandle { +impl fmt::Debug for NodeHandle +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NodeHandle") .field("node", &"...") diff --git a/crates/node/builder/src/hooks.rs b/crates/node/builder/src/hooks.rs index 86c4b56c6d00..c4b42228422a 100644 --- a/crates/node/builder/src/hooks.rs +++ b/crates/node/builder/src/hooks.rs @@ -1,17 +1,25 @@ -use crate::node::FullNode; -use reth_node_api::FullNodeComponents; use std::fmt; +use reth_node_api::{FullNodeComponents, NodeAddOns}; + +use crate::node::FullNode; + /// Container for all the configurable hook functions. -pub(crate) struct NodeHooks { - pub(crate) on_component_initialized: Box>, - pub(crate) on_node_started: Box>, - pub(crate) _marker: std::marker::PhantomData, +pub struct NodeHooks> { + /// Hook to run once core components are initialized. + pub on_component_initialized: Box>, + /// Hook to run once the node is started. + pub on_node_started: Box>, + _marker: std::marker::PhantomData, } -impl NodeHooks { +impl NodeHooks +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ /// Creates a new, empty [`NodeHooks`] instance for the given node type. - pub(crate) fn new() -> Self { + pub fn new() -> Self { Self { on_component_initialized: Box::<()>::default(), on_node_started: Box::<()>::default(), @@ -41,7 +49,7 @@ impl NodeHooks { /// Sets the hook that is run once the node has started. pub(crate) fn set_on_node_started(&mut self, hook: F) -> &mut Self where - F: OnNodeStartedHook + 'static, + F: OnNodeStartedHook + 'static, { self.on_node_started = Box::new(hook); self @@ -51,19 +59,27 @@ impl NodeHooks { #[allow(unused)] pub(crate) fn on_node_started(mut self, hook: F) -> Self where - F: OnNodeStartedHook + 'static, + F: OnNodeStartedHook + 'static, { self.set_on_node_started(hook); self } } -impl Default for NodeHooks { +impl Default for NodeHooks +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ fn default() -> Self { Self::new() } } -impl fmt::Debug for NodeHooks { +impl fmt::Debug for NodeHooks +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NodeHooks") .field("on_component_initialized", &"...") @@ -90,19 +106,20 @@ where } /// A helper trait that is run once the node is started. -pub trait OnNodeStartedHook: Send { +pub trait OnNodeStartedHook>: Send { /// Consumes the event hook and runs it. /// /// If this returns an error, the node launch will be aborted. - fn on_event(self: Box, node: FullNode) -> eyre::Result<()>; + fn on_event(self: Box, node: FullNode) -> eyre::Result<()>; } -impl OnNodeStartedHook for F +impl OnNodeStartedHook for F where Node: FullNodeComponents, - F: FnOnce(FullNode) -> eyre::Result<()> + Send, + AddOns: NodeAddOns, + F: FnOnce(FullNode) -> eyre::Result<()> + Send, { - fn on_event(self: Box, node: FullNode) -> eyre::Result<()> { + fn on_event(self: Box, node: FullNode) -> eyre::Result<()> { (*self)(node) } } @@ -113,8 +130,12 @@ impl OnComponentInitializedHook for () { } } -impl OnNodeStartedHook for () { - fn on_event(self: Box, _node: FullNode) -> eyre::Result<()> { +impl OnNodeStartedHook for () +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ + fn on_event(self: Box, _node: FullNode) -> eyre::Result<()> { Ok(()) } } diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 9a9447aa7ba9..fb22e7908404 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -1,12 +1,13 @@ //! Abstraction for launching a node. -use crate::{ - builder::{NodeAdapter, NodeAddOns, NodeTypesAdapter}, - components::{NodeComponents, NodeComponentsBuilder}, - hooks::NodeHooks, - node::FullNode, - NodeBuilderWithComponents, NodeHandle, -}; +pub mod common; +mod exex; + +pub use common::LaunchContext; +pub use exex::ExExLauncher; + +use std::{future::Future, sync::Arc}; + use futures::{future::Either, stream, stream_select, StreamExt}; use reth_beacon_consensus::{ hooks::{EngineHooks, PruneHook, StaticFileHook}, @@ -15,11 +16,12 @@ use reth_beacon_consensus::{ use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider}; use reth_engine_util::EngineMessageStreamExt; use reth_exex::ExExManagerHandle; -use reth_network::NetworkEvents; -use reth_node_api::FullNodeTypes; +use reth_network::{NetworkEvents, NetworkHandle}; +use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns}; use reth_node_core::{ dirs::{ChainPath, DataDirPath}, exit::NodeExitFuture, + rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; @@ -30,18 +32,32 @@ use reth_rpc_types::engine::ClientVersionV1; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::TransactionPool; -use std::{future::Future, sync::Arc}; use tokio::sync::{mpsc::unbounded_channel, oneshot}; use tokio_stream::wrappers::UnboundedReceiverStream; -pub mod common; -pub use common::LaunchContext; -mod exex; -pub use exex::ExExLauncher; +use crate::{ + builder::{NodeAdapter, NodeTypesAdapter}, + components::{NodeComponents, NodeComponentsBuilder}, + hooks::NodeHooks, + node::FullNode, + rpc::EthApiBuilderProvider, + AddOns, NodeBuilderWithComponents, NodeHandle, +}; + +/// Alias for [`reth_rpc_eth_types::EthApiBuilderCtx`], adapter for [`FullNodeComponents`]. +pub type EthApiBuilderCtx = reth_rpc_eth_types::EthApiBuilderCtx< + ::Provider, + ::Pool, + ::Evm, + NetworkHandle, + TaskExecutor, + ::Provider, +>; /// A general purpose trait that launches a new node of any kind. /// -/// Acts as a node factory. +/// Acts as a node factory that targets a certain node configuration and returns a handle to the +/// node. /// /// This is essentially the launch logic for a node. /// @@ -80,22 +96,25 @@ impl DefaultNodeLauncher { } } -impl LaunchNode> for DefaultNodeLauncher +impl LaunchNode> for DefaultNodeLauncher where T: FullNodeTypes::DB>>, CB: NodeComponentsBuilder, + AO: NodeAddOns>, + AO::EthApi: + EthApiBuilderProvider> + FullEthApiServer + AddDevSigners, { - type Node = NodeHandle>; + type Node = NodeHandle, AO>; async fn launch_node( self, - target: NodeBuilderWithComponents, + target: NodeBuilderWithComponents, ) -> eyre::Result { let Self { ctx } = self; let NodeBuilderWithComponents { adapter: NodeTypesAdapter { database }, components_builder, - add_ons: NodeAddOns { hooks, rpc, exexs: installed_exex }, + add_ons: AddOns { hooks, rpc, exexs: installed_exex }, config, } = target; let NodeHooks { on_component_initialized, on_node_started, .. } = hooks; diff --git a/crates/node/builder/src/lib.rs b/crates/node/builder/src/lib.rs index 6e85cef5d389..f5db24d7f6c4 100644 --- a/crates/node/builder/src/lib.rs +++ b/crates/node/builder/src/lib.rs @@ -17,9 +17,13 @@ pub use node::*; /// Support for configuring the components of a node. pub mod components; +pub use components::{NodeComponents, NodeComponentsBuilder}; mod builder; -pub use builder::*; +pub use builder::{ + add_ons::{AddOns, RpcAddOns}, + *, +}; mod launch; pub use launch::*; diff --git a/crates/node/builder/src/node.rs b/crates/node/builder/src/node.rs index fe8d99ed6090..efc4ff4474f1 100644 --- a/crates/node/builder/src/node.rs +++ b/crates/node/builder/src/node.rs @@ -1,4 +1,8 @@ -use crate::rpc::{RethRpcServerHandles, RpcRegistry}; +// re-export the node api types +pub use reth_node_api::{FullNodeTypes, NodeTypes}; + +use std::{marker::PhantomData, sync::Arc}; + use reth_chainspec::ChainSpec; use reth_network::NetworkHandle; use reth_node_api::FullNodeComponents; @@ -11,11 +15,12 @@ use reth_payload_builder::PayloadBuilderHandle; use reth_provider::ChainSpecProvider; use reth_rpc_builder::{auth::AuthServerHandle, RpcServerHandle}; use reth_tasks::TaskExecutor; -use std::{marker::PhantomData, sync::Arc}; -// re-export the node api types -use crate::components::NodeComponentsBuilder; -pub use reth_node_api::{FullNodeTypes, NodeTypes}; +use crate::{ + components::NodeComponentsBuilder, + rpc::{RethRpcServerHandles, RpcRegistry}, + NodeAdapter, NodeAddOns, +}; /// A [`crate::Node`] is a [`NodeTypes`] that comes with preconfigured components. /// @@ -24,45 +29,53 @@ pub trait Node: NodeTypes + Clone { /// The type that builds the node's components. type ComponentsBuilder: NodeComponentsBuilder; + /// Exposes the customizable node add-on types. + type AddOns: NodeAddOns< + NodeAdapter>::Components>, + >; + /// Returns a [`NodeComponentsBuilder`] for the node. - fn components_builder(self) -> Self::ComponentsBuilder; + fn components_builder(&self) -> Self::ComponentsBuilder; } /// A [`Node`] type builder #[derive(Clone, Default, Debug)] -pub struct AnyNode(PhantomData, C); +pub struct AnyNode(PhantomData<(N, AO)>, C); impl AnyNode { /// Configures the types of the node. pub fn types(self) -> AnyNode { - AnyNode::(PhantomData::, self.1) + AnyNode::(PhantomData::<(T, ())>, self.1) } /// Sets the node components builder. - pub fn components_builder(self, value: T) -> AnyNode { - AnyNode::(PhantomData::, value) + pub const fn components_builder(&self, value: T) -> AnyNode { + AnyNode::(PhantomData::<(N, ())>, value) } } -impl NodeTypes for AnyNode +impl NodeTypes for AnyNode where N: FullNodeTypes, - C: NodeComponentsBuilder + Sync + Unpin + 'static, + C: Send + Sync + Unpin + 'static, + AO: Send + Sync + Unpin + Clone + 'static, { type Primitives = N::Primitives; type Engine = N::Engine; } -impl Node for AnyNode +impl Node for AnyNode where N: FullNodeTypes + Clone, C: NodeComponentsBuilder + Clone + Sync + Unpin + 'static, + AO: NodeAddOns>, { type ComponentsBuilder = C; + type AddOns = AO; - fn components_builder(self) -> Self::ComponentsBuilder { - self.1 + fn components_builder(&self) -> Self::ComponentsBuilder { + self.1.clone() } } @@ -70,7 +83,7 @@ where /// /// This can be used to interact with the launched node. #[derive(Debug, Clone)] -pub struct FullNode { +pub struct FullNode> { /// The evm configuration. pub evm_config: Node::Evm, /// The executor of the node. @@ -88,14 +101,18 @@ pub struct FullNode { /// Handles to the node's rpc servers pub rpc_server_handles: RethRpcServerHandles, /// The configured rpc namespaces - pub rpc_registry: RpcRegistry, + pub rpc_registry: RpcRegistry, /// The initial node config. pub config: NodeConfig, /// The data dir of the node. pub data_dir: ChainPath, } -impl FullNode { +impl FullNode +where + Node: FullNodeComponents, + AddOns: NodeAddOns, +{ /// Returns the [`ChainSpec`] of the node. pub fn chain_spec(&self) -> Arc { self.provider.chain_spec() diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index 03ae899cba8b..f6269abdece3 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -7,19 +7,23 @@ use std::{ use futures::TryFutureExt; use reth_network::NetworkHandle; -use reth_node_api::FullNodeComponents; -use reth_node_core::{node_config::NodeConfig, rpc::api::EngineApiServer}; +use reth_node_api::{BuilderProvider, FullNodeComponents}; +use reth_node_core::{ + node_config::NodeConfig, + rpc::{api::EngineApiServer, eth::FullEthApiServer}, +}; use reth_payload_builder::PayloadBuilderHandle; -use reth_rpc::eth::EthApi; use reth_rpc_builder::{ auth::{AuthRpcModule, AuthServerHandle}, config::RethRpcServerConfig, - EthApiBuild, RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, + RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, }; use reth_rpc_layer::JwtSecret; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; +use crate::{EthApiBuilderCtx, RpcAddOns}; + /// Contains the handles to the spawned RPC servers. /// /// This can be used to access the endpoints of the servers. @@ -32,21 +36,24 @@ pub struct RethRpcServerHandles { } /// Contains hooks that are called during the rpc setup. -pub(crate) struct RpcHooks { - pub(crate) on_rpc_started: Box>, - pub(crate) extend_rpc_modules: Box>, +pub struct RpcHooks { + /// Hooks to run once RPC server is running. + pub on_rpc_started: Box>, + /// Hooks to run to configure RPC server API. + pub extend_rpc_modules: Box>, } -impl RpcHooks { - /// Creates a new, empty [`RpcHooks`] instance for the given node type. - pub(crate) fn new() -> Self { +impl Default for RpcHooks { + fn default() -> Self { Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() } } +} +impl RpcHooks { /// Sets the hook that is run once the rpc server is started. pub(crate) fn set_on_rpc_started(&mut self, hook: F) -> &mut Self where - F: OnRpcStarted + 'static, + F: OnRpcStarted + 'static, { self.on_rpc_started = Box::new(hook); self @@ -56,7 +63,7 @@ impl RpcHooks { #[allow(unused)] pub(crate) fn on_rpc_started(mut self, hook: F) -> Self where - F: OnRpcStarted + 'static, + F: OnRpcStarted + 'static, { self.set_on_rpc_started(hook); self @@ -65,7 +72,7 @@ impl RpcHooks { /// Sets the hook that is run to configure the rpc modules. pub(crate) fn set_extend_rpc_modules(&mut self, hook: F) -> &mut Self where - F: ExtendRpcModules + 'static, + F: ExtendRpcModules + 'static, { self.extend_rpc_modules = Box::new(hook); self @@ -75,14 +82,14 @@ impl RpcHooks { #[allow(unused)] pub(crate) fn extend_rpc_modules(mut self, hook: F) -> Self where - F: ExtendRpcModules + 'static, + F: ExtendRpcModules + 'static, { self.set_extend_rpc_modules(hook); self } } -impl fmt::Debug for RpcHooks { +impl fmt::Debug for RpcHooks { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RpcHooks") .field("on_rpc_started", &"...") @@ -92,33 +99,33 @@ impl fmt::Debug for RpcHooks { } /// Event hook that is called once the rpc server is started. -pub trait OnRpcStarted: Send { +pub trait OnRpcStarted: Send { /// The hook that is called once the rpc server is started. fn on_rpc_started( self: Box, - ctx: RpcContext<'_, Node>, + ctx: RpcContext<'_, Node, EthApi>, handles: RethRpcServerHandles, ) -> eyre::Result<()>; } -impl OnRpcStarted for F +impl OnRpcStarted for F where - F: FnOnce(RpcContext<'_, Node>, RethRpcServerHandles) -> eyre::Result<()> + Send, + F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send, Node: FullNodeComponents, { fn on_rpc_started( self: Box, - ctx: RpcContext<'_, Node>, + ctx: RpcContext<'_, Node, EthApi>, handles: RethRpcServerHandles, ) -> eyre::Result<()> { (*self)(ctx, handles) } } -impl OnRpcStarted for () { +impl OnRpcStarted for () { fn on_rpc_started( self: Box, - _: RpcContext<'_, Node>, + _: RpcContext<'_, Node, EthApi>, _: RethRpcServerHandles, ) -> eyre::Result<()> { Ok(()) @@ -126,49 +133,49 @@ impl OnRpcStarted for () { } /// Event hook that is called when the rpc server is started. -pub trait ExtendRpcModules: Send { +pub trait ExtendRpcModules: Send { /// The hook that is called once the rpc server is started. - fn extend_rpc_modules(self: Box, ctx: RpcContext<'_, Node>) -> eyre::Result<()>; + fn extend_rpc_modules(self: Box, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>; } -impl ExtendRpcModules for F +impl ExtendRpcModules for F where - F: FnOnce(RpcContext<'_, Node>) -> eyre::Result<()> + Send, + F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send, Node: FullNodeComponents, { - fn extend_rpc_modules(self: Box, ctx: RpcContext<'_, Node>) -> eyre::Result<()> { + fn extend_rpc_modules(self: Box, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> { (*self)(ctx) } } -impl ExtendRpcModules for () { - fn extend_rpc_modules(self: Box, _: RpcContext<'_, Node>) -> eyre::Result<()> { +impl ExtendRpcModules for () { + fn extend_rpc_modules(self: Box, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> { Ok(()) } } /// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait. -#[derive(Debug)] +#[derive(Debug, Clone)] #[allow(clippy::type_complexity)] -pub struct RpcRegistry { +pub struct RpcRegistry { pub(crate) registry: RpcRegistryInner< Node::Provider, Node::Pool, NetworkHandle, TaskExecutor, Node::Provider, - EthApi, + EthApi, >, } -impl Deref for RpcRegistry { +impl Deref for RpcRegistry { type Target = RpcRegistryInner< Node::Provider, Node::Pool, NetworkHandle, TaskExecutor, Node::Provider, - EthApi, + EthApi, >; fn deref(&self) -> &Self::Target { @@ -176,18 +183,12 @@ impl Deref for RpcRegistry { } } -impl DerefMut for RpcRegistry { +impl DerefMut for RpcRegistry { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.registry } } -impl Clone for RpcRegistry { - fn clone(&self) -> Self { - Self { registry: self.registry.clone() } - } -} - /// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and /// [`AuthRpcModule`]. /// @@ -196,7 +197,7 @@ impl Clone for RpcRegistry { /// transport modules [`TransportRpcModules`] as well as configured authenticated methods /// [`AuthRpcModule`]. #[allow(missing_debug_implementations)] -pub struct RpcContext<'a, Node: FullNodeComponents> { +pub struct RpcContext<'a, Node: FullNodeComponents, EthApi> { /// The node components. pub(crate) node: Node, @@ -206,7 +207,7 @@ pub struct RpcContext<'a, Node: FullNodeComponents> { /// A Helper type the holds instances of the configured modules. /// /// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`]. - pub registry: &'a mut RpcRegistry, + pub registry: &'a mut RpcRegistry, /// Holds installed modules per transport type. /// /// This can be used to merge additional modules into the configured transports (http, ipc, @@ -218,7 +219,7 @@ pub struct RpcContext<'a, Node: FullNodeComponents> { pub auth_module: &'a mut AuthRpcModule, } -impl<'a, Node: FullNodeComponents> RpcContext<'a, Node> { +impl<'a, Node: FullNodeComponents, EthApi> RpcContext<'a, Node, EthApi> { /// Returns the config of the node. pub const fn config(&self) -> &NodeConfig { self.config @@ -251,19 +252,18 @@ impl<'a, Node: FullNodeComponents> RpcContext<'a, Node> { } /// Launch the rpc servers. -pub(crate) async fn launch_rpc_servers( +pub(crate) async fn launch_rpc_servers( node: Node, engine_api: Engine, config: &NodeConfig, jwt_secret: JwtSecret, - hooks: RpcHooks, -) -> eyre::Result<(RethRpcServerHandles, RpcRegistry)> + add_ons: RpcAddOns, +) -> eyre::Result<(RethRpcServerHandles, RpcRegistry)> where + EthApi: EthApiBuilderProvider + FullEthApiServer, Node: FullNodeComponents + Clone, Engine: EngineApiServer, { - let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks; - let auth_config = config.rpc.auth_server_config(jwt_secret)?; let module_config = config.rpc.transport_rpc_module_config(); debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config"); @@ -275,7 +275,7 @@ where .with_events(node.provider().clone()) .with_executor(node.task_executor().clone()) .with_evm_config(node.evm_config().clone()) - .build_with_auth_server(module_config, engine_api, EthApiBuild::build); + .build_with_auth_server(module_config, engine_api, EthApi::eth_api_builder()); let mut registry = RpcRegistry { registry }; let ctx = RpcContext { @@ -286,6 +286,9 @@ where auth_module: &mut auth_module, }; + let RpcAddOns { hooks, .. } = add_ons; + let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks; + extend_rpc_modules.extend_rpc_modules(ctx)?; let server_config = config.rpc.rpc_server_config(); @@ -329,3 +332,20 @@ where Ok((handles, registry)) } + +/// Provides builder for the core `eth` API type. +pub trait EthApiBuilderProvider: BuilderProvider { + /// Returns the eth api builder. + #[allow(clippy::type_complexity)] + fn eth_api_builder() -> Box) -> Self + Send>; +} + +impl EthApiBuilderProvider for F +where + N: FullNodeComponents, + for<'a> F: BuilderProvider = &'a EthApiBuilderCtx>, +{ + fn eth_api_builder() -> Box) -> Self + Send> { + F::builder() + } +} diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index 1a32bcad6ec4..ddbc4916671c 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -37,6 +37,8 @@ revm-primitives.workspace = true reth-discv5.workspace = true reth-rpc-eth-types.workspace = true reth-rpc-eth-api.workspace = true +reth-optimism-rpc.workspace = true +reth-tasks.workspace = true # async async-trait.workspace = true @@ -78,6 +80,7 @@ optimism = [ "reth-beacon-consensus/optimism", "reth-revm/optimism", "reth-auto-seal-consensus/optimism", - "reth-rpc-eth-types/optimism" + "reth-rpc-eth-types/optimism", + "reth-optimism-rpc/optimism" ] test-utils = ["reth-node-builder/test-utils"] diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index df64d901a513..d406a63b9d9c 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -1,14 +1,12 @@ //! Optimism Node types config. -use crate::{ - args::RollupArgs, - txpool::{OpTransactionPool, OpTransactionValidator}, - OptimismEngineTypes, -}; +use std::sync::Arc; + use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_evm::ConfigureEvm; use reth_evm_optimism::{OpExecutorProvider, OptimismEvmConfig}; use reth_network::{NetworkHandle, NetworkManager}; +use reth_node_api::{FullNodeComponents, NodeAddOns}; use reth_node_builder::{ components::{ ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, @@ -18,14 +16,21 @@ use reth_node_builder::{ BuilderContext, Node, PayloadBuilderConfig, }; use reth_optimism_consensus::OptimismBeaconConsensus; +use reth_optimism_rpc::OpEthApi; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_provider::CanonStateSubscriptions; +use reth_rpc::EthApi; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::{ blobstore::DiskFileBlobStore, CoinbaseTipOrdering, TransactionPool, TransactionValidationTaskExecutor, }; -use std::sync::Arc; + +use crate::{ + args::RollupArgs, + txpool::{OpTransactionPool, OpTransactionValidator}, + OptimismEngineTypes, +}; /// Type configuration for a regular Optimism node. #[derive(Debug, Default, Clone)] @@ -82,9 +87,11 @@ where OptimismConsensusBuilder, >; - fn components_builder(self) -> Self::ComponentsBuilder { + type AddOns = OptimismAddOns; + + fn components_builder(&self) -> Self::ComponentsBuilder { let Self { args } = self; - Self::components(args) + Self::components(args.clone()) } } @@ -93,6 +100,14 @@ impl NodeTypes for OptimismNode { type Engine = OptimismEngineTypes; } +/// Add-ons w.r.t. optimism. +#[derive(Debug, Clone)] +pub struct OptimismAddOns; + +impl NodeAddOns for OptimismAddOns { + type EthApi = OpEthApi>; +} + /// A regular optimism evm and executor builder. #[derive(Debug, Default, Clone, Copy)] #[non_exhaustive] diff --git a/crates/optimism/node/tests/e2e/utils.rs b/crates/optimism/node/tests/e2e/utils.rs index feacabfb2c29..a24656e5d366 100644 --- a/crates/optimism/node/tests/e2e/utils.rs +++ b/crates/optimism/node/tests/e2e/utils.rs @@ -1,15 +1,18 @@ +use std::sync::Arc; + use alloy_genesis::Genesis; use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager}; use reth_chainspec::{ChainSpecBuilder, BASE_MAINNET}; use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType}; -use reth_node_optimism::{OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes}; +use reth_node_optimism::{ + node::OptimismAddOns, OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes, +}; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_primitives::{Address, B256}; -use std::sync::Arc; use tokio::sync::Mutex; /// Optimism Node Helper type -pub(crate) type OpNode = NodeHelperType; +pub(crate) type OpNode = NodeHelperType; pub(crate) async fn setup(num_nodes: usize) -> eyre::Result<(Vec, TaskManager, Wallet)> { let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); diff --git a/crates/optimism/node/tests/it/builder.rs b/crates/optimism/node/tests/it/builder.rs index 5d26e8bda850..cc9c772c027b 100644 --- a/crates/optimism/node/tests/it/builder.rs +++ b/crates/optimism/node/tests/it/builder.rs @@ -3,7 +3,7 @@ use reth_db::test_utils::create_test_rw_db; use reth_node_api::FullNodeComponents; use reth_node_builder::{NodeBuilder, NodeConfig}; -use reth_node_optimism::node::OptimismNode; +use reth_node_optimism::node::{OptimismAddOns, OptimismNode}; #[test] fn test_basic_setup() { @@ -14,6 +14,7 @@ fn test_basic_setup() { .with_database(db) .with_types::() .with_components(OptimismNode::components(Default::default())) + .with_add_ons::() .on_component_initialized(move |ctx| { let _provider = ctx.provider(); Ok(()) diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 71aeefdc3c0e..733947e1139d 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -25,6 +25,8 @@ reth-rpc-server-types.workspace = true reth-rpc-types.workspace = true reth-tasks = { workspace = true, features = ["rayon"] } reth-transaction-pool.workspace = true +reth-rpc.workspace = true +reth-node-api.workspace = true # ethereum alloy-primitives.workspace = true diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 643f935a2061..d8e0de756cac 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -12,9 +12,15 @@ use alloy_primitives::{Address, U64}; use reth_chainspec::{ChainInfo, ChainSpec}; use reth_errors::RethResult; use reth_evm::ConfigureEvm; +use reth_node_api::{BuilderProvider, FullNodeComponents}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderFactory}; -use reth_rpc_eth_api::helpers::{ - Call, EthApiSpec, EthCall, EthFees, EthState, LoadFee, LoadState, SpawnBlocking, Trace, +use reth_rpc::eth::DevSigner; +use reth_rpc_eth_api::{ + helpers::{ + AddDevSigners, Call, EthApiSpec, EthCall, EthFees, EthSigner, EthState, LoadFee, LoadState, + SpawnBlocking, Trace, UpdateRawTxForwarder, + }, + RawTransactionForwarder, }; use reth_rpc_eth_types::EthStateCache; use reth_rpc_types::SyncStatus; @@ -154,3 +160,31 @@ impl Trace for OpEthApi { self.inner.evm_config() } } + +impl AddDevSigners for OpEthApi { + fn signers(&self) -> &parking_lot::RwLock>> { + self.inner.signers() + } + + fn with_dev_accounts(&self) { + *self.signers().write() = DevSigner::random_signers(20) + } +} + +impl UpdateRawTxForwarder for OpEthApi { + fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { + self.inner.set_eth_raw_transaction_forwarder(forwarder); + } +} + +impl BuilderProvider for OpEthApi +where + Eth: BuilderProvider, + N: FullNodeComponents, +{ + type Ctx<'a> = >::Ctx<'a>; + + fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { + Box::new(|ctx| Self { inner: Eth::builder()(ctx) }) + } +} diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index d97b23b5125b..d410268a2df2 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -61,6 +61,7 @@ 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 tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } serde_json.workspace = true diff --git a/crates/rpc/rpc-builder/src/config.rs b/crates/rpc/rpc-builder/src/config.rs index 1f61f57919f2..1cac81f4c8d2 100644 --- a/crates/rpc/rpc-builder/src/config.rs +++ b/crates/rpc/rpc-builder/src/config.rs @@ -1,16 +1,18 @@ -use crate::{ - auth::AuthServerConfig, error::RpcError, EthConfig, IpcServerBuilder, RpcModuleConfig, - RpcServerConfig, TransportRpcModuleConfig, -}; +use std::{net::SocketAddr, path::PathBuf}; + use jsonrpsee::server::ServerBuilder; use reth_node_core::{args::RpcServerArgs, utils::get_or_create_jwt_secret_from_path}; -use reth_rpc_eth_types::{EthStateCacheConfig, GasPriceOracleConfig}; +use reth_rpc_eth_types::{EthConfig, EthStateCacheConfig, GasPriceOracleConfig}; use reth_rpc_layer::{JwtError, JwtSecret}; use reth_rpc_server_types::RpcModuleSelection; -use std::{net::SocketAddr, path::PathBuf}; use tower::layer::util::Identity; use tracing::debug; +use crate::{ + auth::AuthServerConfig, error::RpcError, IpcServerBuilder, RpcModuleConfig, RpcServerConfig, + TransportRpcModuleConfig, +}; + /// A trait that provides a configured RPC server. /// /// This provides all basic config values for the RPC server and is implemented by the diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index b9b2d63ef331..af0097c23b3c 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -1,31 +1,14 @@ -use std::{fmt::Debug, time::Duration}; - use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_provider::{ - BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider, - FullRpcProvider, StateProviderFactory, -}; -use reth_rpc::{eth::EthFilterConfig, EthApi, EthFilter, EthPubSub}; +use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory}; +use reth_rpc::{EthFilter, EthPubSub}; use reth_rpc_eth_types::{ - cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache, - EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, - GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP, -}; -use reth_rpc_server_types::constants::{ - default_max_tracing_requests, DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKS_PER_FILTER, - DEFAULT_MAX_LOGS_PER_RESPONSE, DEFAULT_PROOF_PERMITS, + cache::cache_new_blocks_task, EthApiBuilderCtx, EthConfig, EthStateCache, }; -use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; -use reth_transaction_pool::TransactionPool; -use serde::{Deserialize, Serialize}; +use reth_tasks::TaskSpawner; -/// Default value for stale filter ttl -const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60); - -/// Alias for function that builds the core `eth` namespace API. -pub type EthApiBuilder = - Box) -> EthApi>; +/// Alias for `eth` namespace API builder. +pub type DynEthApiBuilder = + Box) -> EthApi>; /// Handlers for core, filter and pubsub `eth` namespace APIs. #[derive(Debug, Clone)] @@ -43,7 +26,7 @@ pub struct EthHandlers { impl EthHandlers { /// Returns a new [`EthHandlers`] builder. #[allow(clippy::too_many_arguments)] - pub fn builder( + pub fn builder( provider: Provider, pool: Pool, network: Network, @@ -51,12 +34,16 @@ impl EthHandlers EthHandlersBuilder - where - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, - { + eth_api_builder: DynEthApiBuilder< + Provider, + Pool, + EvmConfig, + Network, + Tasks, + Events, + EthApi, + >, + ) -> EthHandlersBuilder { EthHandlersBuilder { provider, pool, @@ -65,7 +52,7 @@ impl EthHandlers, + eth_api_builder: DynEthApiBuilder, } impl @@ -89,9 +76,10 @@ where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Pool: Send + Sync + Clone + 'static, EvmConfig: ConfigureEvm, - Network: Clone, + Network: Clone + 'static, Tasks: TaskSpawner + Clone + 'static, - Events: CanonStateSubscriptions + Clone, + Events: CanonStateSubscriptions + Clone + 'static, + EthApi: 'static, { /// Returns a new instance with handlers for `eth` namespace. pub fn build(self) -> EthHandlers { @@ -135,170 +123,6 @@ where } } -/// Additional config values for the eth namespace. -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct EthConfig { - /// Settings for the caching layer - pub cache: EthStateCacheConfig, - /// Settings for the gas price oracle - pub gas_oracle: GasPriceOracleConfig, - /// The maximum number of blocks into the past for generating state proofs. - pub eth_proof_window: u64, - /// The maximum number of tracing calls that can be executed in concurrently. - pub max_tracing_requests: usize, - /// Maximum number of blocks that could be scanned per filter request in `eth_getLogs` calls. - pub max_blocks_per_filter: u64, - /// Maximum number of logs that can be returned in a single response in `eth_getLogs` calls. - pub max_logs_per_response: usize, - /// Gas limit for `eth_call` and call tracing RPC methods. - /// - /// Defaults to [`RPC_DEFAULT_GAS_CAP`] - pub rpc_gas_cap: u64, - /// - /// Sets TTL for stale filters - pub stale_filter_ttl: Duration, - /// Settings for the fee history cache - pub fee_history_cache: FeeHistoryCacheConfig, - /// The maximum number of getproof calls that can be executed concurrently. - pub proof_permits: usize, -} - -impl EthConfig { - /// Returns the filter config for the `eth_filter` handler. - pub fn filter_config(&self) -> EthFilterConfig { - EthFilterConfig::default() - .max_blocks_per_filter(self.max_blocks_per_filter) - .max_logs_per_response(self.max_logs_per_response) - .stale_filter_ttl(self.stale_filter_ttl) - } -} - -impl Default for EthConfig { - fn default() -> Self { - Self { - cache: EthStateCacheConfig::default(), - gas_oracle: GasPriceOracleConfig::default(), - eth_proof_window: DEFAULT_ETH_PROOF_WINDOW, - max_tracing_requests: default_max_tracing_requests(), - max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER, - max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE, - rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(), - stale_filter_ttl: DEFAULT_STALE_FILTER_TTL, - fee_history_cache: FeeHistoryCacheConfig::default(), - proof_permits: DEFAULT_PROOF_PERMITS, - } - } -} - -impl EthConfig { - /// Configures the caching layer settings - pub const fn state_cache(mut self, cache: EthStateCacheConfig) -> Self { - self.cache = cache; - self - } - - /// Configures the gas price oracle settings - pub const fn gpo_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self { - self.gas_oracle = gas_oracle_config; - self - } - - /// Configures the maximum number of tracing requests - pub const fn max_tracing_requests(mut self, max_requests: usize) -> Self { - self.max_tracing_requests = max_requests; - self - } - - /// Configures the maximum block length to scan per `eth_getLogs` request - pub const fn max_blocks_per_filter(mut self, max_blocks: u64) -> Self { - self.max_blocks_per_filter = max_blocks; - self - } - - /// Configures the maximum number of logs per response - pub const fn max_logs_per_response(mut self, max_logs: usize) -> Self { - self.max_logs_per_response = max_logs; - self - } - - /// Configures the maximum gas limit for `eth_call` and call tracing RPC methods - pub const fn rpc_gas_cap(mut self, rpc_gas_cap: u64) -> Self { - self.rpc_gas_cap = rpc_gas_cap; - self - } - - /// Configures the maximum proof window for historical proof generation. - pub const fn eth_proof_window(mut self, window: u64) -> Self { - self.eth_proof_window = window; - self - } - - /// Configures the number of getproof requests - pub const fn proof_permits(mut self, permits: usize) -> Self { - self.proof_permits = permits; - self - } -} - -/// Context for building the `eth` namespace API. -#[derive(Debug, Clone)] -pub struct EthApiBuilderCtx { - /// Database handle. - pub provider: Provider, - /// Mempool handle. - pub pool: Pool, - /// Network handle. - pub network: Network, - /// EVM configuration. - pub evm_config: EvmConfig, - /// RPC config for `eth` namespace. - pub config: EthConfig, - /// Runtime handle. - pub executor: Tasks, - /// Events handle. - pub events: Events, - /// RPC cache handle. - pub cache: EthStateCache, -} - -/// Ethereum layer one `eth` RPC server builder. -#[derive(Default, Debug, Clone, Copy)] -pub struct EthApiBuild; - -impl EthApiBuild { - /// Builds the [`EthApiServer`](reth_rpc_eth_api::EthApiServer), for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> EthApi - where - Provider: FullRpcProvider, - Pool: TransactionPool, - Network: NetworkInfo + Clone, - Tasks: TaskSpawner + Clone + 'static, - Events: CanonStateSubscriptions, - EvmConfig: ConfigureEvm, - { - let gas_oracle = GasPriceOracleBuilder::build(ctx); - let fee_history_cache = FeeHistoryCacheBuilder::build(ctx); - - EthApi::with_spawner( - ctx.provider.clone(), - ctx.pool.clone(), - ctx.network.clone(), - ctx.cache.clone(), - gas_oracle, - ctx.config.rpc_gas_cap, - ctx.config.eth_proof_window, - Box::new(ctx.executor.clone()), - BlockingTaskPool::build().expect("failed to build blocking task pool"), - fee_history_cache, - ctx.evm_config.clone(), - None, - ctx.config.proof_permits, - ) - } -} - /// Builds the `eth_` namespace API [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer). #[derive(Debug)] pub struct EthFilterApiBuilder; @@ -348,50 +172,3 @@ impl EthPubSubApiBuilder { ) } } - -/// Builds `eth_` core api component [`GasPriceOracle`], for given context. -#[derive(Debug)] -pub struct GasPriceOracleBuilder; - -impl GasPriceOracleBuilder { - /// Builds a [`GasPriceOracle`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> GasPriceOracle - where - Provider: BlockReaderIdExt + Clone, - { - GasPriceOracle::new(ctx.provider.clone(), ctx.config.gas_oracle, ctx.cache.clone()) - } -} - -/// Builds `eth_` core api component [`FeeHistoryCache`], for given context. -#[derive(Debug)] -pub struct FeeHistoryCacheBuilder; - -impl FeeHistoryCacheBuilder { - /// Builds a [`FeeHistoryCache`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> FeeHistoryCache - where - Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, - Tasks: TaskSpawner, - Events: CanonStateSubscriptions, - { - let fee_history_cache = - FeeHistoryCache::new(ctx.cache.clone(), ctx.config.fee_history_cache); - - let new_canonical_blocks = ctx.events.canonical_state_stream(); - let fhc = fee_history_cache.clone(); - let provider = ctx.provider.clone(); - ctx.executor.spawn_critical( - "cache canonical blocks for fee history task", - Box::pin(async move { - fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider).await; - }), - ); - - fee_history_cache - } -} diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index f02afd9836a7..e92067011344 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -19,13 +19,13 @@ //! use reth_evm::ConfigureEvm; //! use reth_network_api::{NetworkInfo, Peers}; //! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; +//! use reth_rpc::EthApi; //! use reth_rpc_builder::{ -//! EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, -//! TransportRpcModuleConfig, +//! RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig, //! }; -//! //! use reth_tasks::TokioTaskExecutor; //! use reth_transaction_pool::TransactionPool; +//! //! pub async fn launch( //! provider: Provider, //! pool: Pool, @@ -54,7 +54,7 @@ //! events, //! evm_config, //! ) -//! .build(transports, EthApiBuild::build); +//! .build(transports, Box::new(EthApi::with_spawner)); //! let handle = RpcServerConfig::default() //! .with_http(ServerBuilder::default()) //! .start(&transport_modules) @@ -70,9 +70,10 @@ //! use reth_evm::ConfigureEvm; //! use reth_network_api::{NetworkInfo, Peers}; //! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; +//! use reth_rpc::EthApi; //! use reth_rpc_api::EngineApiServer; //! use reth_rpc_builder::{ -//! auth::AuthServerConfig, EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, +//! auth::AuthServerConfig, RethRpcModule, RpcModuleBuilder, RpcServerConfig, //! TransportRpcModuleConfig, //! }; //! use reth_rpc_layer::JwtSecret; @@ -113,7 +114,7 @@ //! //! // configure the server modules //! let (modules, auth_module, _registry) = -//! builder.build_with_auth_server(transports, engine_api, EthApiBuild::build); +//! builder.build_with_auth_server(transports, engine_api, Box::new(EthApi::with_spawner)); //! //! // start the servers //! let auth_config = AuthServerConfig::builder(JwtSecret::random()).build(); @@ -140,6 +141,7 @@ use std::{ }; use error::{ConflictingModules, RpcError, ServerKind}; +use eth::DynEthApiBuilder; use http::{header::AUTHORIZATION, HeaderMap}; use jsonrpsee::{ core::RegisterMethodError, @@ -167,7 +169,7 @@ use reth_rpc_eth_api::{ }, EthApiServer, FullEthApiServer, RawTransactionForwarder, }; -use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider}; +use reth_rpc_eth_types::{EthConfig, EthStateCache, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret}; use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; @@ -202,17 +204,14 @@ pub mod error; /// Eth utils pub mod eth; -pub use eth::{ - EthApiBuild, EthApiBuilderCtx, EthConfig, EthHandlers, FeeHistoryCacheBuilder, - GasPriceOracleBuilder, -}; +pub use eth::EthHandlers; // Rpc server metrics mod metrics; /// Convenience function for starting a server in one step. #[allow(clippy::too_many_arguments)] -pub async fn launch( +pub async fn launch( provider: Provider, pool: Pool, network: Network, @@ -221,7 +220,7 @@ pub async fn launch, ) -> Result where Provider: FullRpcProvider + AccountReader + ChangeSetReader, @@ -230,8 +229,6 @@ where Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, EvmConfig: ConfigureEvm, - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, EthApi: FullEthApiServer, { let module_config = module_config.into(); @@ -426,11 +423,11 @@ where /// also configures the auth (engine api) server, which exposes a subset of the `eth_` /// namespace. #[allow(clippy::type_complexity)] - pub fn build_with_auth_server( + pub fn build_with_auth_server( self, module_config: TransportRpcModuleConfig, engine: EngineApi, - eth: EthApiB, + eth: DynEthApiBuilder, ) -> ( TransportRpcModules, AuthRpcModule, @@ -439,8 +436,6 @@ where where EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, EthApi: FullEthApiServer, { let Self { provider, pool, network, executor, events, evm_config } = self; @@ -469,7 +464,8 @@ where /// use reth_evm::ConfigureEvm; /// use reth_network_api::noop::NoopNetwork; /// use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; - /// use reth_rpc_builder::{EthApiBuild, RpcModuleBuilder}; + /// use reth_rpc::EthApi; + /// use reth_rpc_builder::RpcModuleBuilder; /// use reth_tasks::TokioTaskExecutor; /// use reth_transaction_pool::noop::NoopTransactionPool; /// @@ -481,19 +477,18 @@ where /// .with_executor(TokioTaskExecutor::default()) /// .with_events(TestCanonStateSubscriptions::default()) /// .with_evm_config(evm) - /// .into_registry(Default::default(), EthApiBuild::build); + /// .into_registry(Default::default(), Box::new(EthApi::with_spawner)); /// /// let eth_api = registry.eth_api(); /// } /// ``` - pub fn into_registry( + pub fn into_registry( self, config: RpcModuleConfig, - eth: EthApiB, + eth: DynEthApiBuilder, ) -> RpcRegistryInner where - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, + EthApi: 'static, { let Self { provider, pool, network, executor, events, evm_config } = self; RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth) @@ -501,14 +496,12 @@ where /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can /// be used to start the transport server(s). - pub fn build( + pub fn build( self, module_config: TransportRpcModuleConfig, - eth: EthApiB, + eth: DynEthApiBuilder, ) -> TransportRpcModules<()> where - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, EthApi: FullEthApiServer, { let mut modules = TransportRpcModules::default(); @@ -636,13 +629,14 @@ impl where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Pool: Send + Sync + Clone + 'static, - Network: Clone, - Events: CanonStateSubscriptions + Clone, + Network: Clone + 'static, + Events: CanonStateSubscriptions + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, + EthApi: 'static, { /// Creates a new, empty instance. #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( provider: Provider, pool: Pool, network: Network, @@ -650,12 +644,18 @@ where events: Events, config: RpcModuleConfig, evm_config: EvmConfig, - eth_api_builder: EthApiB, + eth_api_builder: DynEthApiBuilder< + Provider, + Pool, + EvmConfig, + Network, + Tasks, + Events, + EthApi, + >, ) -> Self where EvmConfig: ConfigureEvm, - EthApiB: FnOnce(&EthApiBuilderCtx) -> EthApi - + 'static, { let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests); diff --git a/crates/rpc/rpc-builder/tests/it/startup.rs b/crates/rpc/rpc-builder/tests/it/startup.rs index 5680d03a5307..9f6961fbba0d 100644 --- a/crates/rpc/rpc-builder/tests/it/startup.rs +++ b/crates/rpc/rpc-builder/tests/it/startup.rs @@ -2,9 +2,10 @@ use std::io; +use reth_rpc::EthApi; use reth_rpc_builder::{ error::{RpcError, ServerKind, WsHttpSamePortError}, - EthApiBuild, RpcServerConfig, TransportRpcModuleConfig, + RpcServerConfig, TransportRpcModuleConfig, }; use reth_rpc_server_types::RethRpcModule; @@ -26,8 +27,10 @@ async fn test_http_addr_in_use() { let handle = launch_http(vec![RethRpcModule::Admin]).await; let addr = handle.http_local_addr().unwrap(); let builder = test_rpc_builder(); - let server = builder - .build(TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]), EthApiBuild::build); + let server = builder.build( + TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]), + Box::new(EthApi::with_spawner), + ); let result = RpcServerConfig::http(Default::default()).with_http_address(addr).start(&server).await; let err = result.unwrap_err(); @@ -39,8 +42,10 @@ async fn test_ws_addr_in_use() { let handle = launch_ws(vec![RethRpcModule::Admin]).await; let addr = handle.ws_local_addr().unwrap(); let builder = test_rpc_builder(); - let server = builder - .build(TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]), EthApiBuild::build); + let server = builder.build( + TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]), + Box::new(EthApi::with_spawner), + ); let result = RpcServerConfig::ws(Default::default()).with_ws_address(addr).start(&server).await; let err = result.unwrap_err(); assert!(is_addr_in_use_kind(&err, ServerKind::WS(addr)), "{err}"); @@ -60,7 +65,7 @@ async fn test_launch_same_port_different_modules() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]) .with_http(vec![RethRpcModule::Eth]), - EthApiBuild::build, + Box::new(EthApi::with_spawner), ); let addr = test_address(); let res = RpcServerConfig::ws(Default::default()) @@ -82,7 +87,7 @@ async fn test_launch_same_port_same_cors() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) .with_http(vec![RethRpcModule::Eth]), - EthApiBuild::build, + Box::new(EthApi::with_spawner), ); let addr = test_address(); let res = RpcServerConfig::ws(Default::default()) @@ -102,7 +107,7 @@ async fn test_launch_same_port_different_cors() { let server = builder.build( TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) .with_http(vec![RethRpcModule::Eth]), - EthApiBuild::build, + Box::new(EthApi::with_spawner), ); let addr = test_address(); let res = RpcServerConfig::ws(Default::default()) diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index d5fe508aaa09..a9727c0d5783 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -7,9 +7,10 @@ use reth_evm_ethereum::EthEvmConfig; use reth_network_api::noop::NoopNetwork; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; +use reth_rpc::EthApi; use reth_rpc_builder::{ auth::{AuthRpcModule, AuthServerConfig, AuthServerHandle}, - EthApiBuild, RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig, + RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig, }; use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; use reth_rpc_layer::JwtSecret; @@ -53,7 +54,8 @@ pub async fn launch_auth(secret: JwtSecret) -> AuthServerHandle { /// Launches a new server with http only with the given modules pub async fn launch_http(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_http(modules), EthApiBuild::build); + let server = + builder.build(TransportRpcModuleConfig::set_http(modules), Box::new(EthApi::with_spawner)); RpcServerConfig::http(Default::default()) .with_http_address(test_address()) .start(&server) @@ -64,7 +66,8 @@ pub async fn launch_http(modules: impl Into) -> RpcServerHan /// Launches a new server with ws only with the given modules pub async fn launch_ws(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::set_ws(modules), EthApiBuild::build); + let server = + builder.build(TransportRpcModuleConfig::set_ws(modules), Box::new(EthApi::with_spawner)); RpcServerConfig::ws(Default::default()) .with_http_address(test_address()) .start(&server) @@ -78,7 +81,7 @@ pub async fn launch_http_ws(modules: impl Into) -> RpcServer let modules = modules.into(); let server = builder.build( TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), - EthApiBuild::build, + Box::new(EthApi::with_spawner), ); RpcServerConfig::ws(Default::default()) .with_ws_address(test_address()) @@ -95,7 +98,7 @@ pub async fn launch_http_ws_same_port(modules: impl Into) -> let modules = modules.into(); let server = builder.build( TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), - EthApiBuild::build, + Box::new(EthApi::with_spawner), ); let addr = test_address(); RpcServerConfig::ws(Default::default()) diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs index 72e49077efb8..b82a621acaf4 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -32,7 +32,7 @@ pub use call::{Call, EthCall}; pub use fee::{EthFees, LoadFee}; pub use pending_block::LoadPendingBlock; pub use receipt::LoadReceipt; -pub use signer::EthSigner; +pub use signer::{AddDevSigners, EthSigner}; pub use spec::EthApiSpec; pub use state::{EthState, LoadState}; pub use trace::Trace; diff --git a/crates/rpc/rpc-eth-api/src/helpers/signer.rs b/crates/rpc/rpc-eth-api/src/helpers/signer.rs index 2a75d9abb02e..d7aecfe25c33 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/signer.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/signer.rs @@ -37,3 +37,14 @@ pub trait EthSigner: Send + Sync + DynClone { } dyn_clone::clone_trait_object!(EthSigner); + +/// Adds 20 random dev signers for access via the API. Used in dev mode. +#[auto_impl::auto_impl(&)] +pub trait AddDevSigners { + /// Returns a handle to the signers. + fn signers(&self) -> &parking_lot::RwLock>>; + + /// Generates 20 random developer accounts. + /// Used in DEV mode. + fn with_dev_accounts(&self); +} diff --git a/crates/rpc/rpc-eth-types/src/builder/config.rs b/crates/rpc/rpc-eth-types/src/builder/config.rs new file mode 100644 index 000000000000..2edc81e8d7ce --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/builder/config.rs @@ -0,0 +1,170 @@ +//! Configuration for `eth` namespace APIs. + +use std::time::Duration; + +use crate::{ + EthStateCacheConfig, FeeHistoryCacheConfig, GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP, +}; +use reth_rpc_server_types::constants::{ + default_max_tracing_requests, DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKS_PER_FILTER, + DEFAULT_MAX_LOGS_PER_RESPONSE, DEFAULT_PROOF_PERMITS, +}; +use serde::{Deserialize, Serialize}; + +/// Default value for stale filter ttl +pub const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60); + +/// Additional config values for the eth namespace. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct EthConfig { + /// Settings for the caching layer + pub cache: EthStateCacheConfig, + /// Settings for the gas price oracle + pub gas_oracle: GasPriceOracleConfig, + /// The maximum number of blocks into the past for generating state proofs. + pub eth_proof_window: u64, + /// The maximum number of tracing calls that can be executed in concurrently. + pub max_tracing_requests: usize, + /// Maximum number of blocks that could be scanned per filter request in `eth_getLogs` calls. + pub max_blocks_per_filter: u64, + /// Maximum number of logs that can be returned in a single response in `eth_getLogs` calls. + pub max_logs_per_response: usize, + /// Gas limit for `eth_call` and call tracing RPC methods. + /// + /// Defaults to [`RPC_DEFAULT_GAS_CAP`] + pub rpc_gas_cap: u64, + /// + /// Sets TTL for stale filters + pub stale_filter_ttl: Duration, + /// Settings for the fee history cache + pub fee_history_cache: FeeHistoryCacheConfig, + /// The maximum number of getproof calls that can be executed concurrently. + pub proof_permits: usize, +} + +impl EthConfig { + /// Returns the filter config for the `eth_filter` handler. + pub fn filter_config(&self) -> EthFilterConfig { + EthFilterConfig::default() + .max_blocks_per_filter(self.max_blocks_per_filter) + .max_logs_per_response(self.max_logs_per_response) + .stale_filter_ttl(self.stale_filter_ttl) + } +} + +impl Default for EthConfig { + fn default() -> Self { + Self { + cache: EthStateCacheConfig::default(), + gas_oracle: GasPriceOracleConfig::default(), + eth_proof_window: DEFAULT_ETH_PROOF_WINDOW, + max_tracing_requests: default_max_tracing_requests(), + max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER, + max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE, + rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(), + stale_filter_ttl: DEFAULT_STALE_FILTER_TTL, + fee_history_cache: FeeHistoryCacheConfig::default(), + proof_permits: DEFAULT_PROOF_PERMITS, + } + } +} + +impl EthConfig { + /// Configures the caching layer settings + pub const fn state_cache(mut self, cache: EthStateCacheConfig) -> Self { + self.cache = cache; + self + } + + /// Configures the gas price oracle settings + pub const fn gpo_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self { + self.gas_oracle = gas_oracle_config; + self + } + + /// Configures the maximum number of tracing requests + pub const fn max_tracing_requests(mut self, max_requests: usize) -> Self { + self.max_tracing_requests = max_requests; + self + } + + /// Configures the maximum block length to scan per `eth_getLogs` request + pub const fn max_blocks_per_filter(mut self, max_blocks: u64) -> Self { + self.max_blocks_per_filter = max_blocks; + self + } + + /// Configures the maximum number of logs per response + pub const fn max_logs_per_response(mut self, max_logs: usize) -> Self { + self.max_logs_per_response = max_logs; + self + } + + /// Configures the maximum gas limit for `eth_call` and call tracing RPC methods + pub const fn rpc_gas_cap(mut self, rpc_gas_cap: u64) -> Self { + self.rpc_gas_cap = rpc_gas_cap; + self + } + + /// Configures the maximum proof window for historical proof generation. + pub const fn eth_proof_window(mut self, window: u64) -> Self { + self.eth_proof_window = window; + self + } + + /// Configures the number of getproof requests + pub const fn proof_permits(mut self, permits: usize) -> Self { + self.proof_permits = permits; + self + } +} + +/// Config for the filter +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EthFilterConfig { + /// Maximum number of blocks that a filter can scan for logs. + /// + /// If `None` then no limit is enforced. + pub max_blocks_per_filter: Option, + /// Maximum number of logs that can be returned in a single response in `eth_getLogs` calls. + /// + /// If `None` then no limit is enforced. + pub max_logs_per_response: Option, + /// How long a filter remains valid after the last poll. + /// + /// A filter is considered stale if it has not been polled for longer than this duration and + /// will be removed. + pub stale_filter_ttl: Duration, +} + +impl EthFilterConfig { + /// Sets the maximum number of blocks that a filter can scan for logs. + pub const fn max_blocks_per_filter(mut self, num: u64) -> Self { + self.max_blocks_per_filter = Some(num); + self + } + + /// Sets the maximum number of logs that can be returned in a single response in `eth_getLogs` + /// calls. + pub const fn max_logs_per_response(mut self, num: usize) -> Self { + self.max_logs_per_response = Some(num); + self + } + + /// Sets how long a filter remains valid after the last poll before it will be removed. + pub const fn stale_filter_ttl(mut self, duration: Duration) -> Self { + self.stale_filter_ttl = duration; + self + } +} + +impl Default for EthFilterConfig { + fn default() -> Self { + Self { + max_blocks_per_filter: None, + max_logs_per_response: None, + // 5min + stale_filter_ttl: Duration::from_secs(5 * 60), + } + } +} diff --git a/crates/rpc/rpc-eth-types/src/builder/ctx.rs b/crates/rpc/rpc-eth-types/src/builder/ctx.rs new file mode 100644 index 000000000000..6741f2f651bf --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/builder/ctx.rs @@ -0,0 +1,98 @@ +//! Context required for building `eth` namespace APIs. + +use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; +use reth_tasks::TaskSpawner; + +use crate::{ + fee_history::fee_history_cache_new_blocks_task, EthConfig, EthStateCache, FeeHistoryCache, + GasPriceOracle, +}; + +/// Context for building the `eth` namespace API. +#[derive(Debug, Clone)] +pub struct EthApiBuilderCtx { + /// Database handle. + pub provider: Provider, + /// Mempool handle. + pub pool: Pool, + /// Network handle. + pub network: Network, + /// EVM configuration. + pub evm_config: EvmConfig, + /// RPC config for `eth` namespace. + pub config: EthConfig, + /// Runtime handle. + pub executor: Tasks, + /// Events handle. + pub events: Events, + /// RPC cache handle. + pub cache: EthStateCache, +} + +impl + EthApiBuilderCtx +where + Provider: BlockReaderIdExt + Clone, +{ + /// Returns a new [`FeeHistoryCache`] for the context. + pub fn new_fee_history_cache(&self) -> FeeHistoryCache + where + Provider: ChainSpecProvider + 'static, + Tasks: TaskSpawner, + Events: CanonStateSubscriptions, + { + FeeHistoryCacheBuilder::build(self) + } + + /// Returns a new [`GasPriceOracle`] for the context. + pub fn new_gas_price_oracle(&self) -> GasPriceOracle { + GasPriceOracleBuilder::build(self) + } +} + +/// Builds `eth_` core api component [`GasPriceOracle`], for given context. +#[derive(Debug)] +pub struct GasPriceOracleBuilder; + +impl GasPriceOracleBuilder { + /// Builds a [`GasPriceOracle`], for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> GasPriceOracle + where + Provider: BlockReaderIdExt + Clone, + { + GasPriceOracle::new(ctx.provider.clone(), ctx.config.gas_oracle, ctx.cache.clone()) + } +} + +/// Builds `eth_` core api component [`FeeHistoryCache`], for given context. +#[derive(Debug)] +pub struct FeeHistoryCacheBuilder; + +impl FeeHistoryCacheBuilder { + /// Builds a [`FeeHistoryCache`], for given context. + pub fn build( + ctx: &EthApiBuilderCtx, + ) -> FeeHistoryCache + where + Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, + Tasks: TaskSpawner, + Events: CanonStateSubscriptions, + { + let fee_history_cache = + FeeHistoryCache::new(ctx.cache.clone(), ctx.config.fee_history_cache); + + let new_canonical_blocks = ctx.events.canonical_state_stream(); + let fhc = fee_history_cache.clone(); + let provider = ctx.provider.clone(); + ctx.executor.spawn_critical( + "cache canonical blocks for fee history task", + Box::pin(async move { + fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider).await; + }), + ); + + fee_history_cache + } +} diff --git a/crates/rpc/rpc-eth-types/src/builder/mod.rs b/crates/rpc/rpc-eth-types/src/builder/mod.rs new file mode 100644 index 000000000000..0d35de18004d --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/builder/mod.rs @@ -0,0 +1,4 @@ +//! `eth` namespace API builder types. + +pub mod config; +pub mod ctx; diff --git a/crates/rpc/rpc-eth-types/src/lib.rs b/crates/rpc/rpc-eth-types/src/lib.rs index fb9901dd071c..1897a9fd703d 100644 --- a/crates/rpc/rpc-eth-types/src/lib.rs +++ b/crates/rpc/rpc-eth-types/src/lib.rs @@ -8,6 +8,7 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] +pub mod builder; pub mod cache; pub mod error; pub mod fee_history; @@ -20,6 +21,10 @@ pub mod revm_utils; pub mod transaction; pub mod utils; +pub use builder::{ + config::{EthConfig, EthFilterConfig}, + ctx::EthApiBuilderCtx, +}; pub use cache::{ config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache, EthStateCache, diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 8542921c4c24..56a28e8057e3 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -33,6 +33,7 @@ reth-evm.workspace = true reth-rpc-eth-types.workspace = true reth-rpc-server-types.workspace = true reth-evm-optimism = { workspace = true, optional = true } +reth-node-api.workspace = true # eth alloy-dyn-abi.workspace = true diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 3cff3b0096c7..09065dfc1a12 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -1,25 +1,26 @@ //! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait //! Handles RPC requests for the `eth_` namespace. -use futures::Future; use std::sync::Arc; use derive_more::Deref; +use futures::Future; +use reth_node_api::{BuilderProvider, FullNodeComponents}; use reth_primitives::{BlockNumberOrTag, U256}; -use reth_provider::BlockReaderIdExt; +use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; use reth_rpc_eth_api::{ helpers::{transaction::UpdateRawTxForwarder, EthSigner, SpawnBlocking}, RawTransactionForwarder, }; -use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock}; +use reth_rpc_eth_types::{ + EthApiBuilderCtx, EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock, +}; use reth_tasks::{ pool::{BlockingTaskGuard, BlockingTaskPool}, - TaskSpawner, TokioTaskExecutor, + TaskExecutor, TaskSpawner, TokioTaskExecutor, }; use tokio::sync::{AcquireError, Mutex, OwnedSemaphorePermit}; -use crate::eth::DevSigner; - /// `Eth` API implementation. /// /// This type provides the functionality for handling `eth_` related requests. @@ -55,66 +56,59 @@ where raw_transaction_forwarder: Option>, proof_permits: usize, ) -> Self { - Self::with_spawner( + let inner = EthApiInner::new( provider, pool, network, eth_cache, gas_oracle, - gas_cap.into().into(), + gas_cap, eth_proof_window, - Box::::default(), blocking_task_pool, fee_history_cache, evm_config, + TokioTaskExecutor::default(), raw_transaction_forwarder, proof_permits, - ) + ); + + Self { inner: Arc::new(inner) } } +} +impl EthApi +where + Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, + Pool: Clone, + EvmConfig: Clone, + Network: Clone, +{ /// Creates a new, shareable instance. - #[allow(clippy::too_many_arguments)] - pub fn with_spawner( - provider: Provider, - pool: Pool, - network: Network, - eth_cache: EthStateCache, - gas_oracle: GasPriceOracle, - gas_cap: u64, - eth_proof_window: u64, - task_spawner: Box, - blocking_task_pool: BlockingTaskPool, - fee_history_cache: FeeHistoryCache, - evm_config: EvmConfig, - raw_transaction_forwarder: Option>, - proof_permits: usize, - ) -> Self { - // get the block number of the latest block - let latest_block = provider - .header_by_number_or_tag(BlockNumberOrTag::Latest) - .ok() - .flatten() - .map(|header| header.number) - .unwrap_or_default(); - - let inner = EthApiInner { - provider, - pool, - network, - signers: parking_lot::RwLock::new(Default::default()), - eth_cache, - gas_oracle, - gas_cap, - eth_proof_window, - starting_block: U256::from(latest_block), - task_spawner, - pending_block: Default::default(), + pub fn with_spawner( + ctx: &EthApiBuilderCtx, + ) -> Self + where + Tasks: TaskSpawner + Clone + 'static, + Events: CanonStateSubscriptions, + { + let blocking_task_pool = + BlockingTaskPool::build().expect("failed to build blocking task pool"); + + let inner = EthApiInner::new( + ctx.provider.clone(), + ctx.pool.clone(), + ctx.network.clone(), + ctx.cache.clone(), + ctx.new_gas_price_oracle(), + ctx.config.rpc_gas_cap, + ctx.config.eth_proof_window, blocking_task_pool, - fee_history_cache, - evm_config, - raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder), - blocking_task_guard: BlockingTaskGuard::new(proof_permits), - }; + ctx.new_fee_history_cache(), + ctx.evm_config.clone(), + ctx.executor.clone(), + None, + ctx.config.proof_permits, + ); Self { inner: Arc::new(inner) } } @@ -163,12 +157,16 @@ where } } -impl EthApi { - /// Generates 20 random developer accounts. - /// Used in DEV mode. - pub fn with_dev_accounts(&self) { - let mut signers = self.inner.signers.write(); - *signers = DevSigner::random_signers(20); +impl BuilderProvider for EthApi +where + N: FullNodeComponents, + Network: Send + Sync + Clone + 'static, +{ + type Ctx<'a> = + &'a EthApiBuilderCtx; + + fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { + Box::new(|ctx| Self::with_spawner(ctx)) } } @@ -209,6 +207,59 @@ pub struct EthApiInner { blocking_task_guard: BlockingTaskGuard, } +impl EthApiInner +where + Provider: BlockReaderIdExt, +{ + /// Creates a new, shareable instance using the default tokio task spawner. + #[allow(clippy::too_many_arguments)] + pub fn new( + provider: Provider, + pool: Pool, + network: Network, + eth_cache: EthStateCache, + gas_oracle: GasPriceOracle, + gas_cap: impl Into, + eth_proof_window: u64, + blocking_task_pool: BlockingTaskPool, + fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, + task_spawner: impl TaskSpawner + 'static, + raw_transaction_forwarder: Option>, + proof_permits: usize, + ) -> Self { + let signers = parking_lot::RwLock::new(Default::default()); + // get the block number of the latest block + let starting_block = U256::from( + provider + .header_by_number_or_tag(BlockNumberOrTag::Latest) + .ok() + .flatten() + .map(|header| header.number) + .unwrap_or_default(), + ); + + Self { + provider, + pool, + network, + signers, + eth_cache, + gas_oracle, + gas_cap: gas_cap.into().into(), + eth_proof_window, + starting_block, + task_spawner: Box::new(task_spawner), + pending_block: Default::default(), + blocking_task_pool, + fee_history_cache, + evm_config, + raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder), + blocking_task_guard: BlockingTaskGuard::new(proof_permits), + } + } +} + impl EthApiInner { /// Returns a handle to data on disk. #[inline] diff --git a/crates/rpc/rpc/src/eth/filter.rs b/crates/rpc/rpc/src/eth/filter.rs index 1a2e55a5257c..ef26a5781de5 100644 --- a/crates/rpc/rpc/src/eth/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -17,7 +17,7 @@ use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError}; use reth_rpc_eth_api::EthFilterApiServer; use reth_rpc_eth_types::{ logs_utils::{self, append_matching_block_logs}, - EthApiError, EthFilterError, EthStateCache, EthSubscriptionIdProvider, + EthApiError, EthFilterConfig, EthFilterError, EthStateCache, EthSubscriptionIdProvider, }; use reth_rpc_server_types::ToRpcResult; use reth_rpc_types::{ @@ -515,56 +515,6 @@ where } } -/// Config for the filter -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EthFilterConfig { - /// Maximum number of blocks that a filter can scan for logs. - /// - /// If `None` then no limit is enforced. - pub max_blocks_per_filter: Option, - /// Maximum number of logs that can be returned in a single response in `eth_getLogs` calls. - /// - /// If `None` then no limit is enforced. - pub max_logs_per_response: Option, - /// How long a filter remains valid after the last poll. - /// - /// A filter is considered stale if it has not been polled for longer than this duration and - /// will be removed. - pub stale_filter_ttl: Duration, -} - -impl EthFilterConfig { - /// Sets the maximum number of blocks that a filter can scan for logs. - pub const fn max_blocks_per_filter(mut self, num: u64) -> Self { - self.max_blocks_per_filter = Some(num); - self - } - - /// Sets the maximum number of logs that can be returned in a single response in `eth_getLogs` - /// calls. - pub const fn max_logs_per_response(mut self, num: usize) -> Self { - self.max_logs_per_response = Some(num); - self - } - - /// Sets how long a filter remains valid after the last poll before it will be removed. - pub const fn stale_filter_ttl(mut self, duration: Duration) -> Self { - self.stale_filter_ttl = duration; - self - } -} - -impl Default for EthFilterConfig { - fn default() -> Self { - Self { - max_blocks_per_filter: None, - max_logs_per_response: None, - // 5min - stale_filter_ttl: Duration::from_secs(5 * 60), - } - } -} - /// All active filters #[derive(Debug, Clone, Default)] pub struct ActiveFilters { diff --git a/crates/rpc/rpc/src/eth/helpers/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs index a4cb726a2915..d29b0cc07c62 100644 --- a/crates/rpc/rpc/src/eth/helpers/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -6,12 +6,26 @@ use alloy_dyn_abi::TypedData; use reth_primitives::{ eip191_hash_message, sign_message, Address, Signature, TransactionSigned, B256, }; -use reth_rpc_eth_api::helpers::{signer::Result, EthSigner}; +use reth_rpc_eth_api::helpers::{signer::Result, AddDevSigners, EthSigner}; use reth_rpc_eth_types::SignError; use reth_rpc_types::TypedTransactionRequest; use reth_rpc_types_compat::transaction::to_primitive_transaction; use secp256k1::SecretKey; +use crate::EthApi; + +impl AddDevSigners + for EthApi +{ + fn signers(&self) -> &parking_lot::RwLock>> { + self.inner.signers() + } + + fn with_dev_accounts(&self) { + *self.signers().write() = DevSigner::random_signers(20) + } +} + /// Holds developer keys #[derive(Debug, Clone)] pub struct DevSigner { @@ -22,14 +36,14 @@ pub struct DevSigner { #[allow(dead_code)] impl DevSigner { /// Generates a random dev signer which satisfies [`EthSigner`] trait - pub(crate) fn random() -> Box { + pub fn random() -> Box { let mut signers = Self::random_signers(1); signers.pop().expect("expect to generate at least one signer") } /// Generates provided number of random dev signers /// which satisfy [`EthSigner`] trait - pub(crate) fn random_signers(num: u32) -> Vec> { + pub fn random_signers(num: u32) -> Vec> { let mut signers = Vec::new(); for _ in 0..num { let (sk, pk) = secp256k1::generate_keypair(&mut rand::thread_rng()); diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs index 4e6a0cbb8c75..52b10c08c2bf 100644 --- a/crates/rpc/rpc/src/eth/mod.rs +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -9,9 +9,9 @@ pub mod pubsub; /// Implementation of `eth` namespace API. pub use bundle::EthBundle; pub use core::EthApi; -pub use filter::{EthFilter, EthFilterConfig}; +pub use filter::EthFilter; pub use pubsub::EthPubSub; pub use helpers::signer::DevSigner; -pub use reth_rpc_eth_api::RawTransactionForwarder; +pub use reth_rpc_eth_api::{EthApiServer, RawTransactionForwarder}; diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index c006e396e2c7..f1f83c55d49c 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -46,7 +46,8 @@ use reth_node_api::{ }; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_ethereum::node::{ - EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder, + EthereumAddOns, EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, + EthereumPoolBuilder, }; use reth_payload_builder::{ error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, @@ -212,8 +213,9 @@ where EthereumExecutorBuilder, EthereumConsensusBuilder, >; + type AddOns = EthereumAddOns; - fn components_builder(self) -> Self::ComponentsBuilder { + fn components_builder(&self) -> Self::ComponentsBuilder { ComponentsBuilder::default() .node_types::() .pool(EthereumPoolBuilder::default()) diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index 207640dce9c9..6e58acdca169 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -22,7 +22,7 @@ use reth_chainspec::{Chain, ChainSpec, Head}; use reth_evm_ethereum::EthEvmConfig; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{EthExecutorProvider, EthereumNode}; +use reth_node_ethereum::{node::EthereumAddOns, EthExecutorProvider, EthereumNode}; use reth_primitives::{ revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, Address, Header, TransactionSigned, U256, @@ -180,6 +180,7 @@ async fn main() -> eyre::Result<()> { .with_types::() // use default ethereum components but with our executor .with_components(EthereumNode::components().executor(MyExecutorBuilder::default())) + .with_add_ons::() .launch() .await .unwrap(); diff --git a/examples/custom-node-components/src/main.rs b/examples/custom-node-components/src/main.rs index 842627797ef4..007d6fe0f8c0 100644 --- a/examples/custom-node-components/src/main.rs +++ b/examples/custom-node-components/src/main.rs @@ -10,7 +10,7 @@ use reth::{ blobstore::InMemoryBlobStore, EthTransactionPool, TransactionValidationTaskExecutor, }, }; -use reth_node_ethereum::EthereumNode; +use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::PoolConfig; @@ -23,6 +23,7 @@ fn main() { // Configure the components of the node // use default ethereum components but use our custom pool .with_components(EthereumNode::components().pool(CustomPoolBuilder::default())) + .with_add_ons::() .launch() .await?; diff --git a/examples/custom-payload-builder/src/main.rs b/examples/custom-payload-builder/src/main.rs index b2bc6af3607c..ca636198a839 100644 --- a/examples/custom-payload-builder/src/main.rs +++ b/examples/custom-payload-builder/src/main.rs @@ -20,7 +20,7 @@ use reth::{ transaction_pool::TransactionPool, }; use reth_basic_payload_builder::BasicPayloadJobGeneratorConfig; -use reth_node_ethereum::{EthEngineTypes, EthereumNode}; +use reth_node_ethereum::{node::EthereumAddOns, EthEngineTypes, EthereumNode}; use reth_payload_builder::PayloadBuilderService; pub mod generator; @@ -78,6 +78,7 @@ fn main() { .with_components( EthereumNode::components().payload(CustomPayloadBuilder::default()), ) + .with_add_ons::() .launch() .await?; diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs index 30c0479549fc..69f61fbd158d 100644 --- a/examples/rpc-db/src/main.rs +++ b/examples/rpc-db/src/main.rs @@ -19,6 +19,7 @@ use reth::{ providers::{BlockchainProvider, StaticFileProvider}, ProviderFactory, }, + rpc::eth::EthApi, utils::open_db_read_only, }; use reth_chainspec::ChainSpecBuilder; @@ -27,7 +28,7 @@ use reth_db_api::models::ClientVersion; // Bringing up the RPC use reth::rpc::builder::{ - EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, + RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, }; // Configuring the network parts, ideally also wouldn't need to think about this. use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; @@ -70,7 +71,7 @@ async fn main() -> eyre::Result<()> { // Pick which namespaces to expose. let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); - let mut server = rpc_builder.build(config, EthApiBuild::build); + let mut server = rpc_builder.build(config, Box::new(EthApi::with_spawner)); // Add a custom rpc namespace let custom_rpc = MyRpcExt { provider }; diff --git a/examples/stateful-precompile/src/main.rs b/examples/stateful-precompile/src/main.rs index b595647e0952..d73e613d66a9 100644 --- a/examples/stateful-precompile/src/main.rs +++ b/examples/stateful-precompile/src/main.rs @@ -21,7 +21,7 @@ use reth::{ use reth_chainspec::{Chain, ChainSpec}; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{EthEvmConfig, EthExecutorProvider, EthereumNode}; +use reth_node_ethereum::{node::EthereumAddOns, EthEvmConfig, EthExecutorProvider, EthereumNode}; use reth_primitives::{ revm_primitives::{SpecId, StatefulPrecompileMut}, Header, TransactionSigned, @@ -244,6 +244,7 @@ async fn main() -> eyre::Result<()> { .with_types::() // use default ethereum components but with our executor .with_components(EthereumNode::components().executor(MyExecutorBuilder::default())) + .with_add_ons::() .launch() .await .unwrap();