From 9780288554821d4c2ca10d062e7a61f89b1dba0a Mon Sep 17 00:00:00 2001 From: refcell Date: Wed, 31 Jul 2024 12:26:56 -0400 Subject: [PATCH] feat(range-finder): setup --- Cargo.lock | 18 +++ Cargo.toml | 4 +- bin/range-finder/src/cli.rs | 190 +++++++++++++++++++++++++++++- bin/range-finder/src/main.rs | 6 + bin/range-finder/src/verbosity.rs | 2 +- 5 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 bin/range-finder/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 24d592e..aacada8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5230,6 +5230,24 @@ dependencies = [ "rand_core", ] +[[package]] +name = "range-finder" +version = "0.1.0" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "clap", + "color-eyre", + "futures", + "kona-derive", + "reqwest", + "superchain-registry", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "ratatui" version = "0.26.3" diff --git a/Cargo.toml b/Cargo.toml index b4ef62b..36c87c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["crates/*", "bin/opt8n", "bin/opd8n"] -default-members = ["bin/opt8n", "bin/opd8n"] +members = ["crates/*", "bin/*"] +default-members = ["bin/opt8n", "bin/opd8n", "bin/range-finder"] resolver = "2" [workspace.package] diff --git a/bin/range-finder/src/cli.rs b/bin/range-finder/src/cli.rs index 91fb07d..ff598e7 100644 --- a/bin/range-finder/src/cli.rs +++ b/bin/range-finder/src/cli.rs @@ -1,9 +1,17 @@ //! CLI for the range-finder. -use alloy_primitives::B256; use clap::{ArgAction, Parser}; -use color_eyre::eyre::Result; -use std::path::PathBuf; +use color_eyre::eyre::{eyre, Result}; +use kona_derive::{ + online::*, + types::{L2BlockInfo, StageError}, +}; +use reqwest::Url; +use std::sync::Arc; +use superchain_registry::ROLLUP_CONFIGS; +use tracing::{debug, error, trace, warn}; + +const LOG_TARGET: &str = "range_finder"; /// Range Finder Cli /// @@ -45,6 +53,180 @@ impl Cli { /// Parse the CLI arguments and run the command pub async fn run(&self) -> Result<()> { - unimplemented!() + // Build the pipeline + let cfg = Arc::new(self.rollup_config().await?); + let mut l1_provider = self.l1_provider()?; + let mut l2_provider = self.l2_provider(cfg.clone())?; + let attributes = self.attributes(cfg.clone(), &l2_provider, &l1_provider); + let blob_provider = self.blob_provider(); + let dap = self.dap(l1_provider.clone(), blob_provider, &cfg); + let mut l2_cursor = self.cursor().await?; + let l1_tip = l1_provider + .block_info_by_number(l2_cursor.l1_origin.number) + .await + .expect("Failed to fetch genesis L1 block info for pipeline tip"); + let mut pipeline = new_online_pipeline( + cfg, + l1_provider.clone(), + dap, + l2_provider.clone(), + attributes, + l1_tip, + ); + + // Run the pipeline + loop { + // If the cursor is beyond the end block, break the loop. + if l2_cursor.block_info.number > self.end_block { + trace!(target: "loop", "Cursor is beyond the end block, breaking loop"); + break; + } + + // Step on the pipeline. + match pipeline.step(l2_cursor).await { + StepResult::PreparedAttributes => trace!(target: "loop", "Prepared attributes"), + StepResult::AdvancedOrigin => trace!(target: "loop", "Advanced origin"), + StepResult::OriginAdvanceErr(e) => { + warn!(target: "loop", "Could not advance origin: {:?}", e) + } + StepResult::StepFailed(e) => match e { + StageError::NotEnoughData => { + debug!(target: "loop", "Not enough data to step derivation pipeline"); + } + _ => { + error!(target: "loop", "Error stepping derivation pipeline: {:?}", e); + } + }, + } + + // Get the attributes if there are some available. + let attributes = if let Some(attributes) = pipeline.next() { + attributes + } else { + continue; + }; + + // Print the L1 range for this L2 Block. + let derived = attributes.parent.block_info.number as i64 + 1; + let l2_block_info = l2_provider + .l2_block_info_by_number(derived as u64) + .await + .expect("Failed to fetch L2 block info for pipeline cursor"); + let origin = pipeline.origin().expect("Failed to get pipeline l1 origin"); + println!( + "L2 Block [{}] L1 Range: [{}, {}]", + derived, l2_block_info.l1_origin.number, origin.number + ); + + // Keep trying to advance the cursor in case the fetch fails. + loop { + match l2_provider + .l2_block_info_by_number(l2_cursor.block_info.number + 1) + .await + { + Ok(bi) => { + l2_cursor = bi; + break; + } + Err(e) => { + error!(target: LOG_TARGET, "Failed to fetch next pending l2 safe head: {}, err: {:?}", l2_cursor.block_info.number + 1, e); + // Don't step on the pipeline if we failed to fetch the next l2 safe head. + continue; + } + } + } + } + + Ok(()) + } + + /// Gets the L2 starting block number. + /// Returns the genesis L2 block number if the start block is less than the genesis block number. + pub fn start_block(&self, cfg: &RollupConfig) -> u64 { + if self.start_block < cfg.genesis.l2.number { + cfg.genesis.l2.number + } else { + self.start_block + } + } + + /// Returns an [L2BlockInfo] cursor for the pipeline. + pub async fn cursor(&self) -> Result { + let cfg = self.rollup_config().await?; + let mut l2_provider = self.l2_provider(Arc::new(cfg))?; + let cursor = l2_provider + .l2_block_info_by_number(self.start_block) + .await + .map_err(|_| eyre!("Failed to fetch genesis L2 block info for pipeline cursor"))?; + Ok(cursor) + } + + /// Returns a new [AlloyChainProvider] using the l1 rpc url. + pub fn l1_provider(&self) -> Result { + Ok(AlloyChainProvider::new_http(self.l1_rpc_url()?)) + } + + /// Returns a new [AlloyL2ChainProvider] using the l2 rpc url. + pub fn l2_provider(&self, cfg: Arc) -> Result { + Ok(AlloyL2ChainProvider::new_http(self.l2_rpc_url()?, cfg)) + } + + /// Returns a new [StatefulAttributesBuilder] using the l1 and l2 providers. + pub fn attributes( + &self, + cfg: Arc, + l2_provider: &AlloyL2ChainProvider, + l1_provider: &AlloyChainProvider, + ) -> StatefulAttributesBuilder { + StatefulAttributesBuilder::new(cfg, l2_provider.clone(), l1_provider.clone()) + } + + /// Returns a new [OnlineBlobProvider] using the beacon url. + pub fn blob_provider(&self) -> OnlineBlobProvider { + OnlineBlobProvider::new( + OnlineBeaconClient::new_http(self.beacon_url.clone()), + None, + None, + ) + } + + /// Returns a new [EthereumDataSource] using the l1 provider and blob provider. + pub fn dap( + &self, + l1_provider: AlloyChainProvider, + blob_provider: OnlineBlobProvider, + cfg: &RollupConfig, + ) -> EthereumDataSource< + AlloyChainProvider, + OnlineBlobProvider, + > { + EthereumDataSource::new(l1_provider, blob_provider, cfg) + } + + /// Gets the rollup config from the l2 rpc url. + pub async fn rollup_config(&self) -> Result { + let mut l2_provider = + AlloyL2ChainProvider::new_http(self.l2_rpc_url()?, Arc::new(Default::default())); + let l2_chain_id = l2_provider.chain_id().await.map_err(|e| eyre!(e))?; + let cfg = ROLLUP_CONFIGS + .get(&l2_chain_id) + .cloned() + .ok_or_else(|| eyre!("No rollup config found for L2 chain ID: {}", l2_chain_id))?; + Ok(cfg) + } + + /// Returns the l1 rpc url from CLI or environment variable. + pub fn l1_rpc_url(&self) -> Result { + Url::parse(&self.l1_rpc_url).map_err(|e| eyre!(e)) + } + + /// Returns the l2 rpc url from CLI or environment variable. + pub fn l2_rpc_url(&self) -> Result { + Url::parse(&self.l2_rpc_url).map_err(|e| eyre!(e)) + } + + /// Returns the beacon url from CLI or environment variable. + pub fn beacon_url(&self) -> String { + self.beacon_url.clone() } } diff --git a/bin/range-finder/src/main.rs b/bin/range-finder/src/main.rs new file mode 100644 index 0000000..a3df8ce --- /dev/null +++ b/bin/range-finder/src/main.rs @@ -0,0 +1,6 @@ +use clap::Parser; + +#[tokio::main] +async fn main() -> color_eyre::Result<()> { + range_finder::Cli::parse().init_telemetry()?.run().await +} diff --git a/bin/range-finder/src/verbosity.rs b/bin/range-finder/src/verbosity.rs index ad0ad15..da487cf 100644 --- a/bin/range-finder/src/verbosity.rs +++ b/bin/range-finder/src/verbosity.rs @@ -1,7 +1,7 @@ //! Module to configure the verbosity level for logging and telemetry. -use tracing::Level; use color_eyre::eyre::{eyre, Result}; +use tracing::Level; /// Initializes tracing verbosity. pub fn init_tracing(verbosity_level: u8) -> Result<()> {