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