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

View File

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

View File

@ -1,16 +1,19 @@
use std::sync::Arc;
use node::NodeTestContext;
use reth::{
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
builder::{NodeBuilder, NodeConfig, NodeHandle},
rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer},
tasks::TaskManager,
};
use reth_chainspec::ChainSpec;
use reth_db::{test_utils::TempDatabase, DatabaseEnv};
use reth_node_builder::{
components::NodeComponentsBuilder, FullNodeTypesAdapter, Node, NodeAdapter, RethFullAdapter,
components::NodeComponentsBuilder, rpc::EthApiBuilderProvider, FullNodeTypesAdapter, Node,
NodeAdapter, NodeAddOns, RethFullAdapter,
};
use reth_provider::providers::BlockchainProvider;
use std::sync::Arc;
use tracing::{span, Level};
use wallet::Wallet;
@ -42,9 +45,11 @@ pub async fn setup<N>(
num_nodes: usize,
chain_spec: Arc<ChainSpec>,
is_dev: bool,
) -> eyre::Result<(Vec<NodeHelperType<N>>, TaskManager, Wallet)>
) -> eyre::Result<(Vec<NodeHelperType<N, N::AddOns>>, TaskManager, Wallet)>
where
N: Default + Node<TmpNodeAdapter<N>>,
<N::AddOns as NodeAddOns<Adapter<N>>>::EthApi:
FullEthApiServer + AddDevSigners + EthApiBuilderProvider<Adapter<N>>,
{
let tasks = TaskManager::current();
let exec = tasks.executor();
@ -55,7 +60,7 @@ where
};
// 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 {
let node_config = NodeConfig::test()
@ -106,4 +111,4 @@ type Adapter<N> = NodeAdapter<
>;
/// 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::{
engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext,
rpc::RpcTestContext, traits::PayloadEnvelopeExt,
};
use std::{marker::PhantomData, pin::Pin};
use alloy_rpc_types::BlockNumberOrTag;
use eyre::Ok;
@ -11,32 +8,41 @@ use reth::{
builder::FullNode,
payload::PayloadTypes,
providers::{BlockReader, BlockReaderIdExt, CanonStateSubscriptions, StageCheckpointReader},
rpc::types::engine::PayloadStatusEnum,
rpc::{
api::eth::helpers::{EthApiSpec, EthTransactions, TraceExt},
types::engine::PayloadStatusEnum,
},
};
use reth_node_builder::NodeTypes;
use reth_node_builder::{NodeAddOns, NodeTypes};
use reth_primitives::{BlockHash, BlockNumber, Bytes, B256};
use reth_stages_types::StageId;
use std::{marker::PhantomData, pin::Pin};
use tokio_stream::StreamExt;
use crate::{
engine_api::EngineApiTestContext, network::NetworkTestContext, payload::PayloadTestContext,
rpc::RpcTestContext, traits::PayloadEnvelopeExt,
};
/// An helper struct to handle node actions
pub struct NodeTestContext<Node>
pub struct NodeTestContext<Node, AddOns>
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
pub inner: FullNode<Node>,
pub inner: FullNode<Node, AddOns>,
pub payload: PayloadTestContext<Node::Engine>,
pub network: NetworkTestContext,
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
Node: FullNodeComponents,
AddOns: NodeAddOns<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();
Ok(Self {
@ -53,7 +59,7 @@ where
}
/// 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;
node.network.next_session_established().await;
self.network.next_session_established().await;
@ -77,6 +83,7 @@ where
where
<Node::Engine as EngineTypes>::ExecutionPayloadV3:
From<<Node::Engine as PayloadTypes>::BuiltPayload> + PayloadEnvelopeExt,
AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt,
{
let mut chain = Vec::with_capacity(length as usize);
for i in 0..length {

View File

@ -3,17 +3,23 @@ use alloy_network::eip2718::Decodable2718;
use reth::{
builder::{rpc::RpcRegistry, FullNodeComponents},
rpc::{
api::{eth::helpers::EthTransactions, DebugApiServer},
api::{
eth::helpers::{EthApiSpec, EthTransactions, TraceExt},
DebugApiServer,
},
server_types::eth::EthResult,
},
};
use reth_primitives::{Bytes, B256};
pub struct RpcTestContext<Node: FullNodeComponents> {
pub inner: RpcRegistry<Node>,
pub struct RpcTestContext<Node: FullNodeComponents, EthApi> {
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
pub async fn inject_tx(&mut self, raw_tx: Bytes) -> EthResult<B256> {
let eth_api = self.inner.eth_api();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
//! Traits for configuring a node.
use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes};
use std::marker::PhantomData;
use reth_db_api::{
database::Database,
database_metrics::{DatabaseMetadata, DatabaseMetrics},
@ -11,7 +12,8 @@ use reth_payload_builder::PayloadBuilderHandle;
use reth_provider::FullProvider;
use reth_tasks::TaskExecutor;
use reth_transaction_pool::TransactionPool;
use std::marker::PhantomData;
use crate::{primitives::NodePrimitives, ConfigureEvm, EngineTypes};
/// The type that configures the essential types of an ethereum like node.
///
@ -145,3 +147,34 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static {
/// Returns the task executor.
fn task_executor(&self) -> &TaskExecutor;
}
/// Customizable node add-on types.
pub trait NodeAddOns<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-engine-util.workspace = true
reth-cli-util.workspace = true
reth-rpc-eth-types.workspace = true
## async
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)]
use crate::{
common::WithConfigs,
components::NodeComponentsBuilder,
node::FullNode,
rpc::{RethRpcServerHandles, RpcContext},
DefaultNodeLauncher, Node, NodeHandle,
};
pub mod add_ons;
mod states;
pub use states::*;
use std::sync::Arc;
use futures::Future;
use reth_chainspec::ChainSpec;
use reth_cli_util::get_secret_key;
@ -20,23 +20,28 @@ use reth_exex::ExExContext;
use reth_network::{
NetworkBuilder, NetworkConfig, NetworkConfigBuilder, NetworkHandle, NetworkManager,
};
use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeTypes};
use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes};
use reth_node_core::{
cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig},
dirs::{ChainPath, DataDirPath},
node_config::NodeConfig,
primitives::Head,
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
};
use reth_primitives::revm_primitives::EnvKzgSettings;
use reth_provider::{providers::BlockchainProvider, ChainSpecProvider};
use reth_tasks::TaskExecutor;
use reth_transaction_pool::{PoolConfig, TransactionPool};
use secp256k1::SecretKey;
pub use states::*;
use std::sync::Arc;
use tracing::{info, trace, warn};
mod states;
use crate::{
common::WithConfigs,
components::NodeComponentsBuilder,
node::FullNode,
rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext},
DefaultNodeLauncher, Node, NodeHandle,
};
/// The adapter type for a reth node with the builtin provider type
// Note: we need to hardcode this because custom components might depend on it in associated types.
@ -212,11 +217,11 @@ where
pub fn node<N>(
self,
node: N,
) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder>
) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>
where
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>(
self,
node: N,
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder>>
) -> WithLaunchContext<
NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
>
where
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]
@ -280,10 +287,22 @@ where
RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>,
N::AddOns,
>,
>
where
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
}
@ -298,7 +317,7 @@ where
pub fn with_components<CB>(
self,
components_builder: CB,
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB>>
) -> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, ()>>
where
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
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypes,
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.
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
where
F: FnOnce(
FullNode<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
FullNode<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO>,
) -> eyre::Result<()>
+ Send
+ 'static,
@ -344,7 +387,7 @@ where
pub fn on_rpc_started<F>(self, hook: F) -> Self
where
F: FnOnce(
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO::EthApi>,
RethRpcServerHandles,
) -> eyre::Result<()>
+ Send
@ -357,7 +400,7 @@ where
pub fn extend_rpc_modules<F>(self, hook: F) -> Self
where
F: FnOnce(
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
RpcContext<'_, NodeAdapter<RethFullAdapter<DB, T>, CB::Components>, AO::EthApi>,
) -> eyre::Result<()>
+ Send
+ '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
///
/// 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.
pub struct BuilderContext<Node: FullNodeTypes> {
/// 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
//! before the node can be launched.
use crate::{
components::{NodeComponents, NodeComponentsBuilder},
exex::BoxedLaunchExEx,
hooks::NodeHooks,
launch::LaunchNode,
rpc::{RethRpcServerHandles, RpcContext, RpcHooks},
FullNode,
};
use std::{fmt, future::Future, marker::PhantomData};
use reth_exex::ExExContext;
use reth_network::NetworkHandle;
use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes};
use reth_node_core::node_config::NodeConfig;
use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypes};
use reth_node_core::{
node_config::NodeConfig,
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
};
use reth_payload_builder::PayloadBuilderHandle;
use reth_tasks::TaskExecutor;
use 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.
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
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
CB: NodeComponentsBuilder<T>,
{
@ -46,9 +50,9 @@ impl<T: FullNodeTypes> NodeBuilderWithTypes<T> {
config,
adapter,
components_builder,
add_ons: NodeAddOns {
add_ons: AddOns {
hooks: NodeHooks::default(),
rpc: RpcHooks::new(),
rpc: RpcAddOns { _eth_api: PhantomData::<()>, hooks: RpcHooks::default() },
exexs: Vec::new(),
},
}
@ -142,7 +146,11 @@ impl<T: FullNodeTypes, C: NodeComponents<T>> Clone for NodeAdapter<T, C> {
/// A fully type configured node builder.
///
/// 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.
pub(crate) config: NodeConfig,
/// Adapter for the underlying node types and database
@ -150,10 +158,41 @@ pub struct NodeBuilderWithComponents<T: FullNodeTypes, CB: NodeComponentsBuilder
/// container for type specific components
pub(crate) components_builder: CB,
/// 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.
pub fn on_component_initialized<F>(mut self, hook: F) -> Self
where
@ -166,7 +205,9 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
/// Sets the hook that is run once the node has started.
pub fn on_node_started<F>(mut self, hook: F) -> Self
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
@ -176,24 +217,24 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
pub fn on_rpc_started<F>(mut self, hook: F) -> Self
where
F: FnOnce(
RpcContext<'_, NodeAdapter<T, CB::Components>>,
RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>,
RethRpcServerHandles,
) -> eyre::Result<()>
+ Send
+ 'static,
{
self.add_ons.rpc.set_on_rpc_started(hook);
self.add_ons.rpc.hooks.set_on_rpc_started(hook);
self
}
/// Sets the hook that is run to configure the rpc modules.
pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
where
F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>>) -> eyre::Result<()>
F: FnOnce(RpcContext<'_, NodeAdapter<T, CB::Components>, AO::EthApi>) -> eyre::Result<()>
+ Send
+ 'static,
{
self.add_ons.rpc.set_extend_rpc_modules(hook);
self.add_ons.rpc.hooks.set_extend_rpc_modules(hook);
self
}
@ -212,14 +253,6 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
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.
pub fn launch_with_fn<L, R>(self, launcher: L) -> R
where
@ -236,12 +269,19 @@ impl<T: FullNodeTypes, CB: NodeComponentsBuilder<T>> NodeBuilderWithComponents<T
}
}
/// Additional node extensions.
pub(crate) struct NodeAddOns<Node: FullNodeComponents> {
/// Additional `NodeHooks` that are called at specific points in the node's launch lifecycle.
pub(crate) hooks: NodeHooks<Node>,
/// Additional RPC hooks.
pub(crate) rpc: RpcHooks<Node>,
/// The `ExExs` (execution extensions) of the node.
pub(crate) exexs: Vec<(String, Box<dyn BoxedLaunchExEx<Node>>)>,
impl<T, CB, AO> NodeBuilderWithComponents<T, CB, AO>
where
T: FullNodeTypes,
CB: NodeComponentsBuilder<T>,
AO: NodeAddOns<NodeAdapter<T, CB::Components>>,
AO::EthApi:
EthApiBuilderProvider<NodeAdapter<T, CB::Components>> + FullEthApiServer + AddDevSigners,
{
/// 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`]
use std::{future::Future, marker::PhantomData};
use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_transaction_pool::TransactionPool;
use crate::{
components::{
Components, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, NodeComponents,
@ -7,10 +13,6 @@ use crate::{
},
BuilderContext, ConfigureEvm, FullNodeTypes,
};
use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_transaction_pool::TransactionPool;
use std::{future::Future, marker::PhantomData};
/// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation.
///

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 reth_node_api::{FullNodeComponents, NodeAddOns};
use reth_node_core::exit::NodeExitFuture;
use crate::node::FullNode;
/// A Handle to the launched node.
#[must_use = "Needs to await the node exit future"]
pub struct NodeHandle<Node: FullNodeComponents> {
pub struct NodeHandle<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
/// All node components.
pub node: FullNode<Node>,
pub node: FullNode<Node, AddOns>,
/// The exit future of the node.
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.
pub async fn wait_for_node_exit(self) -> eyre::Result<()> {
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 {
f.debug_struct("NodeHandle")
.field("node", &"...")

View File

@ -1,17 +1,25 @@
use crate::node::FullNode;
use reth_node_api::FullNodeComponents;
use std::fmt;
use reth_node_api::{FullNodeComponents, NodeAddOns};
use crate::node::FullNode;
/// Container for all the configurable hook functions.
pub(crate) struct NodeHooks<Node: FullNodeComponents> {
pub(crate) on_component_initialized: Box<dyn OnComponentInitializedHook<Node>>,
pub(crate) on_node_started: Box<dyn OnNodeStartedHook<Node>>,
pub(crate) _marker: std::marker::PhantomData<Node>,
pub struct NodeHooks<Node: FullNodeComponents, AddOns: NodeAddOns<Node>> {
/// Hook to run once core components are initialized.
pub on_component_initialized: Box<dyn OnComponentInitializedHook<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.
pub(crate) fn new() -> Self {
pub fn new() -> Self {
Self {
on_component_initialized: Box::<()>::default(),
on_node_started: Box::<()>::default(),
@ -41,7 +49,7 @@ impl<Node: FullNodeComponents> NodeHooks<Node> {
/// 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
where
F: OnNodeStartedHook<Node> + 'static,
F: OnNodeStartedHook<Node, AddOns> + 'static,
{
self.on_node_started = Box::new(hook);
self
@ -51,19 +59,27 @@ impl<Node: FullNodeComponents> NodeHooks<Node> {
#[allow(unused)]
pub(crate) fn on_node_started<F>(mut self, hook: F) -> Self
where
F: OnNodeStartedHook<Node> + 'static,
F: OnNodeStartedHook<Node, AddOns> + 'static,
{
self.set_on_node_started(hook);
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 {
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 {
f.debug_struct("NodeHooks")
.field("on_component_initialized", &"...")
@ -90,19 +106,20 @@ where
}
/// A helper trait that is run once the node is started.
pub trait OnNodeStartedHook<Node: FullNodeComponents>: Send {
pub trait OnNodeStartedHook<Node: FullNodeComponents, AddOns: NodeAddOns<Node>>: Send {
/// Consumes the event hook and runs it.
///
/// 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
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)
}
}
@ -113,8 +130,12 @@ impl<Node> OnComponentInitializedHook<Node> for () {
}
}
impl<Node: FullNodeComponents> OnNodeStartedHook<Node> for () {
fn on_event(self: Box<Self>, _node: FullNode<Node>) -> eyre::Result<()> {
impl<Node, AddOns> OnNodeStartedHook<Node, AddOns> for ()
where
Node: FullNodeComponents,
AddOns: NodeAddOns<Node>,
{
fn on_event(self: Box<Self>, _node: FullNode<Node, AddOns>) -> eyre::Result<()> {
Ok(())
}
}

View File

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

View File

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

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

View File

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

View File

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

View File

@ -1,15 +1,18 @@
use std::sync::Arc;
use alloy_genesis::Genesis;
use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager};
use reth_chainspec::{ChainSpecBuilder, BASE_MAINNET};
use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType};
use reth_node_optimism::{OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes};
use reth_node_optimism::{
node::OptimismAddOns, OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes,
};
use reth_payload_builder::EthPayloadBuilderAttributes;
use reth_primitives::{Address, B256};
use std::sync::Arc;
use tokio::sync::Mutex;
/// Optimism Node Helper type
pub(crate) type OpNode = NodeHelperType<OptimismNode>;
pub(crate) type OpNode = NodeHelperType<OptimismNode, OptimismAddOns>;
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();

View File

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

View File

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

View File

@ -12,9 +12,15 @@ use alloy_primitives::{Address, U64};
use reth_chainspec::{ChainInfo, ChainSpec};
use reth_errors::RethResult;
use reth_evm::ConfigureEvm;
use reth_node_api::{BuilderProvider, FullNodeComponents};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderFactory};
use reth_rpc_eth_api::helpers::{
Call, EthApiSpec, EthCall, EthFees, EthState, LoadFee, LoadState, SpawnBlocking, Trace,
use reth_rpc::eth::DevSigner;
use reth_rpc_eth_api::{
helpers::{
AddDevSigners, Call, EthApiSpec, EthCall, EthFees, EthSigner, EthState, LoadFee, LoadState,
SpawnBlocking, Trace, UpdateRawTxForwarder,
},
RawTransactionForwarder,
};
use reth_rpc_eth_types::EthStateCache;
use reth_rpc_types::SyncStatus;
@ -154,3 +160,31 @@ impl<Eth: Trace> Trace for OpEthApi<Eth> {
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-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-tokio-util.workspace = true
reth-node-api.workspace = true
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
serde_json.workspace = true

View File

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

View File

@ -1,31 +1,14 @@
use std::{fmt::Debug, time::Duration};
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_provider::{
BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider,
FullRpcProvider, StateProviderFactory,
};
use reth_rpc::{eth::EthFilterConfig, EthApi, EthFilter, EthPubSub};
use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory};
use reth_rpc::{EthFilter, EthPubSub};
use reth_rpc_eth_types::{
cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache,
EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP,
cache::cache_new_blocks_task, EthApiBuilderCtx, EthConfig, EthStateCache,
};
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 reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
use reth_transaction_pool::TransactionPool;
use serde::{Deserialize, Serialize};
use reth_tasks::TaskSpawner;
/// Default value for stale filter ttl
const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60);
/// Alias for function that builds the core `eth` namespace API.
pub type EthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> =
Box<dyn FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi>;
/// Alias for `eth` namespace API builder.
pub type DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> =
Box<dyn Fn(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi>;
/// Handlers for core, filter and pubsub `eth` namespace APIs.
#[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> {
/// Returns a new [`EthHandlers`] builder.
#[allow(clippy::too_many_arguments)]
pub fn builder<EvmConfig, Tasks, EthApiB>(
pub fn builder<EvmConfig, Tasks>(
provider: Provider,
pool: Pool,
network: Network,
@ -51,12 +34,16 @@ impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Networ
config: EthConfig,
executor: Tasks,
events: Events,
eth_api_builder: EthApiB,
) -> EthHandlersBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi>
where
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
{
eth_api_builder: DynEthApiBuilder<
Provider,
Pool,
EvmConfig,
Network,
Tasks,
Events,
EthApi,
>,
) -> EthHandlersBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi> {
EthHandlersBuilder {
provider,
pool,
@ -65,7 +52,7 @@ impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Networ
config,
executor,
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,
executor: Tasks,
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>
@ -89,9 +76,10 @@ where
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static,
Pool: Send + Sync + Clone + 'static,
EvmConfig: ConfigureEvm,
Network: Clone,
Network: Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone,
Events: CanonStateSubscriptions + Clone + 'static,
EthApi: 'static,
{
/// Returns a new instance with handlers for `eth` namespace.
pub fn build(self) -> EthHandlers<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).
#[derive(Debug)]
pub struct EthFilterApiBuilder;
@ -348,50 +172,3 @@ impl EthPubSubApiBuilder {
)
}
}
/// Builds `eth_` core api component [`GasPriceOracle`], for given context.
#[derive(Debug)]
pub struct GasPriceOracleBuilder;
impl GasPriceOracleBuilder {
/// Builds a [`GasPriceOracle`], for given context.
pub fn build<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_network_api::{NetworkInfo, Peers};
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_builder::{
//! EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder,
//! TransportRpcModuleConfig,
//! RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig,
//! };
//!
//! use reth_tasks::TokioTaskExecutor;
//! use reth_transaction_pool::TransactionPool;
//!
//! pub async fn launch<Provider, Pool, Network, Events, EvmConfig>(
//! provider: Provider,
//! pool: Pool,
@ -54,7 +54,7 @@
//! events,
//! evm_config,
//! )
//! .build(transports, EthApiBuild::build);
//! .build(transports, Box::new(EthApi::with_spawner));
//! let handle = RpcServerConfig::default()
//! .with_http(ServerBuilder::default())
//! .start(&transport_modules)
@ -70,9 +70,10 @@
//! use reth_evm::ConfigureEvm;
//! use reth_network_api::{NetworkInfo, Peers};
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_api::EngineApiServer;
//! use reth_rpc_builder::{
//! auth::AuthServerConfig, EthApiBuild, RethRpcModule, RpcModuleBuilder, RpcServerConfig,
//! auth::AuthServerConfig, RethRpcModule, RpcModuleBuilder, RpcServerConfig,
//! TransportRpcModuleConfig,
//! };
//! use reth_rpc_layer::JwtSecret;
@ -113,7 +114,7 @@
//!
//! // configure the server modules
//! let (modules, auth_module, _registry) =
//! builder.build_with_auth_server(transports, engine_api, EthApiBuild::build);
//! builder.build_with_auth_server(transports, engine_api, Box::new(EthApi::with_spawner));
//!
//! // start the servers
//! let auth_config = AuthServerConfig::builder(JwtSecret::random()).build();
@ -140,6 +141,7 @@ use std::{
};
use error::{ConflictingModules, RpcError, ServerKind};
use eth::DynEthApiBuilder;
use http::{header::AUTHORIZATION, HeaderMap};
use jsonrpsee::{
core::RegisterMethodError,
@ -167,7 +169,7 @@ use reth_rpc_eth_api::{
},
EthApiServer, FullEthApiServer, RawTransactionForwarder,
};
use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider};
use reth_rpc_eth_types::{EthConfig, EthStateCache, EthSubscriptionIdProvider};
use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret};
use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
@ -202,17 +204,14 @@ pub mod error;
/// Eth utils
pub mod eth;
pub use eth::{
EthApiBuild, EthApiBuilderCtx, EthConfig, EthHandlers, FeeHistoryCacheBuilder,
GasPriceOracleBuilder,
};
pub use eth::EthHandlers;
// Rpc server metrics
mod metrics;
/// Convenience function for starting a server in one step.
#[allow(clippy::too_many_arguments)]
pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi, EthApiB>(
pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi>(
provider: Provider,
pool: Pool,
network: Network,
@ -221,7 +220,7 @@ pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi, E
executor: Tasks,
events: Events,
evm_config: EvmConfig,
eth: EthApiB,
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> Result<RpcServerHandle, RpcError>
where
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
@ -230,8 +229,6 @@ where
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
EvmConfig: ConfigureEvm,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer,
{
let module_config = module_config.into();
@ -426,11 +423,11 @@ where
/// also configures the auth (engine api) server, which exposes a subset of the `eth_`
/// namespace.
#[allow(clippy::type_complexity)]
pub fn build_with_auth_server<EngineApi, EngineT, EthApi, EthApiB>(
pub fn build_with_auth_server<EngineApi, EngineT, EthApi>(
self,
module_config: TransportRpcModuleConfig,
engine: EngineApi,
eth: EthApiB,
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> (
TransportRpcModules,
AuthRpcModule,
@ -439,8 +436,6 @@ where
where
EngineT: EngineTypes + 'static,
EngineApi: EngineApiServer<EngineT>,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer,
{
let Self { provider, pool, network, executor, events, evm_config } = self;
@ -469,7 +464,8 @@ where
/// use reth_evm::ConfigureEvm;
/// use reth_network_api::noop::NoopNetwork;
/// use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions};
/// use reth_rpc_builder::{EthApiBuild, RpcModuleBuilder};
/// use reth_rpc::EthApi;
/// use reth_rpc_builder::RpcModuleBuilder;
/// use reth_tasks::TokioTaskExecutor;
/// use reth_transaction_pool::noop::NoopTransactionPool;
///
@ -481,19 +477,18 @@ where
/// .with_executor(TokioTaskExecutor::default())
/// .with_events(TestCanonStateSubscriptions::default())
/// .with_evm_config(evm)
/// .into_registry(Default::default(), EthApiBuild::build);
/// .into_registry(Default::default(), Box::new(EthApi::with_spawner));
///
/// let eth_api = registry.eth_api();
/// }
/// ```
pub fn into_registry<EthApi, EthApiB>(
pub fn into_registry<EthApi>(
self,
config: RpcModuleConfig,
eth: EthApiB,
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: 'static,
{
let Self { provider, pool, network, executor, events, evm_config } = self;
RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth)
@ -501,14 +496,12 @@ where
/// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
/// be used to start the transport server(s).
pub fn build<EthApi, EthApiB>(
pub fn build<EthApi>(
self,
module_config: TransportRpcModuleConfig,
eth: EthApiB,
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> TransportRpcModules<()>
where
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
EthApi: FullEthApiServer,
{
let mut modules = TransportRpcModules::default();
@ -636,13 +629,14 @@ impl<Provider, Pool, Network, Tasks, Events, EthApi>
where
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static,
Pool: Send + Sync + Clone + 'static,
Network: Clone,
Events: CanonStateSubscriptions + Clone,
Network: Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
EthApi: 'static,
{
/// Creates a new, empty instance.
#[allow(clippy::too_many_arguments)]
pub fn new<EvmConfig, EthApiB>(
pub fn new<EvmConfig>(
provider: Provider,
pool: Pool,
network: Network,
@ -650,12 +644,18 @@ where
events: Events,
config: RpcModuleConfig,
evm_config: EvmConfig,
eth_api_builder: EthApiB,
eth_api_builder: DynEthApiBuilder<
Provider,
Pool,
EvmConfig,
Network,
Tasks,
Events,
EthApi,
>,
) -> Self
where
EvmConfig: ConfigureEvm,
EthApiB: FnOnce(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi
+ 'static,
{
let blocking_pool_guard = BlockingTaskGuard::new(config.eth.max_tracing_requests);

View File

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

View File

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

View File

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

View File

@ -37,3 +37,14 @@ pub trait EthSigner: Send + Sync + DynClone {
}
dyn_clone::clone_trait_object!(EthSigner);
/// Adds 20 random dev signers for access via the API. Used in dev mode.
#[auto_impl::auto_impl(&)]
pub trait AddDevSigners {
/// Returns a handle to the signers.
fn signers(&self) -> &parking_lot::RwLock<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(not(test), warn(unused_crate_dependencies))]
pub mod builder;
pub mod cache;
pub mod error;
pub mod fee_history;
@ -20,6 +21,10 @@ pub mod revm_utils;
pub mod transaction;
pub mod utils;
pub use builder::{
config::{EthConfig, EthFilterConfig},
ctx::EthApiBuilderCtx,
};
pub use cache::{
config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache,
EthStateCache,

View File

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

View File

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

View File

@ -17,7 +17,7 @@ use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError};
use reth_rpc_eth_api::EthFilterApiServer;
use reth_rpc_eth_types::{
logs_utils::{self, append_matching_block_logs},
EthApiError, EthFilterError, EthStateCache, EthSubscriptionIdProvider,
EthApiError, EthFilterConfig, EthFilterError, EthStateCache, EthSubscriptionIdProvider,
};
use reth_rpc_server_types::ToRpcResult;
use reth_rpc_types::{
@ -515,56 +515,6 @@ where
}
}
/// Config for the filter
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EthFilterConfig {
/// Maximum number of blocks that a filter can scan for logs.
///
/// If `None` then no limit is enforced.
pub max_blocks_per_filter: Option<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
#[derive(Debug, Clone, Default)]
pub struct ActiveFilters {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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