【引介】模糊测试库 Fuzzlib

Fuzzlib 是一个通用的 Solidity 模糊测试库,兼容 Echidna、Medusa 和 Foundry,提供了 assertions、value clamping、logging 和 math operations 等常用工具,方便进行有状态的和无状态的模糊测试。它通过 fl 命名空间提供常用工具,例如断言、值钳制、日志记录、数学运算等。

Fuzzlib 是一个通用的 Solidity 模糊测试库, 提供了 assertions、value clamping、logging 和 math operations 等常用工具,方便进行有状态的和无状态的模糊测试, 方便我们在测试 Solidity 合约时,发现更多的问题。

详见 Github: https://github.com/perimetersec/fuzzlib

以下介绍翻译自:Fuzzlib Github 的 Readme:

Fuzzlib

用于有状态和无状态模糊测试的通用、非主观的 Solidity 模糊测试库。兼容 Echidna、Medusa 和 Foundry。

通过简单的 fl 命名空间提供用于模糊测试的常用实用程序:断言、值钳位(value clamping)、日志记录、数学运算等。

主要特性

  • 基本断言:用于常见测试条件和相等性检查的助手函数
  • 高级断言:诸如通过 errAllow 进行错误处理的实用程序,用于预期的故障
  • 值钳位(value clamping):将值钳位到具有均匀分布的范围内,以获得更好的模糊测试效果
  • 日志记录实用程序:用于调试和跟踪的统一日志记录
  • 数学实用程序:诸如最小值、最大值、绝对值和差值计算之类的运算
  • 随机实用程序:Fisher-Yates 数组混排
  • 函数调用助手:用于通过 actor 欺骗进行函数调用的实用程序
  • 全面测试:具有单元测试和模糊测试的广泛测试套件
  • 良好文档:清晰而完整,遵循 OpenZeppelin 风格的约定

安装

使用 Foundry

forge install perimetersec/fuzzlib

使用 Soldeer

soldeer install perimetersec-fuzzlib~1.0.0

使用 npm

npm install @perimetersec/fuzzlib

添加到你的 remappings.txt

fuzzlib/=lib/fuzzlib/src/

快速开始

通过扩展 FuzzBase 来创建一个简单的模糊测试:

import {FuzzBase} from "fuzzlib/FuzzBase.sol";

contract MyFuzzer is FuzzBase {
    function testMath(uint256 a, uint256 b) public {
        // 将输入钳位到合理的范围内
        uint256 x = fl.clamp(a, 0, 1000);
        uint256 y = fl.clamp(b, 0, 1000);

        // 记录以进行调试
        fl.log("Testing max function. x =", x);
        fl.log("Testing max function. y =", y);

        // 测试数学性质
        fl.gte(fl.max(x, y), x, "Max should be >= x");
        fl.gte(fl.max(x, y), y, "Max should be >= y");
    }
}

函数参考

基本断言

// 基本断言
fl.t(exists, "Property X exists");
fl.eq(result, 100, "Result should equal 100");
fl.neq(userA, userB, "Users should be different");

// 比较断言
fl.gt(balance, 1000, "Balance should be greater than 1000");
fl.gte(amount, 50, "Amount should be greater than or equal to 50");
fl.lt(fee, 100, "Fee should be less than 100");
fl.lte(price, 500, "Price should be less than or equal to 500");

高级断言

// 允许特定的 require 消息
string[] memory allowedMessages = new string[](1);
allowedMessages[0] = "Insufficient balance";
fl.errAllow(errorData, allowedMessages, "Message X should be allowed");

// 允许特定的自定义错误
bytes4[] memory allowedErrors = new bytes4[](1);
allowedErrors[0] = CustomError.selector;
fl.errAllow(errorSelector, allowedErrors, "Error X should be allowed");

// 组合的错误处理
fl.errAllow(errorData, allowedMessages, allowedErrors, "Either should be allowed");

值钳位

// 具有均匀分布的值钳位
uint256 clamped = fl.clamp(inputValue, 0, 100);

// 钳位到大于值
uint256 clampedGt = fl.clampGt(inputValue, 50);

// 钳位到大于或等于
uint256 clampedGte = fl.clampGte(inputValue, 50);

// 钳位到小于值
uint256 clampedLt = fl.clampLt(inputValue, 100);

// 钳位到小于或等于
uint256 clampedLte = fl.clampLte(inputValue, 100);

日志记录

// 简单日志记录
fl.log("Testing scenario");

// 记录值
fl.log("Balance:", balance);
fl.log("User count:", 42);

// 故障日志记录
fl.logFail("This test failed");
fl.logFail("Invalid amount:", amount);

数学实用程序

// 最小值/最大值运算
uint256 maximum = fl.max(150, 300);
int256 minimum = fl.min(-50, 25);

// 绝对值和差值
uint256 absolute = fl.abs(-42);
uint256 difference = fl.diff(100, 75);

随机实用程序

// 混排数组
uint256[] memory array = new uint256[](10);
fl.shuffleArray(array, entropy);

函数调用助手

// 进行函数调用
bytes memory result = fl.doFunctionCall(
    address(target),
    abi.encodeWithSignature("getValue()"),
    msg.sender  // 执行者
);

// 使用自动欺骗进行调用
(bool success, bytes memory data) = fl.doFunctionCall(
    address(target),
    abi.encodeWithSignature("transfer(address,uint256)", recipient, amount),
    sender
);

// 静态调用(视图函数)
(bool success, bytes memory data) = fl.doFunctionStaticCall(
    address(target),
    abi.encodeWithSignature("balanceOf(address)", user)
);

已知限制

  • 有符号整数钳位:限制为 int128 范围,以避免范围计算中的溢出问题
  • Gas 优化:库优先考虑功能而不是 gas 优化
  • 函数选择器冲突:当使用 errAllow 时,如果错误选择器与 Error(string) 冲突,可能会发生意外行为

路线图

  • [ ] 支持更多平台
  • [ ] 添加更多辅助函数
  • [ ] 性能优化

贡献

我们欢迎贡献! 有关详细信息,请参阅我们的贡献指南

许可证

本项目采用 GNU General Public License v3.0 协议授权。 有关详细信息,请参见 LICENSE 文件。

此代码的某些部分修改自 Crytic Properties,该代码已获得 GNU Affero General Public License v3.0 (AGPL-3.0) 协议的许可。

此代码的某些部分修改自 OpenZeppelin Contracts,该代码已获得 MIT 许可证的许可。

免责声明

本软件按原样提供,不提供任何担保。 主分支包含新的和实验性的功能,这些功能可能不稳定。 对于生产用途,我们建议使用经过全面测试的官方标记版本。 虽然我们不对任何 bug 或问题负责,但我们维护一个仅适用于官方版本的 bug 赏金计划。

  • 原文链接: github.com/perimetersec/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
perimetersec
perimetersec
江湖只有他的大名,没有他的介绍。