Skip to content

Commit 01fbdb7

Browse files
authored
feat(rollup): init exex driver and pipeline (#37)
Added a `Driver::exex` method that can initialize a Driver with the components needed to bootstrap in ExEx mode. Also stubbed a `StandaloneDriver` struct that will later be used to start Hera in standalone mode. closes #8.
1 parent a11cb1c commit 01fbdb7

File tree

6 files changed

+111
-16
lines changed

6 files changed

+111
-16
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/op-rs/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn main() -> Result<()> {
5656
};
5757

5858
let node = EthereumNode::default();
59-
let hera = move |ctx| async { Ok(Driver::new(ctx, hera_args, cfg).await.start()) };
59+
let hera = move |ctx| async { Ok(Driver::exex(ctx, hera_args, cfg).start()) };
6060
let handle = builder.node(node).install_exex(HERA_EXEX_ID, hera).launch().await?;
6161
handle.wait_for_node_exit().await
6262
} else {

crates/kona-providers/src/blob_provider.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ use reth::primitives::BlobTransactionSidecar;
1818
use tracing::warn;
1919
use url::Url;
2020

21+
/// A blob provider that first attempts to fetch blobs from a primary beacon client and
22+
/// falls back to a secondary blob archiver if the primary fails.
23+
///
24+
/// Any blob archiver just needs to implement the beacon
25+
/// [`blob_sidecars` API](https://ethereum.github.io/beacon-APIs/#/Beacon/getBlobSidecars)
26+
pub type DurableBlobProvider =
27+
OnlineBlobProviderWithFallback<OnlineBeaconClient, OnlineBeaconClient, SimpleSlotDerivation>;
28+
2129
/// Layered [BlobProvider] for the Kona derivation pipeline.
2230
///
2331
/// This provider wraps different blob sources in an ordered manner:
@@ -35,13 +43,9 @@ pub struct LayeredBlobProvider {
3543
/// This is used primarily during sync when archived blobs
3644
/// aren't provided by reth since they'll be too old.
3745
///
38-
/// The `WithFallback` setup allows to specify two different
46+
/// The `Durable` setup allows to specify two different
3947
/// endpoints for a primary and a fallback blob provider.
40-
online: OnlineBlobProviderWithFallback<
41-
OnlineBeaconClient,
42-
OnlineBeaconClient,
43-
SimpleSlotDerivation,
44-
>,
48+
online: DurableBlobProvider,
4549
}
4650

4751
/// A blob provider that hold blobs in memory.

crates/rollup/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ keywords.workspace = true
1010
categories.workspace = true
1111

1212
[dependencies]
13+
kona-providers = { path = "../kona-providers" }
14+
1315
# Workspace
1416
eyre.workspace = true
1517
tracing.workspace = true

crates/rollup/src/cli.rs

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use url::Url;
88
/// The default L2 chain ID to use. This corresponds to OP Mainnet.
99
pub const DEFAULT_L2_CHAIN_ID: u64 = 10;
1010

11+
/// The default L1 RPC URL to use.
12+
pub const DEFAULT_L1_RPC_URL: &str = "https://eth.llamarpc.com/";
13+
1114
/// The default L2 RPC URL to use.
1215
pub const DEFAULT_L2_RPC_URL: &str = "https://optimism.llamarpc.com/";
1316

@@ -30,6 +33,11 @@ pub struct HeraArgsExt {
3033
#[clap(long = "hera.l2-rpc-url", default_value = DEFAULT_L2_RPC_URL)]
3134
pub l2_rpc_url: Url,
3235

36+
/// RPC URL of an L1 execution client
37+
/// (This is only needed when running in Standalone mode)
38+
#[clap(long = "hera.l1-rpc-url", default_value = DEFAULT_L1_RPC_URL)]
39+
pub l1_rpc_url: Url,
40+
3341
/// URL of an L1 beacon client to fetch blobs
3442
#[clap(long = "hera.l1-beacon-client-url", default_value = DEFAULT_L1_BEACON_CLIENT_URL)]
3543
pub l1_beacon_client_url: Url,

crates/rollup/src/driver.rs

+89-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
//! Rollup Node Driver
22
3-
use std::sync::Arc;
3+
use std::{fmt::Debug, sync::Arc};
44

55
use async_trait::async_trait;
66
use eyre::{bail, Result};
7+
use kona_derive::{
8+
online::{AlloyChainProvider, AlloyL2ChainProvider, OnlineBlobProviderBuilder},
9+
traits::{BlobProvider, ChainProvider, L2ChainProvider},
10+
};
11+
use kona_primitives::BlockInfo;
12+
use kona_providers::{
13+
blob_provider::DurableBlobProvider, InMemoryChainProvider, LayeredBlobProvider,
14+
};
715
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
816
use reth_node_api::FullNodeComponents;
917
use superchain_registry::RollupConfig;
1018
use tokio::sync::mpsc::error::SendError;
1119
use tracing::{debug, info};
1220

13-
use crate::cli::HeraArgsExt;
21+
use crate::{new_rollup_pipeline, HeraArgsExt, RollupPipeline};
1422

1523
#[async_trait]
1624
pub trait DriverContext {
@@ -30,22 +38,76 @@ impl<N: FullNodeComponents> DriverContext for ExExContext<N> {
3038
}
3139
}
3240

41+
#[derive(Debug)]
42+
pub struct StandaloneContext;
43+
44+
#[async_trait]
45+
impl DriverContext for StandaloneContext {
46+
async fn recv_notification(&mut self) -> Option<ExExNotification> {
47+
// TODO: we will need a background task to listen for new blocks
48+
// (either polling or via websocket), parse them into ExExNotifications
49+
// and handle reorgs for the driver to react to.
50+
todo!()
51+
}
52+
53+
fn send_event(&mut self, _event: ExExEvent) -> Result<(), SendError<ExExEvent>> {
54+
// TODO: When we have a better background notifier abstraction, sending
55+
// FinishedHeight events will be useful to make the pipeline advance
56+
// safely through reorgs (as it is currently done for ExExContext).
57+
Ok(())
58+
}
59+
}
60+
3361
/// The Rollup Driver entrypoint.
3462
#[derive(Debug)]
35-
pub struct Driver<DC: DriverContext> {
63+
pub struct Driver<DC, CP, BP, L2CP> {
3664
/// The rollup configuration
3765
cfg: Arc<RollupConfig>,
3866
/// The context of the node
3967
ctx: DC,
68+
/// The L1 chain provider
69+
chain_provider: CP,
70+
/// The L1 blob provider
71+
blob_provider: BP,
72+
/// The L2 chain provider
73+
l2_chain_provider: L2CP,
4074
}
4175

42-
#[allow(unused)]
43-
impl<DC: DriverContext> Driver<DC> {
44-
/// Creates a new instance of the Hera Execution Extension.
45-
pub async fn new(ctx: DC, args: HeraArgsExt, cfg: Arc<RollupConfig>) -> Self {
46-
Self { ctx, cfg }
76+
impl<N> Driver<ExExContext<N>, InMemoryChainProvider, LayeredBlobProvider, AlloyL2ChainProvider>
77+
where
78+
N: FullNodeComponents,
79+
{
80+
/// Create a new Hera Execution Extension Driver
81+
pub fn exex(ctx: ExExContext<N>, args: HeraArgsExt, cfg: Arc<RollupConfig>) -> Self {
82+
let cp = InMemoryChainProvider::with_capacity(1024);
83+
let bp = LayeredBlobProvider::new(args.l1_beacon_client_url, args.l1_blob_archiver_url);
84+
let l2_cp = AlloyL2ChainProvider::new_http(args.l2_rpc_url, cfg.clone());
85+
86+
Self { cfg, ctx, chain_provider: cp, blob_provider: bp, l2_chain_provider: l2_cp }
4787
}
88+
}
89+
90+
impl Driver<StandaloneContext, AlloyChainProvider, DurableBlobProvider, AlloyL2ChainProvider> {
91+
/// Create a new standalone Hera Driver
92+
pub fn standalone(ctx: StandaloneContext, args: HeraArgsExt, cfg: Arc<RollupConfig>) -> Self {
93+
let cp = AlloyChainProvider::new_http(args.l1_rpc_url);
94+
let l2_cp = AlloyL2ChainProvider::new_http(args.l2_rpc_url, cfg.clone());
95+
let bp = OnlineBlobProviderBuilder::new()
96+
.with_primary(args.l1_beacon_client_url.to_string())
97+
.with_fallback(args.l1_blob_archiver_url.map(|url| url.to_string()))
98+
.build();
4899

100+
Self { cfg, ctx, chain_provider: cp, blob_provider: bp, l2_chain_provider: l2_cp }
101+
}
102+
}
103+
104+
impl<DC, CP, BP, L2CP> Driver<DC, CP, BP, L2CP>
105+
where
106+
DC: DriverContext,
107+
CP: ChainProvider + Clone + Send + Sync + Debug + 'static,
108+
BP: BlobProvider + Clone + Send + Sync + Debug + 'static,
109+
L2CP: L2ChainProvider + Clone + Send + Sync + Debug + 'static,
110+
{
49111
/// Wait for the L2 genesis L1 block (aka "origin block") to be available in the L1 chain.
50112
async fn wait_for_l2_genesis_l1_block(&mut self) -> Result<()> {
51113
loop {
@@ -69,12 +131,30 @@ impl<DC: DriverContext> Driver<DC> {
69131
}
70132
}
71133

134+
/// Initialize the rollup pipeline from the driver's components.
135+
fn init_pipeline(&mut self) -> RollupPipeline<CP, BP, L2CP> {
136+
new_rollup_pipeline(
137+
self.cfg.clone(),
138+
self.chain_provider.clone(),
139+
self.blob_provider.clone(),
140+
self.l2_chain_provider.clone(),
141+
// TODO: use a dynamic "tip" block instead of genesis
142+
BlockInfo {
143+
hash: self.cfg.genesis.l2.hash,
144+
number: self.cfg.genesis.l2.number,
145+
..Default::default()
146+
},
147+
)
148+
}
149+
72150
/// Starts the Hera Execution Extension loop.
73151
pub async fn start(mut self) -> Result<()> {
74152
// Step 1: Wait for the L2 origin block to be available
75153
self.wait_for_l2_genesis_l1_block().await?;
76154
info!("Chain synced to rollup genesis");
77155

78-
todo!("init pipeline and start processing events");
156+
let _pipeline = self.init_pipeline();
157+
158+
todo!("start processing events");
79159
}
80160
}

0 commit comments

Comments
 (0)