理解事件 — EVM的内置日志系统

本文介绍了以太坊虚拟机(EVM)中事件(也称为日志)的工作原理,包括事件的定义、存储位置(交易回执日志而非合约存储)、以及如何通过eth_getLogs直接查询事件。文章详细解释了topics(索引字段,用于过滤)和data(非索引字段,存储原始字节)的结构,并通过ERC-20代币转账事件的示例,展示了如何手动解码日志以及如何在区块浏览器上理解事件信息。

理解事件 —— EVM 内置的日志系统

每次合约交互都会留下痕迹,但并非所有痕迹都存储在存储中。事件,也称为日志,是以太坊记录交易内部发生的事情的原生方式,而无需修改状态。

在本文中,我们将分解事件在底层的工作原理:topicsdata 的真正含义,索引参数如何变得可搜索,以及如何直接从 RPC 查询它们。你将学习手动解码日志,并准确理解你在区块浏览器上看到的内容。

理解事件

当大多数开发者想知道 EVM 上发生了什么时,他们会从 事件(也称为日志)开始。

事件是什么:

  • 智能合约可以在执行期间 发出事件
  • 事件不存储在合约存储中,它们存在于 交易回执日志 中。

示例:ERC-20 代币转账事件:

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

每个事件都有:

  • 一个 主题列表(索引字段,用于过滤):

它们是事件的 搜索键。它们允许你/节点提供商过滤日志,而无需读取所有内容。每个事件始终具有:

Topic[0] → 事件签名哈希,例如:

keccack256("Transfer(address,address,uint256)")

Topic[1..3] → 最多三个标记为 indexed 的参数,它们始终存储为固定的 32 字节值。这意味着你可以直接在 RPC 层查询“来自 Alice 的所有转账”或“给定交易对的所有交换”。

  • 一个 数据块(未索引字段,存储为原始字节):

所有未标记为 indexed 的内容都会被打包到 data 字段中。

数据是 不可搜索的,你需要获取日志并自己解码它们。对于你可以包含的非索引字段的数量没有硬性限制,除了 gas 限制。

curl -s -X POST https://polygon-amoy-bor-rpc.publicnode.com \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc":"2.0",
    "method":"eth_getLogs",
    "params":[{\
      "fromBlock":"0x182e86c",\
      "toBlock":"0x182e86c",\
      "address":"0x0fd9e8d3af1aaee056eb9e802c3a762a667b1904",\
      "topics":[\
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\
        "0x0000000000000000000000007f8b1ca29f95274e06367b60fc4a539e4910fd0c"\
      ]\
    }],
    "id":1
  }' | jq

这里我们搜索区块 0x182e86c 上的 Transfer 事件,其中 0x7f8b1ca29f95274e06367b60fc4a539e4910fd0c 发送了 LINK 代币。

响应将如下所示:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [\
    {\
      "address": "0x0fd9e8d3af1aaee056eb9e802c3a762a667b1904",\
      "topics": [\
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",\
        "0x0000000000000000000000007f8b1ca29f95274e06367b60fc4a539e4910fd0c",\
        "0x0000000000000000000000002a51ae0ad42dc7d2eb89462a7d41e79502bcf697"\
      ],\
      "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",\
      "blockNumber": "0x182e86c",\
      "transactionHash": "0x330e48c4c3adcc17b0819b7bf7344bb5010beee59551713231e977508ee1b236",\
      "transactionIndex": "0x2",\
      "blockHash": "0xb48487df956cb9fd6cc9750e2438b03c99d146910a2a1159850712c38ee85681",\
      "logIndex": "0x3",\
      "removed": false\
    }\
  ]
}

我们在这里看到:

address → 发出事件的合约

  • 这里:0x0fd9…b1904 = Polygon Amoy 上的 LINK 代币。

blockNumber → 包含 tx 的区块(十六进制)。

  • 0x182e86c = 十进制的 25356396

transactionHash → 触发此日志的 tx 的哈希。

  • 允许你查找完整的交易。

logIndex → 此日志在区块中的位置(事件已排序)。

topics → 索引参数:

  • topics[0] = 事件签名:

0xddf252ad...keccak256("Transfer(address,address,uint256)")

  • topics[1] = from 地址,填充为 32 字节:

0x7f8b1c…fd0c = 发送者。

  • topics[2] = to 地址,填充为 32 字节:

0x2a51ae…f697 = 接收者。

data → 非索引参数(在本例中,仅为 value

  • 0x...0de0b6b3a7640000 = 十进制的 1000000000000000000 = 1.0 LINK

扫描器上的事件将如下所示:

按 Enter 键或单击以全尺寸查看图像

https://amoy.polygonscan.com/tx/0x330e48c4c3adcc17b0819b7bf7344bb5010beee59551713231e977508ee1b236#eventlog

总结

事件是合约告诉外部世界发生了某些事情的方式。它们存在于交易回执中,而不是存储中,并且可以直接通过 eth_getLogs 查询。一旦你了解了主题和数据的结构,你就可以过滤特定操作,如代币转账、交换或存款,而无需接触合约代码。

  • 原文链接: medium.com/@andrey_obruc...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Andrey Obruchkov
Andrey Obruchkov
江湖只有他的大名,没有他的介绍。