Skip to main content

foundry_evm/inspectors/
stack.rs

1use super::{
2    Cheatcodes, CheatsConfig, ChiselState, CustomPrintTracer, Fuzzer, LineCoverageCollector,
3    LogCollector, RevertDiagnostic, ScriptExecutionInspector, TempoLabels, TracingInspector,
4};
5use alloy_primitives::{
6    Address, B256, Bytes, Log, TxKind, U256,
7    map::{AddressHashMap, AddressMap},
8};
9
10use foundry_cheatcodes::{CheatcodeAnalysis, CheatcodesExecutor, NestedEvmClosure, Wallets};
11use foundry_common::compile::Analysis;
12use foundry_evm_core::{
13    FoundryBlock, FoundryTransaction, InspectorExt,
14    backend::{DatabaseError, DatabaseExt, JournaledState},
15    env::FoundryContextExt,
16    evm::{
17        BlockEnvFor, EthEvmNetwork, EvmEnvFor, FoundryContextFor, FoundryEvmFactory,
18        FoundryEvmNetwork, IntoNestedEvm, NestedEvm, SpecFor, TxEnvFor, with_cloned_context,
19    },
20};
21use foundry_evm_coverage::HitMaps;
22use foundry_evm_networks::NetworkConfigs;
23use foundry_evm_traces::{SparsedTraceArena, TraceMode};
24use revm::{
25    Inspector,
26    context::{
27        Block, Cfg, ContextTr, JournalTr, Transaction,
28        result::{EVMError, ExecutionResult, Output},
29    },
30    context_interface::CreateScheme,
31    inspector::JournalExt,
32    interpreter::{
33        CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult,
34        Interpreter, InterpreterResult,
35    },
36    state::{Account, AccountStatus},
37};
38use revm_inspectors::edge_cov::EdgeCovInspector;
39use std::{
40    ops::{Deref, DerefMut},
41    sync::Arc,
42};
43
44#[derive(Clone, Debug)]
45#[must_use = "builders do nothing unless you call `build` on them"]
46pub struct InspectorStackBuilder<BLOCK: Clone> {
47    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities.
48    pub analysis: Option<Analysis>,
49    /// The block environment.
50    ///
51    /// Used in the cheatcode handler to overwrite the block environment separately from the
52    /// execution block environment.
53    pub block: Option<BLOCK>,
54    /// The gas price.
55    ///
56    /// Used in the cheatcode handler to overwrite the gas price separately from the gas price
57    /// in the execution environment.
58    pub gas_price: Option<u128>,
59    /// The cheatcodes config.
60    pub cheatcodes: Option<Arc<CheatsConfig>>,
61    /// The fuzzer inspector and its state, if it exists.
62    pub fuzzer: Option<Fuzzer>,
63    /// Whether to enable tracing and revert diagnostics.
64    pub trace_mode: TraceMode,
65    /// Whether logs should be collected.
66    /// - None for no log collection.
67    /// - Some(true) for realtime console.log-ing.
68    /// - Some(false) for log collection.
69    pub logs: Option<bool>,
70    /// Whether line coverage info should be collected.
71    pub line_coverage: Option<bool>,
72    /// Whether to print all opcode traces into the console. Useful for debugging the EVM.
73    pub print: Option<bool>,
74    /// The chisel state inspector.
75    pub chisel_state: Option<usize>,
76    /// Whether to enable call isolation.
77    /// In isolation mode all top-level calls are executed as a separate transaction in a separate
78    /// EVM context, enabling more precise gas accounting and transaction state changes.
79    pub enable_isolation: bool,
80    /// Networks with enabled features.
81    pub networks: NetworkConfigs,
82    /// The wallets to set in the cheatcodes context.
83    pub wallets: Option<Wallets>,
84    /// The CREATE2 deployer address.
85    pub create2_deployer: Address,
86}
87
88impl<BLOCK: Clone> Default for InspectorStackBuilder<BLOCK> {
89    fn default() -> Self {
90        Self {
91            analysis: None,
92            block: None,
93            gas_price: None,
94            cheatcodes: None,
95            fuzzer: None,
96            trace_mode: TraceMode::None,
97            logs: None,
98            line_coverage: None,
99            print: None,
100            chisel_state: None,
101            enable_isolation: false,
102            networks: NetworkConfigs::default(),
103            wallets: None,
104            create2_deployer: Default::default(),
105        }
106    }
107}
108
109impl<BLOCK: Clone> InspectorStackBuilder<BLOCK> {
110    /// Create a new inspector stack builder.
111    #[inline]
112    pub fn new() -> Self {
113        Self::default()
114    }
115
116    /// Set the solar compiler instance that grants syntactic and semantic analysis capabilities
117    #[inline]
118    pub fn set_analysis(mut self, analysis: Analysis) -> Self {
119        self.analysis = Some(analysis);
120        self
121    }
122
123    /// Set the block environment.
124    #[inline]
125    pub fn block(mut self, block: BLOCK) -> Self {
126        self.block = Some(block);
127        self
128    }
129
130    /// Set the gas price.
131    #[inline]
132    pub fn gas_price(mut self, gas_price: u128) -> Self {
133        self.gas_price = Some(gas_price);
134        self
135    }
136
137    /// Enable cheatcodes with the given config.
138    #[inline]
139    pub fn cheatcodes(mut self, config: Arc<CheatsConfig>) -> Self {
140        self.cheatcodes = Some(config);
141        self
142    }
143
144    /// Set the wallets.
145    #[inline]
146    pub fn wallets(mut self, wallets: Wallets) -> Self {
147        self.wallets = Some(wallets);
148        self
149    }
150
151    /// Set the fuzzer inspector.
152    #[inline]
153    pub fn fuzzer(mut self, fuzzer: Fuzzer) -> Self {
154        self.fuzzer = Some(fuzzer);
155        self
156    }
157
158    /// Set the Chisel inspector.
159    #[inline]
160    pub fn chisel_state(mut self, final_pc: usize) -> Self {
161        self.chisel_state = Some(final_pc);
162        self
163    }
164
165    /// Set the log collector, and whether to print the logs directly to stdout.
166    #[inline]
167    pub fn logs(mut self, live_logs: bool) -> Self {
168        self.logs = Some(live_logs);
169        self
170    }
171
172    /// Set whether to collect line coverage information.
173    #[inline]
174    pub fn line_coverage(mut self, yes: bool) -> Self {
175        self.line_coverage = Some(yes);
176        self
177    }
178
179    /// Set whether to enable the trace printer.
180    #[inline]
181    pub fn print(mut self, yes: bool) -> Self {
182        self.print = Some(yes);
183        self
184    }
185
186    /// Set whether to enable the tracer.
187    /// Revert diagnostic inspector is activated when `mode != TraceMode::None`
188    #[inline]
189    pub fn trace_mode(mut self, mode: TraceMode) -> Self {
190        if self.trace_mode < mode {
191            self.trace_mode = mode
192        }
193        self
194    }
195
196    /// Set whether to enable the call isolation.
197    /// For description of call isolation, see [`InspectorStack::enable_isolation`].
198    #[inline]
199    pub fn enable_isolation(mut self, yes: bool) -> Self {
200        self.enable_isolation = yes;
201        self
202    }
203
204    /// Set networks with enabled features.
205    #[inline]
206    pub fn networks(mut self, networks: NetworkConfigs) -> Self {
207        self.networks = networks;
208        self
209    }
210
211    #[inline]
212    pub fn create2_deployer(mut self, create2_deployer: Address) -> Self {
213        self.create2_deployer = create2_deployer;
214        self
215    }
216
217    /// Builds the stack of inspectors to use when transacting/committing on the EVM.
218    pub fn build<FEN: FoundryEvmNetwork<EvmFactory: FoundryEvmFactory<BlockEnv = BLOCK>>>(
219        self,
220    ) -> InspectorStack<FEN> {
221        let Self {
222            analysis,
223            block,
224            gas_price,
225            cheatcodes,
226            fuzzer,
227            trace_mode,
228            logs,
229            line_coverage,
230            print,
231            chisel_state,
232            enable_isolation,
233            networks,
234            wallets,
235            create2_deployer,
236        } = self;
237        let mut stack = InspectorStack::new();
238
239        // inspectors
240        if let Some(config) = cheatcodes {
241            let mut cheatcodes = Cheatcodes::new(config);
242            // Set analysis capabilities if they are provided
243            if let Some(analysis) = analysis {
244                stack.set_analysis(analysis.clone());
245                cheatcodes.set_analysis(CheatcodeAnalysis::new(analysis));
246            }
247            // Set wallets if they are provided
248            if let Some(wallets) = wallets {
249                cheatcodes.set_wallets(wallets);
250            }
251            stack.set_cheatcodes(cheatcodes);
252        }
253
254        if let Some(fuzzer) = fuzzer {
255            stack.set_fuzzer(fuzzer);
256        }
257        if let Some(chisel_state) = chisel_state {
258            stack.set_chisel(chisel_state);
259        }
260        stack.collect_line_coverage(line_coverage.unwrap_or(false));
261        stack.collect_logs(logs);
262        stack.print(print.unwrap_or(false));
263        stack.tracing(trace_mode);
264
265        stack.enable_isolation(enable_isolation);
266        stack.networks(networks);
267        stack.set_create2_deployer(create2_deployer);
268
269        if networks.is_tempo() {
270            stack.inner.tempo_labels = Some(Box::default());
271        }
272
273        // environment, must come after all of the inspectors
274        if let Some(block) = block {
275            stack.set_block(block);
276        }
277        if let Some(gas_price) = gas_price {
278            stack.set_gas_price(gas_price);
279        }
280
281        stack
282    }
283}
284
285/// Helper macro to call the same method on multiple inspectors without resorting to dynamic
286/// dispatch.
287#[macro_export]
288macro_rules! call_inspectors {
289    ([$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {
290        $(
291            if let Some($id) = $inspector {
292                $crate::utils::cold_path();
293                $body;
294            }
295        )+
296    };
297    (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {{
298        $(
299            if let Some($id) = $inspector {
300                $crate::utils::cold_path();
301                if let Some(result) = $body {
302                    return result;
303                }
304            }
305        )+
306    }};
307}
308
309/// The collected results of [`InspectorStack`].
310pub struct InspectorData<FEN: FoundryEvmNetwork> {
311    pub logs: Vec<Log>,
312    pub labels: AddressHashMap<String>,
313    pub traces: Option<SparsedTraceArena>,
314    pub line_coverage: Option<HitMaps>,
315    pub edge_coverage: Option<Vec<u8>>,
316    pub cheatcodes: Option<Box<Cheatcodes<FEN>>>,
317    pub chisel_state: Option<(Vec<U256>, Vec<u8>)>,
318    pub reverter: Option<Address>,
319}
320
321/// Contains data about the state of outer/main EVM which created and invoked the inner EVM context.
322/// Used to adjust EVM state while in inner context.
323///
324/// We need this to avoid breaking changes due to EVM behavior differences in isolated vs
325/// non-isolated mode. For descriptions and workarounds for those changes see: <https://github.com/foundry-rs/foundry/pull/7186#issuecomment-1959102195>
326#[derive(Debug, Clone)]
327pub struct InnerContextData {
328    /// Origin of the transaction in the outer EVM context.
329    original_origin: Address,
330}
331
332/// An inspector that calls multiple inspectors in sequence.
333///
334/// If a call to an inspector returns a value (indicating a stop or revert) the remaining inspectors
335/// are not called.
336///
337/// Stack is divided into [Cheatcodes] and `InspectorStackInner`. This is done to allow assembling
338/// `InspectorStackRefMut` inside [Cheatcodes] to allow usage of it as [revm::Inspector]. This gives
339/// us ability to create and execute separate EVM frames from inside cheatcodes while still having
340/// access to entire stack of inspectors and correctly handling traces, logs, debugging info
341/// collection, etc.
342#[derive(Clone, Debug)]
343pub struct InspectorStack<FEN: FoundryEvmNetwork = EthEvmNetwork> {
344    #[allow(clippy::type_complexity)]
345    pub cheatcodes: Option<Box<Cheatcodes<FEN>>>,
346    pub inner: InspectorStackInner,
347}
348
349/// All used inpectors besides [Cheatcodes].
350///
351/// See [`InspectorStack`].
352#[derive(Default, Clone, Debug)]
353pub struct InspectorStackInner {
354    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities.
355    pub analysis: Option<Analysis>,
356
357    // Inspectors.
358    // These are boxed to reduce the size of the struct and slightly improve performance of the
359    // `if let Some` checks.
360    pub chisel_state: Option<Box<ChiselState>>,
361    pub edge_coverage: Option<Box<EdgeCovInspector>>,
362    pub fuzzer: Option<Box<Fuzzer>>,
363    pub line_coverage: Option<Box<LineCoverageCollector>>,
364    pub log_collector: Option<Box<LogCollector>>,
365    pub printer: Option<Box<CustomPrintTracer>>,
366    pub revert_diag: Option<Box<RevertDiagnostic>>,
367    pub script_execution_inspector: Option<Box<ScriptExecutionInspector>>,
368    pub tempo_labels: Option<Box<TempoLabels>>,
369    pub tracer: Option<Box<TracingInspector>>,
370
371    // FoundryInspectorExt and other internal data.
372    pub enable_isolation: bool,
373    pub networks: NetworkConfigs,
374    pub create2_deployer: Address,
375    /// Flag marking if we are in the inner EVM context.
376    pub in_inner_context: bool,
377    pub inner_context_data: Option<InnerContextData>,
378    pub top_frame_journal: AddressMap<Account>,
379    /// Address that reverted the call, if any.
380    pub reverter: Option<Address>,
381}
382
383/// Struct keeping mutable references to both parts of [InspectorStack] and implementing
384/// [revm::Inspector]. This struct can be obtained via [InspectorStack::as_mut].
385pub struct InspectorStackRefMut<'a, FEN: FoundryEvmNetwork = EthEvmNetwork> {
386    pub cheatcodes: Option<&'a mut Cheatcodes<FEN>>,
387    pub inner: &'a mut InspectorStackInner,
388}
389
390impl<FEN: FoundryEvmNetwork> CheatcodesExecutor<FEN> for InspectorStackInner {
391    fn with_nested_evm(
392        &mut self,
393        cheats: &mut Cheatcodes<FEN>,
394        ecx: &mut FoundryContextFor<'_, FEN>,
395        f: NestedEvmClosure<'_, SpecFor<FEN>, BlockEnvFor<FEN>, TxEnvFor<FEN>>,
396    ) -> Result<(), EVMError<DatabaseError>> {
397        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };
398        with_cloned_context(ecx, |db, evm_env, journal_inner| {
399            let mut evm = FEN::EvmFactory::default()
400                .create_foundry_evm_with_inspector(db, evm_env, &mut inspector)
401                .into_nested_evm();
402            *evm.journal_inner_mut() = journal_inner;
403            f(&mut evm)?;
404            let sub_inner = evm.journal_inner_mut().clone();
405            let sub_evm_env = evm.to_evm_env();
406            Ok((sub_evm_env, sub_inner))
407        })
408    }
409
410    fn with_fresh_nested_evm(
411        &mut self,
412        cheats: &mut Cheatcodes<FEN>,
413        db: &mut <FoundryContextFor<'_, FEN> as ContextTr>::Db,
414        evm_env: EvmEnvFor<FEN>,
415        f: NestedEvmClosure<'_, SpecFor<FEN>, BlockEnvFor<FEN>, TxEnvFor<FEN>>,
416    ) -> Result<EvmEnvFor<FEN>, EVMError<DatabaseError>> {
417        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };
418        let mut evm = FEN::EvmFactory::default()
419            .create_foundry_evm_with_inspector(db, evm_env, &mut inspector)
420            .into_nested_evm();
421        f(&mut evm)?;
422        Ok(evm.to_evm_env())
423    }
424
425    fn transact_on_db(
426        &mut self,
427        cheats: &mut Cheatcodes<FEN>,
428        ecx: &mut FoundryContextFor<'_, FEN>,
429        fork_id: Option<U256>,
430        transaction: B256,
431    ) -> eyre::Result<()> {
432        let evm_env = ecx.evm_clone();
433        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };
434        let (db, inner) = ecx.db_journal_inner_mut();
435        db.transact(fork_id, transaction, evm_env, inner, &mut inspector)
436    }
437
438    fn transact_from_tx_on_db(
439        &mut self,
440        cheats: &mut Cheatcodes<FEN>,
441        ecx: &mut FoundryContextFor<'_, FEN>,
442        tx_env: TxEnvFor<FEN>,
443    ) -> eyre::Result<()> {
444        let evm_env = ecx.evm_clone();
445        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };
446        let (db, inner) = ecx.db_journal_inner_mut();
447        db.transact_from_tx(tx_env, evm_env, inner, &mut inspector)
448    }
449
450    fn console_log(&mut self, msg: &str) {
451        if let Some(ref mut collector) = self.log_collector {
452            InspectorExt::console_log(&mut **collector, msg);
453        }
454    }
455
456    fn tracing_inspector(&mut self) -> Option<&mut TracingInspector> {
457        self.tracer.as_deref_mut()
458    }
459
460    fn set_in_inner_context(&mut self, enabled: bool, original_origin: Option<Address>) {
461        self.in_inner_context = enabled;
462        self.inner_context_data = enabled.then(|| InnerContextData {
463            original_origin: original_origin.expect("origin required when enabling inner ctx"),
464        });
465    }
466}
467
468impl<FEN: FoundryEvmNetwork> Default for InspectorStack<FEN> {
469    fn default() -> Self {
470        Self::new()
471    }
472}
473
474impl<FEN: FoundryEvmNetwork> InspectorStack<FEN> {
475    /// Creates a new inspector stack.
476    ///
477    /// Note that the stack is empty by default, and you must add inspectors to it.
478    /// This is done by calling the `set_*` methods on the stack directly, or by building the stack
479    /// with [`InspectorStack`].
480    #[inline]
481    pub fn new() -> Self {
482        Self { cheatcodes: None, inner: InspectorStackInner::default() }
483    }
484
485    /// Set the solar compiler instance.
486    #[inline]
487    pub fn set_analysis(&mut self, analysis: Analysis) {
488        self.analysis = Some(analysis);
489    }
490
491    /// Sets the block for the relevant inspectors.
492    #[inline]
493    pub fn set_block(&mut self, block: BlockEnvFor<FEN>) {
494        if let Some(cheatcodes) = &mut self.cheatcodes {
495            cheatcodes.block = Some(block);
496        }
497    }
498
499    /// Sets the gas price for the relevant inspectors.
500    #[inline]
501    pub fn set_gas_price(&mut self, gas_price: u128) {
502        if let Some(cheatcodes) = &mut self.cheatcodes {
503            cheatcodes.gas_price = Some(gas_price);
504        }
505    }
506
507    /// Set the cheatcodes inspector.
508    #[inline]
509    pub fn set_cheatcodes(&mut self, cheatcodes: Cheatcodes<FEN>) {
510        self.cheatcodes = Some(cheatcodes.into());
511    }
512
513    /// Set the fuzzer inspector.
514    #[inline]
515    pub fn set_fuzzer(&mut self, fuzzer: Fuzzer) {
516        self.fuzzer = Some(fuzzer.into());
517    }
518
519    /// Set the Chisel inspector.
520    #[inline]
521    pub fn set_chisel(&mut self, final_pc: usize) {
522        self.chisel_state = Some(ChiselState::new(final_pc).into());
523    }
524
525    /// Set whether to enable the line coverage collector.
526    #[inline]
527    pub fn collect_line_coverage(&mut self, yes: bool) {
528        self.line_coverage = yes.then(Default::default);
529    }
530
531    /// Set whether to enable the edge coverage collector.
532    #[inline]
533    pub fn collect_edge_coverage(&mut self, yes: bool) {
534        // TODO: configurable edge size?
535        self.edge_coverage = yes.then(EdgeCovInspector::new).map(Into::into);
536    }
537
538    /// Set whether to enable call isolation.
539    #[inline]
540    pub fn enable_isolation(&mut self, yes: bool) {
541        self.inner.enable_isolation = yes;
542    }
543
544    /// Set networks with enabled features.
545    #[inline]
546    pub fn networks(&mut self, networks: NetworkConfigs) {
547        self.inner.networks = networks;
548    }
549
550    /// Set the CREATE2 deployer address.
551    #[inline]
552    pub fn set_create2_deployer(&mut self, deployer: Address) {
553        self.create2_deployer = deployer;
554    }
555
556    /// Set whether to enable the log collector.
557    /// - None for no log collection.
558    /// - Some(true) for realtime console.log-ing.
559    /// - Some(false) for log collection.
560    #[inline]
561    pub fn collect_logs(&mut self, live_logs: Option<bool>) {
562        self.log_collector = live_logs.map(|live_logs| {
563            Box::new(if live_logs {
564                LogCollector::LiveLogs
565            } else {
566                LogCollector::Capture { logs: Vec::new() }
567            })
568        });
569    }
570
571    /// Set whether to enable the trace printer.
572    #[inline]
573    pub fn print(&mut self, yes: bool) {
574        self.printer = yes.then(Default::default);
575    }
576
577    /// Set whether to enable the tracer.
578    /// Revert diagnostic inspector is activated when `mode != TraceMode::None`
579    #[inline]
580    pub fn tracing(&mut self, mode: TraceMode) {
581        self.revert_diag = (!mode.is_none()).then(RevertDiagnostic::default).map(Into::into);
582
583        if let Some(config) = mode.into_config() {
584            *self.tracer.get_or_insert_with(Default::default).config_mut() = config;
585        } else {
586            self.tracer = None;
587        }
588    }
589
590    /// Set whether to enable script execution inspector.
591    #[inline]
592    pub fn script(&mut self, script_address: Address) {
593        self.script_execution_inspector.get_or_insert_with(Default::default).script_address =
594            script_address;
595    }
596
597    #[inline(always)]
598    fn as_mut(&mut self) -> InspectorStackRefMut<'_, FEN> {
599        InspectorStackRefMut { cheatcodes: self.cheatcodes.as_deref_mut(), inner: &mut self.inner }
600    }
601
602    /// Collects all the data gathered during inspection into a single struct.
603    pub fn collect(self) -> InspectorData<FEN> {
604        let Self {
605            mut cheatcodes,
606            inner:
607                InspectorStackInner {
608                    chisel_state,
609                    line_coverage,
610                    edge_coverage,
611                    log_collector,
612                    tempo_labels,
613                    tracer,
614                    reverter,
615                    ..
616                },
617        } = self;
618
619        let traces = tracer.map(|tracer| tracer.into_traces()).map(|arena| {
620            let ignored = cheatcodes
621                .as_mut()
622                .map(|cheatcodes| {
623                    let mut ignored = std::mem::take(&mut cheatcodes.ignored_traces.ignored);
624
625                    // If the last pause call was not resumed, ignore the rest of the trace
626                    if let Some(last_pause_call) = cheatcodes.ignored_traces.last_pause_call {
627                        ignored.insert(last_pause_call, (arena.nodes().len(), 0));
628                    }
629
630                    ignored
631                })
632                .unwrap_or_default();
633
634            SparsedTraceArena { arena, ignored }
635        });
636
637        InspectorData {
638            logs: log_collector.and_then(|logs| logs.into_captured_logs()).unwrap_or_default(),
639            labels: {
640                let mut labels = cheatcodes.as_ref().map(|c| c.labels.clone()).unwrap_or_default();
641                if let Some(tempo_labels) = tempo_labels {
642                    labels.extend(tempo_labels.labels);
643                }
644                labels
645            },
646            traces,
647            line_coverage: line_coverage.map(|line_coverage| line_coverage.finish()),
648            edge_coverage: edge_coverage.map(|edge_coverage| edge_coverage.into_hitcount()),
649            cheatcodes,
650            chisel_state: chisel_state.and_then(|state| state.state),
651            reverter,
652        }
653    }
654}
655
656impl<FEN: FoundryEvmNetwork> InspectorStackRefMut<'_, FEN> {
657    /// Adjusts the EVM data for the inner EVM context.
658    /// Should be called on the top-level call of inner context (depth == 0 &&
659    /// self.in_inner_context) Decreases sender nonce for CALLs to keep backwards compatibility
660    /// Updates tx.origin to the value before entering inner context
661    fn adjust_evm_data_for_inner_context<CTX: FoundryContextExt>(&mut self, ecx: &mut CTX) {
662        let inner_context_data =
663            self.inner_context_data.as_ref().expect("should be called in inner context");
664        ecx.tx_mut().set_caller(inner_context_data.original_origin);
665    }
666
667    fn do_call_end(
668        &mut self,
669        ecx: &mut FoundryContextFor<'_, FEN>,
670        inputs: &CallInputs,
671        outcome: &mut CallOutcome,
672    ) {
673        let result = outcome.result.result;
674        call_inspectors!(
675            #[ret]
676            [
677                &mut self.fuzzer,
678                &mut self.tracer,
679                &mut self.cheatcodes,
680                &mut self.printer,
681                &mut self.revert_diag
682            ],
683            |inspector| {
684                let previous_outcome = outcome.clone();
685                inspector.call_end(ecx, inputs, outcome);
686
687                // If the inspector returns a different status or a revert with a non-empty message,
688                // we assume it wants to tell us something
689                let different = outcome.result.result != result
690                    || (outcome.result.result == InstructionResult::Revert
691                        && outcome.output() != previous_outcome.output());
692                different.then_some(())
693            },
694        );
695
696        // Record first address that reverted the call.
697        if result.is_revert() && self.reverter.is_none() {
698            self.reverter = Some(inputs.target_address);
699        }
700    }
701
702    fn do_create_end(
703        &mut self,
704        ecx: &mut FoundryContextFor<'_, FEN>,
705        call: &CreateInputs,
706        outcome: &mut CreateOutcome,
707    ) {
708        let result = outcome.result.result;
709        call_inspectors!(
710            #[ret]
711            [&mut self.tracer, &mut self.cheatcodes, &mut self.printer],
712            |inspector| {
713                let previous_outcome = outcome.clone();
714                inspector.create_end(ecx, call, outcome);
715
716                // If the inspector returns a different status or a revert with a non-empty message,
717                // we assume it wants to tell us something
718                let different = outcome.result.result != result
719                    || (outcome.result.result == InstructionResult::Revert
720                        && outcome.output() != previous_outcome.output());
721                different.then_some(())
722            },
723        );
724    }
725
726    fn transact_inner(
727        &mut self,
728        ecx: &mut FoundryContextFor<'_, FEN>,
729        kind: TxKind,
730        caller: Address,
731        input: Bytes,
732        gas_limit: u64,
733        value: U256,
734    ) -> (InterpreterResult, Option<Address>) {
735        let cached_evm_env = ecx.evm_clone();
736        let cached_tx_env = ecx.tx_clone();
737
738        ecx.block_mut().set_basefee(0);
739
740        let chain_id = ecx.cfg().chain_id();
741        ecx.tx_mut().set_chain_id(Some(chain_id));
742        ecx.tx_mut().set_caller(caller);
743        ecx.tx_mut().set_kind(kind);
744        ecx.tx_mut().set_data(input);
745        ecx.tx_mut().set_value(value);
746        // Add 21000 to the gas limit to account for the base cost of transaction.
747        ecx.tx_mut().set_gas_limit(gas_limit + 21000);
748
749        // If we haven't disabled gas limit checks, ensure that transaction gas limit will not
750        // exceed block gas limit.
751        if !ecx.cfg().is_block_gas_limit_disabled() {
752            let gas_limit = std::cmp::min(ecx.tx().gas_limit(), ecx.block().gas_limit());
753            ecx.tx_mut().set_gas_limit(gas_limit);
754        }
755        ecx.tx_mut().set_gas_price(0);
756
757        self.inner_context_data =
758            Some(InnerContextData { original_origin: cached_tx_env.caller() });
759        self.in_inner_context = true;
760
761        let evm_env = ecx.evm_clone();
762        let tx_env = ecx.tx_clone();
763
764        let res = self.with_inspector(|mut inspector| {
765            let (res, nested_env) = {
766                let (db, journal) = ecx.db_journal_inner_mut();
767                let mut evm = FEN::EvmFactory::default()
768                    .create_foundry_evm_with_inspector(db, evm_env, &mut inspector)
769                    .into_nested_evm();
770
771                evm.journal_inner_mut().state = {
772                    let mut state = journal.state.clone();
773
774                    for (addr, acc_mut) in &mut state {
775                        // mark all accounts cold, besides preloaded addresses
776                        if journal.warm_addresses.is_cold(addr) {
777                            acc_mut.mark_cold();
778                        }
779
780                        // mark all slots cold
781                        for slot_mut in acc_mut.storage.values_mut() {
782                            slot_mut.is_cold = true;
783                            slot_mut.original_value = slot_mut.present_value;
784                        }
785                    }
786
787                    state
788                };
789
790                // set depth to 1 to make sure traces are collected correctly
791                evm.journal_inner_mut().depth = 1;
792
793                let res = evm.transact_raw(tx_env);
794                let nested_evm_env = evm.to_evm_env();
795                (res, nested_evm_env)
796            };
797
798            // Restore env, preserving cheatcode cfg/block changes from the nested EVM
799            // but restoring the original tx and basefee (which we zeroed for the nested call).
800            let mut restored_evm_env = nested_env;
801            restored_evm_env.block_env.set_basefee(cached_evm_env.block_env.basefee());
802            ecx.set_evm(restored_evm_env);
803            ecx.set_tx(cached_tx_env);
804
805            res
806        });
807
808        self.in_inner_context = false;
809        self.inner_context_data = None;
810
811        let mut gas = Gas::new(gas_limit);
812
813        let Ok(res) = res else {
814            // Should we match, encode and propagate error as a revert reason?
815            let result =
816                InterpreterResult { result: InstructionResult::Revert, output: Bytes::new(), gas };
817            return (result, None);
818        };
819
820        for (addr, mut acc) in res.state {
821            let Some(acc_mut) = ecx.journal_mut().evm_state_mut().get_mut(&addr) else {
822                ecx.journal_mut().evm_state_mut().insert(addr, acc);
823                continue;
824            };
825
826            // make sure accounts that were warmed earlier do not become cold
827            if acc.status.contains(AccountStatus::Cold)
828                && !acc_mut.status.contains(AccountStatus::Cold)
829            {
830                acc.status -= AccountStatus::Cold;
831            }
832            acc_mut.info = acc.info;
833            acc_mut.status |= acc.status;
834
835            for (key, val) in acc.storage {
836                let Some(slot_mut) = acc_mut.storage.get_mut(&key) else {
837                    acc_mut.storage.insert(key, val);
838                    continue;
839                };
840                slot_mut.present_value = val.present_value;
841                slot_mut.is_cold &= val.is_cold;
842            }
843        }
844
845        let (result, address, output) = match res.result {
846            ExecutionResult::Success { reason, gas: result_gas, logs: _, output } => {
847                gas.set_refund(result_gas.final_refunded() as i64);
848                let _ = gas.record_cost(result_gas.used());
849                let address = match output {
850                    Output::Create(_, address) => address,
851                    Output::Call(_) => None,
852                };
853                (reason.into(), address, output.into_data())
854            }
855            ExecutionResult::Halt { reason, gas: result_gas, .. } => {
856                let _ = gas.record_cost(result_gas.used());
857                (InstructionResult::from(reason), None, Bytes::new())
858            }
859            ExecutionResult::Revert { gas: result_gas, output, .. } => {
860                let _ = gas.record_cost(result_gas.used());
861                (InstructionResult::Revert, None, output)
862            }
863        };
864        (InterpreterResult { result, output, gas }, address)
865    }
866
867    /// Moves out of references, constructs a new [`InspectorStackRefMut`] and runs the given
868    /// closure with it.
869    fn with_inspector<O>(&mut self, f: impl FnOnce(InspectorStackRefMut<'_, FEN>) -> O) -> O {
870        let mut cheatcodes = self
871            .cheatcodes
872            .as_deref_mut()
873            .map(|cheats| core::mem::replace(cheats, Cheatcodes::new(cheats.config.clone())));
874        let mut inner = std::mem::take(self.inner);
875
876        let out = f(InspectorStackRefMut { cheatcodes: cheatcodes.as_mut(), inner: &mut inner });
877
878        if let Some(cheats) = self.cheatcodes.as_deref_mut() {
879            *cheats = cheatcodes.unwrap();
880        }
881
882        *self.inner = inner;
883
884        out
885    }
886
887    /// Invoked at the beginning of a new top-level (0 depth) frame.
888    fn top_level_frame_start(&mut self, ecx: &mut FoundryContextFor<'_, FEN>) {
889        if self.enable_isolation {
890            // If we're in isolation mode, we need to keep track of the state at the beginning of
891            // the frame to be able to roll back on revert
892            self.top_frame_journal.clone_from(ecx.journal().evm_state());
893        }
894    }
895
896    /// Invoked at the end of root frame.
897    fn top_level_frame_end(
898        &mut self,
899        ecx: &mut FoundryContextFor<'_, FEN>,
900        result: InstructionResult,
901    ) {
902        if !result.is_revert() {
903            return;
904        }
905        // Encountered a revert, since cheatcodes may have altered the evm state in such a way
906        // that violates some constraints, e.g. `deal`, we need to manually roll back on revert
907        // before revm reverts the state itself
908        if let Some(cheats) = self.cheatcodes.as_mut() {
909            cheats.on_revert(ecx);
910        }
911
912        // If we're in isolation mode, we need to rollback to state before the root frame was
913        // created We can't rely on revm's journal because it doesn't account for changes
914        // made by isolated calls
915        if self.enable_isolation {
916            *ecx.journal_mut().evm_state_mut() = std::mem::take(&mut self.top_frame_journal);
917        }
918    }
919
920    // We take extra care in optimizing `step` and `step_end`, as they're are likely the most
921    // hot functions in all of Foundry.
922    // We want to `#[inline(always)]` these functions so that `InspectorStack` does not
923    // delegate to `InspectorStackRefMut` in this case.
924
925    #[inline(always)]
926    fn step_inlined(
927        &mut self,
928        interpreter: &mut Interpreter,
929        ecx: &mut FoundryContextFor<'_, FEN>,
930    ) {
931        call_inspectors!(
932            [
933                // These are sorted in definition order.
934                &mut self.edge_coverage,
935                &mut self.fuzzer,
936                &mut self.line_coverage,
937                &mut self.printer,
938                &mut self.revert_diag,
939                &mut self.script_execution_inspector,
940                &mut self.tracer,
941                // Keep `cheatcodes` last to make use of the tail call.
942                &mut self.cheatcodes,
943            ],
944            |inspector| (**inspector).step(interpreter, ecx),
945        );
946    }
947
948    #[inline(always)]
949    fn step_end_inlined(
950        &mut self,
951        interpreter: &mut Interpreter,
952        ecx: &mut FoundryContextFor<'_, FEN>,
953    ) {
954        call_inspectors!(
955            [
956                // These are sorted in definition order.
957                &mut self.chisel_state,
958                &mut self.printer,
959                &mut self.revert_diag,
960                &mut self.tracer,
961                // Keep `cheatcodes` last to make use of the tail call.
962                &mut self.cheatcodes,
963            ],
964            |inspector| (**inspector).step_end(interpreter, ecx),
965        );
966    }
967}
968
969impl<FEN: FoundryEvmNetwork> Inspector<FoundryContextFor<'_, FEN>>
970    for InspectorStackRefMut<'_, FEN>
971{
972    fn initialize_interp(
973        &mut self,
974        interpreter: &mut Interpreter,
975        ecx: &mut FoundryContextFor<'_, FEN>,
976    ) {
977        call_inspectors!(
978            [
979                &mut self.line_coverage,
980                &mut self.tracer,
981                &mut self.cheatcodes,
982                &mut self.script_execution_inspector,
983                &mut self.printer
984            ],
985            |inspector| inspector.initialize_interp(interpreter, ecx),
986        );
987    }
988
989    fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut FoundryContextFor<'_, FEN>) {
990        self.step_inlined(interpreter, ecx);
991    }
992
993    fn step_end(&mut self, interpreter: &mut Interpreter, ecx: &mut FoundryContextFor<'_, FEN>) {
994        self.step_end_inlined(interpreter, ecx);
995    }
996
997    #[allow(clippy::redundant_clone)]
998    fn log(&mut self, ecx: &mut FoundryContextFor<'_, FEN>, log: Log) {
999        call_inspectors!(
1000            [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],
1001            |inspector| inspector.log(ecx, log.clone()),
1002        );
1003    }
1004
1005    #[allow(clippy::redundant_clone)]
1006    fn log_full(
1007        &mut self,
1008        interpreter: &mut Interpreter,
1009        ecx: &mut FoundryContextFor<'_, FEN>,
1010        log: Log,
1011    ) {
1012        call_inspectors!(
1013            [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],
1014            |inspector| inspector.log_full(interpreter, ecx, log.clone()),
1015        );
1016    }
1017
1018    fn call(
1019        &mut self,
1020        ecx: &mut FoundryContextFor<'_, FEN>,
1021        call: &mut CallInputs,
1022    ) -> Option<CallOutcome> {
1023        if self.in_inner_context && ecx.journal().depth() == 1 {
1024            self.adjust_evm_data_for_inner_context(ecx);
1025            return None;
1026        }
1027
1028        if ecx.journal().depth() == 0 {
1029            self.top_level_frame_start(ecx);
1030        }
1031
1032        call_inspectors!(
1033            #[ret]
1034            [
1035                &mut self.fuzzer,
1036                &mut self.tracer,
1037                &mut self.log_collector,
1038                &mut self.printer,
1039                &mut self.revert_diag,
1040                &mut self.tempo_labels
1041            ],
1042            |inspector| {
1043                let mut out = None;
1044                if let Some(output) = inspector.call(ecx, call) {
1045                    out = Some(Some(output));
1046                }
1047                out
1048            },
1049        );
1050
1051        if let Some(cheatcodes) = self.cheatcodes.as_deref_mut() {
1052            // Handle mocked functions, replace bytecode address with mock if matched.
1053            if let Some(mocks) = cheatcodes.mocked_functions.get(&call.bytecode_address) {
1054                let input_bytes = call.input.bytes(ecx);
1055                // Check if any mock function set for call data or if catch-all mock function set
1056                // for selector.
1057                if let Some(target) = mocks
1058                    .get(&input_bytes)
1059                    .or_else(|| input_bytes.get(..4).and_then(|selector| mocks.get(selector)))
1060                {
1061                    call.bytecode_address = *target;
1062                    call.known_bytecode = None;
1063                }
1064            }
1065
1066            if let Some(output) = cheatcodes.call_with_executor(ecx, call, self.inner) {
1067                return Some(output);
1068            }
1069        }
1070
1071        if self.enable_isolation && !self.in_inner_context && ecx.journal().depth() == 1 {
1072            match call.scheme {
1073                // Isolate CALLs
1074                CallScheme::Call => {
1075                    let input = call.input.bytes(ecx);
1076                    let (result, _) = self.transact_inner(
1077                        ecx,
1078                        TxKind::Call(call.target_address),
1079                        call.caller,
1080                        input,
1081                        call.gas_limit,
1082                        call.value.get(),
1083                    );
1084                    return Some(CallOutcome {
1085                        result,
1086                        memory_offset: call.return_memory_offset.clone(),
1087                        was_precompile_called: true,
1088                        precompile_call_logs: vec![],
1089                    });
1090                }
1091                // Mark accounts and storage cold before STATICCALLs
1092                CallScheme::StaticCall => {
1093                    let (_, journal_inner) = ecx.db_journal_inner_mut();
1094                    let JournaledState { state, warm_addresses, .. } = journal_inner;
1095                    for (addr, acc_mut) in state {
1096                        // Do not mark accounts and storage cold accounts with arbitrary storage.
1097                        if let Some(cheatcodes) = &self.cheatcodes
1098                            && cheatcodes.has_arbitrary_storage(addr)
1099                        {
1100                            continue;
1101                        }
1102
1103                        if warm_addresses.is_cold(addr) {
1104                            acc_mut.mark_cold();
1105                        }
1106
1107                        for slot_mut in acc_mut.storage.values_mut() {
1108                            slot_mut.is_cold = true;
1109                        }
1110                    }
1111                }
1112                // Process other variants as usual
1113                CallScheme::CallCode | CallScheme::DelegateCall => {}
1114            }
1115        }
1116
1117        None
1118    }
1119
1120    fn call_end(
1121        &mut self,
1122        ecx: &mut FoundryContextFor<'_, FEN>,
1123        inputs: &CallInputs,
1124        outcome: &mut CallOutcome,
1125    ) {
1126        // We are processing inner context outputs in the outer context, so need to avoid processing
1127        // twice.
1128        if self.in_inner_context && ecx.journal().depth() == 1 {
1129            return;
1130        }
1131
1132        self.do_call_end(ecx, inputs, outcome);
1133
1134        if ecx.journal().depth() == 0 {
1135            self.top_level_frame_end(ecx, outcome.result.result);
1136        }
1137    }
1138
1139    fn create(
1140        &mut self,
1141        ecx: &mut FoundryContextFor<'_, FEN>,
1142        create: &mut CreateInputs,
1143    ) -> Option<CreateOutcome> {
1144        if self.in_inner_context && ecx.journal().depth() == 1 {
1145            self.adjust_evm_data_for_inner_context(ecx);
1146            return None;
1147        }
1148
1149        if ecx.journal().depth() == 0 {
1150            self.top_level_frame_start(ecx);
1151        }
1152
1153        call_inspectors!(
1154            #[ret]
1155            [&mut self.tracer, &mut self.line_coverage, &mut self.cheatcodes],
1156            |inspector| inspector.create(ecx, create).map(Some),
1157        );
1158
1159        if !matches!(create.scheme(), CreateScheme::Create2 { .. })
1160            && self.enable_isolation
1161            && !self.in_inner_context
1162            && ecx.journal().depth() == 1
1163        {
1164            let (result, address) = self.transact_inner(
1165                ecx,
1166                TxKind::Create,
1167                create.caller(),
1168                create.init_code().clone(),
1169                create.gas_limit(),
1170                create.value(),
1171            );
1172            return Some(CreateOutcome { result, address });
1173        }
1174
1175        None
1176    }
1177
1178    fn create_end(
1179        &mut self,
1180        ecx: &mut FoundryContextFor<'_, FEN>,
1181        call: &CreateInputs,
1182        outcome: &mut CreateOutcome,
1183    ) {
1184        // We are processing inner context outputs in the outer context, so need to avoid processing
1185        // twice.
1186        if self.in_inner_context && ecx.journal().depth() == 1 {
1187            return;
1188        }
1189
1190        self.do_create_end(ecx, call, outcome);
1191
1192        if ecx.journal().depth() == 0 {
1193            self.top_level_frame_end(ecx, outcome.result.result);
1194        }
1195    }
1196
1197    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1198        call_inspectors!([&mut self.printer], |inspector| {
1199            Inspector::<FoundryContextFor<'_, FEN>>::selfdestruct(
1200                inspector, contract, target, value,
1201            )
1202        });
1203    }
1204}
1205
1206impl<FEN: FoundryEvmNetwork> InspectorExt for InspectorStackRefMut<'_, FEN> {
1207    fn should_use_create2_factory(&mut self, depth: usize, inputs: &CreateInputs) -> bool {
1208        call_inspectors!(
1209            #[ret]
1210            [&mut self.cheatcodes],
1211            |inspector| { inspector.should_use_create2_factory(depth, inputs).then_some(true) },
1212        );
1213
1214        false
1215    }
1216
1217    fn console_log(&mut self, msg: &str) {
1218        call_inspectors!([&mut self.log_collector], |inspector| InspectorExt::console_log(
1219            inspector, msg
1220        ));
1221    }
1222
1223    fn get_networks(&self) -> NetworkConfigs {
1224        self.inner.networks
1225    }
1226
1227    fn create2_deployer(&self) -> Address {
1228        self.inner.create2_deployer
1229    }
1230}
1231
1232impl<FEN: FoundryEvmNetwork> Inspector<FoundryContextFor<'_, FEN>> for InspectorStack<FEN> {
1233    fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut FoundryContextFor<'_, FEN>) {
1234        self.as_mut().step_inlined(interpreter, ecx)
1235    }
1236
1237    fn step_end(&mut self, interpreter: &mut Interpreter, ecx: &mut FoundryContextFor<'_, FEN>) {
1238        self.as_mut().step_end_inlined(interpreter, ecx)
1239    }
1240
1241    fn call(
1242        &mut self,
1243        context: &mut FoundryContextFor<'_, FEN>,
1244        inputs: &mut CallInputs,
1245    ) -> Option<CallOutcome> {
1246        self.as_mut().call(context, inputs)
1247    }
1248
1249    fn call_end(
1250        &mut self,
1251        context: &mut FoundryContextFor<'_, FEN>,
1252        inputs: &CallInputs,
1253        outcome: &mut CallOutcome,
1254    ) {
1255        self.as_mut().call_end(context, inputs, outcome)
1256    }
1257
1258    fn create(
1259        &mut self,
1260        context: &mut FoundryContextFor<'_, FEN>,
1261        create: &mut CreateInputs,
1262    ) -> Option<CreateOutcome> {
1263        self.as_mut().create(context, create)
1264    }
1265
1266    fn create_end(
1267        &mut self,
1268        context: &mut FoundryContextFor<'_, FEN>,
1269        call: &CreateInputs,
1270        outcome: &mut CreateOutcome,
1271    ) {
1272        self.as_mut().create_end(context, call, outcome)
1273    }
1274
1275    fn initialize_interp(
1276        &mut self,
1277        interpreter: &mut Interpreter,
1278        ecx: &mut FoundryContextFor<'_, FEN>,
1279    ) {
1280        self.as_mut().initialize_interp(interpreter, ecx)
1281    }
1282
1283    fn log(&mut self, ecx: &mut FoundryContextFor<'_, FEN>, log: Log) {
1284        self.as_mut().log(ecx, log)
1285    }
1286
1287    fn log_full(
1288        &mut self,
1289        interpreter: &mut Interpreter,
1290        ecx: &mut FoundryContextFor<'_, FEN>,
1291        log: Log,
1292    ) {
1293        self.as_mut().log_full(interpreter, ecx, log)
1294    }
1295
1296    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1297        call_inspectors!([&mut self.inner.printer], |inspector| {
1298            Inspector::<FoundryContextFor<'_, FEN>>::selfdestruct(
1299                inspector, contract, target, value,
1300            )
1301        });
1302    }
1303}
1304
1305impl<FEN: FoundryEvmNetwork> InspectorExt for InspectorStack<FEN> {
1306    fn should_use_create2_factory(&mut self, depth: usize, inputs: &CreateInputs) -> bool {
1307        self.as_mut().should_use_create2_factory(depth, inputs)
1308    }
1309
1310    fn get_networks(&self) -> NetworkConfigs {
1311        self.networks
1312    }
1313
1314    fn create2_deployer(&self) -> Address {
1315        self.create2_deployer
1316    }
1317}
1318
1319impl<'a, FEN: FoundryEvmNetwork> Deref for InspectorStackRefMut<'a, FEN> {
1320    type Target = &'a mut InspectorStackInner;
1321
1322    fn deref(&self) -> &Self::Target {
1323        &self.inner
1324    }
1325}
1326
1327impl<FEN: FoundryEvmNetwork> DerefMut for InspectorStackRefMut<'_, FEN> {
1328    fn deref_mut(&mut self) -> &mut Self::Target {
1329        &mut self.inner
1330    }
1331}
1332
1333impl<FEN: FoundryEvmNetwork> Deref for InspectorStack<FEN> {
1334    type Target = InspectorStackInner;
1335
1336    fn deref(&self) -> &Self::Target {
1337        &self.inner
1338    }
1339}
1340
1341impl<FEN: FoundryEvmNetwork> DerefMut for InspectorStack<FEN> {
1342    fn deref_mut(&mut self) -> &mut Self::Target {
1343        &mut self.inner
1344    }
1345}