reth_revm/
witness.rs

1use alloy_primitives::{keccak256, map::B256HashMap, Bytes, B256};
2use reth_trie::{HashedPostState, HashedStorage};
3use revm::State;
4
5/// Tracks state changes during execution.
6#[derive(Debug, Clone, Default)]
7pub struct ExecutionWitnessRecord {
8    /// Records all state changes
9    pub hashed_state: HashedPostState,
10    /// Map of all contract codes (created / accessed) to their preimages that were required during
11    /// the execution of the block, including during state root recomputation.
12    ///
13    /// `keccak(bytecodes) => bytecodes`
14    pub codes: B256HashMap<Bytes>,
15    /// Map of all hashed account and storage keys (addresses and slots) to their preimages
16    /// (unhashed account addresses and storage slots, respectively) that were required during
17    /// the execution of the block. during the execution of the block.
18    ///
19    /// `keccak(address|slot) => address|slot`
20    pub keys: B256HashMap<Bytes>,
21}
22
23impl ExecutionWitnessRecord {
24    /// Records the state after execution.
25    pub fn record_executed_state<DB>(&mut self, statedb: &State<DB>) {
26        self.codes = statedb
27            .cache
28            .contracts
29            .iter()
30            .map(|(hash, code)| (*hash, code.original_bytes()))
31            .chain(
32                // cache state does not have all the contracts, especially when
33                // a contract is created within the block
34                // the contract only exists in bundle state, therefore we need
35                // to include them as well
36                statedb
37                    .bundle_state
38                    .contracts
39                    .iter()
40                    .map(|(hash, code)| (*hash, code.original_bytes())),
41            )
42            .collect();
43
44        for (address, account) in &statedb.cache.accounts {
45            let hashed_address = keccak256(address);
46            self.hashed_state
47                .accounts
48                .insert(hashed_address, account.account.as_ref().map(|a| (&a.info).into()));
49
50            let storage = self
51                .hashed_state
52                .storages
53                .entry(hashed_address)
54                .or_insert_with(|| HashedStorage::new(account.status.was_destroyed()));
55
56            if let Some(account) = &account.account {
57                self.keys.insert(hashed_address, address.to_vec().into());
58
59                for (slot, value) in &account.storage {
60                    let slot = B256::from(*slot);
61                    let hashed_slot = keccak256(slot);
62                    storage.storage.insert(hashed_slot, *value);
63
64                    self.keys.insert(hashed_slot, slot.into());
65                }
66            }
67        }
68    }
69
70    /// Creates the record from the state after execution.
71    pub fn from_executed_state<DB>(state: &State<DB>) -> Self {
72        let mut record = Self::default();
73        record.record_executed_state(state);
74        record
75    }
76}