From db158f29f46aef53d23a0906996ce23080ccc021 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 15 Feb 2024 14:59:53 +0100 Subject: [PATCH] feat: add OptimismNode type (#6610) Co-authored-by: Emilia Hane --- Cargo.lock | 11 ++ crates/node-builder/src/handle.rs | 7 + crates/node-builder/src/node.rs | 8 +- crates/node-ethereum/src/node.rs | 4 +- crates/node-optimism/Cargo.toml | 25 +++- crates/node-optimism/src/evm.rs | 5 +- crates/node-optimism/src/lib.rs | 3 + crates/node-optimism/src/node.rs | 178 +++++++++++++++++++++++ crates/node-optimism/tests/it/builder.rs | 32 ++++ crates/node-optimism/tests/it/main.rs | 4 + 10 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 crates/node-optimism/src/node.rs create mode 100644 crates/node-optimism/tests/it/builder.rs create mode 100644 crates/node-optimism/tests/it/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3727670037..40d72459a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6493,10 +6493,21 @@ dependencies = [ name = "reth-node-optimism" version = "0.1.0-alpha.18" dependencies = [ + "eyre", + "reth-basic-payload-builder", + "reth-db", + "reth-network", "reth-node-api", + "reth-node-builder", + "reth-optimism-payload-builder", "reth-payload-builder", "reth-primitives", + "reth-provider", + "reth-rpc", "reth-rpc-types", + "reth-rpc-types-compat", + "reth-tracing", + "reth-transaction-pool", "serde", ] diff --git a/crates/node-builder/src/handle.rs b/crates/node-builder/src/handle.rs index a8f3f5f46a..dbdeedccc9 100644 --- a/crates/node-builder/src/handle.rs +++ b/crates/node-builder/src/handle.rs @@ -10,6 +10,13 @@ pub struct NodeHandle { pub node_exit_future: NodeExitFuture, } +impl NodeHandle { + /// Waits for the node to exit, if it was configured to exit. + pub async fn wait_for_node_exit(self) -> eyre::Result<()> { + self.node_exit_future.await + } +} + impl fmt::Debug for NodeHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NodeHandle") diff --git a/crates/node-builder/src/node.rs b/crates/node-builder/src/node.rs index 8c3d539531..68a9d3b967 100644 --- a/crates/node-builder/src/node.rs +++ b/crates/node-builder/src/node.rs @@ -1,4 +1,7 @@ -use crate::{components::FullNodeComponents, rpc::RethRpcServerHandles}; +use crate::{ + components::FullNodeComponents, + rpc::{RethRpcServerHandles, RpcRegistry}, +}; use reth_db::database::Database; use reth_network::NetworkHandle; use reth_node_api::{evm::EvmConfig, primitives::NodePrimitives, EngineTypes}; @@ -9,11 +12,8 @@ use reth_node_core::{ }; 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. diff --git a/crates/node-ethereum/src/node.rs b/crates/node-ethereum/src/node.rs index 66ca14477f..cd4943eeb7 100644 --- a/crates/node-ethereum/src/node.rs +++ b/crates/node-ethereum/src/node.rs @@ -1,6 +1,4 @@ -//! Node types config. - -//! Ethereum node types +//! Ethereum Node types config. use crate::{EthEngineTypes, EthEvmConfig}; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; diff --git a/crates/node-optimism/Cargo.toml b/crates/node-optimism/Cargo.toml index 13df047f1b..3db29dbffc 100644 --- a/crates/node-optimism/Cargo.toml +++ b/crates/node-optimism/Cargo.toml @@ -14,11 +14,34 @@ workspace = true # reth reth-primitives.workspace = true reth-payload-builder.workspace = true +reth-basic-payload-builder.workspace = true +reth-optimism-payload-builder.workspace = true reth-rpc-types.workspace = true +reth-rpc.workspace = true +reth-rpc-types-compat.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 serde.workspace = true +eyre.workspace = true + +[dev-dependencies] +reth-db.workspace = true [features] -optimism = ["reth-node-api/optimism"] +optimism = [ + "reth-node-api/optimism", + "reth-network/optimism", + "reth-primitives/optimism", + "reth-transaction-pool/optimism", + "reth-rpc-types/optimism", + "reth-provider/optimism", + "reth-rpc-types-compat/optimism", + "reth-rpc/optimism", + "reth-optimism-payload-builder/optimism" +] diff --git a/crates/node-optimism/src/evm.rs b/crates/node-optimism/src/evm.rs index 8f2da06394..490f257f73 100644 --- a/crates/node-optimism/src/evm.rs +++ b/crates/node-optimism/src/evm.rs @@ -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_op_tx_env}, revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, @@ -45,6 +45,9 @@ impl ConfigureEvmEnv for OptimismEvmConfig { } } +// TODO +impl EvmConfig for OptimismEvmConfig {} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/node-optimism/src/lib.rs b/crates/node-optimism/src/lib.rs index 63a5e10a31..22ac5fd445 100644 --- a/crates/node-optimism/src/lib.rs +++ b/crates/node-optimism/src/lib.rs @@ -18,3 +18,6 @@ pub use engine::OptimismEngineTypes; /// [ConfigureEvmEnv](reth_node_api::ConfigureEvmEnv) trait. pub mod evm; pub use evm::OptimismEvmConfig; + +pub mod node; +pub use node::OptimismNode; diff --git a/crates/node-optimism/src/node.rs b/crates/node-optimism/src/node.rs new file mode 100644 index 0000000000..0fd97bbc15 --- /dev/null +++ b/crates/node-optimism/src/node.rs @@ -0,0 +1,178 @@ +//! Optimism Node types config. + +use crate::{OptimismEngineTypes, OptimismEvmConfig}; +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 Optimism node. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct OptimismNode; +// TODO make this stateful with evm config + +impl OptimismNode { + /// Returns a [`ComponentsBuilder`] configured for a regular Ethereum node. + pub fn components( + ) -> ComponentsBuilder + where + Node: FullNodeTypes, + { + ComponentsBuilder::default() + .node_types::() + .pool(OptimismPoolBuilder::default()) + .payload(OptimismPayloadBuilder::default()) + .network(OptimismNetwork) + } +} + +impl NodeTypes for OptimismNode { + type Primitives = (); + type Engine = OptimismEngineTypes; + type Evm = OptimismEvmConfig; + + fn evm_config(&self) -> Self::Evm { + todo!() + } +} + +/// A basic optimism 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 OptimismPoolBuilder { + // TODO add options for txpool args +} + +impl PoolBuilder for OptimismPoolBuilder +where + Node: FullNodeTypes, +{ + type Pool = EthTransactionPool; + + fn build_pool(self, ctx: &BuilderContext) -> eyre::Result { + 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 optimism payload service. +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct OptimismPayloadBuilder; + +impl PayloadServiceBuilder for OptimismPayloadBuilder +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + let payload_builder = reth_optimism_payload_builder::OptimismPayloadBuilder::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 OptimismNetwork; + +impl NetworkBuilder for OptimismNetwork +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + fn build_network(self, ctx: &BuilderContext, pool: Pool) -> eyre::Result { + let network = ctx.network_builder_blocking()?; + let handle = ctx.start_network(network, pool); + + Ok(handle) + } +} diff --git a/crates/node-optimism/tests/it/builder.rs b/crates/node-optimism/tests/it/builder.rs new file mode 100644 index 0000000000..9d2246487d --- /dev/null +++ b/crates/node-optimism/tests/it/builder.rs @@ -0,0 +1,32 @@ +//! Node builder setup tests. + +use reth_db::test_utils::create_test_rw_db; +use reth_node_builder::{components::FullNodeComponents, NodeBuilder, NodeConfig}; +use reth_node_optimism::node::OptimismNode; + +#[test] +fn test_basic_setup() { + // parse CLI -> config + let config = NodeConfig::test(); + let db = create_test_rw_db(); + let _builder = NodeBuilder::new(config) + .with_database(db) + .with_types(OptimismNode::default()) + .with_components(OptimismNode::components()) + .on_component_initialized(move |ctx| { + let _provider = ctx.provider(); + 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(); +} diff --git a/crates/node-optimism/tests/it/main.rs b/crates/node-optimism/tests/it/main.rs new file mode 100644 index 0000000000..1aea2c2123 --- /dev/null +++ b/crates/node-optimism/tests/it/main.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "optimism")] +mod builder; + +fn main() {}