Skip to main content

foundry_evm/executors/
trace.rs

1use crate::executors::{Executor, ExecutorBuilder};
2use alloy_evm::EvmEnv;
3use alloy_primitives::{Address, U256, map::HashMap};
4use alloy_rpc_types::state::StateOverride;
5use eyre::Context;
6use foundry_compilers::artifacts::EvmVersion;
7use foundry_config::{Chain, Config, utils::evm_spec_id};
8use foundry_evm_core::{backend::Backend, fork::CreateFork, opts::EvmOpts};
9use foundry_evm_networks::NetworkConfigs;
10use foundry_evm_traces::TraceMode;
11use revm::{context::TxEnv, primitives::hardfork::SpecId, state::Bytecode};
12use std::ops::{Deref, DerefMut};
13
14/// A default executor with tracing enabled
15pub struct TracingExecutor {
16    executor: Executor,
17}
18
19impl TracingExecutor {
20    pub fn new(
21        env: (EvmEnv, TxEnv),
22        fork: CreateFork,
23        version: Option<EvmVersion>,
24        trace_mode: TraceMode,
25        networks: NetworkConfigs,
26        create2_deployer: Address,
27        state_overrides: Option<StateOverride>,
28    ) -> eyre::Result<Self> {
29        let db = Backend::spawn(Some(fork))?;
30        // configures a bare version of the evm executor: no cheatcode and log_collector inspector
31        // is enabled, tracing will be enabled only for the targeted transaction
32        let mut executor = ExecutorBuilder::new()
33            .inspectors(|stack| {
34                stack.trace_mode(trace_mode).networks(networks).create2_deployer(create2_deployer)
35            })
36            .spec_id(evm_spec_id(version.unwrap_or_default()))
37            .build(env.0, env.1, db);
38
39        // Apply the state overrides.
40        if let Some(state_overrides) = state_overrides {
41            for (address, overrides) in state_overrides {
42                if let Some(balance) = overrides.balance {
43                    executor.set_balance(address, balance)?;
44                }
45                if let Some(nonce) = overrides.nonce {
46                    executor.set_nonce(address, nonce)?;
47                }
48                if let Some(code) = overrides.code {
49                    let bytecode = Bytecode::new_raw_checked(code)
50                        .wrap_err("invalid bytecode in state override")?;
51                    executor.set_code(address, bytecode)?;
52                }
53                if let Some(state) = overrides.state {
54                    let state: HashMap<U256, U256> = state
55                        .into_iter()
56                        .map(|(slot, value)| (slot.into(), value.into()))
57                        .collect();
58                    executor.set_storage(address, state)?;
59                }
60                if let Some(state_diff) = overrides.state_diff {
61                    for (slot, value) in state_diff {
62                        executor.set_storage_slot(address, slot.into(), value.into())?;
63                    }
64                }
65            }
66        }
67
68        Ok(Self { executor })
69    }
70
71    /// Returns the spec id of the executor
72    pub fn spec_id(&self) -> SpecId {
73        self.executor.spec_id()
74    }
75
76    /// uses the fork block number from the config
77    pub async fn get_fork_material(
78        config: &mut Config,
79        mut evm_opts: EvmOpts,
80    ) -> eyre::Result<(EvmEnv, TxEnv, CreateFork, Chain, NetworkConfigs)> {
81        evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned());
82        evm_opts.fork_block_number = config.fork_block_number;
83
84        let (evm_env, tx_env) = evm_opts.env().await?;
85
86        let fork = evm_opts.get_fork(config, evm_env.clone()).unwrap();
87        let networks = evm_opts.networks.with_chain_id(evm_env.cfg_env.chain_id);
88        config.labels.extend(networks.precompiles_label());
89
90        let chain = tx_env.chain_id.unwrap().into();
91        Ok((evm_env, tx_env, fork, chain, networks))
92    }
93}
94
95impl Deref for TracingExecutor {
96    type Target = Executor;
97
98    fn deref(&self) -> &Self::Target {
99        &self.executor
100    }
101}
102
103impl DerefMut for TracingExecutor {
104    fn deref_mut(&mut self) -> &mut Self::Target {
105        &mut self.executor
106    }
107}