Skip to content
Draft
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
90 changes: 90 additions & 0 deletions Cargo.lock

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

14 changes: 12 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exclude = [".github/"]

[workspace]
resolver = "2"
members = ["bin/*", "crates/client/*", "crates/shared/*", "crates/builder/*"]
members = ["bin/*", "crates/client/*", "crates/shared/*", "crates/builder/*", "crates/consensus/*"]
default-members = ["bin/node", "bin/consensus"]

[workspace.metadata.cargo-udeps.ignore]
Expand Down 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-engine-driver = { path = "crates/shared/engine-driver" }
base-flashblocks-node = { path = "crates/client/flashblocks-node" }

# Client
Expand All @@ -69,6 +70,11 @@ base-client-node = { path = "crates/client/node" }
base-metering = { path = "crates/client/metering" }
base-txpool = { path = "crates/client/txpool" }
base-flashblocks = { path = "crates/client/flashblocks" }
base-engine-bridge = { path = "crates/client/engine-bridge" }

# Consensus
base-engine-actor = { path = "crates/consensus/engine-actor" }
base-node-service = { path = "crates/consensus/node-service" }

# Builder
base-builder-cli = { path = "crates/builder/base-builder-cli" }
Expand All @@ -81,6 +87,7 @@ kona-engine = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8
kona-derive = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-gossip = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-genesis = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-protocol = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-registry = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-node-service = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
kona-providers-alloy = { git = "https://github.com/op-rs/kona", rev = "24e7e2658e09ac00c8e6cbb48bebe6d10f8fb69d" }
Expand Down Expand Up @@ -122,7 +129,10 @@ reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1
reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", features = [
"serde",
"reth-codec",
] }
reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", features = [
"op",
] }
Expand Down
36 changes: 36 additions & 0 deletions bin/unified/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "base-unified"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
description = "Unified CL+EL binary for Base"

[lints]
workspace = true

[[bin]]
name = "base-unified"
path = "src/main.rs"

[dependencies]
# Workspace crates
base-node-service.workspace = true
base-client-node.workspace = true
base-cli-utils.workspace = true

# reth
reth-optimism-cli.workspace = true
reth-optimism-node.workspace = true
reth-cli-util.workspace = true

# CLI and runtime
eyre.workspace = true
clap = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = ["full"] }
tracing.workspace = true

# Serialization
serde_json.workspace = true
89 changes: 89 additions & 0 deletions bin/unified/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# `base-unified`

<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>

Unified CL+EL binary for Base that runs both consensus and execution layers in a single process.

## Overview

This binary combines:
- **Execution Layer (reth)**: Full OP Stack execution client
- **Consensus Layer (kona)**: Rollup node with derivation pipeline
- **In-Process Bridge**: Zero-overhead communication via direct channels (no HTTP/IPC)

## Architecture

```text
┌────────────────────────────────────────────────────────────────────────┐
│ base-unified binary │
│ ┌────────────────────────────────────────────────────────────────────┐│
│ │ UnifiedRollupNode (orchestrator) ││
│ │ ││
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ││
│ │ │ NetworkActor │ │ DerivationActor │ │ L1WatcherActor │ ││
│ │ │ (from kona) │ │ (from kona) │ │ (from kona) │ ││
│ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ ││
│ │ │ │ │ ││
│ │ └──────────┬──────────┴──────────┬──────────┘ ││
│ │ ▼ ▼ ││
│ │ mpsc::channel mpsc::channel ││
│ │ │ │ ││
│ │ ┌───────────────────▼─────────────────────▼───────────────────┐ ││
│ │ │ DirectEngineActor (custom implementation) │ ││
│ │ │ └─ InProcessEngineDriver (channel-based, no HTTP) │ ││
│ │ └───────────────────┬─────────────────────────────────────────┘ ││
│ │ │ ││
│ │ ▼ (direct channel via ConsensusEngineHandle) ││
│ │ ┌─────────────────────────────────────────────────────────────┐ ││
│ │ │ reth EL (EngineApiTreeHandler) │ ││
│ │ └─────────────────────────────────────────────────────────────┘ ││
│ └────────────────────────────────────────────────────────────────────┘│
└────────────────────────────────────────────────────────────────────────┘
```

## Usage

```bash
# Run the unified node (launches both EL and CL)
base-unified --chain base-sepolia --rollup-config ./rollup.json

# Run EL only (for testing)
base-unified --chain base-sepolia --el-only
```

## Configuration

### Required Arguments
- `--chain`: Chain specification (e.g., `base-mainnet`, `base-sepolia`)

### Optional Arguments
- `--rollup-config`: Path to kona rollup configuration file
- `--datadir`: Data directory for both CL and EL
- `--l1-rpc-url`: L1 Ethereum RPC endpoint
- `--l1-beacon-url`: L1 Beacon API endpoint
- `--el-only`: Skip consensus layer (EL testing mode)

## Why Unified?

The Engine API (HTTP/JSON-RPC) was designed for Ethereum's multi-client ecosystem where
CL and EL are separate processes. For an L2 rollup where you control both layers:

| Aspect | Separate Processes | Unified Binary |
|--------|-------------------|----------------|
| Latency | HTTP/IPC overhead (~1ms+) | Direct channel (~1μs) |
| Serialization | Full JSON-RPC | None (direct types) |
| Deployment | 2 binaries | 1 binary |
| Coordination | External | Internal |

## Components

This binary uses:
- [`base-engine-bridge`](../../crates/client/engine-bridge): InProcessEngineDriver for channel-based engine communication
- [`base-engine-actor`](../../crates/consensus/engine-actor): DirectEngineActor and processor
- [`base-node-service`](../../crates/consensus/node-service): UnifiedRollupNode orchestrator
- [`base-client-node`](../../crates/client/node): BaseNodeRunner for reth

## License

Licensed under the [MIT License](https://github.com/base/node-reth/blob/main/LICENSE).
47 changes: 47 additions & 0 deletions bin/unified/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! CLI argument definitions for the unified binary.

use std::path::PathBuf;

use clap::Parser;
use reth_optimism_node::args::RollupArgs;

/// Unified CL+EL binary for Base.
///
/// Runs both the consensus layer (kona) and execution layer (reth) in a single
/// process with direct in-process channel communication (no HTTP or IPC overhead).
#[derive(Parser, Debug)]
#[command(name = "base-unified")]
#[command(about = "Base unified CL+EL node")]
pub(crate) struct UnifiedCli {
/// Path to the rollup configuration file (kona format).
#[arg(long, value_name = "FILE")]
pub rollup_config: Option<PathBuf>,

/// Path to the chain specification file.
#[arg(long, value_name = "FILE")]
pub chain: Option<PathBuf>,

/// Data directory for both CL and EL.
#[arg(long, value_name = "DIR")]
pub datadir: Option<PathBuf>,

/// L1 RPC endpoint URL.
#[arg(long, value_name = "URL")]
pub l1_rpc_url: Option<String>,

/// L1 beacon API endpoint URL.
#[arg(long, value_name = "URL")]
pub l1_beacon_url: Option<String>,

/// Rollup-specific arguments (forwarded to reth OP node).
#[command(flatten)]
pub rollup_args: RollupArgs,

/// Log verbosity level.
#[arg(short, long, default_value = "info")]
pub verbosity: String,

/// Skip launching the consensus layer (for testing EL only).
#[arg(long)]
pub el_only: bool,
}
Loading
Loading