错误处理及异常

assert(bool condition)

如果不满足条件,则会导致Panic 错误,则撤销状态更改 - 用于检查内部错误。

require(bool condition)

如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误。

require(bool condition, string memory message)

如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误,可以同时提供一个错误消息。

revert()

终止运行并撤销状态更改。

revert(string memory reason)

终止运行并撤销状态更改,可以同时提供一个解释性的字符串。

异常可以包含错误数据,以 error的形式传回给调用者。

内置的错误 Error(string) 和 Panic(uint256) 被作为特殊函数使用, 

 Error 用于 “常规” 错误条件,而 Panic 用于在(无bug)代码中不应该出现的错误

函数 assert 和 require 可用于检查条件并在条件不满足时抛出异常,然后回滚

assert 函数会创建一个 Panic(uint256) 类型的错误。 同样的错误在以下列出的特定情形会被编译器创建。

assert 函数应该只用于测试内部错误,检查不变量,正常的函数代码永远不会产生Panic, 甚至是基于一个无效的外部输入时。 如果发生了,那就说明出现了一个需要你修复的 bug。如果使用得当,语言分析工具可以识别出那些会导致 Panic 的 assert 条件和函数调用

require 函数可以创建无错误提示的错误,也可以创建一个 Error(string) 类型的错误。 require 函数应该用于确认条件有效性,例如输入变量,或合约状态变量是否满足条件,或验证外部合约调用返回的值

contract Sharer {
    function sendHalf(address addr) public payable returns (uint balance) {
        require(msg.value % 2 == 0, "Even value required.");
        uint balanceBeforeTransfer = this.balance;
        addr.transfer(msg.value / 2);

        // 由于转账函数在失败时抛出异常并且不会调用到以下代码,因此我们应该没有办法检查仍然有一半的钱。
        assert(this.balance == balanceBeforeTransfer - msg.value / 2);
        return address(this).balance;
    }
}

require 是一个像其他函数一样可被执行的函数。 意味着,所有的参数在函数被执行之前就都会被执行。 尤其,在 require(condition, f()) 里,函数 f 会被执行,即便 condition 为 True

revert函数

revert(); revert(“description”);

错误数据将被传回给调用者,以便在那里捕获到错误数据。 使用 revert() 会触发一个没有任何错误数据的回退,而 revert("description") 会产生一个 Error(string) 错误

try和catch

try/catch 语句允许我们在 Solidity 合约中捕获和处理异常,并在异常发生时执行指定的逻辑。这对于处理外部调用、控制合约流程以及错误处理非常有用。

try {

    // 潜在会触发异常的代码

} catch Error(string memory error) {

    // 处理特定错误类型

} catch (bytes memory error) {

    // 处理未知错误类型

}

在 try 块中,我们放置可能会发生异常的代码。如果这些代码成功执行,那么 catch 语句将被跳过。

如果在 try 块中发生异常,它将被抛出并被最接近的 catch 块捕获。catch 块可以指定不同类型的异常,并执行相应的错误处理逻辑。

在上面的代码示例中,catch 块捕获 Error 类型的异常,并接收一个 string 类型的错误消息。这样我们可以根据不同类型的错误消息执行不同的处理。

我们也可以使用 catch 来捕获未知类型的异常,使用 bytes 类型接收错误信息。这样可以处理一些无法预料的异常。

  • catch Error(string memory reason) { ... }: 如果错误是由 revert("reasonString") 或 require(false, "reasonString") (或导致这种异常的内部错误)引起的,则执行这个catch子句。
  • catch Panic(uint errorCode) { ... }: 如果错误是由 panic 引起的(如: assert 失败,除以0,无效的数组访问,算术溢出等),将执行这个catch子句。
  • catch (bytes memory lowLevelData) { ... }: 如果错误签名不符合任何其他子句,如果在解码错误信息时出现了错误,或者如果异常没有一起提供错误数据。在这种情况下,子句声明的变量提供了对低级错误数据的访问。
  • catch { ... }: 如果你对错误数据不感兴趣,你可以直接使用 catch { ... } (甚至是作为唯一的catch子句) 而不是前面几个catch子句

需要注意的是,异常只能在 try 块中被捕获,无法从内部函数传播到外部函数。

contract ExceptionExample {

    function divide(uint a, uint b) public pure returns (uint) {

        uint result;

       

        try this.calculateDivide(a, b) returns (uint quotient) {

            result = quotient;

        } catch Error(string memory error) {

            // 处理除以零的错误

            revert(error);

        } catch (bytes memory error) {

            // 处理其他错误

            revert(string(error));

        }

       

        return result;

    }

   

    function calculateDivide(uint a, uint b) internal pure returns (uint) {

        if (b == 0) {

            revert("除数不能为零");

        }

       

        return a / b;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值