跳到主要内容
Web3 前端面试题库
返回题库
中级链上数据概念题

事件日志的 topic、data 与 indexed 规则

说明日志的结构、indexed 参数的位置与动态类型限制,以及过滤与解析事件时应当遵循的规则。

题目

一个索引脚本用 indexed string 的原值去过滤日志,结果始终为空;另一个页面手工拼接 topics 解析转账事件,把金额解析成了地址。请说明日志结构、indexed 规则与正确的解析方式。

考察目标

  • 日志的 address、topics 与 data 结构。
  • indexed 参数与动态类型的限制。
  • 过滤与解析的推荐方式。
查看参考答案包含简要回答、深入分析、常见错误与评分标准

30 秒回答

日志由来源地址、topics 与 data 组成;非匿名事件的 topics[0] 是事件签名哈希,其后依次对应 indexed 参数,最多三个 indexed;匿名事件最多四个。未 indexed 的参数编码在 data 中。动态类型的 indexed topic 保存编码值的哈希,不能把原文直接放进 topic;已知原值时仍可按规范计算哈希并过滤,但不能从 topic 反推出原值。实现差异与工程取舍见深入回答。

深入回答

  • 【协议保证】Solidity 的非匿名事件最多有三个 indexed 参数,匿名事件最多四个;只有非匿名事件的第一个 topic 是事件签名哈希(依据:Solidity ABI 规范 §Events)。
  • 【协议保证】indexed 的动态类型(string、bytes、数组)在 topic 中保存特殊原位编码值的 Keccak 哈希。直接用原文作为 topic 无法命中;已知原值时可以按 ABI 规则计算 topic 并过滤,但无法从日志中恢复未知原值(依据:Solidity ABI 规范 §Events、§Encoding of Indexed Event Parameters)。
  • 【协议保证】未 indexed 的参数 ABI 编码后写入 data 字段;解码需要依据事件定义进行(依据:Solidity 文档 §Events)。
  • 【协议保证】eth_getLogs 支持按地址与 topics 过滤,topics 是顺序敏感的有序数组(依据:EIP-1474 §eth_getLogs)。
  • 【工程经验】日志解析走 ABI 解码:用事件定义或解析工具把 topics 与 data 还原为字段,避免手工按位取值(依据:Solidity 文档 §Events)。
  • 【工程经验】设计事件时把需要过滤的字段放在 indexed 位置;动态字段若同时需要检索与展示,可分别保留 indexed 与非 indexed 两份值,或在满足业务语义时使用 bytes32 标识(依据:Solidity ABI 规范 §Events)。
  • 【工程经验】匿名事件没有签名 topic,解析时按对应合约的事件定义处理,不按常规位置套用(依据:Solidity 文档 §Events)。
  • 【工程经验】把事件定义与 ABI 纳入版本管理,合约升级后同步核对解码逻辑(依据:工程经验,无规范依据)。

常见错误

  • 用 indexed string 的原值构造 topic 过滤(【协议保证】动态类型只存哈希,依据:Solidity 文档 §Events)。
  • 手工拼接 topics 解析,字段错位。
  • 忽略匿名事件的 topics 偏移。
  • 把未 indexed 的参数当作 indexed 去过滤。
  • 解码时不核对事件签名哈希,跨合约同名事件混用定义。

面试官追问

  1. 索引服务回填历史日志时漏掉了某个区块窗口,如何发现并补救?
  2. 可升级合约更换实现后事件定义变化,解码与新事件如何处理?
  3. 把日志解析放在前端、索引服务与数据仓库,各自适合什么规模与实时性要求?
  4. 需要按动态值过滤时,链上事件应如何设计?

评分标准

初级回答

  • 能说明 topics[0] 是事件签名哈希,之后对应 indexed 参数。
  • 知道未 indexed 参数放在 data。

中级回答

  • 能说明动态类型 indexed 参数只保留哈希,并能用已知值计算 topic 过滤。
  • 能描述按地址与 topics 过滤时的位置对应关系。

高级回答

  • 能设计事件解码与过滤方案,并说明事件设计对可索引性的影响。
  • 能说明合约升级后事件兼容与对账的处理流程。

参考资料

发现这道题有问题? 反馈此题