use crate::{frame::EthFrame, instructions::EthInstructions, EthPrecompiles};
use context::{BlockEnv, Cfg, CfgEnv, Context, Evm, FrameStack, Journal, TxEnv};
use context_interface::{Block, Database, JournalTr, Transaction};
use database_interface::EmptyDB;
use interpreter::interpreter::EthInterpreter;
use primitives::hardfork::SpecId;
pub type MainnetEvm<CTX, INSP = ()> =
Evm<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles, EthFrame<EthInterpreter>>;
pub type MainnetContext<DB> = Context<BlockEnv, TxEnv, CfgEnv, DB, Journal<DB>, ()>;
pub trait MainBuilder: Sized {
type Context;
fn build_mainnet(self) -> MainnetEvm<Self::Context>;
fn build_mainnet_with_inspector<INSP>(self, inspector: INSP)
-> MainnetEvm<Self::Context, INSP>;
}
impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN> MainBuilder for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN>
where
BLOCK: Block,
TX: Transaction,
CFG: Cfg,
DB: Database,
JOURNAL: JournalTr<Database = DB>,
{
type Context = Self;
fn build_mainnet(self) -> MainnetEvm<Self::Context> {
let spec = self.cfg.spec().into();
Evm {
ctx: self,
inspector: (),
instruction: EthInstructions::new_mainnet_with_spec(spec),
precompiles: EthPrecompiles::new(spec),
frame_stack: FrameStack::new_prealloc(8),
}
}
fn build_mainnet_with_inspector<INSP>(
self,
inspector: INSP,
) -> MainnetEvm<Self::Context, INSP> {
let spec = self.cfg.spec().into();
Evm {
ctx: self,
inspector,
instruction: EthInstructions::new_mainnet_with_spec(spec),
precompiles: EthPrecompiles::new(spec),
frame_stack: FrameStack::new_prealloc(8),
}
}
}
pub trait MainContext {
fn mainnet() -> Self;
}
impl MainContext for Context<BlockEnv, TxEnv, CfgEnv, EmptyDB, Journal<EmptyDB>, ()> {
fn mainnet() -> Self {
Context::new(EmptyDB::new(), SpecId::default())
}
}
#[cfg(test)]
mod test {
use crate::{ExecuteEvm, MainBuilder, MainContext};
use alloy_signer::{Either, SignerSync};
use alloy_signer_local::PrivateKeySigner;
use bytecode::{
opcode::{PUSH1, SSTORE},
Bytecode,
};
use context::{Context, TxEnv};
use context_interface::transaction::Authorization;
use database::{BenchmarkDB, EEADDRESS, FFADDRESS};
use primitives::{hardfork::SpecId, StorageKey, StorageValue, TxKind, U256};
#[test]
fn sanity_eip7702_tx() {
let signer = PrivateKeySigner::random();
let auth = Authorization {
chain_id: U256::ZERO,
nonce: 0,
address: FFADDRESS,
};
let signature = signer.sign_hash_sync(&auth.signature_hash()).unwrap();
let auth = auth.into_signed(signature);
let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
let ctx = Context::mainnet()
.modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecId::PRAGUE))
.with_db(BenchmarkDB::new_bytecode(bytecode));
let mut evm = ctx.build_mainnet();
let state = evm
.transact(
TxEnv::builder()
.gas_limit(100_000)
.authorization_list(vec![Either::Left(auth)])
.caller(EEADDRESS)
.kind(TxKind::Call(signer.address()))
.build()
.unwrap(),
)
.unwrap()
.state;
let auth_acc = state.get(&signer.address()).unwrap();
assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(FFADDRESS)));
assert_eq!(auth_acc.info.nonce, 1);
assert_eq!(
auth_acc
.storage
.get(&StorageKey::from(1))
.unwrap()
.present_value,
StorageValue::from(1)
);
}
}