diff --git a/Cargo.lock b/Cargo.lock index def2de507..0b00692fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1685,12 +1685,12 @@ dependencies = [ "kona-common", "kona-common-proc", "kona-derive", + "kona-executor", "kona-mpt", "kona-preimage", "kona-primitives", "lru", "op-alloy-consensus", - "revm", "serde", "serde_json", "spin 0.9.8", @@ -1756,6 +1756,24 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "kona-executor" +version = "0.0.1" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "anyhow", + "kona-derive", + "kona-mpt", + "op-alloy-consensus", + "revm", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "kona-host" version = "0.1.0" diff --git a/README.md b/README.md index eb49aa247..9e5f1f956 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ verify an [L2 output root][g-output-root] from the L1 inputs it was [derived fro - [`common-proc`](./crates/common-proc): Proc macro for the `client` program entrypoint. - [`primitives`](./crates/primitives): Primitive types for use in `kona` crates. - [`preimage`](./crates/preimage): High level interfaces to the [`PreimageOracle`][fpp-specs] ABI -- [`mpt`](./crrates/mpt): Utilities for interacting with the Merkle Patricia Trie in the client program. +- [`mpt`](./crates/mpt): Utilities for interacting with the Merkle Patricia Trie in the client program. +- [`executor`](./crates/executor): `no_std` stateless block executor for the [OP Stack][op-stack]. - [`derive`](./crates/derive): `no_std` compatible implementation of the [derivation pipeline][g-derivation-pipeline]. - [`plasma`](./crates/plasma/): Plasma extension to `kona-derive` diff --git a/bin/programs/client/Cargo.toml b/bin/programs/client/Cargo.toml index 2e5cc2bc1..6fea94b48 100644 --- a/bin/programs/client/Cargo.toml +++ b/bin/programs/client/Cargo.toml @@ -16,7 +16,6 @@ alloy-rlp.workspace = true alloy-eips.workspace = true op-alloy-consensus.workspace = true anyhow.workspace = true -revm = { workspace = true, features = ["optimism"] } lru.workspace = true spin.workspace = true async-trait.workspace = true @@ -29,6 +28,7 @@ kona-preimage = { path = "../../../crates/preimage", version = "0.0.1" } kona-primitives = { path = "../../../crates/primitives", version = "0.0.1" } kona-mpt = { path = "../../../crates/mpt", version = "0.0.1" } kona-derive = { path = "../../../crates/derive", default-features = false, version = "0.0.1" } +kona-executor = { path = "../../../crates/executor", version = "0.0.1" } tracing-subscriber = { version = "0.3.18", optional = true } @@ -38,3 +38,7 @@ serde_json = "1.0.117" [features] tracing-subscriber = ["dep:tracing-subscriber"] + +[[bin]] +name = "kona" +path = "src/kona.rs" diff --git a/bin/programs/client/src/main.rs b/bin/programs/client/src/kona.rs similarity index 71% rename from bin/programs/client/src/main.rs rename to bin/programs/client/src/kona.rs index 3ddd26994..07cd6e182 100644 --- a/bin/programs/client/src/main.rs +++ b/bin/programs/client/src/kona.rs @@ -9,10 +9,12 @@ use alloc::sync::Arc; use alloy_consensus::Header; use kona_client::{ l1::{DerivationDriver, OracleBlobProvider, OracleL1ChainProvider}, - l2::{OracleL2ChainProvider, StatelessL2BlockExecutor, TrieDBHintWriter}, + l2::{OracleL2ChainProvider, TrieDBHintWriter}, BootInfo, CachingOracle, }; use kona_common_proc::client_entry; +use kona_executor::StatelessL2BlockExecutor; +use kona_primitives::L2AttributesWithParent; extern crate alloc; @@ -22,7 +24,13 @@ const ORACLE_LRU_SIZE: usize = 1024; #[client_entry(0x77359400)] fn main() -> Result<()> { #[cfg(feature = "tracing-subscriber")] - init_tracing_subscriber(3)?; + { + use anyhow::anyhow; + use tracing::Level; + + let subscriber = tracing_subscriber::fmt().with_max_level(Level::DEBUG).finish(); + tracing::subscriber::set_global_default(subscriber).map_err(|e| anyhow!(e))?; + } kona_common::block_on(async move { //////////////////////////////////////////////////////////////// @@ -47,16 +55,15 @@ fn main() -> Result<()> { l2_provider.clone(), ) .await?; - let attributes = driver.produce_disputed_payload().await?; + let L2AttributesWithParent { attributes, .. } = driver.produce_disputed_payload().await?; - let cfg = Arc::new(boot.rollup_config.clone()); let mut executor = StatelessL2BlockExecutor::new( - cfg, - driver.l2_safe_head_header().clone(), + &boot.rollup_config, + driver.take_l2_safe_head_header(), l2_provider, TrieDBHintWriter, ); - let Header { number, .. } = *executor.execute_payload(attributes.attributes)?; + let Header { number, .. } = *executor.execute_payload(attributes)?; let output_root = executor.compute_output_root()?; //////////////////////////////////////////////////////////////// @@ -76,27 +83,3 @@ fn main() -> Result<()> { Ok::<_, anyhow::Error>(()) }) } - -/// Initializes the tracing subscriber -/// -/// # Arguments -/// * `verbosity_level` - The verbosity level (0-4) -/// -/// # Returns -/// * `Result<()>` - Ok if successful, Err otherwise. -#[cfg(feature = "tracing-subscriber")] -pub fn init_tracing_subscriber(verbosity_level: u8) -> anyhow::Result<()> { - use anyhow::anyhow; - use tracing::Level; - - let subscriber = tracing_subscriber::fmt() - .with_max_level(match verbosity_level { - 0 => Level::ERROR, - 1 => Level::WARN, - 2 => Level::INFO, - 3 => Level::DEBUG, - _ => Level::TRACE, - }) - .finish(); - tracing::subscriber::set_global_default(subscriber).map_err(|e| anyhow!(e)) -} diff --git a/bin/programs/client/src/l1/driver.rs b/bin/programs/client/src/l1/driver.rs index ea2878b64..8f5603531 100644 --- a/bin/programs/client/src/l1/driver.rs +++ b/bin/programs/client/src/l1/driver.rs @@ -64,16 +64,21 @@ pub struct DerivationDriver { } impl DerivationDriver { - /// Returns the current L2 safe head block information. + /// Returns the current L2 safe head [L2BlockInfo]. pub fn l2_safe_head(&self) -> &L2BlockInfo { &self.l2_safe_head } - /// Returns the header of the current L2 safe head. + /// Returns the [Header] of the current L2 safe head. pub fn l2_safe_head_header(&self) -> &Sealed
{ &self.l2_safe_head_header } + /// Consumes self and returns the owned [Header] of the current L2 safe head. + pub fn take_l2_safe_head_header(self) -> Sealed
{ + self.l2_safe_head_header + } + /// Creates a new [DerivationDriver] with the given configuration, blob provider, and chain /// providers. /// diff --git a/bin/programs/client/src/l2/mod.rs b/bin/programs/client/src/l2/mod.rs index 3b945c441..31ceb9323 100644 --- a/bin/programs/client/src/l2/mod.rs +++ b/bin/programs/client/src/l2/mod.rs @@ -1,8 +1,7 @@ -//! Contains the L2-specifc contstructs of the client program, such as the -//! [StatelessL2BlockExecutor] +//! Contains the L2-specifc contstructs of the client program. -mod executor; -pub use executor::{StatelessL2BlockExecutor, TrieDBHintWriter}; +mod trie_hinter; +pub use trie_hinter::TrieDBHintWriter; mod chain_provider; pub use chain_provider::OracleL2ChainProvider; diff --git a/bin/programs/client/src/l2/executor/hinter.rs b/bin/programs/client/src/l2/trie_hinter.rs similarity index 100% rename from bin/programs/client/src/l2/executor/hinter.rs rename to bin/programs/client/src/l2/trie_hinter.rs diff --git a/crates/executor/Cargo.toml b/crates/executor/Cargo.toml new file mode 100644 index 000000000..d17826002 --- /dev/null +++ b/crates/executor/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "kona-executor" +description = "An no_std implementation of a stateless L2 block executor for the OP Stack." +version = "0.0.1" +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +# workspace +anyhow.workspace = true +tracing.workspace = true +alloy-primitives = { workspace = true, features = ["rlp"] } +alloy-rlp.workspace = true +alloy-eips.workspace = true +alloy-consensus.workspace = true +op-alloy-consensus.workspace = true +revm = { workspace = true, features = ["optimism"] } + +# local +kona-mpt = { path = "../mpt", version = "0.0.1" } +kona-derive = { path = "../derive", version = "0.0.1" } + +[dev-dependencies] +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.117" diff --git a/crates/executor/README.md b/crates/executor/README.md new file mode 100644 index 000000000..470d700e3 --- /dev/null +++ b/crates/executor/README.md @@ -0,0 +1,3 @@ +# `kona-executor` + +A `no_std` implementation of a stateless block executor for the OP stack, backed by [`kona-mpt`](../mpt)'s `TrieDB`. diff --git a/bin/programs/client/src/l2/executor/canyon.rs b/crates/executor/src/canyon.rs similarity index 100% rename from bin/programs/client/src/l2/executor/canyon.rs rename to crates/executor/src/canyon.rs diff --git a/bin/programs/client/src/l2/executor/eip4788.rs b/crates/executor/src/eip4788.rs similarity index 100% rename from bin/programs/client/src/l2/executor/eip4788.rs rename to crates/executor/src/eip4788.rs diff --git a/bin/programs/client/src/l2/executor/mod.rs b/crates/executor/src/lib.rs similarity index 99% rename from bin/programs/client/src/l2/executor/mod.rs rename to crates/executor/src/lib.rs index c5d252fcc..acb519ae2 100644 --- a/bin/programs/client/src/l2/executor/mod.rs +++ b/crates/executor/src/lib.rs @@ -1,7 +1,12 @@ -//! The block executor for the L2 client program. Operates off of a [TrieDB] backed [State], -//! allowing for stateless block execution of OP Stack blocks. +#![doc = include_str!("../README.md")] +#![warn(missing_debug_implementations, missing_docs, unreachable_pub, rustdoc::all)] +#![deny(unused_must_use, rust_2018_idioms)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![no_std] -use alloc::{sync::Arc, vec::Vec}; +extern crate alloc; + +use alloc::vec::Vec; use alloy_consensus::{Header, Sealable, Sealed, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{address, keccak256, Address, Bytes, TxKind, B256, U256}; @@ -17,37 +22,32 @@ use revm::{ }, Evm, StateBuilder, }; - -mod hinter; -pub use hinter::TrieDBHintWriter; +use tracing::{debug, info}; mod eip4788; -pub(crate) use eip4788::pre_block_beacon_root_contract_call; +use eip4788::pre_block_beacon_root_contract_call; mod canyon; -pub(crate) use canyon::ensure_create2_deployer_canyon; +use canyon::ensure_create2_deployer_canyon; mod util; -use tracing::{debug, info}; -pub(crate) use util::{logs_bloom, wrap_receipt_with_bloom}; - -use self::util::{extract_tx_gas_limit, is_system_transaction}; +use util::{extract_tx_gas_limit, is_system_transaction, logs_bloom, wrap_receipt_with_bloom}; /// The block executor for the L2 client program. Operates off of a [TrieDB] backed [State], /// allowing for stateless block execution of OP Stack blocks. #[derive(Debug)] -pub struct StatelessL2BlockExecutor +pub struct StatelessL2BlockExecutor<'a, F, H> where F: TrieDBFetcher, H: TrieDBHinter, { /// The [RollupConfig]. - config: Arc, + config: &'a RollupConfig, /// The inner state database component. state: State>, } -impl StatelessL2BlockExecutor +impl<'a, F, H> StatelessL2BlockExecutor<'a, F, H> where F: TrieDBFetcher, H: TrieDBHinter, @@ -55,7 +55,7 @@ where /// Constructs a new [StatelessL2BlockExecutor] with the given starting state root, parent hash, /// and [TrieDBFetcher]. pub fn new( - config: Arc, + config: &'a RollupConfig, parent_header: Sealed
, fetcher: F, hinter: H, @@ -66,7 +66,7 @@ where } } -impl StatelessL2BlockExecutor +impl<'a, F, H> StatelessL2BlockExecutor<'a, F, H> where F: TrieDBFetcher, H: TrieDBHinter, @@ -91,7 +91,7 @@ where // Prepare the `revm` environment. let initialized_block_env = Self::prepare_block_env( self.revm_spec_id(payload.timestamp), - self.config.as_ref(), + self.config, self.state.database.parent_block_header(), &payload, ); @@ -112,7 +112,7 @@ where // Apply the pre-block EIP-4788 contract call. pre_block_beacon_root_contract_call( &mut self.state, - self.config.as_ref(), + self.config, block_number, &initialized_cfg, &initialized_block_env, @@ -120,7 +120,7 @@ where )?; // Ensure that the create2 contract is deployed upon transition to the Canyon hardfork. - ensure_create2_deployer_canyon(&mut self.state, self.config.as_ref(), payload.timestamp)?; + ensure_create2_deployer_canyon(&mut self.state, self.config, payload.timestamp)?; // Construct the EVM with the given configuration. // TODO(clabby): Accelerate precompiles w/ custom precompile handler. @@ -237,8 +237,7 @@ where let state_root = self.state.database.state_root(&bundle)?; let transactions_root = Self::compute_transactions_root(payload.transactions.as_slice()); - let receipts_root = - Self::compute_receipts_root(&receipts, self.config.as_ref(), payload.timestamp); + let receipts_root = Self::compute_receipts_root(&receipts, self.config, payload.timestamp); debug!( target: "client_executor", "Computed transactions root: {transactions_root} | receipts root: {receipts_root}", @@ -717,7 +716,7 @@ mod test { // Initialize the block executor on block #120794431's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, header.seal_slow(), TestdataTrieDBFetcher::new("block_120794432_exec"), NoopTrieDBHinter, @@ -770,7 +769,7 @@ mod test { // Initialize the block executor on block #121049888's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, parent_header.seal_slow(), TestdataTrieDBFetcher::new("block_121049889_exec"), NoopTrieDBHinter, @@ -827,7 +826,7 @@ mod test { // Initialize the block executor on block #121003240's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, parent_header.seal_slow(), TestdataTrieDBFetcher::new("block_121003241_exec"), NoopTrieDBHinter, @@ -891,7 +890,7 @@ mod test { // Initialize the block executor on block #121057302's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, parent_header.seal_slow(), TestdataTrieDBFetcher::new("block_121057303_exec"), NoopTrieDBHinter, @@ -949,7 +948,7 @@ mod test { // Initialize the block executor on block #121057302's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, parent_header.seal_slow(), TestdataTrieDBFetcher::new("block_121065789_exec"), NoopTrieDBHinter, @@ -1016,7 +1015,7 @@ mod test { // Initialize the block executor on block #121135703's post-state. let mut l2_block_executor = StatelessL2BlockExecutor::new( - Arc::new(rollup_config), + &rollup_config, parent_header.seal_slow(), TestdataTrieDBFetcher::new("block_121135704_exec"), NoopTrieDBHinter, diff --git a/bin/programs/client/src/l2/executor/util.rs b/crates/executor/src/util.rs similarity index 100% rename from bin/programs/client/src/l2/executor/util.rs rename to crates/executor/src/util.rs diff --git a/bin/programs/client/testdata/block_120794432_exec/output.json b/crates/executor/testdata/block_120794432_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_120794432_exec/output.json rename to crates/executor/testdata/block_120794432_exec/output.json diff --git a/bin/programs/client/testdata/block_121003241_exec/output.json b/crates/executor/testdata/block_121003241_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_121003241_exec/output.json rename to crates/executor/testdata/block_121003241_exec/output.json diff --git a/bin/programs/client/testdata/block_121049889_exec/output.json b/crates/executor/testdata/block_121049889_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_121049889_exec/output.json rename to crates/executor/testdata/block_121049889_exec/output.json diff --git a/bin/programs/client/testdata/block_121057303_exec/output.json b/crates/executor/testdata/block_121057303_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_121057303_exec/output.json rename to crates/executor/testdata/block_121057303_exec/output.json diff --git a/bin/programs/client/testdata/block_121065789_exec/output.json b/crates/executor/testdata/block_121065789_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_121065789_exec/output.json rename to crates/executor/testdata/block_121065789_exec/output.json diff --git a/bin/programs/client/testdata/block_121135704_exec/output.json b/crates/executor/testdata/block_121135704_exec/output.json similarity index 100% rename from bin/programs/client/testdata/block_121135704_exec/output.json rename to crates/executor/testdata/block_121135704_exec/output.json