Solidity学习::(5)异常处理

异常处理

     以太坊使用状态回退机制处理异常。如果发生异常,当前消息调用和子消息调用产生的所有状态变化都将被撤销并且返回调用者一个报错信号。Solidity语言提供了两个函数:assert和require 来检查条件,并且在条件不满足时抛出一个异常。assert函数通常用于检查变量和内部错误,require函数用于确保程序执行的必要条件是成立的。一个正常运行的程序不应该遇到assert和require失败,否则代码中一定存在需要修复的问题。

     revert 函数和throw 关键字会标志发生了错误,并且回退当前的消息调用产生的状态改变。

     当前调用收到子消息调用产生的异常时,会自动抛出,所以异常会一层层“上浮”,直到最上层的调用,代码会立即终止执行并回退状态的改变。但是<address>.send  call 和 delegatecall是例外,在执行过程中抛出异常时会返回false,而不是自动抛出异常。

举例:

contract AssertExample {
    function sendHalf(address addr) payable returns (uint balance){
        require(msg.value %2==0); //只允许偶数
        uint balanceBeforeTransfer=this.balance;
        addr.transfer(msg.value/2);
        //使用assert 确保transfer 转账成功,否则抛出异常
        assert(this.balance==balanceBeforeTransfer-msg.value/2);
        return this.balance;
    }
}

assert异常抛出场景:

  • 访问数组越界,下标为负数或者超出长度。
  • 访问固定长度的bytesN越界,下标为负数或者超出长度。
  • 对0做除法或者对0取模,比如5/0,5%0
  • 进行移位操作时给了一个负数值
  • 将一个过大的数或者负数转换到枚举类型。
  • 调用assert函数并且参数值为false

 require异常抛出场景:

  • 调用throw
  • 调用require并且参数值为false
  • 发起一个消息调用,但是这个调用没有正常完成,比如Gas耗尽,被调用函数不存在或者函数本身抛出异常
  • 使用new创建一个合约,但是与上面提到的原因一样,构造函数没有正常完成
  • 调用外部函数时指向一个不包含代码的地址
  • 合约通过一个没有payable修饰词的函数接收以太币,包括构造函数和fallback函数
  • 合约通过一个公开的访问函数接收以太币
  • <address>.transfer()失败

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/82729405