去中心化应用监听链上事件,靠的是节点的日志接口:订阅某个合约地址的转账事件,节点一看到匹配日志就推给你。这套机制在连接稳定时很顺滑,但以太坊的链会重组,而节点不保证永远记得你。EIP-234在2017年3月由Micah Zoltu提出,给过滤器选项加了一个字段:blockHash,让查询从“按块号范围扫”升级为“按某个区块哈希精确点名”。提案状态是Final,落进的是所有主流客户端的RPC接口。
断线加重组的连环事故
提案的动机部分写了两个具体剧本。第一个走WebSocket:客户端连上节点、建好日志订阅、收到一批新日志,然后连接断了。就在断线这段时间,一次重组发生,那几个区块被换掉,里面的日志从主链上消失。等客户端重连、重建过滤器,它完全不知道自己错过了日志移除的通知——节点早在连接断开那一刻就忘了这个订阅者的存在。第二个剧本走HTTP轮询:两次轮询之间节点重启,过滤器状态丢失,同时重组又发生,客户端拿到的增量账目怎么都对不平。两个剧本的共同点:日志的新增有通知机制,日志的移除却依赖连接不曾断过,而重组专挑连接的盲区下手。
一个字段怎么补上这个洞
EIP-234的规格很短:过滤器选项加一个可选的blockHash参数,值是一个区块哈希;节点要么报错说查不到这个区块,要么返回限定在该区块内、且满足原过滤条件的日志,内部实现可以类比fromBlock和toBlock的工作方式。看起来只是缩小了查询范围,实际给了客户端一个锚点:我可以先记录见过的每个区块的哈希,再按哈希逐块把日志拉回来核对。被重组掉的区块按哈希去查,节点会明确告诉你它不在当前链上,客户端由此知道要回滚本地状态。换句话说,提案把“日志消失”从一个需要靠运气察觉的事故,变成了一次可以主动发起、结果确定的查询。
和块号范围的本质差别
fromBlock与toBlock按高度画区间,可高度是个会漂移的概念:重组之后,同一个高度对应的是另一个区块、另一批日志。按高度范围查询的客户端想核对历史,只能假设某个高度的内容从未变过,这个假设在重组面前不成立。blockHash则指向内容本身——哈希对上了,才是同一个区块。这也是为什么提案标题特意把它写成fromBlock与toBlock的替代选项,而不是补充。想稳妥地维持一份本地事件账本,正确姿势是高度和哈希双轨记录:高度用来推进度,哈希用来定身份。
重组窗口里的一份账本
用一个对账场景串起全部零件。钱包服务在处理一批 Deposit 事件,本地账本记下每条日志所在的区块号与区块哈希。凌晨节点维护重启,过滤器全丢;同一小时主网发生了一次两深度的重组,钱包先前按哈希A入账的区块被哈希B顶替。恢复流程照着EIP-234的世界观走:按本地记录重新以哈希A查询日志,节点回答“此块不在”;于是撤下那些依赖A的记录,改查高度上现存的哈希B,把里面的日志重新入账。整个过程没有订阅、没有推送,全靠按哈希点名的查询把断线和重组两段事故拼回真相。
快速问答
问:这条提案改变节点共识行为吗? 答:不改变。它是接口层的增量,给RPC加可选参数,不碰区块规则,提案类型是接口类标准。 问:有了订阅推送还需要它吗? 答:推送解决“有新事发生”,按哈希查询解决“我记得的事还算不算数”,后者是前者的对账兜底,两者互补。 问:查不到的区块哈希节点一定报错吗? 答:规范给了两种合法回应——区块不存在就报错,存在就返回限定日志;实现细节由客户端自己安排。
风险提示:本文讨论节点接口机制,不构成任何投资建议,也不涉及任何资产的买卖时机判断。接口字段以各客户端当前文档与EIP原文为准。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。