Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
2 changes: 1 addition & 1 deletion bin/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion bin/node/src/cli.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
2 changes: 1 addition & 1 deletion bin/node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
24 changes: 24 additions & 0 deletions crates/client/flashblocks-node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
58 changes: 58 additions & 0 deletions crates/client/flashblocks-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# `base-flashblocks-node`

<a href="https://github.com/base/node-reth/actions/workflows/ci.yml"><img src="https://github.com/base/node-reth/actions/workflows/ci.yml/badge.svg?label=ci" alt="CI"></a>
<a href="https://github.com/base/node-reth/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-d1d1f6.svg?label=license&labelColor=2a2f35" alt="MIT License"></a>

## 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<FlashblocksConfig> = args.into();

// Install the flashblocks extension (should be installed last as it uses replace_configured)
runner.install_ext::<FlashblocksExtension>(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 <WEBSOCKET_URL>`: The WebSocket URL to stream flashblock updates from (required to enable Flashblocks)
- `--max-pending-blocks-depth <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).
Original file line number Diff line number Diff line change
@@ -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<FlashblocksState>,
}

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)]
Expand Down
8 changes: 8 additions & 0 deletions crates/client/flashblocks-node/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 5 additions & 3 deletions crates/client/flashblocks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions crates/client/flashblocks/src/config.rs
Original file line number Diff line number Diff line change
@@ -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<FlashblocksState>,
}

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 }
}
}
6 changes: 3 additions & 3 deletions crates/client/flashblocks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;