1use super::{
2 Cheatcodes, CheatsConfig, ChiselState, CoverageCollector, Fuzzer, LogCollector,
3 TracingInspector,
4};
5use alloy_primitives::{map::AddressHashMap, Address, Bytes, Log, TxKind, U256};
6use foundry_cheatcodes::{CheatcodesExecutor, Wallets};
7use foundry_evm_core::{backend::DatabaseExt, InspectorExt};
8use foundry_evm_coverage::HitMaps;
9use foundry_evm_traces::{SparsedTraceArena, TraceMode};
10use revm::{
11 inspectors::CustomPrintTracer,
12 interpreter::{
13 CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs,
14 EOFCreateKind, Gas, InstructionResult, Interpreter, InterpreterResult,
15 },
16 primitives::{
17 Account, AccountStatus, BlockEnv, CreateScheme, Env, EnvWithHandlerCfg, ExecutionResult,
18 HashMap, Output, TransactTo,
19 },
20 EvmContext, Inspector, JournaledState,
21};
22use std::{
23 ops::{Deref, DerefMut},
24 sync::Arc,
25};
26
27#[derive(Clone, Debug, Default)]
28#[must_use = "builders do nothing unless you call `build` on them"]
29pub struct InspectorStackBuilder {
30 pub block: Option<BlockEnv>,
35 pub gas_price: Option<U256>,
40 pub cheatcodes: Option<Arc<CheatsConfig>>,
42 pub fuzzer: Option<Fuzzer>,
44 pub trace_mode: TraceMode,
46 pub logs: Option<bool>,
48 pub coverage: Option<bool>,
50 pub print: Option<bool>,
52 pub chisel_state: Option<usize>,
54 pub enable_isolation: bool,
58 pub odyssey: bool,
60 pub wallets: Option<Wallets>,
62 pub create2_deployer: Address,
64}
65
66impl InspectorStackBuilder {
67 #[inline]
69 pub fn new() -> Self {
70 Self::default()
71 }
72
73 #[inline]
75 pub fn block(mut self, block: BlockEnv) -> Self {
76 self.block = Some(block);
77 self
78 }
79
80 #[inline]
82 pub fn gas_price(mut self, gas_price: U256) -> Self {
83 self.gas_price = Some(gas_price);
84 self
85 }
86
87 #[inline]
89 pub fn cheatcodes(mut self, config: Arc<CheatsConfig>) -> Self {
90 self.cheatcodes = Some(config);
91 self
92 }
93
94 #[inline]
96 pub fn wallets(mut self, wallets: Wallets) -> Self {
97 self.wallets = Some(wallets);
98 self
99 }
100
101 #[inline]
103 pub fn fuzzer(mut self, fuzzer: Fuzzer) -> Self {
104 self.fuzzer = Some(fuzzer);
105 self
106 }
107
108 #[inline]
110 pub fn chisel_state(mut self, final_pc: usize) -> Self {
111 self.chisel_state = Some(final_pc);
112 self
113 }
114
115 #[inline]
117 pub fn logs(mut self, yes: bool) -> Self {
118 self.logs = Some(yes);
119 self
120 }
121
122 #[inline]
124 pub fn coverage(mut self, yes: bool) -> Self {
125 self.coverage = Some(yes);
126 self
127 }
128
129 #[inline]
131 pub fn print(mut self, yes: bool) -> Self {
132 self.print = Some(yes);
133 self
134 }
135
136 #[inline]
138 pub fn trace_mode(mut self, mode: TraceMode) -> Self {
139 if self.trace_mode < mode {
140 self.trace_mode = mode
141 }
142 self
143 }
144
145 #[inline]
148 pub fn enable_isolation(mut self, yes: bool) -> Self {
149 self.enable_isolation = yes;
150 self
151 }
152
153 #[inline]
156 pub fn odyssey(mut self, yes: bool) -> Self {
157 self.odyssey = yes;
158 self
159 }
160
161 #[inline]
162 pub fn create2_deployer(mut self, create2_deployer: Address) -> Self {
163 self.create2_deployer = create2_deployer;
164 self
165 }
166
167 pub fn build(self) -> InspectorStack {
169 let Self {
170 block,
171 gas_price,
172 cheatcodes,
173 fuzzer,
174 trace_mode,
175 logs,
176 coverage,
177 print,
178 chisel_state,
179 enable_isolation,
180 odyssey,
181 wallets,
182 create2_deployer,
183 } = self;
184 let mut stack = InspectorStack::new();
185
186 if let Some(config) = cheatcodes {
188 let mut cheatcodes = Cheatcodes::new(config);
189 if let Some(wallets) = wallets {
191 cheatcodes.set_wallets(wallets);
192 }
193 stack.set_cheatcodes(cheatcodes);
194 }
195
196 if let Some(fuzzer) = fuzzer {
197 stack.set_fuzzer(fuzzer);
198 }
199 if let Some(chisel_state) = chisel_state {
200 stack.set_chisel(chisel_state);
201 }
202 stack.collect_coverage(coverage.unwrap_or(false));
203 stack.collect_logs(logs.unwrap_or(true));
204 stack.print(print.unwrap_or(false));
205 stack.tracing(trace_mode);
206
207 stack.enable_isolation(enable_isolation);
208 stack.odyssey(odyssey);
209 stack.set_create2_deployer(create2_deployer);
210
211 if let Some(block) = block {
213 stack.set_block(&block);
214 }
215 if let Some(gas_price) = gas_price {
216 stack.set_gas_price(gas_price);
217 }
218
219 stack
220 }
221}
222
223#[macro_export]
226macro_rules! call_inspectors {
227 ([$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $call:expr $(,)?) => {
228 $(
229 if let Some($id) = $inspector {
230 ({ #[inline(always)] #[cold] || $call })();
231 }
232 )+
233 };
234 (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $call:expr $(,)?) => {
235 $(
236 if let Some($id) = $inspector {
237 if let Some(result) = ({ #[inline(always)] #[cold] || $call })() {
238 return result;
239 }
240 }
241 )+
242 };
243}
244
245pub struct InspectorData {
247 pub logs: Vec<Log>,
248 pub labels: AddressHashMap<String>,
249 pub traces: Option<SparsedTraceArena>,
250 pub coverage: Option<HitMaps>,
251 pub cheatcodes: Option<Cheatcodes>,
252 pub chisel_state: Option<(Vec<U256>, Vec<u8>, InstructionResult)>,
253}
254
255#[derive(Debug, Clone)]
261pub struct InnerContextData {
262 original_origin: Address,
264}
265
266#[derive(Clone, Debug, Default)]
277pub struct InspectorStack {
278 pub cheatcodes: Option<Cheatcodes>,
279 pub inner: InspectorStackInner,
280}
281
282#[derive(Default, Clone, Debug)]
286pub struct InspectorStackInner {
287 pub chisel_state: Option<ChiselState>,
288 pub coverage: Option<CoverageCollector>,
289 pub fuzzer: Option<Fuzzer>,
290 pub log_collector: Option<LogCollector>,
291 pub printer: Option<CustomPrintTracer>,
292 pub tracer: Option<TracingInspector>,
293 pub enable_isolation: bool,
294 pub odyssey: bool,
295 pub create2_deployer: Address,
296
297 pub in_inner_context: bool,
299 pub inner_context_data: Option<InnerContextData>,
300 pub top_frame_journal: HashMap<Address, Account>,
301}
302
303pub struct InspectorStackRefMut<'a> {
307 pub cheatcodes: Option<&'a mut Cheatcodes>,
308 pub inner: &'a mut InspectorStackInner,
309}
310
311impl CheatcodesExecutor for InspectorStackInner {
312 fn get_inspector<'a>(&'a mut self, cheats: &'a mut Cheatcodes) -> Box<dyn InspectorExt + 'a> {
313 Box::new(InspectorStackRefMut { cheatcodes: Some(cheats), inner: self })
314 }
315
316 fn tracing_inspector(&mut self) -> Option<&mut Option<TracingInspector>> {
317 Some(&mut self.tracer)
318 }
319}
320
321impl InspectorStack {
322 #[inline]
328 pub fn new() -> Self {
329 Self::default()
330 }
331
332 pub fn log_status(&self) {
334 trace!(enabled=%{
335 let mut enabled = Vec::with_capacity(16);
336 macro_rules! push {
337 ($($id:ident),* $(,)?) => {
338 $(
339 if self.$id.is_some() {
340 enabled.push(stringify!($id));
341 }
342 )*
343 };
344 }
345 push!(cheatcodes, chisel_state, coverage, fuzzer, log_collector, printer, tracer);
346 if self.enable_isolation {
347 enabled.push("isolation");
348 }
349 format!("[{}]", enabled.join(", "))
350 });
351 }
352
353 #[inline]
355 pub fn set_env(&mut self, env: &Env) {
356 self.set_block(&env.block);
357 self.set_gas_price(env.tx.gas_price);
358 }
359
360 #[inline]
362 pub fn set_block(&mut self, block: &BlockEnv) {
363 if let Some(cheatcodes) = &mut self.cheatcodes {
364 cheatcodes.block = Some(block.clone());
365 }
366 }
367
368 #[inline]
370 pub fn set_gas_price(&mut self, gas_price: U256) {
371 if let Some(cheatcodes) = &mut self.cheatcodes {
372 cheatcodes.gas_price = Some(gas_price);
373 }
374 }
375
376 #[inline]
378 pub fn set_cheatcodes(&mut self, cheatcodes: Cheatcodes) {
379 self.cheatcodes = Some(cheatcodes);
380 }
381
382 #[inline]
384 pub fn set_fuzzer(&mut self, fuzzer: Fuzzer) {
385 self.fuzzer = Some(fuzzer);
386 }
387
388 #[inline]
390 pub fn set_chisel(&mut self, final_pc: usize) {
391 self.chisel_state = Some(ChiselState::new(final_pc));
392 }
393
394 #[inline]
396 pub fn collect_coverage(&mut self, yes: bool) {
397 self.coverage = yes.then(Default::default);
398 }
399
400 #[inline]
402 pub fn enable_isolation(&mut self, yes: bool) {
403 self.enable_isolation = yes;
404 }
405
406 #[inline]
408 pub fn odyssey(&mut self, yes: bool) {
409 self.odyssey = yes;
410 }
411
412 #[inline]
414 pub fn set_create2_deployer(&mut self, deployer: Address) {
415 self.create2_deployer = deployer;
416 }
417
418 #[inline]
420 pub fn collect_logs(&mut self, yes: bool) {
421 self.log_collector = yes.then(Default::default);
422 }
423
424 #[inline]
426 pub fn print(&mut self, yes: bool) {
427 self.printer = yes.then(Default::default);
428 }
429
430 #[inline]
432 pub fn tracing(&mut self, mode: TraceMode) {
433 if let Some(config) = mode.into_config() {
434 *self.tracer.get_or_insert_with(Default::default).config_mut() = config;
435 } else {
436 self.tracer = None;
437 }
438 }
439
440 #[inline]
442 pub fn collect(self) -> InspectorData {
443 let Self {
444 mut cheatcodes,
445 inner: InspectorStackInner { chisel_state, coverage, log_collector, tracer, .. },
446 } = self;
447
448 let traces = tracer.map(|tracer| tracer.into_traces()).map(|arena| {
449 let ignored = cheatcodes
450 .as_mut()
451 .map(|cheatcodes| {
452 let mut ignored = std::mem::take(&mut cheatcodes.ignored_traces.ignored);
453
454 if let Some(last_pause_call) = cheatcodes.ignored_traces.last_pause_call {
456 ignored.insert(last_pause_call, (arena.nodes().len(), 0));
457 }
458
459 ignored
460 })
461 .unwrap_or_default();
462
463 SparsedTraceArena { arena, ignored }
464 });
465
466 InspectorData {
467 logs: log_collector.map(|logs| logs.logs).unwrap_or_default(),
468 labels: cheatcodes
469 .as_ref()
470 .map(|cheatcodes| cheatcodes.labels.clone())
471 .unwrap_or_default(),
472 traces,
473 coverage: coverage.map(|coverage| coverage.finish()),
474 cheatcodes,
475 chisel_state: chisel_state.and_then(|state| state.state),
476 }
477 }
478
479 #[inline(always)]
480 fn as_mut(&mut self) -> InspectorStackRefMut<'_> {
481 InspectorStackRefMut { cheatcodes: self.cheatcodes.as_mut(), inner: &mut self.inner }
482 }
483}
484
485impl InspectorStackRefMut<'_> {
486 fn adjust_evm_data_for_inner_context(&mut self, ecx: &mut EvmContext<&mut dyn DatabaseExt>) {
491 let inner_context_data =
492 self.inner_context_data.as_ref().expect("should be called in inner context");
493 ecx.env.tx.caller = inner_context_data.original_origin;
494 }
495
496 fn do_call_end(
497 &mut self,
498 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
499 inputs: &CallInputs,
500 outcome: CallOutcome,
501 ) -> CallOutcome {
502 let result = outcome.result.result;
503 call_inspectors!(
504 #[ret]
505 [&mut self.fuzzer, &mut self.tracer, &mut self.cheatcodes, &mut self.printer],
506 |inspector| {
507 let new_outcome = inspector.call_end(ecx, inputs, outcome.clone());
508
509 let different = new_outcome.result.result != result ||
512 (new_outcome.result.result == InstructionResult::Revert &&
513 new_outcome.output() != outcome.output());
514 different.then_some(new_outcome)
515 },
516 );
517
518 outcome
519 }
520
521 fn do_create_end(
522 &mut self,
523 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
524 call: &CreateInputs,
525 outcome: CreateOutcome,
526 ) -> CreateOutcome {
527 let result = outcome.result.result;
528 call_inspectors!(
529 #[ret]
530 [&mut self.tracer, &mut self.cheatcodes, &mut self.printer],
531 |inspector| {
532 let new_outcome = inspector.create_end(ecx, call, outcome.clone());
533
534 let different = new_outcome.result.result != result ||
537 (new_outcome.result.result == InstructionResult::Revert &&
538 new_outcome.output() != outcome.output());
539 different.then_some(new_outcome)
540 },
541 );
542
543 outcome
544 }
545
546 fn do_eofcreate_end(
547 &mut self,
548 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
549 call: &EOFCreateInputs,
550 outcome: CreateOutcome,
551 ) -> CreateOutcome {
552 let result = outcome.result.result;
553 call_inspectors!(
554 #[ret]
555 [&mut self.tracer, &mut self.cheatcodes, &mut self.printer],
556 |inspector| {
557 let new_outcome = inspector.eofcreate_end(ecx, call, outcome.clone());
558
559 let different = new_outcome.result.result != result ||
562 (new_outcome.result.result == InstructionResult::Revert &&
563 new_outcome.output() != outcome.output());
564 different.then_some(new_outcome)
565 },
566 );
567
568 outcome
569 }
570
571 fn transact_inner(
572 &mut self,
573 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
574 transact_to: TransactTo,
575 caller: Address,
576 input: Bytes,
577 gas_limit: u64,
578 value: U256,
579 ) -> (InterpreterResult, Option<Address>) {
580 let ecx = &mut ecx.inner;
581
582 let cached_env = ecx.env.clone();
583
584 ecx.env.block.basefee = U256::ZERO;
585 ecx.env.tx.caller = caller;
586 ecx.env.tx.transact_to = transact_to;
587 ecx.env.tx.data = input;
588 ecx.env.tx.value = value;
589 ecx.env.tx.gas_limit = gas_limit + 21000;
591 if !ecx.env.cfg.disable_block_gas_limit {
594 ecx.env.tx.gas_limit =
595 std::cmp::min(ecx.env.tx.gas_limit, ecx.env.block.gas_limit.to());
596 }
597 ecx.env.tx.gas_price = U256::ZERO;
598
599 self.inner_context_data = Some(InnerContextData { original_origin: cached_env.tx.caller });
600 self.in_inner_context = true;
601
602 let env = EnvWithHandlerCfg::new_with_spec_id(ecx.env.clone(), ecx.spec_id());
603 let res = self.with_stack(|inspector| {
604 let mut evm = crate::utils::new_evm_with_inspector(&mut ecx.db, env, inspector);
605
606 evm.context.evm.inner.journaled_state.state = {
607 let mut state = ecx.journaled_state.state.clone();
608
609 for (addr, acc_mut) in &mut state {
610 if !ecx.journaled_state.warm_preloaded_addresses.contains(addr) {
612 acc_mut.mark_cold();
613 }
614
615 for slot_mut in acc_mut.storage.values_mut() {
617 slot_mut.is_cold = true;
618 slot_mut.original_value = slot_mut.present_value;
619 }
620 }
621
622 state
623 };
624
625 evm.context.evm.inner.journaled_state.depth = 1;
627
628 let res = evm.transact();
629
630 ecx.env = evm.context.evm.inner.env;
632 res
633 });
634
635 self.in_inner_context = false;
636 self.inner_context_data = None;
637
638 ecx.env.tx = cached_env.tx;
639 ecx.env.block.basefee = cached_env.block.basefee;
640
641 let mut gas = Gas::new(gas_limit);
642
643 let Ok(res) = res else {
644 let result =
646 InterpreterResult { result: InstructionResult::Revert, output: Bytes::new(), gas };
647 return (result, None);
648 };
649
650 for (addr, mut acc) in res.state {
651 let Some(acc_mut) = ecx.journaled_state.state.get_mut(&addr) else {
652 ecx.journaled_state.state.insert(addr, acc);
653 continue
654 };
655
656 if acc.status.contains(AccountStatus::Cold) &&
658 !acc_mut.status.contains(AccountStatus::Cold)
659 {
660 acc.status -= AccountStatus::Cold;
661 }
662 acc_mut.info = acc.info;
663 acc_mut.status |= acc.status;
664
665 for (key, val) in acc.storage {
666 let Some(slot_mut) = acc_mut.storage.get_mut(&key) else {
667 acc_mut.storage.insert(key, val);
668 continue
669 };
670 slot_mut.present_value = val.present_value;
671 slot_mut.is_cold &= val.is_cold;
672 }
673 }
674
675 let (result, address, output) = match res.result {
676 ExecutionResult::Success { reason, gas_used, gas_refunded, logs: _, output } => {
677 gas.set_refund(gas_refunded as i64);
678 let _ = gas.record_cost(gas_used);
679 let address = match output {
680 Output::Create(_, address) => address,
681 Output::Call(_) => None,
682 };
683 (reason.into(), address, output.into_data())
684 }
685 ExecutionResult::Halt { reason, gas_used } => {
686 let _ = gas.record_cost(gas_used);
687 (reason.into(), None, Bytes::new())
688 }
689 ExecutionResult::Revert { gas_used, output } => {
690 let _ = gas.record_cost(gas_used);
691 (InstructionResult::Revert, None, output)
692 }
693 };
694 (InterpreterResult { result, output, gas }, address)
695 }
696
697 fn with_stack<O>(&mut self, f: impl FnOnce(&mut InspectorStack) -> O) -> O {
700 let mut stack = InspectorStack {
701 cheatcodes: self
702 .cheatcodes
703 .as_deref_mut()
704 .map(|cheats| core::mem::replace(cheats, Cheatcodes::new(cheats.config.clone()))),
705 inner: std::mem::take(self.inner),
706 };
707
708 let out = f(&mut stack);
709
710 if let Some(cheats) = self.cheatcodes.as_deref_mut() {
711 *cheats = stack.cheatcodes.take().unwrap();
712 }
713
714 *self.inner = stack.inner;
715
716 out
717 }
718
719 fn top_level_frame_start(&mut self, ecx: &mut EvmContext<&mut dyn DatabaseExt>) {
721 if self.enable_isolation {
722 self.top_frame_journal = ecx.journaled_state.state.clone();
725 }
726 }
727
728 fn top_level_frame_end(
730 &mut self,
731 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
732 result: InstructionResult,
733 ) {
734 if !result.is_revert() {
735 return;
736 }
737 if let Some(cheats) = self.cheatcodes.as_mut() {
741 cheats.on_revert(ecx);
742 }
743
744 if self.enable_isolation {
748 ecx.journaled_state.state = std::mem::take(&mut self.top_frame_journal);
749 }
750 }
751}
752
753impl Inspector<&mut dyn DatabaseExt> for InspectorStackRefMut<'_> {
754 fn initialize_interp(
755 &mut self,
756 interpreter: &mut Interpreter,
757 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
758 ) {
759 call_inspectors!(
760 [&mut self.coverage, &mut self.tracer, &mut self.cheatcodes, &mut self.printer],
761 |inspector| inspector.initialize_interp(interpreter, ecx),
762 );
763 }
764
765 fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut EvmContext<&mut dyn DatabaseExt>) {
766 call_inspectors!(
767 [
768 &mut self.fuzzer,
769 &mut self.tracer,
770 &mut self.coverage,
771 &mut self.cheatcodes,
772 &mut self.printer,
773 ],
774 |inspector| inspector.step(interpreter, ecx),
775 );
776 }
777
778 fn step_end(
779 &mut self,
780 interpreter: &mut Interpreter,
781 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
782 ) {
783 call_inspectors!(
784 [&mut self.tracer, &mut self.cheatcodes, &mut self.chisel_state, &mut self.printer],
785 |inspector| inspector.step_end(interpreter, ecx),
786 );
787 }
788
789 fn log(
790 &mut self,
791 interpreter: &mut Interpreter,
792 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
793 log: &Log,
794 ) {
795 call_inspectors!(
796 [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],
797 |inspector| inspector.log(interpreter, ecx, log),
798 );
799 }
800
801 fn call(
802 &mut self,
803 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
804 call: &mut CallInputs,
805 ) -> Option<CallOutcome> {
806 if self.in_inner_context && ecx.journaled_state.depth == 1 {
807 self.adjust_evm_data_for_inner_context(ecx);
808 return None;
809 }
810
811 if ecx.journaled_state.depth == 0 {
812 self.top_level_frame_start(ecx);
813 }
814
815 call_inspectors!(
816 #[ret]
817 [&mut self.fuzzer, &mut self.tracer, &mut self.log_collector, &mut self.printer],
818 |inspector| {
819 let mut out = None;
820 if let Some(output) = inspector.call(ecx, call) {
821 if output.result.result != InstructionResult::Continue {
822 out = Some(Some(output));
823 }
824 }
825 out
826 },
827 );
828
829 if let Some(cheatcodes) = self.cheatcodes.as_deref_mut() {
830 if let Some(mocks) = cheatcodes.mocked_functions.get(&call.target_address) {
832 if let Some(target) = mocks
835 .get(&call.input)
836 .or_else(|| call.input.get(..4).and_then(|selector| mocks.get(selector)))
837 {
838 call.bytecode_address = *target;
839 }
840 }
841
842 if let Some(output) = cheatcodes.call_with_executor(ecx, call, self.inner) {
843 if output.result.result != InstructionResult::Continue {
844 return Some(output);
845 }
846 }
847 }
848
849 if self.enable_isolation && !self.in_inner_context && ecx.journaled_state.depth == 1 {
850 match call.scheme {
851 CallScheme::Call | CallScheme::ExtCall => {
853 let (result, _) = self.transact_inner(
854 ecx,
855 TxKind::Call(call.target_address),
856 call.caller,
857 call.input.clone(),
858 call.gas_limit,
859 call.value.get(),
860 );
861 return Some(CallOutcome {
862 result,
863 memory_offset: call.return_memory_offset.clone(),
864 });
865 }
866 CallScheme::StaticCall | CallScheme::ExtStaticCall => {
868 let JournaledState { state, warm_preloaded_addresses, .. } =
869 &mut ecx.journaled_state;
870 for (addr, acc_mut) in state {
871 if let Some(cheatcodes) = &self.cheatcodes {
873 if cheatcodes.has_arbitrary_storage(addr) {
874 continue;
875 }
876 }
877
878 if !warm_preloaded_addresses.contains(addr) {
879 acc_mut.mark_cold();
880 }
881
882 for slot_mut in acc_mut.storage.values_mut() {
883 slot_mut.is_cold = true;
884 }
885 }
886 }
887 CallScheme::CallCode | CallScheme::DelegateCall | CallScheme::ExtDelegateCall => {}
889 }
890 }
891
892 None
893 }
894
895 fn call_end(
896 &mut self,
897 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
898 inputs: &CallInputs,
899 outcome: CallOutcome,
900 ) -> CallOutcome {
901 if self.in_inner_context && ecx.journaled_state.depth == 1 {
904 return outcome;
905 }
906
907 let outcome = self.do_call_end(ecx, inputs, outcome);
908
909 if ecx.journaled_state.depth == 0 {
910 self.top_level_frame_end(ecx, outcome.result.result);
911 }
912
913 outcome
914 }
915
916 fn create(
917 &mut self,
918 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
919 create: &mut CreateInputs,
920 ) -> Option<CreateOutcome> {
921 if self.in_inner_context && ecx.journaled_state.depth == 1 {
922 self.adjust_evm_data_for_inner_context(ecx);
923 return None;
924 }
925
926 if ecx.journaled_state.depth == 0 {
927 self.top_level_frame_start(ecx);
928 }
929
930 call_inspectors!(
931 #[ret]
932 [&mut self.tracer, &mut self.coverage, &mut self.cheatcodes],
933 |inspector| inspector.create(ecx, create).map(Some),
934 );
935
936 if !matches!(create.scheme, CreateScheme::Create2 { .. }) &&
937 self.enable_isolation &&
938 !self.in_inner_context &&
939 ecx.journaled_state.depth == 1
940 {
941 let (result, address) = self.transact_inner(
942 ecx,
943 TxKind::Create,
944 create.caller,
945 create.init_code.clone(),
946 create.gas_limit,
947 create.value,
948 );
949 return Some(CreateOutcome { result, address });
950 }
951
952 None
953 }
954
955 fn create_end(
956 &mut self,
957 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
958 call: &CreateInputs,
959 outcome: CreateOutcome,
960 ) -> CreateOutcome {
961 if self.in_inner_context && ecx.journaled_state.depth == 1 {
964 return outcome;
965 }
966
967 let outcome = self.do_create_end(ecx, call, outcome);
968
969 if ecx.journaled_state.depth == 0 {
970 self.top_level_frame_end(ecx, outcome.result.result);
971 }
972
973 outcome
974 }
975
976 fn eofcreate(
977 &mut self,
978 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
979 create: &mut EOFCreateInputs,
980 ) -> Option<CreateOutcome> {
981 if self.in_inner_context && ecx.journaled_state.depth == 1 {
982 self.adjust_evm_data_for_inner_context(ecx);
983 return None;
984 }
985
986 if ecx.journaled_state.depth == 0 {
987 self.top_level_frame_start(ecx);
988 }
989
990 call_inspectors!(
991 #[ret]
992 [&mut self.tracer, &mut self.coverage, &mut self.cheatcodes],
993 |inspector| inspector.eofcreate(ecx, create).map(Some),
994 );
995
996 if matches!(create.kind, EOFCreateKind::Tx { .. }) &&
997 self.enable_isolation &&
998 !self.in_inner_context &&
999 ecx.journaled_state.depth == 1
1000 {
1001 let init_code = match &mut create.kind {
1002 EOFCreateKind::Tx { initdata } => initdata.clone(),
1003 EOFCreateKind::Opcode { .. } => unreachable!(),
1004 };
1005
1006 let (result, address) = self.transact_inner(
1007 ecx,
1008 TxKind::Create,
1009 create.caller,
1010 init_code,
1011 create.gas_limit,
1012 create.value,
1013 );
1014 return Some(CreateOutcome { result, address });
1015 }
1016
1017 None
1018 }
1019
1020 fn eofcreate_end(
1021 &mut self,
1022 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1023 call: &EOFCreateInputs,
1024 outcome: CreateOutcome,
1025 ) -> CreateOutcome {
1026 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1029 return outcome;
1030 }
1031
1032 let outcome = self.do_eofcreate_end(ecx, call, outcome);
1033
1034 if ecx.journaled_state.depth == 0 {
1035 self.top_level_frame_end(ecx, outcome.result.result);
1036 }
1037
1038 outcome
1039 }
1040
1041 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1042 call_inspectors!([&mut self.tracer, &mut self.printer], |inspector| {
1043 Inspector::<&mut dyn DatabaseExt>::selfdestruct(inspector, contract, target, value)
1044 });
1045 }
1046}
1047
1048impl InspectorExt for InspectorStackRefMut<'_> {
1049 fn should_use_create2_factory(
1050 &mut self,
1051 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1052 inputs: &mut CreateInputs,
1053 ) -> bool {
1054 call_inspectors!(
1055 #[ret]
1056 [&mut self.cheatcodes],
1057 |inspector| { inspector.should_use_create2_factory(ecx, inputs).then_some(true) },
1058 );
1059
1060 false
1061 }
1062
1063 fn console_log(&mut self, msg: &str) {
1064 call_inspectors!([&mut self.log_collector], |inspector| InspectorExt::console_log(
1065 inspector, msg
1066 ));
1067 }
1068
1069 fn is_odyssey(&self) -> bool {
1070 self.inner.odyssey
1071 }
1072
1073 fn create2_deployer(&self) -> Address {
1074 self.inner.create2_deployer
1075 }
1076}
1077
1078impl Inspector<&mut dyn DatabaseExt> for InspectorStack {
1079 #[inline]
1080 fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut EvmContext<&mut dyn DatabaseExt>) {
1081 self.as_mut().step(interpreter, ecx)
1082 }
1083
1084 #[inline]
1085 fn step_end(
1086 &mut self,
1087 interpreter: &mut Interpreter,
1088 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1089 ) {
1090 self.as_mut().step_end(interpreter, ecx)
1091 }
1092
1093 fn call(
1094 &mut self,
1095 context: &mut EvmContext<&mut dyn DatabaseExt>,
1096 inputs: &mut CallInputs,
1097 ) -> Option<CallOutcome> {
1098 self.as_mut().call(context, inputs)
1099 }
1100
1101 fn call_end(
1102 &mut self,
1103 context: &mut EvmContext<&mut dyn DatabaseExt>,
1104 inputs: &CallInputs,
1105 outcome: CallOutcome,
1106 ) -> CallOutcome {
1107 self.as_mut().call_end(context, inputs, outcome)
1108 }
1109
1110 fn create(
1111 &mut self,
1112 context: &mut EvmContext<&mut dyn DatabaseExt>,
1113 create: &mut CreateInputs,
1114 ) -> Option<CreateOutcome> {
1115 self.as_mut().create(context, create)
1116 }
1117
1118 fn create_end(
1119 &mut self,
1120 context: &mut EvmContext<&mut dyn DatabaseExt>,
1121 call: &CreateInputs,
1122 outcome: CreateOutcome,
1123 ) -> CreateOutcome {
1124 self.as_mut().create_end(context, call, outcome)
1125 }
1126
1127 fn eofcreate(
1128 &mut self,
1129 context: &mut EvmContext<&mut dyn DatabaseExt>,
1130 create: &mut EOFCreateInputs,
1131 ) -> Option<CreateOutcome> {
1132 self.as_mut().eofcreate(context, create)
1133 }
1134
1135 fn eofcreate_end(
1136 &mut self,
1137 context: &mut EvmContext<&mut dyn DatabaseExt>,
1138 call: &EOFCreateInputs,
1139 outcome: CreateOutcome,
1140 ) -> CreateOutcome {
1141 self.as_mut().eofcreate_end(context, call, outcome)
1142 }
1143
1144 fn initialize_interp(
1145 &mut self,
1146 interpreter: &mut Interpreter,
1147 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1148 ) {
1149 self.as_mut().initialize_interp(interpreter, ecx)
1150 }
1151
1152 fn log(
1153 &mut self,
1154 interpreter: &mut Interpreter,
1155 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1156 log: &Log,
1157 ) {
1158 self.as_mut().log(interpreter, ecx, log)
1159 }
1160
1161 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1162 Inspector::<&mut dyn DatabaseExt>::selfdestruct(&mut self.as_mut(), contract, target, value)
1163 }
1164}
1165
1166impl InspectorExt for InspectorStack {
1167 fn should_use_create2_factory(
1168 &mut self,
1169 ecx: &mut EvmContext<&mut dyn DatabaseExt>,
1170 inputs: &mut CreateInputs,
1171 ) -> bool {
1172 self.as_mut().should_use_create2_factory(ecx, inputs)
1173 }
1174
1175 fn is_odyssey(&self) -> bool {
1176 self.odyssey
1177 }
1178
1179 fn create2_deployer(&self) -> Address {
1180 self.create2_deployer
1181 }
1182}
1183
1184impl<'a> Deref for InspectorStackRefMut<'a> {
1185 type Target = &'a mut InspectorStackInner;
1186
1187 fn deref(&self) -> &Self::Target {
1188 &self.inner
1189 }
1190}
1191
1192impl DerefMut for InspectorStackRefMut<'_> {
1193 fn deref_mut(&mut self) -> &mut Self::Target {
1194 &mut self.inner
1195 }
1196}
1197
1198impl Deref for InspectorStack {
1199 type Target = InspectorStackInner;
1200
1201 fn deref(&self) -> &Self::Target {
1202 &self.inner
1203 }
1204}
1205
1206impl DerefMut for InspectorStack {
1207 fn deref_mut(&mut self) -> &mut Self::Target {
1208 &mut self.inner
1209 }
1210}