use std::convert::Infallible;
use alloy_primitives::{address, Address, Bytes, U256};
use mega_evm::{
test_utils::{BytecodeBuilder, MemoryDatabase},
EvmTxRuntimeLimits, MegaContext, MegaEvm, MegaHaltReason, MegaSpecId, MegaTransaction,
MegaTransactionError,
};
use revm::{
bytecode::opcode::*,
context::{
result::{EVMError, ExecutionResult, ResultAndState},
tx::TxEnvBuilder,
TxEnv,
},
};
const CALLER: Address = address!("0000000000000000000000000000000000100000");
const FACTORY: Address = address!("0000000000000000000000000000000000200001");
fn create_init_code() -> Vec<u8> {
vec![PUSH1, 0x01, PUSH0, SSTORE, PUSH1, 0x01, PUSH0, RETURN]
}
fn create_factory_code() -> Bytes {
let init = create_init_code();
let init_len = init.len() as u64;
BytecodeBuilder::default()
.mstore(0, init) .push_number(init_len) .push_number(0_u64) .push_number(0_u64) .append(CREATE)
.append(POP)
.append(STOP)
.build()
}
fn transact_with_kv_limit(
db: &mut MemoryDatabase,
kv_update_limit: u64,
tx: TxEnv,
) -> Result<ResultAndState<MegaHaltReason>, EVMError<Infallible, MegaTransactionError>> {
let mut context = MegaContext::new(db, MegaSpecId::MINI_REX).with_tx_runtime_limits(
EvmTxRuntimeLimits::no_limits().with_tx_kv_updates_limit(kv_update_limit),
);
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::from(0));
chain.operator_fee_constant = Some(U256::from(0));
});
let mut evm = MegaEvm::new(context);
let mut tx = MegaTransaction::new(tx);
tx.enveloped_tx = Some(Bytes::new());
alloy_evm::Evm::transact_raw(&mut evm, tx)
}
#[test]
fn test_before_frame_run_short_circuits_already_exceeded_create_frame() {
let mut db = MemoryDatabase::default().account_balance(CALLER, U256::from(1_000_000));
db.set_account_code(FACTORY, create_factory_code());
let tx =
TxEnvBuilder::default().caller(CALLER).call(FACTORY).gas_limit(10_000_000).build_fill();
let result = transact_with_kv_limit(&mut db, 2, tx).unwrap();
let gas_used = match &result.result {
ExecutionResult::Halt {
reason: MegaHaltReason::KVUpdateLimitExceeded { .. },
gas_used,
} => *gas_used,
other => panic!("expected KVUpdateLimitExceeded halt, got {other:?}"),
};
assert_eq!(
gas_used, GAS_USED_SHORT_CIRCUITED,
"before_frame_run must short-circuit the over-budget CREATE frame before its \
constructor runs; a different gas_used means the short-circuit was dropped"
);
}
const GAS_USED_SHORT_CIRCUITED: u64 = 2_053_023;