Skip to content

Commit

Permalink
chore(host): Remove HostOrchestrator (#994)
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby authored Feb 3, 2025
1 parent 3a9c3dd commit ba1c8fa
Show file tree
Hide file tree
Showing 19 changed files with 552 additions and 763 deletions.
13 changes: 5 additions & 8 deletions bin/host/src/bin/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@

use anyhow::Result;
use clap::{ArgAction, Parser, Subcommand};
use kona_host::{
cli::{cli_styles, init_tracing_subscriber},
DetachedHostOrchestrator,
};
use kona_host::cli::{cli_styles, init_tracing_subscriber};
use serde::Serialize;
use tracing::info;

Expand Down Expand Up @@ -39,10 +36,10 @@ pub struct HostCli {
pub enum HostMode {
/// Run the host in single-chain mode.
#[cfg(feature = "single")]
Single(kona_host::single::SingleChainHostCli),
Single(kona_host::single::SingleChainHost),
/// Run the host in super-chain (interop) mode.
#[cfg(feature = "interop")]
Super(kona_host::interop::InteropHostCli),
Super(kona_host::interop::InteropHost),
}

#[tokio::main(flavor = "multi_thread")]
Expand All @@ -53,11 +50,11 @@ async fn main() -> Result<()> {
match cfg.mode {
#[cfg(feature = "single")]
HostMode::Single(cfg) => {
cfg.run().await?;
cfg.start().await?;
}
#[cfg(feature = "interop")]
HostMode::Super(cfg) => {
cfg.run().await?;
cfg.start().await?;
}
}

Expand Down
11 changes: 0 additions & 11 deletions bin/host/src/fetcher.rs

This file was deleted.

280 changes: 280 additions & 0 deletions bin/host/src/interop/cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
//! This module contains all CLI-specific code for the interop entrypoint.
use super::{InteropFetcher, InteropLocalInputs};
use crate::{
cli::{
cli_styles,
parser::{parse_b256, parse_bytes},
},
eth::http_provider,
DiskKeyValueStore, MemoryKeyValueStore, OfflineHostBackend, PreimageServer,
SharedKeyValueStore, SplitKeyValueStore,
};
use alloy_primitives::{Bytes, B256};
use alloy_provider::{Provider, RootProvider};
use alloy_rlp::Decodable;
use anyhow::{anyhow, Result};
use clap::Parser;
use kona_preimage::{
BidirectionalChannel, Channel, HintReader, HintWriter, OracleReader, OracleServer,
};
use kona_proof_interop::PreState;
use kona_providers_alloy::{OnlineBeaconClient, OnlineBlobProvider};
use kona_std_fpvm::{FileChannel, FileDescriptor};
use maili_genesis::RollupConfig;
use serde::Serialize;
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use tokio::{
sync::RwLock,
task::{self, JoinHandle},
};

/// The interop host application.
#[derive(Default, Parser, Serialize, Clone, Debug)]
#[command(styles = cli_styles())]
pub struct InteropHost {
/// Hash of the L1 head block, marking a static, trusted cutoff point for reading data from the
/// L1 chain.
#[clap(long, value_parser = parse_b256, env)]
pub l1_head: B256,
/// Agreed [PreState] to start from. Can be a [PreState::SuperRoot] or
/// [PreState::TransitionState].
///
/// [PreState]: kona_proof_interop::PreState
#[clap(long, visible_alias = "l2-pre-state", value_parser = parse_bytes, env)]
pub agreed_l2_pre_state: Bytes,
/// Claimed L2 post-state to validate.
#[clap(long, visible_alias = "l2-claim", value_parser = parse_b256, env)]
pub claimed_l2_post_state: B256,
/// Claimed L2 timestamp, corresponding to the L2 post-state.
#[clap(long, visible_alias = "l2-timestamp", env)]
pub claimed_l2_timestamp: u64,
/// Addresses of L2 JSON-RPC endpoints to use (eth and debug namespace required).
#[clap(
long,
visible_alias = "l2s",
requires = "l1_node_address",
requires = "l1_beacon_address",
value_delimiter = ',',
env
)]
pub l2_node_addresses: Option<Vec<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_addresses",
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_addresses", "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,
/// Path to rollup configs. If provided, the host will use this config instead of attempting to
/// look up the configs in the superchain registry.
#[clap(long, alias = "rollup-cfgs", value_delimiter = ',', env)]
pub rollup_config_paths: Option<Vec<PathBuf>>,
}

impl InteropHost {
/// Starts the [InteropHost] application.
pub async fn start(self) -> Result<()> {
if self.server {
let hint = FileChannel::new(FileDescriptor::HintRead, FileDescriptor::HintWrite);
let preimage =
FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite);

self.start_server(hint, preimage).await?.await?
} else {
self.start_native().await
}
}

/// Starts the preimage server, communicating with the client over the provided channels.
async fn start_server<C>(&self, hint: C, preimage: C) -> Result<JoinHandle<Result<()>>>
where
C: Channel + Send + Sync + 'static,
{
let kv_store = self.create_key_value_store()?;

let task_handle = if self.is_offline() {
task::spawn(
PreimageServer::new(
OracleServer::new(preimage),
HintReader::new(hint),
Arc::new(OfflineHostBackend::new(kv_store)),
)
.start(),
)
} else {
let providers = self.create_providers().await?;
let backend = InteropFetcher::new(
self.clone(),
kv_store.clone(),
providers.l1_provider,
providers.blob_provider,
providers.l2_providers,
);

task::spawn(
PreimageServer::new(
OracleServer::new(preimage),
HintReader::new(hint),
Arc::new(backend),
)
.start(),
)
};

Ok(task_handle)
}

/// Starts the host in native mode, running both the client and preimage server in the same
/// process.
async fn start_native(&self) -> Result<()> {
let hint = BidirectionalChannel::new()?;
let preimage = BidirectionalChannel::new()?;

let server_task = self.start_server(hint.host, preimage.host).await?;
let client_task = task::spawn(kona_client::single::run(
OracleReader::new(preimage.client),
HintWriter::new(hint.client),
None,
));

let (_, client_result) = tokio::try_join!(server_task, client_task)?;

// Bubble up the exit status of the client program if execution completes.
std::process::exit(client_result.is_err() as i32)
}

/// 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_addresses.is_none() &&
self.l1_beacon_address.is_none() &&
self.data_dir.is_some()
}

/// Returns the active L2 chain ID based on the agreed L2 pre-state.
pub fn active_l2_chain_id(&self) -> Result<u64> {
let pre_state = match PreState::decode(&mut self.agreed_l2_pre_state.as_ref()) {
Ok(pre_state) => pre_state,
// If the pre-state is invalid, return a dummy chain ID.
Err(_) => return Ok(0),
};

match pre_state {
PreState::SuperRoot(super_root) => Ok(super_root
.output_roots
.first()
.ok_or(anyhow!("output roots are empty"))?
.chain_id),
PreState::TransitionState(transition_state) => Ok(transition_state
.pre_state
.output_roots
.get(
(transition_state.step as usize)
.min(transition_state.pre_state.output_roots.len() - 1),
)
.ok_or(anyhow!("no output root found"))?
.chain_id),
}
}

/// 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>> {
let rollup_config_paths = self.rollup_config_paths.as_ref().ok_or_else(|| {
anyhow::anyhow!(
"No rollup config paths provided. Please provide a path to the rollup configs."
)
})?;

rollup_config_paths.iter().try_fold(HashMap::default(), |mut acc, path| {
// 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.
let cfg: RollupConfig = serde_json::from_str(&ser_config)
.map_err(|e| anyhow!("Error deserializing RollupConfig: {e}"))?;

acc.insert(cfg.l2_chain_id, cfg);
Ok(acc)
})
}

/// Creates the key-value store for the host backend.
fn create_key_value_store(&self) -> Result<SharedKeyValueStore> {
let local_kv_store = InteropLocalInputs::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))
};

Ok(kv_store)
}

/// Creates the providers required for the preimage server backend.
async fn create_providers(&self) -> Result<InteropProviders> {
let l1_provider =
http_provider(self.l1_node_address.as_ref().ok_or(anyhow!("Provider must be set"))?);

let blob_provider = OnlineBlobProvider::init(OnlineBeaconClient::new_http(
self.l1_beacon_address.clone().ok_or(anyhow!("Beacon API URL must be set"))?,
))
.await;

// 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::default();
for l2_node_address in l2_node_addresses {
let l2_provider = http_provider(l2_node_address);
let chain_id = l2_provider.get_chain_id().await?;
l2_providers.insert(chain_id, l2_provider);
}

Ok(InteropProviders { l1_provider, blob_provider, l2_providers })
}
}
/// The providers required for the single chain host.
#[derive(Debug)]
pub struct InteropProviders {
/// The L1 EL provider.
l1_provider: RootProvider,
/// The L1 beacon node provider.
blob_provider: OnlineBlobProvider<OnlineBeaconClient>,
/// The L2 EL providers, keyed by chain ID.
l2_providers: HashMap<u64, RootProvider>,
}
Loading

0 comments on commit ba1c8fa

Please sign in to comment.