欢迎订阅专栏:3分钟Solidity--智能合约--Web3区块链技术必学
Echidna
要获取此内容的最新版本,请访问 Cyfrin.io 上的 Echidna(代码示例)
Echidna是一个快速的智能合约(solidity)模糊测试框架,它是用Haskell语言编写的程序,实现基于以太坊智能合约属性的模糊测试。 它使用基于合约ABI的复杂的grammar-based模糊测试来验证用户定义断言或者Solidity断言。 Echidna在设计时考虑了模块化,可以很容易地被扩展成包含新的变种或者在特定情况下,测试特定合约。
使用 Echidna进行模糊测试的示例。
- 将 Solidity 合约保存为
TestEchidna.sol - 在存储合约的文件夹中执行以下命令。
docker run -it --rm -v $PWD:/code trailofbits/eth-security-toolbox
在 Docker 中,您的代码将存储在根目录下的 /code文件夹中。
- 查看以下注释并执行
echidna命令。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/*
echidna TestEchidna.sol --contract TestCounter
*/
contract Counter {
uint256 public count;
function inc() external {
count += 1;
}
function dec() external {
count -= 1;
}
}
contract TestCounter is Counter {
function echidna_test_true() public view returns (bool) {
return true;
}
function echidna_test_false() public view returns (bool) {
return false;
}
function echidna_test_count() public view returns (bool) {
// 这里我们在测试Counter.count应该始终<=5。
// 测试将失败。Echidna足够聪明,会调用Counter.inc()
// 超过5次。
return count <= 5;
}
}
/*
echidna TestEchidna.sol --contract TestAssert --test-mode assertion
*/
contract TestAssert {
function test_assert(uint256 _i) external {
assert(_i < 10);
}
// 更复杂的例子
function abs(uint256 x, uint256 y) private pure returns (uint256) {
if (x >= y) {
return x - y;
}
return y - x;
}
function test_abs(uint256 x, uint256 y) external {
uint256 z = abs(x, y);
if (x >= y) {
assert(z <= x);
} else {
assert(z <= y);
}
}
}
测试时间与发送者
Echidna可以对时间戳进行模糊测试。时间戳范围可在配置中设置,默认为7天。
合约调用者同样可在配置中设置。默认账户为:
0x100000x200000x30000
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/*
docker run -it --rm -v $PWD:/code trailofbits/eth-security-toolbox
echidna EchidnaTestTimeAndCaller.sol --contract EchidnaTestTimeAndCaller
*/
contract EchidnaTestTimeAndCaller {
bool private pass = true;
uint256 private createdAt = block.timestamp;
/*
如果Echidna能够调用setFail(),测试将失败
否则测试将通过
*/
function echidna_test_pass() public view returns (bool) {
return pass;
}
function setFail() external {
/*
如果延迟小于等于最大区块延迟,Echidna可以调用此函数。
否则,Echidna将无法调用此函数。
最大区块延迟可以通过在配置文件中指定来延长。
*/
uint256 delay = 7 days;
require(block.timestamp >= createdAt + delay);
pass = false;
}
// 默认sender
// 更改地址以查看测试失败
address[3] private senders =
[address(0x10000), address(0x20000), address(0x30000)];
address private sender = msg.sender;
// 将 _sender 作为输入,并要求 msg.sender == _sender
// 以 _sender 为例进行反证
function setSender(address _sender) external {
require(_sender == msg.sender);
sender = msg.sender;
}
// 检查默认发件人。发件人应为3个默认账户之一。
function echidna_test_sender() public view returns (bool) {
for (uint256 i; i < 3; i++) {
if (sender == senders[i]) {
return true;
}
}
return false;
}
}