news 2026/9/15 21:29:29

EIP-706 详解:DEVp2p 消息层 Snappy 压缩如何让以太坊节点流量降低 60%–80%

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
EIP-706 详解:DEVp2p 消息层 Snappy 压缩如何让以太坊节点流量降低 60%–80%

EIP-706 详解:DEVp2p 消息层 Snappy 压缩如何让以太坊节点流量降低 60%–80%

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

导读

EIP-706(DEVp2p snappy compression)是一项状态为 Final 的以太坊网络层标准提案,它通过将 DEVp2p 基础网络协议版本从4提升到5,在握手完成后的所有消息负载上启用 Snappy 压缩 为主体,完整讲解该提案的动机、协议变更规范、防 DOS 设计、备选方案取舍与跨语言测试向量,并结合本仓库中其他 EIP(如 EIPS/eip-2972.md、EIPS/eip-7706.md)佐证其在生态中的实际影响。读完本文,你将理解 Snappy 在 DEVp2p 协议栈中的确切注入位置、版本协商机制,以及如何在 Go 与 Python 中验证压缩数据与明文的一致性。

背景:为什么 DEVp2p 需要压缩

DEVp2p 是以太坊节点间通信的底层网络协议,其上层承载着ethlesbzz等子协议。在 EIP-706 提出之前,DEVp2p 不对任何消息做压缩,整条网络因此浪费了大量带宽,导致初始同步(initial sync)与日常运行都更慢、更卡顿。

提案给出了具体的量化依据(EIP-706 写作时的实测数据,块高分别为 4,248,000 与 852,000):

网络同步方式压缩前压缩后
以太坊主网fast sync1.01 GB 上行 / 33.59 GB 下载1.01 GB 上行 / 13.46 GB 下载
Rinkeby 测试网fast sync55.89 MB 上行 / 2.51 GB 下载46.21 MB 上行 / 463.65 MB 下载

其中大部分数据(区块、交易)都具有极强的可压缩性。经过大量基准测试,启用压缩后初始同步的数据流量减少了60%–80%

关键设计决策是:把压缩放在 DEVp2p 层而非某个子协议(如 eth)层。这样所有子协议(ethlesbzz)都能无缝受益,避免了各协议各自为政地去优化数据流量而带来的复杂度。这一思想在后续 EIP 中仍被反复引用——例如 EIPS/eip-7706.md 在论证"零字节密集区块会被压缩到 1.87MB 以下"时,正是基于 Snappy 压缩的现实效果。

规范:版本协商与压缩注入点

版本号提升

将 DEVp2p 通告的版本号从4提升到5

  • 握手时若远端仅通告支持版本4,则完全沿用现有协议,不做任何压缩;
  • 若远端通告 DEVp2p 版本>= 5,则在发送路径上、加密 DEVp2p 消息之前注入一个 Snappy 压缩步骤。

发送路径

一条消息由{Code, Size, Payload}组成,发送侧流程为:

  1. 用 Snappy 压缩原始Payload,并写回同一字段;
  2. 将消息Size更新为压缩后负载的长度;
  3. 像往常一样加密并发送消息,对压缩过程完全无感知。

接收路径

接收 DEVp2p v5 消息时,在解密 DEVp2p 消息之后插入 Snappy 解压步骤:

  1. 照常解密消息负载(对压缩无感知);
  2. 用 Snappy 解压Payload并写回同一字段;
  3. 将消息Size更新为解压后负载的长度。

两条重要注意事项

  • 握手消息永不压缩:因为握手消息正是用来协商公共协议版本的,必须先以明文形式交换。
  • 不使用 Snappy framing:DEVp2p 本身就是面向消息(message oriented)的协议,因此不需要额外的流式分帧。

此外,提案还特别注明:Snappy 也支持未压缩的二进制字面量(最大 4GB),为将来对已压缩或已加密数据(压缩无收益)进行细粒度优化留下了空间——Snappy 通常会自动检测这类情况。

防 DOS 设计:解压前先读长度

目前 DEVp2p 消息长度被限制在 24 位,即单条消息最大 16MB。引入压缩后,必须小心不要盲目解压消息,因为解压结果可能远大于 16MB。

Snappy 的一个关键特性是:无需在内存中展开,即可从输入流计算出解压后的大小——压缩流以 little-endian varint 开头,存储未压缩长度,最大可达2^32 - 1。因此可以借此在任何消息解压后超过某个阈值时直接将其丢弃。

提案建议:将解压后消息的阈值沿用现有上限16MB。这样保留了当前 DEVp2p 协议同样的安全保障,应用层协议不会遇到意外的大消息。

这一 24 位长度上限在以太坊生态中已成为事实约束,例如 EIPS/eip-2972.md 在讨论日志与日志数据上限时明确指出:"EIP-706 将 devp2p 消息限制在 24 位长度,这给了我们任何单条交易一个务实的上限"。

被否决的备选方案

EIP-706 详细记录了讨论过但被否决的方案,理解这些取舍有助于把握协议设计边界:

方案一:扩展某个上层协议xyz以支持压缩消息(而非在 DEVp2p 层做)

  • 优点:可以更好地优化"何时压缩、何时不压缩"。
  • 缺点:把传输层编码混入应用层逻辑;
  • 缺点:使各消息规范被压缩细节搅得更加复杂;
  • 缺点:需要在每一个协议(eth、les、shh、bzz)上做跨客户端协调,工作量大且重复。

方案二:引入协议的无缝变体,如xyz扩展出xyz-compressed

  • 优点:无需跨客户端协调即可"hack"实现。
  • 缺点:网络中充斥客户端专属的协议通告;
  • 缺点:为了跨互操作,最终仍需要通过 EIP 来规范。

方案三:不显式限制解压后消息大小,只限制压缩后大小

  • 优点:允许更大的消息穿过 DEVp2p。
  • 缺点:上层协议需要自行检查并丢弃大消息;
  • 缺点:需要惰性解压(lazy decompression)才能在不引发 DOS 的前提下做大小限制。

最终,在 DEVp2p 层统一压缩 + 16MB 解压阈值成为最优解,兼顾了带宽收益、实现复杂度与安全性。

向后兼容性

本提案完全向后兼容。升级到 DEVp2p 协议版本5的客户端,必须仍然支持对仅通告版本4的连接跳过压缩步骤。这也是版本协商机制的意义所在——新旧节点可以在同一网络中平滑共存。

参考实现

提案给出的参考实现在 go-ethereum 的 PR 中(ethereum/go-ethereum#15106),即 Geth 客户端对 DEVp2p v5 + Snappy 压缩的具体落地。实践中,这成为所有主流以太坊客户端(Geth、Nethermind、Besu、Erigon 等)的默认网络行为。

测试向量:跨语言压缩一致性验证

由于 Snappy 对同一输入存在多种合法编码,且内部有多种在吞吐量与输出大小之间权衡的压缩算法,不同实现产出的压缩形态可能略有差异,但彼此应完全互操作。

EIP-706 以 Rinkeby 测试网区块 #272621 的十六进制编码 RLP 数据(约 3MB)作为测试输入:

  • 用 Go 的 Snappy 库编码得到约 70KB 的压缩结果(block.go.snappy);
  • 用 Python 的 Snappy 库编码同样得到约 70KB 的压缩结果(block.py.snappy)。

两者的压缩输出可以互相解压,验证了跨实现兼容性。下面给出两种语言的验证代码(读者可自行准备明文文件与对应的压缩文件进行验证)。

Go 验证

安装依赖:

$ go get github.com/golang/snappy

验证程序(读取明文 hex 文件与压缩 hex 文件,解压后比对):

package main import ( "bytes" "encoding/hex" "fmt" "io/ioutil" "log" "os" "github.com/golang/snappy" ) func main() { // Read and decode the decompressed file plainhex, err := ioutil.ReadFile(os.Args[1]) if err != nil { log.Fatalf("Failed to read decompressed file %s: %v", os.Args[1], err) } plain, err := hex.DecodeString(string(plainhex)) if err != nil { log.Fatalf("Failed to decode decompressed file: %v", err) } // Read and decode the compressed file comphex, err := ioutil.ReadFile(os.Args[2]) if err != nil { log.Fatalf("Failed to read compressed file %s: %v", os.Args[2], err) } comp, err := hex.DecodeString(string(comphex)) if err != nil { log.Fatalf("Failed to decode compressed file: %v", err) } // Make sure they match decomp, err := snappy.Decode(nil, comp) if err != nil { log.Fatalf("Failed to decompress compressed file: %v", err) } if !bytes.Equal(plain, decomp) { fmt.Println("Booo, decompressed file does not match provided plain text!") return } fmt.Println("Yay, decompressed data matched provided plain text!") }

运行:

$ go run main.go block.rlp block.go.snappy Yay, decompressed data matched provided plain text! $ go run main.go block.rlp block.py.snappy Yay, decompressed data matched provided plain text!

Python 验证

安装依赖:

$ pip install python-snappy

验证脚本:

import snappy import sys # Read and decode the decompressed file with open(sys.argv[1], 'rb') as file: plainhex = file.read() plain = plainhex.decode("hex") # Read and decode the compressed file with open(sys.argv[2], 'rb') as file: comphex = file.read() comp = comphex.decode("hex") # Make sure they match decomp = snappy.uncompress(comp) if plain != decomp: print "Booo, decompressed file does not match provided plain text!" else: print "Yay, decompressed data matched provided plain text!"

运行:

$ python main.py block.rlp block.go.snappy Yay, decompressed data matched provided plain text! $ python main.py block.rlp block.py.snappy Yay, decompressed data matched provided plain text!

两个方向的交叉验证(Go 压缩 ↔ Python 解压、Python 压缩 ↔ Go 解压)均通过,证明不同语言实现产出的压缩流在以太坊网络中可互操作。

生态影响与延伸阅读

EIP-706 的影响远超其文本本身:

  • 它让"区块数据默认可压缩"成为以太坊网络的事实前提,后续 EIP 在设计容量与成本模型时都会把 Snappy 压缩计算在内(见 EIPS/eip-7706.md 对 calldata 的理论上限分析);
  • 它的 16MB 消息上限成为单条交易/日志数据的务实约束(见 EIPS/eip-2972.md 第 102 行的引用);
  • 同一 DEVp2p 版本协商机制也被后续网络层 EIP 沿用,例如 EIPS/eip-2481.md 引入eth/66请求标识符时,同样依赖 devp2p 支持多版本线协议并行运行的能力。

如果想了解 DEVp2p 协议更宏观的演进脉络,可在本仓库中继续阅读网络(Networking)类目的相关 EIP,如 EIPS/eip-8.md(RLPx 握手兼容性)、EIPS/eip-2124.md(网络标识符)等,以形成对以太坊节点间通信协议的完整认知。

总结

EIP-706 用一个极其克制的改动——提升 DEVp2p 版本号到5,在加密前后各插入一步 Snappy 压缩/解压,并沿用 16MB 解压阈值防止 DOS——换来了初始同步流量 60%–80% 的削减,且完全向后兼容。它证明了"传输层统一优化、应用层无感受益"这一设计哲学的有效性,是理解以太坊网络性能演进时不可跳过的一份关键规范。

参考

  • 原始提案:EIPS/eip-706.md
  • Snappy 官方网站与格式规范(压缩流以 little-endian varint 存储未压缩长度,最大2^32 - 1
  • 生态引用:EIPS/eip-2972.md、EIPS/eip-7706.md

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 21:29:22

Matlab FMCW雷达仿真:差频提取与距离-多普勒处理

简介:面向调频连续波(FMCW)雷达仿真需求的Matlab源码包,适合雷达信号处理初学者、电子工程相关专业学生以及需快速验证FMCW原理的研发人员。这套源码包聚焦调频连续波雷达的建模与信号处理,特别适合课程设计、期末项目…

作者头像 李华
网站建设 2026/9/15 21:26:24

UNIHIKER M10嵌入式音频 recorder 设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华