diff --git a/bin/host/README.md b/bin/host/README.md new file mode 100644 index 000000000..0912cabe9 --- /dev/null +++ b/bin/host/README.md @@ -0,0 +1,10 @@ +# `kona-host` + +The host binary's primary role is to serve the client program responses to requests over the [Preimage Oracle ABI][preimage-spec]. + +## Modes + +| Mode | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `server` | Starts with the preimage server only, expecting the client program to have been invoked by the host process. This mode is particularly purposed to be activated by the FPVM running the client program | +| `native` | Starts both the preimage oracle and client program in a native process, bypassing the verifiable FPVM environment. This mode is useful for upfront witness generation as well as testing. | diff --git a/bin/host/src/main.rs b/bin/host/src/main.rs index 2e53c01c6..6f76c8018 100644 --- a/bin/host/src/main.rs +++ b/bin/host/src/main.rs @@ -1,3 +1,8 @@ +#![doc = include_str!("../README.md")] +#![warn(missing_debug_implementations, missing_docs, rustdoc::all)] +#![deny(unused_must_use, rust_2018_idioms)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + use crate::{ cli::{init_tracing_subscriber, HostCli}, server::PreimageServer, @@ -16,14 +21,7 @@ use std::{ panic::AssertUnwindSafe, sync::Arc, }; -use tokio::{ - process::Command, - sync::{ - watch::{Receiver, Sender}, - RwLock, - }, - task, -}; +use tokio::{process::Command, sync::RwLock, task}; use tracing::{error, info}; use types::NativePipeFiles; @@ -90,22 +88,12 @@ async fn start_server_and_native_client(cfg: HostCli) -> Result<()> { Arc::new(RwLock::new(Fetcher::new(kv_store.clone(), l1_provider, l2_provider))) }); - // Create a channel to signal the server and the client program to exit. - let (tx_server, rx_server) = tokio::sync::watch::channel(()); - let (tx_program, rx_program) = (tx_server.clone(), rx_server.clone()); - // Create the server and start it. - let server_task = task::spawn(start_native_preimage_server( - kv_store, - fetcher, - preimage_pipe, - hint_pipe, - tx_server, - rx_server, - )); + let server_task = + task::spawn(start_native_preimage_server(kv_store, fetcher, preimage_pipe, hint_pipe)); // Start the client program in a separate child process. - let program_task = task::spawn(start_native_client_program(cfg, files, tx_program, rx_program)); + let program_task = task::spawn(start_native_client_program(cfg, files)); // Execute both tasks and wait for them to complete. info!("Starting preimage server and client program."); @@ -126,8 +114,6 @@ async fn start_native_preimage_server( fetcher: Option>>>, preimage_pipe: PipeHandle, hint_pipe: PipeHandle, - tx: Sender<()>, - mut rx: Receiver<()>, ) -> Result<()> where KV: KeyValueStore + Send + Sync + ?Sized + 'static, @@ -136,34 +122,17 @@ where let hint_reader = HintReader::new(hint_pipe); let server = PreimageServer::new(oracle_server, hint_reader, kv_store, fetcher); - - let server_pair_task = task::spawn(async move { - AssertUnwindSafe(server.start()) - .catch_unwind() - .await - .map_err(|_| { - error!(target: "preimage_server", "Preimage server panicked"); - anyhow!("Preimage server panicked") - })? - .map_err(|e| { - error!(target: "preimage_server", "Preimage server exited with an error"); - anyhow!("Preimage server exited with an error: {:?}", e) - }) - }); - let rx_server_task = task::spawn(async move { rx.changed().await }); - - // Block the current task until either the client program exits or the server exits. - tokio::select! { - _ = rx_server_task => { - info!(target: "preimage_server", "Received shutdown signal from preimage server task.") - }, - res = util::flatten_join_result(server_pair_task) => { - res?; - } - } - - // Signal to the client program that the server has exited. - let _ = tx.send(()); + AssertUnwindSafe(server.start()) + .catch_unwind() + .await + .map_err(|_| { + error!(target: "preimage_server", "Preimage server panicked"); + anyhow!("Preimage server panicked") + })? + .map_err(|e| { + error!(target: "preimage_server", "Preimage server exited with an error"); + anyhow!("Preimage server exited with an error: {:?}", e) + })?; info!("Preimage server has exited."); Ok(()) @@ -181,12 +150,7 @@ where /// ## Returns /// - `Ok(())` if the client program exits successfully. /// - `Err(_)` if the client program exits with a non-zero status. -async fn start_native_client_program( - cfg: HostCli, - files: NativePipeFiles, - tx: Sender<()>, - mut rx: Receiver<()>, -) -> Result<()> { +async fn start_native_client_program(cfg: HostCli, files: NativePipeFiles) -> Result<()> { // Map the file descriptors to the standard streams and the preimage oracle and hint // reader's special file descriptors. let mut command = Command::new(cfg.exec); @@ -202,37 +166,20 @@ async fn start_native_client_program( ]) .expect("No errors may occur when mapping file descriptors."); - let exec_task = task::spawn(async move { - let status = command - .status() - .await - .map_err(|e| { - error!(target: "client_program", "Failed to execute client program: {:?}", e); - anyhow!("Failed to execute client program: {:?}", e) - })? - .success(); - Ok::<_, anyhow::Error>(status) - }); - let rx_program_task = task::spawn(async move { rx.changed().await }); - - // Block the current task until either the client program exits or the server exits. - tokio::select! { - _ = rx_program_task => { - info!(target: "client_program", "Received shutdown signal from preimage server task.") - }, - res = util::flatten_join_result(exec_task) => { - if !(res?) { - // Signal to the preimage server that the client program has exited. - let _ = tx.send(()); - error!(target: "client_program", "Client program exited with a non-zero status."); - return Err(anyhow!("Client program exited with a non-zero status.")); - } - } + let status = command + .status() + .await + .map_err(|e| { + error!(target: "client_program", "Failed to execute client program: {:?}", e); + anyhow!("Failed to execute client program: {:?}", e) + })? + .success(); + + if !status { + error!(target: "client_program", "Client program exited with a non-zero status."); + return Err(anyhow!("Client program exited with a non-zero status.")); } - // Signal to the preimage server that the client program has exited. - let _ = tx.send(()); - info!(target: "client_program", "Client program has exited."); Ok(()) } diff --git a/bin/programs/client/src/main.rs b/bin/programs/client/src/main.rs index 8d4ec6248..ba152ab7b 100644 --- a/bin/programs/client/src/main.rs +++ b/bin/programs/client/src/main.rs @@ -17,6 +17,6 @@ fn main() -> Result<()> { let caching_oracle = CachingOracle::<16>::new(); let boot = BootInfo::load(&caching_oracle).await?; io::print(&alloc::format!("{:?}\n", boot)); - Ok(()) + Ok::<_, anyhow::Error>(()) }) } diff --git a/bin/programs/minimal/src/main.rs b/bin/programs/minimal/src/main.rs index 20526a3b8..401364066 100644 --- a/bin/programs/minimal/src/main.rs +++ b/bin/programs/minimal/src/main.rs @@ -9,5 +9,5 @@ extern crate alloc; #[client_entry(0xFFFFFFF)] fn main() -> Result<()> { io::print("Hello, world!\n"); - Ok(()) + Ok::<(), anyhow::Error>(()) } diff --git a/bin/programs/simple-revm/src/main.rs b/bin/programs/simple-revm/src/main.rs index 24e24a335..f80289da6 100644 --- a/bin/programs/simple-revm/src/main.rs +++ b/bin/programs/simple-revm/src/main.rs @@ -47,7 +47,7 @@ fn main() -> Result<()> { io::exit(1); } } - Ok(()) + Ok::<(), anyhow::Error>(()) }) } diff --git a/crates/common-proc/src/lib.rs b/crates/common-proc/src/lib.rs index 7d23bca5b..e2e70ba07 100644 --- a/crates/common-proc/src/lib.rs +++ b/crates/common-proc/src/lib.rs @@ -33,7 +33,13 @@ pub fn client_entry(attr: TokenStream, input: TokenStream) -> TokenStream { use anyhow::Result as AnyhowResult; fn #fn_name() -> AnyhowResult<()> { - #fn_body + match #fn_body { + Ok(_) => kona_common::io::exit(0), + Err(e) => { + kona_common::io::print_err(alloc::format!("Program encountered fatal error: {:?}\n", e).as_ref()); + kona_common::io::exit(1); + } + } } cfg_if::cfg_if! { @@ -43,8 +49,7 @@ pub fn client_entry(attr: TokenStream, input: TokenStream) -> TokenStream { #[no_mangle] pub extern "C" fn _start() { kona_common::alloc_heap!(HEAP_SIZE); - #fn_name().unwrap(); - kona_common::io::exit(0); + let _ = #fn_name(); } #[panic_handler]