您当前的位置: 首页 >  ui

StevenX5

暂无认证

  • 7浏览

    0关注

    22博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

智能合约Solidity语言错误处理函数(require、revert、assert)使用详解

StevenX5 发布时间:2022-06-29 19:09:25 ,浏览量:7

Solidity语言中定义了以下三种错误处理方式:

  • require:用于在执行前验证输入和条件;
  • revert:用于直接触发回退,可自定义异常处理;
  • assert:用于检查不应该为假的代码,失败的断言可能意味着代码层面存在错误。

异常处理将撤消当前调用对状态所做的所有更改,并且还可以向调用者抛出错误。

错误处理函数
  • Require()

    require(condition, description)
    

    require 首先检查 condition,如果条件为真则继续执行,否则提供一个消息字符串 description 用于标记错误(可选)。

  • revert()

    if (!condition) revert(); 
    if (!condition) revert(description);
    if (!condition) revert CustomError(arg1, arg2, ...);
    

    revert 可以直接触发回退,也可以抛出一个消息字符串用于标记错误,也可以自定义错误处理。

  • assert()

    assert(condition);
    

    assert 用于检查 condition 是否为真,检查失败时抛出异常。

函数共同点

以下三个语句的功能完全相同:

if (msg.sender != owner) { revert(); }
assert(msg.sender == owner);
require(msg.sender == owner);

这三个语句都用于检查当前调用者是否为合约的所有者,如果检查结果不为真则抛出异常。

函数差异化 Gas开销

assert() 将消耗所有剩余的Gas,并恢复所有的操作。

require()revert() 将退还所有剩余的Gas,同时可以返回一个值(自定义的报错信息)。

适用场景 require() 的适用场景
  • 验证用户输入,如:

    require(input > 10);
    
  • 验证外部合约响应(返回值),如:

    require(external.send(amount));
    
  • 执行合约前验证状态条件,如:

    require(block.number > SOME_BLOCK_NUMBER);	// 或者
    require(balance[msg.sender] >= amount);
    

合约中应该尽量使用 require 来处理错误,且放在函数最开始的地方使用。

revert() 的适用场景

revert 函数与 require 函数类似,但是适用更复杂处理逻辑的场景。如果代码中需要复杂的 if/else 逻辑流,那么应该考虑适用 revert 函数而不是 require 函数。

assert() 的适用场景
  • 检查整数溢出(overflow/underflow),如:

    c = a + b;
    assert(c > b);
    
  • 检查不变量(invariants),如:

    assert(this.balance >= totalSupply);
    
  • 验证改变后的状态,如:

    assert(state);
    

合约中应该尽量少用 assert 调用,如果要适用 assert 应该在函数结尾处使用。

assertrequire 函数均被用来检查条件并在条件不满足时抛出异常,它们的主要区别是 require 应该被用于函数中检查条件,assert 用于预防不应该发生的情况,即不应该使条件错误。

合约例子

例子1:下面是一个合约例子,用来演示错误处理函数的用法。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

// 错误处理及异常
contract Errors {
   // Require测试
    function testRequire(uint i) public pure {
        require(i > 10, "Input must be greater than 10");
    }

    // Revert测试
    function testRevert(uint i) public pure {
        if (i = oldBalance, "Overflow");

        balance = newBalance;
        assert(balance >= oldBalance);
    }

    // 从合约提取以太币
    function withdraw(uint _amount) public payable {
        uint oldBalance = balance;

        // 检查溢出
        require(balance >= _amount, "Underflow");

        if (balance < _amount) {
            revert("Underflow");
        }

        balance -= _amount;
        assert(balance             
关注
打赏
1651313693
查看更多评论
0.0768s