Skip to content
Open
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
5 changes: 5 additions & 0 deletions crates/executor/guest/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
}
71 changes: 68 additions & 3 deletions crates/executor/guest/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use reth_evm::{
use reth_evm_ethereum::EthEvmConfig;
use reth_execution_types::ExecutionOutcome;
use reth_primitives_traits::Block;
use reth_trie::KeccakKeyHasher;
use revm::{database::WrapDatabaseRef, install_crypto};
use revm_primitives::Address;
use reth_trie::{KeccakKeyHasher, TrieAccount, EMPTY_ROOT_HASH};
use revm::{database::WrapDatabaseRef, install_crypto, DatabaseRef};
use revm_primitives::{Address, HashMap, U256};

use crate::{
custom::{CustomCrypto, CustomEvmFactory},
Expand All @@ -33,6 +33,7 @@ pub const BLOCK_EXECUTION: &str = "block execution";
pub const VALIDATE_HEADER: &str = "validate header";
pub const VALIDATE_EXECUTION: &str = "validate block post-execution";
pub const COMPUTE_STATE_ROOT: &str = "compute state root";
pub const CHECK_SLOT_AND_VALUE: &str = "check slot and value";

pub type EthClientExecutor = ClientExecutor<EthEvmConfig<ChainSpec, CustomEvmFactory>, ChainSpec>;

Expand All @@ -55,6 +56,7 @@ where
pub fn execute(
&self,
mut input: ClientExecutorInput<C::Primitives>,
storage_info: Option<Vec<(Address, U256, U256)>>,
) -> Result<(Header, B256), ClientError> {
let chain_id: u64 = (&input.genesis).try_into().expect("convert chain id err");

Expand Down Expand Up @@ -152,6 +154,69 @@ 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::<TrieAccount>(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::<HashMap<_, _>>();

// Verify and build block hashes
let mut block_hashes: HashMap<u64, B256> =
HashMap::with_hasher(Default::default());
for (child_header, parent_header) in input.sealed_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))
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/executor/guest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ pub fn verify_block(input: &[u8]) -> (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)
}
2 changes: 1 addition & 1 deletion crates/executor/host/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async fn run_e2e<C, CS, N>(
.expect("failed to execute host");

// Execute the client.
client_executor.execute(client_input.clone()).expect("failed to execute client");
client_executor.execute(client_input.clone(), None).expect("failed to execute client");

// Save the client input to a buffer.
let buffer = bincode::serialize(&client_input).unwrap();
Expand Down