1use crate::executors::{Executor, ExecutorBuilder};
2use alloy_primitives::{Address, ChainId, U256, map::HashMap};
3use alloy_rpc_types::state::StateOverride;
4use eyre::{Context, ContextCompat};
5use foundry_compilers::artifacts::EvmVersion;
6use foundry_config::{Chain, Config, evm_spec_id};
7use foundry_evm_core::{
8 backend::Backend,
9 evm::{BlockEnvFor, EvmEnvFor, FoundryEvmNetwork, SpecFor, TxEnvFor},
10 fork::CreateFork,
11 opts::{EvmOpts, ExecutionSpecContext, resolve_execution_spec},
12};
13use foundry_evm_hardforks::{FoundryHardfork, TempoHardfork};
14use foundry_evm_networks::NetworkConfigs;
15use foundry_evm_traces::TraceRequirements;
16use revm::state::Bytecode;
17use std::ops::{Deref, DerefMut};
18
19pub struct TracingExecutor<FEN: FoundryEvmNetwork> {
21 executor: Executor<FEN>,
22}
23
24impl<FEN: FoundryEvmNetwork> TracingExecutor<FEN> {
25 pub fn new(
26 env: (EvmEnvFor<FEN>, TxEnvFor<FEN>),
27 fork: CreateFork,
28 version: Option<EvmVersion>,
29 trace_requirements: TraceRequirements,
30 networks: NetworkConfigs,
31 create2_deployer: Address,
32 state_overrides: Option<StateOverride>,
33 ) -> eyre::Result<Self> {
34 let db = Backend::spawn(Some(fork))?;
35 let mut executor = ExecutorBuilder::default()
38 .inspectors(|stack| {
39 stack.trace_requirements(trace_requirements).create2_deployer(create2_deployer)
40 })
41 .spec_id_opt(version.map(evm_spec_id::<SpecFor<FEN>>))
42 .build(env.0, env.1, db, networks);
43
44 if let Some(state_overrides) = state_overrides {
45 apply_state_overrides(&mut executor, state_overrides)?;
46 }
47
48 Ok(Self { executor })
49 }
50
51 pub const fn spec_id(&self) -> SpecFor<FEN> {
53 self.executor.spec_id()
54 }
55
56 pub fn resolve_spec(
58 config: &Config,
59 networks: NetworkConfigs,
60 evm_env: &mut EvmEnvFor<FEN>,
61 evm_version: Option<EvmVersion>,
62 ) -> Option<FoundryHardfork> {
63 Self::resolve_spec_for_chain(
64 config,
65 networks,
66 evm_env.cfg_env.chain_id,
67 None,
68 evm_env,
69 evm_version,
70 )
71 }
72
73 pub fn resolve_spec_for_chain(
75 config: &Config,
76 networks: NetworkConfigs,
77 source_chain_id: ChainId,
78 endpoint_hardfork: Option<FoundryHardfork>,
79 evm_env: &mut EvmEnvFor<FEN>,
80 evm_version: Option<EvmVersion>,
81 ) -> Option<FoundryHardfork> {
82 let explicit_hardfork =
83 evm_version.and_then(|version| network_hardfork_from_evm_version(networks, version));
84 resolve_execution_spec(
85 config,
86 networks,
87 evm_env,
88 ExecutionSpecContext::historical(source_chain_id, endpoint_hardfork),
89 evm_version.map(evm_spec_id::<SpecFor<FEN>>),
90 explicit_hardfork,
91 )
92 }
93
94 pub fn extend_precompile_labels(
96 config: &mut Config,
97 networks: NetworkConfigs,
98 resolved_hardfork: Option<FoundryHardfork>,
99 ) {
100 config.labels.extend(networks.precompiles_label(resolved_hardfork));
101 }
102
103 pub async fn get_fork_material(
105 config: &mut Config,
106 mut evm_opts: EvmOpts,
107 ) -> eyre::Result<(
108 EvmEnvFor<FEN>,
109 TxEnvFor<FEN>,
110 CreateFork,
111 Chain,
112 NetworkConfigs,
113 Option<FoundryHardfork>,
114 )> {
115 evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned());
116 evm_opts.fork_block_number = config.fork_block_number;
117 evm_opts.infer_network_from_fork().await?;
118 let networks = evm_opts.networks;
119 let (evm_env, tx_env, resolved) =
120 evm_opts.env_resolved::<SpecFor<FEN>, BlockEnvFor<FEN>, TxEnvFor<FEN>>().await?;
121 let resolved = resolved.context("fork context is missing for tracing executor")?;
122 let fork = evm_opts
123 .get_fork_resolved(config, evm_env.cfg_env.chain_id, Some(&resolved))
124 .context("fork URL is missing for tracing executor")?;
125 let fork_context = resolved.context();
126
127 let chain = fork_context.source_chain_id.into();
128 Ok((evm_env, tx_env, fork, chain, networks, fork_context.hardfork))
129 }
130}
131
132fn apply_state_overrides<FEN: FoundryEvmNetwork>(
133 executor: &mut Executor<FEN>,
134 state_overrides: StateOverride,
135) -> eyre::Result<()> {
136 for (address, overrides) in state_overrides {
137 if let Some(balance) = overrides.balance {
138 executor.set_balance(address, balance)?;
139 }
140 if let Some(nonce) = overrides.nonce {
141 executor.set_account_nonce(address, nonce)?;
142 }
143 if let Some(code) = overrides.code {
144 let bytecode =
145 Bytecode::new_raw_checked(code).wrap_err("invalid bytecode in state override")?;
146 executor.set_code(address, bytecode)?;
147 }
148 if let Some(state) = overrides.state {
149 let state: HashMap<U256, U256> =
150 state.into_iter().map(|(slot, value)| (slot.into(), value.into())).collect();
151 executor.set_storage(address, state)?;
152 }
153 if let Some(state_diff) = overrides.state_diff {
154 for (slot, value) in state_diff {
155 executor.set_storage_slot(address, slot.into(), value.into())?;
156 }
157 }
158 }
159 Ok(())
160}
161
162fn network_hardfork_from_evm_version(
163 networks: NetworkConfigs,
164 evm_version: EvmVersion,
165) -> Option<FoundryHardfork> {
166 if networks.is_tempo() {
167 return Some(FoundryHardfork::Tempo(evm_spec_id::<TempoHardfork>(evm_version)));
168 }
169 #[cfg(feature = "monad")]
170 if networks.is_monad() {
171 return Some(FoundryHardfork::Monad(evm_spec_id::<foundry_evm_hardforks::MonadHardfork>(
172 evm_version,
173 )));
174 }
175 None
176}
177
178impl<FEN: FoundryEvmNetwork> Deref for TracingExecutor<FEN> {
179 type Target = Executor<FEN>;
180
181 fn deref(&self) -> &Self::Target {
182 &self.executor
183 }
184}
185
186impl<FEN: FoundryEvmNetwork> DerefMut for TracingExecutor<FEN> {
187 fn deref_mut(&mut self) -> &mut Self::Target {
188 &mut self.executor
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use alloy_rpc_types::state::AccountOverride;
196 use foundry_evm_core::{FoundryTransaction, evm::EthEvmNetwork};
197 use revm::context::Transaction;
198
199 #[test]
200 fn state_override_nonce_does_not_modify_transaction_nonce() {
201 let sender = Address::repeat_byte(0x11);
202 let mut tx_env = TxEnvFor::<EthEvmNetwork>::default();
203 tx_env.set_caller(sender);
204 tx_env.set_nonce(7);
205 let backend = Backend::<EthEvmNetwork>::spawn(None).unwrap();
206 let mut evm_env = EvmEnvFor::<EthEvmNetwork>::default();
207 evm_env.cfg_env.disable_nonce_check = true;
208 let mut executor =
209 ExecutorBuilder::default().build(evm_env, tx_env, backend, NetworkConfigs::default());
210 executor.set_gas_limit(1_000_000);
211 executor.set_account_nonce(sender, 7).unwrap();
212
213 let overridden = Address::repeat_byte(0x42);
214 let mut state_overrides = StateOverride::default();
215 state_overrides.insert(sender, AccountOverride { nonce: Some(100), ..Default::default() });
216 state_overrides
217 .insert(overridden, AccountOverride { nonce: Some(200), ..Default::default() });
218
219 apply_state_overrides(&mut executor, state_overrides).unwrap();
220
221 assert_eq!(executor.get_nonce(sender).unwrap(), 100);
222 assert_eq!(executor.get_nonce(overridden).unwrap(), 200);
223 assert_eq!(executor.tx_env().caller(), sender);
224 assert_eq!(executor.tx_env().nonce(), 7);
225
226 let result =
227 executor.transact_raw(sender, overridden, Default::default(), U256::ZERO).unwrap();
228 assert_eq!(result.tx_env.nonce(), 7);
229 }
230}