mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
feat: declarative builder v2 (#6447)
Co-authored-by: Oliver Nordbjerg <onbjerg@users.noreply.github.com>
This commit is contained in:
41
Cargo.lock
generated
41
Cargo.lock
generated
@@ -6368,6 +6368,38 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-node-builder"
|
||||
version = "0.1.0-alpha.17"
|
||||
dependencies = [
|
||||
"confy",
|
||||
"eyre",
|
||||
"fdlimit",
|
||||
"futures",
|
||||
"reth-auto-seal-consensus",
|
||||
"reth-beacon-consensus",
|
||||
"reth-blockchain-tree",
|
||||
"reth-config",
|
||||
"reth-db",
|
||||
"reth-interfaces",
|
||||
"reth-network",
|
||||
"reth-node-api",
|
||||
"reth-node-core",
|
||||
"reth-payload-builder",
|
||||
"reth-primitives",
|
||||
"reth-provider",
|
||||
"reth-prune",
|
||||
"reth-revm",
|
||||
"reth-rpc",
|
||||
"reth-rpc-engine-api",
|
||||
"reth-snapshot",
|
||||
"reth-stages",
|
||||
"reth-tasks",
|
||||
"reth-tracing",
|
||||
"reth-transaction-pool",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-node-core"
|
||||
version = "0.1.0-alpha.18"
|
||||
@@ -6441,10 +6473,19 @@ dependencies = [
|
||||
name = "reth-node-ethereum"
|
||||
version = "0.1.0-alpha.18"
|
||||
dependencies = [
|
||||
"eyre",
|
||||
"reth-basic-payload-builder",
|
||||
"reth-db",
|
||||
"reth-ethereum-payload-builder",
|
||||
"reth-network",
|
||||
"reth-node-api",
|
||||
"reth-node-builder",
|
||||
"reth-payload-builder",
|
||||
"reth-primitives",
|
||||
"reth-provider",
|
||||
"reth-rpc-types",
|
||||
"reth-tracing",
|
||||
"reth-transaction-pool",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ members = [
|
||||
"crates/rpc/rpc-types/",
|
||||
"crates/rpc/rpc-types-compat/",
|
||||
"crates/node-ethereum/",
|
||||
"crates/node-builder/",
|
||||
"crates/node-optimism/",
|
||||
"crates/node-core/",
|
||||
"crates/node-api/",
|
||||
@@ -125,6 +126,7 @@ reth-consensus-common = { path = "crates/consensus/common" }
|
||||
reth-db = { path = "crates/storage/db" }
|
||||
reth-discv4 = { path = "crates/net/discv4" }
|
||||
reth-dns-discovery = { path = "crates/net/dns" }
|
||||
reth-node-builder = { path = "crates/node-builder" }
|
||||
reth-node-ethereum = { path = "crates/node-ethereum" }
|
||||
reth-node-optimism = { path = "crates/node-optimism" }
|
||||
reth-node-core = { path = "crates/node-core" }
|
||||
@@ -269,4 +271,4 @@ similar-asserts = "1.5.0"
|
||||
|
||||
[workspace.metadata.cargo-udeps.ignore]
|
||||
# ignored because this is mutually exclusive with the optimism payload builder via feature flags
|
||||
normal = ["reth-ethereum-payload-builder"]
|
||||
normal = ["reth-ethereum-payload-builder", "reth-node-ethereum"]
|
||||
|
||||
@@ -161,6 +161,7 @@ optimism = [
|
||||
"reth-payload-builder/optimism",
|
||||
"reth-optimism-payload-builder/optimism",
|
||||
"reth-ethereum-payload-builder/optimism",
|
||||
"reth-node-ethereum/optimism",
|
||||
"dep:reth-node-optimism",
|
||||
"reth-node-core/optimism",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! This contains the [EngineTypes] trait and implementations for ethereum mainnet types.
|
||||
|
||||
use core::fmt;
|
||||
use reth_primitives::{ChainSpec, Hardfork};
|
||||
|
||||
/// Contains traits to abstract over payload attributes types and default implementations of the
|
||||
@@ -15,8 +16,10 @@ pub use error::AttributesValidationError;
|
||||
pub mod payload;
|
||||
pub use payload::PayloadOrAttributes;
|
||||
|
||||
/// The types that are used by the engine.
|
||||
pub trait EngineTypes: serde::de::DeserializeOwned + Send + Sync + Clone {
|
||||
/// The types that are used by the engine API.
|
||||
pub trait EngineTypes:
|
||||
serde::de::DeserializeOwned + fmt::Debug + Unpin + Send + Sync + Clone
|
||||
{
|
||||
/// The RPC payload attributes type the CL node emits via the engine API.
|
||||
type PayloadAttributes: PayloadAttributes + Unpin;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use reth_primitives::{revm::env::fill_block_env, Address, ChainSpec, Header, Transaction, U256};
|
||||
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId, TxEnv};
|
||||
|
||||
/// EVM configuration trait.
|
||||
pub trait EvmConfig: ConfigureEvmEnv + Clone + Send + Sync + 'static {}
|
||||
|
||||
/// This represents the set of methods used to configure the EVM before execution.
|
||||
pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone {
|
||||
/// The type of the transaction metadata.
|
||||
|
||||
@@ -20,3 +20,5 @@ pub use engine::{
|
||||
/// Traits and helper types used to abstract over EVM methods and types.
|
||||
pub mod evm;
|
||||
pub use evm::ConfigureEvmEnv;
|
||||
|
||||
pub mod primitives;
|
||||
|
||||
8
crates/node-api/src/primitives.rs
Normal file
8
crates/node-api/src/primitives.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
//! Type abstraction for node primitive types.
|
||||
|
||||
/// Configures all the primitive types of the node.
|
||||
// TODO(mattsse): this is currently a placeholder
|
||||
pub trait NodePrimitives {}
|
||||
|
||||
// TODO(mattsse): Placeholder
|
||||
impl NodePrimitives for () {}
|
||||
50
crates/node-builder/Cargo.toml
Normal file
50
crates/node-builder/Cargo.toml
Normal file
@@ -0,0 +1,50 @@
|
||||
[package]
|
||||
name = "reth-node-builder"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
## reth
|
||||
reth-auto-seal-consensus.workspace = true
|
||||
reth-beacon-consensus.workspace = true
|
||||
reth-blockchain-tree.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-db.workspace = true
|
||||
reth-rpc-engine-api.workspace = true
|
||||
reth-rpc.workspace = true
|
||||
reth-node-api.workspace = true
|
||||
reth-node-core.workspace = true
|
||||
reth-network.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-payload-builder.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-interfaces.workspace = true
|
||||
reth-snapshot.workspace = true
|
||||
reth-prune.workspace = true
|
||||
reth-stages.workspace = true
|
||||
reth-config.workspace = true
|
||||
|
||||
|
||||
## async
|
||||
futures.workspace = true
|
||||
tokio = { workspace = true, features = [
|
||||
"sync",
|
||||
"macros",
|
||||
"time",
|
||||
"rt-multi-thread",
|
||||
] }
|
||||
|
||||
## misc
|
||||
eyre.workspace = true
|
||||
fdlimit = "0.3.0"
|
||||
confy.workspace = true
|
||||
786
crates/node-builder/src/builder.rs
Normal file
786
crates/node-builder/src/builder.rs
Normal file
@@ -0,0 +1,786 @@
|
||||
//! Customizable node builder.
|
||||
|
||||
#![allow(clippy::type_complexity, missing_debug_implementations)]
|
||||
|
||||
use crate::{
|
||||
components::{
|
||||
FullNodeComponents, FullNodeComponentsAdapter, NodeComponents, NodeComponentsBuilder,
|
||||
},
|
||||
hooks::NodeHooks,
|
||||
node::{FullNode, FullNodeTypes, FullNodeTypesAdapter, NodeTypes},
|
||||
rpc::{RethRpcServerHandles, RpcContext, RpcHooks},
|
||||
NodeHandle,
|
||||
};
|
||||
use eyre::Context;
|
||||
use futures::{future::Either, stream, stream_select, StreamExt};
|
||||
use reth_beacon_consensus::{
|
||||
hooks::{EngineHooks, PruneHook},
|
||||
BeaconConsensusEngine,
|
||||
};
|
||||
use reth_blockchain_tree::{BlockchainTreeConfig, ShareableBlockchainTree};
|
||||
use reth_db::{
|
||||
database::Database,
|
||||
database_metrics::{DatabaseMetadata, DatabaseMetrics},
|
||||
};
|
||||
use reth_interfaces::p2p::either::EitherDownloader;
|
||||
use reth_network::{NetworkBuilder, NetworkEvents, NetworkHandle};
|
||||
use reth_node_core::{
|
||||
cli::config::{PayloadBuilderConfig, RethRpcConfig, RethTransactionPoolConfig},
|
||||
dirs::{ChainPath, DataDirPath},
|
||||
events::cl::ConsensusLayerHealthEvents,
|
||||
exit::NodeExitFuture,
|
||||
init::init_genesis,
|
||||
node_config::NodeConfig,
|
||||
primitives::{kzg::KzgSettings, Head},
|
||||
utils::write_peers_to_file,
|
||||
};
|
||||
use reth_primitives::{
|
||||
constants::eip4844::{LoadKzgSettingsError, MAINNET_KZG_TRUSTED_SETUP},
|
||||
ChainSpec, DisplayHardforks,
|
||||
};
|
||||
use reth_provider::{providers::BlockchainProvider, ChainSpecProvider, ProviderFactory};
|
||||
use reth_prune::{PrunerBuilder, PrunerEvent};
|
||||
use reth_revm::EvmProcessorFactory;
|
||||
use reth_rpc_engine_api::EngineApi;
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_tracing::tracing::{debug, info};
|
||||
use reth_transaction_pool::{PoolConfig, TransactionPool};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc::unbounded_channel, oneshot};
|
||||
|
||||
/// The builtin provider type of the reth node.
|
||||
// Note: we need to hardcode this because custom components might depend on it in associated types.
|
||||
type RethFullProviderType<DB, Evm> =
|
||||
BlockchainProvider<DB, ShareableBlockchainTree<DB, EvmProcessorFactory<Evm>>>;
|
||||
|
||||
/// Declaratively construct a node.
|
||||
///
|
||||
/// [`NodeBuilder`] provides a [builder-like interface][builder] for composing
|
||||
/// components of a node.
|
||||
///
|
||||
/// Configuring a node starts out with a [`NodeConfig`] and then proceeds to configure the core
|
||||
/// static types of the node: [NodeTypes], these include the node's primitive types and the node's
|
||||
/// engine types.
|
||||
///
|
||||
/// Next all stateful components of the node are configured, these include the
|
||||
/// [EvmConfig](reth_node_api::evm::EvmConfig), the database [Database] and finally all the
|
||||
/// components of the node that are downstream of those types, these include:
|
||||
///
|
||||
/// - The transaction pool: [PoolBuilder](crate::components::PoolBuilder)
|
||||
/// - The network: [NetworkBuilder](crate::components::NetworkBuilder)
|
||||
/// - The payload builder: [PayloadBuilder](crate::components::PayloadServiceBuilder)
|
||||
///
|
||||
/// Finally, the node is ready to launch [NodeBuilder::launch]
|
||||
///
|
||||
/// [builder]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
|
||||
pub struct NodeBuilder<DB, State> {
|
||||
/// All settings for how the node should be configured.
|
||||
config: NodeConfig,
|
||||
/// State of the node builder process.
|
||||
state: State,
|
||||
/// The configured database for the node.
|
||||
database: DB,
|
||||
}
|
||||
|
||||
impl<DB, State> NodeBuilder<DB, State> {
|
||||
/// Returns a reference to the node builder's config.
|
||||
pub fn config(&self) -> &NodeConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
/// Loads the reth config with the given datadir root
|
||||
fn load_config(&self, data_dir: &ChainPath<DataDirPath>) -> eyre::Result<reth_config::Config> {
|
||||
let config_path = self.config.config.clone().unwrap_or_else(|| data_dir.config_path());
|
||||
|
||||
let mut config = confy::load_path::<reth_config::Config>(&config_path)
|
||||
.wrap_err_with(|| format!("Could not load config file {:?}", config_path))?;
|
||||
|
||||
info!(target: "reth::cli", path = ?config_path, "Configuration loaded");
|
||||
|
||||
// Update the config with the command line arguments
|
||||
config.peers.connect_trusted_nodes_only = self.config.network.trusted_only;
|
||||
|
||||
if !self.config.network.trusted_peers.is_empty() {
|
||||
info!(target: "reth::cli", "Adding trusted nodes");
|
||||
self.config.network.trusted_peers.iter().for_each(|peer| {
|
||||
config.peers.trusted_nodes.insert(*peer);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeBuilder<(), InitState> {
|
||||
/// Create a new [`NodeBuilder`].
|
||||
pub fn new(config: NodeConfig) -> Self {
|
||||
Self { config, database: (), state: InitState::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> NodeBuilder<DB, InitState> {
|
||||
/// Configures the additional external context, e.g. additional context captured via CLI args.
|
||||
pub fn with_database<D>(self, database: D) -> NodeBuilder<D, InitState> {
|
||||
NodeBuilder { config: self.config, state: self.state, database }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> NodeBuilder<DB, InitState>
|
||||
where
|
||||
DB: Database + Clone + 'static,
|
||||
{
|
||||
/// Configures the types of the node.
|
||||
pub fn with_types<T>(self, types: T) -> NodeBuilder<DB, TypesState<T, DB>>
|
||||
where
|
||||
T: NodeTypes,
|
||||
{
|
||||
NodeBuilder {
|
||||
config: self.config,
|
||||
state: TypesState { adapter: FullNodeTypesAdapter::new(types) },
|
||||
database: self.database,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, Types> NodeBuilder<DB, TypesState<Types, DB>>
|
||||
where
|
||||
Types: NodeTypes,
|
||||
DB: Database + Clone + Unpin + 'static,
|
||||
{
|
||||
/// Configures the node's components.
|
||||
pub fn with_components<Components>(
|
||||
self,
|
||||
components_builder: Components,
|
||||
) -> NodeBuilder<
|
||||
DB,
|
||||
ComponentsState<
|
||||
Types,
|
||||
Components,
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Components: NodeComponentsBuilder<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
>,
|
||||
{
|
||||
NodeBuilder {
|
||||
config: self.config,
|
||||
database: self.database,
|
||||
state: ComponentsState {
|
||||
types: self.state.adapter.types,
|
||||
components_builder,
|
||||
hooks: NodeHooks::new(),
|
||||
rpc: RpcHooks::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, Types, Components>
|
||||
NodeBuilder<
|
||||
DB,
|
||||
ComponentsState<
|
||||
Types,
|
||||
Components,
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
>
|
||||
where
|
||||
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
|
||||
Types: NodeTypes,
|
||||
Components: NodeComponentsBuilder<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
>,
|
||||
{
|
||||
/// Apply a function to the components builder.
|
||||
pub fn map_components(self, f: impl FnOnce(Components) -> Components) -> Self {
|
||||
Self {
|
||||
config: self.config,
|
||||
database: self.database,
|
||||
state: ComponentsState {
|
||||
types: self.state.types,
|
||||
components_builder: f(self.state.components_builder),
|
||||
hooks: self.state.hooks,
|
||||
rpc: self.state.rpc,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the setup process to the components stage.
|
||||
///
|
||||
/// CAUTION: All previously configured hooks will be lost.
|
||||
pub fn fuse_components<C>(
|
||||
self,
|
||||
components_builder: C,
|
||||
) -> NodeBuilder<
|
||||
DB,
|
||||
ComponentsState<
|
||||
Types,
|
||||
C,
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
C::Pool,
|
||||
>,
|
||||
>,
|
||||
>
|
||||
where
|
||||
C: NodeComponentsBuilder<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
>,
|
||||
{
|
||||
NodeBuilder {
|
||||
config: self.config,
|
||||
database: self.database,
|
||||
state: ComponentsState {
|
||||
types: self.state.types,
|
||||
components_builder,
|
||||
hooks: NodeHooks::new(),
|
||||
rpc: RpcHooks::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
F: Fn(
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
) -> eyre::Result<()>
|
||||
+ 'static,
|
||||
{
|
||||
self.state.hooks.set_on_component_initialized(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the node has started.
|
||||
pub fn on_node_started<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: Fn(
|
||||
FullNode<
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
) -> eyre::Result<()>
|
||||
+ 'static,
|
||||
{
|
||||
self.state.hooks.set_on_node_started(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the rpc server is started.
|
||||
pub fn on_rpc_started<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: Fn(
|
||||
RpcContext<
|
||||
'_,
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
RethRpcServerHandles,
|
||||
) -> eyre::Result<()>
|
||||
+ 'static,
|
||||
{
|
||||
self.state.rpc.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: Fn(
|
||||
RpcContext<
|
||||
'_,
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
) -> eyre::Result<()>
|
||||
+ 'static,
|
||||
{
|
||||
self.state.rpc.set_extend_rpc_modules(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Launches the node and returns a handle to it.
|
||||
pub async fn launch(
|
||||
self,
|
||||
executor: TaskExecutor,
|
||||
data_dir: ChainPath<DataDirPath>,
|
||||
) -> eyre::Result<
|
||||
NodeHandle<
|
||||
FullNodeComponentsAdapter<
|
||||
FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
Components::Pool,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
// get config
|
||||
let reth_config = self.load_config(&data_dir)?;
|
||||
|
||||
let Self {
|
||||
config,
|
||||
state: ComponentsState { types, components_builder, hooks, rpc },
|
||||
database,
|
||||
} = self;
|
||||
|
||||
// Raise the fd limit of the process.
|
||||
// Does not do anything on windows.
|
||||
fdlimit::raise_fd_limit()?;
|
||||
|
||||
let prometheus_handle = config.install_prometheus_recorder()?;
|
||||
config.start_metrics_endpoint(prometheus_handle, database.clone()).await?;
|
||||
|
||||
info!(target: "reth::cli", "Database opened");
|
||||
|
||||
let mut provider_factory =
|
||||
ProviderFactory::new(database.clone(), Arc::clone(&config.chain));
|
||||
|
||||
// configure snapshotter
|
||||
let snapshotter = reth_snapshot::Snapshotter::new(
|
||||
provider_factory.clone(),
|
||||
data_dir.snapshots_path(),
|
||||
config.chain.snapshot_block_interval,
|
||||
)?;
|
||||
|
||||
provider_factory = provider_factory
|
||||
.with_snapshots(data_dir.snapshots_path(), snapshotter.highest_snapshot_receiver())?;
|
||||
|
||||
debug!(target: "reth::cli", chain=%config.chain.chain, genesis=?config.chain.genesis_hash(), "Initializing genesis");
|
||||
|
||||
let genesis_hash = init_genesis(database.clone(), config.chain.clone())?;
|
||||
|
||||
info!(target: "reth::cli", "{}", DisplayHardforks::new(config.chain.hardforks()));
|
||||
|
||||
let consensus = config.consensus();
|
||||
|
||||
debug!(target: "reth::cli", "Spawning stages metrics listener task");
|
||||
let (sync_metrics_tx, sync_metrics_rx) = unbounded_channel();
|
||||
let sync_metrics_listener = reth_stages::MetricsListener::new(sync_metrics_rx);
|
||||
executor.spawn_critical("stages metrics listener task", sync_metrics_listener);
|
||||
|
||||
let prune_config = config.prune_config()?.or(reth_config.prune.clone());
|
||||
|
||||
let evm_config = types.evm_config();
|
||||
let tree_config = BlockchainTreeConfig::default();
|
||||
let tree = config.build_blockchain_tree(
|
||||
provider_factory.clone(),
|
||||
consensus.clone(),
|
||||
prune_config.clone(),
|
||||
sync_metrics_tx.clone(),
|
||||
tree_config,
|
||||
evm_config.clone(),
|
||||
)?;
|
||||
|
||||
let canon_state_notification_sender = tree.canon_state_notification_sender();
|
||||
let blockchain_tree = ShareableBlockchainTree::new(tree);
|
||||
debug!(target: "reth::cli", "configured blockchain tree");
|
||||
|
||||
// fetch the head block from the database
|
||||
let head =
|
||||
config.lookup_head(provider_factory.clone()).wrap_err("the head block is missing")?;
|
||||
|
||||
// setup the blockchain provider
|
||||
let blockchain_db =
|
||||
BlockchainProvider::new(provider_factory.clone(), blockchain_tree.clone())?;
|
||||
|
||||
let ctx = BuilderContext {
|
||||
head,
|
||||
provider: blockchain_db,
|
||||
executor,
|
||||
data_dir,
|
||||
config,
|
||||
reth_config,
|
||||
};
|
||||
|
||||
debug!(target: "reth::cli", "creating components");
|
||||
let NodeComponents { transaction_pool, network, payload_builder } =
|
||||
components_builder.build_components(&ctx)?;
|
||||
|
||||
let BuilderContext {
|
||||
provider: blockchain_db,
|
||||
executor,
|
||||
data_dir,
|
||||
mut config,
|
||||
reth_config,
|
||||
..
|
||||
} = ctx;
|
||||
|
||||
let NodeHooks { on_component_initialized, on_node_started, .. } = hooks;
|
||||
|
||||
let node_components = FullNodeComponentsAdapter {
|
||||
evm_config: evm_config.clone(),
|
||||
pool: transaction_pool.clone(),
|
||||
network: network.clone(),
|
||||
provider: blockchain_db.clone(),
|
||||
payload_builder: payload_builder.clone(),
|
||||
executor: executor.clone(),
|
||||
};
|
||||
debug!(target: "reth::cli", "calling on_component_initialized hook");
|
||||
on_component_initialized.on_event(node_components.clone())?;
|
||||
|
||||
// create pipeline
|
||||
let network_client = network.fetch_client().await?;
|
||||
let (consensus_engine_tx, consensus_engine_rx) = unbounded_channel();
|
||||
let max_block = config.max_block(&network_client, provider_factory.clone()).await?;
|
||||
|
||||
// Configure the pipeline
|
||||
let (mut pipeline, client) = if config.dev.dev {
|
||||
info!(target: "reth::cli", "Starting Reth in dev mode");
|
||||
let mining_mode = config.mining_mode(transaction_pool.pending_transactions_listener());
|
||||
|
||||
let (_, client, mut task) = reth_auto_seal_consensus::AutoSealBuilder::new(
|
||||
Arc::clone(&config.chain),
|
||||
blockchain_db.clone(),
|
||||
transaction_pool.clone(),
|
||||
consensus_engine_tx.clone(),
|
||||
canon_state_notification_sender,
|
||||
mining_mode,
|
||||
evm_config.clone(),
|
||||
)
|
||||
.build();
|
||||
|
||||
let mut pipeline = config
|
||||
.build_networked_pipeline(
|
||||
&reth_config.stages,
|
||||
client.clone(),
|
||||
Arc::clone(&consensus),
|
||||
provider_factory.clone(),
|
||||
&executor,
|
||||
sync_metrics_tx,
|
||||
prune_config.clone(),
|
||||
max_block,
|
||||
evm_config,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let pipeline_events = pipeline.events();
|
||||
task.set_pipeline_events(pipeline_events);
|
||||
debug!(target: "reth::cli", "Spawning auto mine task");
|
||||
executor.spawn(Box::pin(task));
|
||||
|
||||
(pipeline, EitherDownloader::Left(client))
|
||||
} else {
|
||||
let pipeline = config
|
||||
.build_networked_pipeline(
|
||||
&reth_config.stages,
|
||||
network_client.clone(),
|
||||
Arc::clone(&consensus),
|
||||
provider_factory.clone(),
|
||||
&executor,
|
||||
sync_metrics_tx,
|
||||
prune_config.clone(),
|
||||
max_block,
|
||||
evm_config,
|
||||
)
|
||||
.await?;
|
||||
|
||||
(pipeline, EitherDownloader::Right(network_client))
|
||||
};
|
||||
|
||||
let pipeline_events = pipeline.events();
|
||||
|
||||
let initial_target = config.initial_pipeline_target(genesis_hash);
|
||||
let mut hooks = EngineHooks::new();
|
||||
|
||||
let pruner_events = if let Some(prune_config) = prune_config {
|
||||
let mut pruner = PrunerBuilder::new(prune_config.clone())
|
||||
.max_reorg_depth(tree_config.max_reorg_depth() as usize)
|
||||
.prune_delete_limit(config.chain.prune_delete_limit)
|
||||
.build(provider_factory, snapshotter.highest_snapshot_receiver());
|
||||
|
||||
let events = pruner.events();
|
||||
hooks.add(PruneHook::new(pruner, Box::new(executor.clone())));
|
||||
|
||||
info!(target: "reth::cli", ?prune_config, "Pruner initialized");
|
||||
Either::Left(events)
|
||||
} else {
|
||||
Either::Right(stream::empty::<PrunerEvent>())
|
||||
};
|
||||
|
||||
// Configure the consensus engine
|
||||
let (beacon_consensus_engine, beacon_engine_handle) = BeaconConsensusEngine::with_channel(
|
||||
client,
|
||||
pipeline,
|
||||
blockchain_db.clone(),
|
||||
Box::new(executor.clone()),
|
||||
Box::new(network.clone()),
|
||||
max_block,
|
||||
config.debug.continuous,
|
||||
payload_builder.clone(),
|
||||
initial_target,
|
||||
reth_beacon_consensus::MIN_BLOCKS_FOR_PIPELINE_RUN,
|
||||
consensus_engine_tx,
|
||||
consensus_engine_rx,
|
||||
hooks,
|
||||
)?;
|
||||
info!(target: "reth::cli", "Consensus engine initialized");
|
||||
|
||||
let events = stream_select!(
|
||||
network.event_listener().map(Into::into),
|
||||
beacon_engine_handle.event_listener().map(Into::into),
|
||||
pipeline_events.map(Into::into),
|
||||
if config.debug.tip.is_none() {
|
||||
Either::Left(
|
||||
ConsensusLayerHealthEvents::new(Box::new(blockchain_db.clone()))
|
||||
.map(Into::into),
|
||||
)
|
||||
} else {
|
||||
Either::Right(stream::empty())
|
||||
},
|
||||
pruner_events.map(Into::into)
|
||||
);
|
||||
executor.spawn_critical(
|
||||
"events task",
|
||||
reth_node_core::events::node::handle_events(
|
||||
Some(network.clone()),
|
||||
Some(head.number),
|
||||
events,
|
||||
database.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
let engine_api = EngineApi::new(
|
||||
blockchain_db.clone(),
|
||||
config.chain.clone(),
|
||||
beacon_engine_handle,
|
||||
payload_builder.into(),
|
||||
Box::new(executor.clone()),
|
||||
);
|
||||
info!(target: "reth::cli", "Engine API handler initialized");
|
||||
|
||||
// extract the jwt secret from the args if possible
|
||||
let default_jwt_path = data_dir.jwt_path();
|
||||
let jwt_secret = config.rpc.auth_jwt_secret(default_jwt_path)?;
|
||||
|
||||
// adjust rpc port numbers based on instance number
|
||||
config.adjust_instance_ports();
|
||||
|
||||
// Start RPC servers
|
||||
|
||||
let (rpc_server_handles, rpc_registry) = crate::rpc::launch_rpc_servers(
|
||||
node_components.clone(),
|
||||
engine_api,
|
||||
&config,
|
||||
jwt_secret,
|
||||
rpc,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Run consensus engine to completion
|
||||
let (tx, rx) = oneshot::channel();
|
||||
info!(target: "reth::cli", "Starting consensus engine");
|
||||
executor.spawn_critical_blocking("consensus engine", async move {
|
||||
let res = beacon_consensus_engine.await;
|
||||
let _ = tx.send(res);
|
||||
});
|
||||
|
||||
let FullNodeComponentsAdapter {
|
||||
evm_config,
|
||||
pool,
|
||||
network,
|
||||
provider,
|
||||
payload_builder,
|
||||
executor,
|
||||
} = node_components;
|
||||
|
||||
let full_node = FullNode {
|
||||
evm_config,
|
||||
pool,
|
||||
network,
|
||||
provider,
|
||||
payload_builder,
|
||||
executor,
|
||||
rpc_server_handles,
|
||||
rpc_registry,
|
||||
config,
|
||||
data_dir,
|
||||
};
|
||||
// Notify on node started
|
||||
on_node_started.on_event(full_node.clone())?;
|
||||
|
||||
let handle = NodeHandle {
|
||||
node_exit_future: NodeExitFuture::new(rx, full_node.config.debug.terminate),
|
||||
node: full_node,
|
||||
};
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
/// Check that the builder can be launched
|
||||
///
|
||||
/// This is useful when writing tests to ensure that the builder is configured correctly.
|
||||
pub fn check_launch(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Captures the necessary context for building the components of the node.
|
||||
#[derive(Debug)]
|
||||
pub struct BuilderContext<Node: FullNodeTypes> {
|
||||
/// The current head of the blockchain at launch.
|
||||
head: Head,
|
||||
/// The configured provider to interact with the blockchain.
|
||||
provider: Node::Provider,
|
||||
/// The executor of the node.
|
||||
executor: TaskExecutor,
|
||||
/// The data dir of the node.
|
||||
data_dir: ChainPath<DataDirPath>,
|
||||
/// The config of the node
|
||||
config: NodeConfig,
|
||||
/// loaded config
|
||||
reth_config: reth_config::Config,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeTypes> BuilderContext<Node> {
|
||||
/// Returns the configured provider to interact with the blockchain.
|
||||
pub fn provider(&self) -> &Node::Provider {
|
||||
&self.provider
|
||||
}
|
||||
|
||||
/// Returns the current head of the blockchain at launch.
|
||||
pub fn head(&self) -> Head {
|
||||
self.head
|
||||
}
|
||||
|
||||
/// Returns the config of the node.
|
||||
pub fn config(&self) -> &NodeConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
/// Returns the data dir of the node.
|
||||
///
|
||||
/// This gives access to all relevant files and directories of the node's datadir.
|
||||
pub fn data_dir(&self) -> &ChainPath<DataDirPath> {
|
||||
&self.data_dir
|
||||
}
|
||||
|
||||
/// Returns the executor of the node.
|
||||
///
|
||||
/// This can be used to execute async tasks or functions during the setup.
|
||||
pub fn task_executor(&self) -> &TaskExecutor {
|
||||
&self.executor
|
||||
}
|
||||
|
||||
/// Returns the chain spec of the node.
|
||||
pub fn chain_spec(&self) -> Arc<ChainSpec> {
|
||||
self.provider().chain_spec()
|
||||
}
|
||||
|
||||
/// Returns the transaction pool config of the node.
|
||||
pub fn pool_config(&self) -> PoolConfig {
|
||||
self.config().txpool.pool_config()
|
||||
}
|
||||
|
||||
/// Loads the trusted setup params from a given file path or falls back to
|
||||
/// `MAINNET_KZG_TRUSTED_SETUP`.
|
||||
pub fn kzg_settings(&self) -> eyre::Result<Arc<KzgSettings>> {
|
||||
if let Some(ref trusted_setup_file) = self.config().trusted_setup_file {
|
||||
let trusted_setup = KzgSettings::load_trusted_setup_file(trusted_setup_file)
|
||||
.map_err(LoadKzgSettingsError::KzgError)?;
|
||||
Ok(Arc::new(trusted_setup))
|
||||
} else {
|
||||
Ok(Arc::clone(&MAINNET_KZG_TRUSTED_SETUP))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the config for payload building.
|
||||
pub fn payload_builder_config(&self) -> impl PayloadBuilderConfig {
|
||||
self.config.builder.clone()
|
||||
}
|
||||
|
||||
/// Creates the [NetworkBuilder] for the node.
|
||||
pub async fn network_builder(&self) -> eyre::Result<NetworkBuilder<Node::Provider, (), ()>> {
|
||||
self.config
|
||||
.build_network(
|
||||
&self.reth_config,
|
||||
self.provider.clone(),
|
||||
self.executor.clone(),
|
||||
self.head,
|
||||
self.data_dir(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Creates the [NetworkBuilder] for the node and blocks until it is ready.
|
||||
pub fn network_builder_blocking(&self) -> eyre::Result<NetworkBuilder<Node::Provider, (), ()>> {
|
||||
self.executor.block_on(self.network_builder())
|
||||
}
|
||||
|
||||
/// Spawns the configured network and associated tasks and returns the [NetworkHandle] connected
|
||||
/// to that network.
|
||||
pub fn start_network<Pool>(
|
||||
&self,
|
||||
builder: NetworkBuilder<Node::Provider, (), ()>,
|
||||
pool: Pool,
|
||||
) -> NetworkHandle
|
||||
where
|
||||
Pool: TransactionPool + Unpin + 'static,
|
||||
{
|
||||
let (handle, network, txpool, eth) =
|
||||
builder.transactions(pool).request_handler(self.provider().clone()).split_with_handle();
|
||||
|
||||
self.executor.spawn_critical("p2p txpool", txpool);
|
||||
self.executor.spawn_critical("p2p eth request handler", eth);
|
||||
|
||||
let default_peers_path = self.data_dir().known_peers_path();
|
||||
let known_peers_file = self.config.network.persistent_peers_file(default_peers_path);
|
||||
self.executor.spawn_critical_with_graceful_shutdown_signal(
|
||||
"p2p network task",
|
||||
|shutdown| {
|
||||
network.run_until_graceful_shutdown(shutdown, |network| {
|
||||
write_peers_to_file(network, known_peers_file)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
handle
|
||||
}
|
||||
}
|
||||
|
||||
/// The initial state of the node builder process.
|
||||
#[derive(Debug, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct InitState;
|
||||
|
||||
/// The state after all types of the node have been configured.
|
||||
#[derive(Debug)]
|
||||
pub struct TypesState<Types, DB>
|
||||
where
|
||||
DB: Database + Clone + 'static,
|
||||
Types: NodeTypes,
|
||||
{
|
||||
adapter: FullNodeTypesAdapter<Types, DB, RethFullProviderType<DB, Types::Evm>>,
|
||||
}
|
||||
|
||||
/// The state of the node builder process after the node's components have been configured.
|
||||
///
|
||||
/// With this state all types and components of the node are known and the node can be launched.
|
||||
///
|
||||
/// Additionally, this state captures additional hooks that are called at specific points in the
|
||||
/// node's launch lifecycle.
|
||||
#[derive(Debug)]
|
||||
pub struct ComponentsState<Types, Components, FullNode: FullNodeComponents> {
|
||||
/// The types of the node.
|
||||
types: Types,
|
||||
/// Type that builds the components of the node.
|
||||
components_builder: Components,
|
||||
/// Additional NodeHooks that are called at specific points in the node's launch lifecycle.
|
||||
hooks: NodeHooks<FullNode>,
|
||||
/// Additional RPC hooks.
|
||||
rpc: RpcHooks<FullNode>,
|
||||
}
|
||||
156
crates/node-builder/src/components/builder.rs
Normal file
156
crates/node-builder/src/components/builder.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
//! A generic [NodeComponentsBuilder]
|
||||
|
||||
use crate::{
|
||||
components::{
|
||||
NetworkBuilder, NodeComponents, NodeComponentsBuilder, PayloadServiceBuilder, PoolBuilder,
|
||||
},
|
||||
node::FullNodeTypes,
|
||||
BuilderContext,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A generic, customizable [`NodeComponentsBuilder`].
|
||||
///
|
||||
/// This type is stateful and captures the configuration of the node's components.
|
||||
///
|
||||
/// ## Component dependencies:
|
||||
///
|
||||
/// The components of the node depend on each other:
|
||||
/// - The payload builder service depends on the transaction pool.
|
||||
/// - The network depends on the transaction pool.
|
||||
///
|
||||
/// We distinguish between different kind of components:
|
||||
/// - Components that are standalone, such as the transaction pool.
|
||||
/// - Components that are spawned as a service, such as the payload builder service or the network.
|
||||
///
|
||||
/// ## Builder lifecycle:
|
||||
///
|
||||
/// First all standalone components are built. Then the service components are spawned.
|
||||
/// All component builders are captured in the builder state and will be consumed once the node is
|
||||
/// launched.
|
||||
#[derive(Debug)]
|
||||
pub struct ComponentsBuilder<Node, PoolB, PayloadB, NetworkB> {
|
||||
pool_builder: PoolB,
|
||||
payload_builder: PayloadB,
|
||||
network_builder: NetworkB,
|
||||
_marker: PhantomData<Node>,
|
||||
}
|
||||
|
||||
impl<Node, PoolB, PayloadB, NetworkB> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB> {
|
||||
/// Configures the node types.
|
||||
pub fn node_types<Types>(self) -> ComponentsBuilder<Types, PoolB, PayloadB, NetworkB>
|
||||
where
|
||||
Types: FullNodeTypes,
|
||||
{
|
||||
let Self { pool_builder, payload_builder, network_builder, _marker } = self;
|
||||
ComponentsBuilder {
|
||||
pool_builder,
|
||||
payload_builder,
|
||||
network_builder,
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply a function to the pool builder.
|
||||
pub fn map_pool(self, f: impl FnOnce(PoolB) -> PoolB) -> Self {
|
||||
Self {
|
||||
pool_builder: f(self.pool_builder),
|
||||
payload_builder: self.payload_builder,
|
||||
network_builder: self.network_builder,
|
||||
_marker: self._marker,
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply a function to the payload builder.
|
||||
pub fn map_payload(self, f: impl FnOnce(PayloadB) -> PayloadB) -> Self {
|
||||
Self {
|
||||
pool_builder: self.pool_builder,
|
||||
payload_builder: f(self.payload_builder),
|
||||
network_builder: self.network_builder,
|
||||
_marker: self._marker,
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply a function to the network builder.
|
||||
pub fn map_network(self, f: impl FnOnce(NetworkB) -> NetworkB) -> Self {
|
||||
Self {
|
||||
pool_builder: self.pool_builder,
|
||||
payload_builder: self.payload_builder,
|
||||
network_builder: f(self.network_builder),
|
||||
_marker: self._marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node, PoolB, PayloadB, NetworkB> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
{
|
||||
/// Configures the pool builder.
|
||||
pub fn pool<PB>(self, pool_builder: PB) -> ComponentsBuilder<Node, PB, PayloadB, NetworkB>
|
||||
where
|
||||
PB: PoolBuilder<Node>,
|
||||
{
|
||||
let Self { payload_builder, network_builder, _marker, .. } = self;
|
||||
ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node, PoolB, PayloadB, NetworkB> ComponentsBuilder<Node, PoolB, PayloadB, NetworkB>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
PoolB: PoolBuilder<Node>,
|
||||
{
|
||||
/// Configures the network builder.
|
||||
pub fn network<NB>(self, network_builder: NB) -> ComponentsBuilder<Node, PoolB, PayloadB, NB>
|
||||
where
|
||||
NB: NetworkBuilder<Node, PoolB::Pool>,
|
||||
{
|
||||
let Self { payload_builder, pool_builder, _marker, .. } = self;
|
||||
ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker }
|
||||
}
|
||||
|
||||
/// Configures the payload builder.
|
||||
pub fn payload<PB>(self, payload_builder: PB) -> ComponentsBuilder<Node, PoolB, PB, NetworkB>
|
||||
where
|
||||
PB: PayloadServiceBuilder<Node, PoolB::Pool>,
|
||||
{
|
||||
let Self { pool_builder, network_builder, _marker, .. } = self;
|
||||
ComponentsBuilder { pool_builder, payload_builder, network_builder, _marker }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node, PoolB, PayloadB, NetworkB> NodeComponentsBuilder<Node>
|
||||
for ComponentsBuilder<Node, PoolB, PayloadB, NetworkB>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
PoolB: PoolBuilder<Node>,
|
||||
NetworkB: NetworkBuilder<Node, PoolB::Pool>,
|
||||
PayloadB: PayloadServiceBuilder<Node, PoolB::Pool>,
|
||||
{
|
||||
type Pool = PoolB::Pool;
|
||||
|
||||
fn build_components(
|
||||
self,
|
||||
context: &BuilderContext<Node>,
|
||||
) -> eyre::Result<NodeComponents<Node, Self::Pool>> {
|
||||
let Self { pool_builder, payload_builder, network_builder, _marker } = self;
|
||||
|
||||
let pool = pool_builder.build_pool(context)?;
|
||||
let network = network_builder.build_network(context, pool.clone())?;
|
||||
let payload_builder = payload_builder.spawn_payload_service(context, pool.clone())?;
|
||||
|
||||
Ok(NodeComponents { transaction_pool: pool, network, payload_builder })
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ComponentsBuilder<(), (), (), ()> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pool_builder: (),
|
||||
payload_builder: (),
|
||||
network_builder: (),
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
43
crates/node-builder/src/components/mod.rs
Normal file
43
crates/node-builder/src/components/mod.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
//! Support for configuring the components of a node.
|
||||
//!
|
||||
//! Customizable components of the node include:
|
||||
//! - The transaction pool.
|
||||
//! - The network implementation.
|
||||
//! - The payload builder service.
|
||||
//!
|
||||
//! Components depend on a fully type configured node: [FullNodeTypes](crate::node::FullNodeTypes).
|
||||
|
||||
use crate::node::FullNodeTypes;
|
||||
pub use builder::*;
|
||||
pub use network::*;
|
||||
pub use payload::*;
|
||||
pub use pool::*;
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_payload_builder::PayloadBuilderHandle;
|
||||
pub use traits::*;
|
||||
|
||||
mod builder;
|
||||
mod network;
|
||||
mod payload;
|
||||
mod pool;
|
||||
mod traits;
|
||||
|
||||
/// All the components of the node.
|
||||
///
|
||||
/// This provides access to all the components of the node.
|
||||
#[derive(Debug)]
|
||||
pub struct NodeComponents<Node: FullNodeTypes, Pool> {
|
||||
/// The transaction pool of the node.
|
||||
pub transaction_pool: Pool,
|
||||
/// The network implementation of the node.
|
||||
pub network: NetworkHandle,
|
||||
/// The handle to the payload builder service.
|
||||
pub payload_builder: PayloadBuilderHandle<Node::Engine>,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeTypes, Pool> NodeComponents<Node, Pool> {
|
||||
/// Returns the handle to the payload builder service.
|
||||
pub fn payload_builder(&self) -> PayloadBuilderHandle<Node::Engine> {
|
||||
self.payload_builder.clone()
|
||||
}
|
||||
}
|
||||
22
crates/node-builder/src/components/network.rs
Normal file
22
crates/node-builder/src/components/network.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
//! Network component for the node builder.
|
||||
|
||||
use crate::{node::FullNodeTypes, BuilderContext};
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
/// A type that knows how to build the network implementation.
|
||||
pub trait NetworkBuilder<Node: FullNodeTypes, Pool: TransactionPool> {
|
||||
/// Launches the network implementation and returns the handle to it.
|
||||
fn build_network(self, ctx: &BuilderContext<Node>, pool: Pool) -> eyre::Result<NetworkHandle>;
|
||||
}
|
||||
|
||||
impl<Node, F, Pool> NetworkBuilder<Node, Pool> for F
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool,
|
||||
F: FnOnce(&BuilderContext<Node>, Pool) -> eyre::Result<NetworkHandle>,
|
||||
{
|
||||
fn build_network(self, ctx: &BuilderContext<Node>, pool: Pool) -> eyre::Result<NetworkHandle> {
|
||||
self(ctx, pool)
|
||||
}
|
||||
}
|
||||
30
crates/node-builder/src/components/payload.rs
Normal file
30
crates/node-builder/src/components/payload.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
//! Payload service component for the node builder.
|
||||
|
||||
use crate::{node::FullNodeTypes, BuilderContext};
|
||||
use reth_payload_builder::PayloadBuilderHandle;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
/// A type that knows how to spawn the payload service.
|
||||
pub trait PayloadServiceBuilder<Node: FullNodeTypes, Pool: TransactionPool> {
|
||||
/// Spawns the payload service and returns the handle to it.
|
||||
fn spawn_payload_service(
|
||||
self,
|
||||
ctx: &BuilderContext<Node>,
|
||||
pool: Pool,
|
||||
) -> eyre::Result<PayloadBuilderHandle<Node::Engine>>;
|
||||
}
|
||||
|
||||
impl<Node, F, Pool> PayloadServiceBuilder<Node, Pool> for F
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool,
|
||||
F: FnOnce(&BuilderContext<Node>, Pool) -> eyre::Result<PayloadBuilderHandle<Node::Engine>>,
|
||||
{
|
||||
fn spawn_payload_service(
|
||||
self,
|
||||
ctx: &BuilderContext<Node>,
|
||||
pool: Pool,
|
||||
) -> eyre::Result<PayloadBuilderHandle<Node::Engine>> {
|
||||
self(ctx, pool)
|
||||
}
|
||||
}
|
||||
25
crates/node-builder/src/components/pool.rs
Normal file
25
crates/node-builder/src/components/pool.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
//! Pool component for the node builder.
|
||||
use crate::{node::FullNodeTypes, BuilderContext};
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
/// A type that knows how to build the transaction pool.
|
||||
pub trait PoolBuilder<Node: FullNodeTypes> {
|
||||
/// The transaction pool to build.
|
||||
type Pool: TransactionPool + Unpin + 'static;
|
||||
|
||||
/// Creates the transaction pool.
|
||||
fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool>;
|
||||
}
|
||||
|
||||
impl<Node, F, Pool> PoolBuilder<Node> for F
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool + Unpin + 'static,
|
||||
F: FnOnce(&BuilderContext<Node>) -> eyre::Result<Pool>,
|
||||
{
|
||||
type Pool = Pool;
|
||||
|
||||
fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
|
||||
self(ctx)
|
||||
}
|
||||
}
|
||||
145
crates/node-builder/src/components/traits.rs
Normal file
145
crates/node-builder/src/components/traits.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
//! Traits for the builder
|
||||
|
||||
use crate::{
|
||||
components::NodeComponents,
|
||||
node::{FullNodeTypes, NodeTypes},
|
||||
BuilderContext,
|
||||
};
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_payload_builder::PayloadBuilderHandle;
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
/// Encapsulates all types and components of the node.
|
||||
pub trait FullNodeComponents: FullNodeTypes + 'static {
|
||||
/// The transaction pool of the node.
|
||||
type Pool: TransactionPool;
|
||||
|
||||
/// Returns the transaction pool of the node.
|
||||
fn pool(&self) -> &Self::Pool;
|
||||
|
||||
/// Returns the provider of the node.
|
||||
fn provider(&self) -> &Self::Provider;
|
||||
|
||||
/// Returns the handle to the network
|
||||
fn network(&self) -> &NetworkHandle;
|
||||
|
||||
/// Returns the handle to the payload builder service.
|
||||
fn payload_builder(&self) -> &PayloadBuilderHandle<Self::Engine>;
|
||||
|
||||
/// Returns the task executor.
|
||||
fn task_executor(&self) -> &TaskExecutor;
|
||||
}
|
||||
|
||||
/// A type that encapsulates all the components of the node.
|
||||
#[derive(Debug)]
|
||||
pub struct FullNodeComponentsAdapter<Node: FullNodeTypes, Pool> {
|
||||
pub(crate) evm_config: Node::Evm,
|
||||
pub(crate) pool: Pool,
|
||||
pub(crate) network: NetworkHandle,
|
||||
pub(crate) provider: Node::Provider,
|
||||
pub(crate) payload_builder: PayloadBuilderHandle<Node::Engine>,
|
||||
pub(crate) executor: TaskExecutor,
|
||||
}
|
||||
|
||||
impl<Node, Pool> FullNodeTypes for FullNodeComponentsAdapter<Node, Pool>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool + 'static,
|
||||
{
|
||||
type DB = Node::DB;
|
||||
type Provider = Node::Provider;
|
||||
}
|
||||
|
||||
impl<Node, Pool> NodeTypes for FullNodeComponentsAdapter<Node, Pool>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool + 'static,
|
||||
{
|
||||
type Primitives = Node::Primitives;
|
||||
type Engine = Node::Engine;
|
||||
type Evm = Node::Evm;
|
||||
|
||||
fn evm_config(&self) -> Self::Evm {
|
||||
self.evm_config.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node, Pool> FullNodeComponents for FullNodeComponentsAdapter<Node, Pool>
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool + 'static,
|
||||
{
|
||||
type Pool = Pool;
|
||||
|
||||
fn pool(&self) -> &Self::Pool {
|
||||
&self.pool
|
||||
}
|
||||
|
||||
fn provider(&self) -> &Self::Provider {
|
||||
&self.provider
|
||||
}
|
||||
|
||||
fn network(&self) -> &NetworkHandle {
|
||||
&self.network
|
||||
}
|
||||
|
||||
fn payload_builder(&self) -> &PayloadBuilderHandle<Self::Engine> {
|
||||
&self.payload_builder
|
||||
}
|
||||
|
||||
fn task_executor(&self) -> &TaskExecutor {
|
||||
&self.executor
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeTypes, Pool> Clone for FullNodeComponentsAdapter<Node, Pool>
|
||||
where
|
||||
Pool: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
evm_config: self.evm_config.clone(),
|
||||
pool: self.pool.clone(),
|
||||
network: self.network.clone(),
|
||||
provider: self.provider.clone(),
|
||||
payload_builder: self.payload_builder.clone(),
|
||||
executor: self.executor.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that configures all the customizable components of the node and knows how to build them.
|
||||
///
|
||||
/// Implementors of this trait are responsible for building all the components of the node: See
|
||||
/// [NodeComponents].
|
||||
///
|
||||
/// The [ComponentsBuilder](crate::components::builder::ComponentsBuilder) is a generic
|
||||
/// implementation of this trait that can be used to customize certain components of the node using
|
||||
/// the builder pattern and defaults, e.g. Ethereum and Optimism.
|
||||
pub trait NodeComponentsBuilder<Node: FullNodeTypes> {
|
||||
/// The transaction pool to use.
|
||||
type Pool: TransactionPool + Unpin + 'static;
|
||||
|
||||
/// Builds the components of the node.
|
||||
fn build_components(
|
||||
self,
|
||||
context: &BuilderContext<Node>,
|
||||
) -> eyre::Result<NodeComponents<Node, Self::Pool>>;
|
||||
}
|
||||
|
||||
impl<Node, F, Pool> NodeComponentsBuilder<Node> for F
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
F: FnOnce(&BuilderContext<Node>) -> eyre::Result<NodeComponents<Node, Pool>>,
|
||||
Pool: TransactionPool + Unpin + 'static,
|
||||
{
|
||||
type Pool = Pool;
|
||||
|
||||
fn build_components(
|
||||
self,
|
||||
ctx: &BuilderContext<Node>,
|
||||
) -> eyre::Result<NodeComponents<Node, Pool>> {
|
||||
self(ctx)
|
||||
}
|
||||
}
|
||||
20
crates/node-builder/src/handle.rs
Normal file
20
crates/node-builder/src/handle.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use crate::{components::FullNodeComponents, node::FullNode};
|
||||
use reth_node_core::exit::NodeExitFuture;
|
||||
use std::fmt;
|
||||
|
||||
/// A Handle to the launched node.
|
||||
pub struct NodeHandle<Node: FullNodeComponents> {
|
||||
/// All node components.
|
||||
pub node: FullNode<Node>,
|
||||
/// The exit future of the node.
|
||||
pub node_exit_future: NodeExitFuture,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> fmt::Debug for NodeHandle<Node> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("NodeHandle")
|
||||
.field("node", &"...")
|
||||
.field("node_exit_future", &self.node_exit_future)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
119
crates/node-builder/src/hooks.rs
Normal file
119
crates/node-builder/src/hooks.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use crate::{components::FullNodeComponents, node::FullNode};
|
||||
use std::fmt;
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> NodeHooks<Node> {
|
||||
/// Creates a new, empty [NodeHooks] instance for the given node type.
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
on_component_initialized: Box::<()>::default(),
|
||||
on_node_started: Box::<()>::default(),
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the node's components are initialized.
|
||||
pub(crate) fn set_on_component_initialized<F>(&mut self, hook: F) -> &mut Self
|
||||
where
|
||||
F: OnComponentInitializedHook<Node> + 'static,
|
||||
{
|
||||
self.on_component_initialized = Box::new(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the node's components are initialized.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn on_component_initialized<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: OnComponentInitializedHook<Node> + 'static,
|
||||
{
|
||||
self.set_on_component_initialized(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// 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,
|
||||
{
|
||||
self.on_node_started = Box::new(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the node has started.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn on_node_started<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: OnNodeStartedHook<Node> + 'static,
|
||||
{
|
||||
self.set_on_node_started(hook);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> Default for NodeHooks<Node> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl<Node: FullNodeComponents> fmt::Debug for NodeHooks<Node> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("NodeHooks")
|
||||
.field("on_component_initialized", &"...")
|
||||
.field("on_node_started", &"...")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper trait for the event hook that is run once the node is initialized.
|
||||
pub trait OnComponentInitializedHook<Node> {
|
||||
/// Consumes the event hook and runs it.
|
||||
///
|
||||
/// If this returns an error, the node launch will be aborted.
|
||||
fn on_event(&self, node: Node) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
impl<Node, F> OnComponentInitializedHook<Node> for F
|
||||
where
|
||||
F: Fn(Node) -> eyre::Result<()>,
|
||||
{
|
||||
fn on_event(&self, node: Node) -> eyre::Result<()> {
|
||||
self(node)
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper trait that is run once the node is started.
|
||||
pub trait OnNodeStartedHook<Node: FullNodeComponents> {
|
||||
/// Consumes the event hook and runs it.
|
||||
///
|
||||
/// If this returns an error, the node launch will be aborted.
|
||||
fn on_event(&self, node: FullNode<Node>) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
impl<Node, F> OnNodeStartedHook<Node> for F
|
||||
where
|
||||
Node: FullNodeComponents,
|
||||
F: Fn(FullNode<Node>) -> eyre::Result<()>,
|
||||
{
|
||||
fn on_event(&self, node: FullNode<Node>) -> eyre::Result<()> {
|
||||
self(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node> OnComponentInitializedHook<Node> for () {
|
||||
fn on_event(&self, _node: Node) -> eyre::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> OnNodeStartedHook<Node> for () {
|
||||
fn on_event(&self, _node: FullNode<Node>) -> eyre::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
34
crates/node-builder/src/lib.rs
Normal file
34
crates/node-builder/src/lib.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
//! Standalone crate for Reth configuration and builder types.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
#![warn(unused_crate_dependencies)]
|
||||
|
||||
/// Node event hooks.
|
||||
pub mod hooks;
|
||||
|
||||
/// Support for configuring the higher level node types.
|
||||
pub mod node;
|
||||
|
||||
/// Support for configuring the components of a node.
|
||||
pub mod components;
|
||||
|
||||
mod builder;
|
||||
mod handle;
|
||||
pub mod rpc;
|
||||
|
||||
pub mod provider;
|
||||
|
||||
pub use builder::*;
|
||||
pub use handle::NodeHandle;
|
||||
|
||||
/// Re-export the core configuration traits.
|
||||
pub use reth_node_core::cli::config::{
|
||||
PayloadBuilderConfig, RethNetworkConfig, RethRpcConfig, RethTransactionPoolConfig,
|
||||
};
|
||||
|
||||
pub use reth_node_core::node_config::NodeConfig;
|
||||
110
crates/node-builder/src/node.rs
Normal file
110
crates/node-builder/src/node.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use crate::{components::FullNodeComponents, rpc::RethRpcServerHandles};
|
||||
use reth_db::database::Database;
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_node_api::{evm::EvmConfig, primitives::NodePrimitives, EngineTypes};
|
||||
use reth_node_core::{
|
||||
cli::components::FullProvider,
|
||||
dirs::{ChainPath, DataDirPath},
|
||||
node_config::NodeConfig,
|
||||
};
|
||||
use reth_payload_builder::PayloadBuilderHandle;
|
||||
use reth_tasks::TaskExecutor;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::rpc::RpcRegistry;
|
||||
|
||||
/// The type that configures stateless node types, the node's primitive types.
|
||||
pub trait NodeTypes: Send + Sync + 'static {
|
||||
/// The node's primitive types.
|
||||
type Primitives: NodePrimitives;
|
||||
/// The node's engine types.
|
||||
type Engine: EngineTypes;
|
||||
/// The node's evm configuration.
|
||||
type Evm: EvmConfig;
|
||||
|
||||
/// Returns the node's evm config.
|
||||
fn evm_config(&self) -> Self::Evm;
|
||||
}
|
||||
|
||||
/// A helper type that is downstream of the node types and adds stateful components to the node.
|
||||
pub trait FullNodeTypes: NodeTypes + 'static {
|
||||
/// Underlying database type.
|
||||
type DB: Database + Clone + 'static;
|
||||
/// The provider type used to interact with the node.
|
||||
type Provider: FullProvider<Self::DB>;
|
||||
}
|
||||
|
||||
/// An adapter type that adds the builtin provider type to the user configured node types.
|
||||
#[derive(Debug)]
|
||||
pub struct FullNodeTypesAdapter<Types, DB, Provider> {
|
||||
pub(crate) types: Types,
|
||||
_db: PhantomData<DB>,
|
||||
_provider: PhantomData<Provider>,
|
||||
}
|
||||
|
||||
impl<Types, DB, Provider> FullNodeTypesAdapter<Types, DB, Provider> {
|
||||
/// Create a new adapter from the given node types.
|
||||
pub fn new(types: Types) -> Self {
|
||||
Self { types, _db: Default::default(), _provider: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Types, DB, Provider> NodeTypes for FullNodeTypesAdapter<Types, DB, Provider>
|
||||
where
|
||||
Types: NodeTypes,
|
||||
DB: Send + Sync + 'static,
|
||||
Provider: Send + Sync + 'static,
|
||||
{
|
||||
type Primitives = Types::Primitives;
|
||||
type Engine = Types::Engine;
|
||||
type Evm = Types::Evm;
|
||||
|
||||
fn evm_config(&self) -> Self::Evm {
|
||||
self.types.evm_config()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Types, DB, Provider> FullNodeTypes for FullNodeTypesAdapter<Types, DB, Provider>
|
||||
where
|
||||
Types: NodeTypes,
|
||||
Provider: FullProvider<DB>,
|
||||
DB: Database + Clone + 'static,
|
||||
{
|
||||
type DB = DB;
|
||||
type Provider = Provider;
|
||||
}
|
||||
|
||||
/// The launched node with all components including RPC handlers.
|
||||
#[derive(Debug)]
|
||||
pub struct FullNode<Node: FullNodeComponents> {
|
||||
pub(crate) evm_config: Node::Evm,
|
||||
pub(crate) pool: Node::Pool,
|
||||
pub(crate) network: NetworkHandle,
|
||||
pub(crate) provider: Node::Provider,
|
||||
pub(crate) payload_builder: PayloadBuilderHandle<Node::Engine>,
|
||||
pub(crate) executor: TaskExecutor,
|
||||
pub(crate) rpc_server_handles: RethRpcServerHandles,
|
||||
pub(crate) rpc_registry: RpcRegistry<Node>,
|
||||
/// The initial node config.
|
||||
pub(crate) config: NodeConfig,
|
||||
/// The data dir of the node.
|
||||
pub(crate) data_dir: ChainPath<DataDirPath>,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> Clone for FullNode<Node> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
evm_config: self.evm_config.clone(),
|
||||
pool: self.pool.clone(),
|
||||
network: self.network.clone(),
|
||||
provider: self.provider.clone(),
|
||||
payload_builder: self.payload_builder.clone(),
|
||||
executor: self.executor.clone(),
|
||||
rpc_server_handles: self.rpc_server_handles.clone(),
|
||||
rpc_registry: self.rpc_registry.clone(),
|
||||
config: self.config.clone(),
|
||||
data_dir: self.data_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
38
crates/node-builder/src/provider.rs
Normal file
38
crates/node-builder/src/provider.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
//! Helper provider traits to encapsulate all provider traits for simplicity.
|
||||
|
||||
use reth_db::database::Database;
|
||||
use reth_provider::{
|
||||
AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
|
||||
DatabaseProviderFactory, EvmEnvProvider, StateProviderFactory,
|
||||
};
|
||||
|
||||
/// Helper trait to unify all provider traits for simplicity.
|
||||
pub trait FullProvider<DB: Database>:
|
||||
DatabaseProviderFactory<DB>
|
||||
+ BlockReaderIdExt
|
||||
+ AccountReader
|
||||
+ StateProviderFactory
|
||||
+ EvmEnvProvider
|
||||
+ ChainSpecProvider
|
||||
+ ChangeSetReader
|
||||
+ CanonStateSubscriptions
|
||||
+ Clone
|
||||
+ Unpin
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, DB: Database> FullProvider<DB> for T where
|
||||
T: DatabaseProviderFactory<DB>
|
||||
+ BlockReaderIdExt
|
||||
+ AccountReader
|
||||
+ StateProviderFactory
|
||||
+ EvmEnvProvider
|
||||
+ ChainSpecProvider
|
||||
+ ChangeSetReader
|
||||
+ CanonStateSubscriptions
|
||||
+ Clone
|
||||
+ Unpin
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
301
crates/node-builder/src/rpc.rs
Normal file
301
crates/node-builder/src/rpc.rs
Normal file
@@ -0,0 +1,301 @@
|
||||
//! Builder support for rpc components.
|
||||
|
||||
use crate::components::FullNodeComponents;
|
||||
use futures::TryFutureExt;
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_node_core::{
|
||||
cli::config::RethRpcConfig,
|
||||
node_config::NodeConfig,
|
||||
rpc::{
|
||||
api::EngineApiServer,
|
||||
builder::{
|
||||
auth::{AuthRpcModule, AuthServerHandle},
|
||||
RethModuleRegistry, RpcModuleBuilder, RpcServerHandle, TransportRpcModules,
|
||||
},
|
||||
},
|
||||
};
|
||||
use reth_rpc::JwtSecret;
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_tracing::tracing::{debug, info};
|
||||
use std::{
|
||||
fmt,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
/// Contains the handles to the spawned RPC servers.
|
||||
///
|
||||
/// This can be used to access the endpoints of the servers.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RethRpcServerHandles {
|
||||
/// The regular RPC server handle to all configured transports.
|
||||
pub rpc: RpcServerHandle,
|
||||
/// The handle to the auth server (engine API)
|
||||
pub auth: AuthServerHandle,
|
||||
}
|
||||
|
||||
/// 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>>,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> RpcHooks<Node> {
|
||||
/// Creates a new, empty [RpcHooks] instance for the given node type.
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
|
||||
}
|
||||
|
||||
/// 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,
|
||||
{
|
||||
self.on_rpc_started = Box::new(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run once the rpc server is started.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: OnRpcStarted<Node> + 'static,
|
||||
{
|
||||
self.set_on_rpc_started(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// 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,
|
||||
{
|
||||
self.extend_rpc_modules = Box::new(hook);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the hook that is run to configure the rpc modules.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
|
||||
where
|
||||
F: ExtendRpcModules<Node> + 'static,
|
||||
{
|
||||
self.set_extend_rpc_modules(hook);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> fmt::Debug for RpcHooks<Node> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("RpcHooks")
|
||||
.field("on_rpc_started", &"...")
|
||||
.field("extend_rpc_modules", &"...")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Event hook that is called once the rpc server is started.
|
||||
pub trait OnRpcStarted<Node: FullNodeComponents> {
|
||||
/// The hook that is called once the rpc server is started.
|
||||
fn on_rpc_started(
|
||||
&self,
|
||||
ctx: RpcContext<'_, Node>,
|
||||
handles: RethRpcServerHandles,
|
||||
) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
impl<Node, F> OnRpcStarted<Node> for F
|
||||
where
|
||||
F: Fn(RpcContext<'_, Node>, RethRpcServerHandles) -> eyre::Result<()>,
|
||||
Node: FullNodeComponents,
|
||||
{
|
||||
fn on_rpc_started(
|
||||
&self,
|
||||
ctx: RpcContext<'_, Node>,
|
||||
handles: RethRpcServerHandles,
|
||||
) -> eyre::Result<()> {
|
||||
self(ctx, handles)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> OnRpcStarted<Node> for () {
|
||||
fn on_rpc_started(&self, _: RpcContext<'_, Node>, _: RethRpcServerHandles) -> eyre::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Event hook that is called when the rpc server is started.
|
||||
pub trait ExtendRpcModules<Node: FullNodeComponents> {
|
||||
/// The hook that is called once the rpc server is started.
|
||||
fn extend_rpc_modules(&self, ctx: RpcContext<'_, Node>) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
impl<Node, F> ExtendRpcModules<Node> for F
|
||||
where
|
||||
F: Fn(RpcContext<'_, Node>) -> eyre::Result<()>,
|
||||
Node: FullNodeComponents,
|
||||
{
|
||||
fn extend_rpc_modules(&self, ctx: RpcContext<'_, Node>) -> eyre::Result<()> {
|
||||
self(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> ExtendRpcModules<Node> for () {
|
||||
fn extend_rpc_modules(&self, _: RpcContext<'_, Node>) -> eyre::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper wrapper type to encapsulate the [RethModuleRegistry] over components trait.
|
||||
#[derive(Debug)]
|
||||
pub struct RpcRegistry<Node: FullNodeComponents> {
|
||||
pub(crate) registry: RethModuleRegistry<
|
||||
Node::Provider,
|
||||
Node::Pool,
|
||||
NetworkHandle,
|
||||
TaskExecutor,
|
||||
Node::Provider,
|
||||
Node::Evm,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> Deref for RpcRegistry<Node> {
|
||||
type Target = RethModuleRegistry<
|
||||
Node::Provider,
|
||||
Node::Pool,
|
||||
NetworkHandle,
|
||||
TaskExecutor,
|
||||
Node::Provider,
|
||||
Node::Evm,
|
||||
>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.registry
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node: FullNodeComponents> DerefMut for RpcRegistry<Node> {
|
||||
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 [RethModuleRegistry], [TransportRpcModules] and [AuthRpcModule].
|
||||
///
|
||||
/// This can be used to access installed modules, or create commonly used handlers like
|
||||
/// [reth_rpc::EthApi], and ultimately merge additional rpc handler into the configured transport
|
||||
/// modules [TransportRpcModules] as well as configured authenticated methods [AuthRpcModule].
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct RpcContext<'a, Node: FullNodeComponents> {
|
||||
/// The node components.
|
||||
pub(crate) node: Node,
|
||||
|
||||
/// Gives access to the node configuration.
|
||||
pub(crate) config: &'a NodeConfig,
|
||||
|
||||
/// A Helper type the holds instances of the configured modules.
|
||||
///
|
||||
/// This provides easy access to rpc handlers, such as [RethModuleRegistry::eth_api].
|
||||
pub registry: &'a mut RpcRegistry<Node>,
|
||||
/// Holds installed modules per transport type.
|
||||
///
|
||||
/// This can be used to merge additional modules into the configured transports (http, ipc,
|
||||
/// ws). See [TransportRpcModules::merge_configured]
|
||||
pub modules: &'a mut TransportRpcModules,
|
||||
/// Holds jwt authenticated rpc module.
|
||||
///
|
||||
/// This can be used to merge additional modules into the configured authenticated methods
|
||||
pub auth_module: &'a mut AuthRpcModule,
|
||||
}
|
||||
|
||||
impl<'a, Node: FullNodeComponents> RpcContext<'a, Node> {
|
||||
/// Returns the config of the node.
|
||||
pub fn config(&self) -> &NodeConfig {
|
||||
self.config
|
||||
}
|
||||
|
||||
/// Returns a reference to the configured node.
|
||||
pub fn node(&self) -> &Node {
|
||||
&self.node
|
||||
}
|
||||
}
|
||||
|
||||
/// Launch the rpc servers.
|
||||
pub(crate) async fn launch_rpc_servers<Node, Engine>(
|
||||
node: Node,
|
||||
engine_api: Engine,
|
||||
config: &NodeConfig,
|
||||
jwt_secret: JwtSecret,
|
||||
hooks: RpcHooks<Node>,
|
||||
) -> eyre::Result<(RethRpcServerHandles, RpcRegistry<Node>)>
|
||||
where
|
||||
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");
|
||||
|
||||
let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
|
||||
.with_provider(node.provider().clone())
|
||||
.with_pool(node.pool().clone())
|
||||
.with_network(node.network().clone())
|
||||
.with_events(node.provider().clone())
|
||||
.with_executor(node.task_executor().clone())
|
||||
.with_evm_config(node.evm_config())
|
||||
.build_with_auth_server(module_config, engine_api);
|
||||
|
||||
let mut registry = RpcRegistry { registry };
|
||||
let ctx = RpcContext {
|
||||
node: node.clone(),
|
||||
config,
|
||||
registry: &mut registry,
|
||||
modules: &mut modules,
|
||||
auth_module: &mut auth_module,
|
||||
};
|
||||
|
||||
extend_rpc_modules.extend_rpc_modules(ctx)?;
|
||||
|
||||
let server_config = config.rpc.rpc_server_config();
|
||||
let launch_rpc = modules.clone().start_server(server_config).map_ok(|handle| {
|
||||
if let Some(url) = handle.ipc_endpoint() {
|
||||
info!(target: "reth::cli", url=%url, "RPC IPC server started");
|
||||
}
|
||||
if let Some(addr) = handle.http_local_addr() {
|
||||
info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
|
||||
}
|
||||
if let Some(addr) = handle.ws_local_addr() {
|
||||
info!(target: "reth::cli", url=%addr, "RPC WS server started");
|
||||
}
|
||||
handle
|
||||
});
|
||||
|
||||
let launch_auth = auth_module.clone().start_server(auth_config).map_ok(|handle| {
|
||||
let addr = handle.local_addr();
|
||||
info!(target: "reth::cli", url=%addr, "RPC auth server started");
|
||||
handle
|
||||
});
|
||||
|
||||
// launch servers concurrently
|
||||
let (rpc, auth) = futures::future::try_join(launch_rpc, launch_auth).await?;
|
||||
let handles = RethRpcServerHandles { rpc, auth };
|
||||
|
||||
let ctx = RpcContext {
|
||||
node,
|
||||
config,
|
||||
registry: &mut registry,
|
||||
modules: &mut modules,
|
||||
auth_module: &mut auth_module,
|
||||
};
|
||||
|
||||
on_rpc_started.on_rpc_started(ctx, handles.clone())?;
|
||||
|
||||
Ok((handles, registry))
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use reth_primitives::{TxHash, B256};
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Parameters for debugging purposes
|
||||
#[derive(Debug, Args, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, Args, PartialEq, Default)]
|
||||
#[clap(next_help_heading = "Debug")]
|
||||
pub struct DebugArgs {
|
||||
/// Prompt the downloader to download blocks one at a time.
|
||||
|
||||
@@ -11,7 +11,7 @@ use secp256k1::SecretKey;
|
||||
use std::{net::Ipv4Addr, path::PathBuf, sync::Arc};
|
||||
|
||||
/// Parameters for configuring the network more granularity via CLI
|
||||
#[derive(Debug, Args, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq)]
|
||||
#[clap(next_help_heading = "Networking")]
|
||||
pub struct NetworkArgs {
|
||||
/// Disable the discovery service.
|
||||
@@ -160,7 +160,7 @@ impl Default for NetworkArgs {
|
||||
}
|
||||
|
||||
/// Arguments to setup discovery
|
||||
#[derive(Debug, Args, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq)]
|
||||
pub struct DiscoveryArgs {
|
||||
/// Disable the discovery service.
|
||||
#[arg(short, long, default_value_if("dev", "true", "true"))]
|
||||
|
||||
@@ -12,7 +12,7 @@ use reth_primitives::constants::{
|
||||
use std::{borrow::Cow, ffi::OsStr, time::Duration};
|
||||
|
||||
/// Parameters for configuring the Payload Builder
|
||||
#[derive(Debug, Args, PartialEq)]
|
||||
#[derive(Debug, Clone, Args, PartialEq)]
|
||||
#[clap(next_help_heading = "Builder")]
|
||||
pub struct PayloadBuilderArgs {
|
||||
/// Block extra data set by the payload builder.
|
||||
|
||||
@@ -8,7 +8,7 @@ use reth_primitives::{
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Parameters for pruning and full node
|
||||
#[derive(Debug, Args, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, Args, PartialEq, Default)]
|
||||
#[clap(next_help_heading = "Pruning")]
|
||||
pub struct PruningArgs {
|
||||
/// Run full node. Only the most recent [`MINIMUM_PRUNING_DISTANCE`] block states are stored.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! clap [Args](clap::Args) for op-reth rollup configuration
|
||||
|
||||
/// Parameters for rollup configuration
|
||||
#[derive(Debug, Default, PartialEq, Eq, clap::Args)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)]
|
||||
#[clap(next_help_heading = "Rollup")]
|
||||
pub struct RollupArgs {
|
||||
/// HTTP endpoint for the sequencer mempool
|
||||
|
||||
@@ -9,7 +9,7 @@ use reth_transaction_pool::{
|
||||
TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
|
||||
};
|
||||
/// Parameters for debugging purposes
|
||||
#[derive(Debug, Args, PartialEq)]
|
||||
#[derive(Debug, Clone, Args, PartialEq)]
|
||||
#[clap(next_help_heading = "TxPool")]
|
||||
pub struct TxPoolArgs {
|
||||
/// Max number of transaction in the pending sub-pool.
|
||||
|
||||
@@ -26,6 +26,7 @@ pub trait FullProvider<DB: Database>:
|
||||
+ EvmEnvProvider
|
||||
+ ChainSpecProvider
|
||||
+ ChangeSetReader
|
||||
+ CanonStateSubscriptions
|
||||
+ Clone
|
||||
+ Unpin
|
||||
+ 'static
|
||||
@@ -40,6 +41,7 @@ impl<T, DB: Database> FullProvider<DB> for T where
|
||||
+ EvmEnvProvider
|
||||
+ ChainSpecProvider
|
||||
+ ChangeSetReader
|
||||
+ CanonStateSubscriptions
|
||||
+ Clone
|
||||
+ Unpin
|
||||
+ 'static
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{str::FromStr, sync::Arc};
|
||||
|
||||
/// A type that represents either a _real_ (represented by a path), or _test_ database, which will
|
||||
/// use a [TempDatabase].
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DatabaseBuilder {
|
||||
/// The real database type, with a specified data dir
|
||||
Real(MaybePlatformPath<DataDirPath>),
|
||||
|
||||
@@ -47,7 +47,7 @@ impl From<DatabaseError> for InitDatabaseError {
|
||||
|
||||
/// Write the genesis block if it has not already been written
|
||||
pub fn init_genesis<DB: Database>(
|
||||
db: Arc<DB>,
|
||||
db: DB,
|
||||
chain: Arc<ChainSpec>,
|
||||
) -> Result<B256, InitDatabaseError> {
|
||||
let genesis = chain.genesis();
|
||||
|
||||
@@ -136,7 +136,7 @@ pub static PROMETHEUS_RECORDER_HANDLE: Lazy<PrometheusHandle> =
|
||||
/// let builder = builder.with_rpc(rpc);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NodeConfig {
|
||||
/// The test database
|
||||
pub database: DatabaseBuilder,
|
||||
@@ -349,6 +349,11 @@ impl NodeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns pruning configuration.
|
||||
pub fn prune_config(&self) -> eyre::Result<Option<PruneConfig>> {
|
||||
self.pruning.prune_config(Arc::clone(&self.chain))
|
||||
}
|
||||
|
||||
/// Returns the max block that the node should run to, looking it up from the network if
|
||||
/// necessary
|
||||
pub async fn max_block<Provider, Client>(
|
||||
@@ -383,7 +388,9 @@ impl NodeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a network and spawn it
|
||||
/// Create the [NetworkBuilder].
|
||||
///
|
||||
/// This only configures it and does not spawn it.
|
||||
pub async fn build_network<C>(
|
||||
&self,
|
||||
config: &Config,
|
||||
|
||||
@@ -14,8 +14,24 @@ workspace = true
|
||||
# reth
|
||||
reth-primitives.workspace = true
|
||||
reth-payload-builder.workspace = true
|
||||
reth-basic-payload-builder.workspace = true
|
||||
reth-ethereum-payload-builder.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
reth-node-api.workspace = true
|
||||
reth-node-builder.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-network.workspace = true
|
||||
|
||||
# io
|
||||
# misc
|
||||
eyre.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-db.workspace = true
|
||||
|
||||
[features]
|
||||
# This is a workaround for reth-cli crate to allow this as mandatory dependency without breaking the build even if unused.
|
||||
# This makes managing features and testing workspace easier because clippy always builds all members if --workspace is provided
|
||||
optimism = []
|
||||
@@ -1,4 +1,4 @@
|
||||
use reth_node_api::ConfigureEvmEnv;
|
||||
use reth_node_api::{evm::EvmConfig, ConfigureEvmEnv};
|
||||
use reth_primitives::{
|
||||
revm::{config::revm_spec, env::fill_tx_env},
|
||||
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
|
||||
@@ -44,6 +44,9 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
impl EvmConfig for EthEvmConfig {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -16,3 +16,6 @@ pub use engine::EthEngineTypes;
|
||||
/// [ConfigureEvmEnv](reth_node_api::ConfigureEvmEnv) trait.
|
||||
pub mod evm;
|
||||
pub use evm::EthEvmConfig;
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
pub mod node;
|
||||
|
||||
182
crates/node-ethereum/src/node.rs
Normal file
182
crates/node-ethereum/src/node.rs
Normal file
@@ -0,0 +1,182 @@
|
||||
//! Node types config.
|
||||
|
||||
//! Ethereum node types
|
||||
|
||||
use crate::{EthEngineTypes, EthEvmConfig};
|
||||
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_node_builder::{
|
||||
components::{ComponentsBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder},
|
||||
node::{FullNodeTypes, NodeTypes},
|
||||
BuilderContext, PayloadBuilderConfig,
|
||||
};
|
||||
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
|
||||
use reth_provider::CanonStateSubscriptions;
|
||||
use reth_tracing::tracing::{debug, info};
|
||||
use reth_transaction_pool::{
|
||||
blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool,
|
||||
TransactionValidationTaskExecutor,
|
||||
};
|
||||
|
||||
/// Type configuration for a regular Ethereum node.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct EthereumNode;
|
||||
// TODO make this stateful with evm config
|
||||
|
||||
impl EthereumNode {
|
||||
/// Returns a [ComponentsBuilder] configured for a regular Ethereum node.
|
||||
pub fn components<Node>(
|
||||
) -> ComponentsBuilder<Node, EthereumPoolBuilder, EthereumPayloadBuilder, EthereumNetwork>
|
||||
where
|
||||
Node: FullNodeTypes<Engine = EthEngineTypes>,
|
||||
{
|
||||
ComponentsBuilder::default()
|
||||
.node_types::<Node>()
|
||||
.pool(EthereumPoolBuilder::default())
|
||||
.payload(EthereumPayloadBuilder::default())
|
||||
.network(EthereumNetwork::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeTypes for EthereumNode {
|
||||
type Primitives = ();
|
||||
type Engine = EthEngineTypes;
|
||||
type Evm = EthEvmConfig;
|
||||
|
||||
fn evm_config(&self) -> Self::Evm {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// A basic ethereum transaction pool.
|
||||
///
|
||||
/// This contains various settings that can be configured and take precedence over the node's
|
||||
/// config.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct EthereumPoolBuilder {
|
||||
// TODO add options for txpool args
|
||||
}
|
||||
|
||||
impl<Node> PoolBuilder<Node> for EthereumPoolBuilder
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
{
|
||||
type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore>;
|
||||
|
||||
fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
|
||||
let data_dir = ctx.data_dir();
|
||||
let blob_store = DiskFileBlobStore::open(data_dir.blobstore_path(), Default::default())?;
|
||||
let validator = TransactionValidationTaskExecutor::eth_builder(ctx.chain_spec())
|
||||
.with_head_timestamp(ctx.head().timestamp)
|
||||
.kzg_settings(ctx.kzg_settings()?)
|
||||
.with_additional_tasks(1)
|
||||
.build_with_tasks(
|
||||
ctx.provider().clone(),
|
||||
ctx.task_executor().clone(),
|
||||
blob_store.clone(),
|
||||
);
|
||||
|
||||
let transaction_pool =
|
||||
reth_transaction_pool::Pool::eth_pool(validator, blob_store, ctx.pool_config());
|
||||
info!(target: "reth::cli", "Transaction pool initialized");
|
||||
let transactions_path = data_dir.txpool_transactions_path();
|
||||
|
||||
// spawn txpool maintenance task
|
||||
{
|
||||
let pool = transaction_pool.clone();
|
||||
let chain_events = ctx.provider().canonical_state_stream();
|
||||
let client = ctx.provider().clone();
|
||||
let transactions_backup_config =
|
||||
reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path);
|
||||
|
||||
ctx.task_executor().spawn_critical_with_graceful_shutdown_signal(
|
||||
"local transactions backup task",
|
||||
|shutdown| {
|
||||
reth_transaction_pool::maintain::backup_local_transactions_task(
|
||||
shutdown,
|
||||
pool.clone(),
|
||||
transactions_backup_config,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
// spawn the maintenance task
|
||||
ctx.task_executor().spawn_critical(
|
||||
"txpool maintenance task",
|
||||
reth_transaction_pool::maintain::maintain_transaction_pool_future(
|
||||
client,
|
||||
pool,
|
||||
chain_events,
|
||||
ctx.task_executor().clone(),
|
||||
Default::default(),
|
||||
),
|
||||
);
|
||||
debug!(target: "reth::cli", "Spawned txpool maintenance task");
|
||||
}
|
||||
|
||||
Ok(transaction_pool)
|
||||
}
|
||||
}
|
||||
|
||||
/// A basic ethereum payload service.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct EthereumPayloadBuilder;
|
||||
|
||||
impl<Node, Pool> PayloadServiceBuilder<Node, Pool> for EthereumPayloadBuilder
|
||||
where
|
||||
Node: FullNodeTypes<Engine = EthEngineTypes>,
|
||||
Pool: TransactionPool + Unpin + 'static,
|
||||
{
|
||||
fn spawn_payload_service(
|
||||
self,
|
||||
ctx: &BuilderContext<Node>,
|
||||
pool: Pool,
|
||||
) -> eyre::Result<PayloadBuilderHandle<Node::Engine>> {
|
||||
let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::default();
|
||||
let conf = ctx.payload_builder_config();
|
||||
|
||||
let payload_job_config = BasicPayloadJobGeneratorConfig::default()
|
||||
.interval(conf.interval())
|
||||
.deadline(conf.deadline())
|
||||
.max_payload_tasks(conf.max_payload_tasks())
|
||||
.extradata(conf.extradata_rlp_bytes())
|
||||
.max_gas_limit(conf.max_gas_limit());
|
||||
|
||||
let payload_generator = BasicPayloadJobGenerator::with_builder(
|
||||
ctx.provider().clone(),
|
||||
pool,
|
||||
ctx.task_executor().clone(),
|
||||
payload_job_config,
|
||||
ctx.chain_spec(),
|
||||
payload_builder,
|
||||
);
|
||||
let (payload_service, payload_builder) =
|
||||
PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream());
|
||||
|
||||
ctx.task_executor().spawn_critical("payload builder service", Box::pin(payload_service));
|
||||
|
||||
Ok(payload_builder)
|
||||
}
|
||||
}
|
||||
|
||||
/// A basic ethereum payload service.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct EthereumNetwork {
|
||||
// TODO add closure to modify network
|
||||
}
|
||||
|
||||
impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetwork
|
||||
where
|
||||
Node: FullNodeTypes,
|
||||
Pool: TransactionPool + Unpin + 'static,
|
||||
{
|
||||
fn build_network(self, ctx: &BuilderContext<Node>, pool: Pool) -> eyre::Result<NetworkHandle> {
|
||||
let network = ctx.network_builder_blocking()?;
|
||||
let handle = ctx.start_network(network, pool);
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
34
crates/node-ethereum/tests/it/builder.rs
Normal file
34
crates/node-ethereum/tests/it/builder.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
//! Node builder setup tests.
|
||||
|
||||
use reth_db::test_utils::create_test_rw_db;
|
||||
use reth_node_builder::{components::FullNodeComponents, NodeBuilder, NodeConfig};
|
||||
use reth_node_ethereum::node::EthereumNode;
|
||||
|
||||
#[test]
|
||||
fn test_basic_setup() {
|
||||
// parse CLI -> config
|
||||
let config = NodeConfig::test();
|
||||
let db = create_test_rw_db();
|
||||
let msg = "On components".to_string();
|
||||
let _builder = NodeBuilder::new(config)
|
||||
.with_database(db)
|
||||
.with_types(EthereumNode::default())
|
||||
.with_components(EthereumNode::components())
|
||||
.on_component_initialized(move |ctx| {
|
||||
let _provider = ctx.provider();
|
||||
println!("{msg}");
|
||||
Ok(())
|
||||
})
|
||||
.on_node_started(|_full_node| Ok(()))
|
||||
.on_rpc_started(|_ctx, handles| {
|
||||
let _client = handles.rpc.http_client();
|
||||
Ok(())
|
||||
})
|
||||
.extend_rpc_modules(|ctx| {
|
||||
let _ = ctx.config();
|
||||
let _ = ctx.node().provider();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.check_launch();
|
||||
}
|
||||
4
crates/node-ethereum/tests/it/main.rs
Normal file
4
crates/node-ethereum/tests/it/main.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
mod builder;
|
||||
|
||||
fn main() {}
|
||||
@@ -928,7 +928,7 @@ impl Serialize for RethRpcModule {
|
||||
}
|
||||
|
||||
/// A Helper type the holds instances of the configured modules.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RethModuleRegistry<Provider, Pool, Network, Tasks, Events, EvmConfig> {
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
|
||||
@@ -298,6 +298,12 @@ impl TaskExecutor {
|
||||
&self.on_shutdown
|
||||
}
|
||||
|
||||
/// Runs a future to completion on this Handle's associated Runtime.
|
||||
#[track_caller]
|
||||
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
|
||||
self.handle.block_on(future)
|
||||
}
|
||||
|
||||
/// Spawns a future on the tokio runtime depending on the [TaskKind]
|
||||
fn spawn_on_rt<F>(&self, fut: F, task_kind: TaskKind) -> JoinHandle<()>
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user