跳转到主要内容

一个从Echidna和Medusa复现器自动生成单元测试的工具。

项目描述

Slither Static Analysis Framework Logo

智能合约模糊器的自动化工具库

fuzz-utils 是一组Python工具,旨在改善使用智能合约模糊时的开发者体验。工具包括

  • EchidnaMedusa 失败属性自动生成单元测试,使用生成的复现文件。
  • 自动生成Echidna/Medusa兼容的模糊 harness。

fuzz-utils 使用 Slither 确定类型,并使用 jinja2 通过字符串模板生成测试文件。

免责声明:请注意,fuzz-utils 正在 开发中。目前,并不支持所有 Solidity 类型,并且一些类型(如 bytes*string)可能无法正确地从语料库调用序列解码。我们正在调查一种更好的语料库格式,这将简化单元测试的创建。

特性

fuzz-utils 提供以下支持

  • ✔️ 从单入口点模糊 harness 的 fuzzer 语料库生成 Foundry 单元测试。
  • ✔️ 生成模糊 harness、Actor 合同和模板化的 attack 合同,以简化模糊设置。
  • ✔️ 支持 Medusa 和 Echidna 语料库
  • ✔️ 测试生成支持 Solidity 类型:booluint*int*addressstructenum、一维固定大小数组、动态数组和多维固定大小数组。

多维动态数组、函数指针和其他更复杂类型正在开发中,但目前不支持。

安装和先决条件

要安装 fuzz-utils

pip install fuzz-utils

这些命令将安装运行 fuzz-utils 所需的所有 Python 库和工具。但是,它不会安装 Echidna 或 Medusa,因此您需要从其官方发布版本(EchidnaMedusa)自行下载和安装。

工具

可用的工具命令是

  • init - 初始化配置文件
  • generate - 从语料库生成单元测试
  • template - 生成模糊测试工具

生成单元测试

generate 命令用于从 Echidna 或 Medusa 语料库调用序列生成 Foundry 单元测试。

命令行选项

  • compilation_path:Solidity 文件或 Foundry 目录的路径。默认为 .
  • -cd/--corpus-dir path_to_corpus_dir:相对于工作目录的语料库目录路径。默认为 corpus
  • -c/--contract contract_name:目标合约的名称。如果编译路径只包含一个合约,则目标将自动推导。
  • -td/--test-directory path_to_test_directory:相对于工作目录的测试目录路径。默认为 test
  • -i/--inheritance-path relative_path_to_contract:从测试目录到合约的相对路径(用于覆盖继承)。如果未提供此配置选项,继承路径将自动推导。
  • -f/--fuzzer fuzzer_name:模糊测试器的名称,目前支持:echidnamedusa。默认为 medusa
  • --named-inputs:在调用时包含函数输入名称。默认为 false
  • --config:fuzz-utils 配置 JSON 文件的路径。默认为空。
  • --all-sequences:在生成单元测试时包含所有语料库序列。默认为 false

示例

为了为 BasicTypes.sol 合约生成测试文件,基于该合约的 Echidna 语料库复制器(corpus-basic),我们需要进入包含 Foundry 项目的 tests/test_data 目录并运行以下命令

fuzz-utils generate ./src/BasicTypes.sol --corpus-dir echidna-corpora/corpus-basic --contract "BasicTypes" --fuzzer echidna

运行此命令应在 Foundry 项目的 test 目录中生成 BasicTypes_Echidna_Test.sol 文件。

生成模糊测试工具

template 命令用于生成模糊测试工具。工具可以包含多个用作用户操作代理的 Actor 合约,以及可以从一组预制的合约中选择以执行某些常见攻击场景的 attack 合约。

命令行选项

  • compilation_path:Solidity 文件或 Foundry 目录的路径
  • -n/--name name: str:模糊测试工具的名称。默认为 DefaultHarness
  • -c/--contracts target_contracts: list:目标合约的名称。默认为空。
  • -o/--output-dir output_directory: str:输出目录名称。默认为 fuzzing
  • --config:fuzz-utils 配置 JSON 文件的路径
  • --mode:生成工具时使用的策略。有效选项:simpleprankactor

生成模式 工具支持三种工具生成策略

  • simple - 模糊测试工具将包含目标合约的所有状态更改函数。所有函数调用都直接执行,工具合约作为 msg.sender
  • prank - 与 simple 模式类似,区别在于使用 hevm.prank() 从不同的用户执行函数调用。用户可以在配置文件中定义为 "actors": ["0xb4b3", "0xb0b", ...]
  • actor - 将生成 Actor 合约,并且所有 harness 函数调用将通过这些合约代理。可以认为 Actor 合约是目标合约的用户,而这些 actor 包含的函数可以通过修饰符、外部调用或 payable 进行过滤。这允许对用户能力进行细粒度控制。

示例

为了为 TestERC20.sol 合约生成模糊测试 harness,我们需要 cd 进入包含 Foundry 项目的 tests/test_data/ 目录并运行以下命令:

fuzz-utils template ./src/TestERC20.sol --name "ERC20Harness" --contracts TestERC20

运行此命令应在 tests/test_data/test/fuzzing 中生成目录结构,该目录包含模糊测试 harness ERC20Harness 和 Actor 合约 DefaultActor

我们可以看到,工具已经生成了包含我们 ERC20 令牌所有函数的 DefaultActor 合约,并且我们的模糊测试 harness ERC20Harness 能够通过随机选择一个已部署的 actor 来调用这些函数,模拟不同的用户。

这减少了设置模糊测试 harness 的样板代码所需的时间,让您能集中精力定义不变量并测试系统。

工具

初始化配置文件

可以使用 init 命令在项目根目录中初始化默认配置文件。

配置文件:使用配置文件可以比仅使用命令行选项提供更细粒度的控制。以下列出了有效的配置选项:

{
    "generate": {
        "targetContract": "BasicTypes",              // The Echidna/Medusa fuzzing harness 
        "compilationPath": "./src/BasicTypes",       // Path to the file or Foundry directory
        "corpusDir": "echidna-corpora/corpus-basic", // Path to the corpus directory
        "fuzzer": "echidna",                         // `echidna` | `medusa`
        "testsDir": "./test/",                       // Path to the directory where the tests will be generated
        "inheritancePath": "../src/",                // Relative path from the testing directory to the contracts
        "namedInputs": false,                        // True | False, whether to include function input names when making calls
        "allSequences": false,                       // True | False, whether to generate tests for the entire corpus (including non-failing sequences)
    },
    "template": {
        "name": "DefaultHarness",                    // The name of the fuzzing harness that will be generated
        "targets": ["BasicTypes"],                   // The contracts to be included in the fuzzing harness
        "outputDir": "./test/fuzzing",               // The output directory where the files and directories will be saved
        "compilationPath": ".",                      // The path to the Solidity file (if single target) or Foundry directory
        "actors": [                                  // At least one actor is required. If the array is empty, the DefaultActor which wraps all of the functions from the target contracts will be generated
            {
                "name": "Default",                   // The name of the Actor contract, saved as `Actor{name}`
                "targets": ["BasicTypes"],           // The list of contracts that the Actor can interact with
                "number": 3,                         // The number of instances of this Actor that will be used in the harness
                "filters": {                         // Used to filter functions so that only functions that fulfill certain criteria are included
                    "strict": false,                 // If `true`, only functions that fulfill *all* the criteria will be included. If `false`, functions that fulfill *any* criteria will be included
                    "onlyModifiers": [],             // List of modifiers to include
                    "onlyPayable": false,            // If `true`, only `payable` functions will be included. If `false`, both payable and non-payable functions will be included
                    "onlyExternalCalls": [],         // Only include functions that make a certain external call. E.g. [`transferFrom`]
                },
            }
        ],
        "attacks": [                                 // A list of premade attack contracts to include. 
            {
                "name": "Deposit",                   // The name of the attack contract. 
                "targets": ["BasicTypes"],           // The list of contracts that the attack contract can interact with
                "number": 1,                         // The number of instances of this attack contract that will be used in the harness
                "filters": {                         // Used to filter functions so that only functions that fulfill certain criteria are included
                    "strict": false,                 // If `true`, only functions that fulfill *all* the criteria will be included. If `false`, functions that fulfill *any* criteria will be included
                    "onlyModifiers": [],             // List of modifiers to include
                    "onlyPayable": false,            // If `true`, only `payable` functions will be included. If `false`, both payable and non-payable functions will be included
                    "onlyExternalCalls": [],         // Only include functions that make a certain external call. E.g. [`transferFrom`]
                },
            }
        ],
    },
}

贡献

有关如何为此项目做出贡献的信息,请参阅 CONTRIBUTING 指南。

许可

fuzz-utilsAGPLv3 许可下授权和分发。

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

fuzz-utils-0.2.0.tar.gz (45.4 kB 查看哈希)

上传时间

构建分布

fuzz_utils-0.2.0-py3-none-any.whl (52.0 kB 查看哈希)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面