节点跑在同步阶段时,会不断向对端发出取数据的请求:给我一段区块头、给我这批哈希对应的区块体、给我这些交易的完整内容。对端把这些东西发回来,节点拼进自己的链。看起来只是问答,但在以太坊 P2P 协议的早期版本里,这一问一答藏着一个脆弱的约定:所有请求和响应消息都不带编号,双方默认响应必须按照请求送达的顺序原样返回。
没有编号时,串行是强制的
订单式的问答对响应端意味着一种枷锁。假设节点 A 连着节点 B,先后发出三个请求:取区块头、取一批区块体、取一批交易。节点 B 想要并行处理——每个请求丢给不同的工作线程去磁盘上取数据,谁先取完谁先回话——它做不到。因为协议规定响应必须保持请求顺序,B 要么把三个请求排队串行执行,要么全部完成后按原序重排再发出。前者浪费多核与并行磁盘的能力,后者要额外缓存与排序逻辑。更麻烦的是,一旦响应端想乱序完成,请求方根本没有办法把响应和请求对上号——消息本身不含任何身份线索,顺序成了唯一的线索。

EIP-2481 的最小改动
EIP-2481 在 2020 年 1 月起草,2021 年 4 月随柏林升级生效,核心改动只有一处:在 GetBlockHeaders、BlockHeaders、GetBlockBodies、BlockBodies、GetPooledTransactions、PooledTransactions 等成对的请求响应消息开头,插入一个 request id 字段,用 RLP 的变长整数编码。请求方填一个自己保证在途不重复的编号,响应方收到后把同样的编号原样回填。规范对编号的要求很松:六十四位整数,不必连续,甚至可以随机。提案的问答部分解释了为什么不强制连续递增——连接断开重连之后计数会乱成一团,不如放弃顺序语义,只要求在途不重复。从此响应端可以开线程池并行查库、乱序回话,请求方按编号认领即可。同一份改动覆盖了节点数据与收据的取用消息,一次把同步层的问答全部编号化。问答里还回应了一个顺带的担忧:并行效率的提升会不会引诱客户端向对端洪泛大量并发请求?答案是朴素的一层——对端觉得被打扰时随时可以限流或断连,这与改动前没有区别;编号本身不制造新的资源压力。另一个”为何不干脆改用轻客户端协议那套现成机制”的问题也有现实回答:在公网上提供轻服务的对端太少,同步这条路必须自己修。
和 eth/65 各管一半
容易混的是它的兄弟提案。eth/65(EIP-2464,2020 年定稿)改的是交易传播:节点不再向每个邻居推送完整交易,改为只公告交易哈希加体积,谁没见到过谁再来取,解决的是带宽问题。eth/66 管的则是另一头——请求与响应的配对正确性与并行效率。两者在 devp2p 的版本谱系里是接力关系,规范的版本表写得清楚:eth/64(EIP-2364,2019 年 11 月)解决分叉困惑,eth/65(2020 年 1 月)换来交易公告,eth/66(2021 年 4 月)加上请求编号,eth/67(2022 年 3 月)把状态同步整段交给专门的 snap 协议,eth/68(2022 年 10 月)给交易公告补上类型与体积字段,eth/69(2025 年 4 月)让节点在状态消息里报告自己可供哪一段区块并简化收据编码。request id 从 66 版起再没有被拿掉,后面的每一版都在这套编号问答上做加法。
用户视角与边界
普通用户极少直接观察这层。它的存在痕迹出现在两处:一是节点日志或接口里显示的对等端协议版本,能看到 eth/66、eth/67 这类字样,那是版本协商的结果;二是排障时,同步卡顿的原因可能是对端不支持更高的 eth 版本而被降级配对。要注意分层:JSON-RPC 里批量请求的响应乱序是客户端接口层的事,eth 协议的 request id 是节点与节点同步层的事,两者机制相似但互不相干,排障时不要互相归因。本文只讨论协议机制,不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。