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.bytecode_address) {
967 let input_bytes = call.input.bytes(ecx);
968 if let Some(target) = mocks
971 .get(&input_bytes)
972 .or_else(|| input_bytes.get(..4).and_then(|selector| mocks.get(selector)))
973 {
974 call.bytecode_address = *target;
975 call.known_bytecode = None;
976 }
977 }
978
979 if let Some(output) = cheatcodes.call_with_executor(ecx, call, self.inner) {
980 return Some(output);
981 }
982 }
983
984 if self.enable_isolation && !self.in_inner_context && ecx.journaled_state.depth == 1 {
985 match call.scheme {
986 CallScheme::Call => {
988 let input = call.input.bytes(ecx);
989 let (result, _) = self.transact_inner(
990 ecx,
991 TxKind::Call(call.target_address),
992 call.caller,
993 input,
994 call.gas_limit,
995 call.value.get(),
996 );
997 return Some(CallOutcome {
998 result,
999 memory_offset: call.return_memory_offset.clone(),
1000 was_precompile_called: true,
1001 precompile_call_logs: vec![],
1002 });
1003 }
1004 CallScheme::StaticCall => {
1006 let JournaledState { state, warm_addresses, .. } =
1007 &mut ecx.journaled_state.inner;
1008 for (addr, acc_mut) in state {
1009 if let Some(cheatcodes) = &self.cheatcodes
1011 && cheatcodes.has_arbitrary_storage(addr)
1012 {
1013 continue;
1014 }
1015
1016 if warm_addresses.is_cold(addr) {
1017 acc_mut.mark_cold();
1018 }
1019
1020 for slot_mut in acc_mut.storage.values_mut() {
1021 slot_mut.is_cold = true;
1022 }
1023 }
1024 }
1025 CallScheme::CallCode | CallScheme::DelegateCall => {}
1027 }
1028 }
1029
1030 None
1031 }
1032
1033 fn call_end(
1034 &mut self,
1035 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1036 inputs: &CallInputs,
1037 outcome: &mut CallOutcome,
1038 ) {
1039 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1042 return;
1043 }
1044
1045 self.do_call_end(ecx, inputs, outcome);
1046
1047 if ecx.journaled_state.depth == 0 {
1048 self.top_level_frame_end(ecx, outcome.result.result);
1049 }
1050 }
1051
1052 fn create(
1053 &mut self,
1054 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1055 create: &mut CreateInputs,
1056 ) -> Option<CreateOutcome> {
1057 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1058 self.adjust_evm_data_for_inner_context(ecx);
1059 return None;
1060 }
1061
1062 if ecx.journaled_state.depth == 0 {
1063 self.top_level_frame_start(ecx);
1064 }
1065
1066 call_inspectors!(
1067 #[ret]
1068 [&mut self.tracer, &mut self.line_coverage, &mut self.cheatcodes],
1069 |inspector| inspector.create(ecx, create).map(Some),
1070 );
1071
1072 if !matches!(create.scheme(), CreateScheme::Create2 { .. })
1073 && self.enable_isolation
1074 && !self.in_inner_context
1075 && ecx.journaled_state.depth == 1
1076 {
1077 let (result, address) = self.transact_inner(
1078 ecx,
1079 TxKind::Create,
1080 create.caller(),
1081 create.init_code().clone(),
1082 create.gas_limit(),
1083 create.value(),
1084 );
1085 return Some(CreateOutcome { result, address });
1086 }
1087
1088 None
1089 }
1090
1091 fn create_end(
1092 &mut self,
1093 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1094 call: &CreateInputs,
1095 outcome: &mut CreateOutcome,
1096 ) {
1097 if self.in_inner_context && ecx.journaled_state.depth == 1 {
1100 return;
1101 }
1102
1103 self.do_create_end(ecx, call, outcome);
1104
1105 if ecx.journaled_state.depth == 0 {
1106 self.top_level_frame_end(ecx, outcome.result.result);
1107 }
1108 }
1109
1110 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1111 call_inspectors!([&mut self.printer], |inspector| Inspector::<
1112 EthEvmContext<&mut dyn DatabaseExt>,
1113 >::selfdestruct(
1114 inspector, contract, target, value,
1115 ));
1116 }
1117}
1118
1119impl InspectorExt for InspectorStackRefMut<'_> {
1120 fn should_use_create2_factory(
1121 &mut self,
1122 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1123 inputs: &CreateInputs,
1124 ) -> bool {
1125 call_inspectors!(
1126 #[ret]
1127 [&mut self.cheatcodes],
1128 |inspector| { inspector.should_use_create2_factory(ecx, inputs).then_some(true) },
1129 );
1130
1131 false
1132 }
1133
1134 fn console_log(&mut self, msg: &str) {
1135 call_inspectors!([&mut self.log_collector], |inspector| InspectorExt::console_log(
1136 inspector, msg
1137 ));
1138 }
1139
1140 fn get_networks(&self) -> NetworkConfigs {
1141 self.inner.networks
1142 }
1143
1144 fn create2_deployer(&self) -> Address {
1145 self.inner.create2_deployer
1146 }
1147}
1148
1149impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for InspectorStack {
1150 fn step(
1151 &mut self,
1152 interpreter: &mut Interpreter,
1153 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1154 ) {
1155 self.as_mut().step_inlined(interpreter, ecx)
1156 }
1157
1158 fn step_end(
1159 &mut self,
1160 interpreter: &mut Interpreter,
1161 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1162 ) {
1163 self.as_mut().step_end_inlined(interpreter, ecx)
1164 }
1165
1166 fn call(
1167 &mut self,
1168 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1169 inputs: &mut CallInputs,
1170 ) -> Option<CallOutcome> {
1171 self.as_mut().call(context, inputs)
1172 }
1173
1174 fn call_end(
1175 &mut self,
1176 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1177 inputs: &CallInputs,
1178 outcome: &mut CallOutcome,
1179 ) {
1180 self.as_mut().call_end(context, inputs, outcome)
1181 }
1182
1183 fn create(
1184 &mut self,
1185 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1186 create: &mut CreateInputs,
1187 ) -> Option<CreateOutcome> {
1188 self.as_mut().create(context, create)
1189 }
1190
1191 fn create_end(
1192 &mut self,
1193 context: &mut EthEvmContext<&mut dyn DatabaseExt>,
1194 call: &CreateInputs,
1195 outcome: &mut CreateOutcome,
1196 ) {
1197 self.as_mut().create_end(context, call, outcome)
1198 }
1199
1200 fn initialize_interp(
1201 &mut self,
1202 interpreter: &mut Interpreter,
1203 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1204 ) {
1205 self.as_mut().initialize_interp(interpreter, ecx)
1206 }
1207
1208 fn log(&mut self, ecx: &mut EthEvmContext<&mut dyn DatabaseExt>, log: Log) {
1209 self.as_mut().log(ecx, log)
1210 }
1211
1212 fn log_full(
1213 &mut self,
1214 interpreter: &mut Interpreter,
1215 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1216 log: Log,
1217 ) {
1218 self.as_mut().log_full(interpreter, ecx, log)
1219 }
1220
1221 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
1222 self.as_mut().selfdestruct(contract, target, value);
1223 }
1224}
1225
1226impl InspectorExt for InspectorStack {
1227 fn should_use_create2_factory(
1228 &mut self,
1229 ecx: &mut EthEvmContext<&mut dyn DatabaseExt>,
1230 inputs: &CreateInputs,
1231 ) -> bool {
1232 self.as_mut().should_use_create2_factory(ecx, inputs)
1233 }
1234
1235 fn get_networks(&self) -> NetworkConfigs {
1236 self.networks
1237 }
1238
1239 fn create2_deployer(&self) -> Address {
1240 self.create2_deployer
1241 }
1242}
1243
1244impl<'a> Deref for InspectorStackRefMut<'a> {
1245 type Target = &'a mut InspectorStackInner;
1246
1247 fn deref(&self) -> &Self::Target {
1248 &self.inner
1249 }
1250}
1251
1252impl DerefMut for InspectorStackRefMut<'_> {
1253 fn deref_mut(&mut self) -> &mut Self::Target {
1254 &mut self.inner
1255 }
1256}
1257
1258impl Deref for InspectorStack {
1259 type Target = InspectorStackInner;
1260
1261 fn deref(&self) -> &Self::Target {
1262 &self.inner
1263 }
1264}
1265
1266impl DerefMut for InspectorStack {
1267 fn deref_mut(&mut self) -> &mut Self::Target {
1268 &mut self.inner
1269 }
1270}