Skip to main content

foundry_evm_symbolic/runtime/
executor_view.rs

1use super::*;
2use foundry_evm::core::backend::DatabaseError;
3
4/// Network-independent, read-only view of a concrete Foundry executor.
5///
6/// The view is built by the caller of the public entry points so the symbolic executor does not
7/// have to be monomorphized for every [`FoundryEvmNetwork`].
8pub struct ExecutorView<'a> {
9    pub(crate) backend: &'a dyn DatabaseRef<Error = DatabaseError>,
10    pub(crate) spec_id: SpecId,
11    pub(crate) chain_id: u64,
12    pub(crate) memory_limit: u64,
13    pub(crate) max_code_size: usize,
14    pub(crate) active_fork_id: Option<U256>,
15    /// Addresses cached by the in-memory database and the active fork database.
16    pub(crate) account_addresses: Vec<Address>,
17    pub(crate) block: ExecutorBlock,
18    pub(crate) gas_price: u128,
19    pub(crate) isolate: bool,
20    /// Whether `vm.expectRevert` may be satisfied by an internal call below the next call.
21    pub(crate) internal_expect_revert: bool,
22    pub(crate) blob_hashes: Vec<B256>,
23    pub(crate) arbitrary_storage_targets: Vec<(Address, bool)>,
24    pub(crate) arbitrary_storage_copies: Vec<(Address, Address)>,
25    pub(crate) storage_load_hooks: Vec<(Address, SymbolicStorageHook)>,
26    pub(crate) storage_store_hooks: Vec<(Address, SymbolicStorageHook)>,
27    pub(crate) mapping_storage_store_hooks: Vec<((Address, U256), SymbolicStorageHook)>,
28}
29
30/// Block environment values exposed to symbolic execution.
31pub(crate) struct ExecutorBlock {
32    pub(crate) coinbase: Address,
33    pub(crate) timestamp: U256,
34    pub(crate) number: U256,
35    pub(crate) difficulty: U256,
36    pub(crate) gas_limit: u64,
37    pub(crate) basefee: u64,
38    pub(crate) blob_basefee: u128,
39}
40
41impl<'a> ExecutorView<'a> {
42    /// Snapshots the environment, backend, and cheatcode configuration of `executor`.
43    pub fn new<FEN: FoundryEvmNetwork>(executor: &'a Executor<FEN>) -> Self {
44        let backend = executor.backend();
45        let evm_env = executor.evm_env();
46        let cheats = executor.inspector().cheatcodes.as_deref();
47        let block = cheats.and_then(|cheats| cheats.block.as_ref()).unwrap_or(evm_env.block_env());
48        let difficulty = block.prevrandao().map(Into::into).unwrap_or_else(|| block.difficulty());
49
50        let mut account_addresses =
51            backend.mem_db().cache.accounts.keys().copied().collect::<Vec<_>>();
52        if let Some(db) = backend.active_fork_db() {
53            account_addresses.extend(db.cache.accounts.keys().copied());
54        }
55
56        Self {
57            backend,
58            spec_id: executor.spec_id().into(),
59            chain_id: evm_env.cfg_env.chain_id,
60            memory_limit: evm_env.cfg_env.memory_limit(),
61            max_code_size: evm_env.cfg_env.max_code_size(),
62            active_fork_id: backend.active_fork_id(),
63            account_addresses,
64            block: ExecutorBlock {
65                coinbase: block.beneficiary(),
66                timestamp: block.timestamp(),
67                number: block.number(),
68                difficulty,
69                gas_limit: block.gas_limit(),
70                basefee: block.basefee(),
71                blob_basefee: block.blob_gasprice().unwrap_or_default(),
72            },
73            gas_price: cheats
74                .and_then(|cheats| cheats.gas_price)
75                .unwrap_or_else(|| executor.tx_env().gas_price()),
76            isolate: cheats.is_some_and(|cheats| cheats.core.config.isolate),
77            internal_expect_revert: cheats
78                .is_some_and(|cheats| cheats.core.config.internal_expect_revert),
79            blob_hashes: executor.tx_env().blob_versioned_hashes().to_vec(),
80            arbitrary_storage_targets: cheats
81                .into_iter()
82                .flat_map(|cheats| cheats.arbitrary_storage_target_overwrite_modes())
83                .collect(),
84            arbitrary_storage_copies: cheats
85                .into_iter()
86                .flat_map(|cheats| cheats.arbitrary_storage_copied_target_sources())
87                .collect(),
88            storage_load_hooks: cheats
89                .into_iter()
90                .flat_map(|cheats| cheats.storage_load_hooks())
91                .map(|(target, hook)| {
92                    (
93                        target,
94                        SymbolicStorageHook {
95                            callback_target: hook.callback_target,
96                            callback_selector: hook.callback_selector,
97                        },
98                    )
99                })
100                .collect(),
101            storage_store_hooks: cheats
102                .into_iter()
103                .flat_map(|cheats| cheats.storage_store_hooks())
104                .map(|(target, hook)| {
105                    (
106                        target,
107                        SymbolicStorageHook {
108                            callback_target: hook.callback_target,
109                            callback_selector: hook.callback_selector,
110                        },
111                    )
112                })
113                .collect(),
114            mapping_storage_store_hooks: cheats
115                .into_iter()
116                .flat_map(|cheats| cheats.mapping_storage_store_hooks())
117                .map(|(target, root, hook)| {
118                    (
119                        (target, root.into()),
120                        SymbolicStorageHook {
121                            callback_target: hook.callback_target,
122                            callback_selector: hook.callback_selector,
123                        },
124                    )
125                })
126                .collect(),
127        }
128    }
129}