本文是Advanced Foundry Cheatcodes系列文章的第六部分,介绍了 Foundry 的高级模糊测试功能,通过随机输入参数自动发现智能合约的边缘情况,包括溢出、回滚等问题。文章还涉及了如何使用 forking cheat-codes 与主网合约交互,以及如何通过 vm.assume 和 bound() 来缩小输入范围,从而提高测试效率。
高级 Foundry 作弊码系列:第 6 部分 - 使用 Forge 进行高级模糊测试
认为你的测试覆盖了极端情况?Forge 的模糊测试证明你是错的。一个参数 = 数百个随机输入。自动捕获溢出、回滚和奇怪的错误。
在单行作弊码的基础上 来自第 5 部分,我们现在将方向盘交给随机性。今天的重点是 Forge 的内置模糊测试:你将看到参数化测试如何自动发现极端情况,以及边界、假设和基于 Fork 的模糊运行的技巧。
Forge 的内置模糊测试使用随机输入运行测试,从而实现智能合约的基于属性的测试。任何带有参数的 forge 测试函数都被视为模糊测试:例如:
在这个 testFuzz_ 函数中,Forge 会自动生成 许多 amount 的值,以尝试查找极端情况。它“将任何至少接受一个参数的测试作为基于属性的测试运行”。在实践中,Forge 将运行数百个随机案例,寻找任何违反断言的输入。如果它找到一个失败,它会报告具体的反例。
测试结构:模糊测试看起来类似于单元测试。按照惯例,在函数名称前加上前缀(通常是 testFuzz_)不是 Forge 严格要求的(它运行任何参数化测试),但它阐明了意图。主体使用输入参数设置场景,然后进行断言。在上面的示例中,我们测试了对于 任何 amount,提款都会返回 完全 存入的金额。如果极端值导致溢出或回滚,运行此操作可能会发现错误。
单元级别的模糊测试功能强大,但有时你必须与真实的 main-net 合约交互:读取 USDC 的 ERC-20 余额、调用 Uniswap 池或根据实时代理验证升级逻辑。Foundry 的答案是 forking 作弊码。Fork 是给定区块处另一个链的完整内存副本;你使用 vm.createFork 创建一个,并使用 vm.selectFork 激活它。选择 fork 后,每 一次 后续调用、日志和存储读取都会通过该远程状态,而写入仍然保留在你的测试本地。
createFork 是重载的。最简单的形式是采用 RPC URL 或别名并快照最新的区块。第二个变体允许你将 fork 锁定在显式的区块高度。
第三个重载接受交易哈希;Foundry 将 fork 滚动到挖掘该哈希的区块,重放该区块中的每 次 先前交易,并将执行定位在后状态。当你想要重放已知漏洞交易的确切环境时,这非常有用。
缩小条件:有时你只想模糊测试输入的子集。Forge 为此目的提供了 vm.assume(bool cond):如果条件为假,Forge 会丢弃该随机输入并尝试另一个。例如,要跳过零值,你可以编写 vm.assume(v != 0); require(v != 0);。这个 cheatsheet 警告说要谨慎使用 assume(广泛的条件会因为拒绝 许多 尝试而减慢模糊测试的速度)。另一种策略是使用 bound()(来自 Forge Std)将输入限制在一个范围内,而不是拒绝它们。例如:
function testFuzz_WithdrawalAmount(uint256 amount) public {
// 限制 amount 的范围
amount = bound(amount, 1, 100);
// 函数体
}
你可以触发模糊测试,就像触发普通测试一样,只需运行 forge test。Forge 会看到参数化函数签名并自动切换到其模糊器。要增加覆盖率或加快速度,你可以传递常用的 CLI 标志,例如:
forge test --match-test testFuzz_WithdrawalAmount --fuzz-runs 1000 -vv
--match-test 过滤器专注于你关心的模糊案例,--fuzz-runs 设置 Forge 将尝试的随机输入数量(默认为 256),-vv 提高详细程度,这样你就可以实时观察每个反例、gas读数和平均值/中值报告的滚动显示。
陷阱和提示:
最大拒绝次数:如果 太多 的输入被假设排除,模糊器可能会达到拒绝限制。你可以在 foundry.toml 中或使用 fuzz.max_test_rejects 配置此项。
状态性:每 一次 模糊调用都在一个新的 EVM 状态中运行(与普通测试相同)。确保你的测试设置(如 setUp())是幂等的。
可重复性:Forge 报告种子/反例,因此你可以重现失败的案例。
覆盖率:因为 Forge 运行数百个模糊案例,所以它显着提高了代码覆盖率。这对于安全关键型代码尤其有价值;Paradigm 报告说 v1.0 提高了模糊执行速度 2 倍,从而允许在 CI 中使用更多案例。
总而言之,Foundry 的模糊测试可以自动进行极端情况探索。使用参数化的 testFuzz_ 函数,利用 vm.assume 或 bound() 进行约束,并将失败解释为极端输入的具体示例。通过捕获人工编写的案例可能遗漏的内容来补充单元测试。
如果你喜欢这种类型的内容,请在 Twitter 上关注 @threesigmaxyz
并浏览我们的博客
以获取更多关于区块链主题的见解。
明天发布第 7 部分:Foundry 中的不变量测试
- 原文链接: x.com/threesigmaxyz/stat...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!