foundry_evm/executors/
trace.rs
1use crate::{
2 Env,
3 executors::{Executor, ExecutorBuilder},
4};
5use alloy_primitives::{Address, U256, map::HashMap};
6use alloy_rpc_types::state::StateOverride;
7use eyre::Context;
8use foundry_compilers::artifacts::EvmVersion;
9use foundry_config::{Chain, Config, utils::evm_spec_id};
10use foundry_evm_core::{backend::Backend, fork::CreateFork, opts::EvmOpts};
11use foundry_evm_traces::TraceMode;
12use revm::{primitives::hardfork::SpecId, state::Bytecode};
13use std::ops::{Deref, DerefMut};
14
15pub struct TracingExecutor {
17 executor: Executor,
18}
19
20impl TracingExecutor {
21 pub fn new(
22 env: Env,
23 fork: Option<CreateFork>,
24 version: Option<EvmVersion>,
25 trace_mode: TraceMode,
26 odyssey: bool,
27 create2_deployer: Address,
28 state_overrides: Option<StateOverride>,
29 ) -> eyre::Result<Self> {
30 let db = Backend::spawn(fork)?;
31 let mut executor = ExecutorBuilder::new()
34 .inspectors(|stack| {
35 stack.trace_mode(trace_mode).odyssey(odyssey).create2_deployer(create2_deployer)
36 })
37 .spec_id(evm_spec_id(version.unwrap_or_default(), odyssey))
38 .build(env, db);
39
40 if let Some(state_overrides) = state_overrides {
42 for (address, overrides) in state_overrides {
43 if let Some(balance) = overrides.balance {
44 executor.set_balance(address, balance)?;
45 }
46 if let Some(nonce) = overrides.nonce {
47 executor.set_nonce(address, nonce)?;
48 }
49 if let Some(code) = overrides.code {
50 let bytecode = Bytecode::new_raw_checked(code)
51 .wrap_err("invalid bytecode in state override")?;
52 executor.set_code(address, bytecode)?;
53 }
54 if let Some(state) = overrides.state {
55 let state: HashMap<U256, U256> = state
56 .into_iter()
57 .map(|(slot, value)| (slot.into(), value.into()))
58 .collect();
59 executor.set_storage(address, state)?;
60 }
61 if let Some(state_diff) = overrides.state_diff {
62 for (slot, value) in state_diff {
63 executor.set_storage_slot(address, slot.into(), value.into())?;
64 }
65 }
66 }
67 }
68
69 Ok(Self { executor })
70 }
71
72 pub fn spec_id(&self) -> SpecId {
74 self.executor.spec_id()
75 }
76
77 pub async fn get_fork_material(
79 config: &Config,
80 mut evm_opts: EvmOpts,
81 ) -> eyre::Result<(Env, Option<CreateFork>, Option<Chain>, bool)> {
82 evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned());
83 evm_opts.fork_block_number = config.fork_block_number;
84
85 let env = evm_opts.evm_env().await?;
86
87 let fork = evm_opts.get_fork(config, env.clone());
88
89 Ok((env, fork, evm_opts.get_remote_chain_id().await, evm_opts.odyssey))
90 }
91}
92
93impl Deref for TracingExecutor {
94 type Target = Executor;
95
96 fn deref(&self) -> &Self::Target {
97 &self.executor
98 }
99}
100
101impl DerefMut for TracingExecutor {
102 fn deref_mut(&mut self) -> &mut Self::Target {
103 &mut self.executor
104 }
105}