RLP 与 SSZ:以太坊序列化为什么分了两个世界 图 1
RLP 与 SSZ:以太坊序列化为什么分了两个世界 · 图 1

同一个以太坊,区块交易用一种编码,信标链上的验证者数据用另一种。新手常以为这是“历史包袱加新造轮子”,实际上 RLP 与 SSZ 的分工是一次明确的取舍:前者管把嵌套列表压成字节流,后者在此之上再给每个字段配一把可独立出示的钥匙——哈希树根。看懂这套取舍,Patricia Trie、blob 承诺和轻客户端证明就都串起来了。

RLP:极简但只会打包

RLP(递归长度前缀)是执行层的老住户:区块头、交易、树节点都靠它编码。规则小得惊人——字节串和嵌套列表两种原料,长度前缀加内容的贪心拼接,没有类型、没有字段名、没有任何元信息。优点是快而简;软肋是所有语义都活在编码之外:拿到一串 RLP 字节,不看模式(schema)你就不知道里面有没有负数、列表多长。更关键的是,RLP 流上想对“某个字段的值”出证明,只能整段给出再哈希,没有捷径。

SSZ:为证明而设计

信标链选择 SSZ(SimpleSerialize)正是冲着这个短板。它同样紧凑,但把数据结构当类型系统看:定长与变长字段、列表与容器,每个类型自带模式。编码之外,SSZ 定义了默克尔化——把对象的 32 字节分块铺成叶子的完全二叉树,不足补齐,得到 hash_tree_root;列表长度、联合体选择器还会被混进根里防止篡改。有了这棵树,节点可以不交整个对象,只交某字段加上若干兄弟节点哈希,验证者沿广义索引指引的路径重算根值即可核验单个字段。信标链的同步委员会、验证者注册、以及 KZG 承诺周边的一系列证明,都长在这块地基上。它要求预先约定 schema 的另一面,是不像 JSON 那样自描述——对协议内数据这是纪律,对开放接口是负担。

为什么执行层不换

统一编码的提议每隔一阵就会出现,却始终没成为工程共识:执行层的 RLP 深深刻在存量区块、交易哈希与工具链里,换编码等于换哈希身份证,风险远大于收益;而共识层是 2020 年从零起草的新世界,没有历史包袱,正好用上更适合证明的设计。于是出现务实的双轨制:执行层内容继续 RLP,凡被信标链引用时先原样嵌入或取哈希再包装;跨层接口各自注明口径。唯一保留 RLP 的特殊角落是共识层的节点发现协议——官方文档对此有明确说明,细节查规范比背结论可靠。

一个直觉算术

粗算一笔:一笔调用触碰三十个不同存储槽,其中二十五槽是首次,光首访费就要吃掉五万上下的燃料;若同样的数据被拆进两条交易执行,热清单不跨交易继承,冷费得原样再付一遍。这就是批处理合约偏爱一次性大事务、调度器把同批数据攒进一笔的原因——省下来的不是计算量,而是把同一片状态从沉睡里叫醒的次数。

快速问答

问:SSZ 会取代 RLP 吗?至少在可见的升级清单里,执行层编码没有更换计划。问:默克尔化合约 ABI 编码算 SSZ 吗?思路相近但属另一套约定,别混用术语。问:哈希树根和交易哈希是一回事吗?不是,前者是对共识结构按 SSZ 规则出的根,后者按执行层编码定义。问:字段证明为什么省流量?因为只需出示差异路径的哈希,不必搬运整个对象,这正是数据可用性采样等方向的底层弹药。

常见误区

一是把 SSZ 说成“更先进的 RLP”,两者目标函数不同,比“谁好”不如比“给谁用”。二是忽略默克尔化的补齐规则——叶子数必须补齐到 2 的幂,跨实现联调时这是经典的根不一致来源。三是把哈希树根直接当内容寻址 ID 用,它只对同一模式下的编码有意义,改字段顺序就换根。

小结

RLP 回答“怎么把列表压成字节”,SSZ 回答“怎么让结构里的每个零件都能被单独出示”。以太坊保留两种编码不是犹豫不决,而是让编码跟着证明需求走:执行层为吞吐与历史负责,共识层为可验证性加码。分清这两个世界,就分清了链上数据“被传输”与“被证明”的两层含义。

风险提示:本文只解释协议编码机制,不构成投资或收益建议;字段级规则以 consensus-specs 与执行层规范当期文本为准。