1use 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 Evm {
40 ctx: self,
41 inspector: (),
42 instruction: EthInstructions::default(),
43 precompiles: EthPrecompiles::default(),
44 frame_stack: FrameStack::new(),
45 }
46 }
47
48 fn build_mainnet_with_inspector<INSP>(
49 self,
50 inspector: INSP,
51 ) -> MainnetEvm<Self::Context, INSP> {
52 Evm {
53 ctx: self,
54 inspector,
55 instruction: EthInstructions::default(),
56 precompiles: EthPrecompiles::default(),
57 frame_stack: FrameStack::new(),
58 }
59 }
60}
61
62pub trait MainContext {
64 fn mainnet() -> Self;
66}
67
68impl MainContext for Context<BlockEnv, TxEnv, CfgEnv, EmptyDB, Journal<EmptyDB>, ()> {
69 fn mainnet() -> Self {
70 Context::new(EmptyDB::new(), SpecId::default())
71 }
72}
73
74#[cfg(test)]
75mod test {
76 use crate::ExecuteEvm;
77 use crate::{MainBuilder, MainContext};
78 use alloy_signer::{Either, SignerSync};
79 use alloy_signer_local::PrivateKeySigner;
80 use bytecode::{
81 opcode::{PUSH1, SSTORE},
82 Bytecode,
83 };
84 use context::{Context, TxEnv};
85 use context_interface::{transaction::Authorization, TransactionType};
86 use database::{BenchmarkDB, EEADDRESS, FFADDRESS};
87 use primitives::{hardfork::SpecId, TxKind, U256};
88 use primitives::{StorageKey, StorageValue};
89
90 #[test]
91 fn sanity_eip7702_tx() {
92 let signer = PrivateKeySigner::random();
93 let auth = Authorization {
94 chain_id: U256::ZERO,
95 nonce: 0,
96 address: FFADDRESS,
97 };
98 let signature = signer.sign_hash_sync(&auth.signature_hash()).unwrap();
99 let auth = auth.into_signed(signature);
100
101 let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
102
103 let ctx = Context::mainnet()
104 .modify_cfg_chained(|cfg| cfg.spec = SpecId::PRAGUE)
105 .with_db(BenchmarkDB::new_bytecode(bytecode));
106
107 let mut evm = ctx.build_mainnet();
108
109 let state = evm
110 .transact(TxEnv {
111 tx_type: TransactionType::Eip7702.into(),
112 gas_limit: 100_000,
113 authorization_list: vec![Either::Left(auth)],
114 caller: EEADDRESS,
115 kind: TxKind::Call(signer.address()),
116 ..Default::default()
117 })
118 .unwrap()
119 .state;
120
121 let auth_acc = state.get(&signer.address()).unwrap();
122 assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(FFADDRESS)));
123 assert_eq!(auth_acc.info.nonce, 1);
124 assert_eq!(
125 auth_acc
126 .storage
127 .get(&StorageKey::from(1))
128 .unwrap()
129 .present_value,
130 StorageValue::from(1)
131 );
132 }
133}