diff --git a/Cargo.lock b/Cargo.lock
index 2d6cfb0a..9c79afc3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1976,6 +1976,18 @@ dependencies = [
"url",
]
+[[package]]
+name = "base-flashblocks-node"
+version = "0.0.0"
+dependencies = [
+ "base-client-node",
+ "base-flashblocks",
+ "reth-chain-state",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+]
+
[[package]]
name = "base-flashtypes"
version = "0.0.0"
@@ -2072,7 +2084,7 @@ version = "0.0.0"
dependencies = [
"base-cli-utils",
"base-client-node",
- "base-flashblocks",
+ "base-flashblocks-node",
"base-metering",
"base-txpool",
"clap",
diff --git a/Cargo.toml b/Cargo.toml
index 7dd484f7..7f7eaff2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -60,6 +60,7 @@ base-primitives = { path = "crates/shared/primitives" }
base-access-lists = { path = "crates/shared/access-lists" }
base-reth-rpc-types = { path = "crates/shared/reth-rpc-types" }
base-jwt = { path = "crates/shared/jwt" }
+base-flashblocks-node = { path = "crates/client/flashblocks-node" }
# Client
base-client-cli = { path = "crates/client/cli" }
diff --git a/bin/node/Cargo.toml b/bin/node/Cargo.toml
index 43f2ce23..ff58f2d4 100644
--- a/bin/node/Cargo.toml
+++ b/bin/node/Cargo.toml
@@ -16,7 +16,7 @@ workspace = true
# internal
base-cli-utils.workspace = true
base-client-node.workspace = true
-base-flashblocks.workspace = true
+base-flashblocks-node.workspace = true
base-metering.workspace = true
base-txpool.workspace = true
diff --git a/bin/node/src/cli.rs b/bin/node/src/cli.rs
index ea0d1b0d..03177da5 100644
--- a/bin/node/src/cli.rs
+++ b/bin/node/src/cli.rs
@@ -1,6 +1,6 @@
//! Contains the CLI arguments
-use base_flashblocks::FlashblocksConfig;
+use base_flashblocks_node::FlashblocksConfig;
use base_txpool::TxpoolConfig;
use reth_optimism_node::args::RollupArgs;
diff --git a/bin/node/src/main.rs b/bin/node/src/main.rs
index 3af028d5..21338592 100644
--- a/bin/node/src/main.rs
+++ b/bin/node/src/main.rs
@@ -6,7 +6,7 @@
pub mod cli;
use base_client_node::BaseNodeRunner;
-use base_flashblocks::{FlashblocksConfig, FlashblocksExtension};
+use base_flashblocks_node::{FlashblocksConfig, FlashblocksExtension};
use base_metering::{MeteringConfig, MeteringExtension};
use base_txpool::TxPoolExtension;
diff --git a/crates/client/flashblocks-node/Cargo.toml b/crates/client/flashblocks-node/Cargo.toml
new file mode 100644
index 00000000..41f9c628
--- /dev/null
+++ b/crates/client/flashblocks-node/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "base-flashblocks-node"
+description = "Flashblocks Node Extension"
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+
+[lints]
+workspace = true
+
+[dependencies]
+# workspace
+base-flashblocks.workspace = true
+base-client-node.workspace = true
+
+# reth
+reth-chain-state.workspace = true
+
+tokio-stream.workspace = true
+tracing.workspace = true
+tokio.workspace = true
diff --git a/crates/client/flashblocks-node/README.md b/crates/client/flashblocks-node/README.md
new file mode 100644
index 00000000..7daaabb1
--- /dev/null
+++ b/crates/client/flashblocks-node/README.md
@@ -0,0 +1,58 @@
+# `base-flashblocks-node`
+
+
+
+
+## Extension
+
+This crate provides the Flashblocks extension for the Base node, which enables real-time streaming of pending block state and extended RPC capabilities.
+
+## Usage
+
+### Programmatic Integration
+
+To integrate the Flashblocks extension into your node, use the `install_ext` method on your `BaseNodeRunner`:
+
+```rust
+use base_client_node::BaseNodeRunner;
+use base_flashblocks_node::{FlashblocksConfig, FlashblocksExtension};
+
+let mut runner = BaseNodeRunner::new(rollup_args);
+
+// Create flashblocks configuration
+let flashblocks_config: Option = args.into();
+
+// Install the flashblocks extension (should be installed last as it uses replace_configured)
+runner.install_ext::(flashblocks_config);
+
+let handle = runner.run(builder);
+```
+
+### CLI Arguments
+
+When running the node binary, Flashblocks can be configured with the following CLI arguments:
+
+- `--websocket-url `: The WebSocket URL to stream flashblock updates from (required to enable Flashblocks)
+- `--max-pending-blocks-depth `: Maximum number of pending flashblocks to retain in memory (default: 3)
+
+### Example
+
+```bash
+# Run the Base node with Flashblocks enabled
+base-node \
+ --websocket-url ws://flashblock-service:8080 \
+ --max-pending-blocks-depth 5
+```
+
+## What It Does
+
+The `FlashblocksExtension` wires up:
+
+1. **State Processor**: Maintains pending block state by processing incoming flashblocks
+2. **Canonical Subscription**: Reconciles pending state with canonical blocks
+3. **RPC Extensions**: Provides extended Ethereum RPC methods with flashblock awareness
+4. **WebSocket Subscriber**: Connects to and streams updates from the flashblock service
+
+## License
+
+Licensed under the [MIT License](https://github.com/base/node-reth/blob/main/LICENSE).
diff --git a/crates/client/flashblocks/src/extension.rs b/crates/client/flashblocks-node/src/extension.rs
similarity index 80%
rename from crates/client/flashblocks/src/extension.rs
rename to crates/client/flashblocks-node/src/extension.rs
index c1b14e6a..7e6996d7 100644
--- a/crates/client/flashblocks/src/extension.rs
+++ b/crates/client/flashblocks-node/src/extension.rs
@@ -1,38 +1,14 @@
//! Contains the [`FlashblocksExtension`] which wires up the flashblocks feature
//! (canonical block subscription and RPC surface) on the Base node builder.
-use std::sync::Arc;
-
use base_client_node::{BaseBuilder, BaseNodeExtension, FromExtensionConfig};
+use base_flashblocks::{
+ EthApiExt, EthApiOverrideServer, EthPubSub, EthPubSubApiServer, FlashblocksConfig,
+ FlashblocksSubscriber,
+};
use reth_chain_state::CanonStateSubscriptions;
use tokio_stream::{StreamExt, wrappers::BroadcastStream};
use tracing::info;
-use url::Url;
-
-use crate::{
- EthApiExt, EthApiOverrideServer, EthPubSub, EthPubSubApiServer, FlashblocksState,
- FlashblocksSubscriber,
-};
-
-/// Flashblocks-specific configuration knobs.
-#[derive(Debug, Clone)]
-pub struct FlashblocksConfig {
- /// The websocket endpoint that streams flashblock updates.
- pub websocket_url: Url,
- /// Maximum number of pending flashblocks to retain in memory.
- pub max_pending_blocks_depth: u64,
- /// Shared Flashblocks state.
- pub state: Arc,
-}
-
-impl FlashblocksConfig {
- /// Create a new Flashblocks configuration.
- pub fn new(websocket_url: String, max_pending_blocks_depth: u64) -> Self {
- let state = Arc::new(FlashblocksState::new(max_pending_blocks_depth));
- let ws_url = Url::parse(&websocket_url).expect("valid websocket URL");
- Self { websocket_url: ws_url, max_pending_blocks_depth, state }
- }
-}
/// Helper struct that wires the Flashblocks feature (canonical subscription and RPC) into the node builder.
#[derive(Debug)]
diff --git a/crates/client/flashblocks-node/src/lib.rs b/crates/client/flashblocks-node/src/lib.rs
new file mode 100644
index 00000000..dd52f943
--- /dev/null
+++ b/crates/client/flashblocks-node/src/lib.rs
@@ -0,0 +1,8 @@
+#![doc = include_str!("../README.md")]
+#![doc(issue_tracker_base_url = "https://github.com/base/node-reth/issues/")]
+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
+#![cfg_attr(not(test), warn(unused_crate_dependencies))]
+
+mod extension;
+pub use base_flashblocks::FlashblocksConfig;
+pub use extension::FlashblocksExtension;
diff --git a/crates/client/flashblocks/Cargo.toml b/crates/client/flashblocks/Cargo.toml
index a5fd1204..67ba4340 100644
--- a/crates/client/flashblocks/Cargo.toml
+++ b/crates/client/flashblocks/Cargo.toml
@@ -13,9 +13,10 @@ workspace = true
[features]
test-utils = [
- "base-client-node/test-utils",
+ "dep:base-client-node",
"dep:derive_more",
"dep:eyre",
+ "dep:reth-chain-state",
"reth-chain-state/test-utils",
"reth-chainspec/test-utils",
"reth-evm/test-utils",
@@ -27,10 +28,10 @@ test-utils = [
[dependencies]
# workspace
base-flashtypes.workspace = true
-base-client-node.workspace = true
+base-client-node = { workspace = true, optional = true }
# reth
-reth-chain-state.workspace = true
+reth-chain-state = { workspace = true, optional = true }
reth-evm.workspace = true
reth-primitives.workspace = true
reth-rpc.workspace = true
@@ -92,6 +93,7 @@ derive_more = { workspace = true, features = ["deref"], optional = true }
eyre = { workspace = true, optional = true }
[dev-dependencies]
+base-client-node = { workspace = true, features = ["test-utils"] }
base-flashblocks = { path = ".", features = ["test-utils"] }
rstest.workspace = true
rand.workspace = true
diff --git a/crates/client/flashblocks/src/config.rs b/crates/client/flashblocks/src/config.rs
new file mode 100644
index 00000000..62b793df
--- /dev/null
+++ b/crates/client/flashblocks/src/config.rs
@@ -0,0 +1,25 @@
+use std::sync::Arc;
+
+use url::Url;
+
+use crate::FlashblocksState;
+
+/// Flashblocks-specific configuration knobs.
+#[derive(Debug, Clone)]
+pub struct FlashblocksConfig {
+ /// The websocket endpoint that streams flashblock updates.
+ pub websocket_url: Url,
+ /// Maximum number of pending flashblocks to retain in memory.
+ pub max_pending_blocks_depth: u64,
+ /// Shared Flashblocks state.
+ pub state: Arc,
+}
+
+impl FlashblocksConfig {
+ /// Create a new Flashblocks configuration.
+ pub fn new(websocket_url: String, max_pending_blocks_depth: u64) -> Self {
+ let state = Arc::new(FlashblocksState::new(max_pending_blocks_depth));
+ let ws_url = Url::parse(&websocket_url).expect("valid websocket URL");
+ Self { websocket_url: ws_url, max_pending_blocks_depth, state }
+ }
+}
diff --git a/crates/client/flashblocks/src/lib.rs b/crates/client/flashblocks/src/lib.rs
index 30931992..647d479b 100644
--- a/crates/client/flashblocks/src/lib.rs
+++ b/crates/client/flashblocks/src/lib.rs
@@ -41,14 +41,14 @@ pub use validation::{
ReorgDetectionResult, ReorgDetector, SequenceValidationResult,
};
+mod config;
+pub use config::FlashblocksConfig;
+
mod rpc;
pub use rpc::{
BaseSubscriptionKind, EthApiExt, EthApiOverrideServer, EthPubSub, EthPubSubApiServer,
ExtendedSubscriptionKind,
};
-mod extension;
-pub use extension::{FlashblocksConfig, FlashblocksExtension};
-
#[cfg(any(test, feature = "test-utils"))]
pub mod test_harness;