feat: integrate builder (#6611)

This commit is contained in:
Matthias Seitz
2024-02-29 17:50:04 +01:00
committed by GitHub
parent 7d36206dfe
commit c5955f1305
73 changed files with 2201 additions and 3022 deletions

View File

@@ -1,230 +0,0 @@
//! Components that are used by the node command.
use reth_db::database::Database;
use reth_network::{NetworkEvents, NetworkProtocols};
use reth_network_api::{NetworkInfo, Peers};
use reth_node_api::ConfigureEvmEnv;
use reth_primitives::ChainSpec;
use reth_provider::{
AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
DatabaseProviderFactory, EvmEnvProvider, StateProviderFactory,
};
use reth_rpc_builder::{
auth::{AuthRpcModule, AuthServerHandle},
RethModuleRegistry, RpcServerHandle, TransportRpcModules,
};
use reth_tasks::TaskSpawner;
use reth_transaction_pool::TransactionPool;
use std::{marker::PhantomData, sync::Arc};
/// 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
{
}
/// The trait that is implemented for the Node command.
pub trait RethNodeComponents: Clone + Send + Sync + 'static {
/// Underlying database type.
type DB: Database + Clone + Unpin + 'static;
/// The Provider type that is provided by the node itself
type Provider: FullProvider<Self::DB>;
/// The transaction pool type
type Pool: TransactionPool + Clone + Unpin + 'static;
/// The network type used to communicate with p2p.
type Network: NetworkInfo + Peers + NetworkProtocols + NetworkEvents + Clone + Unpin + 'static;
/// The events type used to create subscriptions.
type Events: CanonStateSubscriptions + Clone + 'static;
/// The type that is used to spawn tasks.
type Tasks: TaskSpawner + Clone + Unpin + 'static;
/// The type that defines how to configure the EVM before execution.
type EvmConfig: ConfigureEvmEnv + 'static;
/// Returns the instance of the provider
fn provider(&self) -> Self::Provider;
/// Returns the instance of the task executor.
fn task_executor(&self) -> Self::Tasks;
/// Returns the instance of the transaction pool.
fn pool(&self) -> Self::Pool;
/// Returns the instance of the network API.
fn network(&self) -> Self::Network;
/// Returns the instance of the events subscription handler.
fn events(&self) -> Self::Events;
/// Returns the instance of the EVM config.
fn evm_config(&self) -> Self::EvmConfig;
/// Helper function to return the chain spec.
fn chain_spec(&self) -> Arc<ChainSpec> {
self.provider().chain_spec()
}
}
/// 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].
#[derive(Debug)]
#[allow(clippy::type_complexity)]
pub struct RethRpcComponents<'a, Reth: RethNodeComponents> {
/// 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 RethModuleRegistry<
Reth::Provider,
Reth::Pool,
Reth::Network,
Reth::Tasks,
Reth::Events,
Reth::EvmConfig,
>,
/// 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,
}
/// A Generic implementation of the RethNodeComponents trait.
///
/// Represents components required for the Reth node.
#[derive(Clone, Debug)]
pub struct RethNodeComponentsImpl<DB, Provider, Pool, Network, Events, Tasks, EvmConfig> {
/// Represents underlying database type.
__phantom: PhantomData<DB>,
/// Represents the provider instance.
pub provider: Provider,
/// Represents the transaction pool instance.
pub pool: Pool,
/// Represents the network instance used for communication.
pub network: Network,
/// Represents the task executor instance.
pub task_executor: Tasks,
/// Represents the events subscription handler instance.
pub events: Events,
/// Represents the type that is used to configure the EVM before execution.
pub evm_config: EvmConfig,
}
impl<DB, Provider, Pool, Network, Events, Tasks, EvmConfig>
RethNodeComponentsImpl<DB, Provider, Pool, Network, Events, Tasks, EvmConfig>
{
/// Create new instance of the node components.
pub fn new(
provider: Provider,
pool: Pool,
network: Network,
task_executor: Tasks,
events: Events,
evm_config: EvmConfig,
) -> Self {
Self {
provider,
pool,
network,
task_executor,
events,
evm_config,
__phantom: std::marker::PhantomData,
}
}
}
impl<DB, Provider, Pool, Network, Events, Tasks, EvmConfig> RethNodeComponents
for RethNodeComponentsImpl<DB, Provider, Pool, Network, Events, Tasks, EvmConfig>
where
DB: Database + Clone + Unpin + 'static,
Provider: FullProvider<DB> + Clone + 'static,
Tasks: TaskSpawner + Clone + Unpin + 'static,
Pool: TransactionPool + Clone + Unpin + 'static,
Network: NetworkInfo + Peers + NetworkProtocols + NetworkEvents + Clone + Unpin + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
EvmConfig: ConfigureEvmEnv + 'static,
{
type DB = DB;
type Provider = Provider;
type Pool = Pool;
type Network = Network;
type Events = Events;
type Tasks = Tasks;
type EvmConfig = EvmConfig;
fn provider(&self) -> Self::Provider {
self.provider.clone()
}
fn task_executor(&self) -> Self::Tasks {
self.task_executor.clone()
}
fn pool(&self) -> Self::Pool {
self.pool.clone()
}
fn network(&self) -> Self::Network {
self.network.clone()
}
fn events(&self) -> Self::Events {
self.events.clone()
}
fn evm_config(&self) -> Self::EvmConfig {
self.evm_config.clone()
}
}
/// Contains the handles to the spawned RPC servers.
///
/// This can be used to access the endpoints of the servers.
///
/// # Example
///
/// ```rust
/// use reth_node_core::{cli::components::RethRpcServerHandles, rpc::api::EthApiClient};
/// # async fn t(handles: RethRpcServerHandles) {
/// let client = handles.rpc.http_client().expect("http server not started");
/// let block_number = client.block_number().await.unwrap();
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct RethRpcServerHandles {
/// The regular RPC server handle.
pub rpc: RpcServerHandle,
/// The handle to the auth server (engine API)
pub auth: AuthServerHandle,
}

View File

@@ -105,10 +105,6 @@ pub trait PayloadBuilderConfig {
/// Maximum number of tasks to spawn for building a payload.
fn max_payload_tasks(&self) -> usize;
/// Returns whether or not to construct the pending block.
#[cfg(feature = "optimism")]
fn compute_pending_block(&self) -> bool;
}
/// A trait that represents the configured network and can be used to apply additional configuration

View File

@@ -1,125 +0,0 @@
//! A real or test database type
use crate::dirs::{ChainPath, DataDirPath, MaybePlatformPath};
use alloy_chains::Chain;
use reth_db::{
init_db,
mdbx::DatabaseArguments,
test_utils::{create_test_rw_db, TempDatabase},
DatabaseEnv,
};
use reth_interfaces::db::LogLevel;
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, Clone)]
pub enum DatabaseBuilder {
/// The real database type, with a specified data dir
Real(MaybePlatformPath<DataDirPath>),
/// The test database type
Test,
}
impl DatabaseBuilder {
/// Creates a _test_ database
pub fn test() -> Self {
Self::Test
}
/// Initializes and returns the [DatabaseInstance] depending on the current database type.
///
/// If the [DatabaseBuilder] is test, then the [ChainPath] constructed will be derived from the
/// db path of the [TempDatabase] and the given chain. The [LogLevel] will not be used.
///
/// If the [DatabaseBuilder] is real, then the db will be initialized using the given log level
/// and the [ChainPath] will be derived from the given path and chain. This database path is
/// then passed into [init_db].
pub fn init_db(
self,
log_level: Option<LogLevel>,
chain: Chain,
) -> eyre::Result<DatabaseInstance> {
match self {
DatabaseBuilder::Test => {
let db = create_test_rw_db();
let db_path_str = db.path().to_str().expect("Path is not valid unicode");
let path = MaybePlatformPath::<DataDirPath>::from_str(db_path_str)
.expect("Path is not valid");
let data_dir = path.unwrap_or_chain_default(chain);
Ok(DatabaseInstance::Test { db, data_dir })
}
DatabaseBuilder::Real(path) => {
let data_dir = path.unwrap_or_chain_default(chain);
let db_path = data_dir.db_path();
tracing::info!(target: "reth::cli", path = ?db_path, "Opening database");
let db = Arc::new(
init_db(db_path.clone(), DatabaseArguments::default().log_level(log_level))?
.with_metrics(),
);
Ok(DatabaseInstance::Real { db, data_dir })
}
}
}
}
/// The [Default] implementation for [DatabaseBuilder] uses the _real_ variant, using the default
/// value for the inner [MaybePlatformPath].
impl Default for DatabaseBuilder {
fn default() -> Self {
Self::Real(MaybePlatformPath::<DataDirPath>::default())
}
}
/// A constructed database type, with a [ChainPath].
#[derive(Debug, Clone)]
pub enum DatabaseInstance {
/// The test database
Test {
/// The database
db: Arc<TempDatabase<DatabaseEnv>>,
/// The data dir
data_dir: ChainPath<DataDirPath>,
},
/// The real database
Real {
/// The database
db: Arc<DatabaseEnv>,
/// The data dir
data_dir: ChainPath<DataDirPath>,
},
}
impl DatabaseInstance {
/// Returns the data dir for this database instance
pub fn data_dir(&self) -> &ChainPath<DataDirPath> {
match self {
Self::Test { data_dir, .. } => data_dir,
Self::Real { data_dir, .. } => data_dir,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_database_db_dir() {
// create temp dir to test that the db path is correct
let tempdir = tempfile::tempdir().unwrap();
let expected_datadir_path = tempdir.path().to_path_buf();
let expected_db_path = tempdir.path().join("db");
let datadir_path = MaybePlatformPath::<DataDirPath>::from(tempdir.path().to_path_buf());
let db = DatabaseBuilder::Real(datadir_path);
let db = db.init_db(None, Chain::mainnet()).unwrap();
// ensure that the datadir path is correct
assert_eq!(db.data_dir().data_dir_path(), expected_datadir_path);
// ensure that the db path is correct
assert_eq!(db.data_dir().db_path(), expected_db_path);
}
}

View File

@@ -1,360 +0,0 @@
//! Support for integrating customizations into the CLI.
use crate::cli::{
components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles},
config::{PayloadBuilderConfig, RethNetworkConfig, RethRpcConfig},
};
use clap::Args;
use reth_basic_payload_builder::{
BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, PayloadBuilder,
};
use reth_node_api::EngineTypes;
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_provider::CanonStateSubscriptions;
use reth_tasks::TaskSpawner;
use std::{fmt, marker::PhantomData};
/// A trait that allows for extending parts of the CLI with additional functionality.
///
/// This is intended as a way to allow to _extend_ the node command. For example, to register
/// additional RPC namespaces.
pub trait RethCliExt {
/// Provides additional configuration for the node CLI command.
///
/// This supports additional CLI arguments that can be used to modify the node configuration.
///
/// If no additional CLI arguments are required, the [NoArgs] wrapper type can be used.
type Node: RethNodeCommandExt;
}
/// The default CLI extension.
impl RethCliExt for () {
type Node = DefaultRethNodeCommandConfig;
}
/// A trait that allows for extending and customizing parts of the rethr node command.
///
/// The functions are invoked during the initialization of the node command in the following order:
///
/// 1. [configure_network](RethNodeCommandConfig::configure_network)
/// 2. [on_components_initialized](RethNodeCommandConfig::on_components_initialized)
/// 3. [spawn_payload_builder_service](RethNodeCommandConfig::spawn_payload_builder_service)
/// 4. [extend_rpc_modules](RethNodeCommandConfig::extend_rpc_modules)
/// 5. [on_rpc_server_started](RethNodeCommandConfig::on_rpc_server_started)
/// 6. [on_node_started](RethNodeCommandConfig::on_node_started)
pub trait RethNodeCommandConfig: fmt::Debug {
/// Invoked with the network configuration before the network is configured.
///
/// This allows additional configuration of the network before it is launched.
fn configure_network<Conf, Reth>(
&mut self,
config: &mut Conf,
components: &Reth,
) -> eyre::Result<()>
where
Conf: RethNetworkConfig,
Reth: RethNodeComponents,
{
let _ = config;
let _ = components;
Ok(())
}
/// Event hook called once all components have been initialized.
///
/// This is called as soon as the node components have been initialized.
fn on_components_initialized<Reth: RethNodeComponents>(
&mut self,
components: &Reth,
) -> eyre::Result<()> {
let _ = components;
Ok(())
}
/// Event hook called once the node has been launched.
///
/// This is called last after the node has been launched.
fn on_node_started<Reth: RethNodeComponents>(&mut self, components: &Reth) -> eyre::Result<()> {
let _ = components;
Ok(())
}
/// Event hook called once the rpc servers has been started.
///
/// This is called after the rpc server has been started.
fn on_rpc_server_started<Conf, Reth>(
&mut self,
config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
handles: RethRpcServerHandles,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
let _ = config;
let _ = components;
let _ = rpc_components;
let _ = handles;
Ok(())
}
/// Allows for registering additional RPC modules for the transports.
///
/// This is expected to call the merge functions of [reth_rpc_builder::TransportRpcModules], for
/// example [reth_rpc_builder::TransportRpcModules::merge_configured].
///
/// This is called before the rpc server will be started [Self::on_rpc_server_started].
fn extend_rpc_modules<Conf, Reth>(
&mut self,
config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
let _ = config;
let _ = components;
let _ = rpc_components;
Ok(())
}
/// Configures the [PayloadBuilderService] for the node, spawns it and returns the
/// [PayloadBuilderHandle].
///
/// By default this spawns a [BasicPayloadJobGenerator] with the default configuration
/// [BasicPayloadJobGeneratorConfig].
fn spawn_payload_builder_service<Conf, Reth, Builder, Engine>(
&mut self,
conf: &Conf,
components: &Reth,
payload_builder: Builder,
) -> eyre::Result<PayloadBuilderHandle<Engine>>
where
Conf: PayloadBuilderConfig,
Reth: RethNodeComponents,
Engine: EngineTypes + 'static,
Builder: PayloadBuilder<
Reth::Pool,
Reth::Provider,
Attributes = Engine::PayloadBuilderAttributes,
BuiltPayload = Engine::BuiltPayload,
> + Unpin
+ 'static,
{
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());
// no extradata for optimism
#[cfg(feature = "optimism")]
let payload_job_config = payload_job_config.extradata(Default::default());
let payload_generator = BasicPayloadJobGenerator::with_builder(
components.provider(),
components.pool(),
components.task_executor(),
payload_job_config,
components.chain_spec(),
payload_builder,
);
let (payload_service, payload_builder) = PayloadBuilderService::new(
payload_generator,
components.events().canonical_state_stream(),
);
components
.task_executor()
.spawn_critical("payload builder service", Box::pin(payload_service));
Ok(payload_builder)
}
}
/// A trait that allows for extending parts of the CLI with additional functionality.
pub trait RethNodeCommandExt: RethNodeCommandConfig + fmt::Debug + clap::Args {}
// blanket impl for all types that implement the required traits.
impl<T> RethNodeCommandExt for T where T: RethNodeCommandConfig + fmt::Debug + clap::Args {}
/// The default configuration for the reth node command.
///
/// This is a convenience type for [NoArgs<()>].
#[derive(Debug, Clone, Copy, Default, Args)]
#[non_exhaustive]
pub struct DefaultRethNodeCommandConfig;
impl RethNodeCommandConfig for DefaultRethNodeCommandConfig {}
impl RethNodeCommandConfig for () {}
/// A helper type for [RethCliExt] extension that don't require any additional clap Arguments.
#[derive(Debug, Clone, Copy)]
pub struct NoArgsCliExt<Conf>(PhantomData<Conf>);
impl<Conf: RethNodeCommandConfig> RethCliExt for NoArgsCliExt<Conf> {
type Node = NoArgs<Conf>;
}
/// A helper struct that allows for wrapping a [RethNodeCommandConfig] value without providing
/// additional CLI arguments.
///
/// Note: This type must be manually filled with a [RethNodeCommandConfig] manually before executing
/// the reth node command.
#[derive(Debug, Clone, Copy, Default, Args)]
pub struct NoArgs<T = ()> {
#[arg(skip)]
inner: Option<T>,
}
impl<T> NoArgs<T> {
/// Creates a new instance of the wrapper type.
pub fn with(inner: T) -> Self {
Self { inner: Some(inner) }
}
/// Sets the inner value.
pub fn set(&mut self, inner: T) {
self.inner = Some(inner)
}
/// Transforms the configured value.
pub fn map<U>(self, inner: U) -> NoArgs<U> {
NoArgs::with(inner)
}
/// Returns the inner value if it exists.
pub fn inner(&self) -> Option<&T> {
self.inner.as_ref()
}
/// Returns a mutable reference to the inner value if it exists.
pub fn inner_mut(&mut self) -> Option<&mut T> {
self.inner.as_mut()
}
/// Consumes the wrapper and returns the inner value if it exists.
pub fn into_inner(self) -> Option<T> {
self.inner
}
}
impl<T: RethNodeCommandConfig> RethNodeCommandConfig for NoArgs<T> {
fn configure_network<Conf, Reth>(
&mut self,
config: &mut Conf,
components: &Reth,
) -> eyre::Result<()>
where
Conf: RethNetworkConfig,
Reth: RethNodeComponents,
{
if let Some(conf) = self.inner_mut() {
conf.configure_network(config, components)
} else {
Ok(())
}
}
fn on_components_initialized<Reth: RethNodeComponents>(
&mut self,
components: &Reth,
) -> eyre::Result<()> {
if let Some(conf) = self.inner_mut() {
conf.on_components_initialized(components)
} else {
Ok(())
}
}
fn on_node_started<Reth: RethNodeComponents>(&mut self, components: &Reth) -> eyre::Result<()> {
if let Some(conf) = self.inner_mut() {
conf.on_node_started(components)
} else {
Ok(())
}
}
fn on_rpc_server_started<Conf, Reth>(
&mut self,
config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
handles: RethRpcServerHandles,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
if let Some(conf) = self.inner_mut() {
conf.on_rpc_server_started(config, components, rpc_components, handles)
} else {
Ok(())
}
}
fn extend_rpc_modules<Conf, Reth>(
&mut self,
config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
if let Some(conf) = self.inner_mut() {
conf.extend_rpc_modules(config, components, rpc_components)
} else {
Ok(())
}
}
fn spawn_payload_builder_service<Conf, Reth, Builder, Engine>(
&mut self,
conf: &Conf,
components: &Reth,
payload_builder: Builder,
) -> eyre::Result<PayloadBuilderHandle<Engine>>
where
Conf: PayloadBuilderConfig,
Reth: RethNodeComponents,
Engine: EngineTypes + 'static,
Builder: PayloadBuilder<
Reth::Pool,
Reth::Provider,
Attributes = Engine::PayloadBuilderAttributes,
BuiltPayload = Engine::BuiltPayload,
> + Unpin
+ 'static,
{
self.inner_mut()
.ok_or_else(|| eyre::eyre!("config value must be set"))?
.spawn_payload_builder_service(conf, components, payload_builder)
}
}
impl<T> From<T> for NoArgs<T> {
fn from(value: T) -> Self {
Self::with(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_ext<T: RethNodeCommandExt>() {}
#[test]
fn ensure_ext() {
assert_ext::<DefaultRethNodeCommandConfig>();
assert_ext::<NoArgs<()>>();
}
}

View File

@@ -1,7 +1,4 @@
//! Types for the CLI.
//! Additional CLI configuration support.
pub mod components;
pub mod config;
pub mod db_type;
pub mod ext;
pub mod runner;