use std::convert::Infallible;
use alloy_evm::{
block::{BlockExecutor, BlockExecutorFactory},
EvmEnv, EvmFactory,
};
use alloy_hardforks::ForkCondition;
use alloy_op_evm::block::receipt_builder::OpAlloyReceiptBuilder;
use alloy_primitives::{Bytes, B256, U256};
use mega_evm::{
test_utils::MemoryDatabase, BlockLimits, EvmTxRuntimeLimits, MegaBlockExecutionCtx,
MegaBlockExecutorFactory, MegaEvmFactory, MegaHardfork, MegaHardforkConfig, MegaSpecId,
TestExternalEnvs,
};
use revm::{context::BlockEnv, database::State, handler::EvmTr};
const NON_DEFAULT_TX_COMPUTE_GAS_LIMIT: u64 = 1_234_567;
fn evm_env_for_spec(spec: MegaSpecId) -> EvmEnv<MegaSpecId> {
let mut cfg_env = revm::context::CfgEnv::default();
cfg_env.spec = spec;
cfg_env.chain_id = 8453;
let block_env = BlockEnv {
number: U256::from(1000),
timestamp: U256::from(1_800_000_000),
gas_limit: 30_000_000,
..Default::default()
};
EvmEnv::new(cfg_env, block_env)
}
fn chain_spec_at(hardfork: MegaHardfork) -> MegaHardforkConfig {
MegaHardforkConfig::default().with(hardfork, ForkCondition::Timestamp(0))
}
fn block_ctx_with_compute_gas_limit(limit: u64) -> MegaBlockExecutionCtx {
MegaBlockExecutionCtx::new(
B256::ZERO,
None,
Bytes::new(),
BlockLimits::no_limits().with_tx_compute_gas_limit(limit),
)
}
#[test]
fn test_trait_path_applies_block_context_compute_gas_limit_rex5() {
let mut db = MemoryDatabase::default();
let mut state = State::builder().with_database(&mut db).build();
let external_envs = TestExternalEnvs::<Infallible>::new();
let evm_factory = MegaEvmFactory::new().with_external_env_factory(external_envs);
let chain_spec = chain_spec_at(MegaHardfork::Rex5);
let receipt_builder = OpAlloyReceiptBuilder::default();
let factory = MegaBlockExecutorFactory::new(chain_spec, evm_factory, receipt_builder);
let evm = factory.evm_factory().create_evm(&mut state, evm_env_for_spec(MegaSpecId::REX5));
let ctx = block_ctx_with_compute_gas_limit(NON_DEFAULT_TX_COMPUTE_GAS_LIMIT);
let executor = <MegaBlockExecutorFactory<_, _, _> as BlockExecutorFactory>::create_executor(
&factory, evm, ctx,
);
assert_eq!(
executor.evm().ctx_ref().additional_limit.borrow().limits.tx_compute_gas_limit,
NON_DEFAULT_TX_COMPUTE_GAS_LIMIT,
"trait factory must propagate block_ctx.block_limits.tx_compute_gas_limit \
to the prebuilt EVM's runtime limits under REX5",
);
}
#[test]
fn test_trait_path_applies_block_context_compute_gas_limit_rex4() {
let mut db = MemoryDatabase::default();
let mut state = State::builder().with_database(&mut db).build();
let external_envs = TestExternalEnvs::<Infallible>::new();
let evm_factory = MegaEvmFactory::new().with_external_env_factory(external_envs);
let chain_spec = chain_spec_at(MegaHardfork::Rex4);
let receipt_builder = OpAlloyReceiptBuilder::default();
let factory = MegaBlockExecutorFactory::new(chain_spec, evm_factory, receipt_builder);
let evm = factory.evm_factory().create_evm(&mut state, evm_env_for_spec(MegaSpecId::REX4));
let ctx = block_ctx_with_compute_gas_limit(NON_DEFAULT_TX_COMPUTE_GAS_LIMIT);
let executor = <MegaBlockExecutorFactory<_, _, _> as BlockExecutorFactory>::create_executor(
&factory, evm, ctx,
);
assert_eq!(
executor.evm().ctx_ref().additional_limit.borrow().limits.tx_compute_gas_limit,
NON_DEFAULT_TX_COMPUTE_GAS_LIMIT,
"trait factory must propagate block_ctx.block_limits.tx_compute_gas_limit \
to the prebuilt EVM's runtime limits under REX4",
);
}
#[test]
fn test_inherent_and_trait_paths_apply_same_runtime_limits() {
let chain_spec = chain_spec_at(MegaHardfork::Rex5);
let receipt_builder = OpAlloyReceiptBuilder::default();
let inherent_limit: u64 = {
let mut db = MemoryDatabase::default();
let mut state = State::builder().with_database(&mut db).build();
let external_envs = TestExternalEnvs::<Infallible>::new();
let evm_factory = MegaEvmFactory::new().with_external_env_factory(external_envs);
let factory =
MegaBlockExecutorFactory::new(chain_spec.clone(), evm_factory, receipt_builder);
let ctx = block_ctx_with_compute_gas_limit(NON_DEFAULT_TX_COMPUTE_GAS_LIMIT);
let executor = factory.create_executor(&mut state, ctx, evm_env_for_spec(MegaSpecId::REX5));
let limit = executor.evm().ctx_ref().additional_limit.borrow().limits.tx_compute_gas_limit;
limit
};
let trait_limit: u64 = {
let mut db = MemoryDatabase::default();
let mut state = State::builder().with_database(&mut db).build();
let external_envs = TestExternalEnvs::<Infallible>::new();
let evm_factory = MegaEvmFactory::new().with_external_env_factory(external_envs);
let factory = MegaBlockExecutorFactory::new(chain_spec, evm_factory, receipt_builder);
let evm = factory.evm_factory().create_evm(&mut state, evm_env_for_spec(MegaSpecId::REX5));
let ctx = block_ctx_with_compute_gas_limit(NON_DEFAULT_TX_COMPUTE_GAS_LIMIT);
let executor = <MegaBlockExecutorFactory<_, _, _> as BlockExecutorFactory>::create_executor(
&factory, evm, ctx,
);
let limit = executor.evm().ctx_ref().additional_limit.borrow().limits.tx_compute_gas_limit;
limit
};
assert_eq!(
inherent_limit, NON_DEFAULT_TX_COMPUTE_GAS_LIMIT,
"inherent factory must apply the configured tx_compute_gas_limit",
);
assert_eq!(
trait_limit, NON_DEFAULT_TX_COMPUTE_GAS_LIMIT,
"trait factory must apply the configured tx_compute_gas_limit",
);
assert_eq!(
inherent_limit, trait_limit,
"inherent and trait construction routes must produce identical \
tx_compute_gas_limit values for the same BlockLimits",
);
}
#[test]
fn test_trait_path_idempotent_when_caller_pre_applied_runtime_limits() {
let mut db = MemoryDatabase::default();
let mut state = State::builder().with_database(&mut db).build();
let external_envs = TestExternalEnvs::<Infallible>::new();
let evm_factory = MegaEvmFactory::new().with_external_env_factory(external_envs);
let chain_spec = chain_spec_at(MegaHardfork::Rex5);
let receipt_builder = OpAlloyReceiptBuilder::default();
let factory = MegaBlockExecutorFactory::new(chain_spec, evm_factory, receipt_builder);
let block_limits =
BlockLimits::no_limits().with_tx_compute_gas_limit(NON_DEFAULT_TX_COMPUTE_GAS_LIMIT);
let pre_applied: EvmTxRuntimeLimits = block_limits.to_evm_tx_runtime_limits();
let evm = factory
.evm_factory()
.create_evm(&mut state, evm_env_for_spec(MegaSpecId::REX5))
.with_tx_runtime_limits(pre_applied);
let ctx = MegaBlockExecutionCtx::new(B256::ZERO, None, Bytes::new(), block_limits);
let executor = <MegaBlockExecutorFactory<_, _, _> as BlockExecutorFactory>::create_executor(
&factory, evm, ctx,
);
assert_eq!(
executor.evm().ctx_ref().additional_limit.borrow().limits.tx_compute_gas_limit,
NON_DEFAULT_TX_COMPUTE_GAS_LIMIT,
"trait factory's runtime-limit synchronization must be idempotent for \
callers that already applied the same limits via with_tx_runtime_limits",
);
}