foundry_evm/executors/
strategy.rs1use std::{any::Any, fmt::Debug};
2
3use alloy_primitives::{Address, U256};
4use eyre::Result;
5use foundry_cheatcodes::CheatcodesStrategy;
6use foundry_compilers::{
7 ProjectCompileOutput, compilers::resolc::dual_compiled_contracts::DualCompiledContracts,
8};
9use foundry_evm_core::{
10 Env,
11 backend::{Backend, BackendResult, BackendStrategy, CowBackend},
12};
13use revm::{DatabaseRef, context::result::ResultAndState};
14
15use crate::inspectors::InspectorStack;
16
17use super::Executor;
18
19pub trait ExecutorStrategyContext: Debug + Send + Sync + Any {
21 fn new_cloned(&self) -> Box<dyn ExecutorStrategyContext>;
23 fn as_any_ref(&self) -> &dyn Any;
25 fn as_any_mut(&mut self) -> &mut dyn Any;
27}
28
29impl Clone for Box<dyn ExecutorStrategyContext> {
30 fn clone(&self) -> Self {
31 self.new_cloned()
32 }
33}
34
35impl ExecutorStrategyContext for () {
37 fn new_cloned(&self) -> Box<dyn ExecutorStrategyContext> {
38 Box::new(())
39 }
40
41 fn as_any_ref(&self) -> &dyn Any {
42 self
43 }
44
45 fn as_any_mut(&mut self) -> &mut dyn Any {
46 self
47 }
48}
49
50pub trait ExecutorStrategyRunner: Debug + Send + Sync + ExecutorStrategyExt {
52 fn new_backend_strategy(&self, ctx: &dyn ExecutorStrategyContext) -> BackendStrategy;
54
55 fn new_cheatcodes_strategy(&self, ctx: &dyn ExecutorStrategyContext) -> CheatcodesStrategy;
57
58 fn set_balance(
60 &self,
61 executor: &mut Executor,
62 address: Address,
63 amount: U256,
64 ) -> BackendResult<()>;
65
66 fn get_balance(&self, executor: &mut Executor, address: Address) -> BackendResult<U256>;
68
69 fn set_nonce(&self, executor: &mut Executor, address: Address, nonce: u64)
71 -> BackendResult<()>;
72
73 fn get_nonce(&self, executor: &mut Executor, address: Address) -> BackendResult<u64>;
75
76 fn call(
78 &self,
79 ctx: &dyn ExecutorStrategyContext,
80 backend: &mut CowBackend<'_>,
81 env: &mut Env,
82 executor_env: &Env,
83 inspector: &mut InspectorStack,
84 ) -> Result<ResultAndState>;
85
86 fn transact(
88 &self,
89 ctx: &mut dyn ExecutorStrategyContext,
90 backend: &mut Backend,
91 env: &mut Env,
92 executor_env: &Env,
93 inspector: &mut InspectorStack,
94 ) -> Result<ResultAndState>;
95}
96
97pub trait ExecutorStrategyExt {
99 fn revive_set_dual_compiled_contracts(
101 &self,
102 _ctx: &mut dyn ExecutorStrategyContext,
103 _dual_compiled_contracts: DualCompiledContracts,
104 ) {
105 }
106
107 fn revive_set_compilation_output(
108 &self,
109 _ctx: &mut dyn ExecutorStrategyContext,
110 _output: ProjectCompileOutput,
111 ) {
112 }
113
114 fn start_transaction(&self, _ctx: &dyn ExecutorStrategyContext) {}
115 fn rollback_transaction(&self, _ctx: &dyn ExecutorStrategyContext) {}
116}
117
118#[derive(Debug, Default, Clone)]
120pub struct EvmExecutorStrategyRunner;
121
122impl ExecutorStrategyRunner for EvmExecutorStrategyRunner {
123 fn set_balance(
124 &self,
125 executor: &mut Executor,
126 address: Address,
127 amount: U256,
128 ) -> BackendResult<()> {
129 let mut account = executor.backend().basic_ref(address)?.unwrap_or_default();
130 account.balance = amount;
131 executor.backend_mut().insert_account_info(address, account);
132 Ok(())
133 }
134
135 fn get_balance(&self, executor: &mut Executor, address: Address) -> BackendResult<U256> {
136 Ok(executor.backend().basic_ref(address)?.map(|acc| acc.balance).unwrap_or_default())
137 }
138
139 fn set_nonce(
140 &self,
141 executor: &mut Executor,
142 address: Address,
143 nonce: u64,
144 ) -> BackendResult<()> {
145 let mut account = executor.backend().basic_ref(address)?.unwrap_or_default();
146 account.nonce = nonce;
147 executor.backend_mut().insert_account_info(address, account);
148 Ok(())
149 }
150
151 fn get_nonce(&self, executor: &mut Executor, address: Address) -> BackendResult<u64> {
152 Ok(executor.backend().basic_ref(address)?.map(|acc| acc.nonce).unwrap_or_default())
153 }
154
155 fn call(
156 &self,
157 _ctx: &dyn ExecutorStrategyContext,
158 backend: &mut CowBackend<'_>,
159 env: &mut Env,
160 _executor_env: &Env,
161 inspector: &mut InspectorStack,
162 ) -> Result<ResultAndState> {
163 backend.inspect(env, inspector, Box::new(()))
164 }
165
166 fn transact(
167 &self,
168 _ctx: &mut dyn ExecutorStrategyContext,
169 backend: &mut Backend,
170 env: &mut Env,
171 _executor_env: &Env,
172 inspector: &mut InspectorStack,
173 ) -> Result<ResultAndState> {
174 backend.inspect(env, inspector, Box::new(()))
175 }
176
177 fn new_backend_strategy(&self, _ctx: &dyn ExecutorStrategyContext) -> BackendStrategy {
178 BackendStrategy::new_evm()
179 }
180
181 fn new_cheatcodes_strategy(&self, _ctx: &dyn ExecutorStrategyContext) -> CheatcodesStrategy {
182 CheatcodesStrategy::new_evm()
183 }
184}
185
186impl ExecutorStrategyExt for EvmExecutorStrategyRunner {}
187
188#[derive(Debug)]
190pub struct ExecutorStrategy {
191 pub runner: &'static dyn ExecutorStrategyRunner,
193 pub context: Box<dyn ExecutorStrategyContext>,
195}
196
197impl ExecutorStrategy {
198 pub fn new_evm() -> Self {
200 Self { runner: &EvmExecutorStrategyRunner, context: Box::new(()) }
201 }
202}
203
204impl Clone for ExecutorStrategy {
205 fn clone(&self) -> Self {
206 Self { runner: self.runner, context: self.context.clone() }
207 }
208}