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::{CheatcodeAnalysis, CheatcodesExecutor, Wallets};
11use foundry_common::compile::Analysis;
12use foundry_compilers::ProjectPathsConfig;
13use foundry_evm_core::{
14 ContextExt, Env, InspectorExt,
15 backend::{DatabaseExt, JournaledState},
16 evm::new_evm_with_inspector,
17};
18use foundry_evm_coverage::HitMaps;
19use foundry_evm_networks::NetworkConfigs;
20use foundry_evm_traces::{SparsedTraceArena, TraceMode};
21use revm::{
22 Inspector,
23 context::{
24 BlockEnv,
25 result::{ExecutionResult, Output},
26 },
27 context_interface::CreateScheme,
28 interpreter::{
29 CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult,
30 Interpreter, InterpreterResult,
31 },
32 state::{Account, AccountStatus},
33};
34use revm_inspectors::edge_cov::EdgeCovInspector;
35use std::{
36 ops::{Deref, DerefMut},
37 sync::Arc,
38};
39
40#[derive(Clone, Debug, Default)]
41#[must_use = "builders do nothing unless you call `build` on them"]
42pub struct InspectorStackBuilder {
43 pub analysis: Option<Analysis>,
45 pub block: Option<BlockEnv>,
50 pub gas_price: Option<u128>,
55 pub cheatcodes: Option<Arc<CheatsConfig>>,
57 pub fuzzer: Option<Fuzzer>,
59 pub trace_mode: TraceMode,
61 pub logs: Option<bool>,
63 pub line_coverage: Option<bool>,
65 pub print: Option<bool>,
67 pub chisel_state: Option<usize>,
69 pub enable_isolation: bool,
73 pub networks: NetworkConfigs,
75 pub wallets: Option<Wallets>,
77 pub create2_deployer: Address,
79}
80
81impl InspectorStackBuilder {
82 #[inline]
84 pub fn new() -> Self {
85 Self::default()
86 }
87
88 #[inline]
90 pub fn set_analysis(mut self, analysis: Analysis) -> Self {
91 self.analysis = Some(analysis);
92 self
93 }
94
95 #[inline]
97 pub fn block(mut self, block: BlockEnv) -> Self {
98 self.block = Some(block);
99 self
100 }
101
102 #[inline]
104 pub fn gas_price(mut self, gas_price: u128) -> Self {
105 self.gas_price = Some(gas_price);
106 self
107 }
108
109 #[inline]
111 pub fn cheatcodes(mut self, config: Arc<CheatsConfig>) -> Self {
112 self.cheatcodes = Some(config);
113 self
114 }
115
116 #[inline]
118 pub fn wallets(mut self, wallets: Wallets) -> Self {
119 self.wallets = Some(wallets);
120 self
121 }
122
123 #[inline]
125 pub fn fuzzer(mut self, fuzzer: Fuzzer) -> Self {
126 self.fuzzer = Some(fuzzer);
127 self
128 }
129
130 #[inline]
132 pub fn chisel_state(mut self, final_pc: usize) -> Self {
133 self.chisel_state = Some(final_pc);
134 self
135 }
136
137 #[inline]
139 pub fn logs(mut self, yes: bool) -> Self {
140 self.logs = Some(yes);
141 self
142 }
143
144 #[inline]
146 pub fn line_coverage(mut self, yes: bool) -> Self {
147 self.line_coverage = Some(yes);
148 self
149 }
150
151 #[inline]
153 pub fn print(mut self, yes: bool) -> Self {
154 self.print = Some(yes);
155 self
156 }
157
158 #[inline]
161 pub fn trace_mode(mut self, mode: TraceMode) -> Self {
162 if self.trace_mode < mode {
163 self.trace_mode = mode
164 }
165 self
166 }
167
168 #[inline]
171 pub fn enable_isolation(mut self, yes: bool) -> Self {
172 self.enable_isolation = yes;
173 self
174 }
175
176 #[inline]
178 pub fn networks(mut self, networks: NetworkConfigs) -> Self {
179 self.networks = networks;
180 self
181 }
182
183 #[inline]
184 pub fn create2_deployer(mut self, create2_deployer: Address) -> Self {
185 self.create2_deployer = create2_deployer;
186 self
187 }
188
189 pub fn build(self) -> InspectorStack {
191 let Self {
192 analysis,
193 block,
194 gas_price,
195 cheatcodes,
196 fuzzer,
197 trace_mode,
198 logs,
199 line_coverage,
200 print,
201 chisel_state,
202 enable_isolation,
203 networks,
204 wallets,
205 create2_deployer,
206 } = self;
207 let mut stack = InspectorStack::new();
208
209 if let Some(config) = cheatcodes {
211 let mut cheatcodes = Cheatcodes::new(config);
212 if let Some(analysis) = analysis {
214 stack.set_analysis(analysis.clone());
215 cheatcodes.set_analysis(CheatcodeAnalysis::new(analysis));
216 }
217 if let Some(wallets) = wallets {
219 cheatcodes.set_wallets(wallets);
220 }
221 stack.set_cheatcodes(cheatcodes);
222 }
223
224 if let Some(fuzzer) = fuzzer {
225 stack.set_fuzzer(fuzzer);
226 }
227 if let Some(chisel_state) = chisel_state {
228 stack.set_chisel(chisel_state);
229 }
230 stack.collect_line_coverage(line_coverage.unwrap_or(false));
231 stack.collect_logs(logs.unwrap_or(true));
232 stack.print(print.unwrap_or(false));
233 stack.tracing(trace_mode);
234
235 stack.enable_isolation(enable_isolation);
236 stack.networks(networks);
237 stack.set_create2_deployer(create2_deployer);
238
239 if let Some(block) = block {
241 stack.set_block(&block);
242 }
243 if let Some(gas_price) = gas_price {
244 stack.set_gas_price(gas_price);
245 }
246
247 stack
248 }
249}
250
251#[macro_export]
254macro_rules! call_inspectors {
255 ([$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {
256 $(
257 if let Some($id) = $inspector {
258 $crate::utils::cold_path();
259 $body;
260 }
261 )+
262 };
263 (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {{
264 $(
265 if let Some($id) = $inspector {
266 $crate::utils::cold_path();
267 if let Some(result) = $body {
268 return result;
269 }
270 }
271 )+
272 }};
273}
274
275pub struct InspectorData {
277 pub logs: Vec<Log>,
278 pub labels: AddressHashMap<String>,
279 pub traces: Option<SparsedTraceArena>,
280 pub line_coverage: Option<HitMaps>,
281 pub edge_coverage: Option<Vec<u8>>,
282 pub cheatcodes: Option<Box<Cheatcodes>>,
283 pub chisel_state: Option<(Vec<U256>, Vec<u8>)>,
284 pub reverter: Option<Address>,
285}
286
287#[derive(Debug, Clone)]
293pub struct InnerContextData {
294 original_origin: Address,
296}
297
298#[derive(Clone, Debug, Default)]
309pub struct InspectorStack {
310 pub cheatcodes: Option<Box<Cheatcodes>>,
311 pub inner: InspectorStackInner,
312}
313
314impl InspectorStack {
315 pub fn paths_config(&self) -> Option<&ProjectPathsConfig> {
316 self.cheatcodes.as_ref().map(|c| &c.config.paths)
317 }
318}
319
320#[derive(Default, Clone, Debug)]
324pub struct InspectorStackInner {
325 pub analysis: Option<Analysis>,
327
328 pub chisel_state: Option<Box<ChiselState>>,
332 pub edge_coverage: Option<Box<EdgeCovInspector>>,
333 pub fuzzer: Option<Box<Fuzzer>>,
334 pub line_coverage: Option<Box<LineCoverageCollector>>,
335 pub log_collector: Option<Box<LogCollector>>,
336 pub printer: Option<Box<CustomPrintTracer>>,
337 pub revert_diag: Option<Box<RevertDiagnostic>>,
338 pub script_execution_inspector: Option<Box<ScriptExecutionInspector>>,
339 pub tracer: Option<Box<TracingInspector>>,
340
341 pub enable_isolation: bool,
343 pub networks: NetworkConfigs,
344 pub create2_deployer: Address,
345 pub in_inner_context: bool,
347 pub inner_context_data: Option<InnerContextData>,
348 pub top_frame_journal: HashMap<Address, Account>,
349 pub reverter: Option<Address>,
351}
352
353pub struct InspectorStackRefMut<'a> {
357 pub cheatcodes: Option<&'a mut Cheatcodes>,
358 pub inner: &'a mut InspectorStackInner,
359}
360
361impl CheatcodesExecutor for InspectorStackInner {
362 fn get_inspector<'a>(&'a mut self, cheats: &'a mut Cheatcodes) -> Box<dyn InspectorExt + 'a> {
363 Box::new(InspectorStackRefMut { cheatcodes: Some(cheats), inner: self })
364 }
365
366 fn tracing_inspector(&mut self) -> Option<&mut TracingInspector> {
367 self.tracer.as_deref_mut()
368 }
369}
370
371impl InspectorStack {
372 #[inline]
378 pub fn new() -> Self {
379 Self::default()
380 }
381
382 pub fn log_status(&self) {
384 trace!(enabled=%{
385 let mut enabled = Vec::with_capacity(16);
386 macro_rules! push {
387 ($($id:ident),* $(,)?) => {
388 $(
389 if self.$id.is_some() {
390 enabled.push(stringify!($id));
391 }
392 )*
393 };
394 }
395 push!(cheatcodes, chisel_state, line_coverage, fuzzer, log_collector, printer, tracer);
396 if self.enable_isolation {
397 enabled.push("isolation");
398 }
399 format!("[{}]", enabled.join(", "))
400 });
401 }
402
403 #[inline]
405 pub fn set_analysis(&mut self, analysis: Analysis) {
406 self.analysis = Some(analysis);
407 }
408
409 #[inline]
411 pub fn set_env(&mut self, env: &Env) {
412 self.set_block(&env.evm_env.block_env);
413 self.set_gas_price(env.tx.gas_price);
414 }
415
416 #[inline]
418 pub fn set_block(&mut self, block: &BlockEnv) {
419 if let Some(cheatcodes) = &mut self.cheatcodes {
420 cheatcodes.block = Some(block.clone());
421 }
422 }
423
424 #[inline]
426 pub fn set_gas_price(&mut self, gas_price: u128) {
427 if let Some(cheatcodes) = &mut self.cheatcodes {
428 cheatcodes.gas_price = Some(gas_price);
429 }
430 }
431
432 #[inline]
434 pub fn set_cheatcodes(&mut self, cheatcodes: Cheatcodes) {
435 self.cheatcodes = Some(cheatcodes.into());
436 }
437
438 #[inline]
440 pub fn set_fuzzer(&mut self, fuzzer: Fuzzer) {
441 self.fuzzer = Some(fuzzer.into());
442 }
443
444 #[inline]
446 pub fn set_chisel(&mut self, final_pc: usize) {
447 self.chisel_state = Some(ChiselState::new(final_pc).into());
448 }
449
450 #[inline]
452 pub fn collect_line_coverage(&mut self, yes: bool) {
453 self.line_coverage = yes.then(Default::default);
454 }
455
456 #[inline]
458 pub fn collect_edge_coverage(&mut self, yes: bool) {
459 self.edge_coverage = yes.then(EdgeCovInspector::new).map(Into::into);
461 }
462
463 #[inline]
465 pub fn enable_isolation(&mut self, yes: bool) {
466 self.enable_isolation = yes;
467 }
468
469 #[inline]
471 pub fn networks(&mut self, networks: NetworkConfigs) {
472 self.networks = networks;
473 }
474
475 #[inline]
477 pub fn set_create2_deployer(&mut self, deployer: Address) {
478 self.create2_deployer = deployer;
479 }
480
481 #[inline]
483 pub fn collect_logs(&mut self, yes: bool) {
484 self.log_collector = yes.then(Default::default);
485 }
486
487 #[inline]
489 pub fn print(&mut self, yes: bool) {
490 self.printer = yes.then(Default::default);
491 }
492
493 #[inline]
496 pub fn tracing(&mut self, mode: TraceMode) {
497 self.revert_diag = (!mode.is_none()).then(RevertDiagnostic::default).map(Into::into);
498
499 if let Some(config) = mode.into_config() {
500 *self.tracer.get_or_insert_with(Default::default).config_mut() = config;
501 } else {
502 self.tracer = None;
503 }
504 }
505
506 #[inline]
508 pub fn script(&mut self, script_address: Address) {
509 self.script_execution_inspector.get_or_insert_with(Default::default).script_address =
510 script_address;
511 }
512
513 #[inline(always)]
514 fn as_mut(&mut self) -> InspectorStackRefMut<'_> {
515 InspectorStackRefMut { cheatcodes: self.cheatcodes.as_deref_mut(), inner: &mut self.inner }
516 }
517
518 #[inline]
520 pub fn as_inspector(&mut self) -> impl InspectorExt + '_ {
521 self
522 }
523
524 pub fn collect(self) -> InspectorData {
526 let Self {
527 mut cheatcodes,
528 inner:
529 InspectorStackInner {
530 chisel_state,
531 line_coverage,
532 edge_coverage,
533 log_collector,
534 tracer,
535 reverter,
536 ..
537 },
538 } = self;
539
540 let traces = tracer.map(|tracer| tracer.into_traces()).map(|arena| {
541 let ignored = cheatcodes
542 .as_mut()
543 .map(|cheatcodes| {
544 let mut ignored = std::mem::take(&mut cheatcodes.ignored_traces.ignored);
545
546 if let Some(last_pause_call) = cheatcodes.ignored_traces.last_pause_call {
548 ignored.insert(last_pause_call, (arena.nodes().len(), 0));
549 }
550
551 ignored
552 })
553 .unwrap_or_default();
554
555 SparsedTraceArena { arena, ignored }
556 });
557
558 InspectorData {
559 logs: log_collector.map(|logs| logs.logs).unwrap_or_default(),
560 labels: cheatcodes
561 .as_ref()
562 .map(|cheatcodes| cheatcodes.labels.clone())
563 .unwrap_or_default(),
564 traces,
565 line_coverage: line_coverage.map(|line_coverage| line_coverage.finish()),
566 edge_coverage: edge_coverage.map(|edge_coverage| edge_coverage.into_hitcount()),
567 cheatcodes,
568 chisel_state: chisel_state.and_then(|state| state.state),
569 reverter,
570 }
571 }
572}
573
574impl InspectorStackRefMut<'_> {
575 fn adjust_evm_data_for_inner_context(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>) {
580 let inner_context_data =
581 self.inner_context_data.as_ref().expect("should be called in inner context");
582 ecx.tx.caller = inner_context_data.original_origin;
583 }
584
585 fn do_call_end(
586 &mut self,
587 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
588 inputs: &CallInputs,
589 outcome: &mut CallOutcome,
590 ) -> CallOutcome {
591 let result = outcome.result.result;
592 call_inspectors!(
593 #[ret]
594 [
595 &mut self.fuzzer,
596 &mut self.tracer,
597 &mut self.cheatcodes,
598 &mut self.printer,
599 &mut self.revert_diag
600 ],
601 |inspector| {
602 let previous_outcome = outcome.clone();
603 inspector.call_end(ecx, inputs, outcome);
604
605 let different = outcome.result.result != result
608 || (outcome.result.result == InstructionResult::Revert
609 && outcome.output() != previous_outcome.output());
610 different.then_some(outcome.clone())
611 },
612 );
613
614 if result.is_revert() && self.reverter.is_none() {
616 self.reverter = Some(inputs.target_address);
617 }
618
619 outcome.clone()
620 }
621
622 fn do_create_end(
623 &mut self,
624 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
625 call: &CreateInputs,
626 outcome: &mut CreateOutcome,
627 ) -> CreateOutcome {
628 let result = outcome.result.result;
629 call_inspectors!(
630 #[ret]
631 [&mut self.tracer, &mut self.cheatcodes, &mut self.printer],
632 |inspector| {
633 let previous_outcome = outcome.clone();
634 inspector.create_end(ecx, call, outcome);
635
636 let different = outcome.result.result != result
639 || (outcome.result.result == InstructionResult::Revert
640 && outcome.output() != previous_outcome.output());
641 different.then_some(outcome.clone())
642 },
643 );
644
645 outcome.clone()
646 }
647
648 fn transact_inner(
649 &mut self,
650 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
651 kind: TxKind,
652 caller: Address,
653 input: Bytes,
654 gas_limit: u64,
655 value: U256,
656 ) -> (InterpreterResult, Option<Address>) {
657 let cached_env = Env::from(ecx.cfg.clone(), ecx.block.clone(), ecx.tx.clone());
658
659 ecx.block.basefee = 0;
660 ecx.tx.chain_id = Some(ecx.cfg.chain_id);
661 ecx.tx.caller = caller;
662 ecx.tx.kind = kind;
663 ecx.tx.data = input;
664 ecx.tx.value = value;
665 ecx.tx.gas_limit = gas_limit + 21000;
667
668 if !ecx.cfg.disable_block_gas_limit {
671 ecx.tx.gas_limit = std::cmp::min(ecx.tx.gas_limit, ecx.block.gas_limit);
672 }
673 ecx.tx.gas_price = 0;
674
675 self.inner_context_data = Some(InnerContextData { original_origin: cached_env.tx.caller });
676 self.in_inner_context = true;
677
678 let res = self.with_inspector(|inspector| {
679 let (db, journal, env) = ecx.as_db_env_and_journal();
680 let mut evm = new_evm_with_inspector(db, env.to_owned(), inspector);
681
682 evm.journaled_state.state = {
683 let mut state = journal.state.clone();
684
685 for (addr, acc_mut) in &mut state {
686 if journal.warm_addresses.is_cold(addr) {
688 acc_mut.mark_cold();
689 }
690
691 for slot_mut in acc_mut.storage.values_mut() {
693 slot_mut.is_cold = true;
694 slot_mut.original_value = slot_mut.present_value;
695 }
696 }
697
698 state
699 };
700
701 evm.journaled_state.depth = 1;
703
704 let res = evm.transact(env.tx.clone());
705
706 *env.cfg = evm.cfg.clone();
708 *env.block = evm.block.clone();
709
710 *env.tx = cached_env.tx;
711 env.block.basefee = cached_env.evm_env.block_env.basefee;
712
713 res
714 });
715
716 self.in_inner_context = false;
717 self.inner_context_data = None;
718
719 let mut gas = Gas::new(gas_limit);
720
721 let Ok(res) = res else {
722 let result =
724 InterpreterResult { result: InstructionResult::Revert, output: Bytes::new(), gas };
725 return (result, None);
726 };
727
728 for (addr, mut acc) in res.state {
729 let Some(acc_mut) = ecx.journaled_state.state.get_mut(&addr) else {
730 ecx.journaled_state.state.insert(addr, acc);
731 continue;
732 };
733
734 if acc.status.contains(AccountStatus::Cold)
736 && !acc_mut.status.contains(AccountStatus::Cold)
737 {
738 acc.status -= AccountStatus::Cold;
739 }
740 acc_mut.info = acc.info;
741 acc_mut.status |= acc.status;
742
743 for (key, val) in acc.storage {
744 let Some(slot_mut) = acc_mut.storage.get_mut(&key) else {
745 acc_mut.storage.insert(key, val);
746 continue;
747 };
748 slot_mut.present_value = val.present_value;
749 slot_mut.is_cold &= val.is_cold;
750 }
751 }
752
753 let (result, address, output) = match res.result {
754 ExecutionResult::Success { reason, gas_used, gas_refunded, logs: _, output } => {
755 gas.set_refund(gas_refunded as i64);
756 let _ = gas.record_cost(gas_used);
757 let address = match output {
758 Output::Create(_, address) => address,
759 Output::Call(_) => None,
760 };
761 (reason.into(), address, output.into_data())
762 }
763 ExecutionResult::Halt { reason, gas_used } => {
764 let _ = gas.record_cost(gas_used);
765 (reason.into(), None, Bytes::new())
766 }
767 ExecutionResult::Revert { gas_used, output } => {
768 let _ = gas.record_cost(gas_used);
769 (InstructionResult::Revert, None, output)
770 }
771 };
772 (InterpreterResult { result, output, gas }, address)
773 }
774
775 fn with_inspector<O>(&mut self, f: impl FnOnce(InspectorStackRefMut<'_>) -> O) -> O {
778 let mut cheatcodes = self
779 .cheatcodes
780 .as_deref_mut()
781 .map(|cheats| core::mem::replace(cheats, Cheatcodes::new(cheats.config.clone())));
782 let mut inner = std::mem::take(self.inner);
783
784 let out = f(InspectorStackRefMut { cheatcodes: cheatcodes.as_mut(), inner: &mut inner });
785
786 if let Some(cheats) = self.cheatcodes.as_deref_mut() {
787 *cheats = cheatcodes.unwrap();
788 }
789
790 *self.inner = inner;
791
792 out
793 }
794
795 fn top_level_frame_start(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>) {
797 if self.enable_isolation {
798 self.top_frame_journal.clone_from(&ecx.journaled_state.state);
801 }
802 }
803
804 fn top_level_frame_end(
806 &mut self,
807 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
808 result: InstructionResult,
809 ) {
810 if !result.is_revert() {
811 return;
812 }
813 if let Some(cheats) = self.cheatcodes.as_mut() {
817 cheats.on_revert(ecx);
818 }
819
820 if self.enable_isolation {
824 ecx.journaled_state.state = std::mem::take(&mut self.top_frame_journal);
825 }
826 }
827
828 #[inline(always)]
834 fn step_inlined(
835 &mut self,
836 interpreter: &mut Interpreter,
837 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
838 ) {
839 call_inspectors!(
840 [
841 &mut self.edge_coverage,
843 &mut self.fuzzer,
844 &mut self.line_coverage,
845 &mut self.printer,
846 &mut self.revert_diag,
847 &mut self.script_execution_inspector,
848 &mut self.tracer,
849 &mut self.cheatcodes,
851 ],
852 |inspector| (**inspector).step(interpreter, ecx),
853 );
854 }
855
856 #[inline(always)]
857 fn step_end_inlined(
858 &mut self,
859 interpreter: &mut Interpreter,
860 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
861 ) {
862 call_inspectors!(
863 [
864 &mut self.chisel_state,
866 &mut self.printer,
867 &mut self.revert_diag,
868 &mut self.tracer,
869 &mut self.cheatcodes,
871 ],
872 |inspector| (**inspector).step_end(interpreter, ecx),
873 );
874 }
875}
876
877impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for InspectorStackRefMut<'_> {
878 fn initialize_interp(
879 &mut self,
880 interpreter: &mut Interpreter,
881 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
882 ) {
883 call_inspectors!(
884 [
885 &mut self.line_coverage,
886 &mut self.tracer,
887 &mut self.cheatcodes,
888 &mut self.script_execution_inspector,
889 &mut self.printer
890 ],
891 |inspector| inspector.initialize_interp(interpreter, ecx),
892 );
893 }
894
895 fn step(
896 &mut self,
897 interpreter: &mut Interpreter,
898 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
899 ) {
900 self.step_inlined(interpreter, ecx);
901 }
902
903 fn step_end(
904 &mut self,
905 interpreter: &mut Interpreter,
906 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
907 ) {
908 self.step_end_inlined(interpreter, ecx);
909 }
910
911 #[allow(clippy::redundant_clone)]
912 fn log(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, log: Log) {
913 call_inspectors!(
914 [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],
915 |inspector| inspector.log(ecx, log.clone()),
916 );
917 }
918
919 #[allow(clippy::redundant_clone)]
920 fn log_full(
921 &mut self,
922 interpreter: &mut Interpreter,
923 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
924 log: Log,
925 ) {
926 call_inspectors!(
927 [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],
928 |inspector| inspector.log_full(interpreter, ecx, log.clone()),
929 );
930 }
931
932 fn call(
933 &mut self,
934 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
935 call: &mut CallInputs,
936 ) -> Option<CallOutcome> {
937 if self.in_inner_context && ecx.journaled_state.depth == 1 {
938 self.adjust_evm_data_for_inner_context(ecx);
939 return None;
940 }
941
942 if ecx.journaled_state.depth == 0 {
943 self.top_level_frame_start(ecx);
944 }
945
946 call_inspectors!(
947 #[ret]
948 [
949 &mut self.fuzzer,
950 &mut self.tracer,
951 &mut self.log_collector,
952 &mut self.printer,
953 &mut self.revert_diag
954 ],
955 |inspector| {
956 let mut out = None;
957 if let Some(output) = inspector.call(ecx, call) {
958 out = Some(Some(output));
959 }
960 out
961 },
962 );
963
964 if let Some(cheatcodes) = self.cheatcodes.as_deref_mut() {
965 if let Some(mocks) = cheatcodes.mocked_functions.get(&call.target_address) {
967 if let Some(target) = mocks.get(&call.input.bytes(ecx)).or_else(|| {
970 call.input.bytes(ecx).get(..4).and_then(|selector| mocks.get(selector))
971 }) {
972 call.bytecode_address = *target;
973 call.known_bytecode = None;
974 }
975 }
976
977 if let Some(output) = cheatcodes.call_with_executor(ecx, call, self.inner) {
978 return Some(output);
979 }
980 }
981
982 if self.enable_isolation && !self.in_inner_context && ecx.journaled_state.depth == 1 {
983 match call.scheme {
984 CallScheme::Call => {
986 let input = call.input.bytes(ecx);
987 let (result, _) = self.transact_inner(
988 ecx,
989 TxKind::Call(call.target_address),
990 call.caller,
991 input,
992 call.gas_limit,
993 call.value.get(),
994 );
995 return Some(CallOutcome {
996 result,
997 memory_offset: call.return_memory_offset.clone(),
998 was_precompile_called: true,
999 precompile_call_logs: vec![],
1000 });
1001 }
1002 CallScheme::StaticCall => {
1004 let JournaledState { state, warm_addresses, .. } =
1005 &mut ecx.journaled_state.inner;
1006 for (addr, acc_mut) in state {
1007 if let Some(cheatcodes) = &self.cheatcodes
1009 && cheatcodes.has_arbitrary_storage(addr)
1010 {
1011 continue;
1012 }
1013
1014 if warm_addresses.is_cold(addr) {
1015 acc_mut.mark_cold();
1016 }
1017
1018 for slot_mut in acc_mut.storage.values_mut() {
1019 slot_mut.is_cold = true;
1020 }
1021 }
1022 }
1023 CallScheme::CallCode | CallScheme::DelegateCall => {}
1025 }
1026 }
1027
1028 None
1029 }
1030
1031 fn call_end(
1032 &mut self,
1033 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1034 inputs: &CallInputs,
1035 outcome: &mut CallOutcome,
1036 ) {
1037 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1040 return;
1041 }
1042
1043 self.do_call_end(ecx, inputs, outcome);
1044
1045 if ecx.journaled_state.depth == 0 {
1046 self.top_level_frame_end(ecx, outcome.result.result);
1047 }
1048 }
1049
1050 fn create(
1051 &mut self,
1052 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1053 create: &mut CreateInputs,
1054 ) -> Option<CreateOutcome> {
1055 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1056 self.adjust_evm_data_for_inner_context(ecx);
1057 return None;
1058 }
1059
1060 if ecx.journaled_state.depth == 0 {
1061 self.top_level_frame_start(ecx);
1062 }
1063
1064 call_inspectors!(
1065 #[ret]
1066 [&mut self.tracer, &mut self.line_coverage, &mut self.cheatcodes],
1067 |inspector| inspector.create(ecx, create).map(Some),
1068 );
1069
1070 if !matches!(create.scheme, CreateScheme::Create2 { .. })
1071 && self.enable_isolation
1072 && !self.in_inner_context
1073 && ecx.journaled_state.depth == 1
1074 {
1075 let (result, address) = self.transact_inner(
1076 ecx,
1077 TxKind::Create,
1078 create.caller,
1079 create.init_code.clone(),
1080 create.gas_limit,
1081 create.value,
1082 );
1083 return Some(CreateOutcome { result, address });
1084 }
1085
1086 None
1087 }
1088
1089 fn create_end(
1090 &mut self,
1091 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1092 call: &CreateInputs,
1093 outcome: &mut CreateOutcome,
1094 ) {
1095 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1098 return;
1099 }
1100
1101 self.do_create_end(ecx, call, outcome);
1102
1103 if ecx.journaled_state.depth == 0 {
1104 self.top_level_frame_end(ecx, outcome.result.result);
1105 }
1106 }
1107
1108 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1109 call_inspectors!([&mut self.printer], |inspector| Inspector::<
1110 EthEvmContext<&mut dyn DatabaseExt>,
1111 >::selfdestruct(
1112 inspector, contract, target, value,
1113 ));
1114 }
1115}
1116
1117impl InspectorExt for InspectorStackRefMut<'_> {
1118 fn should_use_create2_factory(
1119 &mut self,
1120 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1121 inputs: &CreateInputs,
1122 ) -> bool {
1123 call_inspectors!(
1124 #[ret]
1125 [&mut self.cheatcodes],
1126 |inspector| { inspector.should_use_create2_factory(ecx, inputs).then_some(true) },
1127 );
1128
1129 false
1130 }
1131
1132 fn console_log(&mut self, msg: &str) {
1133 call_inspectors!([&mut self.log_collector], |inspector| InspectorExt::console_log(
1134 inspector, msg
1135 ));
1136 }
1137
1138 fn get_networks(&self) -> NetworkConfigs {
1139 self.inner.networks
1140 }
1141
1142 fn create2_deployer(&self) -> Address {
1143 self.inner.create2_deployer
1144 }
1145}
1146
1147impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for InspectorStack {
1148 fn step(
1149 &mut self,
1150 interpreter: &mut Interpreter,
1151 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1152 ) {
1153 self.as_mut().step_inlined(interpreter, ecx)
1154 }
1155
1156 fn step_end(
1157 &mut self,
1158 interpreter: &mut Interpreter,
1159 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1160 ) {
1161 self.as_mut().step_end_inlined(interpreter, ecx)
1162 }
1163
1164 fn call(
1165 &mut self,
1166 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1167 inputs: &mut CallInputs,
1168 ) -> Option<CallOutcome> {
1169 self.as_mut().call(context, inputs)
1170 }
1171
1172 fn call_end(
1173 &mut self,
1174 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1175 inputs: &CallInputs,
1176 outcome: &mut CallOutcome,
1177 ) {
1178 self.as_mut().call_end(context, inputs, outcome)
1179 }
1180
1181 fn create(
1182 &mut self,
1183 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1184 create: &mut CreateInputs,
1185 ) -> Option<CreateOutcome> {
1186 self.as_mut().create(context, create)
1187 }
1188
1189 fn create_end(
1190 &mut self,
1191 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1192 call: &CreateInputs,
1193 outcome: &mut CreateOutcome,
1194 ) {
1195 self.as_mut().create_end(context, call, outcome)
1196 }
1197
1198 fn initialize_interp(
1199 &mut self,
1200 interpreter: &mut Interpreter,
1201 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1202 ) {
1203 self.as_mut().initialize_interp(interpreter, ecx)
1204 }
1205
1206 fn log(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, log: Log) {
1207 self.as_mut().log(ecx, log)
1208 }
1209
1210 fn log_full(
1211 &mut self,
1212 interpreter: &mut Interpreter,
1213 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1214 log: Log,
1215 ) {
1216 self.as_mut().log_full(interpreter, ecx, log)
1217 }
1218
1219 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1220 self.as_mut().selfdestruct(contract, target, value);
1221 }
1222}
1223
1224impl InspectorExt for InspectorStack {
1225 fn should_use_create2_factory(
1226 &mut self,
1227 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1228 inputs: &CreateInputs,
1229 ) -> bool {
1230 self.as_mut().should_use_create2_factory(ecx, inputs)
1231 }
1232
1233 fn get_networks(&self) -> NetworkConfigs {
1234 self.networks
1235 }
1236
1237 fn create2_deployer(&self) -> Address {
1238 self.create2_deployer
1239 }
1240}
1241
1242impl<'a> Deref for InspectorStackRefMut<'a> {
1243 type Target = &'a mut InspectorStackInner;
1244
1245 fn deref(&self) -> &Self::Target {
1246 &self.inner
1247 }
1248}
1249
1250impl DerefMut for InspectorStackRefMut<'_> {
1251 fn deref_mut(&mut self) -> &mut Self::Target {
1252 &mut self.inner
1253 }
1254}
1255
1256impl Deref for InspectorStack {
1257 type Target = InspectorStackInner;
1258
1259 fn deref(&self) -> &Self::Target {
1260 &self.inner
1261 }
1262}
1263
1264impl DerefMut for InspectorStack {
1265 fn deref_mut(&mut self) -> &mut Self::Target {
1266 &mut self.inner
1267 }
1268}