revm_handler/
mainnet_builder.rs

1use crate::{instructions::EthInstructions, EthPrecompiles};
2use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, EvmData, 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 = ()> =
9    Evm<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles>;
10
11pub type MainnetContext<DB> = Context<BlockEnv, TxEnv, CfgEnv, DB, Journal<DB>, ()>;
12
13pub trait MainBuilder: Sized {
14    type Context;
15
16    fn build_mainnet(self) -> MainnetEvm<Self::Context>;
17
18    fn build_mainnet_with_inspector<INSP>(self, inspector: INSP)
19        -> MainnetEvm<Self::Context, INSP>;
20}
21
22impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN> MainBuilder for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN>
23where
24    BLOCK: Block,
25    TX: Transaction,
26    CFG: Cfg,
27    DB: Database,
28    JOURNAL: JournalTr<Database = DB>,
29{
30    type Context = Self;
31
32    fn build_mainnet(self) -> MainnetEvm<Self::Context> {
33        Evm {
34            data: EvmData {
35                ctx: self,
36                inspector: (),
37            },
38            instruction: EthInstructions::default(),
39            precompiles: EthPrecompiles::default(),
40        }
41    }
42
43    fn build_mainnet_with_inspector<INSP>(
44        self,
45        inspector: INSP,
46    ) -> MainnetEvm<Self::Context, INSP> {
47        Evm {
48            data: EvmData {
49                ctx: self,
50                inspector,
51            },
52            instruction: EthInstructions::default(),
53            precompiles: EthPrecompiles::default(),
54        }
55    }
56}
57
58/// Trait used to initialize Context with default mainnet types.
59pub trait MainContext {
60    fn mainnet() -> Self;
61}
62
63impl MainContext for Context<BlockEnv, TxEnv, CfgEnv, EmptyDB, Journal<EmptyDB>, ()> {
64    fn mainnet() -> Self {
65        Context::new(EmptyDB::new(), SpecId::default())
66    }
67}
68
69#[cfg(test)]
70mod test {
71    use crate::ExecuteEvm;
72    use crate::{MainBuilder, MainContext};
73    use alloy_signer::SignerSync;
74    use alloy_signer_local::PrivateKeySigner;
75    use bytecode::{
76        opcode::{PUSH1, SSTORE},
77        Bytecode,
78    };
79    use context::Context;
80    use context_interface::{transaction::Authorization, TransactionType};
81    use database::{BenchmarkDB, EEADDRESS, FFADDRESS};
82    use primitives::{hardfork::SpecId, TxKind, U256};
83
84    #[test]
85    fn sanity_eip7702_tx() {
86        let signer = PrivateKeySigner::random();
87        let auth = Authorization {
88            chain_id: U256::ZERO,
89            nonce: 0,
90            address: FFADDRESS,
91        };
92        let signature = signer.sign_hash_sync(&auth.signature_hash()).unwrap();
93        let auth = auth.into_signed(signature);
94
95        let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
96
97        let ctx = Context::mainnet()
98            .modify_cfg_chained(|cfg| cfg.spec = SpecId::PRAGUE)
99            .with_db(BenchmarkDB::new_bytecode(bytecode))
100            .modify_tx_chained(|tx| {
101                tx.tx_type = TransactionType::Eip7702.into();
102                tx.gas_limit = 100_000;
103                tx.authorization_list = vec![auth];
104                tx.caller = EEADDRESS;
105                tx.kind = TxKind::Call(signer.address());
106            });
107
108        let mut evm = ctx.build_mainnet();
109
110        let ok = evm.replay().unwrap();
111
112        let auth_acc = ok.state.get(&signer.address()).unwrap();
113        assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(FFADDRESS)));
114        assert_eq!(auth_acc.info.nonce, 1);
115        assert_eq!(
116            auth_acc.storage.get(&U256::from(1)).unwrap().present_value,
117            U256::from(1)
118        );
119    }
120}