测试智能合约非常重要。为什么?智能合约在生产、公共、黑客目标中通常是不可变的,并且通常涉及重大的财务影响。短篇小说?使用智能合约,您不想搞砸。您需要进行大量测试、经常测试和彻底测试。智能合约测试涉及所有常见的问题——单元测试、集成测试、自动化测试——但也强烈推荐模糊测试——一种用一堆随机输入轰炸你的代码以查看会发生什么的方法。
让我们来看看究竟什么是模糊测试作为一种测试方法,以及如何使用 ConsenSys Diligence Fuzzing等工具轻松地将其包含在软件测试工作流程中。我们将使用示例 defi 智能联系人浏览教程,看看它是如何完成的。
模糊测试(或模糊测试)涉及针对智能合约发送数百万个无效、意外和(半)随机数据,以引起意外行为并检测漏洞。这是一种快速、高效、强力的方法来测试您可能没有想到的边缘案例和场景。它补充了您的其他测试流程和审核。
模糊测试在传统的全栈开发中已经存在了一段时间,但是现在出现了一类新的工具,可以将模糊测试应用于 web3 中的智能合约测试。一些模糊测试工具包括开源Echidna和MythX 。
然而,在本文中,我将深入探讨Diligence Fuzzing ,它提供模糊测试服务——一种非常酷且简单的模糊测试方法。
要使用 Diligence Fuzzing,您可以使用Scribble注释您的智能合约。基本上,您在代码中使用 Scribble 注释来告诉模糊器该函数期望的输出类型。
它看起来像这样:
/// #invariant {:msg "balances are in sync"} unchecked_sum(_balances) == _totalSupply;
您可以从提交智能合约代码的 Web UI 调用模糊器。您点击运行,大约 10 分钟后,您会收到一份报告,其中包含发现的问题、问题位置、覆盖率百分比等。
这是检查某些边缘情况的简单而强大的方法。
假设我们有一个新的 DeFi 协议和我们想要推出的相应代币。 DeFi 是前沿金融,写起来很有趣,关键是我们没有任何错误。 DeFi 智能合约通常涉及数百万(或更多)用户资金。因此,我们希望确保尽可能彻底地测试(和审计)我们的智能合约。
重要说明:此代码中有漏洞是故意的!这样我们就可以展示模糊测试如何捕捉这些错误。请不要将此代码用于任何用途。
让我们开始吧。
首先,我们需要我们的 Diligence 帐户。在Diligence注册。您可以免费获得 10 小时的模糊测试时间来试用。
单击右上角的帐户名称,单击“创建新的 API 密钥”,然后为其命名。这个 API 密钥允许我们连接到 FaaS。
克隆以下存储库:
https://github.com/ConsenSys/scribble-exercise-1.git
从命令行导航到存储库文件夹,该文件夹现在将成为您的项目根文件夹。如果您的机器需要,请激活 Python venv。然后,运行以下命令来安装项目依赖项:
$ npm i -g eth-scribble ganache truffle $ pip3 install diligence-fuzzing
编辑.fuzz.yml
文件以使用您的 Diligence 帐户 API 密钥作为 key 的值。
您生成的文件应如下所示:
.fuzz.yml fuzz: # Tell the CLI where to find the compiled contracts and compilation artifacts build_directory: build/contracts ... campaign_name_prefix: "ERC20 campaign" # Point to your ganache node which holds the seed rpc_url: "http://localhost:8545" key: "DILIGENCE API KEY GOES HERE" ...
现在让我们在contracts/vulnerableERC20.sol
查看我们的智能合约。在这里,我们的新 DeFi 协议有一个易受攻击的代币(正如它的名字!)。我们显然需要尽可能多地测试它。因此,让我们使用模糊器希望捕获的 Scribble 添加检查。
在合约定义之上,添加:
/// #invariant "balances are in sync" unchecked_sum(_balances) == _totalSupply;
在传递函数之上,添加:
/// #if_succeeds msg.sender != _to ==> _balances[_to] == old(_balances[_to]) + _value; /// #if_succeeds msg.sender != _to ==> _balances[msg.sender] == old(_balances[msg.sender]) - _value; /// #if_succeeds msg.sender == _to ==> _balances[msg.sender] == old(_balances[_to]); /// #if_succeeds old(_balances[msg.sender]) >= _value;
所以现在让我们看看模糊测试器是否会捕捉到一些东西。请注意我们添加到合同中的注释,以帮助测试人员了解我们期望发生的事情。请注意,在配置中,测试器设置为最多运行 10 分钟,因此它可能无法捕获所有内容。
现在我们准备好测试了!在项目根文件夹中,运行make fuzz
以调用 make 文件,该文件将编译、构建并将所有内容发送到 FaaS。
返回您的仪表板,您应该会看到类似于下面的内容。等待几秒钟,让活动开始。
生成完成后,您应该会看到类似于下图的内容:
我们甚至可以看到代码覆盖率!
几分钟后,我们看到失败!
单击属性,我们会看到任何违规行为。是的,我们有一个错误!单击行位置可查看我们潜在代码漏洞的详细信息。
我们就到此为止,但如果让模糊器继续运行,它可能会找到更多!
模糊测试可能是软件开发和测试过程中的关键步骤。它可以帮助您识别否则可能会被忽视的潜在漏洞。通过使用它,您开始认识和理解常见的陷阱和挑战。利用Diligence Fuzzing等工具,编写更好的智能合约,成为更好的开发人员!