diff --git a/Cargo.lock b/Cargo.lock index 1f89e9f9f..39cd20372 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2551,6 +2551,7 @@ dependencies = [ "alloy-rlp", "async-trait", "kona-derive", + "kona-executor", "maili-genesis", "maili-protocol", "maili-rpc", diff --git a/crates/driver/Cargo.toml b/crates/driver/Cargo.toml index 5fecc4c82..155cdd444 100644 --- a/crates/driver/Cargo.toml +++ b/crates/driver/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] # Workspace kona-derive.workspace = true +kona-executor.workspace = true # Maili maili-rpc.workspace = true diff --git a/crates/driver/src/core.rs b/crates/driver/src/core.rs index db2b62ea1..1f45250af 100644 --- a/crates/driver/src/core.rs +++ b/crates/driver/src/core.rs @@ -2,7 +2,7 @@ use crate::{DriverError, DriverPipeline, DriverResult, Executor, PipelineCursor, TipCursor}; use alloc::{sync::Arc, vec::Vec}; -use alloy_consensus::{BlockBody, Sealable}; +use alloy_consensus::BlockBody; use alloy_primitives::B256; use alloy_rlp::Decodable; use core::fmt::Debug; @@ -119,7 +119,7 @@ where }; self.executor.update_safe_head(tip_cursor.l2_safe_head_header.clone()); - let header = match self.executor.execute_payload(attributes.clone()).await { + let execution_result = match self.executor.execute_payload(attributes.clone()).await { Ok(header) => header, Err(e) => { error!(target: "client", "Failed to execute L2 block: {}", e); @@ -162,7 +162,7 @@ where // Construct the block. let block = OpBlock { - header: header.clone(), + header: execution_result.block_header.inner().clone(), body: BlockBody { transactions: attributes .transactions @@ -183,7 +183,7 @@ where )?; let tip_cursor = TipCursor::new( l2_info, - header.clone().seal_slow(), + execution_result.block_header, self.executor.compute_output_root().map_err(DriverError::Executor)?, ); diff --git a/crates/driver/src/executor.rs b/crates/driver/src/executor.rs index 2e57ca54f..d1855f5b7 100644 --- a/crates/driver/src/executor.rs +++ b/crates/driver/src/executor.rs @@ -5,6 +5,7 @@ use core::{ error::Error, fmt::{Debug, Display}, }; +use kona_executor::ExecutionArtifacts; use alloc::string::ToString; use alloy_consensus::{Header, Sealed}; @@ -30,7 +31,7 @@ pub trait Executor { async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result; + ) -> Result; /// Computes the output root. /// Expected to be called after the payload has been executed. diff --git a/crates/executor/src/constants.rs b/crates/executor/src/constants.rs index 3a1a71cc6..bde61e24a 100644 --- a/crates/executor/src/constants.rs +++ b/crates/executor/src/constants.rs @@ -1,6 +1,6 @@ //! Protocol constants for the executor. -use alloy_primitives::{address, Address}; +use alloy_primitives::{address, b256, Address, B256}; /// The address of the fee recipient. pub(crate) const FEE_RECIPIENT: Address = address!("4200000000000000000000000000000000000011"); @@ -9,7 +9,11 @@ pub(crate) const FEE_RECIPIENT: Address = address!("4200000000000000000000000000 pub(crate) const L2_TO_L1_BRIDGE: Address = address!("4200000000000000000000000000000000000016"); /// The current version of the output root format. -pub(crate) const OUTPUT_ROOT_VERSION: u8 = 0; +pub(crate) const OUTPUT_ROOT_VERSION: u8 = 0x00; /// The version byte for the Holocene extra data. pub(crate) const HOLOCENE_EXTRA_DATA_VERSION: u8 = 0x00; + +/// Empty SHA-256 hash. +pub(crate) const SHA256_EMPTY: B256 = + b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); diff --git a/crates/executor/src/executor/mod.rs b/crates/executor/src/executor/mod.rs index bfe79cd35..9c46e3b44 100644 --- a/crates/executor/src/executor/mod.rs +++ b/crates/executor/src/executor/mod.rs @@ -1,7 +1,7 @@ //! A stateless block executor for the OP Stack. use crate::{ - constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION}, + constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION, SHA256_EMPTY}, db::TrieDB, errors::TrieDBError, syscalls::{ @@ -12,9 +12,11 @@ use crate::{ ExecutorError, ExecutorResult, TrieDBProvider, }; use alloc::vec::Vec; -use alloy_consensus::{Header, Sealable, Transaction, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; +use alloy_consensus::{ + Header, Sealable, Sealed, Transaction, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH, +}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; -use alloy_primitives::{b256, keccak256, logs_bloom, Bytes, Log, B256, U256}; +use alloy_primitives::{keccak256, logs_bloom, Bytes, Log, B256, U256}; use kona_mpt::{ordered_trie_with_encoder, TrieHinter}; use maili_genesis::RollupConfig; use op_alloy_consensus::{OpReceiptEnvelope, OpTxEnvelope}; @@ -33,9 +35,15 @@ mod env; mod util; use util::encode_holocene_eip_1559_params; -/// Empty SHA-256 hash. -const SHA256_EMPTY: B256 = - b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); +/// The [ExecutionArtifacts] holds the produced block header and receipts from the execution of a +/// block. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExecutionArtifacts { + /// The block header. + pub block_header: Sealed
, + /// The receipts generated during execution. + pub receipts: Vec, +} /// The block executor for the L2 client program. Operates off of a [TrieDB] backed [State], /// allowing for stateless block execution of OP Stack blocks. @@ -96,7 +104,10 @@ where /// 4. Merge all state transitions into the cache state. /// 5. Compute the [state root, transactions root, receipts root, logs bloom] for the processed /// block. - pub fn execute_payload(&mut self, payload: OpPayloadAttributes) -> ExecutorResult<&Header> { + pub fn execute_payload( + &mut self, + payload: OpPayloadAttributes, + ) -> ExecutorResult { // Prepare the `revm` environment. let base_fee_params = Self::active_base_fee_params( self.config, @@ -417,8 +428,8 @@ where ); // Update the parent block hash in the state database. - state.database.set_parent_block_header(header); - Ok(state.database.parent_block_header()) + state.database.set_parent_block_header(header.clone()); + Ok(ExecutionArtifacts { block_header: header, receipts }) } /// Computes the current output root of the executor, based on the parent header and the diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs index b3a6bf03a..f6ca7e816 100644 --- a/crates/executor/src/lib.rs +++ b/crates/executor/src/lib.rs @@ -16,7 +16,10 @@ mod errors; pub use errors::{ExecutorError, ExecutorResult, TrieDBError, TrieDBResult}; mod executor; -pub use executor::{KonaHandleRegister, StatelessL2BlockExecutor, StatelessL2BlockExecutorBuilder}; +pub use executor::{ + ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, + StatelessL2BlockExecutorBuilder, +}; mod db; pub use db::{NoopTrieDBProvider, TrieAccount, TrieDB, TrieDBProvider}; diff --git a/crates/executor/src/test_utils.rs b/crates/executor/src/test_utils.rs index 3787d3006..928fb3f0d 100644 --- a/crates/executor/src/test_utils.rs +++ b/crates/executor/src/test_utils.rs @@ -147,11 +147,12 @@ impl ExecutorTestFixtureCreator { let mut executor = StatelessL2BlockExecutor::builder(rollup_config, self, NoopTrieHinter) .with_parent_header(parent_header) .build(); - let produced_header = + let exec_artifacts = executor.execute_payload(payload_attrs).expect("Failed to execute block").clone(); assert_eq!( - produced_header, executing_header.inner, + exec_artifacts.block_header.inner(), + &executing_header.inner, "Produced header does not match the expected header" ); fs::write(fixture_path.as_path(), serde_json::to_vec(&fixture).unwrap()).await.unwrap(); @@ -338,10 +339,10 @@ pub(crate) async fn run_test_fixture(fixture_path: PathBuf) { .with_parent_header(fixture.parent_header.seal_slow()) .build(); - let produced_header = executor.execute_payload(fixture.executing_payload).unwrap(); + let exec_artifacts = executor.execute_payload(fixture.executing_payload).unwrap(); assert_eq!( - produced_header.hash_slow(), + exec_artifacts.block_header.hash(), fixture.expected_block_hash, "Produced header does not match the expected header" ); diff --git a/crates/proof-sdk/proof/src/executor.rs b/crates/proof-sdk/proof/src/executor.rs index 8333282cd..ac9a814ee 100644 --- a/crates/proof-sdk/proof/src/executor.rs +++ b/crates/proof-sdk/proof/src/executor.rs @@ -5,7 +5,9 @@ use alloy_consensus::{Header, Sealed}; use alloy_primitives::B256; use async_trait::async_trait; use kona_driver::Executor; -use kona_executor::{KonaHandleRegister, StatelessL2BlockExecutor, TrieDBProvider}; +use kona_executor::{ + ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, TrieDBProvider, +}; use kona_mpt::TrieHinter; use maili_genesis::RollupConfig; use op_alloy_rpc_types_engine::OpPayloadAttributes; @@ -82,14 +84,11 @@ where async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result { - self.inner - .as_mut() - .map_or_else( - || Err(kona_executor::ExecutorError::MissingExecutor), - |e| e.execute_payload(attributes), - ) - .cloned() + ) -> Result { + self.inner.as_mut().map_or_else( + || Err(kona_executor::ExecutorError::MissingExecutor), + |e| e.execute_payload(attributes), + ) } /// Computes the output root.