From ea401d1b6b7dfce2690ccbad82754b14307dd951 Mon Sep 17 00:00:00 2001 From: eigmax Date: Wed, 29 Oct 2025 18:39:54 +0800 Subject: [PATCH] return post state --- crates/executor/guest/src/error.rs | 5 ++ crates/executor/guest/src/executor.rs | 69 +++++++++++++++++++++-- crates/executor/guest/src/lib.rs | 2 +- crates/executor/host/tests/integration.rs | 2 +- 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/crates/executor/guest/src/error.rs b/crates/executor/guest/src/error.rs index 557bd8e..8093320 100644 --- a/crates/executor/guest/src/error.rs +++ b/crates/executor/guest/src/error.rs @@ -2,6 +2,7 @@ use alloy_primitives::{Address, FixedBytes}; use mpt::Error as MptError; use reth_consensus::ConsensusError; use reth_evm::execute::BlockExecutionError; +use revm_primitives::U256; #[derive(Debug, thiserror::Error)] pub enum ClientError { @@ -31,4 +32,8 @@ pub enum ClientError { FailedToReadGenesisFile(#[from] std::io::Error), #[error("Failed to deserialize the genesis file: {}", .0)] FailedToDeserializeGenesisFile(#[from] serde_json::Error), + #[error("Failed to check slot and value: {}", .0)] + FailedToCheckSlotAndValue(U256), + #[error("Failed to fetch slot and value: {}", .0)] + FailedToFetchSlotAndValue(U256), } diff --git a/crates/executor/guest/src/executor.rs b/crates/executor/guest/src/executor.rs index 7620ee9..3b1988a 100644 --- a/crates/executor/guest/src/executor.rs +++ b/crates/executor/guest/src/executor.rs @@ -1,5 +1,5 @@ use std::sync::Arc; - +use itertools::Itertools; use alloy_consensus::{BlockHeader, Header, TxReceipt}; use alloy_evm::EthEvmFactory; use alloy_primitives::{Bloom, B256}; @@ -12,15 +12,16 @@ use reth_evm::{ use reth_evm_ethereum::EthEvmConfig; use reth_execution_types::ExecutionOutcome; use reth_primitives_traits::Block; -use reth_trie::KeccakKeyHasher; +use reth_trie::{EMPTY_ROOT_HASH, KeccakKeyHasher, TrieAccount}; use revm::database::WrapDatabaseRef; -use revm_primitives::Address; +use revm::DatabaseRef; +use revm_primitives::{Address, HashMap, U256}; use crate::{ custom::CustomEvmFactory, error::ClientError, into_primitives::FromInput, - io::{ClientExecutorInput, TrieDB}, + io::{ClientExecutorInput, TrieDB, WitnessInput}, tracking::OpCodesTrackingBlockExecutor, ValidateBlockPostExecution, }; @@ -32,6 +33,7 @@ pub const BLOCK_EXECUTION: &str = "block execution"; pub const VALIDATE_EXECUTION: &str = "validate block post-execution"; pub const ACCRUE_LOG_BLOOM: &str = "accrue logs bloom"; pub const COMPUTE_STATE_ROOT: &str = "compute state root"; +pub const CHECK_SLOT_AND_VALUE: &str = "check slot and value"; pub type EthClientExecutor = ClientExecutor>>; @@ -52,6 +54,7 @@ where pub fn execute( &self, mut input: ClientExecutorInput, + storage_info: Option>, ) -> Result<(Header, B256), ClientError> { // Initialize the witnessed database with verified storage proofs. let db = profile_report!(INIT_WITNESS_DB, { @@ -132,6 +135,64 @@ where requests_hash: input.current_block.header().requests_hash(), }; + if storage_info.is_some() { + let check_result: Result<(), ClientError> = profile_report!(CHECK_SLOT_AND_VALUE, { + let state = input.state(); + let db = { + for (hashed_address, storage_trie) in state.storage_tries.iter() { + let account = + state.state_trie.get_rlp::(hashed_address.as_slice()).unwrap(); + let storage_root = account.map_or(EMPTY_ROOT_HASH, |a| a.storage_root); + if storage_root != storage_trie.hash() { + return Err(ClientError::MismatchedStorageRoot); + } + } + + let bytecodes_by_hash = + input.bytecodes().map(|code| (code.hash_slow(), code)).collect::>(); + + // Verify and build block hashes + let mut block_hashes: HashMap = HashMap::with_hasher(Default::default()); + for (child_header, parent_header) in input.headers().tuple_windows() { + if parent_header.number() != child_header.number() - 1 { + return Err(ClientError::InvalidHeaderBlockNumber( + parent_header.number() + 1, + child_header.number(), + )); + } + + let parent_header_hash = parent_header.hash_slow(); + if parent_header_hash != child_header.parent_hash() { + return Err(ClientError::InvalidHeaderParentHash( + parent_header_hash, + child_header.parent_hash(), + )); + } + + block_hashes.insert(parent_header.number(), child_header.parent_hash()); + } + + TrieDB::new(state, block_hashes, bytecodes_by_hash) + }; + + for (contract_address, slot_id, expected_value) in storage_info.unwrap() { + match db.storage_ref(contract_address, slot_id) { + Ok(actual_value) => { + if actual_value != expected_value { + return Err(ClientError::FailedToCheckSlotAndValue(slot_id)); + } + }, + _ => { + return Err(ClientError::FailedToFetchSlotAndValue(slot_id)); + } + } + } + Ok(()) + }); + if check_result.is_err() { + return Err(check_result.err().unwrap()); + } + } Ok((header, parent_state_root)) } } diff --git a/crates/executor/guest/src/lib.rs b/crates/executor/guest/src/lib.rs index 3a7f76b..fc8c3f5 100644 --- a/crates/executor/guest/src/lib.rs +++ b/crates/executor/guest/src/lib.rs @@ -27,7 +27,7 @@ pub fn verify_block(input: &Vec) -> (B256, B256, B256) { Arc::new((&input.genesis).try_into().unwrap()), input.custom_beneficiary, ); - let (header, prev_state_root) = executor.execute(input).expect("failed to execute client"); + let (header, prev_state_root) = executor.execute(input, None).expect("failed to execute client"); let block_hash = header.hash_slow(); (block_hash, header.state_root, prev_state_root) } diff --git a/crates/executor/host/tests/integration.rs b/crates/executor/host/tests/integration.rs index 23d0679..e728eda 100644 --- a/crates/executor/host/tests/integration.rs +++ b/crates/executor/host/tests/integration.rs @@ -126,7 +126,7 @@ async fn run_e2e( .expect("failed to execute host"); // Execute the client. - guest_executor.execute(client_input.clone()).expect("failed to execute client"); + guest_executor.execute(client_input.clone(), None, None).expect("failed to execute client"); // Save the client input to a buffer. let buffer = bincode::serialize(&client_input).unwrap();