• Solidity智能合约事件(event)


    Solidity智能合约事件(event)

    什么是event

    EVM有一个日志功能,用于将数据“写”到智能合约之外的数据结构中。其中一个重要的数据是Solidity事件。事件允许我们“打印”在区块链上的信息,这种方式比在智能合约中保存到公共存储变量更容易搜索,且更省gas费。

    当被发送事件(调用)时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并记录到区块链中.

    Solidity event,在更通用的以太坊和 EVM 中称为logs,Solidity中的事件(event)是EVM上日志的抽象。日志是指事件保存在区块链上的数据。事件强调操作行为,日志强调存储内容。

    以太坊中的Events和Logs基本上算是同一个概念。Solidity和web3.js中称为Events,以太坊黄皮书中称为Logs。可以理解为:以太坊通过Logs实现Events(事件)功能。智能合约代码通过LOG 将日志写入区块链中。

    事件event有什么作用

    事件Event的作用的可以总结为以下几点:

    • 异步获取执行结果
    • 和前端交互
      我们可以通过监听event来做到及时更新前端显示
    • 存储合约数据,相比storage要便宜很多(storage存储的大概价格为:每32字节需要消耗20000Gas,而日志存储价格大概为每字节8Gas)

    事件有 3 中主要的使用场景

    • 智能合约给用户的返回值
    • 异常触发
    • 更便宜的数据存储

    日志内容位于区块链的什么地方?

    日志内容是交易收据(Transaction Receipts)的一部分,整个日志内容,包括Receipts的其它内容会生成一个ReceiptsRoot存储在区块的头部。而完整数据则是链下存储

    【重要】以太坊交易获取

    以太坊交易信息及event、input、logs、topics等概念机制
    参考URL: https://learnblockchain.cn/article/3274

    当上述事件在合约中调用后,我们通过其交易hash获取交易信息。从以太坊得到一条交易信息的方式有两种:

    • eth_getTransactionByHash: :返回指定交易对应的交易信息
    • eth_getTransactionReceipt :返回指定交易对应的收据信息

    eth_getTransactionByHash 返回的具体信息如下

    {
      "jsonrpc": "2.0",
      "id": 1,
      "result": {
        "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
        "blockNumber": "0xd19505",
        "from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
        "gas": "0x10e3d",
        "gasPrice": "0x274daee580",
        "maxFeePerGas": "0x2d48ddd9f1",
        "maxPriorityFeePerGas": "0x6ccc91d0",
        "hash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
        "input": "0xa9059cbb000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000016512c902",
        "nonce": "0x14",
        "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "transactionIndex": "0x71",
        "value": "0x0",
        "type": "0x2",
        "accessList": [],
        "chainId": "0x1",
        "v": "0x1",
        "r": "0xa1d7455286525df11602aab34e9e8ab21b092e2c7853a0d6beca0dfb2a78b2e8",
        "s": "0x75a485b8c378173a829b27a2e55312311fdb33c68ae65f4c74e5f9cc0a748e0d"
      }
    }
    

    eth_getTransactionReceipt

    {
      "jsonrpc": "2.0",
      "id": 1,
      "result": {
        "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
        "blockNumber": "0xd19505",
        "contractAddress": null,
        "cumulativeGasUsed": "0x6c847e",
        "effectiveGasPrice": "0x274daee580",
        "from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
        "gasUsed": "0xa169",
        "logs": [
          {
            "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
            "topics": [
              "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
              "0x000000000000000000000000b8262c6a2dcabd92a77df1d5bd074afd07fc5829",
              "0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7"
            ],
            "data": "0x000000000000000000000000000000000000000000000000000000016512c902",
            "blockNumber": "0xd19505",
            "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
            "transactionIndex": "0x71",
            "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
            "logIndex": "0xa0",
            "removed": false
          }
        ],
        "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000008000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000080000000000000000000000000000000000000004000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200",
        "status": "0x1",
        "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
        "transactionIndex": "0x71",
        "type": "0x2"
      }
    }
    

    不同于比特币,以太坊作为智能合约平台。每一笔交易作为消息在以太坊虚拟机中执行时,均会获得一个交易回执信息(Receipt)。
    在这里插入图片描述

    getTransaction返回结果中包含input,而getTransactionReceipts返回结果中包含logs。

    如何在 Solidity 中使用事件?

    solidity中,使用关键字event来定义事件,其中参数列表就是需要保存到区块链上的数据。

    1. 在 solidity 中如何定义事件?
    • 事件在函数外部定义
    • 事件名必须和函数名称有所区分
    • 事件名称必须是大写
    • 为了减少混淆事件名称至少得 2 个字母和函数名称不一样

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

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

    在这个事件中,有两种参数:有索引的和无索引的。索引参数也被称为“主题”,是事件中的可搜索参数。
    每个事件最多有3个带indexed的变量,Transfer事件共记录了3个变量from,to和value,分别对应代币的转账地址,接收地址和转账数量。同时from和to前面带着indexed关键字,表示很重要,程序可以轻松的筛选出特定转账地址和接收地址的转账事件。

    一个事件可以分解为:

    • Address:地址,发出事件的合约或账户的地址当前交易被调用的合约地址
    • Topics:主题,事件的索引参数。
    • Data:数据,事件的非索引参数的ABI编码或“哈希”。由于我们知道合约的ABI(因为我们在Etherscan上验证了合约),我们可以在“Dec”或“Decoded”模式下查看它,或者在其原始的“hex”、“Hexidecimal”或 “Encoded”模式下查看。如果我们没有验证过合约,我们就无法看到解码的版本。
    1. 如何来使用事件
      在函数内部通过 emit 关键词,后面跟上事件的名称和事件所需的参数(如果有的话)。
      如果函数会触发事件,则不能将其定义为view或pure。这是因为触发事件会将数据写入区块链(到日志中)。

    2. 匿名事件
      在 solidity 中事件可以是匿名的。默认情况下所有的事件都会有一个主题,来自定义时候的函数名称。使用 anonymous 来记录一个没有主题的事件。匿名事件也会成为 ABI 的一部分。

    event Message(
        address _recipient,
        string _message
    ) anonymous;
    

    如果事件声明为anonymous,在合约 ABI 中,事件的"anonymous"字段将标记为true。
    匿名事件的使用成本更低。但是匿名事件不能通过名称去筛选,只能通过合约地址。

    参考

    web3.js与智能合约交互监听合约事件
    参考URL: https://www.b2bchain.cn/8083.html
    web3j开发以太坊过滤器(filter)和智能合约事件(event)
    参考URL: https://blog.csdn.net/rejames/article/details/81294638
    智能合约Solidity教程-事件和日志(一)
    参考URL: https://blog.csdn.net/weixin_34252090/article/details/88720360
    [强烈推荐,写的很详细]以太坊交易信息及event、input、logs、topics等概念机制
    参考URL: https://learnblockchain.cn/article/3274

  • 相关阅读:
    SQL语言-关系数据库的标准语言
    2.如何使用Python官方文档
    Java常用设计模式
    (2023|ICLR,检索引导,交叉引导,EntityDrawBench)Re-Imagen:检索增强的文本到图像生成器
    Go 语言进阶 - 工程进阶
    React项目使用craco(由create-react-app创建项目)
    做题杂记222
    rk3588编译lunch出错
    react-router-dom6学习11-如何使用路由监听上
    vue+element-ui实现主题切换
  • 原文地址:https://blog.csdn.net/inthat/article/details/110424274