拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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-706DEVp2p snappy compression是一项状态为 Final 的以太坊网络层标准提案它通过将 DEVp2p 基础网络协议版本从4提升到5在握手完成后的所有消息负载上启用 Snappy 压缩 为主体完整讲解该提案的动机、协议变更规范、防 DOS 设计、备选方案取舍与跨语言测试向量并结合本仓库中其他 EIP如 EIPS/eip-2972.md、EIPS/eip-7706.md佐证其在生态中的实际影响。读完本文你将理解 Snappy 在 DEVp2p 协议栈中的确切注入位置、版本协商机制以及如何在 Go 与 Python 中验证压缩数据与明文的一致性。背景为什么 DEVp2p 需要压缩DEVp2p 是以太坊节点间通信的底层网络协议其上层承载着eth、les、bzz等子协议。在 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层。这样所有子协议eth、les、bzz都能无缝受益避免了各协议各自为政地去优化数据流量而带来的复杂度。这一思想在后续 EIP 中仍被反复引用——例如 EIPS/eip-7706.md 在论证零字节密集区块会被压缩到 1.87MB 以下时正是基于 Snappy 压缩的现实效果。规范版本协商与压缩注入点版本号提升将 DEVp2p 通告的版本号从4提升到5握手时若远端仅通告支持版本4则完全沿用现有协议不做任何压缩若远端通告 DEVp2p 版本 5则在发送路径上、加密 DEVp2p 消息之前注入一个 Snappy 压缩步骤。发送路径一条消息由{Code, Size, Payload}组成发送侧流程为用 Snappy 压缩原始Payload并写回同一字段将消息Size更新为压缩后负载的长度像往常一样加密并发送消息对压缩过程完全无感知。接收路径接收 DEVp2p v5 消息时在解密 DEVp2p 消息之后插入 Snappy 解压步骤照常解密消息负载对压缩无感知用 Snappy 解压Payload并写回同一字段将消息Size更新为解压后负载的长度。两条重要注意事项握手消息永不压缩因为握手消息正是用来协商公共协议版本的必须先以明文形式交换。不使用 Snappy framingDEVp2p 本身就是面向消息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.mdRLPx 握手兼容性、EIPS/eip-2124.md网络标识符等以形成对以太坊节点间通信协议的完整认知。总结EIP-706 用一个极其克制的改动——提升 DEVp2p 版本号到5在加密前后各插入一步 Snappy 压缩/解压并沿用 16MB 解压阈值防止 DOS——换来了初始同步流量 60%–80% 的削减且完全向后兼容。它证明了传输层统一优化、应用层无感受益这一设计哲学的有效性是理解以太坊网络性能演进时不可跳过的一份关键规范。参考原始提案EIPS/eip-706.mdSnappy 官方网站与格式规范压缩流以 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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门