本文介绍了以太坊虚拟机(EVM)中事件(也称为日志)的工作原理,包括事件的定义、存储位置(交易回执日志而非合约存储)、以及如何通过eth_getLogs直接查询事件。文章详细解释了topics(索引字段,用于过滤)和data(非索引字段,存储原始字节)的结构,并通过ERC-20代币转账事件的示例,展示了如何手动解码日志以及如何在区块浏览器上理解事件信息。
每次合约交互都会留下痕迹,但并非所有痕迹都存储在存储中。事件,也称为日志,是以太坊记录交易内部发生的事情的原生方式,而无需修改状态。
在本文中,我们将分解事件在底层的工作原理:
topics和data的真正含义,索引参数如何变得可搜索,以及如何直接从 RPC 查询它们。你将学习手动解码日志,并准确理解你在区块浏览器上看到的内容。
当大多数开发者想知道 EVM 上发生了什么时,他们会从 事件(也称为日志)开始。
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 键或单击以全尺寸查看图像

总结
事件是合约告诉外部世界发生了某些事情的方式。它们存在于交易回执中,而不是存储中,并且可以直接通过 eth_getLogs 查询。一旦你了解了主题和数据的结构,你就可以过滤特定操作,如代币转账、交换或存款,而无需接触合约代码。
- 原文链接: medium.com/@andrey_obruc...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!