如何用Foundry的有状态模糊测试验证事件触发条件?
用有状态模糊测试验证Solidity合约事件触发的前置条件
测试目标
确保合约触发Abstain(Type.One)事件时,someVar的值始终不为0。由于_someFunc、_someFunc2是内部函数且被多处调用,需要用有状态模糊测试覆盖所有可能的代码路径,排查是否存在违反该条件的场景。
实现步骤(以Foundry为例)
1. 编写测试合约
创建继承目标合约的测试合约,通过监听事件+状态校验的方式实现验证逻辑:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "../src/YourTargetContract.sol"; // 替换为你的合约实际路径 contract TargetContractFuzzTest is Test { YourTargetContract public contractUnderTest; function setUp() public { // 每次测试前重新部署合约,保证初始状态一致 contractUnderTest = new YourTargetContract(); } // 有状态模糊测试:覆盖所有调用内部函数的外部入口 function testFuzz_AbstainOneRequiresNonZeroSomeVar(uint256 randomInput) public { // 调用所有可能触发_internal函数的外部/公共函数 // 替换为你的合约中实际存在的入口函数,传入模糊生成的参数 contractUnderTest.publicFuncA(randomInput); contractUnderTest.publicFuncB(randomInput); // ... 其他调用_internal函数的入口 // 捕获合约触发的所有日志 Vm.Log[] memory logs = vm.getRecordedLogs(); for (uint256 i = 0; i < logs.length; i++) { // 解析Abstain事件的参数 (Type emittedType) = abi.decode(logs[i].data, (Type)); // 当事件类型为Type.One时,强制校验someVar不为0 if (emittedType == Type.One) { // 若someVar是私有变量,需在目标合约中添加getter函数 assert(contractUnderTest.getSomeVar() != 0); } } // 重置日志记录,避免影响后续测试 vm.recordLogs(); } }
2. 关键细节处理
- 私有变量访问:如果
someVar是私有变量,必须在目标合约中添加一个视图类型的getter函数:function getSomeVar() external view returns (uint256) { return someVar; } - 入口函数全覆盖:必须确保测试中调用了所有会触发
_someFunc/_someFunc2的外部函数,否则会遗漏潜在的违规路径。 - 参数范围限制:如果输入参数有取值约束(比如仅支持uint8类型),可以调整参数类型,或用
bound(randomInput, minValue, maxValue)来缩小模糊范围,提升测试效率。
3. 运行测试
执行Foundry测试命令,指定目标测试函数:
forge test --match-test testFuzz_AbstainOneRequiresNonZeroSomeVar -vvv
若存在违反条件的代码路径,测试会直接抛出断言错误,并输出触发该场景的调用序列与合约状态。
内容的提问来源于stack exchange,提问作者Ren
相关产品推荐
相关产品推荐

