美文网首页
7. Solidity:报错控制、事件

7. Solidity:报错控制、事件

作者: 泡泡龙吐泡泡 | 来源:发表于2023-09-26 09:54 被阅读0次

7.1 报错控制

Solidity中抛出异常的方法有:require、revert、assert。本章分别介绍三种方法的使用。

7.1.1 require

require命令是solidity 0.8版本之前抛出异常的常用方法,目前很多主流合约仍然还在使用它。require使用简单方便,唯一的缺点就是gas随着描述异常的字符串长度增加,比error命令(下一节介绍)要高。使用方法:require(检查条件,"异常的描述"),当检查条件不成立的时候,就会抛出异常。

示例代码:

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

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwner(address _oneOwner) external {
        require(msg.sender == owner, "No permissions!");
        owner = _oneOwner;
    }
}

7.1.2 revert

7.1.2.1 默认revert

revert使用方法相似,只是判断写在revert语句之外,且判断方向和require相反。revert中只包含报错信息。
示例代码:

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

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwnerRevert(address _oneOwner) external {
        if (msg.sender != owner) {
            revert("No permissions!");
        }
        owner = _oneOwner;
    }
}
7.1.2.2 revert自定义error

error是solidity 0.8.4版本新增加的内容,允许开发者自定义错误。error不仅能够携带操作失败的原因信息,还能够携带参数,方便开发者进行调试,提高合约调用的操作体验。error需要和revert配合使用。
示例代码:

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

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 自定义错误
    error NoPermissions(address caller, address owner);
    // 变更合约owner
    function transferOwnerRevertError(address _owner) external {
        if (msg.sender != owner) {
            revert NoPermissions(msg.sender, owner);
        }
        owner = _owner;
    }

}

报错信息:

NoPermissions
Parameters:
{
 "caller": {
  "value": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2"
 },
 "owner": {
  "value": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"
 }
}

7.1.3 assert

assert命令一般用于程序员写程序debug,因为它不能解释抛出异常的原因(比require少个字符串)。它的用法很简单:assert(检查条件),当检查条件不成立的时候,就会抛出异常。
示例代码:

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

contract errorDemo {
    // 定义owner变量
    address public owner;

    // 在合约构造方法中设置owner
    constructor() {
        owner = msg.sender;
    }

    // 变更合约owner
    function transferOwnerAssert(address _oneOwner) external {
        assert(msg.sender == owner);
        owner = _oneOwner;
    }

TODO:try catch

7.2 事件

7.2.1 智能合约中的事件

Solidity中的事件(event)是EVM上日志的抽象,它具有两个特点:

  • 响应:应用程序(ethers.js)可以通过RPC接口订阅和监听这些事件,并在前端做响应。
  • 经济:事件是EVM上比较经济的存储数据的方式,每个大概消耗2,000 gas;相比之下,链上存储一个新变量至少需要20,000 gas。
7.2.1.1 事件声明

事件的声明由event关键字开头,接着是事件名称,括号里面写好事件需要记录的变量类型和变量名。以ERC20代币合约的Transfer事件为例:

    event Transfer(address indexed from, address indexed to, uint value);

该事件包含from、to、value三个参数,其中,from和to参数使用indexed修饰。indexed关键字有以下特点:

  • indexed关键字修饰的参数会保存在以太坊虚拟机日志的topics中,可以进行检索。
  • 一个事件可以有多个参数,但是使用indexed关键字修饰的参数最多只能有3个。
7.2..1.2 释放事件

上述自定义事件的释放示例函数:

    function emitFunc(address _from, address _to, uint _value) external {
        emit Transfer(_from, _to, _value);
    }

remix中的log记录:

[
    {
        "from": "0x9D7f74d0C41E726EC95884E0e97Fa6129e3b5E99",
        "topic": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "event": "Transfer",
        "args": {
            "0": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
            "1": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
            "2": "123",
            "from": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
            "to": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
            "value": "123"
        }
    }
]

区块链浏览器中的log记录

transfer_log.png
  • Address:合约地址
  • Name:事件名称
  • Topics:事件描述数组,最大长度为4(一个事件hash,最多三个indexd参数)
    • 0:事件hash值,计算方式如下:
      function getTopics0() external pure returns (bytes32) {
          return keccak256("Transfer(address,address,uint256)"); // uint默认为uint256参与计算
          // 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
      }
    
    • 1:indexed修饰的参数(from)
    • 2:indexed修饰的参数(to)
  • Data:其他非indexed参数(value)

相关文章

网友评论

      本文标题:7. Solidity:报错控制、事件

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