Skip to content

Commit

Permalink
feat(host): Modular components (#915)
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby authored Jan 22, 2025
1 parent c56c3fc commit 80b9c44
Show file tree
Hide file tree
Showing 20 changed files with 402 additions and 454 deletions.
11 changes: 1 addition & 10 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion bin/host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ tracing.workspace = true
reqwest.workspace = true
serde_json.workspace = true
async-trait.workspace = true
rocksdb = { workspace = true, features = ["snappy"] }
tokio = { workspace = true, features = ["full"] }
serde = { workspace = true, features = ["derive"] }
rocksdb = { workspace = true, features = ["snappy"] }
clap = { workspace = true, features = ["derive", "env"] }
tracing-subscriber = { workspace = true, features = ["fmt"] }

Expand Down
2 changes: 1 addition & 1 deletion bin/host/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub enum HostMode {
}

/// Styles for the CLI application.
const fn cli_styles() -> clap::builder::Styles {
pub(crate) const fn cli_styles() -> clap::builder::Styles {
clap::builder::Styles::styled()
.usage(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow))))
.header(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow))))
Expand Down
12 changes: 12 additions & 0 deletions bin/host/src/eth/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//! Ethereum utilities for the host binary.
use alloy_provider::ReqwestProvider;
use alloy_rpc_client::RpcClient;
use alloy_transport_http::Http;
use reqwest::Client;

mod blobs;
pub use blobs::{
APIConfigResponse, APIGenesisResponse, OnlineBlobProvider, ReducedConfigData,
Expand All @@ -8,3 +13,10 @@ pub use blobs::{

mod precompiles;
pub(crate) use precompiles::execute;

/// Returns an HTTP provider for the given URL.
pub fn http_provider(url: &str) -> ReqwestProvider {
let url = url.parse().unwrap();
let http = Http::<Client>::new(url);
ReqwestProvider::new(RpcClient::new(http, true))
}
2 changes: 1 addition & 1 deletion bin/host/src/fetcher.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Fetcher trait definition.
//! [Fetcher] trait definition.
use kona_preimage::{HintRouter, PreimageFetcher};

Expand Down
113 changes: 4 additions & 109 deletions bin/host/src/interop/cli.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
//! This module contains all CLI-specific code for the interop entrypoint.
use super::{
local_kv::DEFAULT_CHAIN_ID, start_server, start_server_and_native_client, LocalKeyValueStore,
};
use crate::{
cli::{parse_b256, parse_bytes},
eth::OnlineBlobProvider,
kv::{DiskKeyValueStore, MemoryKeyValueStore, SharedKeyValueStore, SplitKeyValueStore},
};
use super::local_kv::DEFAULT_CHAIN_ID;
use crate::cli::{cli_styles, parse_b256, parse_bytes};
use alloy_primitives::{Bytes, B256};
use alloy_provider::{Provider, ReqwestProvider};
use alloy_rlp::Decodable;
use alloy_rpc_client::RpcClient;
use alloy_transport_http::Http;
use anyhow::{anyhow, Result};
use clap::{
builder::styling::{AnsiColor, Color, Style},
Parser,
};
use clap::Parser;
use kona_proof_interop::PreState;
use maili_genesis::RollupConfig;
use reqwest::Client;
use serde::Serialize;
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use tokio::sync::RwLock;
use tracing::error;
use std::{collections::HashMap, path::PathBuf};

/// The host binary CLI application arguments.
#[derive(Default, Parser, Serialize, Clone, Debug)]
Expand Down Expand Up @@ -97,26 +82,6 @@ pub struct InteropHostCli {
}

impl InteropHostCli {
/// Runs the host binary in single-chain mode.
pub async fn run(self) -> Result<()> {
if self.server {
start_server(self).await?;
} else {
let status = match start_server_and_native_client(self).await {
Ok(status) => status,
Err(e) => {
error!(target: "kona_host", "Exited with an error: {:?}", e);
panic!("{e}");
}
};

// Bubble up the exit status of the client program.
std::process::exit(status as i32);
}

Ok(())
}

/// Returns `true` if the host is running in offline mode.
pub const fn is_offline(&self) -> bool {
self.l1_node_address.is_none() &&
Expand Down Expand Up @@ -150,57 +115,6 @@ impl InteropHostCli {
}
}

/// Creates the providers associated with the [InteropHostCli] configuration.
///
/// ## Returns
/// - A [ReqwestProvider] for the L1 node.
/// - An [OnlineBlobProvider] for the L1 beacon node.
/// - A hash map of chain ID -> [ReqwestProvider] for the L2 nodes.
pub async fn create_providers(
&self,
) -> Result<(ReqwestProvider, OnlineBlobProvider, HashMap<u64, ReqwestProvider>)> {
let l1_provider = Self::http_provider(
self.l1_node_address.as_ref().ok_or(anyhow!("Provider must be set"))?,
);

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}"))?;

// Resolve all chain IDs to their corresponding providers.
let l2_node_addresses =
self.l2_node_addresses.as_ref().ok_or(anyhow!("L2 node addresses must be set"))?;
let mut l2_providers = HashMap::with_capacity(l2_node_addresses.len());
for l2_node_address in l2_node_addresses {
let l2_provider = Self::http_provider(l2_node_address);
let chain_id = l2_provider.get_chain_id().await?;

l2_providers.insert(chain_id, l2_provider);
}

Ok((l1_provider, blob_provider, l2_providers))
}

/// 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]s from the file system and returns a map of L2 chain ID ->
/// [RollupConfig]s.
pub fn read_rollup_configs(&self) -> Result<HashMap<u64, RollupConfig>> {
Expand All @@ -226,23 +140,4 @@ impl InteropHostCli {
},
)
}

/// 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))
}
}

/// Styles for the CLI application.
const fn cli_styles() -> clap::builder::Styles {
clap::builder::Styles::styled()
.usage(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow))))
.header(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow))))
.literal(Style::new().fg_color(Some(Color::Ansi(AnsiColor::Green))))
.invalid(Style::new().bold().fg_color(Some(Color::Ansi(AnsiColor::Red))))
.error(Style::new().bold().fg_color(Some(Color::Ansi(AnsiColor::Red))))
.valid(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Green))))
.placeholder(Style::new().fg_color(Some(Color::Ansi(AnsiColor::White))))
}
3 changes: 2 additions & 1 deletion bin/host/src/interop/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! preimages from a remote source serving the super-chain (interop) proof mode.
use super::InteropHostCli;
use crate::{eth::OnlineBlobProvider, kv::KeyValueStore};
use crate::eth::OnlineBlobProvider;
use alloy_consensus::{Header, TxEnvelope, EMPTY_ROOT_HASH};
use alloy_eips::{
eip2718::Encodable2718,
Expand All @@ -18,6 +18,7 @@ use alloy_rpc_types::{
};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use kona_host::KeyValueStore;
use kona_preimage::{
errors::{PreimageOracleError, PreimageOracleResult},
HintRouter, PreimageFetcher, PreimageKey, PreimageKeyType,
Expand Down
2 changes: 1 addition & 1 deletion bin/host/src/interop/local_kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
//! using the [InteropHostCli] config.
use super::InteropHostCli;
use crate::kv::KeyValueStore;
use alloy_primitives::{keccak256, B256};
use anyhow::Result;
use kona_host::KeyValueStore;
use kona_preimage::PreimageKey;
use kona_proof_interop::boot::{
L1_HEAD_KEY, L2_AGREED_PRE_STATE_KEY, L2_CHAIN_ID_KEY, L2_CLAIMED_POST_STATE_KEY,
Expand Down
109 changes: 2 additions & 107 deletions bin/host/src/interop/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
//! This module contains the super-chain (interop) mode for the host.
use crate::{kv::KeyValueStore, server::PreimageServer};
use anyhow::Result;
use kona_preimage::{
BidirectionalChannel, HintReader, HintWriter, NativeChannel, OracleReader, OracleServer,
};
use kona_std_fpvm::{FileChannel, FileDescriptor};
use std::sync::Arc;
use tokio::{sync::RwLock, task};
use tracing::info;

mod cli;
pub use cli::InteropHostCli;

Expand All @@ -19,100 +9,5 @@ pub use local_kv::LocalKeyValueStore;
mod fetcher;
pub use fetcher::InteropFetcher;

/// Starts the [PreimageServer] in the primary thread. In this mode, the host program has been
/// invoked by the Fault Proof VM and the client program is running in the parent process.
pub async fn start_server(cfg: InteropHostCli) -> Result<()> {
let (preimage_chan, hint_chan) = (
FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite),
FileChannel::new(FileDescriptor::HintRead, FileDescriptor::HintWrite),
);
let oracle_server = OracleServer::new(preimage_chan);
let hint_reader = HintReader::new(hint_chan);
let kv_store = cfg.construct_kv_store();
let fetcher = if !cfg.is_offline() {
let (l1_provider, blob_provider, l2_providers) = cfg.create_providers().await?;
Some(Arc::new(RwLock::new(InteropFetcher::new(
cfg,
kv_store.clone(),
l1_provider,
blob_provider,
l2_providers,
))))
} else {
None
};

// Start the server and wait for it to complete.
info!("Starting preimage server.");
PreimageServer::new(oracle_server, hint_reader, kv_store, fetcher).start().await?;
info!("Preimage server has exited.");

Ok(())
}

/// Starts the [PreimageServer] and the client program in separate threads. The client program is
/// ran natively in this mode.
///
/// ## Takes
/// - `cfg`: The host configuration.
///
/// ## Returns
/// - `Ok(exit_code)` if the client program exits successfully.
/// - `Err(_)` if the client program failed to execute, was killed by a signal, or the host program
/// exited first.
pub async fn start_server_and_native_client(cfg: InteropHostCli) -> Result<i32> {
let hint_chan = BidirectionalChannel::new()?;
let preimage_chan = BidirectionalChannel::new()?;
let kv_store = cfg.construct_kv_store();
let fetcher = if !cfg.is_offline() {
let (l1_provider, blob_provider, l2_providers) = cfg.create_providers().await?;
Some(Arc::new(RwLock::new(InteropFetcher::new(
cfg,
kv_store.clone(),
l1_provider,
blob_provider,
l2_providers,
))))
} else {
None
};

// Create the server and start it.
let server_task = task::spawn(start_native_preimage_server(
kv_store,
fetcher,
hint_chan.host,
preimage_chan.host,
));

// Start the client program in a separate child process.
let program_task = task::spawn(kona_client::interop::run(
OracleReader::new(preimage_chan.client),
HintWriter::new(hint_chan.client),
None,
));

// Execute both tasks and wait for them to complete.
info!("Starting preimage server and client program.");
let (_, client_result) = tokio::try_join!(server_task, program_task,)?;
info!(target: "kona_host", "Preimage server and client program have joined.");

Ok(client_result.is_err() as i32)
}

/// Starts the preimage server in a separate thread. The client program is ran natively in this
/// mode.
pub async fn start_native_preimage_server<KV>(
kv_store: Arc<RwLock<KV>>,
fetcher: Option<Arc<RwLock<InteropFetcher<KV>>>>,
hint_chan: NativeChannel,
preimage_chan: NativeChannel,
) -> Result<()>
where
KV: KeyValueStore + Send + Sync + ?Sized + 'static,
{
let hint_reader = HintReader::new(hint_chan);
let oracle_server = OracleServer::new(preimage_chan);

PreimageServer::new(oracle_server, hint_reader, kv_store, fetcher).start().await
}
mod orchestrator;
pub use orchestrator::InteropProviders;
Loading

0 comments on commit 80b9c44

Please sign in to comment.