Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(host): Support multiple modes #904

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .monorepo
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e52030dba4d6130874f80e80900961c342c8c074
3cc36be2ef1ff1797fd85a30754551949b29dbc1
4 changes: 4 additions & 0 deletions bin/client/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ run-client-asterisc block_number l1_rpc l1_beacon_rpc l2_rpc rollup_node_rpc ver
--input $STATE_PATH \
-- \
$HOST_BIN_PATH \
single \
--l1-head $L1_HEAD \
--agreed-l2-head-hash $AGREED_L2_HEAD_HASH \
--claimed-l2-output-root $CLAIMED_L2_OUTPUT_ROOT \
Expand Down Expand Up @@ -96,6 +97,7 @@ run-client-native block_number l1_rpc l1_beacon_rpc l2_rpc rollup_node_rpc rollu

echo "Running host program with native client program..."
cargo r --bin kona-host --release -- \
single \
--l1-head $L1_HEAD \
--agreed-l2-head-hash $AGREED_L2_HEAD_HASH \
--claimed-l2-output-root $CLAIMED_L2_OUTPUT_ROOT \
Expand Down Expand Up @@ -125,6 +127,7 @@ run-client-native-offline block_number l2_claim l2_output_root l2_head l1_head l

echo "Running host program with native client program..."
cargo r --bin kona-host --release -- \
single \
--l1-head $L1_HEAD \
--agreed-l2-head-hash $AGREED_L2_HEAD_HASH \
--claimed-l2-output-root $CLAIMED_L2_OUTPUT_ROOT \
Expand Down Expand Up @@ -169,6 +172,7 @@ run-client-asterisc-offline block_number l2_claim l2_output_root l2_head l1_head
--input $STATE_PATH \
-- \
$HOST_BIN_PATH \
single \
--l1-head $L1_HEAD \
--agreed-l2-head-hash $AGREED_L2_HEAD_HASH \
--claimed-l2-output-root $CLAIMED_L2_OUTPUT_ROOT \
Expand Down
245 changes: 11 additions & 234 deletions bin/host/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
//! This module contains all CLI-specific code for the host binary.

use crate::{
blobs::OnlineBlobProvider,
kv::{
DiskKeyValueStore, LocalKeyValueStore, MemoryKeyValueStore, SharedKeyValueStore,
SplitKeyValueStore,
},
};
use alloy_primitives::B256;
use alloy_provider::ReqwestProvider;
use alloy_rpc_client::RpcClient;
use alloy_transport_http::Http;
use anyhow::{anyhow, Result};
use crate::single::SingleChainHostCli;
use clap::{
builder::styling::{AnsiColor, Color, Style},
ArgAction, Parser,
ArgAction, Parser, Subcommand,
};
use op_alloy_genesis::RollupConfig;
use reqwest::Client;
use serde::Serialize;
use std::{path::PathBuf, sync::Arc};
use tokio::sync::RwLock;

mod parser;
pub(crate) use parser::parse_b256;
Expand All @@ -37,164 +22,22 @@ primary thread.
";

/// The host binary CLI application arguments.
#[derive(Default, Parser, Serialize, Clone, Debug)]
#[derive(Parser, Serialize, Clone, Debug)]
#[command(about = ABOUT, version, styles = cli_styles())]
pub struct HostCli {
/// Verbosity level (0-2)
#[arg(long, short, action = ArgAction::Count)]
pub v: u8,
/// Hash of the L1 head block. Derivation stops after this block is processed.
#[clap(long, value_parser = parse_b256, env)]
pub l1_head: B256,
/// Hash of the agreed upon safe L2 block committed to by `--agreed-l2-output-root`.
#[clap(long, visible_alias = "l2-head", value_parser = parse_b256, env)]
pub agreed_l2_head_hash: B256,
/// Agreed safe L2 Output Root to start derivation from.
#[clap(long, visible_alias = "l2-output-root", value_parser = parse_b256, env)]
pub agreed_l2_output_root: B256,
/// Claimed L2 output root at block # `--claimed-l2-block-number` to validate.
#[clap(long, visible_alias = "l2-claim", value_parser = parse_b256, env)]
pub claimed_l2_output_root: B256,
/// Number of the L2 block that the claimed output root commits to.
#[clap(long, visible_alias = "l2-block-number", env)]
pub claimed_l2_block_number: u64,
/// Address of L2 JSON-RPC endpoint to use (eth and debug namespace required).
#[clap(
long,
visible_alias = "l2",
requires = "l1_node_address",
requires = "l1_beacon_address",
env
)]
pub l2_node_address: Option<String>,
/// Address of L1 JSON-RPC endpoint to use (eth and debug namespace required)
#[clap(
long,
visible_alias = "l1",
requires = "l2_node_address",
requires = "l1_beacon_address",
env
)]
pub l1_node_address: Option<String>,
/// Address of the L1 Beacon API endpoint to use.
#[clap(
long,
visible_alias = "beacon",
requires = "l1_node_address",
requires = "l2_node_address",
env
)]
pub l1_beacon_address: Option<String>,
/// The Data Directory for preimage data storage. Optional if running in online mode,
/// required if running in offline mode.
#[clap(
long,
visible_alias = "db",
required_unless_present_all = ["l2_node_address", "l1_node_address", "l1_beacon_address"],
env
)]
pub data_dir: Option<PathBuf>,
/// Run the client program natively.
#[clap(long, conflicts_with = "server", required_unless_present = "server")]
pub native: bool,
/// Run in pre-image server mode without executing any client program. If not provided, the
/// host will run the client program in the host process.
#[clap(long, conflicts_with = "native", required_unless_present = "native")]
pub server: bool,
/// The L2 chain ID of a supported chain. If provided, the host will look for the corresponding
/// rollup config in the superchain registry.
#[clap(
long,
conflicts_with = "rollup_config_path",
required_unless_present = "rollup_config_path",
env
)]
pub l2_chain_id: Option<u64>,
/// Path to rollup config. If provided, the host will use this config instead of attempting to
/// look up the config in the superchain registry.
#[clap(
long,
alias = "rollup-cfg",
conflicts_with = "l2_chain_id",
required_unless_present = "l2_chain_id",
env
)]
pub rollup_config_path: Option<PathBuf>,
/// Host mode
#[clap(subcommand)]
pub mode: HostMode,
}

impl HostCli {
/// Returns `true` if the host is running in offline mode.
pub const fn is_offline(&self) -> bool {
self.l1_node_address.is_none() &&
self.l2_node_address.is_none() &&
self.l1_beacon_address.is_none()
}

/// Returns an HTTP provider for the given URL.
fn http_provider(url: &str) -> ReqwestProvider {
let url = url.parse().unwrap();
let http = Http::<Client>::new(url);
ReqwestProvider::new(RpcClient::new(http, true))
}

/// Creates the providers associated with the [HostCli] configuration.
///
/// ## Returns
/// - A [ReqwestProvider] for the L1 node.
/// - An [OnlineBlobProvider] for the L1 beacon node.
/// - A [ReqwestProvider] for the L2 node.
pub async fn create_providers(
&self,
) -> Result<(ReqwestProvider, OnlineBlobProvider, ReqwestProvider)> {
let blob_provider = OnlineBlobProvider::new_http(
self.l1_beacon_address.clone().ok_or(anyhow!("Beacon API URL must be set"))?,
)
.await
.map_err(|e| anyhow!("Failed to load blob provider configuration: {e}"))?;
let l1_provider = Self::http_provider(
self.l1_node_address.as_ref().ok_or(anyhow!("Provider must be set"))?,
);
let l2_provider = Self::http_provider(
self.l2_node_address.as_ref().ok_or(anyhow!("L2 node address must be set"))?,
);

Ok((l1_provider, blob_provider, l2_provider))
}

/// Parses the CLI arguments and returns a new instance of a [SharedKeyValueStore], as it is
/// configured to be created.
pub fn construct_kv_store(&self) -> SharedKeyValueStore {
let local_kv_store = LocalKeyValueStore::new(self.clone());

let kv_store: SharedKeyValueStore = if let Some(ref data_dir) = self.data_dir {
let disk_kv_store = DiskKeyValueStore::new(data_dir.clone());
let split_kv_store = SplitKeyValueStore::new(local_kv_store, disk_kv_store);
Arc::new(RwLock::new(split_kv_store))
} else {
let mem_kv_store = MemoryKeyValueStore::new();
let split_kv_store = SplitKeyValueStore::new(local_kv_store, mem_kv_store);
Arc::new(RwLock::new(split_kv_store))
};

kv_store
}

/// Reads the [RollupConfig] from the file system and returns it as a string.
pub fn read_rollup_config(&self) -> Result<RollupConfig> {
let path = self.rollup_config_path.as_ref().ok_or_else(|| {
anyhow::anyhow!(
"No rollup config path provided. Please provide a path to the rollup config."
)
})?;

// Read the serialized config from the file system.
let ser_config = std::fs::read_to_string(path)
.map_err(|e| anyhow!("Error reading RollupConfig file: {e}"))?;

// Deserialize the config and return it.
serde_json::from_str(&ser_config)
.map_err(|e| anyhow!("Error deserializing RollupConfig: {e}"))
}
/// Operation modes for the host binary.
#[derive(Subcommand, Serialize, Clone, Debug)]
pub enum HostMode {
/// Run the host in single-chain mode.
Single(SingleChainHostCli),
}

/// Styles for the CLI application.
Expand All @@ -208,69 +51,3 @@ const fn cli_styles() -> clap::builder::Styles {
.valid(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Green))))
.placeholder(Style::new().fg_color(Some(Color::Ansi(AnsiColor::White))))
}

#[cfg(test)]
mod test {
use crate::HostCli;
use alloy_primitives::B256;
use clap::Parser;

#[test]
fn test_flags() {
let zero_hash_str = &B256::ZERO.to_string();
let default_flags = [
"host",
"--l1-head",
zero_hash_str,
"--l2-head",
zero_hash_str,
"--l2-output-root",
zero_hash_str,
"--l2-claim",
zero_hash_str,
"--l2-block-number",
"0",
];

let cases = [
// valid
(["--server", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true),
(["--server", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true),
(["--native", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true),
(["--native", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true),
(
[
"--l1-node-address",
"dummy",
"--l2-node-address",
"dummy",
"--l1-beacon-address",
"dummy",
"--server",
"--l2-chain-id",
"0",
]
.as_slice(),
true,
),
// invalid
(["--server", "--native", "--l2-chain-id", "0"].as_slice(), false),
(["--l2-chain-id", "0", "--rollup-config-path", "dummy", "--server"].as_slice(), false),
(["--server"].as_slice(), false),
(["--native"].as_slice(), false),
(["--rollup-config-path", "dummy"].as_slice(), false),
(["--l2-chain-id", "0"].as_slice(), false),
(["--l1-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false),
(["--l2-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false),
(["--l1-beacon-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false),
([].as_slice(), false),
];

for (args_ext, valid) in cases.into_iter() {
let args = default_flags.iter().chain(args_ext.iter()).cloned().collect::<Vec<_>>();

let parsed = HostCli::try_parse_from(args);
assert_eq!(parsed.is_ok(), valid);
}
}
}
File renamed without changes.
10 changes: 10 additions & 0 deletions bin/host/src/eth/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Ethereum utilities for the host binary.

mod blobs;
pub use blobs::{
APIConfigResponse, APIGenesisResponse, OnlineBlobProvider, ReducedConfigData,
ReducedGenesisData,
};

mod precompiles;
pub(crate) use precompiles::execute;
File renamed without changes.
11 changes: 11 additions & 0 deletions bin/host/src/fetcher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Fetcher trait definition.

use kona_preimage::{HintRouter, PreimageFetcher};

/// The Fetcher trait is used to define the interface for fetching data from the preimage oracle,
/// by [PreimageKey], and routing hints.
///
/// [PreimageKey]: kona_preimage::PreimageKey
pub trait Fetcher: PreimageFetcher + HintRouter {}

impl<T> Fetcher for T where T: PreimageFetcher + HintRouter {}
3 changes: 0 additions & 3 deletions bin/host/src/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ pub use disk::DiskKeyValueStore;
mod split;
pub use split::SplitKeyValueStore;

mod local;
pub use local::LocalKeyValueStore;

/// A type alias for a shared key-value store.
pub type SharedKeyValueStore = Arc<RwLock<dyn KeyValueStore + Send + Sync>>;

Expand Down
Loading
Loading