1use std::{
2 fmt::Debug,
3 marker::PhantomData,
4 ops::{Deref, DerefMut},
5};
6
7use crate::{
8 FoundryBlock, FoundryContextExt, FoundryInspectorExt, FoundryTransaction,
9 FromAnyRpcTransaction,
10 backend::{DatabaseExt, JournaledState},
11 constants::{CALLER, DEFAULT_CREATE2_DEPLOYER_CODEHASH, TEST_CONTRACT_ADDRESS},
12 tempo::{TEMPO_PRECOMPILE_ADDRESSES, TEMPO_TIP20_TOKENS, initialize_tempo_genesis_inner},
13};
14use alloy_consensus::{
15 SignableTransaction, Signed, constants::KECCAK_EMPTY, transaction::SignerRecoverable,
16};
17use alloy_evm::{
18 EthEvmFactory, Evm, EvmEnv, EvmFactory, FromRecoveredTx, eth::EthEvmContext,
19 precompiles::PrecompilesMap,
20};
21use alloy_network::{Ethereum, Network};
22use alloy_op_evm::OpEvmFactory;
23use alloy_primitives::{Address, Bytes, Signature, U256};
24use alloy_rlp::Decodable;
25use foundry_common::{FoundryReceiptResponse, FoundryTransactionBuilder, fmt::UIfmt};
26use foundry_config::FromEvmVersion;
27use foundry_fork_db::{DatabaseError, ForkBlockEnv};
28use op_alloy_network::Optimism;
29use op_revm::{
30 DefaultOp, OpBuilder, OpContext, OpHaltReason, OpSpecId, OpTransaction, handler::OpHandler,
31 precompiles::OpPrecompiles, transaction::error::OpTransactionError,
32};
33use revm::{
34 Context,
35 context::{
36 BlockEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContextTr, TxEnv,
37 result::{EVMError, ExecResultAndState, ExecutionResult, HaltReason, ResultAndState},
38 },
39 handler::{
40 EthFrame, EvmTr, FrameResult, FrameTr, Handler, ItemOrResult, instructions::EthInstructions,
41 },
42 inspector::{InspectorEvmTr, InspectorHandler},
43 interpreter::{
44 CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,
45 FrameInput, Gas, InstructionResult, InterpreterResult, SharedMemory,
46 interpreter::EthInterpreter, interpreter_action::FrameInit, return_ok,
47 },
48 primitives::hardfork::SpecId,
49 state::Bytecode,
50};
51use serde::{Deserialize, Serialize};
52use tempo_alloy::TempoNetwork;
53use tempo_chainspec::hardfork::TempoHardfork;
54use tempo_evm::evm::TempoEvmFactory;
55use tempo_precompiles::storage::StorageCtx;
56use tempo_revm::{
57 TempoBlockEnv, TempoHaltReason, TempoInvalidTransaction, TempoTxEnv, evm::TempoContext,
58 gas_params::tempo_gas_params, handler::TempoEvmHandler,
59};
60
61pub trait IntoInstructionResult {
63 fn into_instruction_result(self) -> InstructionResult;
64}
65
66impl IntoInstructionResult for HaltReason {
67 fn into_instruction_result(self) -> InstructionResult {
68 self.into()
69 }
70}
71
72impl IntoInstructionResult for OpHaltReason {
73 fn into_instruction_result(self) -> InstructionResult {
74 match self {
75 Self::Base(eth) => eth.into(),
76 Self::FailedDeposit => InstructionResult::Stop,
77 }
78 }
79}
80
81impl IntoInstructionResult for TempoHaltReason {
82 fn into_instruction_result(self) -> InstructionResult {
83 match self {
84 Self::Ethereum(eth) => eth.into(),
85 _ => InstructionResult::PrecompileError,
86 }
87 }
88}
89
90pub trait FoundryEvmNetwork: Copy + Debug + Default + 'static {
92 type Network: Network<
93 TxEnvelope: Decodable
94 + SignerRecoverable
95 + From<Signed<<Self::Network as Network>::UnsignedTx>>
96 + for<'d> Deserialize<'d>
97 + Serialize
98 + UIfmt,
99 UnsignedTx: SignableTransaction<Signature>,
100 TransactionRequest: FoundryTransactionBuilder<Self::Network>
101 + for<'d> Deserialize<'d>
102 + Serialize,
103 ReceiptResponse: FoundryReceiptResponse,
104 >;
105 type EvmFactory: FoundryEvmFactory<Tx: FromRecoveredTx<<Self::Network as Network>::TxEnvelope>>;
106}
107
108#[derive(Clone, Copy, Debug, Default)]
109pub struct EthEvmNetwork;
110impl FoundryEvmNetwork for EthEvmNetwork {
111 type Network = Ethereum;
112 type EvmFactory = EthEvmFactory;
113}
114
115#[derive(Clone, Copy, Debug, Default)]
116pub struct TempoEvmNetwork;
117impl FoundryEvmNetwork for TempoEvmNetwork {
118 type Network = TempoNetwork;
119 type EvmFactory = TempoEvmFactory;
120}
121
122#[derive(Clone, Copy, Debug, Default)]
123pub struct OpEvmNetwork;
124impl FoundryEvmNetwork for OpEvmNetwork {
125 type Network = Optimism;
126 type EvmFactory = OpEvmFactory;
127}
128
129pub type EvmFactoryFor<FEN> = <FEN as FoundryEvmNetwork>::EvmFactory;
131pub type FoundryContextFor<'db, FEN> =
132 <EvmFactoryFor<FEN> as FoundryEvmFactory>::FoundryContext<'db>;
133pub type TxEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Tx;
134pub type HaltReasonFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::HaltReason;
135pub type SpecFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Spec;
136pub type BlockEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::BlockEnv;
137pub type PrecompilesFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Precompiles;
138pub type EvmEnvFor<FEN> = EvmEnv<SpecFor<FEN>, BlockEnvFor<FEN>>;
139
140pub type NetworkFor<FEN> = <FEN as FoundryEvmNetwork>::Network;
141pub type TxEnvelopeFor<FEN> = <NetworkFor<FEN> as Network>::TxEnvelope;
142pub type TransactionRequestFor<FEN> = <NetworkFor<FEN> as Network>::TransactionRequest;
143pub type TransactionResponseFor<FEN> = <NetworkFor<FEN> as Network>::TransactionResponse;
144pub type BlockResponseFor<FEN> = <NetworkFor<FEN> as Network>::BlockResponse;
145
146pub trait FoundryEvmFactory:
147 EvmFactory<
148 Spec: Into<SpecId> + FromEvmVersion + Default + Copy + Unpin + Send + 'static,
149 BlockEnv: FoundryBlock + ForkBlockEnv + Default + Unpin,
150 Tx: Clone + Debug + FoundryTransaction + FromAnyRpcTransaction + Default + Send + Sync,
151 HaltReason: IntoInstructionResult,
152 Precompiles = PrecompilesMap,
153 > + Clone
154 + Debug
155 + Default
156 + 'static
157{
158 type FoundryContext<'db>: FoundryContextExt<
160 Block = Self::BlockEnv,
161 Tx = Self::Tx,
162 Spec = Self::Spec,
163 Db: DatabaseExt<Self>,
164 >
165 where
166 Self: 'db;
167
168 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>: Evm<
170 DB = &'db mut dyn DatabaseExt<Self>,
171 Tx = Self::Tx,
172 BlockEnv = Self::BlockEnv,
173 Spec = Self::Spec,
174 HaltReason = Self::HaltReason,
175 > + Deref<Target = Self::FoundryContext<'db>>
176 + IntoNestedEvm<Self::Spec, Self::BlockEnv, Self::Tx>
177 where
178 Self: 'db;
179
180 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
182 &self,
183 db: &'db mut dyn DatabaseExt<Self>,
184 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
185 inspector: I,
186 ) -> Self::FoundryEvm<'db, I>;
187
188 fn create_foundry_nested_evm<'db>(
195 &self,
196 db: &'db mut dyn DatabaseExt<Self>,
197 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
198 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
199 ) -> Box<dyn NestedEvm<Spec = Self::Spec, Block = Self::BlockEnv, Tx = Self::Tx> + 'db>;
200}
201
202impl FoundryEvmFactory for EthEvmFactory {
203 type FoundryContext<'db> = EthEvmContext<&'db mut dyn DatabaseExt<Self>>;
204
205 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> = EthFoundryEvm<'db, I>;
206
207 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
208 &self,
209 db: &'db mut dyn DatabaseExt<Self>,
210 evm_env: EvmEnv,
211 inspector: I,
212 ) -> Self::FoundryEvm<'db, I> {
213 let eth_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
214 let mut inner = eth_evm.into_inner();
215 inner.ctx.cfg.tx_chain_id_check = true;
216
217 let mut evm = EthFoundryEvm { inner };
218 evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());
219 evm
220 }
221
222 fn create_foundry_nested_evm<'db>(
223 &self,
224 db: &'db mut dyn DatabaseExt<Self>,
225 evm_env: EvmEnv,
226 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
227 ) -> Box<dyn NestedEvm<Spec = SpecId, Block = BlockEnv, Tx = TxEnv> + 'db> {
228 Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
229 }
230}
231
232fn get_create2_factory_call_inputs(
234 salt: U256,
235 inputs: &CreateInputs,
236 deployer: Address,
237) -> CallInputs {
238 let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code()[..]].concat();
239 CallInputs {
240 caller: inputs.caller(),
241 bytecode_address: deployer,
242 known_bytecode: None,
243 target_address: deployer,
244 scheme: CallScheme::Call,
245 value: CallValue::Transfer(inputs.value()),
246 input: CallInput::Bytes(calldata.into()),
247 gas_limit: inputs.gas_limit(),
248 is_static: false,
249 return_memory_offset: 0..0,
250 }
251}
252
253type EthRevmEvm<'db, I> = RevmEvm<
254 EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>,
255 I,
256 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
257 PrecompilesMap,
258 EthFrame<EthInterpreter>,
259>;
260
261pub struct EthFoundryEvm<
262 'db,
263 I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
264> {
265 pub inner: EthRevmEvm<'db, I>,
266}
267
268impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Evm
269 for EthFoundryEvm<'db, I>
270{
271 type Precompiles = PrecompilesMap;
272 type Inspector = I;
273 type DB = &'db mut dyn DatabaseExt<EthEvmFactory>;
274 type Error = EVMError<DatabaseError>;
275 type HaltReason = HaltReason;
276 type Spec = SpecId;
277 type Tx = TxEnv;
278 type BlockEnv = BlockEnv;
279
280 fn block(&self) -> &BlockEnv {
281 &self.inner.block
282 }
283
284 fn chain_id(&self) -> u64 {
285 self.inner.ctx.cfg.chain_id
286 }
287
288 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
289 (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)
290 }
291
292 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
293 (
294 &mut self.inner.ctx.journaled_state.database,
295 &mut self.inner.inspector,
296 &mut self.inner.precompiles,
297 )
298 }
299
300 fn set_inspector_enabled(&mut self, _enabled: bool) {
301 unimplemented!("FoundryEvm is always inspecting")
302 }
303
304 fn transact_raw(
305 &mut self,
306 tx: Self::Tx,
307 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
308 self.inner.set_tx(tx);
309
310 let mut handler = EthFoundryHandler::<I>::default();
311 let result = handler.inspect_run(&mut self.inner)?;
312
313 Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
314 }
315
316 fn transact_system_call(
317 &mut self,
318 _caller: Address,
319 _contract: Address,
320 _data: Bytes,
321 ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
322 unimplemented!()
323 }
324
325 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
326 where
327 Self: Sized,
328 {
329 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
330
331 (journaled_state.database, EvmEnv { block_env, cfg_env })
332 }
333}
334
335impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Deref
336 for EthFoundryEvm<'db, I>
337{
338 type Target = EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>;
339
340 fn deref(&self) -> &Self::Target {
341 &self.inner.ctx
342 }
343}
344
345impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> DerefMut
346 for EthFoundryEvm<'db, I>
347{
348 fn deref_mut(&mut self) -> &mut Self::Target {
349 &mut self.inner.ctx
350 }
351}
352
353pub trait IntoNestedEvm<SPEC, BLOCK, TX> {
358 type Inner: NestedEvm<Spec = SPEC, Block = BLOCK, Tx = TX>;
360
361 fn into_nested_evm(self) -> Self::Inner;
363}
364
365impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
366 IntoNestedEvm<SpecId, BlockEnv, TxEnv> for EthFoundryEvm<'db, I>
367{
368 type Inner = EthRevmEvm<'db, I>;
369
370 fn into_nested_evm(self) -> Self::Inner {
371 self.inner
372 }
373}
374
375pub trait NestedEvm {
380 type Spec;
382 type Block;
384 type Tx;
386
387 fn journal_inner_mut(&mut self) -> &mut JournaledState;
389
390 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>>;
392
393 fn transact_raw(
395 &mut self,
396 tx: Self::Tx,
397 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>>;
398
399 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block>;
400}
401
402impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> NestedEvm
403 for EthRevmEvm<'db, I>
404{
405 type Spec = SpecId;
406 type Block = BlockEnv;
407 type Tx = TxEnv;
408
409 fn journal_inner_mut(&mut self) -> &mut JournaledState {
410 &mut self.ctx_mut().journaled_state.inner
411 }
412
413 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
414 let mut handler = EthFoundryHandler::<I>::default();
415
416 let memory =
418 SharedMemory::new_with_buffer(self.ctx().local().shared_memory_buffer().clone());
419 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
420
421 let mut frame_result = handler.inspect_run_exec_loop(self, first_frame_input)?;
423
424 handler.last_frame_result(self, &mut frame_result)?;
426
427 Ok(frame_result)
428 }
429
430 fn transact_raw(
431 &mut self,
432 tx: Self::Tx,
433 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
434 self.set_tx(tx);
435
436 let mut handler = EthFoundryHandler::<I>::default();
437 let result = handler.inspect_run(self)?;
438
439 Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
440 }
441
442 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
443 self.ctx_ref().evm_clone()
444 }
445}
446
447pub type NestedEvmClosure<'a, Spec, Block, Tx> =
449 &'a mut dyn FnMut(
450 &mut dyn NestedEvm<Spec = Spec, Block = Block, Tx = Tx>,
451 ) -> Result<(), EVMError<DatabaseError>>;
452
453pub fn with_cloned_context<CTX: FoundryContextExt>(
458 ecx: &mut CTX,
459 f: impl FnOnce(
460 &mut CTX::Db,
461 EvmEnv<CTX::Spec, CTX::Block>,
462 JournaledState,
463 )
464 -> Result<(EvmEnv<CTX::Spec, CTX::Block>, JournaledState), EVMError<DatabaseError>>,
465) -> Result<(), EVMError<DatabaseError>> {
466 let evm_env = ecx.evm_clone();
467
468 let (db, journal_inner) = ecx.db_journal_inner_mut();
469 let journal_inner_clone = journal_inner.clone();
470
471 let (sub_evm_env, sub_inner) = f(db, evm_env, journal_inner_clone)?;
472
473 ecx.set_journal_inner(sub_inner);
475 ecx.set_evm(sub_evm_env);
476
477 Ok(())
478}
479
480pub struct EthFoundryHandler<
481 'db,
482 I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
483> {
484 create2_overrides: Vec<(usize, CallInputs)>,
485 _phantom: PhantomData<(&'db mut dyn DatabaseExt<EthEvmFactory>, I)>,
486}
487
488impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Default
489 for EthFoundryHandler<'db, I>
490{
491 fn default() -> Self {
492 Self { create2_overrides: Vec::new(), _phantom: PhantomData }
493 }
494}
495
496impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Handler
499 for EthFoundryHandler<'db, I>
500{
501 type Evm = RevmEvm<
502 EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>,
503 I,
504 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
505 PrecompilesMap,
506 EthFrame<EthInterpreter>,
507 >;
508 type Error = EVMError<DatabaseError>;
509 type HaltReason = HaltReason;
510}
511
512impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
513 EthFoundryHandler<'db, I>
514{
515 fn handle_create_frame(
518 &mut self,
519 evm: &mut <Self as Handler>::Evm,
520 init: &mut FrameInit,
521 ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
522 if let FrameInput::Create(inputs) = &init.frame_input
523 && let CreateScheme::Create2 { salt } = inputs.scheme()
524 {
525 let (ctx, inspector) = evm.ctx_inspector();
526
527 if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
528 let gas_limit = inputs.gas_limit();
529
530 let create2_deployer = evm.inspector().create2_deployer();
532
533 let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
535
536 self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
538
539 let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
541 if code_hash == KECCAK_EMPTY {
542 return Ok(Some(FrameResult::Call(CallOutcome {
543 result: InterpreterResult {
544 result: InstructionResult::Revert,
545 output: Bytes::from(
546 format!("missing CREATE2 deployer: {create2_deployer}")
547 .into_bytes(),
548 ),
549 gas: Gas::new(gas_limit),
550 },
551 memory_offset: 0..0,
552 was_precompile_called: false,
553 precompile_call_logs: vec![],
554 })));
555 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
556 return Ok(Some(FrameResult::Call(CallOutcome {
557 result: InterpreterResult {
558 result: InstructionResult::Revert,
559 output: "invalid CREATE2 deployer bytecode".into(),
560 gas: Gas::new(gas_limit),
561 },
562 memory_offset: 0..0,
563 was_precompile_called: false,
564 precompile_call_logs: vec![],
565 })));
566 }
567
568 init.frame_input = FrameInput::Call(Box::new(call_inputs));
570 }
571 }
572 Ok(None)
573 }
574
575 fn handle_create2_override(
577 &mut self,
578 evm: &mut <Self as Handler>::Evm,
579 result: FrameResult,
580 ) -> FrameResult {
581 if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
582 let (_, call_inputs) = self.create2_overrides.pop().unwrap();
583 let FrameResult::Call(mut call) = result else {
584 unreachable!("create2 override should be a call frame");
585 };
586
587 let address = match call.instruction_result() {
589 return_ok!() => Address::try_from(call.output().as_ref())
590 .map_err(|_| {
591 call.result = InterpreterResult {
592 result: InstructionResult::Revert,
593 output: "invalid CREATE2 factory output".into(),
594 gas: Gas::new(call_inputs.gas_limit),
595 };
596 })
597 .ok(),
598 _ => None,
599 };
600
601 FrameResult::Create(CreateOutcome { result: call.result, address })
602 } else {
603 result
604 }
605 }
606}
607
608impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
609 InspectorHandler for EthFoundryHandler<'db, I>
610{
611 type IT = EthInterpreter;
612
613 fn inspect_run_exec_loop(
614 &mut self,
615 evm: &mut Self::Evm,
616 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
617 ) -> Result<FrameResult, Self::Error> {
618 let res = evm.inspect_frame_init(first_frame_input)?;
619
620 if let ItemOrResult::Result(frame_result) = res {
621 return Ok(frame_result);
622 }
623
624 loop {
625 let call_or_result = evm.inspect_frame_run()?;
626
627 let result = match call_or_result {
628 ItemOrResult::Item(mut init) => {
629 if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
631 return Ok(frame_result);
632 }
633
634 match evm.inspect_frame_init(init)? {
635 ItemOrResult::Item(_) => continue,
636 ItemOrResult::Result(result) => result,
637 }
638 }
639 ItemOrResult::Result(result) => result,
640 };
641
642 let result = self.handle_create2_override(evm, result);
644
645 if let Some(result) = evm.frame_return_result(result)? {
646 return Ok(result);
647 }
648 }
649 }
650}
651
652type OpRevmEvm<'db, I> = op_revm::OpEvm<
653 OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>,
654 I,
655 EthInstructions<EthInterpreter, OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
656 PrecompilesMap,
657>;
658
659pub struct OpFoundryEvm<
662 'db,
663 I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
664> {
665 pub inner: OpRevmEvm<'db, I>,
666}
667
668impl FoundryEvmFactory for OpEvmFactory {
669 type FoundryContext<'db> = OpContext<&'db mut dyn DatabaseExt<Self>>;
670
671 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> = OpFoundryEvm<'db, I>;
672
673 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
674 &self,
675 db: &'db mut dyn DatabaseExt<Self>,
676 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
677 inspector: I,
678 ) -> Self::FoundryEvm<'db, I> {
679 let spec_id = *evm_env.spec_id();
680 let mut inner = Context::op()
681 .with_db(db)
682 .with_block(evm_env.block_env)
683 .with_cfg(evm_env.cfg_env)
684 .build_op_with_inspector(inspector)
685 .with_precompiles(PrecompilesMap::from_static(
686 OpPrecompiles::new_with_spec(spec_id).precompiles(),
687 ));
688 inner.ctx().cfg.tx_chain_id_check = true;
689
690 let mut evm = OpFoundryEvm { inner };
691 let networks = Evm::inspector(&evm).get_networks();
692 networks.inject_precompiles(evm.precompiles_mut());
693 evm
694 }
695
696 fn create_foundry_nested_evm<'db>(
697 &self,
698 db: &'db mut dyn DatabaseExt<Self>,
699 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
700 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
701 ) -> Box<dyn NestedEvm<Spec = OpSpecId, Block = BlockEnv, Tx = OpTransaction<TxEnv>> + 'db>
702 {
703 Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
704 }
705}
706
707impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Evm
708 for OpFoundryEvm<'db, I>
709{
710 type Precompiles = PrecompilesMap;
711 type Inspector = I;
712 type DB = &'db mut dyn DatabaseExt<OpEvmFactory>;
713 type Error = EVMError<DatabaseError, OpTransactionError>;
714 type HaltReason = OpHaltReason;
715 type Spec = OpSpecId;
716 type Tx = OpTransaction<TxEnv>;
717 type BlockEnv = BlockEnv;
718
719 fn block(&self) -> &BlockEnv {
720 &self.inner.ctx_ref().block
721 }
722
723 fn chain_id(&self) -> u64 {
724 self.inner.ctx_ref().cfg.chain_id
725 }
726
727 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
728 let (ctx, _, precompiles, _, inspector) = self.inner.all_inspector();
729 (&ctx.journaled_state.database, inspector, precompiles)
730 }
731
732 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
733 let (ctx, _, precompiles, _, inspector) = self.inner.all_mut_inspector();
734 (&mut ctx.journaled_state.database, inspector, precompiles)
735 }
736
737 fn set_inspector_enabled(&mut self, _enabled: bool) {
738 unimplemented!("OpFoundryEvm is always inspecting")
739 }
740
741 fn transact_raw(
742 &mut self,
743 tx: Self::Tx,
744 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
745 self.inner.ctx().set_tx(tx);
746
747 let mut handler = OpFoundryHandler::<I>::default();
748 let result = handler.inspect_run(&mut self.inner)?;
749
750 Ok(ResultAndState::new(result, self.inner.ctx_ref().journaled_state.inner.state.clone()))
751 }
752
753 fn transact_system_call(
754 &mut self,
755 _caller: Address,
756 _contract: Address,
757 _data: Bytes,
758 ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
759 unimplemented!()
760 }
761
762 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
763 where
764 Self: Sized,
765 {
766 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx;
767 (journaled_state.database, EvmEnv { block_env, cfg_env })
768 }
769}
770
771impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Deref
772 for OpFoundryEvm<'db, I>
773{
774 type Target = OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>;
775
776 fn deref(&self) -> &Self::Target {
777 &self.inner.0.ctx
778 }
779}
780
781impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> DerefMut
782 for OpFoundryEvm<'db, I>
783{
784 fn deref_mut(&mut self) -> &mut Self::Target {
785 &mut self.inner.0.ctx
786 }
787}
788
789impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>>
790 IntoNestedEvm<OpSpecId, BlockEnv, OpTransaction<TxEnv>> for OpFoundryEvm<'db, I>
791{
792 type Inner = OpRevmEvm<'db, I>;
793
794 fn into_nested_evm(self) -> Self::Inner {
795 self.inner
796 }
797}
798
799fn map_op_error(e: EVMError<DatabaseError, OpTransactionError>) -> EVMError<DatabaseError> {
801 match e {
802 EVMError::Database(db) => EVMError::Database(db),
803 EVMError::Header(h) => EVMError::Header(h),
804 EVMError::Custom(s) => EVMError::Custom(s),
805 EVMError::Transaction(t) => EVMError::Custom(format!("op transaction error: {t}")),
806 }
807}
808
809impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> NestedEvm
810 for OpRevmEvm<'db, I>
811{
812 type Spec = OpSpecId;
813 type Block = BlockEnv;
814 type Tx = OpTransaction<TxEnv>;
815
816 fn journal_inner_mut(&mut self) -> &mut JournaledState {
817 &mut self.ctx().journaled_state.inner
818 }
819
820 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
821 let mut handler = OpFoundryHandler::<I>::default();
822
823 let memory =
824 SharedMemory::new_with_buffer(self.ctx_ref().local.shared_memory_buffer().clone());
825 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
826
827 let mut frame_result =
828 handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_op_error)?;
829
830 handler.last_frame_result(self, &mut frame_result).map_err(map_op_error)?;
831
832 Ok(frame_result)
833 }
834
835 fn transact_raw(
836 &mut self,
837 tx: Self::Tx,
838 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
839 self.ctx().set_tx(tx);
840
841 let mut handler = OpFoundryHandler::<I>::default();
842 let result = handler.inspect_run(self).map_err(map_op_error)?;
843
844 let result = result.map_haltreason(|h| match h {
845 OpHaltReason::Base(eth) => eth,
846 _ => HaltReason::PrecompileError,
847 });
848
849 Ok(ResultAndState::new(result, self.ctx_ref().journaled_state.inner.state.clone()))
850 }
851
852 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
853 EvmEnv::new(self.ctx_ref().cfg.clone(), self.ctx_ref().block.clone())
854 }
855}
856
857pub struct OpFoundryHandler<
859 'db,
860 I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
861> {
862 inner: OpHandler<
863 OpRevmEvm<'db, I>,
864 EVMError<DatabaseError, OpTransactionError>,
865 EthFrame<EthInterpreter>,
866 >,
867 create2_overrides: Vec<(usize, CallInputs)>,
868}
869
870impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Default
871 for OpFoundryHandler<'db, I>
872{
873 fn default() -> Self {
874 Self { inner: OpHandler::new(), create2_overrides: Vec::new() }
875 }
876}
877
878impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Handler
879 for OpFoundryHandler<'db, I>
880{
881 type Evm = OpRevmEvm<'db, I>;
882 type Error = EVMError<DatabaseError, OpTransactionError>;
883 type HaltReason = OpHaltReason;
884
885 #[inline]
886 fn run(
887 &mut self,
888 evm: &mut Self::Evm,
889 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
890 self.inner.run(evm)
891 }
892
893 #[inline]
894 fn execution(
895 &mut self,
896 evm: &mut Self::Evm,
897 init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
898 ) -> Result<FrameResult, Self::Error> {
899 self.inner.execution(evm, init_and_floor_gas)
900 }
901
902 #[inline]
903 fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
904 self.inner.validate_env(evm)
905 }
906
907 #[inline]
908 fn validate_against_state_and_deduct_caller(
909 &self,
910 evm: &mut Self::Evm,
911 ) -> Result<(), Self::Error> {
912 self.inner.validate_against_state_and_deduct_caller(evm)
913 }
914
915 #[inline]
916 fn reimburse_caller(
917 &self,
918 evm: &mut Self::Evm,
919 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
920 ) -> Result<(), Self::Error> {
921 self.inner.reimburse_caller(evm, exec_result)
922 }
923
924 #[inline]
925 fn reward_beneficiary(
926 &self,
927 evm: &mut Self::Evm,
928 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
929 ) -> Result<(), Self::Error> {
930 self.inner.reward_beneficiary(evm, exec_result)
931 }
932
933 #[inline]
934 fn validate_initial_tx_gas(
935 &self,
936 evm: &mut Self::Evm,
937 ) -> Result<revm::interpreter::InitialAndFloorGas, Self::Error> {
938 self.inner.validate_initial_tx_gas(evm)
939 }
940
941 #[inline]
942 fn execution_result(
943 &mut self,
944 evm: &mut Self::Evm,
945 result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
946 result_gas: revm::context::result::ResultGas,
947 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
948 self.inner.execution_result(evm, result, result_gas)
949 }
950
951 #[inline]
952 fn catch_error(
953 &self,
954 evm: &mut Self::Evm,
955 error: Self::Error,
956 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
957 self.inner.catch_error(evm, error)
958 }
959}
960
961impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>>
962 InspectorHandler for OpFoundryHandler<'db, I>
963{
964 type IT = EthInterpreter;
965
966 fn inspect_run_exec_loop(
967 &mut self,
968 evm: &mut Self::Evm,
969 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
970 ) -> Result<FrameResult, Self::Error> {
971 let res = evm.inspect_frame_init(first_frame_input)?;
972
973 if let ItemOrResult::Result(frame_result) = res {
974 return Ok(frame_result);
975 }
976
977 loop {
978 let call_or_result = evm.inspect_frame_run()?;
979
980 let result = match call_or_result {
981 ItemOrResult::Item(mut init) => {
982 if let FrameInput::Create(inputs) = &init.frame_input
984 && let CreateScheme::Create2 { salt } = inputs.scheme()
985 {
986 let (ctx, inspector) = evm.ctx_inspector();
987 if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
988 let gas_limit = inputs.gas_limit();
989 let create2_deployer = evm.inspector().create2_deployer();
990 let call_inputs =
991 get_create2_factory_call_inputs(salt, inputs, create2_deployer);
992
993 self.create2_overrides
994 .push((evm.ctx_ref().journal().depth(), call_inputs.clone()));
995
996 let code_hash = evm
997 .ctx()
998 .journal_mut()
999 .load_account(create2_deployer)?
1000 .info
1001 .code_hash;
1002 if code_hash == KECCAK_EMPTY {
1003 return Ok(FrameResult::Call(CallOutcome {
1004 result: InterpreterResult {
1005 result: InstructionResult::Revert,
1006 output: Bytes::from(
1007 format!("missing CREATE2 deployer: {create2_deployer}")
1008 .into_bytes(),
1009 ),
1010 gas: Gas::new(gas_limit),
1011 },
1012 memory_offset: 0..0,
1013 was_precompile_called: false,
1014 precompile_call_logs: vec![],
1015 }));
1016 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
1017 return Ok(FrameResult::Call(CallOutcome {
1018 result: InterpreterResult {
1019 result: InstructionResult::Revert,
1020 output: "invalid CREATE2 deployer bytecode".into(),
1021 gas: Gas::new(gas_limit),
1022 },
1023 memory_offset: 0..0,
1024 was_precompile_called: false,
1025 precompile_call_logs: vec![],
1026 }));
1027 }
1028
1029 init.frame_input = FrameInput::Call(Box::new(call_inputs));
1030 }
1031 }
1032
1033 match evm.inspect_frame_init(init)? {
1034 ItemOrResult::Item(_) => continue,
1035 ItemOrResult::Result(result) => result,
1036 }
1037 }
1038 ItemOrResult::Result(result) => result,
1039 };
1040
1041 let result = if self
1043 .create2_overrides
1044 .last()
1045 .is_some_and(|(depth, _)| *depth == evm.ctx_ref().journal().depth())
1046 {
1047 let (_, call_inputs) = self.create2_overrides.pop().unwrap();
1048 let FrameResult::Call(mut call) = result else {
1049 unreachable!("create2 override should be a call frame");
1050 };
1051 let address = match call.instruction_result() {
1052 return_ok!() => Address::try_from(call.output().as_ref())
1053 .map_err(|_| {
1054 call.result = InterpreterResult {
1055 result: InstructionResult::Revert,
1056 output: "invalid CREATE2 factory output".into(),
1057 gas: Gas::new(call_inputs.gas_limit),
1058 };
1059 })
1060 .ok(),
1061 _ => None,
1062 };
1063 FrameResult::Create(CreateOutcome { result: call.result, address })
1064 } else {
1065 result
1066 };
1067
1068 if let Some(result) = evm.frame_return_result(result)? {
1069 return Ok(result);
1070 }
1071 }
1072 }
1073}
1074
1075type TempoRevmEvm<'db, I> = tempo_revm::TempoEvm<&'db mut dyn DatabaseExt<TempoEvmFactory>, I>;
1077
1078pub struct TempoFoundryEvm<
1085 'db,
1086 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1087> {
1088 pub inner: TempoRevmEvm<'db, I>,
1089}
1090
1091fn initialize_tempo_evm<
1100 'db,
1101 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1102>(
1103 evm: &mut TempoFoundryEvm<'db, I>,
1104 is_forked: bool,
1105) {
1106 let ctx = &mut evm.inner.inner.ctx;
1107 StorageCtx::enter_evm(&mut ctx.journaled_state, &ctx.block, &ctx.cfg, &ctx.tx, || {
1108 if is_forked {
1109 let mut sctx = StorageCtx;
1111 let sentinel = Bytecode::new_legacy(Bytes::from_static(&[0xef]));
1112 for addr in TEMPO_PRECOMPILE_ADDRESSES.iter().chain(TEMPO_TIP20_TOKENS.iter()) {
1113 sctx.set_code(*addr, sentinel.clone())
1114 .expect("failed to warm tempo precompile address");
1115 }
1116 } else {
1117 initialize_tempo_genesis_inner(TEST_CONTRACT_ADDRESS, CALLER)
1119 .expect("tempo genesis initialization failed");
1120 }
1121 });
1122}
1123
1124impl FoundryEvmFactory for TempoEvmFactory {
1125 type FoundryContext<'db> = TempoContext<&'db mut dyn DatabaseExt<Self>>;
1126
1127 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> =
1128 TempoFoundryEvm<'db, I>;
1129
1130 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
1131 &self,
1132 db: &'db mut dyn DatabaseExt<Self>,
1133 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
1134 inspector: I,
1135 ) -> Self::FoundryEvm<'db, I> {
1136 let is_forked = db.is_forked_mode();
1137 let spec = *evm_env.spec_id();
1138 let tempo_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
1139 let mut inner = tempo_evm.into_inner();
1140 inner.ctx.cfg.gas_params = tempo_gas_params(spec);
1141 inner.ctx.cfg.tx_chain_id_check = true;
1142
1143 let mut evm = TempoFoundryEvm { inner };
1144 let networks = Evm::inspector(&evm).get_networks();
1145 networks.inject_precompiles(evm.precompiles_mut());
1146
1147 initialize_tempo_evm(&mut evm, is_forked);
1148 evm
1149 }
1150
1151 fn create_foundry_nested_evm<'db>(
1152 &self,
1153 db: &'db mut dyn DatabaseExt<Self>,
1154 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
1155 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
1156 ) -> Box<dyn NestedEvm<Spec = TempoHardfork, Block = TempoBlockEnv, Tx = TempoTxEnv> + 'db>
1157 {
1158 Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
1159 }
1160}
1161
1162impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Evm
1163 for TempoFoundryEvm<'db, I>
1164{
1165 type Precompiles = PrecompilesMap;
1166 type Inspector = I;
1167 type DB = &'db mut dyn DatabaseExt<TempoEvmFactory>;
1168 type Error = EVMError<DatabaseError, TempoInvalidTransaction>;
1169 type HaltReason = TempoHaltReason;
1170 type Spec = TempoHardfork;
1171 type Tx = TempoTxEnv;
1172 type BlockEnv = TempoBlockEnv;
1173
1174 fn block(&self) -> &TempoBlockEnv {
1175 &self.inner.block
1176 }
1177
1178 fn chain_id(&self) -> u64 {
1179 self.inner.ctx.cfg.chain_id
1180 }
1181
1182 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
1183 let evm = &self.inner.inner;
1184 (&evm.ctx.journaled_state.database, &evm.inspector, &evm.precompiles)
1185 }
1186
1187 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
1188 let evm = &mut self.inner.inner;
1189 (&mut evm.ctx.journaled_state.database, &mut evm.inspector, &mut evm.precompiles)
1190 }
1191
1192 fn set_inspector_enabled(&mut self, _enabled: bool) {
1193 unimplemented!("TempoFoundryEvm is always inspecting")
1194 }
1195
1196 fn transact_raw(
1197 &mut self,
1198 tx: Self::Tx,
1199 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
1200 self.inner.set_tx(tx);
1201
1202 let mut handler = TempoFoundryHandler::<I>::default();
1203 let result = handler.inspect_run(&mut self.inner)?;
1204
1205 Ok(ResultAndState::new(result, self.inner.inner.ctx.journaled_state.inner.state.clone()))
1206 }
1207
1208 fn transact_system_call(
1209 &mut self,
1210 _caller: Address,
1211 _contract: Address,
1212 _data: Bytes,
1213 ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
1214 unimplemented!()
1215 }
1216
1217 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec, Self::BlockEnv>)
1218 where
1219 Self: Sized,
1220 {
1221 let revm_evm = self.inner.inner;
1222 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = revm_evm.ctx;
1223 (journaled_state.database, EvmEnv { block_env, cfg_env })
1224 }
1225}
1226
1227impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Deref
1228 for TempoFoundryEvm<'db, I>
1229{
1230 type Target = TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>;
1231
1232 fn deref(&self) -> &Self::Target {
1233 &self.inner.ctx
1234 }
1235}
1236
1237impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> DerefMut
1238 for TempoFoundryEvm<'db, I>
1239{
1240 fn deref_mut(&mut self) -> &mut Self::Target {
1241 &mut self.inner.ctx
1242 }
1243}
1244
1245impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>>
1246 IntoNestedEvm<TempoHardfork, TempoBlockEnv, TempoTxEnv> for TempoFoundryEvm<'db, I>
1247{
1248 type Inner = TempoRevmEvm<'db, I>;
1249
1250 fn into_nested_evm(self) -> Self::Inner {
1251 self.inner
1252 }
1253}
1254
1255fn map_tempo_error(e: EVMError<DatabaseError, TempoInvalidTransaction>) -> EVMError<DatabaseError> {
1260 match e {
1261 EVMError::Database(db) => EVMError::Database(db),
1262 EVMError::Header(h) => EVMError::Header(h),
1263 EVMError::Custom(s) => EVMError::Custom(s),
1264 EVMError::Transaction(t) => match t {
1265 TempoInvalidTransaction::EthInvalidTransaction(eth) => EVMError::Transaction(eth),
1266 t => EVMError::Custom(format!("tempo transaction error: {t}")),
1267 },
1268 }
1269}
1270
1271impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> NestedEvm
1272 for TempoRevmEvm<'db, I>
1273{
1274 type Spec = TempoHardfork;
1275 type Block = TempoBlockEnv;
1276 type Tx = TempoTxEnv;
1277
1278 fn journal_inner_mut(&mut self) -> &mut JournaledState {
1279 &mut self.ctx_mut().journaled_state.inner
1280 }
1281
1282 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
1283 let mut handler = TempoFoundryHandler::<I>::default();
1284
1285 let memory =
1286 SharedMemory::new_with_buffer(self.ctx().local().shared_memory_buffer().clone());
1287 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
1288
1289 let mut frame_result =
1290 handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_tempo_error)?;
1291
1292 handler.last_frame_result(self, &mut frame_result).map_err(map_tempo_error)?;
1293
1294 Ok(frame_result)
1295 }
1296
1297 fn transact_raw(
1298 &mut self,
1299 tx: Self::Tx,
1300 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
1301 self.set_tx(tx);
1302
1303 let mut handler = TempoFoundryHandler::<I>::default();
1304 let result = handler.inspect_run(self).map_err(map_tempo_error)?;
1305
1306 let result = result.map_haltreason(|h| match h {
1307 TempoHaltReason::Ethereum(eth) => eth,
1308 _ => HaltReason::PrecompileError,
1309 });
1310
1311 Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
1312 }
1313
1314 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
1315 self.ctx_ref().evm_clone()
1316 }
1317}
1318
1319pub struct TempoFoundryHandler<
1326 'db,
1327 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1328> {
1329 inner: TempoEvmHandler<&'db mut dyn DatabaseExt<TempoEvmFactory>, I>,
1330 create2_overrides: Vec<(usize, CallInputs)>,
1331}
1332
1333impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Default
1334 for TempoFoundryHandler<'db, I>
1335{
1336 fn default() -> Self {
1337 Self { inner: TempoEvmHandler::new(), create2_overrides: Vec::new() }
1338 }
1339}
1340
1341impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Handler
1342 for TempoFoundryHandler<'db, I>
1343{
1344 type Evm = TempoRevmEvm<'db, I>;
1345 type Error = EVMError<DatabaseError, TempoInvalidTransaction>;
1346 type HaltReason = TempoHaltReason;
1347
1348 #[inline]
1349 fn run(
1350 &mut self,
1351 evm: &mut Self::Evm,
1352 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1353 self.inner.run(evm)
1354 }
1355
1356 #[inline]
1357 fn execution(
1358 &mut self,
1359 evm: &mut Self::Evm,
1360 init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
1361 ) -> Result<FrameResult, Self::Error> {
1362 self.inner.execution(evm, init_and_floor_gas)
1363 }
1364
1365 #[inline]
1366 fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
1367 self.inner.validate_env(evm)
1368 }
1369
1370 #[inline]
1371 fn validate_against_state_and_deduct_caller(
1372 &self,
1373 evm: &mut Self::Evm,
1374 ) -> Result<(), Self::Error> {
1375 self.inner.validate_against_state_and_deduct_caller(evm)
1376 }
1377
1378 #[inline]
1379 fn reimburse_caller(
1380 &self,
1381 evm: &mut Self::Evm,
1382 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1383 ) -> Result<(), Self::Error> {
1384 self.inner.reimburse_caller(evm, exec_result)
1385 }
1386
1387 #[inline]
1388 fn reward_beneficiary(
1389 &self,
1390 evm: &mut Self::Evm,
1391 exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1392 ) -> Result<(), Self::Error> {
1393 self.inner.reward_beneficiary(evm, exec_result)
1394 }
1395
1396 #[inline]
1397 fn validate_initial_tx_gas(
1398 &self,
1399 evm: &mut Self::Evm,
1400 ) -> Result<revm::interpreter::InitialAndFloorGas, Self::Error> {
1401 self.inner.validate_initial_tx_gas(evm)
1402 }
1403
1404 #[inline]
1405 fn execution_result(
1406 &mut self,
1407 evm: &mut Self::Evm,
1408 result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1409 result_gas: revm::context::result::ResultGas,
1410 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1411 self.inner.execution_result(evm, result, result_gas)
1412 }
1413
1414 #[inline]
1415 fn catch_error(
1416 &self,
1417 evm: &mut Self::Evm,
1418 error: Self::Error,
1419 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1420 self.inner.catch_error(evm, error)
1421 }
1422}
1423
1424fn create2_exec_loop<
1426 'db,
1427 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1428>(
1429 create2_overrides: &mut Vec<(usize, CallInputs)>,
1430 evm: &mut TempoRevmEvm<'db, I>,
1431 first_frame_input: FrameInit,
1432) -> Result<FrameResult, EVMError<DatabaseError, TempoInvalidTransaction>> {
1433 let res = evm.inspect_frame_init(first_frame_input)?;
1434
1435 if let ItemOrResult::Result(frame_result) = res {
1436 return Ok(frame_result);
1437 }
1438
1439 loop {
1440 let call_or_result = evm.inspect_frame_run()?;
1441
1442 let result = match call_or_result {
1443 ItemOrResult::Item(mut init) => {
1444 if let Some(frame_result) = handle_create2_frame(create2_overrides, evm, &mut init)?
1445 {
1446 return Ok(frame_result);
1447 }
1448
1449 match evm.inspect_frame_init(init)? {
1450 ItemOrResult::Item(_) => continue,
1451 ItemOrResult::Result(result) => result,
1452 }
1453 }
1454 ItemOrResult::Result(result) => result,
1455 };
1456
1457 let result = handle_create2_result(create2_overrides, evm, result);
1458
1459 if let Some(result) = evm.frame_return_result(result)? {
1460 return Ok(result);
1461 }
1462 }
1463}
1464
1465fn handle_create2_frame<
1467 'db,
1468 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1469>(
1470 create2_overrides: &mut Vec<(usize, CallInputs)>,
1471 evm: &mut TempoRevmEvm<'db, I>,
1472 init: &mut FrameInit,
1473) -> Result<Option<FrameResult>, EVMError<DatabaseError, TempoInvalidTransaction>> {
1474 if let FrameInput::Create(inputs) = &init.frame_input
1475 && let CreateScheme::Create2 { salt } = inputs.scheme()
1476 {
1477 let (ctx, inspector) = evm.ctx_inspector();
1478
1479 if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
1480 let gas_limit = inputs.gas_limit();
1481 let create2_deployer = evm.inspector().create2_deployer();
1482 let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
1483
1484 create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
1485
1486 let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
1487 if code_hash == KECCAK_EMPTY {
1488 return Ok(Some(FrameResult::Call(CallOutcome {
1489 result: InterpreterResult {
1490 result: InstructionResult::Revert,
1491 output: Bytes::from(
1492 format!("missing CREATE2 deployer: {create2_deployer}").into_bytes(),
1493 ),
1494 gas: Gas::new(gas_limit),
1495 },
1496 memory_offset: 0..0,
1497 was_precompile_called: false,
1498 precompile_call_logs: vec![],
1499 })));
1500 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
1501 return Ok(Some(FrameResult::Call(CallOutcome {
1502 result: InterpreterResult {
1503 result: InstructionResult::Revert,
1504 output: "invalid CREATE2 deployer bytecode".into(),
1505 gas: Gas::new(gas_limit),
1506 },
1507 memory_offset: 0..0,
1508 was_precompile_called: false,
1509 precompile_call_logs: vec![],
1510 })));
1511 }
1512
1513 init.frame_input = FrameInput::Call(Box::new(call_inputs));
1514 }
1515 }
1516 Ok(None)
1517}
1518
1519fn handle_create2_result<
1521 'db,
1522 I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1523>(
1524 create2_overrides: &mut Vec<(usize, CallInputs)>,
1525 evm: &mut TempoRevmEvm<'db, I>,
1526 result: FrameResult,
1527) -> FrameResult {
1528 if create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
1529 let (_, call_inputs) = create2_overrides.pop().unwrap();
1530 let FrameResult::Call(mut call) = result else {
1531 unreachable!("create2 override should be a call frame");
1532 };
1533
1534 let address = match call.instruction_result() {
1535 return_ok!() => Address::try_from(call.output().as_ref())
1536 .map_err(|_| {
1537 call.result = InterpreterResult {
1538 result: InstructionResult::Revert,
1539 output: "invalid CREATE2 factory output".into(),
1540 gas: Gas::new(call_inputs.gas_limit),
1541 };
1542 })
1543 .ok(),
1544 _ => None,
1545 };
1546
1547 FrameResult::Create(CreateOutcome { result: call.result, address })
1548 } else {
1549 result
1550 }
1551}
1552
1553impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>>
1554 InspectorHandler for TempoFoundryHandler<'db, I>
1555{
1556 type IT = EthInterpreter;
1557
1558 fn inspect_run(
1563 &mut self,
1564 evm: &mut Self::Evm,
1565 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1566 self.inner.load_fee_fields(evm)?;
1567
1568 match self.inspect_run_without_catch_error(evm) {
1569 Ok(output) => Ok(output),
1570 Err(e) => self.catch_error(evm, e),
1571 }
1572 }
1573
1574 #[inline]
1578 fn inspect_execution(
1579 &mut self,
1580 evm: &mut Self::Evm,
1581 init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
1582 ) -> Result<FrameResult, Self::Error> {
1583 let overrides = &mut self.create2_overrides;
1584 self.inner.inspect_execution_with(evm, init_and_floor_gas, |_handler, evm, init| {
1585 create2_exec_loop(overrides, evm, init)
1586 })
1587 }
1588
1589 fn inspect_run_exec_loop(
1590 &mut self,
1591 evm: &mut Self::Evm,
1592 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
1593 ) -> Result<FrameResult, Self::Error> {
1594 create2_exec_loop(&mut self.create2_overrides, evm, first_frame_input)
1595 }
1596}