美文网首页践行区块链
智能合约的两种异常处理模式

智能合约的两种异常处理模式

作者: Ashton | 来源:发表于2020-07-14 22:44 被阅读0次

0x01 即时回滚式

这是最常用的模式,如有不满足条件的错误发生,即时回滚当前交易。比如下面的 ERC20 转账代码:

 function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

当调用该函数时传入的参数为地址 0,require 语句的执行会使当前交易回滚。
这种方式用起来最为直接简单,但也有一些硬伤:

  1. 不容易对错误情况进行回溯,当交易回滚时很难看出具体是什么原因导致的回滚。
  2. 错误信息不是 ABI 的一部分,很难将友好的错误信息展示出来。
  3. 在合约间调用时,主调合约只能跟着被调合约回滚而回滚,不能根据不同的错误类型进行修复。尽管最新的 Solidity 已经部分支持 try ... catch 语法,但并不能捕获很多的错误类型。

0x02 即时记录式

与使用 require 语句在异常发生时引发交易回滚不同,这种模式通过合约提供的事件机制记录所发生的异常事件。比如下面的代码定义了专门的异常处理函数 fail。当该函数被调用时,会通过 Failure 事件详细记录相关错误信息,并返回错误代号。

event Failure(uint error, uint info, uint detail);
function fail(Error err, FailureInfo info) internal returns (uint) {
    emit Failure(uint(err), uint(info), 0);
    return uint(err);
}

下面使用该异常处理函数的代码:

function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
        /* Fail if borrow not allowed */
        uint allowed = ptroller.borrowAllowed(address(this), borrower, borrowAmount);
...

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < borrowAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);
        }
...

这种处理方式通过事件将错误信息记录下来,更容易对错误情况进行监控和跟踪。在发生合约间调用时也方便主调合约根据返回的不同错误码进行灵活处理。
但这种方式也存在硬伤:

  1. gas 消耗可能更大
  2. 容易误将失败的交易当作成功
  3. 代码里会散列大量的异常处理代码,影响代码可读性

0x03 哪种方式更好呢?

自己去权衡吧,这里最能提现代码人的价值。记得有个段子是这么讲的:
A:现在代码网上到处都有,为啥程序员的工资还这么高呢?
B:如果一个程序员的工资是一万美金,那么在网上搜罗代码价值 1 美金,决定用哪个代码价值 9999 美金。

相关文章

网友评论

    本文标题:智能合约的两种异常处理模式

    本文链接:https://www.haomeiwen.com/subject/slyqhktx.html