1use super::*;
2
3pub type TempoRevmEvm<'db, I> = tempo_revm::TempoEvm<&'db mut dyn DatabaseExt<TempoEvmFactory>, I>;
5
6pub struct TempoFoundryEvm<
12 'db,
13 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
14> {
15 pub inner: TempoRevmEvm<'db, I>,
16}
17
18pub(crate) fn initialize_tempo_evm<
27 'db,
28 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
29>(
30 evm: &mut TempoFoundryEvm<'db, I>,
31 is_forked: bool,
32) {
33 let ctx = &mut evm.inner.inner.ctx;
34 StorageCtx::enter_evm(&mut ctx.journaled_state, &ctx.block, &ctx.cfg, &ctx.tx, || {
35 if is_forked {
36 let mut sctx = StorageCtx;
38 let sentinel = Bytecode::new_legacy(Bytes::from_static(&[0xef]));
39 for addr in TEMPO_PRECOMPILE_ADDRESSES.iter().chain(TEMPO_TIP20_TOKENS.iter()) {
40 sctx.set_code(*addr, sentinel.clone())
41 .expect("failed to warm tempo precompile address");
42 }
43 } else {
44 initialize_tempo_genesis_inner(TEST_CONTRACT_ADDRESS, CALLER)
46 .expect("tempo genesis initialization failed");
47 }
48 });
49}
50
51impl FoundryEvmFactory for TempoEvmFactory {
52 type FoundryContext<'db> = TempoContext<&'db mut dyn DatabaseExt<Self>>;
53
54 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> =
55 TempoFoundryEvm<'db, I>;
56
57 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
58 &self,
59 db: &'db mut dyn DatabaseExt<Self>,
60 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
61 inspector: I,
62 ) -> Self::FoundryEvm<'db, I> {
63 let is_forked = db.is_forked_mode();
64 let spec = *evm_env.spec_id();
65 let tempo_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
66 let mut inner = tempo_evm.into_inner();
67 inner.ctx.cfg.gas_params = tempo_gas_params(spec);
68 inner.ctx.cfg.tx_chain_id_check = true;
69 if inner.ctx.cfg.tx_gas_limit_cap.is_none() {
70 inner.ctx.cfg.tx_gas_limit_cap = spec.tx_gas_limit_cap();
71 }
72
73 let mut evm = TempoFoundryEvm { inner };
74 let networks = Evm::inspector(&evm).get_networks();
75 networks.inject_precompiles(evm.precompiles_mut());
76
77 initialize_tempo_evm(&mut evm, is_forked);
78 evm
79 }
80
81 fn create_foundry_nested_evm<'db>(
82 &self,
83 db: &'db mut dyn DatabaseExt<Self>,
84 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
85 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
86 ) -> Box<dyn NestedEvm<Spec = TempoHardfork, Block = TempoBlockEnv, Tx = TempoTxEnv> + 'db>
87 {
88 Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).inner)
89 }
90}
91
92impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Evm
93 for TempoFoundryEvm<'db, I>
94{
95 type Precompiles = PrecompilesMap;
96 type Inspector = I;
97 type DB = &'db mut dyn DatabaseExt<TempoEvmFactory>;
98 type Error = EVMError<DatabaseError, TempoInvalidTransaction>;
99 type HaltReason = TempoHaltReason;
100 type Spec = TempoHardfork;
101 type Tx = TempoTxEnv;
102 type BlockEnv = TempoBlockEnv;
103
104 fn block(&self) -> &TempoBlockEnv {
105 &self.inner.block
106 }
107
108 fn chain_id(&self) -> u64 {
109 self.inner.ctx.cfg.chain_id
110 }
111
112 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
113 let evm = &self.inner.inner;
114 (&evm.ctx.journaled_state.database, &evm.inspector, &evm.precompiles)
115 }
116
117 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
118 let evm = &mut self.inner.inner;
119 (&mut evm.ctx.journaled_state.database, &mut evm.inspector, &mut evm.precompiles)
120 }
121
122 fn set_inspector_enabled(&mut self, _enabled: bool) {
123 unimplemented!("TempoFoundryEvm is always inspecting")
124 }
125
126 fn transact_raw(
127 &mut self,
128 tx: Self::Tx,
129 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
130 self.inner.set_tx(tx);
131
132 let mut handler = TempoEvmHandler::new();
133 let result = handler.inspect_run(&mut self.inner)?;
134
135 Ok(ResultAndState::new(result, self.inner.inner.ctx.journaled_state.inner.state.clone()))
136 }
137
138 fn transact_system_call(
139 &mut self,
140 _caller: Address,
141 _contract: Address,
142 _data: Bytes,
143 ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
144 unimplemented!()
145 }
146
147 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec, Self::BlockEnv>)
148 where
149 Self: Sized,
150 {
151 let revm_evm = self.inner.inner;
152 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = revm_evm.ctx;
153 (journaled_state.database, EvmEnv { block_env, cfg_env })
154 }
155}
156
157impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Deref
158 for TempoFoundryEvm<'db, I>
159{
160 type Target = TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>;
161
162 fn deref(&self) -> &Self::Target {
163 &self.inner.ctx
164 }
165}
166
167impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> DerefMut
168 for TempoFoundryEvm<'db, I>
169{
170 fn deref_mut(&mut self) -> &mut Self::Target {
171 &mut self.inner.ctx
172 }
173}
174
175pub(crate) fn map_tempo_error(
180 e: EVMError<DatabaseError, TempoInvalidTransaction>,
181) -> EVMError<DatabaseError> {
182 match e {
183 EVMError::Database(db) => EVMError::Database(db),
184 EVMError::Header(h) => EVMError::Header(h),
185 EVMError::Custom(s) => EVMError::Custom(s),
186 EVMError::CustomAny(custom_any_error) => EVMError::CustomAny(custom_any_error),
187 EVMError::Transaction(t) => match t {
188 TempoInvalidTransaction::EthInvalidTransaction(eth) => EVMError::Transaction(eth),
189 t => EVMError::Custom(format!("tempo transaction error: {t}")),
190 },
191 }
192}
193
194impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> NestedEvm
195 for TempoRevmEvm<'db, I>
196{
197 type Spec = TempoHardfork;
198 type Block = TempoBlockEnv;
199 type Tx = TempoTxEnv;
200
201 fn journal_inner_mut(&mut self) -> &mut JournaledState {
202 &mut self.ctx_mut().journaled_state.inner
203 }
204
205 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
206 let mut handler = TempoEvmHandler::new();
207
208 let memory =
209 SharedMemory::new_with_buffer(self.ctx().local().shared_memory_buffer().clone());
210 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
211
212 let mut frame_result =
213 handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_tempo_error)?;
214
215 handler.last_frame_result(self, &mut frame_result).map_err(map_tempo_error)?;
216
217 Ok(frame_result)
218 }
219
220 fn transact_raw(
221 &mut self,
222 tx: Self::Tx,
223 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
224 self.set_tx(tx);
225
226 let mut handler = TempoEvmHandler::new();
227 let result = handler.inspect_run(self).map_err(map_tempo_error)?;
228
229 let result = result.map_haltreason(|h| match h {
230 TempoHaltReason::Ethereum(eth) => eth,
231 _ => HaltReason::PrecompileError,
232 });
233
234 Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
235 }
236
237 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
238 self.ctx_ref().evm_clone()
239 }
240}