Skip to main content

revm_handler/
mainnet_builder.rs

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
8/// Type alias for a mainnet EVM instance with standard Ethereum components.
9pub type MainnetEvm<CTX, INSP = ()> =
10    Evm<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles, EthFrame<EthInterpreter>>;
11
12/// Type alias for a mainnet context with standard Ethereum environment types.
13pub type MainnetContext<DB> = Context<BlockEnv, TxEnv, CfgEnv, DB, Journal<DB>, ()>;
14
15/// Trait for building mainnet EVM instances from contexts.
16pub trait MainBuilder: Sized {
17    /// The context type that will be used in the EVM.
18    type Context;
19
20    /// Builds a mainnet EVM instance without an inspector.
21    fn build_mainnet(self) -> MainnetEvm<Self::Context>;
22
23    /// Builds a mainnet EVM instance with the provided inspector.
24    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
68/// Trait used to initialize Context with default mainnet types.
69pub trait MainContext {
70    /// Creates a new mainnet context with default configuration.
71    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}