diff --git a/crates/mega-evm/tests/rex4/deployment.rs b/crates/mega-evm/tests/rex4/deployment.rs new file mode 100644 index 0000000..2c2a043 --- /dev/null +++ b/crates/mega-evm/tests/rex4/deployment.rs @@ -0,0 +1,192 @@ +//! Tests for Rex4 system contract deployment wiring. + +use alloy_evm::{block::BlockExecutor, Database, Evm, EvmEnv, EvmFactory}; +use alloy_hardforks::ForkCondition; +use alloy_op_evm::block::receipt_builder::OpAlloyReceiptBuilder; +use alloy_primitives::{Address, B256, Bytes}; +use mega_evm::{ + test_utils::MemoryDatabase, BlockLimits, MegaBlockExecutionCtx, MegaBlockExecutor, + MegaEvmFactory, MegaHardfork, MegaHardforkConfig, MegaSpecId, ACCESS_CONTROL_ADDRESS, + ACCESS_CONTROL_CODE, ACCESS_CONTROL_CODE_HASH, LIMIT_CONTROL_ADDRESS, LIMIT_CONTROL_CODE, + LIMIT_CONTROL_CODE_HASH, +}; +use revm::{context::BlockEnv, database::State, primitives::U256}; + +fn rex4_chain_spec() -> MegaHardforkConfig { + MegaHardforkConfig::default().with(MegaHardfork::Rex4, ForkCondition::Timestamp(0)) +} + +fn rex3_chain_spec() -> MegaHardforkConfig { + MegaHardforkConfig::default().with(MegaHardfork::Rex3, ForkCondition::Timestamp(0)) +} + +fn make_block_env(timestamp: u64) -> BlockEnv { + BlockEnv { + number: U256::from(1_u64), + timestamp: U256::from(timestamp), + gas_limit: 30_000_000, + ..Default::default() + } +} + +fn assert_contract_deployed( + db: &mut State, + address: Address, + expected_code_hash: B256, + expected_code: Bytes, + name: &str, +) { + let cache_acc = db.load_cache_account(address).expect("should load cache account"); + let acc_info = cache_acc.account_info().expect("system contract account should exist"); + + assert_eq!( + acc_info.code_hash, expected_code_hash, + "{name} code hash should match expected bytecode" + ); + assert!(acc_info.code.is_some(), "{name} code should be set"); + let deployed_code = acc_info.code.as_ref().expect("code should be present"); + assert_eq!( + deployed_code.original_bytes(), + expected_code, + "{name} bytecode should match the embedded system contract code" + ); +} + +fn assert_contract_not_deployed( + db: &mut State, + address: Address, + name: &str, +) { + let cache_acc = db.load_cache_account(address).expect("should load cache account"); + assert!( + cache_acc.account_info().is_none(), + "{name} should not be deployed for this spec boundary" + ); +} + +#[test] +fn test_rex4_system_contracts_deployed_on_activation() { + let mut db = MemoryDatabase::default(); + let mut state = State::builder().with_database(&mut db).build(); + + let mut cfg_env = revm::context::CfgEnv::default(); + cfg_env.spec = MegaSpecId::REX4; + let evm_env = EvmEnv::new(cfg_env, make_block_env(0)); + + let evm_factory = MegaEvmFactory::new(); + let evm = evm_factory.create_evm(&mut state, evm_env); + let block_ctx = MegaBlockExecutionCtx::new( + B256::ZERO, + Some(B256::ZERO), + Default::default(), + BlockLimits::no_limits(), + ); + let receipt_builder = OpAlloyReceiptBuilder::default(); + let mut executor = MegaBlockExecutor::new(evm, block_ctx, rex4_chain_spec(), receipt_builder); + + executor.apply_pre_execution_changes().expect("pre-execution changes should succeed"); + + let db_ref = executor.evm_mut().db_mut(); + assert_contract_deployed( + db_ref, + ACCESS_CONTROL_ADDRESS, + ACCESS_CONTROL_CODE_HASH, + ACCESS_CONTROL_CODE, + "MegaAccessControl", + ); + assert_contract_deployed( + db_ref, + LIMIT_CONTROL_ADDRESS, + LIMIT_CONTROL_CODE_HASH, + LIMIT_CONTROL_CODE, + "MegaLimitControl", + ); +} + +#[test] +fn test_rex4_system_contract_deployment_is_idempotent() { + let mut db = MemoryDatabase::default(); + let mut state = State::builder().with_database(&mut db).build(); + + let mut cfg_env = revm::context::CfgEnv::default(); + cfg_env.spec = MegaSpecId::REX4; + let evm_env = EvmEnv::new(cfg_env, make_block_env(0)); + + let evm_factory = MegaEvmFactory::new(); + let evm = evm_factory.create_evm(&mut state, evm_env); + let block_ctx = MegaBlockExecutionCtx::new( + B256::ZERO, + Some(B256::ZERO), + Default::default(), + BlockLimits::no_limits(), + ); + let receipt_builder = OpAlloyReceiptBuilder::default(); + let mut executor = MegaBlockExecutor::new(evm, block_ctx, rex4_chain_spec(), receipt_builder); + + executor.apply_pre_execution_changes().expect("first pre-execution changes should succeed"); + + { + let db_ref = executor.evm_mut().db_mut(); + assert_contract_deployed( + db_ref, + ACCESS_CONTROL_ADDRESS, + ACCESS_CONTROL_CODE_HASH, + ACCESS_CONTROL_CODE, + "MegaAccessControl", + ); + assert_contract_deployed( + db_ref, + LIMIT_CONTROL_ADDRESS, + LIMIT_CONTROL_CODE_HASH, + LIMIT_CONTROL_CODE, + "MegaLimitControl", + ); + } + + executor + .apply_pre_execution_changes() + .expect("second pre-execution changes should also succeed"); + + let db_ref = executor.evm_mut().db_mut(); + assert_contract_deployed( + db_ref, + ACCESS_CONTROL_ADDRESS, + ACCESS_CONTROL_CODE_HASH, + ACCESS_CONTROL_CODE, + "MegaAccessControl after second apply", + ); + assert_contract_deployed( + db_ref, + LIMIT_CONTROL_ADDRESS, + LIMIT_CONTROL_CODE_HASH, + LIMIT_CONTROL_CODE, + "MegaLimitControl after second apply", + ); +} + +#[test] +fn test_rex3_boundary_does_not_deploy_rex4_system_contracts() { + let mut db = MemoryDatabase::default(); + let mut state = State::builder().with_database(&mut db).build(); + + let mut cfg_env = revm::context::CfgEnv::default(); + cfg_env.spec = MegaSpecId::REX3; + let evm_env = EvmEnv::new(cfg_env, make_block_env(0)); + + let evm_factory = MegaEvmFactory::new(); + let evm = evm_factory.create_evm(&mut state, evm_env); + let block_ctx = MegaBlockExecutionCtx::new( + B256::ZERO, + Some(B256::ZERO), + Default::default(), + BlockLimits::no_limits(), + ); + let receipt_builder = OpAlloyReceiptBuilder::default(); + let mut executor = MegaBlockExecutor::new(evm, block_ctx, rex3_chain_spec(), receipt_builder); + + executor.apply_pre_execution_changes().expect("pre-execution changes should succeed"); + + let db_ref = executor.evm_mut().db_mut(); + assert_contract_not_deployed(db_ref, ACCESS_CONTROL_ADDRESS, "MegaAccessControl"); + assert_contract_not_deployed(db_ref, LIMIT_CONTROL_ADDRESS, "MegaLimitControl"); +} diff --git a/crates/mega-evm/tests/rex4/main.rs b/crates/mega-evm/tests/rex4/main.rs index 703ccad..2513a5c 100644 --- a/crates/mega-evm/tests/rex4/main.rs +++ b/crates/mega-evm/tests/rex4/main.rs @@ -1,6 +1,7 @@ //! Tests for `Rex4` hardfork features. mod access_control; +mod deployment; mod frame_limits; mod frame_state_growth; mod gas_detention;