译者 | 李睿
对一些人来说,编写安全智能合约很难。本文将介绍Web3中的一些安全工具,以提高智能合约的安全性。
毫无疑问,编写安全智能合约比较困难,即使是高级开发人员编写的智能合约也可能被黑客攻击。由于这些智能合约通常具有很高的经济价值,因此黑客攻击和破解它们的动机也很高。再加上Web3的不变性,安全性变得更加重要。安全性因此成为了智能合约开发人员的首要任务。
本文将介绍智能合约开发的每个阶段可用的一些安全工具,并对采用这些工具提供一些建议。
1、为开发做好准备
当开始开发智能合约时,安全性应该是开发人员首要考虑的问题,而一些工具可以在准备编写代码时提供帮助,这其中包括文档、检测和编写可重用代码。
首先,文档是任何开发项目的关键,智能合约开发也不例外。以太坊自然规范格式(NatSpec)是一种记录智能合约的好方法。
NatSpec是一种特殊形式的注释,用于为合约、接口、库、函数和事件提供丰富的文档。例如以下Tree Contract的稳定性代码片段:
复制
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 < 0.9.0;
/// @title A simulator for trees
/// @author Larry A. Gardner
/// @notice You can use this contract for only the most basic simulation
contract Tree {
/// @notice Calculate tree age in years, rounded up, for live trees
/// @dev The Alexandr N. Tetearing algorithm could increase precision
/// @param rings The number of rings from dendrochronological sample
/// @return Age in years, rounded up for partial years
function age(uint256 rings) external virtual pure returns (uint256) {
展开全文
return rings + 1;
NatSpec 对Solidity Contract的注释
通过使用NatSpec注释,可以很容易地向其他开发人员、审核人员或只想与合约交互的人解释代码。简单地说,它是干净的、可读的、容易理解的。
其次,重用经过实战测试的代码是降低智能合约中漏洞风险的另一种经过验证的方法。目前有许多广泛使用的开源智能合约库,例如OpenZeppelin,其中包含用于实现访问控制、暂停功能、升级等的预先编写的逻辑,以及用于优化使用的Solmate合约。
最后,检测是在智能合约代码中发现潜在问题的具有价值的工具。它可以在代码中发现风格错误、违反编程约定和不安全的结构。有很多很好的检测工具可用,例如ETHLint(以前的Solium)。检测可以帮助发现潜在的问题(例如重入漏洞这样的安全问题),甚至在它们成为代价高昂的错误之前。
通过在智能合约开发过程中考虑文档、检测和可重用代码,可以提高合约的安全性。从长远来看,花时间正确地设置这些将会在安全性和效率方面得到回报。
2、开发
现在了解可以在编码时提供帮助的两类工具——单元测试和基于属性的测试。
单元测试显然是创建安全可靠代码的重要组成部分。通过测试代码的单个单元,可以确保合约按照预期的方式运行,并希望在生产中出现问题之前发现任何潜在问题。
有几种不同的工具可用于为智能合约编写单元测试。Foundry、Truffle和Brownie都是支持各种编程语言的流行框架。
Foundry(用Rust编写)是一个用于编写智能合约的框架,其中包括测试框架Forge。伪造单元测试可以直接在Solidity中编写,包括许多欺骗代码,这些代码可以提供断言、改变EVM状态的能力、模拟数据等等。Foundry还带有内置的Fuzzing(将在后面的文章中详细讨论)。
复制
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.10;
import "ds-test/test.sol";
import "../StakeContract.sol";
import "./mocks/MockERC20.sol";
contract StakeContractTest is DSTest {
StakeContract public stakeContract;
MockERC20 public mockToken;
function setUp() public {
stakeContract = new StakeContract();
mockToken = new MockERC20();
/// @notice Test token staking with different amount
function test_staking_tokens() public {
uint256 amount = 10e18;
mockToken.approve(address(stakeContract), amount);
bool stakePassed = stakeContract.stake(amount, address(mockToken));
assertTrue(stakePassed);
在Foundry中的Solidity单元测试示例
Truffle也是构建智能合约的框架。Truffle中的单元测试可以用Solidity或JavaScript编写。开发人员通常使用基于JavaScript的测试与合同进行外部交互,并使用Solidity测试评估合同在实际区块链上的行为。Truffle使用Mocha进行异步测试,使用Chai进行断言。
Brownie是一个基于python的框架,用于开发和测试智能合约。Brownie与pytest集成用于单元测试,并提供了一个堆栈跟踪分析工具来测量代码覆盖率。
在编写单元测试时,通过测试尽可能多的代码不同部分来实现高测试覆盖率,以确保所有功能都能按预期工作。Foundry不需要额外的插件来测量测试覆盖率。对于其他框架,可能至少可以添加一个插件来衡量这一点。
虽然单元测试是确保智能合约正确性的可靠方法,但基于属性的测试允许对智能合约进行更深入的验证。这是一个相对较新的概念,与传统的单元测试相比,它提供了一系列优势。基于属性的测试侧重于测试智能合约的属性,而不是单个组件。
在指南中,“属性描述了智能合约的预期行为,并声明了关于其执行的逻辑断言。属性必须始终为真。基于属性的测试工具将智能合约的代码和用户定义的属性集合作为输入,并检查执行是否在任何时间点违反了它们。”
基于属性的测试基于模糊概念,这是一种通过引入随机输入来测试系统的技术。这意味着基于属性的测试可以在更广泛的层面上检查智能合约,因为它不依赖于开发人员提供的特定输入。正因为如此,它正成为一种越来越流行的测试智能合约的方法。
以之前的合约为例,使用基于属性的方法来测试一个简单的staking函数。为此,将使用Scribble,这是一种规范语言和运行时工具,它使这一切变得更加容易。
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
error TransferFailed();
contract StakeContract {
mapping(address => uint256) public s_balances;
/// #if_succeeds {:msg "Stake created successfully"} $result == true;
function stake(uint256 amount, address token) external returns (bool){
s_balances[msg.sender] += amount;
bool success = IERC20(token).transferFrom(msg.sender, address(this), amount);
if (!success) revert TransferFailed();
return success;
使用Scribble Notation进行的样品可靠性测试
不同的工具可以使用Scribble规范进行属性测试
为了评估staking函数,必须检查它是否在成功执行的情况下返回true。这可以通过向stake函数代码添加注释来完成,正如上面所表明的那样,不需要单独的测试文件。然后可以运行Scribble CLI工具将Scribble注释转换为断言。接下来,这些断言必须通过模糊器(如Diligence Fuzzing或Mythril)运行,以确定是否存在任何违反属性的情况。
来自Diligence Fuzzing活动示例的报告
还有一些其他工具可用于基于属性的测试,例如Foundry。Scribble(以上使用的)、Diligence Fuzzing和Mythril是最值得推荐的几种工具。Scribble和Diligence Fuzzing是由ConsenSys Diligence构建的免费开源工具。Mythril是一个旨在检测以太坊智能合约中潜在漏洞的工具。
Scribble这种工具令人喜欢,因为把可这些测试放在一起就像添加函数注释一样简单。
3、后期开发
最后一组工具是后期开发。具体来说,就是监控。
因为大多数区块链上的智能合约代码是不可变的,一旦代码被推送到主网,就几乎无法控制它。监控可以帮助开发人员了解代码中的任何问题或更改,以便可以快速解决它们。这不仅可以帮助开发人员提高合约的安全性,还可以帮助优化和改进其功能。
OpenZepplin的Defender Sentinels和Tenderly的实时警报工具非常适合监控区块链上合约和钱包。
Tenderly Alerts提供了一组自定义触发器以供选择,允许快速设置各种活动的警报,例如部署新合同时、发送或接收事务时以及特定地址时。
Defender Sentinel通过定义的一系列自定义参数提供实时安全监控和警报,例如,如果取款超过特定阈值,如果有人执行关键操作(例如调用转账所有权),或者如果黑名单地址试图与合约交互的时候。
4、结论
智能合约安全工具非常重要。希望本文能够帮助人们了解适合工具,以便编写更安全的智能合约。
原文链接:
特别声明
本文仅代表作者观点,不代表本站立场,本站仅提供信息存储服务。