eth/65 与交易哈希公告:以太坊怎么把交易传播带宽砍到平方根 图 1
eth/65 与交易哈希公告:以太坊怎么把交易传播带宽砍到平方根 · 图 1

一笔新签名的交易要变成块里的候选,第一步不是进块,而是让足够多的节点在各自的交易池里看到它。以太坊早期的做法很朴素:直接把完整交易广播给每个对等方——你有多少条连接,同一份数据就要原样发多少遍。EIP-2464 引入的 eth/65 版本改变了这个格局:规范原文给出三个新消息,用公告哈希加按需拉取替代全量推送,并把一个量化结论写得很清楚——交易传播带宽从对等方数量的线性复杂度降到平方根,节点重启时的初始交换也从几十到上百 MB 级别降到内存池条数乘以 32 字节的量级,按常见池深估算约 128 KB。

三个消息各干什么

NewPooledTransactionHashes(消息号 0x08)公告一批交易哈希,每个哈希 32 字节,不带任何交易内容。GetPooledTransactions(0x09)让收到公告又想要全貌的对等方按哈希批量点菜。PooledTransactions(0x0a)是被问方对这批哈希的应答。于是传播的经济学变了:多数节点只花 32 字节知道某笔交易存在,真正要执行或打包的节点才花真实带宽去取内容。这和比特币用 inv 公告、getdata 拉取的分工同构——两套网络殊途同归,因为省带宽的数学是同一个:向 N 个邻居推全文是 N 倍成本,推摘要再加按需拉取可以把重复降到约平方根量级。

eth/65 与交易哈希公告:以太坊怎么把交易传播带宽砍到平方根 图 2
eth/65 与交易哈希公告:以太坊怎么把交易传播带宽砍到平方根 · 图 2

哈希公告顺带解决的两件事

第一件是冗余确认。对等方手里往往已经有池里大部分交易——重启、重连、或者从另一条连接先收到了。旧协议里这些情况要靠 NewBlockHashes 式的补充交换或者干脆重推;哈希公告把去重前置:比对一下已知集合,缺什么拉什么。第二件是隐私面的差别:旧式全量广播里,收到全文本身就暴露了传输对象的内容;哈希公告阶段内容尚未流出,取全文的请求只发给它真正缺的那几笔。当然公告哈希本身仍是元数据,把公告时间与拉取时序做关联分析并非不可能,这是任何公告拉取体系共有的分析面,eth/65 没有假装消灭它,只是压缩了默认暴露量。

版本协商:协议升级的老大难

改线上传输格式最难的不是设计,是让新旧节点共存。eth/65 的答案挂在 devp2p 的能力协商上:节点在握手时声明自己支持的协议与版本号(eth/63、eth/65 这样的命名),双方取交集最高的版本通信。这解释了一个运维现象:升级客户端后,同网段节点的版本号会自然趋同,而落后版本节点自动降级交流——功能交集之外没有暗礁。后续的 eth/66 给消息换了统一的分帧信封,eth/68 与 eth/69 继续在公告层做加法与减法,交易公告这条线上的每次版本演进都在回答同一个问题:怎么少发字节。

一条算术直觉

拿 EIP 自己给的锚点算:池深几千笔、每笔均值几 KB,旧式重启交换几十到上百 MB 很常见;换成哈希公告加拉取,初始交换约等于池规模乘以 32 字节的索引开销,剩下的内容成本只付给真正缺失的部分。带宽对普通家用节点从来不是稀缺到用不起的资源,但把它降一个数量级意味着更多低配设备愿意长期做全节点——去中心化的账本最终是靠这些不起眼的工程数字撑起来的。

快速问答

问:只发哈希,攻击者能伪造公告让我去拉垃圾吗?答:公告方可以对拉取返回任意内容,但接收方会校验返回交易哈希与请求哈希是否一致,对不上直接丢弃并计负分。

问:这和 MEV 私有交易什么关系?答:私有流交易从不进公共公告池,自然也不会被公告——公告机制只约束公开传播的部分。

问:跑节点时怎么确认在用哪个版本?答:客户端日志一般会打印协商结果,参数层面也有对等协议相关选项,以当期客户端文档为准。

风险提示:本文为网络协议科普;协议版本号与带宽数字随版本与网络状态演化,分析节点流量时以实际抓包与当期规范为准。