revm_handler/
mainnet_builder.rs1use crate::{frame::EthFrame, instructions::EthInstructions, EthPrecompiles};
2use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, FrameStack, Journal, TxEnv};
3use context_interface::{Block, Database, JournalTr, Transaction};
4use database_interface::EmptyDB;
5use interpreter::interpreter::EthInterpreter;
6use primitives::hardfork::SpecId;
7
8pub type MainnetEvm<CTX, INSP = ()> =
10 Evm<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles, EthFrame<EthInterpreter>>;
11
12pub type MainnetContext<DB> = Context<BlockEnv, TxEnv, CfgEnv, DB, Journal<DB>, ()>;
14
15pub trait MainBuilder: Sized {
17 type Context;
19
20 fn build_mainnet(self) -> MainnetEvm<Self::Context>;
22
23 fn build_mainnet_with_inspector<INSP>(self, inspector: INSP)
25 -> MainnetEvm<Self::Context, INSP>;
26}
27
28impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN> MainBuilder for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN>
29where
30 BLOCK: Block,
31 TX: Transaction,
32 CFG: Cfg,
33 DB: Database,
34 JOURNAL: JournalTr<Database = DB>,
35{
36 type Context = Self;
37
38 fn build_mainnet(self) -> MainnetEvm<Self::Context> {
39 let spec = self.cfg.spec().into();
40 Evm {
41 ctx: self,
42 inspector: (),
43 instruction: EthInstructions::new_mainnet_with_spec(spec),
44 precompiles: EthPrecompiles::new(spec),
45 frame_stack: FrameStack::new_prealloc(8),
46 #[cfg(feature = "asyncdb")]
47 async_stack: database_interface::async_db::FiberStack::default(),
48 }
49 }
50
51 fn build_mainnet_with_inspector<INSP>(
52 self,
53 inspector: INSP,
54 ) -> MainnetEvm<Self::Context, INSP> {
55 let spec = self.cfg.spec().into();
56 Evm {
57 ctx: self,
58 inspector,
59 instruction: EthInstructions::new_mainnet_with_spec(spec),
60 precompiles: EthPrecompiles::new(spec),
61 frame_stack: FrameStack::new_prealloc(8),
62 #[cfg(feature = "asyncdb")]
63 async_stack: database_interface::async_db::FiberStack::default(),
64 }
65 }
66}
67
68pub trait MainContext {
70 fn mainnet() -> Self;
72}
73
74impl MainContext for Context<BlockEnv, TxEnv, CfgEnv, EmptyDB, Journal<EmptyDB>, ()> {
75 fn mainnet() -> Self {
76 Context::new(EmptyDB::new(), SpecId::default())
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use crate::{ExecuteEvm, MainBuilder, MainContext};
83 use alloy_signer::{Either, SignerSync};
84 use alloy_signer_local::PrivateKeySigner;
85 use bytecode::{
86 opcode::{PUSH1, SSTORE},
87 Bytecode,
88 };
89 use context::{Context, TxEnv};
90 use context_interface::transaction::Authorization;
91 use database::{BenchmarkDB, EEADDRESS, FFADDRESS};
92 use primitives::{hardfork::SpecId, StorageKey, StorageValue, TxKind, U256};
93
94 #[test]
95 fn sanity_eip7702_tx() {
96 let signer = PrivateKeySigner::random();
97 let auth = Authorization {
98 chain_id: U256::ZERO,
99 nonce: 0,
100 address: FFADDRESS,
101 };
102 let signature = signer.sign_hash_sync(&auth.signature_hash()).unwrap();
103 let auth = auth.into_signed(signature);
104
105 let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
106
107 let ctx = Context::mainnet()
108 .modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecId::PRAGUE))
109 .with_db(BenchmarkDB::new_bytecode(bytecode));
110
111 let mut evm = ctx.build_mainnet();
112
113 let state = evm
114 .transact(
115 TxEnv::builder()
116 .gas_limit(100_000)
117 .authorization_list(vec![Either::Left(auth)])
118 .caller(EEADDRESS)
119 .kind(TxKind::Call(signer.address()))
120 .build()
121 .unwrap(),
122 )
123 .unwrap()
124 .state;
125
126 let auth_acc = state.get(&signer.address()).unwrap();
127 assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(FFADDRESS)));
128 assert_eq!(auth_acc.info.nonce, 1);
129 assert_eq!(
130 auth_acc
131 .storage
132 .get(&StorageKey::from(1))
133 .unwrap()
134 .present_value,
135 StorageValue::from(1)
136 );
137 }
138}