Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions crates/bin/src/helpers/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ pub fn verify_catch_panics(
vec![witness],
chain_spec,
#[cfg(feature = "scroll")]
verifier::StateCommitMode::Block,
#[cfg(feature = "scroll")]
None::<Vec<Vec<sbv::primitives::U256>>>,
)
.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}"));
Expand Down
27 changes: 7 additions & 20 deletions crates/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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
Expand All @@ -39,37 +42,21 @@ pub enum VerificationError {
#[cfg(not(target_os = "zkvm"))]
bundle_state: Box<BundleState>,
},
/// 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<Box<BundleState>>,
) -> 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 }
}
}
2 changes: 1 addition & 1 deletion crates/core/src/verifier/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
209 changes: 63 additions & 146 deletions crates/core/src/verifier/scroll.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -48,7 +48,6 @@ pub struct VerifyResult {
pub fn run(
witnesses: Vec<BlockWitness>,
chain_spec: Arc<ChainSpec>,
state_commit_mode: StateCommitMode,
compression_ratios: Option<
impl IntoIterator<Item = impl IntoIterator<Item = impl Into<sbv_primitives::U256>>> + Clone,
>,
Expand All @@ -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| {
Expand All @@ -76,39 +77,68 @@ pub fn run(
})
.collect::<Result<Vec<RecoveredBlock<Block>>, _>>()?;

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,
Expand Down Expand Up @@ -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<Block>],
pub(super) chain_spec: Arc<ChainSpec>,
pub(super) defer_commit: bool,
pub(super) compression_ratios: Option<I>,
}

#[inline]
fn execute<II, I, R>(
ExecuteInnerArgs {
code_db,
nodes_provider,
pre_state_root,
blocks,
chain_spec,
defer_commit,
compression_ratios,
}: ExecuteInnerArgs<II>,
) -> Result<(B256, B256, u64), VerificationError>
where
II: IntoIterator<Item = I>,
I: IntoIterator<Item = R>,
R: Into<U256>,
{
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::*;
Expand All @@ -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::<Vec<Vec<U256>>>,
)
.unwrap();
run(vec![witness], chain_spec, None::<Vec<Vec<U256>>>).unwrap();
}

#[rstest::rstest]
Expand All @@ -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::<Vec<Vec<U256>>>,
)
.unwrap();
run(vec![witness], chain_spec, None::<Vec<Vec<U256>>>).unwrap();
}
}
10 changes: 5 additions & 5 deletions crates/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
))
}
Expand Down
Loading