#![allow(dead_code)] #![allow(unreachable_pub)]
use alloy_primitives::{Address, Bytes, U256};
use criterion::black_box;
use mega_evm::{
revm::{context::TxEnv, inspector::NoOpInspector},
test_utils::MemoryDatabase,
EmptyExternalEnv, MegaContext, MegaEvm, MegaSpecId, MegaTransaction,
};
use op_revm::{
DefaultOp as _, OpBuilder as _, OpContext as OpContextPinned, OpSpecId as OpSpecIdPinned,
OpTransaction as OpTransactionPinned,
};
use op_revm_latest::{
DefaultOp as _, OpBuilder as _, OpContext as OpContextLatest, OpSpecId as OpSpecIdLatest,
OpTransaction as OpTransactionLatest,
};
use revm::{
context::tx::TxEnvBuilder, database::EmptyDB as EmptyDBPinned,
primitives::hardfork::SpecId as SpecIdPinned, Context as ContextPinned, ExecuteEvm,
MainBuilder as _, MainContext as _,
};
use revm_latest::{
bytecode::Bytecode as BytecodeLatest,
context::tx::TxEnvBuilder as TxEnvBuilderLatest,
database::{CacheDB as CacheDBLatest, EmptyDB as EmptyDBLatest},
primitives::hardfork::SpecId as SpecIdLatest,
Context as ContextLatest, ExecuteEvm as _, MainBuilder as _, MainContext as _,
};
pub const SPEC_IDS: &[(&str, MegaSpecId)] = &[
("equivalence", MegaSpecId::EQUIVALENCE),
("mini_rex", MegaSpecId::MINI_REX),
("rex4", MegaSpecId::REX4),
];
pub fn make_mega_evm(
db: MemoryDatabase,
spec: MegaSpecId,
) -> MegaEvm<MemoryDatabase, NoOpInspector, EmptyExternalEnv> {
let mut context = MegaContext::new(db, spec);
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::ZERO);
chain.operator_fee_constant = Some(U256::ZERO);
});
MegaEvm::new(context)
}
pub fn build_mega_tx(tx: TxEnv) -> MegaTransaction {
let mut mega_tx = MegaTransaction::new(tx);
mega_tx.enveloped_tx = Some(Bytes::new());
mega_tx
}
#[derive(Clone)]
pub struct CallParams {
pub caller: Address,
pub target: Address,
pub gas_limit: u64,
pub value: U256,
pub data: Bytes,
}
impl Default for CallParams {
fn default() -> Self {
Self {
caller: Address::ZERO,
target: Address::ZERO,
gas_limit: 30_000_000,
value: U256::ZERO,
data: Bytes::new(),
}
}
}
pub fn transact_call_revm_pinned(db: MemoryDatabase, p: &CallParams) {
let mut evm = ContextPinned::mainnet()
.modify_cfg_chained(|cfg| cfg.spec = SpecIdPinned::CANCUN)
.with_db(db)
.build_mainnet();
let tx = TxEnvBuilder::new()
.caller(p.caller)
.call(p.target)
.gas_limit(p.gas_limit)
.value(p.value)
.data(p.data.clone())
.build_fill();
let r = evm.transact(tx).expect("revm_pinned transact");
assert!(r.result.is_success(), "revm_pinned should succeed: {:?}", r.result);
black_box(r);
}
pub fn transact_call_op_revm_pinned(db: MemoryDatabase, p: &CallParams) {
let mut ctx = <OpContextPinned<EmptyDBPinned>>::op().with_db(db);
ctx.modify_cfg(|cfg| cfg.spec = OpSpecIdPinned::HOLOCENE);
ctx.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::ZERO);
chain.operator_fee_constant = Some(U256::ZERO);
});
let mut evm = ctx.build_op();
let tx_env = TxEnvBuilder::new()
.caller(p.caller)
.call(p.target)
.gas_limit(p.gas_limit)
.value(p.value)
.data(p.data.clone())
.build_fill();
let mut op_tx = OpTransactionPinned::new(tx_env);
op_tx.enveloped_tx = Some(Bytes::new());
let r = evm.transact(op_tx).expect("op_revm_pinned transact");
assert!(r.result.is_success(), "op_revm_pinned should succeed: {:?}", r.result);
black_box(r);
}
pub fn transact_call_revm_latest(db: CacheDBLatest<EmptyDBLatest>, p: &CallParams) {
let mut evm = ContextLatest::mainnet()
.modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecIdLatest::CANCUN))
.with_db(db)
.build_mainnet();
let tx = TxEnvBuilderLatest::new()
.caller(p.caller)
.call(p.target)
.gas_limit(p.gas_limit)
.value(p.value)
.data(p.data.clone())
.build_fill();
let r = evm.transact(tx).expect("revm_latest transact");
assert!(r.result.is_success(), "revm_latest should succeed: {:?}", r.result);
black_box(r);
}
pub fn transact_call_op_revm_latest(db: CacheDBLatest<EmptyDBLatest>, p: &CallParams) {
let mut ctx = <OpContextLatest<EmptyDBLatest>>::op().with_db(db);
ctx.modify_cfg(|cfg| cfg.spec = OpSpecIdLatest::HOLOCENE);
ctx.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::ZERO);
chain.operator_fee_constant = Some(U256::ZERO);
});
let mut evm = ctx.build_op();
let tx_env = TxEnvBuilderLatest::new()
.caller(p.caller)
.call(p.target)
.gas_limit(p.gas_limit)
.value(p.value)
.data(p.data.clone())
.build_fill();
let mut op_tx = OpTransactionLatest::new(tx_env);
op_tx.enveloped_tx = Some(Bytes::new());
let r = evm.transact(op_tx).expect("op_revm_latest transact");
assert!(r.result.is_success(), "op_revm_latest should succeed: {:?}", r.result);
black_box(r);
}
#[derive(Default)]
pub struct LatestDbBuilder {
db: CacheDBLatest<EmptyDBLatest>,
}
impl LatestDbBuilder {
pub fn new() -> Self {
Self { db: CacheDBLatest::new(EmptyDBLatest::default()) }
}
pub fn account_code(mut self, address: Address, code: Bytes) -> Self {
let bytecode = BytecodeLatest::new_legacy(code);
let code_hash = bytecode.hash_slow();
let entry = self.db.cache.accounts.entry(address).or_default();
entry.info.code = Some(bytecode);
entry.info.code_hash = code_hash;
self
}
pub fn account_balance(mut self, address: Address, balance: U256) -> Self {
let entry = self.db.cache.accounts.entry(address).or_default();
entry.info.balance = balance;
self
}
pub fn account_storage(mut self, address: Address, slot: U256, value: U256) -> Self {
let entry = self.db.cache.accounts.entry(address).or_default();
entry.storage.insert(slot, value);
self
}
pub fn build(self) -> CacheDBLatest<EmptyDBLatest> {
self.db
}
}
pub fn add_baseline_rows<FP, FL>(
group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>,
params: &CallParams,
make_pinned_db: &FP,
make_latest_db: &FL,
) where
FP: Fn() -> MemoryDatabase,
FL: Fn() -> CacheDBLatest<EmptyDBLatest>,
{
add_baseline_rows_suffixed(group, "", params, make_pinned_db, make_latest_db);
}
pub fn add_baseline_rows_suffixed<FP, FL>(
group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>,
variant: &str,
params: &CallParams,
make_pinned_db: &FP,
make_latest_db: &FL,
) where
FP: Fn() -> MemoryDatabase,
FL: Fn() -> CacheDBLatest<EmptyDBLatest>,
{
let with = |base: &str| -> String {
if variant.is_empty() {
base.to_string()
} else {
format!("{base}/{variant}")
}
};
group.bench_function(with("revm_pinned"), |b| {
b.iter(|| transact_call_revm_pinned(make_pinned_db(), params))
});
group.bench_function(with("revm_latest"), |b| {
b.iter(|| transact_call_revm_latest(make_latest_db(), params))
});
group.bench_function(with("op_revm_pinned"), |b| {
b.iter(|| transact_call_op_revm_pinned(make_pinned_db(), params))
});
group.bench_function(with("op_revm_latest"), |b| {
b.iter(|| transact_call_op_revm_latest(make_latest_db(), params))
});
}