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