use alloy_primitives::{address, Bytes, TxKind, U256};
use mega_evm::{
test_utils::{BytecodeBuilder, MemoryDatabase},
MegaContext, MegaEvm, MegaSpecId, MegaTransaction, TestExternalEnvs, MEGA_SYSTEM_ADDRESS,
ORACLE_CONTRACT_ADDRESS,
};
use revm::{
bytecode::opcode::{CALL, GAS, POP, PUSH0, SLOAD, STOP},
context::TxEnv,
handler::EvmTr,
inspector::NoOpInspector,
};
const CALLEE: alloy_primitives::Address = address!("1000000000000000000000000000000000000001");
fn build_oracle_sload_code() -> Bytes {
BytecodeBuilder::default()
.append(PUSH0) .append(SLOAD) .append(POP)
.append(STOP)
.build()
}
#[test]
fn test_mega_system_address_exempted_from_rex3_sload_detention() {
let oracle_code = build_oracle_sload_code();
let mut db = MemoryDatabase::default();
db.set_account_code(ORACLE_CONTRACT_ADDRESS, oracle_code);
let external_envs = TestExternalEnvs::<std::convert::Infallible>::new();
let mut context =
MegaContext::new(&mut db, MegaSpecId::REX3).with_external_envs((&external_envs).into());
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::from(0));
chain.operator_fee_constant = Some(U256::from(0));
});
let tx = TxEnv {
caller: MEGA_SYSTEM_ADDRESS,
kind: TxKind::Call(ORACLE_CONTRACT_ADDRESS),
data: Default::default(),
value: U256::ZERO,
gas_limit: 1_000_000_000_000,
gas_price: 0,
..Default::default()
};
let mut tx = MegaTransaction::new(tx);
tx.enveloped_tx = Some(Bytes::new());
let mut evm = MegaEvm::new(context).with_inspector(NoOpInspector);
let result_envelope = alloy_evm::Evm::transact_raw(&mut evm, tx).unwrap();
let result = result_envelope.result;
assert!(result.is_success(), "Transaction from mega system address should succeed");
let oracle_accessed = evm
.ctx
.volatile_data_tracker
.try_borrow()
.map(|tracker| tracker.has_accessed_oracle())
.unwrap_or(false);
assert!(
!oracle_accessed,
"Oracle access should NOT be tracked for transactions from MEGA_SYSTEM_ADDRESS in Rex3"
);
let compute_gas_limit = evm
.ctx
.volatile_data_tracker
.try_borrow()
.map(|tracker| tracker.get_compute_gas_limit())
.unwrap_or(None);
assert!(
compute_gas_limit.is_none(),
"Compute gas limit should NOT be set for mega system address transactions"
);
}
#[test]
fn test_non_system_address_subject_to_rex3_sload_detention() {
let oracle_code = build_oracle_sload_code();
let callee_bytecode = BytecodeBuilder::default()
.append_many([PUSH0, PUSH0, PUSH0, PUSH0])
.push_number(0u8) .push_address(ORACLE_CONTRACT_ADDRESS)
.append(GAS)
.append(CALL)
.append(POP)
.append(STOP)
.build();
let mut db = MemoryDatabase::default();
db.set_account_code(ORACLE_CONTRACT_ADDRESS, oracle_code);
db.set_account_code(CALLEE, callee_bytecode);
let external_envs = TestExternalEnvs::<std::convert::Infallible>::new();
let mut context =
MegaContext::new(&mut db, MegaSpecId::REX3).with_external_envs((&external_envs).into());
context.modify_chain(|chain| {
chain.operator_fee_scalar = Some(U256::from(0));
chain.operator_fee_constant = Some(U256::from(0));
});
let regular_caller = address!("2000000000000000000000000000000000000002");
let tx = TxEnv {
caller: regular_caller,
kind: TxKind::Call(CALLEE),
data: Default::default(),
value: U256::ZERO,
gas_limit: 1_000_000_000_000,
gas_price: 0,
..Default::default()
};
let mut tx = MegaTransaction::new(tx);
tx.enveloped_tx = Some(Bytes::new());
let mut evm = MegaEvm::new(context).with_inspector(NoOpInspector);
let result_envelope = alloy_evm::Evm::transact_raw(&mut evm, tx).unwrap();
let result = result_envelope.result;
assert!(result.is_success(), "Transaction should succeed");
let oracle_accessed = evm
.ctx
.volatile_data_tracker
.try_borrow()
.map(|tracker| tracker.has_accessed_oracle())
.unwrap_or(false);
assert!(
oracle_accessed,
"Oracle access SHOULD be tracked for regular address transactions in Rex3"
);
let compute_gas_limit = evm.ctx_ref().additional_limit.borrow().compute_gas_limit();
assert_eq!(
compute_gas_limit,
mega_evm::constants::rex3::ORACLE_ACCESS_COMPUTE_GAS,
"Compute gas limit should be 20M for regular transactions accessing oracle in Rex3"
);
}