diff --git a/Cargo.lock b/Cargo.lock index 45ccce340..f7a858476 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6454,6 +6454,19 @@ dependencies = [ "reth-primitives", ] +[[package]] +name = "reth-exex" +version = "0.2.0-beta.5" +dependencies = [ + "reth-config", + "reth-node-api", + "reth-node-core", + "reth-primitives", + "reth-provider", + "reth-tasks", + "tokio", +] + [[package]] name = "reth-interfaces" version = "0.2.0-beta.5" @@ -6690,6 +6703,7 @@ dependencies = [ "reth-blockchain-tree", "reth-config", "reth-db", + "reth-exex", "reth-interfaces", "reth-network", "reth-node-api", @@ -6784,6 +6798,7 @@ dependencies = [ "reth-db", "reth-ethereum-payload-builder", "reth-evm-ethereum", + "reth-exex", "reth-network", "reth-node-api", "reth-node-builder", diff --git a/Cargo.toml b/Cargo.toml index efd3b585b..7f471ffab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/etl/", "crates/evm/", "crates/evm-ethereum/", + "crates/exex/", "crates/interfaces/", "crates/metrics/", "crates/metrics/metrics-derive/", @@ -217,6 +218,7 @@ reth-ethereum-payload-builder = { path = "crates/payload/ethereum" } reth-etl = { path = "crates/etl" } reth-evm = { path = "crates/evm" } reth-evm-ethereum = { path = "crates/evm-ethereum" } +reth-exex = { path = "crates/exex" } reth-optimism-payload-builder = { path = "crates/payload/optimism" } reth-interfaces = { path = "crates/interfaces" } reth-ipc = { path = "crates/rpc/ipc" } @@ -252,8 +254,13 @@ reth-trie = { path = "crates/trie" } reth-trie-parallel = { path = "crates/trie-parallel" } # revm -revm = { version = "8.0.0", features = ["std", "secp256k1"], default-features = false } -revm-primitives = { version = "3.1.0", features = ["std"], default-features = false } +revm = { version = "8.0.0", features = [ + "std", + "secp256k1", +], default-features = false } +revm-primitives = { version = "3.1.0", features = [ + "std", +], default-features = false } revm-inspectors = { git = "https://github.com/paradigmxyz/evm-inspectors", rev = "5baa6b3" } # eth diff --git a/crates/exex/Cargo.toml b/crates/exex/Cargo.toml new file mode 100644 index 000000000..91fd04ae9 --- /dev/null +++ b/crates/exex/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "reth-exex" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +description = "Execution extensions for Reth" + +[lints] +workspace = true + +[dependencies] +reth-config.workspace = true +reth-node-api.workspace = true +reth-node-core.workspace = true +reth-primitives.workspace = true +reth-provider.workspace = true +reth-tasks.workspace = true +tokio.workspace = true diff --git a/crates/exex/src/context.rs b/crates/exex/src/context.rs new file mode 100644 index 000000000..e25ba3c9f --- /dev/null +++ b/crates/exex/src/context.rs @@ -0,0 +1,44 @@ +use reth_node_api::FullNodeTypes; +use reth_node_core::{ + dirs::{ChainPath, DataDirPath}, + node_config::NodeConfig, +}; +use reth_primitives::Head; +use reth_provider::CanonStateNotification; +use reth_tasks::TaskExecutor; +use tokio::sync::mpsc::{Receiver, Sender}; + +use crate::ExExEvent; + +/// Captures the context that an ExEx has access to. +#[derive(Debug)] +pub struct ExExContext { + /// The current head of the blockchain at launch. + pub head: Head, + /// The configured provider to interact with the blockchain. + pub provider: Node::Provider, + /// The task executor of the node. + pub task_executor: TaskExecutor, + /// The data dir of the node. + pub data_dir: ChainPath, + /// The config of the node + pub config: NodeConfig, + /// The loaded node config + pub reth_config: reth_config::Config, + /// Channel used to send [`ExExEvent`]s to the rest of the node. + /// + /// # Important + /// + /// The exex should emit a `FinishedHeight` whenever a processed block is safe to prune. + /// Additionally, the exex can pre-emptively emit a `FinishedHeight` event to specify what + /// blocks to receive notifications for. + pub events: Sender, + /// Channel to receive [`CanonStateNotification`]s on state transitions. + /// + /// # Important + /// + /// Once a `CanonStateNotification` is sent over the channel, it is considered delivered by the + /// node. + pub notifications: Receiver, + // TODO(alexey): add pool, payload builder, anything else? +} diff --git a/crates/exex/src/event.rs b/crates/exex/src/event.rs new file mode 100644 index 000000000..cc6ac4365 --- /dev/null +++ b/crates/exex/src/event.rs @@ -0,0 +1,13 @@ +use reth_primitives::BlockNumber; + +/// Events emitted by an ExEx. +#[derive(Debug)] +pub enum ExExEvent { + /// Highest block processed by the ExEx. + /// + /// The ExEx must guarantee that it will not require all earlier blocks in the future, meaning + /// that Reth is allowed to prune them. + /// + /// On reorgs, it's possible for the height to go down. + FinishedHeight(BlockNumber), +} diff --git a/crates/exex/src/lib.rs b/crates/exex/src/lib.rs new file mode 100644 index 000000000..411e223af --- /dev/null +++ b/crates/exex/src/lib.rs @@ -0,0 +1,16 @@ +//! Execution extensions. +//! +//! TBD +#![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))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +mod context; +pub use context::*; + +mod event; +pub use event::*; diff --git a/crates/node-builder/Cargo.toml b/crates/node-builder/Cargo.toml index f7acf600c..4996878fc 100644 --- a/crates/node-builder/Cargo.toml +++ b/crates/node-builder/Cargo.toml @@ -16,6 +16,7 @@ workspace = true reth-auto-seal-consensus.workspace = true reth-beacon-consensus.workspace = true reth-blockchain-tree.workspace = true +reth-exex.workspace = true reth-provider.workspace = true reth-revm.workspace = true reth-db.workspace = true diff --git a/crates/node-builder/src/builder.rs b/crates/node-builder/src/builder.rs index ee194386d..69147da35 100644 --- a/crates/node-builder/src/builder.rs +++ b/crates/node-builder/src/builder.rs @@ -7,7 +7,7 @@ use crate::{ ComponentsBuilder, FullNodeComponents, FullNodeComponentsAdapter, NodeComponents, NodeComponentsBuilder, PoolBuilder, }, - exex::{BoxedLaunchExEx, ExExContext}, + exex::BoxedLaunchExEx, hooks::NodeHooks, node::FullNode, rpc::{RethRpcServerHandles, RpcContext, RpcHooks}, @@ -28,6 +28,7 @@ use reth_db::{ test_utils::{create_test_rw_db, TempDatabase}, DatabaseEnv, }; +use reth_exex::ExExContext; use reth_interfaces::p2p::either::EitherDownloader; use reth_network::{NetworkBuilder, NetworkConfig, NetworkEvents, NetworkHandle}; use reth_node_api::{FullNodeTypes, FullNodeTypesAdapter, NodeTypes}; diff --git a/crates/node-builder/src/exex.rs b/crates/node-builder/src/exex.rs index 1482be14f..d4bec54e7 100644 --- a/crates/node-builder/src/exex.rs +++ b/crates/node-builder/src/exex.rs @@ -25,49 +25,14 @@ //! `block_number >= 0`. //! //! [`Future`]: std::future::Future -//! [`ExExContext`]: crate::exex::ExExContext +//! [`ExExContext`]: reth_exex::ExExContext //! [`CanonStateNotification`]: reth_provider::CanonStateNotification use crate::FullNodeTypes; use futures::{future::BoxFuture, FutureExt}; -use reth_node_core::{ - dirs::{ChainPath, DataDirPath}, - node_config::NodeConfig, -}; -use reth_primitives::{BlockNumber, Head}; -use reth_tasks::TaskExecutor; +use reth_exex::ExExContext; use std::future::Future; -/// Events emitted by an ExEx. -#[derive(Debug)] -pub enum ExExEvent { - /// Highest block processed by the ExEx. - /// - /// The ExEx must guarantee that it will not require all earlier blocks in the future, meaning - /// that Reth is allowed to prune them. - /// - /// On reorgs, it's possible for the height to go down. - FinishedHeight(BlockNumber), -} - -/// Captures the context that an ExEx has access to. -#[derive(Clone, Debug)] -pub struct ExExContext { - /// The current head of the blockchain at launch. - pub head: Head, - /// The configured provider to interact with the blockchain. - pub provider: Node::Provider, - /// The task executor of the node. - pub task_executor: TaskExecutor, - /// The data dir of the node. - pub data_dir: ChainPath, - /// The config of the node - pub config: NodeConfig, - /// The loaded node config - pub reth_config: reth_config::Config, - // TODO(alexey): add pool, payload builder, anything else? -} - /// A trait for launching an ExEx. trait LaunchExEx: Send { /// Launches the ExEx. diff --git a/crates/node-ethereum/Cargo.toml b/crates/node-ethereum/Cargo.toml index 243bdd4f2..a88627491 100644 --- a/crates/node-ethereum/Cargo.toml +++ b/crates/node-ethereum/Cargo.toml @@ -31,5 +31,5 @@ serde.workspace = true [dev-dependencies] reth-db.workspace = true +reth-exex.workspace = true futures.workspace = true - diff --git a/crates/node-ethereum/tests/it/exex.rs b/crates/node-ethereum/tests/it/exex.rs index bf21bd549..b98f9e5fc 100644 --- a/crates/node-ethereum/tests/it/exex.rs +++ b/crates/node-ethereum/tests/it/exex.rs @@ -1,6 +1,7 @@ use futures::future; use reth_db::test_utils::create_test_rw_db; -use reth_node_builder::{exex::ExExContext, FullNodeTypes, NodeBuilder, NodeConfig}; +use reth_exex::ExExContext; +use reth_node_builder::{FullNodeTypes, NodeBuilder, NodeConfig}; use reth_node_ethereum::EthereumNode; use std::{ future::Future,