diff --git a/crates/bin/src/helpers/verifier.rs b/crates/bin/src/helpers/verifier.rs index f0a916c..688475b 100644 --- a/crates/bin/src/helpers/verifier.rs +++ b/crates/bin/src/helpers/verifier.rs @@ -25,12 +25,10 @@ pub fn verify_catch_panics( vec![witness], chain_spec, #[cfg(feature = "scroll")] - verifier::StateCommitMode::Block, - #[cfg(feature = "scroll")] None::>>, ) .inspect_err(|e| { - if let VerificationError::BlockRootMismatch { bundle_state, .. } = e { + if let VerificationError::RootMismatch { bundle_state, .. } = e { let dump_dir = env::temp_dir() .join("dumps") .join(format!("{chain_id}-{block_number}")); diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index f2cd6e3..fadce5b 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -17,6 +17,9 @@ pub enum VerificationError { /// The witnesses are not sequential. #[error("witnesses are not sequential")] NonSequentialWitnesses, + /// The parent hash of a block does not match the hash of the previous block. + #[error("parent hash of a block does not match the hash of the previous block")] + ParentHashMismatch, /// Error while recovering signer from an ECDSA signature. #[error("invalid signature: {0}")] InvalidSignature(#[from] SignatureError), @@ -30,7 +33,7 @@ pub enum VerificationError { #[error( "state root in witness doesn't match with state root executed: expected {expected}, actual {actual}" )] - BlockRootMismatch { + RootMismatch { /// Root after in trace expected: B256, /// Root after in revm @@ -39,37 +42,21 @@ pub enum VerificationError { #[cfg(not(target_os = "zkvm"))] bundle_state: Box, }, - /// Root mismatch error - #[error( - "state root in last witness doesn't match with state root executed: expected {expected}, actual {actual}" - )] - ChunkRootMismatch { - /// Root after in trace - expected: B256, - /// Root after in revm - actual: B256, - }, } impl VerificationError { - /// Create a new [`VerificationError::BlockRootMismatch`] variant. + /// Create a new [`VerificationError::RootMismatch`] variant. #[inline] - pub fn block_root_mismatch( + pub fn root_mismatch( expected: B256, actual: B256, #[cfg(not(target_os = "zkvm"))] bundle_state: impl Into>, ) -> Self { - VerificationError::BlockRootMismatch { + VerificationError::RootMismatch { expected, actual, #[cfg(not(target_os = "zkvm"))] bundle_state: bundle_state.into(), } } - - /// Create a new [`VerificationError::ChunkRootMismatch`] variant. - #[inline] - pub fn chunk_root_mismatch(expected: B256, actual: B256) -> Self { - VerificationError::ChunkRootMismatch { expected, actual } - } } diff --git a/crates/core/src/verifier/ethereum.rs b/crates/core/src/verifier/ethereum.rs index c56038e..3c8b0fe 100644 --- a/crates/core/src/verifier/ethereum.rs +++ b/crates/core/src/verifier/ethereum.rs @@ -78,7 +78,7 @@ pub fn run( block.state_root, post_state_root ); - return Err(VerificationError::block_root_mismatch( + return Err(VerificationError::root_mismatch( block.state_root, post_state_root, #[cfg(not(target_os = "zkvm"))] diff --git a/crates/core/src/verifier/scroll.rs b/crates/core/src/verifier/scroll.rs index e6f1c8d..0e48faa 100644 --- a/crates/core/src/verifier/scroll.rs +++ b/crates/core/src/verifier/scroll.rs @@ -1,8 +1,8 @@ -use crate::{DatabaseError, EvmDatabase, EvmExecutor, VerificationError}; +use crate::{EvmDatabase, EvmExecutor, VerificationError}; use itertools::Itertools; use sbv_kv::{nohash::NoHashMap, null::NullProvider}; use sbv_primitives::{ - B256, Bytes, U256, + B256, Bytes, chainspec::ChainSpec, ext::{BlockWitnessChunkExt, BlockWitnessExt}, types::{ @@ -48,7 +48,6 @@ pub struct VerifyResult { pub fn run( witnesses: Vec, chain_spec: Arc, - state_commit_mode: StateCommitMode, compression_ratios: Option< impl IntoIterator>> + Clone, >, @@ -68,6 +67,8 @@ pub fn run( let nodes_provider = manually_drop_on_zkvm!(nodes_provider); let pre_state_root = witnesses[0].prev_state_root; + let post_state_root = witnesses.last().unwrap().header.state_root; + let blocks = witnesses .into_iter() .map(|w| { @@ -76,39 +77,68 @@ pub fn run( }) .collect::>, _>>()?; - let mut args = ExecuteInnerArgs { - code_db: &code_db, - nodes_provider: &nodes_provider, + if !blocks + .iter() + .tuple_windows() + .all(|(a, b)| a.hash() == b.header().parent_hash) + { + return Err(VerificationError::ParentHashMismatch); + } + + let mut db = manually_drop_on_zkvm!(EvmDatabase::new_from_root( + code_db, pre_state_root, - blocks: &blocks, - chain_spec: chain_spec.clone(), - defer_commit: true, - compression_ratios, - }; + &nodes_provider, + NullProvider, + )?); + + let mut gas_used = 0; + + let mut execute_block = |block, compression_ratio| -> Result<(), VerificationError> { + let output = manually_drop_on_zkvm!( + EvmExecutor::new(chain_spec.clone(), &db, block, compression_ratio).execute()? + ); + + gas_used += output.gas_used; + + db.update( + &nodes_provider, + BTreeMap::from_iter(output.state.state.clone()).iter(), + )?; - let result = match state_commit_mode { - StateCommitMode::Chunk | StateCommitMode::Block => { - args.defer_commit = matches!(state_commit_mode, StateCommitMode::Chunk); - execute(args)? + let post_state_root = db.commit_changes(); + if block.state_root != post_state_root { + dev_error!( + "Block #{} root mismatch: root after in trace = {:x}, root after in reth = {:x}", + block.number, + block.state_root, + post_state_root + ); + return Err(VerificationError::root_mismatch( + block.state_root, + post_state_root, + #[cfg(not(target_os = "zkvm"))] + output.state, + )); } - StateCommitMode::Auto => match execute(args.clone()) { - Ok(result) => result, - Err(VerificationError::Database(DatabaseError::PartialStateTrie(_e))) => { - dev_warn!( - "Failed to execute with defer commit enabled: {_e}; retrying with defer commit disabled" - ); - #[cfg(target_os = "zkvm")] - { - println!("failed to update db: {_e}; retrying with defer commit disabled"); - } - args.defer_commit = false; - execute(args)? - } - Err(e) => return Err(e), - }, + + Ok(()) }; - let (post_state_root, withdraw_root, gas_used) = result; + if let Some(compression_ratios) = compression_ratios { + for (block, compression_ratios) in blocks.iter().zip_eq(compression_ratios) { + execute_block( + block, + Some(compression_ratios.into_iter().map(|u| u.into())), + )?; + } + } else { + for block in blocks.iter() { + execute_block(block, None)?; + } + } + + let withdraw_root = db.withdraw_root()?; Ok(VerifyResult { blocks, @@ -144,107 +174,6 @@ fn make_providers(witnesses: &[BlockWitness]) -> (CodeDb, NodesProvider) { (code_db, nodes_provider) } -#[derive(Clone)] -pub(super) struct ExecuteInnerArgs<'a, I> { - pub(super) code_db: &'a CodeDb, - pub(super) nodes_provider: &'a NodesProvider, - pub(super) pre_state_root: B256, - pub(super) blocks: &'a [RecoveredBlock], - pub(super) chain_spec: Arc, - pub(super) defer_commit: bool, - pub(super) compression_ratios: Option, -} - -#[inline] -fn execute( - ExecuteInnerArgs { - code_db, - nodes_provider, - pre_state_root, - blocks, - chain_spec, - defer_commit, - compression_ratios, - }: ExecuteInnerArgs, -) -> Result<(B256, B256, u64), VerificationError> -where - II: IntoIterator, - I: IntoIterator, - R: Into, -{ - let mut gas_used = 0; - - let mut db = manually_drop_on_zkvm!(EvmDatabase::new_from_root( - code_db, - pre_state_root, - nodes_provider, - NullProvider, - )?); - - let mut execute_block = |block, compression_ratio| -> Result<(), VerificationError> { - let output = manually_drop_on_zkvm!( - EvmExecutor::new(chain_spec.clone(), &db, block, compression_ratio).execute()? - ); - - gas_used += output.gas_used; - - db.update( - nodes_provider, - BTreeMap::from_iter(output.state.state.clone()).iter(), - )?; - - if !defer_commit { - let post_state_root = db.commit_changes(); - if block.state_root != post_state_root { - dev_error!( - "Block #{} root mismatch: root after in trace = {:x}, root after in reth = {:x}", - block.number, - block.state_root, - post_state_root - ); - return Err(VerificationError::block_root_mismatch( - block.state_root, - post_state_root, - #[cfg(not(target_os = "zkvm"))] - output.state, - )); - } - dev_info!("Block #{} verified successfully", block.number); - } else { - dev_info!("Block #{} executed successfully", block.number); - } - - Ok(()) - }; - - if let Some(compression_ratios) = compression_ratios { - for (block, compression_ratios) in blocks.iter().zip_eq(compression_ratios) { - execute_block( - block, - Some(compression_ratios.into_iter().map(|u| u.into())), - )?; - } - } else { - for block in blocks { - execute_block(block, None)?; - } - } - - let post_state_root = db.commit_changes(); - let expected_state_root = blocks.last().unwrap().state_root; - if expected_state_root != post_state_root { - dev_error!( - "Final state root mismatch: expected {expected_state_root:x}, found {post_state_root:x}", - ); - return Err(VerificationError::chunk_root_mismatch( - expected_state_root, - post_state_root, - )); - } - let withdraw_root = db.withdraw_root()?; - Ok((post_state_root, withdraw_root, gas_used)) -} - #[cfg(test)] mod tests { use super::*; @@ -264,13 +193,7 @@ mod tests { let witness: BlockWitness = serde_json::from_str(witness_json).unwrap(); let chain_spec = build_chain_spec_force_hardfork(Chain::from_id(witness.chain_id), Hardfork::EuclidV2); - run( - vec![witness], - chain_spec, - StateCommitMode::Block, - None::>>, - ) - .unwrap(); + run(vec![witness], chain_spec, None::>>).unwrap(); } #[rstest::rstest] @@ -282,12 +205,6 @@ mod tests { let witness: BlockWitness = serde_json::from_str(witness_json).unwrap(); let chain_spec = build_chain_spec_force_hardfork(Chain::from_id(witness.chain_id), Hardfork::Feynman); - run( - vec![witness], - chain_spec, - StateCommitMode::Block, - None::>>, - ) - .unwrap(); + run(vec![witness], chain_spec, None::>>).unwrap(); } } diff --git a/crates/primitives/src/types.rs b/crates/primitives/src/types.rs index f27eee5..db5b423 100644 --- a/crates/primitives/src/types.rs +++ b/crates/primitives/src/types.rs @@ -66,7 +66,7 @@ pub mod revm { pub mod reth { /// Re-export types from `reth-primitives-types` pub mod primitives { - pub use reth_primitives::RecoveredBlock; + pub use reth_primitives::{RecoveredBlock, SealedBlock}; #[cfg(not(feature = "scroll"))] pub use reth_primitives::{Block, BlockBody, EthPrimitives, Receipt, TransactionSigned}; @@ -125,7 +125,7 @@ pub mod witness { Header, consensus::{SignerRecoverable, TxEnvelope}, eips::eip4895::Withdrawals, - reth::primitives::{Block, BlockBody, RecoveredBlock}, + reth::primitives::{Block, BlockBody, RecoveredBlock, SealedBlock}, }, }; use reth_primitives_traits::serde_bincode_compat::BincodeReprFor; @@ -210,11 +210,11 @@ pub mod witness { withdrawals: self.withdrawals, }; - Ok(RecoveredBlock::new_unhashed( - Block { + Ok(RecoveredBlock::new_sealed( + SealedBlock::seal_slow(Block { header: self.header, body, - }, + }), senders, )) }