revm-ee-tests 集成测试指南:基于快照机制验证 revm 与 op-revm 的 OP Stack 执行语义

发布时间:2026/9/18 9:14:35
revm-ee-tests 集成测试指南:基于快照机制验证 revm 与 op-revm 的 OP Stack 执行语义 revm-ee-tests 集成测试指南基于快照机制验证 revm 与 op-revm 的 OP Stack 执行语义【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism导读revm-ee-tests是 Optimism 仓库rust/工作区中一个面向revm与op-revm的共享测试工具与集成测试 crate核心定位是为 OP Stack 的 EVM 执行层语义存款交易、预编译合约、系统调用、L1 区块信息等提供首次运行自动生成快照、后续运行逐字节比对的可回归测试框架。阅读本文后你将掌握该 crate 的运行方式、快照比对工具的底层实现原理以及它如何用一组Context::op()构建的集成测试覆盖 OP 链上各硬分叉FJORD、GRANITE、HOLOCENE、ISTHMUS 等的关键执行行为。crate 定位连接 revm 与 op-revm 的测试枢纽从 Cargo.toml 可以看到该 crate 的依赖结构决定了它的枢纽地位revm启用serde、stdfeature以太坊 EVM 参考实现提供Context、ExecuteEvm、InspectEvm、Inspector、Journal等核心执行与观测接口op-revm启用serdefeatureOP Stack 的 EVM 扩展提供OpTransaction、L1BlockInfo、OpHaltReason、OpSpecId以及各 OP 专属预编译合约serde/serde_json启用preserve_order支撑执行结果与状态快照的序列化、反序列化与比对。此外它还暴露了一个可选 featureoptional_balance_check用于联动op-revm/optional_balance_check控制是否跳过交易余额检查详见后文。crate 本身版本为0.2.0是工作区内各 REVM 系 crate 共享的测试基础设施源码入口见 src/lib.rs 与 src/op_revm_tests.rs。快速开始运行全部与定向测试根据 README.md测试通过cargo test驱动位于工作区根目录rust/下执行# 运行全部测试 cargo test -p revm-ee-tests # 运行特定测试子集例如 TIP-1016 状态 gas 测试 cargo test -p revm-ee-tests tip1016-p revm-ee-tests指定包名第二条命令中的tip1016是 cargo 的测试名过滤参数cargo 会按子串匹配测试函数名凡是名称中包含tip1016的测试都会被执行。这是阅读该 crate 时最常用的两条命令也是 CI 中验证 revm 行为是否回归的入口。值得强调的是快照测试的运行机制快照测试数据在首次运行时自动生成并在后续运行中作为期望值参与比对。这意味着你拿到一个全新的 clone 时直接cargo test -p revm-ee-tests即可得到完整的tests/下的 JSON 数据而一旦代码逻辑发生变更导致执行结果与既有快照不一致测试会立即失败并打印期望值与实际值的差异。快照比对工具的实现原理快照机制的核心是 src/lib.rs 中的compare_or_save_testdata与其更灵活的变体compare_or_save_testdata_with_config二者都依赖TestdataConfig配置结构pub struct TestdataConfig { pub testdata_dir: PathBuf, // 测试数据文件存放目录 }TestdataConfig::default()指向tests/testdata而 OP 集成测试则通过自定义配置指向tests/op_revm_testdata见 src/op_revm_tests.rs。比对函数的执行流程可以拆解为五个关键步骤序列化将执行输出output实现serde::Serialize Deserialize PartialEq Debug序列化为 JSON 字符串规范化反序列化为serde_json::Value后调用sort_all_objects()对所有对象按键排序消除字段顺序导致的误报差异首次运行落盘若目标文件不存在则直接以 pretty 格式写入并打印Saved testdata to ...本轮测试视为通过再次运行比对若文件已存在读取期望 JSON 并反序列化为T与本次执行输出直接进行PartialEq相等比较失败即 panic不相等时以assert!断言失败并同时输出期望值与实际值方便定位执行语义的漂移。此外该 crate 自带一个单元测试test_compare_or_save_testdata用一个value: 42的示例结构体演示了首次保存、后续比对的完整生命周期src/lib.rs是理解该工具最小用法的绝佳范本。快照数据长什么样以 test_deposit_tx.json 为例以 tests/op_revm_testdata/test_deposit_tx.json 为例快照 JSON 顶层只有两个字段result执行结果包含Success分支下的 gas 明细floor_gas、gas_refunded、gas_spent、intrinsic_gas、limit、logs、outputCall形式返回的字节以及结束原因reason如Stopstate交易执行后的世界状态按地址索引记录账户的infobalance、code、code_hash、nonce、original_info、status如Touched | LoadedAsNotExisting、storage与transaction_id。注意gas.limit为16777216这正是eip7825::TX_GAS_LIMIT_CAP的值说明 OP 链对交易 gas 上限有固定上限约束见test_halted_deposit_tx中ResultGas::default().with_total_gas_spent(eip7825::TX_GAS_LIMIT_CAP)的断言。这种结果 状态双视图快照能够同时捕获执行语义与状态写入两类回归。集成测试覆盖面op-revm 执行语义全景src/op_revm_tests.rs 中共约二十个集成测试全部以Context::op()构建 OP 专用执行上下文用evm.replay()/transact_one/inspect_tx驱动执行。按主题可分为六大类1. 存款交易Deposit Transactiontest_deposit_tx构造OpTransaction::builder().mint(100).source_hash(...)的存款交易在OpSpecId::HOLOCENE下执行断言零地址余额变为 100并落盘快照test_halted_deposit_tx在目标合约字节码为单条POP指令的情况下重放同一存款交易——POP无操作数必然触发 halt断言结果为ExecutionResult::Halt { reason: OpHaltReason::FailedDeposit, ... }且调用者余额为100 BENCH_CALLER_BALANCE即存款 mint 金额在失败时依然到账OP 存款交易的失败回滚语义手续费与 mint 计入但执行体失败。2. 预编译合约Precompilegas 边界这部分占测试主体覆盖三类密码学预编译secp256r1 P256VERIFYFJORD 引入test_tx_call_p256verify验证 gas 恰好为initial_total_gas P256VERIFY_BASE_GAS_FEE时调用成功test_halted_tx_call_p256verify将 gas_limit 减 1断言OutOfGas(OutOfGasError::Precompile)bn254 pairFJORD / GRANITE 行为差异对比test_halted_tx_call_bn254_pair_fjord在 FJORD 下输入超过GRANITE_MAX_INPUT_SIZE 2字节时报预编译 gas 不足out of gas而test_halted_tx_call_bn254_pair_granite在 GRANITE 下同输入直接以PrecompileErrorWithContext(bn254 invalid pair length)提前退出——两个测试精确锁定了该预编译在相邻硬分叉之间的语义变化bls12-381 全家桶ISTHMUS 引入G1/G2 add、G1/G2 MSM多点标量乘法、pairing、map_fp_to_g1、map_fp2_to_g2各自成对测试out of gas与input wrong size / wrong layout两类失败路径断言的具体错误消息如bls12-381 g1 add input length error、bls12-381 fp 64 top bytes of input are not zero直接来自预编译实现。值得注意的实现细节是bl12_381系列测试都通过.modify_chain_chained(|l1_block| { l1_block.operator_fee_constant Some(U256::ZERO); l1_block.operator_fee_scalar Some(U256::ZERO) })将 operator fee 置零从而隔离出纯粹的预编译 gas 计算路径避免手续费分摊干扰断言。而 gas 计算本身借助 revm 的calculate_initial_tx_gas与bls12_381_utils::msm_required_gas精确构造对应实现可参见 rust/op-revm/src/precompiles.rs 中的bls12_381_const/bls12_381_utils模块。3. L1 区块信息加载L1BlockInfotest_l1block_load_for_pre_regolith在OpSpecId::REGOLITH下调用 OP 预部署地址0x0000000000000000000000000000000000100000同时把l1_block.l2_block置为None验证 pre-Regolith 时代 L1Block 合约在缺少 L2 区块头信息时仍能成功执行——这是对 L1 区块信息编码兼容性的回归保护。4. Inspector 观测与系统调用test_log_inspector自定义LogInspector实现revm::Inspectortrait 的log回调对一个构造期即LOG0的 Yul 合约执行inspect_tx断言捕获到日志并落盘快照test_system_call_inspection覆盖inspect_one_system_call、inspect_one_system_call_with_caller、inspect_one_system_call_with_inspector三种系统调用观测 APItest_system_call直接执行system_call_one后finalize断言系统地址SYSTEM_ADDRESS未进入最终状态、目标账户被标记为touched——验证了系统调用对状态写入的收尾规则。5. 可选余额检查optional_balance_checktest_disable_balance_check使用#[cfg(feature optional_balance_check)]条件编译仅在启用该 feature 时编译运行。测试构造了gas_price 1, gas_limit 100_000且value BENCH_CALLER_BALANCE - 1的交易——其有效成本将超过调用者余额——配合.modify_cfg_chained(|cfg| cfg.disable_balance_check true)关闭余额检查后交易仍成功执行且合约返回的BALANCE为 0证明全部有效成本已被扣除。硬分叉覆盖矩阵OpSpecId 与预编译的对应关系测试中频繁出现的OpSpecId见 rust/op-revm/src/spec.rs是 OP 链硬分叉的标识枚举从BEDROCK100起按序递增测试覆盖到REGOLITH、FJORD、GRANITE、HOLOCENE、ISTHMUS等。其与底层以太坊硬分叉的映射为BEDROCK/REGOLITH → MERGE、ECOTONE/FJORD/GRANITE/HOLOCENE → CANCUN、ISTHMUS/JOVIAN → PRAGUE。对照测试矩阵可以得到一张清晰的分叉 × 预编译关系表预编译能力引入分叉对应测试Deposit transactionBedrock 起test_deposit_tx/test_halted_deposit_txP256VERIFYsecp256r1FJORDtest_tx_call_p256verify/test_halted_tx_call_p256verifybn254 pairgas 语义收紧FJORD → GRANITE 变化test_halted_tx_call_bn254_pair_fjord/_granitebls12-381add/MSM/pairing/mapISTHMUS13 个test_halted_tx_call_bls12_381_*L1BlockInfo 兼容REGOLITH 及以前test_l1block_load_for_pre_regolith这正是快照测试的价值所在硬分叉升级时同一输入在不同OpSpecId下可能产生截然不同的 halt 原因与 gas 消耗而快照机制让这些差异变成可追踪、可评审的显式 JSON 差异。在 CI 与日常开发中的使用建议改动 revm / op-revm 后必跑全量cargo test -p revm-ee-tests是验证执行语义是否回退的最低成本手段任何result或state快照差异都意味着行为变化需要人工确认是否预期新增功能测试的推荐姿势仿照compare_or_save_op_testdata的模式新测试先跑一遍生成快照人工 review JSON 后再提交后续迭代即可自动防回归定向过滤加速调试当只想验证某个预编译时用cargo test -p revm-ee-tests 子串过滤测试名例如cargo test -p revm-ee-tests bls12feature 开关验证需要验证disable_balance_check相关行为时记得带上 feature 编译cargo test -p revm-ee-tests --features optional_balance_check。综上revm-ee-tests以极简的保存-比对快照哲学为 OP Stack 最敏感的 EVM 执行语义尤其是跨硬分叉的预编译行为提供了可靠的回归防线是理解 op-revm 行为差异时最值得优先阅读的测试资产。【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考