foundry_evm/executors/
trace.rs1use crate::executors::{Executor, ExecutorBuilder};
2use alloy_primitives::{Address, U256, map::HashMap};
3use alloy_rpc_types::state::StateOverride;
4use eyre::Context;
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,
12};
13use foundry_evm_hardforks::TempoHardfork;
14use foundry_evm_networks::NetworkConfigs;
15use foundry_evm_traces::TraceRequirements;
16use revm::{context::Transaction, 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
40 .trace_requirements(trace_requirements)
41 .networks(networks)
42 .create2_deployer(create2_deployer)
43 })
44 .spec_id_opt(version.map(evm_spec_id::<SpecFor<FEN>>))
45 .build(env.0, env.1, db);
46
47 if let Some(state_overrides) = state_overrides {
49 for (address, overrides) in state_overrides {
50 if let Some(balance) = overrides.balance {
51 executor.set_balance(address, balance)?;
52 }
53 if let Some(nonce) = overrides.nonce {
54 executor.set_nonce(address, nonce)?;
55 }
56 if let Some(code) = overrides.code {
57 let bytecode = Bytecode::new_raw_checked(code)
58 .wrap_err("invalid bytecode in state override")?;
59 executor.set_code(address, bytecode)?;
60 }
61 if let Some(state) = overrides.state {
62 let state: HashMap<U256, U256> = state
63 .into_iter()
64 .map(|(slot, value)| (slot.into(), value.into()))
65 .collect();
66 executor.set_storage(address, state)?;
67 }
68 if let Some(state_diff) = overrides.state_diff {
69 for (slot, value) in state_diff {
70 executor.set_storage_slot(address, slot.into(), value.into())?;
71 }
72 }
73 }
74 }
75
76 Ok(Self { executor })
77 }
78
79 pub const fn spec_id(&self) -> SpecFor<FEN> {
81 self.executor.spec_id()
82 }
83
84 pub async fn get_fork_material(
86 config: &mut Config,
87 mut evm_opts: EvmOpts,
88 ) -> eyre::Result<(EvmEnvFor<FEN>, TxEnvFor<FEN>, CreateFork, Chain, NetworkConfigs)> {
89 evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned());
90 evm_opts.fork_block_number = config.fork_block_number;
91
92 let (evm_env, tx_env, fork_block) =
93 evm_opts.env::<SpecFor<FEN>, BlockEnvFor<FEN>, TxEnvFor<FEN>>().await?;
94
95 let fork = evm_opts.get_fork(config, evm_env.cfg_env.chain_id, fork_block).unwrap();
96 let networks = evm_opts.networks.with_chain_id(evm_env.cfg_env.chain_id);
97 config
98 .labels
99 .extend(networks.precompiles_label(Some(config.evm_spec_id::<TempoHardfork>())));
100
101 let chain = tx_env.chain_id().unwrap().into();
102 Ok((evm_env, tx_env, fork, chain, networks))
103 }
104}
105
106impl<FEN: FoundryEvmNetwork> Deref for TracingExecutor<FEN> {
107 type Target = Executor<FEN>;
108
109 fn deref(&self) -> &Self::Target {
110 &self.executor
111 }
112}
113
114impl<FEN: FoundryEvmNetwork> DerefMut for TracingExecutor<FEN> {
115 fn deref_mut(&mut self) -> &mut Self::Target {
116 &mut self.executor
117 }
118}