chore(rpc): expose ethapi in node builder for op customisation (#9444)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Emilia Hane
2024-07-16 15:53:03 +02:00
committed by GitHub
parent fcc6307ada
commit 2aa94e9aee
53 changed files with 1117 additions and 664 deletions

9
Cargo.lock generated
View File

@ -6837,6 +6837,7 @@ dependencies = [
"reth-db", "reth-db",
"reth-network-peers", "reth-network-peers",
"reth-node-builder", "reth-node-builder",
"reth-node-ethereum",
"reth-payload-builder", "reth-payload-builder",
"reth-primitives", "reth-primitives",
"reth-provider", "reth-provider",
@ -7581,6 +7582,7 @@ dependencies = [
"reth-rpc", "reth-rpc",
"reth-rpc-builder", "reth-rpc-builder",
"reth-rpc-engine-api", "reth-rpc-engine-api",
"reth-rpc-eth-types",
"reth-rpc-layer", "reth-rpc-layer",
"reth-rpc-types", "reth-rpc-types",
"reth-stages", "reth-stages",
@ -7683,6 +7685,7 @@ dependencies = [
"reth-node-core", "reth-node-core",
"reth-payload-builder", "reth-payload-builder",
"reth-provider", "reth-provider",
"reth-rpc",
"reth-tracing", "reth-tracing",
"reth-transaction-pool", "reth-transaction-pool",
"serde_json", "serde_json",
@ -7740,6 +7743,7 @@ dependencies = [
"reth-node-builder", "reth-node-builder",
"reth-optimism-consensus", "reth-optimism-consensus",
"reth-optimism-payload-builder", "reth-optimism-payload-builder",
"reth-optimism-rpc",
"reth-payload-builder", "reth-payload-builder",
"reth-primitives", "reth-primitives",
"reth-provider", "reth-provider",
@ -7749,6 +7753,7 @@ dependencies = [
"reth-rpc-eth-types", "reth-rpc-eth-types",
"reth-rpc-types", "reth-rpc-types",
"reth-rpc-types-compat", "reth-rpc-types-compat",
"reth-tasks",
"reth-tracing", "reth-tracing",
"reth-transaction-pool", "reth-transaction-pool",
"revm-primitives", "revm-primitives",
@ -7848,8 +7853,10 @@ dependencies = [
"reth-errors", "reth-errors",
"reth-evm", "reth-evm",
"reth-evm-optimism", "reth-evm-optimism",
"reth-node-api",
"reth-primitives", "reth-primitives",
"reth-provider", "reth-provider",
"reth-rpc",
"reth-rpc-eth-api", "reth-rpc-eth-api",
"reth-rpc-eth-types", "reth-rpc-eth-types",
"reth-rpc-server-types", "reth-rpc-server-types",
@ -8119,6 +8126,7 @@ dependencies = [
"reth-evm-optimism", "reth-evm-optimism",
"reth-network-api", "reth-network-api",
"reth-network-peers", "reth-network-peers",
"reth-node-api",
"reth-primitives", "reth-primitives",
"reth-provider", "reth-provider",
"reth-revm", "reth-revm",
@ -8195,6 +8203,7 @@ dependencies = [
"reth-metrics", "reth-metrics",
"reth-network-api", "reth-network-api",
"reth-network-peers", "reth-network-peers",
"reth-node-api",
"reth-node-core", "reth-node-core",
"reth-payload-builder", "reth-payload-builder",
"reth-primitives", "reth-primitives",

View File

@ -22,6 +22,7 @@ reth-node-builder = { workspace = true, features = ["test-utils"] }
reth-tokio-util.workspace = true reth-tokio-util.workspace = true
reth-stages-types.workspace = true reth-stages-types.workspace = true
reth-network-peers.workspace = true reth-network-peers.workspace = true
reth-node-ethereum.workspace = true
jsonrpsee.workspace = true jsonrpsee.workspace = true

View File

@ -1,16 +1,19 @@
use std::sync::Arc;
use node::NodeTestContext; use node::NodeTestContext;
use reth::{ use reth::{
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
builder::{NodeBuilder, NodeConfig, NodeHandle}, builder::{NodeBuilder, NodeConfig, NodeHandle},
rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer},
tasks::TaskManager, tasks::TaskManager,
}; };
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_db::{test_utils::TempDatabase, DatabaseEnv}; use reth_db::{test_utils::TempDatabase, DatabaseEnv};
use reth_node_builder::{ 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 reth_provider::providers::BlockchainProvider;
use std::sync::Arc;
use tracing::{span, Level}; use tracing::{span, Level};
use wallet::Wallet; use wallet::Wallet;
@ -42,9 +45,11 @@ pub async fn setup<N>(
num_nodes: usize, num_nodes: usize,
chain_spec: Arc<ChainSpec>, chain_spec: Arc<ChainSpec>,
is_dev: bool, is_dev: bool,
) -> eyre::Result<(Vec<NodeHelperType<N>>, TaskManager, Wallet)> ) -> eyre::Result<(Vec<NodeHelperType<N, N::AddOns>>, TaskManager, Wallet)>
where where
N: Default + Node<TmpNodeAdapter<N>>, N: Default + Node<TmpNodeAdapter<N>>,
<N::AddOns as NodeAddOns<Adapter<N>>>::EthApi:
FullEthApiServer + AddDevSigners + EthApiBuilderProvider<Adapter<N>>,
{ {
let tasks = TaskManager::current(); let tasks = TaskManager::current();
let exec = tasks.executor(); let exec = tasks.executor();
@ -55,7 +60,7 @@ where
}; };
// Create nodes and peer them // Create nodes and peer them
let mut nodes: Vec<NodeTestContext<_>> = Vec::with_capacity(num_nodes); let mut nodes: Vec<NodeTestContext<_, _>> = Vec::with_capacity(num_nodes);
for idx in 0..num_nodes { for idx in 0..num_nodes {
let node_config = NodeConfig::test() let node_config = NodeConfig::test()
@ -106,4 +111,4 @@ type Adapter<N> = NodeAdapter<
>; >;
/// Type alias for a type of NodeHelper /// Type alias for a type of NodeHelper
pub type NodeHelperType<N> = NodeTestContext<Adapter<N>>; pub type NodeHelperType<N, AO> = NodeTestContext<Adapter<N>, AO>;

View File

@ -1,7 +1,4 @@
use crate::{ use std::{marker::PhantomData, pin::Pin};
engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext,
rpc::RpcTestContext, traits::PayloadEnvelopeExt,
};
use alloy_rpc_types::BlockNumberOrTag; use alloy_rpc_types::BlockNumberOrTag;
use eyre::Ok; use eyre::Ok;
@ -11,32 +8,41 @@ use reth::{
builder::FullNode, builder::FullNode,
payload::PayloadTypes, payload::PayloadTypes,
providers::{BlockReader, BlockReaderIdExt, CanonStateSubscriptions, StageCheckpointReader}, 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_primitives::{BlockHash, BlockNumber, Bytes, B256};
use reth_stages_types::StageId; use reth_stages_types::StageId;
use std::{marker::PhantomData, pin::Pin};
use tokio_stream::StreamExt; use tokio_stream::StreamExt;
use crate::{
engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext,
rpc::RpcTestContext, traits::PayloadEnvelopeExt,
};
/// An helper struct to handle node actions /// An helper struct to handle node actions
pub struct NodeTestContext<Node> pub struct NodeTestContext<Node, AddOns>
where where
Node: FullNodeComponents, Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{ {
pub inner: FullNode<Node>, pub inner: FullNode<Node, AddOns>,
pub payload: PayloadTestContext<Node::Engine>, pub payload: PayloadTestContext<Node::Engine>,
pub network: NetworkTestContext, pub network: NetworkTestContext,
pub engine_api: EngineApiTestContext<Node::Engine>, pub engine_api: EngineApiTestContext<Node::Engine>,
pub rpc: RpcTestContext<Node>, pub rpc: RpcTestContext<Node, AddOns::EthApi>,
} }
impl<Node> NodeTestContext<Node> impl<Node, AddOns> NodeTestContext<Node, AddOns>
where where
Node: FullNodeComponents, Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{ {
/// Creates a new test node /// Creates a new test node
pub async fn new(node: FullNode<Node>) -> eyre::Result<Self> { pub async fn new(node: FullNode<Node, AddOns>) -> eyre::Result<Self> {
let builder = node.payload_builder.clone(); let builder = node.payload_builder.clone();
Ok(Self { Ok(Self {
@ -53,7 +59,7 @@ where
} }
/// Establish a connection to the node /// Establish a connection to the node
pub async fn connect(&mut self, node: &mut NodeTestContext<Node>) { pub async fn connect(&mut self, node: &mut NodeTestContext<Node, AddOns>) {
self.network.add_peer(node.network.record()).await; self.network.add_peer(node.network.record()).await;
node.network.next_session_established().await; node.network.next_session_established().await;
self.network.next_session_established().await; self.network.next_session_established().await;
@ -77,6 +83,7 @@ where
where where
<Node::Engine as EngineTypes>::ExecutionPayloadV3: <Node::Engine as EngineTypes>::ExecutionPayloadV3:
From<<Node::Engine as PayloadTypes>::BuiltPayload> + PayloadEnvelopeExt, From<<Node::Engine as PayloadTypes>::BuiltPayload> + PayloadEnvelopeExt,
AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt,
{ {
let mut chain = Vec::with_capacity(length as usize); let mut chain = Vec::with_capacity(length as usize);
for i in 0..length { for i in 0..length {

View File

@ -3,17 +3,23 @@ use alloy_network::eip2718::Decodable2718;
use reth::{ use reth::{
builder::{rpc::RpcRegistry, FullNodeComponents}, builder::{rpc::RpcRegistry, FullNodeComponents},
rpc::{ rpc::{
api::{eth::helpers::EthTransactions, DebugApiServer}, api::{
eth::helpers::{EthApiSpec, EthTransactions, TraceExt},
DebugApiServer,
},
server_types::eth::EthResult, server_types::eth::EthResult,
}, },
}; };
use reth_primitives::{Bytes, B256}; use reth_primitives::{Bytes, B256};
pub struct RpcTestContext<Node: FullNodeComponents> { pub struct RpcTestContext<Node: FullNodeComponents, EthApi> {
pub inner: RpcRegistry<Node>, pub inner: RpcRegistry<Node, EthApi>,
} }
impl<Node: FullNodeComponents> RpcTestContext<Node> { impl<Node: FullNodeComponents, EthApi> RpcTestContext<Node, EthApi>
where
EthApi: EthApiSpec + EthTransactions + TraceExt,
{
/// Injects a raw transaction into the node tx pool via RPC server /// Injects a raw transaction into the node tx pool via RPC server
pub async fn inject_tx(&mut self, raw_tx: Bytes) -> EthResult<B256> { pub async fn inject_tx(&mut self, raw_tx: Bytes) -> EthResult<B256> {
let eth_api = self.inner.eth_api(); let eth_api = self.inner.eth_api();

View File

@ -25,6 +25,8 @@ reth-evm-ethereum.workspace = true
reth-consensus.workspace = true reth-consensus.workspace = true
reth-auto-seal-consensus.workspace = true reth-auto-seal-consensus.workspace = true
reth-beacon-consensus.workspace = true reth-beacon-consensus.workspace = true
reth-rpc.workspace = true
reth-node-api.workspace = true
# misc # misc
eyre.workspace = true eyre.workspace = true

View File

@ -1,6 +1,7 @@
//! Ethereum Node types config. //! Ethereum Node types config.
use crate::{EthEngineTypes, EthEvmConfig}; use std::sync::Arc;
use reth_auto_seal_consensus::AutoSealConsensus; use reth_auto_seal_consensus::AutoSealConsensus;
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
use reth_beacon_consensus::EthBeaconConsensus; use reth_beacon_consensus::EthBeaconConsensus;
@ -9,6 +10,7 @@ use reth_ethereum_engine_primitives::{
}; };
use reth_evm_ethereum::execute::EthExecutorProvider; use reth_evm_ethereum::execute::EthExecutorProvider;
use reth_network::NetworkHandle; use reth_network::NetworkHandle;
use reth_node_api::{FullNodeComponents, NodeAddOns};
use reth_node_builder::{ use reth_node_builder::{
components::{ components::{
ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder,
@ -19,12 +21,14 @@ use reth_node_builder::{
}; };
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_provider::CanonStateSubscriptions; use reth_provider::CanonStateSubscriptions;
use reth_rpc::EthApi;
use reth_tracing::tracing::{debug, info}; use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{ use reth_transaction_pool::{
blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool, blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool,
TransactionValidationTaskExecutor, TransactionValidationTaskExecutor,
}; };
use std::sync::Arc;
use crate::{EthEngineTypes, EthEvmConfig};
/// Type configuration for a regular Ethereum node. /// Type configuration for a regular Ethereum node.
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
@ -64,6 +68,14 @@ impl NodeTypes for EthereumNode {
type Engine = EthEngineTypes; type Engine = EthEngineTypes;
} }
/// Add-ons w.r.t. l1 ethereum.
#[derive(Debug, Clone)]
pub struct EthereumAddOns;
impl<N: FullNodeComponents> NodeAddOns<N> for EthereumAddOns {
type EthApi = EthApi<N::Provider, N::Pool, NetworkHandle, N::Evm>;
}
impl<N> Node<N> for EthereumNode impl<N> Node<N> for EthereumNode
where where
N: FullNodeTypes<Engine = EthEngineTypes>, N: FullNodeTypes<Engine = EthEngineTypes>,
@ -77,7 +89,9 @@ where
EthereumConsensusBuilder, EthereumConsensusBuilder,
>; >;
fn components_builder(self) -> Self::ComponentsBuilder { type AddOns = EthereumAddOns;
fn components_builder(&self) -> Self::ComponentsBuilder {
Self::components() Self::components()
} }
} }

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use alloy_genesis::Genesis; use alloy_genesis::Genesis;
use alloy_primitives::{b256, hex}; use alloy_primitives::{b256, hex};
use futures::StreamExt; use futures::StreamExt;
use reth::rpc::api::eth::helpers::EthTransactions; use reth::core::rpc::eth::helpers::EthTransactions;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_e2e_test_utils::setup; use reth_e2e_test_utils::setup;
use reth_provider::CanonStateSubscriptions; use reth_provider::CanonStateSubscriptions;

View File

@ -1,11 +1,11 @@
use alloy_primitives::{Address, B256}; use alloy_primitives::{Address, B256};
use reth::rpc::types::engine::PayloadAttributes; use reth::rpc::types::engine::PayloadAttributes;
use reth_e2e_test_utils::NodeHelperType; use reth_e2e_test_utils::NodeHelperType;
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::{node::EthereumAddOns, EthereumNode};
use reth_payload_builder::EthPayloadBuilderAttributes; use reth_payload_builder::EthPayloadBuilderAttributes;
/// Ethereum Node Helper type /// Ethereum Node Helper type
pub(crate) type EthNode = NodeHelperType<EthereumNode>; pub(crate) type EthNode = NodeHelperType<EthereumNode, EthereumAddOns>;
/// Helper function to create a new eth payload attributes /// Helper function to create a new eth payload attributes
pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes { pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes {

View File

@ -1,9 +1,8 @@
//! Node builder setup tests. //! Node builder setup tests.
use reth_db::test_utils::create_test_rw_db; use reth_db::test_utils::create_test_rw_db;
use reth_node_api::FullNodeComponents; use reth_node_builder::{FullNodeComponents, NodeBuilder, NodeConfig};
use reth_node_builder::{NodeBuilder, NodeConfig}; use reth_node_ethereum::node::{EthereumAddOns, EthereumNode};
use reth_node_ethereum::node::EthereumNode;
#[test] #[test]
fn test_basic_setup() { fn test_basic_setup() {
@ -15,6 +14,7 @@ fn test_basic_setup() {
.with_database(db) .with_database(db)
.with_types::<EthereumNode>() .with_types::<EthereumNode>()
.with_components(EthereumNode::components()) .with_components(EthereumNode::components())
.with_add_ons::<EthereumAddOns>()
.on_component_initialized(move |ctx| { .on_component_initialized(move |ctx| {
let _provider = ctx.provider(); let _provider = ctx.provider();
println!("{msg}"); println!("{msg}");

View File

@ -3,7 +3,7 @@ use reth_db::test_utils::create_test_rw_db;
use reth_exex::ExExContext; use reth_exex::ExExContext;
use reth_node_api::FullNodeComponents; use reth_node_api::FullNodeComponents;
use reth_node_builder::{NodeBuilder, NodeConfig}; use reth_node_builder::{NodeBuilder, NodeConfig};
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::{node::EthereumAddOns, EthereumNode};
use std::{ use std::{
future::Future, future::Future,
pin::Pin, pin::Pin,
@ -33,6 +33,7 @@ fn basic_exex() {
.with_database(db) .with_database(db)
.with_types::<EthereumNode>() .with_types::<EthereumNode>()
.with_components(EthereumNode::components()) .with_components(EthereumNode::components())
.with_add_ons::<EthereumAddOns>()
.install_exex("dummy", move |ctx| future::ok(DummyExEx { _ctx: ctx })) .install_exex("dummy", move |ctx| future::ok(DummyExEx { _ctx: ctx }))
.check_launch(); .check_launch();
} }

View File

@ -28,7 +28,7 @@ use reth_node_builder::{
}; };
use reth_node_core::node_config::NodeConfig; use reth_node_core::node_config::NodeConfig;
use reth_node_ethereum::{ use reth_node_ethereum::{
node::{EthereumNetworkBuilder, EthereumPayloadBuilder}, node::{EthereumAddOns, EthereumNetworkBuilder, EthereumPayloadBuilder},
EthEngineTypes, EthEvmConfig, EthEngineTypes, EthEvmConfig,
}; };
use reth_payload_builder::noop::NoopPayloadBuilderService; use reth_payload_builder::noop::NoopPayloadBuilderService;
@ -125,8 +125,9 @@ where
TestExecutorBuilder, TestExecutorBuilder,
TestConsensusBuilder, TestConsensusBuilder,
>; >;
type AddOns = EthereumAddOns;
fn components_builder(self) -> Self::ComponentsBuilder { fn components_builder(&self) -> Self::ComponentsBuilder {
ComponentsBuilder::default() ComponentsBuilder::default()
.node_types::<N>() .node_types::<N>()
.pool(TestPoolBuilder::default()) .pool(TestPoolBuilder::default())

View File

@ -1,6 +1,7 @@
//! Traits for configuring a node. //! Traits for configuring a node.
use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes}; use std::marker::PhantomData;
use reth_db_api::{ use reth_db_api::{
database::Database, database::Database,
database_metrics::{DatabaseMetadata, DatabaseMetrics}, database_metrics::{DatabaseMetadata, DatabaseMetrics},
@ -11,7 +12,8 @@ use reth_payload_builder::PayloadBuilderHandle;
use reth_provider::FullProvider; use reth_provider::FullProvider;
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use reth_transaction_pool::TransactionPool; 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. /// 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. /// Returns the task executor.
fn task_executor(&self) -> &TaskExecutor; fn task_executor(&self) -> &TaskExecutor;
} }
/// Customizable node add-on types.
pub trait NodeAddOns<N: FullNodeComponents>: 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<N: FullNodeComponents> NodeAddOns<N> for () {
type EthApi = ();
}
/// Returns the builder for type.
pub trait BuilderProvider<N: FullNodeComponents>: Send {
/// Context required to build type.
type Ctx<'a>;
/// Returns builder for type.
#[allow(clippy::type_complexity)]
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send>;
}
impl<N: FullNodeComponents> BuilderProvider<N> for () {
type Ctx<'a> = ();
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send> {
Box::new(noop_builder)
}
}
const fn noop_builder(_: ()) {}

View File

@ -47,6 +47,7 @@ reth-consensus-debug-client.workspace = true
reth-rpc-types.workspace = true reth-rpc-types.workspace = true
reth-engine-util.workspace = true reth-engine-util.workspace = true
reth-cli-util.workspace = true reth-cli-util.workspace = true
reth-rpc-eth-types.workspace = true
## async ## async
futures.workspace = true futures.workspace = true

View File

@ -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<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
/// Additional `NodeHooks` that are called at specific points in the node's launch lifecycle.
pub hooks: NodeHooks<Node, AddOns>,
/// The `ExExs` (execution extensions) of the node.
pub exexs: Vec<(String, Box<dyn BoxedLaunchExEx<Node>>)>,
/// Additional RPC add-ons.
pub rpc: RpcAddOns<Node, AddOns::EthApi>,
}
/// 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<Node: FullNodeComponents, EthApi> {
/// Core `eth` API type to install on the RPC server, configured w.r.t. network.
pub _eth_api: PhantomData<EthApi>,
/// Additional RPC hooks.
pub hooks: RpcHooks<Node, EthApi>,
}

View File

@ -2,13 +2,13 @@
#![allow(clippy::type_complexity, missing_debug_implementations)] #![allow(clippy::type_complexity, missing_debug_implementations)]
use crate::{ pub mod add_ons;
common::WithConfigs, mod states;
components::NodeComponentsBuilder,
node::FullNode, pub use states::*;
rpc::{RethRpcServerHandles, RpcContext},
DefaultNodeLauncher, Node, NodeHandle, use std::sync::Arc;
};
use futures::Future; use futures::Future;
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_cli_util::get_secret_key; use reth_cli_util::get_secret_key;
@ -20,23 +20,28 @@ use reth_exex::ExExContext;
use reth_network::{ use reth_network::{
NetworkBuilder, NetworkConfig, NetworkConfigBuilder, NetworkHandle, NetworkManager, NetworkBuilder, NetworkConfig, NetworkConfigBuilder, NetworkHandle, NetworkManager,
}; };
use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeTypes}; use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes};
use reth_node_core::{ use reth_node_core::{
cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig}, cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig},
dirs::{ChainPath, DataDirPath}, dirs::{ChainPath, DataDirPath},
node_config::NodeConfig, node_config::NodeConfig,
primitives::Head, primitives::Head,
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
}; };
use reth_primitives::revm_primitives::EnvKzgSettings; use reth_primitives::revm_primitives::EnvKzgSettings;
use reth_provider::{providers::BlockchainProvider, ChainSpecProvider}; use reth_provider::{providers::BlockchainProvider, ChainSpecProvider};
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use reth_transaction_pool::{PoolConfig, TransactionPool}; use reth_transaction_pool::{PoolConfig, TransactionPool};
use secp256k1::SecretKey; use secp256k1::SecretKey;
pub use states::*;
use std::sync::Arc;
use tracing::{info, trace, warn}; 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 /// 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. // Note: we need to hardcode this because custom components might depend on it in associated types.
@ -212,11 +217,11 @@ where
pub fn node<N>( pub fn node<N>(
self, self,
node: N, node: N,
) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder> ) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>
where where
N: Node<RethFullAdapter<DB, N>>, N: Node<RethFullAdapter<DB, N>>,
{ {
self.with_types().with_components(node.components_builder()) self.with_types().with_components(node.components_builder()).with_add_ons::<N::AddOns>()
} }
} }
@ -259,11 +264,13 @@ where
pub fn node<N>( pub fn node<N>(
self, self,
node: N, node: N,
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder>> ) -> WithLaunchContext<
NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
>
where where
N: Node<RethFullAdapter<DB, N>>, N: Node<RethFullAdapter<DB, N>>,
{ {
self.with_types().with_components(node.components_builder()) self.with_types().with_components(node.components_builder()).with_add_ons::<N::AddOns>()
} }
/// Launches a preconfigured [Node] /// Launches a preconfigured [Node]
@ -280,10 +287,22 @@ where
RethFullAdapter<DB, N>, RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components, <N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>, >,
N::AddOns,
>, >,
> >
where where
N: Node<RethFullAdapter<DB, N>>, N: Node<RethFullAdapter<DB, N>>,
<N::AddOns as NodeAddOns<
NodeAdapter<
RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>,
>>::EthApi: EthApiBuilderProvider<
NodeAdapter<
RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>,
> + FullEthApiServer + AddDevSigners,
{ {
self.node(node).launch().await self.node(node).launch().await
} }
@ -298,7 +317,7 @@ where
pub fn with_components<CB>( pub fn with_components<CB>(
self, self,
components_builder: CB, components_builder: CB,
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB>> ) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, ()>>
where where
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>, CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
{ {
@ -309,11 +328,35 @@ where
} }
} }
impl<T, DB, CB> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB>> impl<T, DB, CB> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, ()>>
where where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypes, T: NodeTypes,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>, CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
{
/// Advances the state of the node builder to the next state where all customizable
/// [`NodeAddOns`] types are configured.
pub fn with_add_ons<AO>(
self,
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, AO>>
where
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
AO: NodeAddOns<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
{
WithLaunchContext {
builder: self.builder.with_add_ons::<AO>(),
task_executor: self.task_executor,
}
}
}
impl<T, DB, CB, AO> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, AO>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypes,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
AO: NodeAddOns<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
AO::EthApi: FullEthApiServer + AddDevSigners,
{ {
/// Sets the hook that is run once the node's components are initialized. /// Sets the hook that is run once the node's components are initialized.
pub fn on_component_initialized<F>(self, hook: F) -> Self pub fn on_component_initialized<F>(self, hook: F) -> Self
@ -332,7 +375,7 @@ where
pub fn on_node_started<F>(self, hook: F) -> Self pub fn on_node_started<F>(self, hook: F) -> Self
where where
F: FnOnce( F: FnOnce(
FullNode<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>, FullNode<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO>,
) -> eyre::Result<()> ) -> eyre::Result<()>
+ Send + Send
+ 'static, + 'static,
@ -344,7 +387,7 @@ where
pub fn on_rpc_started<F>(self, hook: F) -> Self pub fn on_rpc_started<F>(self, hook: F) -> Self
where where
F: FnOnce( F: FnOnce(
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>, RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO::EthApi>,
RethRpcServerHandles, RethRpcServerHandles,
) -> eyre::Result<()> ) -> eyre::Result<()>
+ Send + Send
@ -357,7 +400,7 @@ where
pub fn extend_rpc_modules<F>(self, hook: F) -> Self pub fn extend_rpc_modules<F>(self, hook: F) -> Self
where where
F: FnOnce( F: FnOnce(
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>, RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO::EthApi>,
) -> eyre::Result<()> ) -> eyre::Result<()>
+ Send + Send
+ 'static, + 'static,
@ -384,16 +427,6 @@ where
} }
} }
/// Launches the node and returns a handle to it.
pub async fn launch(
self,
) -> eyre::Result<NodeHandle<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>> {
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 /// Check that the builder can be launched
/// ///
/// This is useful when writing tests to ensure that the builder is configured correctly. /// This is useful when writing tests to ensure that the builder is configured correctly.
@ -402,6 +435,27 @@ where
} }
} }
impl<T, DB, CB, AO> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, AO>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypes,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
AO: NodeAddOns<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
AO::EthApi: EthApiBuilderProvider<NodeAdapter<RethFullAdapter<DB, T>, 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<NodeHandle<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO>> {
let Self { builder, task_executor } = self;
let launcher = DefaultNodeLauncher::new(task_executor, builder.config.datadir());
builder.launch_with(launcher).await
}
}
/// Captures the necessary context for building the components of the node. /// Captures the necessary context for building the components of the node.
pub struct BuilderContext<Node: FullNodeTypes> { pub struct BuilderContext<Node: FullNodeTypes> {
/// The current head of the blockchain at launch. /// The current head of the blockchain at launch.

View File

@ -5,21 +5,25 @@
//! The node builder process is essentially a state machine that transitions through various states //! The node builder process is essentially a state machine that transitions through various states
//! before the node can be launched. //! before the node can be launched.
use crate::{ use std::{fmt, future::Future, marker::PhantomData};
components::{NodeComponents, NodeComponentsBuilder},
exex::BoxedLaunchExEx,
hooks::NodeHooks,
launch::LaunchNode,
rpc::{RethRpcServerHandles, RpcContext, RpcHooks},
FullNode,
};
use reth_exex::ExExContext; use reth_exex::ExExContext;
use reth_network::NetworkHandle; use reth_network::NetworkHandle;
use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes}; use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypes};
use reth_node_core::node_config::NodeConfig; use reth_node_core::{
node_config::NodeConfig,
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
};
use reth_payload_builder::PayloadBuilderHandle; use reth_payload_builder::PayloadBuilderHandle;
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use std::{fmt, future::Future};
use crate::{
components::{NodeComponents, NodeComponentsBuilder},
hooks::NodeHooks,
launch::LaunchNode,
rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext, RpcHooks},
AddOns, FullNode, RpcAddOns,
};
/// A node builder that also has the configured types. /// A node builder that also has the configured types.
pub struct NodeBuilderWithTypes<T: FullNodeTypes> { pub struct NodeBuilderWithTypes<T: FullNodeTypes> {
@ -36,7 +40,7 @@ impl<T: FullNodeTypes> NodeBuilderWithTypes<T> {
} }
/// Advances the state of the node builder to the next state where all components are configured /// Advances the state of the node builder to the next state where all components are configured
pub fn with_components<CB>(self, components_builder: CB) -> NodeBuilderWithComponents<T, CB> pub fn with_components<CB>(self, components_builder: CB) -> NodeBuilderWithComponents<T, CB, ()>
where where
CB: NodeComponentsBuilder<T>, CB: NodeComponentsBuilder<T>,
{ {
@ -46,9 +50,9 @@ impl<T: FullNodeTypes> NodeBuilderWithTypes<T> {
config, config,
adapter, adapter,
components_builder, components_builder,
add_ons: NodeAddOns { add_ons: AddOns {
hooks: NodeHooks::default(), hooks: NodeHooks::default(),
rpc: RpcHooks::new(), rpc: RpcAddOns { _eth_api: PhantomData::<()>, hooks: RpcHooks::default() },
exexs: Vec::new(), exexs: Vec::new(),
}, },
} }
@ -142,7 +146,11 @@ impl<T: FullNodeTypes, C: NodeComponents<T>> Clone for NodeAdapter<T, C> {
/// A fully type configured node builder. /// A fully type configured node builder.
/// ///
/// Supports adding additional addons to the node. /// Supports adding additional addons to the node.
pub struct NodeBuilderWithComponents<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> { pub struct NodeBuilderWithComponents<
T: FullNodeTypes,
CB: NodeComponentsBuilder<T>,
AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
> {
/// All settings for how the node should be configured. /// All settings for how the node should be configured.
pub(crate) config: NodeConfig, pub(crate) config: NodeConfig,
/// Adapter for the underlying node types and database /// Adapter for the underlying node types and database
@ -150,10 +158,41 @@ pub struct NodeBuilderWithComponents<T: FullNodeTypes, CB: NodeComponentsBuilder
/// container for type specific components /// container for type specific components
pub(crate) components_builder: CB, pub(crate) components_builder: CB,
/// Additional node extensions. /// Additional node extensions.
pub(crate) add_ons: NodeAddOns<NodeAdapter<T, CB::Components>>, pub(crate) add_ons: AddOns<NodeAdapter<T, CB::Components>, AO>,
} }
impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T, CB> { impl<T, CB> NodeBuilderWithComponents<T, CB, ()>
where
T: FullNodeTypes,
CB: NodeComponentsBuilder<T>,
{
/// Advances the state of the node builder to the next state where all customizable
/// [`NodeAddOns`] types are configured.
pub fn with_add_ons<AO>(self) -> NodeBuilderWithComponents<T, CB, AO>
where
AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
{
let Self { config, adapter, components_builder, .. } = self;
NodeBuilderWithComponents {
config,
adapter,
components_builder,
add_ons: AddOns {
hooks: NodeHooks::default(),
rpc: RpcAddOns { _eth_api: PhantomData::<AO::EthApi>, hooks: RpcHooks::default() },
exexs: Vec::new(),
},
}
}
}
impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
where
T: FullNodeTypes,
CB: NodeComponentsBuilder<T>,
AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
{
/// Sets the hook that is run once the node's components are initialized. /// Sets the hook that is run once the node's components are initialized.
pub fn on_component_initialized<F>(mut self, hook: F) -> Self pub fn on_component_initialized<F>(mut self, hook: F) -> Self
where where
@ -166,7 +205,9 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
/// Sets the hook that is run once the node has started. /// Sets the hook that is run once the node has started.
pub fn on_node_started<F>(mut self, hook: F) -> Self pub fn on_node_started<F>(mut self, hook: F) -> Self
where where
F: FnOnce(FullNode<NodeAdapter<T, CB::Components>>) -> eyre::Result<()> + Send + 'static, F: FnOnce(FullNode<NodeAdapter<T, CB::Components>, AO>) -> eyre::Result<()>
+ Send
+ 'static,
{ {
self.add_ons.hooks.set_on_node_started(hook); self.add_ons.hooks.set_on_node_started(hook);
self self
@ -176,24 +217,24 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
pub fn on_rpc_started<F>(mut self, hook: F) -> Self pub fn on_rpc_started<F>(mut self, hook: F) -> Self
where where
F: FnOnce( F: FnOnce(
RpcContext<'_, NodeAdapter<T, CB::Components>>, RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
RethRpcServerHandles, RethRpcServerHandles,
) -> eyre::Result<()> ) -> eyre::Result<()>
+ Send + Send
+ 'static, + 'static,
{ {
self.add_ons.rpc.set_on_rpc_started(hook); self.add_ons.rpc.hooks.set_on_rpc_started(hook);
self self
} }
/// Sets the hook that is run to configure the rpc modules. /// Sets the hook that is run to configure the rpc modules.
pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
where where
F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>>) -> eyre::Result<()> F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
+ Send + Send
+ 'static, + 'static,
{ {
self.add_ons.rpc.set_extend_rpc_modules(hook); self.add_ons.rpc.hooks.set_extend_rpc_modules(hook);
self self
} }
@ -212,14 +253,6 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
self self
} }
/// Launches the node with the given launcher.
pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
where
L: LaunchNode<Self>,
{
launcher.launch_node(self).await
}
/// Launches the node with the given closure. /// Launches the node with the given closure.
pub fn launch_with_fn<L, R>(self, launcher: L) -> R pub fn launch_with_fn<L, R>(self, launcher: L) -> R
where where
@ -236,12 +269,19 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
} }
} }
/// Additional node extensions. impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
pub(crate) struct NodeAddOns<Node: FullNodeComponents> { where
/// Additional `NodeHooks` that are called at specific points in the node's launch lifecycle. T: FullNodeTypes,
pub(crate) hooks: NodeHooks<Node>, CB: NodeComponentsBuilder<T>,
/// Additional RPC hooks. AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
pub(crate) rpc: RpcHooks<Node>, AO::EthApi:
/// The `ExExs` (execution extensions) of the node. EthApiBuilderProvider<NodeAdapter<T, CB::Components>> + FullEthApiServer + AddDevSigners,
pub(crate) exexs: Vec<(String, Box<dyn BoxedLaunchExEx<Node>>)>, {
/// Launches the node with the given launcher.
pub async fn launch_with<L>(self, launcher: L) -> eyre::Result<L::Node>
where
L: LaunchNode<Self>,
{
launcher.launch_node(self).await
}
} }

View File

@ -1,5 +1,11 @@
//! A generic [`NodeComponentsBuilder`] //! 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::{ use crate::{
components::{ components::{
Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents, Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents,
@ -7,10 +13,6 @@ use crate::{
}, },
BuilderContext, ConfigureEvm, FullNodeTypes, 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. /// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation.
/// ///

View File

@ -1,25 +1,35 @@
use crate::node::FullNode;
use reth_node_api::FullNodeComponents;
use reth_node_core::exit::NodeExitFuture;
use std::fmt; 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. /// A Handle to the launched node.
#[must_use = "Needs to await the node exit future"] #[must_use = "Needs to await the node exit future"]
pub struct NodeHandle<Node: FullNodeComponents> { pub struct NodeHandle<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
/// All node components. /// All node components.
pub node: FullNode<Node>, pub node: FullNode<Node, AddOns>,
/// The exit future of the node. /// The exit future of the node.
pub node_exit_future: NodeExitFuture, pub node_exit_future: NodeExitFuture,
} }
impl<Node: FullNodeComponents> NodeHandle<Node> { impl<Node, AddOns> NodeHandle<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
/// Waits for the node to exit, if it was configured to exit. /// Waits for the node to exit, if it was configured to exit.
pub async fn wait_for_node_exit(self) -> eyre::Result<()> { pub async fn wait_for_node_exit(self) -> eyre::Result<()> {
self.node_exit_future.await self.node_exit_future.await
} }
} }
impl<Node: FullNodeComponents> fmt::Debug for NodeHandle<Node> { impl<Node, AddOns> fmt::Debug for NodeHandle<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NodeHandle") f.debug_struct("NodeHandle")
.field("node", &"...") .field("node", &"...")

View File

@ -1,17 +1,25 @@
use crate::node::FullNode;
use reth_node_api::FullNodeComponents;
use std::fmt; use std::fmt;
use reth_node_api::{FullNodeComponents, NodeAddOns};
use crate::node::FullNode;
/// Container for all the configurable hook functions. /// Container for all the configurable hook functions.
pub(crate) struct NodeHooks<Node: FullNodeComponents> { pub struct NodeHooks<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
pub(crate) on_component_initialized: Box<dyn OnComponentInitializedHook<Node>>, /// Hook to run once core components are initialized.
pub(crate) on_node_started: Box<dyn OnNodeStartedHook<Node>>, pub on_component_initialized: Box<dyn OnComponentInitializedHook<Node>>,
pub(crate) _marker: std::marker::PhantomData<Node>, /// Hook to run once the node is started.
pub on_node_started: Box<dyn OnNodeStartedHook<Node, AddOns>>,
_marker: std::marker::PhantomData<Node>,
} }
impl<Node: FullNodeComponents> NodeHooks<Node> { impl<Node, AddOns> NodeHooks<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
/// Creates a new, empty [`NodeHooks`] instance for the given node type. /// Creates a new, empty [`NodeHooks`] instance for the given node type.
pub(crate) fn new() -> Self { pub fn new() -> Self {
Self { Self {
on_component_initialized: Box::<()>::default(), on_component_initialized: Box::<()>::default(),
on_node_started: Box::<()>::default(), on_node_started: Box::<()>::default(),
@ -41,7 +49,7 @@ impl<Node: FullNodeComponents> NodeHooks<Node> {
/// Sets the hook that is run once the node has started. /// Sets the hook that is run once the node has started.
pub(crate) fn set_on_node_started<F>(&mut self, hook: F) -> &mut Self pub(crate) fn set_on_node_started<F>(&mut self, hook: F) -> &mut Self
where where
F: OnNodeStartedHook<Node> + 'static, F: OnNodeStartedHook<Node, AddOns> + 'static,
{ {
self.on_node_started = Box::new(hook); self.on_node_started = Box::new(hook);
self self
@ -51,19 +59,27 @@ impl<Node: FullNodeComponents> NodeHooks<Node> {
#[allow(unused)] #[allow(unused)]
pub(crate) fn on_node_started<F>(mut self, hook: F) -> Self pub(crate) fn on_node_started<F>(mut self, hook: F) -> Self
where where
F: OnNodeStartedHook<Node> + 'static, F: OnNodeStartedHook<Node, AddOns> + 'static,
{ {
self.set_on_node_started(hook); self.set_on_node_started(hook);
self self
} }
} }
impl<Node: FullNodeComponents> Default for NodeHooks<Node> { impl<Node, AddOns> Default for NodeHooks<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl<Node: FullNodeComponents> fmt::Debug for NodeHooks<Node> { impl<Node, AddOns> fmt::Debug for NodeHooks<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NodeHooks") f.debug_struct("NodeHooks")
.field("on_component_initialized", &"...") .field("on_component_initialized", &"...")
@ -90,19 +106,20 @@ where
} }
/// A helper trait that is run once the node is started. /// A helper trait that is run once the node is started.
pub trait OnNodeStartedHook<Node: FullNodeComponents>: Send { pub trait OnNodeStartedHook<Node: FullNodeComponents, AddOns: NodeAddOns<Node>>: Send {
/// Consumes the event hook and runs it. /// Consumes the event hook and runs it.
/// ///
/// If this returns an error, the node launch will be aborted. /// If this returns an error, the node launch will be aborted.
fn on_event(self: Box<Self>, node: FullNode<Node>) -> eyre::Result<()>; fn on_event(self: Box<Self>, node: FullNode<Node, AddOns>) -> eyre::Result<()>;
} }
impl<Node, F> OnNodeStartedHook<Node> for F impl<Node, AddOns, F> OnNodeStartedHook<Node, AddOns> for F
where where
Node: FullNodeComponents, Node: FullNodeComponents,
F: FnOnce(FullNode<Node>) -> eyre::Result<()> + Send, AddOns: NodeAddOns<Node>,
F: FnOnce(FullNode<Node, AddOns>) -> eyre::Result<()> + Send,
{ {
fn on_event(self: Box<Self>, node: FullNode<Node>) -> eyre::Result<()> { fn on_event(self: Box<Self>, node: FullNode<Node, AddOns>) -> eyre::Result<()> {
(*self)(node) (*self)(node)
} }
} }
@ -113,8 +130,12 @@ impl<Node> OnComponentInitializedHook<Node> for () {
} }
} }
impl<Node: FullNodeComponents> OnNodeStartedHook<Node> for () { impl<Node, AddOns> OnNodeStartedHook<Node, AddOns> for ()
fn on_event(self: Box<Self>, _node: FullNode<Node>) -> eyre::Result<()> { where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
fn on_event(self: Box<Self>, _node: FullNode<Node, AddOns>) -> eyre::Result<()> {
Ok(()) Ok(())
} }
} }

View File

@ -1,12 +1,13 @@
//! Abstraction for launching a node. //! Abstraction for launching a node.
use crate::{ pub mod common;
builder::{NodeAdapter, NodeAddOns, NodeTypesAdapter}, mod exex;
components::{NodeComponents, NodeComponentsBuilder},
hooks::NodeHooks, pub use common::LaunchContext;
node::FullNode, pub use exex::ExExLauncher;
NodeBuilderWithComponents, NodeHandle,
}; use std::{future::Future, sync::Arc};
use futures::{future::Either, stream, stream_select, StreamExt}; use futures::{future::Either, stream, stream_select, StreamExt};
use reth_beacon_consensus::{ use reth_beacon_consensus::{
hooks::{EngineHooks, PruneHook, StaticFileHook}, hooks::{EngineHooks, PruneHook, StaticFileHook},
@ -15,11 +16,12 @@ use reth_beacon_consensus::{
use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider}; use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider};
use reth_engine_util::EngineMessageStreamExt; use reth_engine_util::EngineMessageStreamExt;
use reth_exex::ExExManagerHandle; use reth_exex::ExExManagerHandle;
use reth_network::NetworkEvents; use reth_network::{NetworkEvents, NetworkHandle};
use reth_node_api::FullNodeTypes; use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns};
use reth_node_core::{ use reth_node_core::{
dirs::{ChainPath, DataDirPath}, dirs::{ChainPath, DataDirPath},
exit::NodeExitFuture, exit::NodeExitFuture,
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA},
}; };
use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; use reth_node_events::{cl::ConsensusLayerHealthEvents, node};
@ -30,18 +32,32 @@ use reth_rpc_types::engine::ClientVersionV1;
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info}; use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::TransactionPool; use reth_transaction_pool::TransactionPool;
use std::{future::Future, sync::Arc};
use tokio::sync::{mpsc::unbounded_channel, oneshot}; use tokio::sync::{mpsc::unbounded_channel, oneshot};
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
pub mod common; use crate::{
pub use common::LaunchContext; builder::{NodeAdapter, NodeTypesAdapter},
mod exex; components::{NodeComponents, NodeComponentsBuilder},
pub use exex::ExExLauncher; hooks::NodeHooks,
node::FullNode,
rpc::EthApiBuilderProvider,
AddOns, NodeBuilderWithComponents, NodeHandle,
};
/// Alias for [`reth_rpc_eth_types::EthApiBuilderCtx`], adapter for [`FullNodeComponents`].
pub type EthApiBuilderCtx<N> = reth_rpc_eth_types::EthApiBuilderCtx<
<N as FullNodeTypes>::Provider,
<N as FullNodeComponents>::Pool,
<N as FullNodeComponents>::Evm,
NetworkHandle,
TaskExecutor,
<N as FullNodeTypes>::Provider,
>;
/// A general purpose trait that launches a new node of any kind. /// 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. /// This is essentially the launch logic for a node.
/// ///
@ -80,22 +96,25 @@ impl DefaultNodeLauncher {
} }
} }
impl<T, CB> LaunchNode<NodeBuilderWithComponents<T, CB>> for DefaultNodeLauncher impl<T, CB, AO> LaunchNode<NodeBuilderWithComponents<T, CB, AO>> for DefaultNodeLauncher
where where
T: FullNodeTypes<Provider = BlockchainProvider<<T as FullNodeTypes>::DB>>, T: FullNodeTypes<Provider = BlockchainProvider<<T as FullNodeTypes>::DB>>,
CB: NodeComponentsBuilder<T>, CB: NodeComponentsBuilder<T>,
AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
AO::EthApi:
EthApiBuilderProvider<NodeAdapter<T, CB::Components>> + FullEthApiServer + AddDevSigners,
{ {
type Node = NodeHandle<NodeAdapter<T, CB::Components>>; type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;
async fn launch_node( async fn launch_node(
self, self,
target: NodeBuilderWithComponents<T, CB>, target: NodeBuilderWithComponents<T, CB, AO>,
) -> eyre::Result<Self::Node> { ) -> eyre::Result<Self::Node> {
let Self { ctx } = self; let Self { ctx } = self;
let NodeBuilderWithComponents { let NodeBuilderWithComponents {
adapter: NodeTypesAdapter { database }, adapter: NodeTypesAdapter { database },
components_builder, components_builder,
add_ons: NodeAddOns { hooks, rpc, exexs: installed_exex }, add_ons: AddOns { hooks, rpc, exexs: installed_exex },
config, config,
} = target; } = target;
let NodeHooks { on_component_initialized, on_node_started, .. } = hooks; let NodeHooks { on_component_initialized, on_node_started, .. } = hooks;

View File

@ -17,9 +17,13 @@ pub use node::*;
/// Support for configuring the components of a node. /// Support for configuring the components of a node.
pub mod components; pub mod components;
pub use components::{NodeComponents, NodeComponentsBuilder};
mod builder; mod builder;
pub use builder::*; pub use builder::{
add_ons::{AddOns, RpcAddOns},
*,
};
mod launch; mod launch;
pub use launch::*; pub use launch::*;

View File

@ -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_chainspec::ChainSpec;
use reth_network::NetworkHandle; use reth_network::NetworkHandle;
use reth_node_api::FullNodeComponents; use reth_node_api::FullNodeComponents;
@ -11,11 +15,12 @@ use reth_payload_builder::PayloadBuilderHandle;
use reth_provider::ChainSpecProvider; use reth_provider::ChainSpecProvider;
use reth_rpc_builder::{auth::AuthServerHandle, RpcServerHandle}; use reth_rpc_builder::{auth::AuthServerHandle, RpcServerHandle};
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use std::{marker::PhantomData, sync::Arc};
// re-export the node api types use crate::{
use crate::components::NodeComponentsBuilder; components::NodeComponentsBuilder,
pub use reth_node_api::{FullNodeTypes, NodeTypes}; rpc::{RethRpcServerHandles, RpcRegistry},
NodeAdapter, NodeAddOns,
};
/// A [`crate::Node`] is a [`NodeTypes`] that comes with preconfigured components. /// A [`crate::Node`] is a [`NodeTypes`] that comes with preconfigured components.
/// ///
@ -24,45 +29,53 @@ pub trait Node<N: FullNodeTypes>: NodeTypes + Clone {
/// The type that builds the node's components. /// The type that builds the node's components.
type ComponentsBuilder: NodeComponentsBuilder<N>; type ComponentsBuilder: NodeComponentsBuilder<N>;
/// Exposes the customizable node add-on types.
type AddOns: NodeAddOns<
NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
>;
/// Returns a [`NodeComponentsBuilder`] for the node. /// Returns a [`NodeComponentsBuilder`] for the node.
fn components_builder(self) -> Self::ComponentsBuilder; fn components_builder(&self) -> Self::ComponentsBuilder;
} }
/// A [`Node`] type builder /// A [`Node`] type builder
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct AnyNode<N = (), C = ()>(PhantomData<N>, C); pub struct AnyNode<N = (), C = (), AO = ()>(PhantomData<(N, AO)>, C);
impl<N, C> AnyNode<N, C> { impl<N, C> AnyNode<N, C> {
/// Configures the types of the node. /// Configures the types of the node.
pub fn types<T>(self) -> AnyNode<T, C> { pub fn types<T>(self) -> AnyNode<T, C> {
AnyNode::<T, C>(PhantomData::<T>, self.1) AnyNode::<T, C>(PhantomData::<(T, ())>, self.1)
} }
/// Sets the node components builder. /// Sets the node components builder.
pub fn components_builder<T>(self, value: T) -> AnyNode<N, T> { pub const fn components_builder<T>(&self, value: T) -> AnyNode<N, T> {
AnyNode::<N, T>(PhantomData::<N>, value) AnyNode::<N, T>(PhantomData::<(N, ())>, value)
} }
} }
impl<N, C> NodeTypes for AnyNode<N, C> impl<N, C, AO> NodeTypes for AnyNode<N, C, AO>
where where
N: FullNodeTypes, N: FullNodeTypes,
C: NodeComponentsBuilder<N> + Sync + Unpin + 'static, C: Send + Sync + Unpin + 'static,
AO: Send + Sync + Unpin + Clone + 'static,
{ {
type Primitives = N::Primitives; type Primitives = N::Primitives;
type Engine = N::Engine; type Engine = N::Engine;
} }
impl<N, C> Node<N> for AnyNode<N, C> impl<N, C, AO> Node<N> for AnyNode<N, C, AO>
where where
N: FullNodeTypes + Clone, N: FullNodeTypes + Clone,
C: NodeComponentsBuilder<N> + Clone + Sync + Unpin + 'static, C: NodeComponentsBuilder<N> + Clone + Sync + Unpin + 'static,
AO: NodeAddOns<NodeAdapter<N, C::Components>>,
{ {
type ComponentsBuilder = C; type ComponentsBuilder = C;
type AddOns = AO;
fn components_builder(self) -> Self::ComponentsBuilder { fn components_builder(&self) -> Self::ComponentsBuilder {
self.1 self.1.clone()
} }
} }
@ -70,7 +83,7 @@ where
/// ///
/// This can be used to interact with the launched node. /// This can be used to interact with the launched node.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FullNode<Node: FullNodeComponents> { pub struct FullNode<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
/// The evm configuration. /// The evm configuration.
pub evm_config: Node::Evm, pub evm_config: Node::Evm,
/// The executor of the node. /// The executor of the node.
@ -88,14 +101,18 @@ pub struct FullNode<Node: FullNodeComponents> {
/// Handles to the node's rpc servers /// Handles to the node's rpc servers
pub rpc_server_handles: RethRpcServerHandles, pub rpc_server_handles: RethRpcServerHandles,
/// The configured rpc namespaces /// The configured rpc namespaces
pub rpc_registry: RpcRegistry<Node>, pub rpc_registry: RpcRegistry<Node, AddOns::EthApi>,
/// The initial node config. /// The initial node config.
pub config: NodeConfig, pub config: NodeConfig,
/// The data dir of the node. /// The data dir of the node.
pub data_dir: ChainPath<DataDirPath>, pub data_dir: ChainPath<DataDirPath>,
} }
impl<Node: FullNodeComponents> FullNode<Node> { impl<Node, AddOns> FullNode<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
/// Returns the [`ChainSpec`] of the node. /// Returns the [`ChainSpec`] of the node.
pub fn chain_spec(&self) -> Arc<ChainSpec> { pub fn chain_spec(&self) -> Arc<ChainSpec> {
self.provider.chain_spec() self.provider.chain_spec()

View File

@ -7,19 +7,23 @@ use std::{
use futures::TryFutureExt; use futures::TryFutureExt;
use reth_network::NetworkHandle; use reth_network::NetworkHandle;
use reth_node_api::FullNodeComponents; use reth_node_api::{BuilderProvider, FullNodeComponents};
use reth_node_core::{node_config::NodeConfig, rpc::api::EngineApiServer}; use reth_node_core::{
node_config::NodeConfig,
rpc::{api::EngineApiServer, eth::FullEthApiServer},
};
use reth_payload_builder::PayloadBuilderHandle; use reth_payload_builder::PayloadBuilderHandle;
use reth_rpc::eth::EthApi;
use reth_rpc_builder::{ use reth_rpc_builder::{
auth::{AuthRpcModule, AuthServerHandle}, auth::{AuthRpcModule, AuthServerHandle},
config::RethRpcServerConfig, config::RethRpcServerConfig,
EthApiBuild, RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules,
}; };
use reth_rpc_layer::JwtSecret; use reth_rpc_layer::JwtSecret;
use reth_tasks::TaskExecutor; use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info}; use reth_tracing::tracing::{debug, info};
use crate::{EthApiBuilderCtx, RpcAddOns};
/// Contains the handles to the spawned RPC servers. /// Contains the handles to the spawned RPC servers.
/// ///
/// This can be used to access the endpoints of the 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. /// Contains hooks that are called during the rpc setup.
pub(crate) struct RpcHooks<Node: FullNodeComponents> { pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
pub(crate) on_rpc_started: Box<dyn OnRpcStarted<Node>>, /// Hooks to run once RPC server is running.
pub(crate) extend_rpc_modules: Box<dyn ExtendRpcModules<Node>>, pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
/// Hooks to run to configure RPC server API.
pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
} }
impl<Node: FullNodeComponents> RpcHooks<Node> { impl<Node: FullNodeComponents, EthApi> Default for RpcHooks<Node, EthApi> {
/// Creates a new, empty [`RpcHooks`] instance for the given node type. fn default() -> Self {
pub(crate) fn new() -> Self {
Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() } Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
} }
}
impl<Node: FullNodeComponents, EthApi> RpcHooks<Node, EthApi> {
/// Sets the hook that is run once the rpc server is started. /// Sets the hook that is run once the rpc server is started.
pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
where where
F: OnRpcStarted<Node> + 'static, F: OnRpcStarted<Node, EthApi> + 'static,
{ {
self.on_rpc_started = Box::new(hook); self.on_rpc_started = Box::new(hook);
self self
@ -56,7 +63,7 @@ impl<Node: FullNodeComponents> RpcHooks<Node> {
#[allow(unused)] #[allow(unused)]
pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
where where
F: OnRpcStarted<Node> + 'static, F: OnRpcStarted<Node, EthApi> + 'static,
{ {
self.set_on_rpc_started(hook); self.set_on_rpc_started(hook);
self self
@ -65,7 +72,7 @@ impl<Node: FullNodeComponents> RpcHooks<Node> {
/// Sets the hook that is run to configure the rpc modules. /// Sets the hook that is run to configure the rpc modules.
pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
where where
F: ExtendRpcModules<Node> + 'static, F: ExtendRpcModules<Node, EthApi> + 'static,
{ {
self.extend_rpc_modules = Box::new(hook); self.extend_rpc_modules = Box::new(hook);
self self
@ -75,14 +82,14 @@ impl<Node: FullNodeComponents> RpcHooks<Node> {
#[allow(unused)] #[allow(unused)]
pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
where where
F: ExtendRpcModules<Node> + 'static, F: ExtendRpcModules<Node, EthApi> + 'static,
{ {
self.set_extend_rpc_modules(hook); self.set_extend_rpc_modules(hook);
self self
} }
} }
impl<Node: FullNodeComponents> fmt::Debug for RpcHooks<Node> { impl<Node: FullNodeComponents, EthApi> fmt::Debug for RpcHooks<Node, EthApi> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RpcHooks") f.debug_struct("RpcHooks")
.field("on_rpc_started", &"...") .field("on_rpc_started", &"...")
@ -92,33 +99,33 @@ impl<Node: FullNodeComponents> fmt::Debug for RpcHooks<Node> {
} }
/// Event hook that is called once the rpc server is started. /// Event hook that is called once the rpc server is started.
pub trait OnRpcStarted<Node: FullNodeComponents>: Send { pub trait OnRpcStarted<Node: FullNodeComponents, EthApi>: Send {
/// The hook that is called once the rpc server is started. /// The hook that is called once the rpc server is started.
fn on_rpc_started( fn on_rpc_started(
self: Box<Self>, self: Box<Self>,
ctx: RpcContext<'_, Node>, ctx: RpcContext<'_, Node, EthApi>,
handles: RethRpcServerHandles, handles: RethRpcServerHandles,
) -> eyre::Result<()>; ) -> eyre::Result<()>;
} }
impl<Node, F> OnRpcStarted<Node> for F impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
where where
F: FnOnce(RpcContext<'_, Node>, RethRpcServerHandles) -> eyre::Result<()> + Send, F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
Node: FullNodeComponents, Node: FullNodeComponents,
{ {
fn on_rpc_started( fn on_rpc_started(
self: Box<Self>, self: Box<Self>,
ctx: RpcContext<'_, Node>, ctx: RpcContext<'_, Node, EthApi>,
handles: RethRpcServerHandles, handles: RethRpcServerHandles,
) -> eyre::Result<()> { ) -> eyre::Result<()> {
(*self)(ctx, handles) (*self)(ctx, handles)
} }
} }
impl<Node: FullNodeComponents> OnRpcStarted<Node> for () { impl<Node: FullNodeComponents, EthApi> OnRpcStarted<Node, EthApi> for () {
fn on_rpc_started( fn on_rpc_started(
self: Box<Self>, self: Box<Self>,
_: RpcContext<'_, Node>, _: RpcContext<'_, Node, EthApi>,
_: RethRpcServerHandles, _: RethRpcServerHandles,
) -> eyre::Result<()> { ) -> eyre::Result<()> {
Ok(()) Ok(())
@ -126,49 +133,49 @@ impl<Node: FullNodeComponents> OnRpcStarted<Node> for () {
} }
/// Event hook that is called when the rpc server is started. /// Event hook that is called when the rpc server is started.
pub trait ExtendRpcModules<Node: FullNodeComponents>: Send { pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi>: Send {
/// The hook that is called once the rpc server is started. /// The hook that is called once the rpc server is started.
fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node>) -> eyre::Result<()>; fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
} }
impl<Node, F> ExtendRpcModules<Node> for F impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
where where
F: FnOnce(RpcContext<'_, Node>) -> eyre::Result<()> + Send, F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
Node: FullNodeComponents, Node: FullNodeComponents,
{ {
fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node>) -> eyre::Result<()> { fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
(*self)(ctx) (*self)(ctx)
} }
} }
impl<Node: FullNodeComponents> ExtendRpcModules<Node> for () { impl<Node: FullNodeComponents, EthApi> ExtendRpcModules<Node, EthApi> for () {
fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node>) -> eyre::Result<()> { fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
Ok(()) Ok(())
} }
} }
/// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait. /// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait.
#[derive(Debug)] #[derive(Debug, Clone)]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub struct RpcRegistry<Node: FullNodeComponents> { pub struct RpcRegistry<Node: FullNodeComponents, EthApi> {
pub(crate) registry: RpcRegistryInner< pub(crate) registry: RpcRegistryInner<
Node::Provider, Node::Provider,
Node::Pool, Node::Pool,
NetworkHandle, NetworkHandle,
TaskExecutor, TaskExecutor,
Node::Provider, Node::Provider,
EthApi<Node::Provider, Node::Pool, NetworkHandle, Node::Evm>, EthApi,
>, >,
} }
impl<Node: FullNodeComponents> Deref for RpcRegistry<Node> { impl<Node: FullNodeComponents, EthApi> Deref for RpcRegistry<Node, EthApi> {
type Target = RpcRegistryInner< type Target = RpcRegistryInner<
Node::Provider, Node::Provider,
Node::Pool, Node::Pool,
NetworkHandle, NetworkHandle,
TaskExecutor, TaskExecutor,
Node::Provider, Node::Provider,
EthApi<Node::Provider, Node::Pool, NetworkHandle, Node::Evm>, EthApi,
>; >;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -176,18 +183,12 @@ impl<Node: FullNodeComponents> Deref for RpcRegistry<Node> {
} }
} }
impl<Node: FullNodeComponents> DerefMut for RpcRegistry<Node> { impl<Node: FullNodeComponents, EthApi> DerefMut for RpcRegistry<Node, EthApi> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.registry &mut self.registry
} }
} }
impl<Node: FullNodeComponents> Clone for RpcRegistry<Node> {
fn clone(&self) -> Self {
Self { registry: self.registry.clone() }
}
}
/// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and /// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and
/// [`AuthRpcModule`]. /// [`AuthRpcModule`].
/// ///
@ -196,7 +197,7 @@ impl<Node: FullNodeComponents> Clone for RpcRegistry<Node> {
/// transport modules [`TransportRpcModules`] as well as configured authenticated methods /// transport modules [`TransportRpcModules`] as well as configured authenticated methods
/// [`AuthRpcModule`]. /// [`AuthRpcModule`].
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct RpcContext<'a, Node: FullNodeComponents> { pub struct RpcContext<'a, Node: FullNodeComponents, EthApi> {
/// The node components. /// The node components.
pub(crate) node: Node, pub(crate) node: Node,
@ -206,7 +207,7 @@ pub struct RpcContext<'a, Node: FullNodeComponents> {
/// A Helper type the holds instances of the configured modules. /// A Helper type the holds instances of the configured modules.
/// ///
/// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`]. /// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`].
pub registry: &'a mut RpcRegistry<Node>, pub registry: &'a mut RpcRegistry<Node, EthApi>,
/// Holds installed modules per transport type. /// Holds installed modules per transport type.
/// ///
/// This can be used to merge additional modules into the configured transports (http, ipc, /// 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, 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. /// Returns the config of the node.
pub const fn config(&self) -> &NodeConfig { pub const fn config(&self) -> &NodeConfig {
self.config self.config
@ -251,19 +252,18 @@ impl<'a, Node: FullNodeComponents> RpcContext<'a, Node> {
} }
/// Launch the rpc servers. /// Launch the rpc servers.
pub(crate) async fn launch_rpc_servers<Node, Engine>( pub(crate) async fn launch_rpc_servers<Node, Engine, EthApi>(
node: Node, node: Node,
engine_api: Engine, engine_api: Engine,
config: &NodeConfig, config: &NodeConfig,
jwt_secret: JwtSecret, jwt_secret: JwtSecret,
hooks: RpcHooks<Node>, add_ons: RpcAddOns<Node, EthApi>,
) -> eyre::Result<(RethRpcServerHandles, RpcRegistry<Node>)> ) -> eyre::Result<(RethRpcServerHandles, RpcRegistry<Node, EthApi>)>
where where
EthApi: EthApiBuilderProvider<Node> + FullEthApiServer,
Node: FullNodeComponents + Clone, Node: FullNodeComponents + Clone,
Engine: EngineApiServer<Node::Engine>, Engine: EngineApiServer<Node::Engine>,
{ {
let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
let auth_config = config.rpc.auth_server_config(jwt_secret)?; let auth_config = config.rpc.auth_server_config(jwt_secret)?;
let module_config = config.rpc.transport_rpc_module_config(); 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"); 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_events(node.provider().clone())
.with_executor(node.task_executor().clone()) .with_executor(node.task_executor().clone())
.with_evm_config(node.evm_config().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 mut registry = RpcRegistry { registry };
let ctx = RpcContext { let ctx = RpcContext {
@ -286,6 +286,9 @@ where
auth_module: &mut auth_module, 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)?; extend_rpc_modules.extend_rpc_modules(ctx)?;
let server_config = config.rpc.rpc_server_config(); let server_config = config.rpc.rpc_server_config();
@ -329,3 +332,20 @@ where
Ok((handles, registry)) Ok((handles, registry))
} }
/// Provides builder for the core `eth` API type.
pub trait EthApiBuilderProvider<N: FullNodeComponents>: BuilderProvider<N> {
/// Returns the eth api builder.
#[allow(clippy::type_complexity)]
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N>) -> Self + Send>;
}
impl<N, F> EthApiBuilderProvider<N> for F
where
N: FullNodeComponents,
for<'a> F: BuilderProvider<N, Ctx<'a> = &'a EthApiBuilderCtx<N>>,
{
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N>) -> Self + Send> {
F::builder()
}
}

View File

@ -37,6 +37,8 @@ revm-primitives.workspace = true
reth-discv5.workspace = true reth-discv5.workspace = true
reth-rpc-eth-types.workspace = true reth-rpc-eth-types.workspace = true
reth-rpc-eth-api.workspace = true reth-rpc-eth-api.workspace = true
reth-optimism-rpc.workspace = true
reth-tasks.workspace = true
# async # async
async-trait.workspace = true async-trait.workspace = true
@ -78,6 +80,7 @@ optimism = [
"reth-beacon-consensus/optimism", "reth-beacon-consensus/optimism",
"reth-revm/optimism", "reth-revm/optimism",
"reth-auto-seal-consensus/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"] test-utils = ["reth-node-builder/test-utils"]

View File

@ -1,14 +1,12 @@
//! Optimism Node types config. //! Optimism Node types config.
use crate::{ use std::sync::Arc;
args::RollupArgs,
txpool::{OpTransactionPool, OpTransactionValidator},
OptimismEngineTypes,
};
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
use reth_evm::ConfigureEvm; use reth_evm::ConfigureEvm;
use reth_evm_optimism::{OpExecutorProvider, OptimismEvmConfig}; use reth_evm_optimism::{OpExecutorProvider, OptimismEvmConfig};
use reth_network::{NetworkHandle, NetworkManager}; use reth_network::{NetworkHandle, NetworkManager};
use reth_node_api::{FullNodeComponents, NodeAddOns};
use reth_node_builder::{ use reth_node_builder::{
components::{ components::{
ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder,
@ -18,14 +16,21 @@ use reth_node_builder::{
BuilderContext, Node, PayloadBuilderConfig, BuilderContext, Node, PayloadBuilderConfig,
}; };
use reth_optimism_consensus::OptimismBeaconConsensus; use reth_optimism_consensus::OptimismBeaconConsensus;
use reth_optimism_rpc::OpEthApi;
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_provider::CanonStateSubscriptions; use reth_provider::CanonStateSubscriptions;
use reth_rpc::EthApi;
use reth_tracing::tracing::{debug, info}; use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{ use reth_transaction_pool::{
blobstore::DiskFileBlobStore, CoinbaseTipOrdering, TransactionPool, blobstore::DiskFileBlobStore, CoinbaseTipOrdering, TransactionPool,
TransactionValidationTaskExecutor, TransactionValidationTaskExecutor,
}; };
use std::sync::Arc;
use crate::{
args::RollupArgs,
txpool::{OpTransactionPool, OpTransactionValidator},
OptimismEngineTypes,
};
/// Type configuration for a regular Optimism node. /// Type configuration for a regular Optimism node.
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -82,9 +87,11 @@ where
OptimismConsensusBuilder, OptimismConsensusBuilder,
>; >;
fn components_builder(self) -> Self::ComponentsBuilder { type AddOns = OptimismAddOns;
fn components_builder(&self) -> Self::ComponentsBuilder {
let Self { args } = self; let Self { args } = self;
Self::components(args) Self::components(args.clone())
} }
} }
@ -93,6 +100,14 @@ impl NodeTypes for OptimismNode {
type Engine = OptimismEngineTypes; type Engine = OptimismEngineTypes;
} }
/// Add-ons w.r.t. optimism.
#[derive(Debug, Clone)]
pub struct OptimismAddOns;
impl<N: FullNodeComponents> NodeAddOns<N> for OptimismAddOns {
type EthApi = OpEthApi<EthApi<N::Provider, N::Pool, NetworkHandle, N::Evm>>;
}
/// A regular optimism evm and executor builder. /// A regular optimism evm and executor builder.
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive] #[non_exhaustive]

View File

@ -1,15 +1,18 @@
use std::sync::Arc;
use alloy_genesis::Genesis; use alloy_genesis::Genesis;
use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager}; use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager};
use reth_chainspec::{ChainSpecBuilder, BASE_MAINNET}; use reth_chainspec::{ChainSpecBuilder, BASE_MAINNET};
use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType}; 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_payload_builder::EthPayloadBuilderAttributes;
use reth_primitives::{Address, B256}; use reth_primitives::{Address, B256};
use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
/// Optimism Node Helper type /// Optimism Node Helper type
pub(crate) type OpNode = NodeHelperType<OptimismNode>; pub(crate) type OpNode = NodeHelperType<OptimismNode, OptimismAddOns>;
pub(crate) async fn setup(num_nodes: usize) -> eyre::Result<(Vec<OpNode>, TaskManager, Wallet)> { pub(crate) async fn setup(num_nodes: usize) -> eyre::Result<(Vec<OpNode>, TaskManager, Wallet)> {
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();

View File

@ -3,7 +3,7 @@
use reth_db::test_utils::create_test_rw_db; use reth_db::test_utils::create_test_rw_db;
use reth_node_api::FullNodeComponents; use reth_node_api::FullNodeComponents;
use reth_node_builder::{NodeBuilder, NodeConfig}; use reth_node_builder::{NodeBuilder, NodeConfig};
use reth_node_optimism::node::OptimismNode; use reth_node_optimism::node::{OptimismAddOns, OptimismNode};
#[test] #[test]
fn test_basic_setup() { fn test_basic_setup() {
@ -14,6 +14,7 @@ fn test_basic_setup() {
.with_database(db) .with_database(db)
.with_types::<OptimismNode>() .with_types::<OptimismNode>()
.with_components(OptimismNode::components(Default::default())) .with_components(OptimismNode::components(Default::default()))
.with_add_ons::<OptimismAddOns>()
.on_component_initialized(move |ctx| { .on_component_initialized(move |ctx| {
let _provider = ctx.provider(); let _provider = ctx.provider();
Ok(()) Ok(())

View File

@ -25,6 +25,8 @@ reth-rpc-server-types.workspace = true
reth-rpc-types.workspace = true reth-rpc-types.workspace = true
reth-tasks = { workspace = true, features = ["rayon"] } reth-tasks = { workspace = true, features = ["rayon"] }
reth-transaction-pool.workspace = true reth-transaction-pool.workspace = true
reth-rpc.workspace = true
reth-node-api.workspace = true
# ethereum # ethereum
alloy-primitives.workspace = true alloy-primitives.workspace = true

View File

@ -12,9 +12,15 @@ use alloy_primitives::{Address, U64};
use reth_chainspec::{ChainInfo, ChainSpec}; use reth_chainspec::{ChainInfo, ChainSpec};
use reth_errors::RethResult; use reth_errors::RethResult;
use reth_evm::ConfigureEvm; use reth_evm::ConfigureEvm;
use reth_node_api::{BuilderProvider, FullNodeComponents};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderFactory}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderFactory};
use reth_rpc_eth_api::helpers::{ use reth_rpc::eth::DevSigner;
Call, EthApiSpec, EthCall, EthFees, EthState, LoadFee, LoadState, SpawnBlocking, Trace, 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_eth_types::EthStateCache;
use reth_rpc_types::SyncStatus; use reth_rpc_types::SyncStatus;
@ -154,3 +160,31 @@ impl<Eth: Trace> Trace for OpEthApi<Eth> {
self.inner.evm_config() self.inner.evm_config()
} }
} }
impl<Eth: AddDevSigners> AddDevSigners for OpEthApi<Eth> {
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
self.inner.signers()
}
fn with_dev_accounts(&self) {
*self.signers().write() = DevSigner::random_signers(20)
}
}
impl<Eth: UpdateRawTxForwarder> UpdateRawTxForwarder for OpEthApi<Eth> {
fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc<dyn RawTransactionForwarder>) {
self.inner.set_eth_raw_transaction_forwarder(forwarder);
}
}
impl<N, Eth> BuilderProvider<N> for OpEthApi<Eth>
where
Eth: BuilderProvider<N>,
N: FullNodeComponents,
{
type Ctx<'a> = <Eth as BuilderProvider<N>>::Ctx<'a>;
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send> {
Box::new(|ctx| Self { inner: Eth::builder()(ctx) })
}
}

View File

@ -61,6 +61,7 @@ reth-rpc-types-compat.workspace = true
reth-tracing.workspace = true reth-tracing.workspace = true
reth-transaction-pool = { workspace = true, features = ["test-utils"] } reth-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-tokio-util.workspace = true reth-tokio-util.workspace = true
reth-node-api.workspace = true
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
serde_json.workspace = true serde_json.workspace = true

View File

@ -1,16 +1,18 @@
use crate::{ use std::{net::SocketAddr, path::PathBuf};
auth::AuthServerConfig, error::RpcError, EthConfig, IpcServerBuilder, RpcModuleConfig,
RpcServerConfig, TransportRpcModuleConfig,
};
use jsonrpsee::server::ServerBuilder; use jsonrpsee::server::ServerBuilder;
use reth_node_core::{args::RpcServerArgs, utils::get_or_create_jwt_secret_from_path}; 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_layer::{JwtError, JwtSecret};
use reth_rpc_server_types::RpcModuleSelection; use reth_rpc_server_types::RpcModuleSelection;
use std::{net::SocketAddr, path::PathBuf};
use tower::layer::util::Identity; use tower::layer::util::Identity;
use tracing::debug; use tracing::debug;
use crate::{
auth::AuthServerConfig, error::RpcError, IpcServerBuilder, RpcModuleConfig, RpcServerConfig,
TransportRpcModuleConfig,
};
/// A trait that provides a configured RPC server. /// A trait that provides a configured RPC server.
/// ///
/// This provides all basic config values for the RPC server and is implemented by the /// This provides all basic config values for the RPC server and is implemented by the

View File

@ -1,31 +1,14 @@
use std::{fmt::Debug, time::Duration};
use reth_evm::ConfigureEvm; use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo; use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory};
use reth_provider::{ use reth_rpc::{EthFilter, EthPubSub};
BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider,
FullRpcProvider, StateProviderFactory,
};
use reth_rpc::{eth::EthFilterConfig, EthApi, EthFilter, EthPubSub};
use reth_rpc_eth_types::{ use reth_rpc_eth_types::{
cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache, cache::cache_new_blocks_task, EthApiBuilderCtx, EthConfig, EthStateCache,
EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP,
}; };
use reth_rpc_server_types::constants::{ use reth_tasks::TaskSpawner;
default_max_tracing_requests, DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKS_PER_FILTER,
DEFAULT_MAX_LOGS_PER_RESPONSE, DEFAULT_PROOF_PERMITS,
};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
use reth_transaction_pool::TransactionPool;
use serde::{Deserialize, Serialize};
/// Default value for stale filter ttl /// Alias for `eth` namespace API builder.
const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60); pub type DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> =
Box<dyn Fn(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi>;
/// Alias for function that builds the core `eth` namespace API.
pub type EthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> =
Box<dyn FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi>;
/// Handlers for core, filter and pubsub `eth` namespace APIs. /// Handlers for core, filter and pubsub `eth` namespace APIs.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -43,7 +26,7 @@ pub struct EthHandlers<Provider, Pool, Network, Events, EthApi> {
impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Network, Events, EthApi> { impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Network, Events, EthApi> {
/// Returns a new [`EthHandlers`] builder. /// Returns a new [`EthHandlers`] builder.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn builder<EvmConfig, Tasks, EthApiB>( pub fn builder<EvmConfig, Tasks>(
provider: Provider, provider: Provider,
pool: Pool, pool: Pool,
network: Network, network: Network,
@ -51,12 +34,16 @@ impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Networ
config: EthConfig, config: EthConfig,
executor: Tasks, executor: Tasks,
events: Events, events: Events,
eth_api_builder: EthApiB, eth_api_builder: DynEthApiBuilder<
) -> EthHandlersBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi> Provider,
where Pool,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi EvmConfig,
+ 'static, Network,
{ Tasks,
Events,
EthApi,
>,
) -> EthHandlersBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi> {
EthHandlersBuilder { EthHandlersBuilder {
provider, provider,
pool, pool,
@ -65,7 +52,7 @@ impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Networ
config, config,
executor, executor,
events, events,
eth_api_builder: Box::new(eth_api_builder), eth_api_builder,
} }
} }
} }
@ -80,7 +67,7 @@ pub struct EthHandlersBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig,
config: EthConfig, config: EthConfig,
executor: Tasks, executor: Tasks,
events: Events, events: Events,
eth_api_builder: EthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>, eth_api_builder: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
} }
impl<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi> impl<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi>
@ -89,9 +76,10 @@ where
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static,
Pool: Send + Sync + Clone + 'static, Pool: Send + Sync + Clone + 'static,
EvmConfig: ConfigureEvm, EvmConfig: ConfigureEvm,
Network: Clone, Network: Clone + 'static,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone, Events: CanonStateSubscriptions + Clone + 'static,
EthApi: 'static,
{ {
/// Returns a new instance with handlers for `eth` namespace. /// Returns a new instance with handlers for `eth` namespace.
pub fn build(self) -> EthHandlers<Provider, Pool, Network, Events, EthApi> { pub fn build(self) -> EthHandlers<Provider, Pool, Network, Events, EthApi> {
@ -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<Provider, Pool, EvmConfig, Network, Tasks, Events> {
/// 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<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> EthApi<Provider, Pool, Network, EvmConfig>
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). /// Builds the `eth_` namespace API [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer).
#[derive(Debug)] #[derive(Debug)]
pub struct EthFilterApiBuilder; 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<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> GasPriceOracle<Provider>
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<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> 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
}
}

View File

@ -19,13 +19,13 @@
//! use reth_evm::ConfigureEvm; //! use reth_evm::ConfigureEvm;
//! use reth_network_api::{NetworkInfo, Peers}; //! use reth_network_api::{NetworkInfo, Peers};
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; //! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_builder::{ //! use reth_rpc_builder::{
//! EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, //! RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig,
//! TransportRpcModuleConfig,
//! }; //! };
//!
//! use reth_tasks::TokioTaskExecutor; //! use reth_tasks::TokioTaskExecutor;
//! use reth_transaction_pool::TransactionPool; //! use reth_transaction_pool::TransactionPool;
//!
//! pub async fn launch<Provider, Pool, Network, Events, EvmConfig>( //! pub async fn launch<Provider, Pool, Network, Events, EvmConfig>(
//! provider: Provider, //! provider: Provider,
//! pool: Pool, //! pool: Pool,
@ -54,7 +54,7 @@
//! events, //! events,
//! evm_config, //! evm_config,
//! ) //! )
//! .build(transports, EthApiBuild::build); //! .build(transports, Box::new(EthApi::with_spawner));
//! let handle = RpcServerConfig::default() //! let handle = RpcServerConfig::default()
//! .with_http(ServerBuilder::default()) //! .with_http(ServerBuilder::default())
//! .start(&transport_modules) //! .start(&transport_modules)
@ -70,9 +70,10 @@
//! use reth_evm::ConfigureEvm; //! use reth_evm::ConfigureEvm;
//! use reth_network_api::{NetworkInfo, Peers}; //! use reth_network_api::{NetworkInfo, Peers};
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider}; //! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_api::EngineApiServer; //! use reth_rpc_api::EngineApiServer;
//! use reth_rpc_builder::{ //! use reth_rpc_builder::{
//! auth::AuthServerConfig, EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, //! auth::AuthServerConfig, RethRpcModule, RpcModuleBuilder, RpcServerConfig,
//! TransportRpcModuleConfig, //! TransportRpcModuleConfig,
//! }; //! };
//! use reth_rpc_layer::JwtSecret; //! use reth_rpc_layer::JwtSecret;
@ -113,7 +114,7 @@
//! //!
//! // configure the server modules //! // configure the server modules
//! let (modules, auth_module, _registry) = //! 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 //! // start the servers
//! let auth_config = AuthServerConfig::builder(JwtSecret::random()).build(); //! let auth_config = AuthServerConfig::builder(JwtSecret::random()).build();
@ -140,6 +141,7 @@ use std::{
}; };
use error::{ConflictingModules, RpcError, ServerKind}; use error::{ConflictingModules, RpcError, ServerKind};
use eth::DynEthApiBuilder;
use http::{header::AUTHORIZATION, HeaderMap}; use http::{header::AUTHORIZATION, HeaderMap};
use jsonrpsee::{ use jsonrpsee::{
core::RegisterMethodError, core::RegisterMethodError,
@ -167,7 +169,7 @@ use reth_rpc_eth_api::{
}, },
EthApiServer, FullEthApiServer, RawTransactionForwarder, 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_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret};
use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor}; use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
@ -202,17 +204,14 @@ pub mod error;
/// Eth utils /// Eth utils
pub mod eth; pub mod eth;
pub use eth::{ pub use eth::EthHandlers;
EthApiBuild, EthApiBuilderCtx, EthConfig, EthHandlers, FeeHistoryCacheBuilder,
GasPriceOracleBuilder,
};
// Rpc server metrics // Rpc server metrics
mod metrics; mod metrics;
/// Convenience function for starting a server in one step. /// Convenience function for starting a server in one step.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi, EthApiB>( pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi>(
provider: Provider, provider: Provider,
pool: Pool, pool: Pool,
network: Network, network: Network,
@ -221,7 +220,7 @@ pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi, E
executor: Tasks, executor: Tasks,
events: Events, events: Events,
evm_config: EvmConfig, evm_config: EvmConfig,
eth: EthApiB, eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> Result<RpcServerHandle, RpcError> ) -> Result<RpcServerHandle, RpcError>
where where
Provider: FullRpcProvider + AccountReader + ChangeSetReader, Provider: FullRpcProvider + AccountReader + ChangeSetReader,
@ -230,8 +229,6 @@ where
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static,
EvmConfig: ConfigureEvm, EvmConfig: ConfigureEvm,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer, EthApi: FullEthApiServer,
{ {
let module_config = module_config.into(); 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_` /// also configures the auth (engine api) server, which exposes a subset of the `eth_`
/// namespace. /// namespace.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn build_with_auth_server<EngineApi, EngineT, EthApi, EthApiB>( pub fn build_with_auth_server<EngineApi, EngineT, EthApi>(
self, self,
module_config: TransportRpcModuleConfig, module_config: TransportRpcModuleConfig,
engine: EngineApi, engine: EngineApi,
eth: EthApiB, eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> ( ) -> (
TransportRpcModules, TransportRpcModules,
AuthRpcModule, AuthRpcModule,
@ -439,8 +436,6 @@ where
where where
EngineT: EngineTypes + 'static, EngineT: EngineTypes + 'static,
EngineApi: EngineApiServer<EngineT>, EngineApi: EngineApiServer<EngineT>,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer, EthApi: FullEthApiServer,
{ {
let Self { provider, pool, network, executor, events, evm_config } = self; let Self { provider, pool, network, executor, events, evm_config } = self;
@ -469,7 +464,8 @@ where
/// use reth_evm::ConfigureEvm; /// use reth_evm::ConfigureEvm;
/// use reth_network_api::noop::NoopNetwork; /// use reth_network_api::noop::NoopNetwork;
/// use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; /// 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_tasks::TokioTaskExecutor;
/// use reth_transaction_pool::noop::NoopTransactionPool; /// use reth_transaction_pool::noop::NoopTransactionPool;
/// ///
@ -481,19 +477,18 @@ where
/// .with_executor(TokioTaskExecutor::default()) /// .with_executor(TokioTaskExecutor::default())
/// .with_events(TestCanonStateSubscriptions::default()) /// .with_events(TestCanonStateSubscriptions::default())
/// .with_evm_config(evm) /// .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(); /// let eth_api = registry.eth_api();
/// } /// }
/// ``` /// ```
pub fn into_registry<EthApi, EthApiB>( pub fn into_registry<EthApi>(
self, self,
config: RpcModuleConfig, config: RpcModuleConfig,
eth: EthApiB, eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi> ) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where where
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi EthApi: 'static,
+ 'static,
{ {
let Self { provider, pool, network, executor, events, evm_config } = self; let Self { provider, pool, network, executor, events, evm_config } = self;
RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth) 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 /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
/// be used to start the transport server(s). /// be used to start the transport server(s).
pub fn build<EthApi, EthApiB>( pub fn build<EthApi>(
self, self,
module_config: TransportRpcModuleConfig, module_config: TransportRpcModuleConfig,
eth: EthApiB, eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> TransportRpcModules<()> ) -> TransportRpcModules<()>
where where
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer, EthApi: FullEthApiServer,
{ {
let mut modules = TransportRpcModules::default(); let mut modules = TransportRpcModules::default();
@ -636,13 +629,14 @@ impl<Provider, Pool, Network, Tasks, Events, EthApi>
where where
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static,
Pool: Send + Sync + Clone + 'static, Pool: Send + Sync + Clone + 'static,
Network: Clone, Network: Clone + 'static,
Events: CanonStateSubscriptions + Clone, Events: CanonStateSubscriptions + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static, Tasks: TaskSpawner + Clone + 'static,
EthApi: 'static,
{ {
/// Creates a new, empty instance. /// Creates a new, empty instance.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new<EvmConfig, EthApiB>( pub fn new<EvmConfig>(
provider: Provider, provider: Provider,
pool: Pool, pool: Pool,
network: Network, network: Network,
@ -650,12 +644,18 @@ where
events: Events, events: Events,
config: RpcModuleConfig, config: RpcModuleConfig,
evm_config: EvmConfig, evm_config: EvmConfig,
eth_api_builder: EthApiB, eth_api_builder: DynEthApiBuilder<
Provider,
Pool,
EvmConfig,
Network,
Tasks,
Events,
EthApi,
>,
) -> Self ) -> Self
where where
EvmConfig: ConfigureEvm, EvmConfig: ConfigureEvm,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
{ {
let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests); let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests);

View File

@ -2,9 +2,10 @@
use std::io; use std::io;
use reth_rpc::EthApi;
use reth_rpc_builder::{ use reth_rpc_builder::{
error::{RpcError, ServerKind, WsHttpSamePortError}, error::{RpcError, ServerKind, WsHttpSamePortError},
EthApiBuild, RpcServerConfig, TransportRpcModuleConfig, RpcServerConfig, TransportRpcModuleConfig,
}; };
use reth_rpc_server_types::RethRpcModule; 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 handle = launch_http(vec![RethRpcModule::Admin]).await;
let addr = handle.http_local_addr().unwrap(); let addr = handle.http_local_addr().unwrap();
let builder = test_rpc_builder(); let builder = test_rpc_builder();
let server = builder let server = builder.build(
.build(TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]), EthApiBuild::build); TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]),
Box::new(EthApi::with_spawner),
);
let result = let result =
RpcServerConfig::http(Default::default()).with_http_address(addr).start(&server).await; RpcServerConfig::http(Default::default()).with_http_address(addr).start(&server).await;
let err = result.unwrap_err(); 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 handle = launch_ws(vec![RethRpcModule::Admin]).await;
let addr = handle.ws_local_addr().unwrap(); let addr = handle.ws_local_addr().unwrap();
let builder = test_rpc_builder(); let builder = test_rpc_builder();
let server = builder let server = builder.build(
.build(TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]), EthApiBuild::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 result = RpcServerConfig::ws(Default::default()).with_ws_address(addr).start(&server).await;
let err = result.unwrap_err(); let err = result.unwrap_err();
assert!(is_addr_in_use_kind(&err, ServerKind::WS(addr)), "{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( let server = builder.build(
TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]) TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin])
.with_http(vec![RethRpcModule::Eth]), .with_http(vec![RethRpcModule::Eth]),
EthApiBuild::build, Box::new(EthApi::with_spawner),
); );
let addr = test_address(); let addr = test_address();
let res = RpcServerConfig::ws(Default::default()) let res = RpcServerConfig::ws(Default::default())
@ -82,7 +87,7 @@ async fn test_launch_same_port_same_cors() {
let server = builder.build( let server = builder.build(
TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth])
.with_http(vec![RethRpcModule::Eth]), .with_http(vec![RethRpcModule::Eth]),
EthApiBuild::build, Box::new(EthApi::with_spawner),
); );
let addr = test_address(); let addr = test_address();
let res = RpcServerConfig::ws(Default::default()) let res = RpcServerConfig::ws(Default::default())
@ -102,7 +107,7 @@ async fn test_launch_same_port_different_cors() {
let server = builder.build( let server = builder.build(
TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth]) TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Eth])
.with_http(vec![RethRpcModule::Eth]), .with_http(vec![RethRpcModule::Eth]),
EthApiBuild::build, Box::new(EthApi::with_spawner),
); );
let addr = test_address(); let addr = test_address();
let res = RpcServerConfig::ws(Default::default()) let res = RpcServerConfig::ws(Default::default())

View File

@ -7,9 +7,10 @@ use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork; use reth_network_api::noop::NoopNetwork;
use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_payload_builder::test_utils::spawn_test_payload_service;
use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions};
use reth_rpc::EthApi;
use reth_rpc_builder::{ use reth_rpc_builder::{
auth::{AuthRpcModule, AuthServerConfig, AuthServerHandle}, auth::{AuthRpcModule, AuthServerConfig, AuthServerHandle},
EthApiBuild, RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig, RpcModuleBuilder, RpcServerConfig, RpcServerHandle, TransportRpcModuleConfig,
}; };
use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
use reth_rpc_layer::JwtSecret; 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 /// Launches a new server with http only with the given modules
pub async fn launch_http(modules: impl Into<RpcModuleSelection>) -> RpcServerHandle { pub async fn launch_http(modules: impl Into<RpcModuleSelection>) -> RpcServerHandle {
let builder = test_rpc_builder(); 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()) RpcServerConfig::http(Default::default())
.with_http_address(test_address()) .with_http_address(test_address())
.start(&server) .start(&server)
@ -64,7 +66,8 @@ pub async fn launch_http(modules: impl Into<RpcModuleSelection>) -> RpcServerHan
/// Launches a new server with ws only with the given modules /// Launches a new server with ws only with the given modules
pub async fn launch_ws(modules: impl Into<RpcModuleSelection>) -> RpcServerHandle { pub async fn launch_ws(modules: impl Into<RpcModuleSelection>) -> RpcServerHandle {
let builder = test_rpc_builder(); 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()) RpcServerConfig::ws(Default::default())
.with_http_address(test_address()) .with_http_address(test_address())
.start(&server) .start(&server)
@ -78,7 +81,7 @@ pub async fn launch_http_ws(modules: impl Into<RpcModuleSelection>) -> RpcServer
let modules = modules.into(); let modules = modules.into();
let server = builder.build( let server = builder.build(
TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules),
EthApiBuild::build, Box::new(EthApi::with_spawner),
); );
RpcServerConfig::ws(Default::default()) RpcServerConfig::ws(Default::default())
.with_ws_address(test_address()) .with_ws_address(test_address())
@ -95,7 +98,7 @@ pub async fn launch_http_ws_same_port(modules: impl Into<RpcModuleSelection>) ->
let modules = modules.into(); let modules = modules.into();
let server = builder.build( let server = builder.build(
TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules), TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules),
EthApiBuild::build, Box::new(EthApi::with_spawner),
); );
let addr = test_address(); let addr = test_address();
RpcServerConfig::ws(Default::default()) RpcServerConfig::ws(Default::default())

View File

@ -32,7 +32,7 @@ pub use call::{Call, EthCall};
pub use fee::{EthFees, LoadFee}; pub use fee::{EthFees, LoadFee};
pub use pending_block::LoadPendingBlock; pub use pending_block::LoadPendingBlock;
pub use receipt::LoadReceipt; pub use receipt::LoadReceipt;
pub use signer::EthSigner; pub use signer::{AddDevSigners, EthSigner};
pub use spec::EthApiSpec; pub use spec::EthApiSpec;
pub use state::{EthState, LoadState}; pub use state::{EthState, LoadState};
pub use trace::Trace; pub use trace::Trace;

View File

@ -37,3 +37,14 @@ pub trait EthSigner: Send + Sync + DynClone {
} }
dyn_clone::clone_trait_object!(EthSigner); 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<Vec<Box<dyn EthSigner>>>;
/// Generates 20 random developer accounts.
/// Used in DEV mode.
fn with_dev_accounts(&self);
}

View File

@ -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<u64>,
/// 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<usize>,
/// 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),
}
}
}

View File

@ -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<Provider, Pool, EvmConfig, Network, Tasks, Events> {
/// 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<Provider, Pool, EvmConfig, Network, Tasks, Events>
EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>
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<Provider> {
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<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> GasPriceOracle<Provider>
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<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> 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
}
}

View File

@ -0,0 +1,4 @@
//! `eth` namespace API builder types.
pub mod config;
pub mod ctx;

View File

@ -8,6 +8,7 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(test), warn(unused_crate_dependencies))]
pub mod builder;
pub mod cache; pub mod cache;
pub mod error; pub mod error;
pub mod fee_history; pub mod fee_history;
@ -20,6 +21,10 @@ pub mod revm_utils;
pub mod transaction; pub mod transaction;
pub mod utils; pub mod utils;
pub use builder::{
config::{EthConfig, EthFilterConfig},
ctx::EthApiBuilderCtx,
};
pub use cache::{ pub use cache::{
config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache, config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache,
EthStateCache, EthStateCache,

View File

@ -33,6 +33,7 @@ reth-evm.workspace = true
reth-rpc-eth-types.workspace = true reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true reth-rpc-server-types.workspace = true
reth-evm-optimism = { workspace = true, optional = true } reth-evm-optimism = { workspace = true, optional = true }
reth-node-api.workspace = true
# eth # eth
alloy-dyn-abi.workspace = true alloy-dyn-abi.workspace = true

View File

@ -1,25 +1,26 @@
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait //! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
//! Handles RPC requests for the `eth_` namespace. //! Handles RPC requests for the `eth_` namespace.
use futures::Future;
use std::sync::Arc; use std::sync::Arc;
use derive_more::Deref; use derive_more::Deref;
use futures::Future;
use reth_node_api::{BuilderProvider, FullNodeComponents};
use reth_primitives::{BlockNumberOrTag, U256}; use reth_primitives::{BlockNumberOrTag, U256};
use reth_provider::BlockReaderIdExt; use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider};
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
helpers::{transaction::UpdateRawTxForwarder, EthSigner, SpawnBlocking}, helpers::{transaction::UpdateRawTxForwarder, EthSigner, SpawnBlocking},
RawTransactionForwarder, 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::{ use reth_tasks::{
pool::{BlockingTaskGuard, BlockingTaskPool}, pool::{BlockingTaskGuard, BlockingTaskPool},
TaskSpawner, TokioTaskExecutor, TaskExecutor, TaskSpawner, TokioTaskExecutor,
}; };
use tokio::sync::{AcquireError, Mutex, OwnedSemaphorePermit}; use tokio::sync::{AcquireError, Mutex, OwnedSemaphorePermit};
use crate::eth::DevSigner;
/// `Eth` API implementation. /// `Eth` API implementation.
/// ///
/// This type provides the functionality for handling `eth_` related requests. /// This type provides the functionality for handling `eth_` related requests.
@ -55,66 +56,59 @@ where
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>, raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
proof_permits: usize, proof_permits: usize,
) -> Self { ) -> Self {
Self::with_spawner( let inner = EthApiInner::new(
provider, provider,
pool, pool,
network, network,
eth_cache, eth_cache,
gas_oracle, gas_oracle,
gas_cap.into().into(),
eth_proof_window,
Box::<TokioTaskExecutor>::default(),
blocking_task_pool,
fee_history_cache,
evm_config,
raw_transaction_forwarder,
proof_permits,
)
}
/// 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<Provider>,
gas_cap: u64,
eth_proof_window: u64,
task_spawner: Box<dyn TaskSpawner>,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
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, gas_cap,
eth_proof_window, eth_proof_window,
starting_block: U256::from(latest_block),
task_spawner,
pending_block: Default::default(),
blocking_task_pool, blocking_task_pool,
fee_history_cache, fee_history_cache,
evm_config, evm_config,
raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder), TokioTaskExecutor::default(),
blocking_task_guard: BlockingTaskGuard::new(proof_permits), raw_transaction_forwarder,
}; proof_permits,
);
Self { inner: Arc::new(inner) }
}
}
impl<Provider, Pool, EvmConfig, Network> EthApi<Provider, Pool, Network, EvmConfig>
where
Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static,
Pool: Clone,
EvmConfig: Clone,
Network: Clone,
{
/// Creates a new, shareable instance.
pub fn with_spawner<Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> 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,
ctx.new_fee_history_cache(),
ctx.evm_config.clone(),
ctx.executor.clone(),
None,
ctx.config.proof_permits,
);
Self { inner: Arc::new(inner) } Self { inner: Arc::new(inner) }
} }
@ -163,12 +157,16 @@ where
} }
} }
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> { impl<N, Network> BuilderProvider<N> for EthApi<N::Provider, N::Pool, Network, N::Evm>
/// Generates 20 random developer accounts. where
/// Used in DEV mode. N: FullNodeComponents,
pub fn with_dev_accounts(&self) { Network: Send + Sync + Clone + 'static,
let mut signers = self.inner.signers.write(); {
*signers = DevSigner::random_signers(20); type Ctx<'a> =
&'a EthApiBuilderCtx<N::Provider, N::Pool, N::Evm, Network, TaskExecutor, N::Provider>;
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send> {
Box::new(|ctx| Self::with_spawner(ctx))
} }
} }
@ -209,6 +207,59 @@ pub struct EthApiInner<Provider, Pool, Network, EvmConfig> {
blocking_task_guard: BlockingTaskGuard, blocking_task_guard: BlockingTaskGuard,
} }
impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig>
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<Provider>,
gas_cap: impl Into<GasCap>,
eth_proof_window: u64,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
task_spawner: impl TaskSpawner + 'static,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
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<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> { impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> {
/// Returns a handle to data on disk. /// Returns a handle to data on disk.
#[inline] #[inline]

View File

@ -17,7 +17,7 @@ use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError};
use reth_rpc_eth_api::EthFilterApiServer; use reth_rpc_eth_api::EthFilterApiServer;
use reth_rpc_eth_types::{ use reth_rpc_eth_types::{
logs_utils::{self, append_matching_block_logs}, 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_server_types::ToRpcResult;
use reth_rpc_types::{ 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<u64>,
/// 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<usize>,
/// 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 /// All active filters
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ActiveFilters { pub struct ActiveFilters {

View File

@ -6,12 +6,26 @@ use alloy_dyn_abi::TypedData;
use reth_primitives::{ use reth_primitives::{
eip191_hash_message, sign_message, Address, Signature, TransactionSigned, B256, 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_eth_types::SignError;
use reth_rpc_types::TypedTransactionRequest; use reth_rpc_types::TypedTransactionRequest;
use reth_rpc_types_compat::transaction::to_primitive_transaction; use reth_rpc_types_compat::transaction::to_primitive_transaction;
use secp256k1::SecretKey; use secp256k1::SecretKey;
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> AddDevSigners
for EthApi<Provider, Pool, Network, EvmConfig>
{
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
self.inner.signers()
}
fn with_dev_accounts(&self) {
*self.signers().write() = DevSigner::random_signers(20)
}
}
/// Holds developer keys /// Holds developer keys
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DevSigner { pub struct DevSigner {
@ -22,14 +36,14 @@ pub struct DevSigner {
#[allow(dead_code)] #[allow(dead_code)]
impl DevSigner { impl DevSigner {
/// Generates a random dev signer which satisfies [`EthSigner`] trait /// Generates a random dev signer which satisfies [`EthSigner`] trait
pub(crate) fn random() -> Box<dyn EthSigner> { pub fn random() -> Box<dyn EthSigner> {
let mut signers = Self::random_signers(1); let mut signers = Self::random_signers(1);
signers.pop().expect("expect to generate at least one signer") signers.pop().expect("expect to generate at least one signer")
} }
/// Generates provided number of random dev signers /// Generates provided number of random dev signers
/// which satisfy [`EthSigner`] trait /// which satisfy [`EthSigner`] trait
pub(crate) fn random_signers(num: u32) -> Vec<Box<dyn EthSigner + 'static>> { pub fn random_signers(num: u32) -> Vec<Box<dyn EthSigner + 'static>> {
let mut signers = Vec::new(); let mut signers = Vec::new();
for _ in 0..num { for _ in 0..num {
let (sk, pk) = secp256k1::generate_keypair(&mut rand::thread_rng()); let (sk, pk) = secp256k1::generate_keypair(&mut rand::thread_rng());

View File

@ -9,9 +9,9 @@ pub mod pubsub;
/// Implementation of `eth` namespace API. /// Implementation of `eth` namespace API.
pub use bundle::EthBundle; pub use bundle::EthBundle;
pub use core::EthApi; pub use core::EthApi;
pub use filter::{EthFilter, EthFilterConfig}; pub use filter::EthFilter;
pub use pubsub::EthPubSub; pub use pubsub::EthPubSub;
pub use helpers::signer::DevSigner; pub use helpers::signer::DevSigner;
pub use reth_rpc_eth_api::RawTransactionForwarder; pub use reth_rpc_eth_api::{EthApiServer, RawTransactionForwarder};

View File

@ -46,7 +46,8 @@ use reth_node_api::{
}; };
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
use reth_node_ethereum::node::{ use reth_node_ethereum::node::{
EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder, EthereumAddOns, EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder,
EthereumPoolBuilder,
}; };
use reth_payload_builder::{ use reth_payload_builder::{
error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle,
@ -212,8 +213,9 @@ where
EthereumExecutorBuilder, EthereumExecutorBuilder,
EthereumConsensusBuilder, EthereumConsensusBuilder,
>; >;
type AddOns = EthereumAddOns;
fn components_builder(self) -> Self::ComponentsBuilder { fn components_builder(&self) -> Self::ComponentsBuilder {
ComponentsBuilder::default() ComponentsBuilder::default()
.node_types::<N>() .node_types::<N>()
.pool(EthereumPoolBuilder::default()) .pool(EthereumPoolBuilder::default())

View File

@ -22,7 +22,7 @@ use reth_chainspec::{Chain, ChainSpec, Head};
use reth_evm_ethereum::EthEvmConfig; use reth_evm_ethereum::EthEvmConfig;
use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes};
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; 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::{ use reth_primitives::{
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
Address, Header, TransactionSigned, U256, Address, Header, TransactionSigned, U256,
@ -180,6 +180,7 @@ async fn main() -> eyre::Result<()> {
.with_types::<EthereumNode>() .with_types::<EthereumNode>()
// use default ethereum components but with our executor // use default ethereum components but with our executor
.with_components(EthereumNode::components().executor(MyExecutorBuilder::default())) .with_components(EthereumNode::components().executor(MyExecutorBuilder::default()))
.with_add_ons::<EthereumAddOns>()
.launch() .launch()
.await .await
.unwrap(); .unwrap();

View File

@ -10,7 +10,7 @@ use reth::{
blobstore::InMemoryBlobStore, EthTransactionPool, TransactionValidationTaskExecutor, blobstore::InMemoryBlobStore, EthTransactionPool, TransactionValidationTaskExecutor,
}, },
}; };
use reth_node_ethereum::EthereumNode; use reth_node_ethereum::{node::EthereumAddOns, EthereumNode};
use reth_tracing::tracing::{debug, info}; use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::PoolConfig; use reth_transaction_pool::PoolConfig;
@ -23,6 +23,7 @@ fn main() {
// Configure the components of the node // Configure the components of the node
// use default ethereum components but use our custom pool // use default ethereum components but use our custom pool
.with_components(EthereumNode::components().pool(CustomPoolBuilder::default())) .with_components(EthereumNode::components().pool(CustomPoolBuilder::default()))
.with_add_ons::<EthereumAddOns>()
.launch() .launch()
.await?; .await?;

View File

@ -20,7 +20,7 @@ use reth::{
transaction_pool::TransactionPool, transaction_pool::TransactionPool,
}; };
use reth_basic_payload_builder::BasicPayloadJobGeneratorConfig; 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; use reth_payload_builder::PayloadBuilderService;
pub mod generator; pub mod generator;
@ -78,6 +78,7 @@ fn main() {
.with_components( .with_components(
EthereumNode::components().payload(CustomPayloadBuilder::default()), EthereumNode::components().payload(CustomPayloadBuilder::default()),
) )
.with_add_ons::<EthereumAddOns>()
.launch() .launch()
.await?; .await?;

View File

@ -19,6 +19,7 @@ use reth::{
providers::{BlockchainProvider, StaticFileProvider}, providers::{BlockchainProvider, StaticFileProvider},
ProviderFactory, ProviderFactory,
}, },
rpc::eth::EthApi,
utils::open_db_read_only, utils::open_db_read_only,
}; };
use reth_chainspec::ChainSpecBuilder; use reth_chainspec::ChainSpecBuilder;
@ -27,7 +28,7 @@ use reth_db_api::models::ClientVersion;
// Bringing up the RPC // Bringing up the RPC
use reth::rpc::builder::{ 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. // Configuring the network parts, ideally also wouldn't need to think about this.
use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; use myrpc_ext::{MyRpcExt, MyRpcExtApiServer};
@ -70,7 +71,7 @@ async fn main() -> eyre::Result<()> {
// Pick which namespaces to expose. // Pick which namespaces to expose.
let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); 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 // Add a custom rpc namespace
let custom_rpc = MyRpcExt { provider }; let custom_rpc = MyRpcExt { provider };

View File

@ -21,7 +21,7 @@ use reth::{
use reth_chainspec::{Chain, ChainSpec}; use reth_chainspec::{Chain, ChainSpec};
use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes};
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; 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::{ use reth_primitives::{
revm_primitives::{SpecId, StatefulPrecompileMut}, revm_primitives::{SpecId, StatefulPrecompileMut},
Header, TransactionSigned, Header, TransactionSigned,
@ -244,6 +244,7 @@ async fn main() -> eyre::Result<()> {
.with_types::<EthereumNode>() .with_types::<EthereumNode>()
// use default ethereum components but with our executor // use default ethereum components but with our executor
.with_components(EthereumNode::components().executor(MyExecutorBuilder::default())) .with_components(EthereumNode::components().executor(MyExecutorBuilder::default()))
.with_add_ons::<EthereumAddOns>()
.launch() .launch()
.await .await
.unwrap(); .unwrap();