如何正确测试 Solidity 中的异常?

How to properly test exceptions in Solidity?

我是 Solidity 的新手,我正在尝试在 ERC-20 token standard 之后创建我的第一个智能合约。按照标准要求,我有一个 transfer 函数,如下所示:

function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balanceOf[msg.sender] >= _value);

    // transfer the amount
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;

    // trigger a Transfer event
    emit Transfer(msg.sender, _to, _value);

    return true;
}

可以看出,我首先进行健全性检查,确保发件人有足够的金额来执行与 require(balanceOf[msg.sender] >= _value) 的交易。我现在想测试代码的那个特定部分,看看如果数量太大,它是否真的会抛出预期的错误。我正在使用 truffle 和有用的 truffle-assertions package:

const truffleAssert = require("truffle-assertions");

it("should revert transfer if the amount is larger than the sender's balance", () => {
  return MyToken.deployed().then((instance) =>
    truffleAssert.fails(
      instance.transfer.call(accounts[1], 10000000),
      truffleAssert.ErrorType.REVERT
    )
  );
});

这似乎按预期工作。但是,如果我要从我的 transfer 函数中删除 require 部分,我预计测试会失败,但测试会以某种方式通过。来自 Java 的背景,这让我怀疑我是否真的在正确地测试代码。在 Solidity 中测试此类场景的正确且可靠的方法是什么?

Solidity 在版本 0.8.0 中引入了整数 overflow/underflow 的自动异常。

Arithmetic operations revert on underflow and overflow. You can use unchecked { ... } to use the previous wrapping behaviour.

来源:docs

如果您使用的是 Solidity ^0.8,它仍然会抛出 balanceOf[msg.sender] -= _value;(假设 value 大于 balanceOf[msg.sender]),否则 balanceOf[msg.sender]值会下溢。


您会在许多来源中使用 require 语句看到这种精确检查,因为它们要么是在 0.8 版之前创建的,要么它们的作者可能没有意识到这一新功能。或者他们可能想使用 require(false, 'error message') 的第二个参数传递自定义错误消息(自动异常不提供任何消息)。但是从0.8开始就不需要了。