分叉一次,证明碎一遍
以太坊共识层的数据结构用 SSZ 序列化:固定字段按默克尔树排列,轻客户端与跨链合约靠默克尔证明读取某个字段。这套机制有一个长期痛点:SSZ 容器在分叉中经常增删字段,字段数量一旦跨过 2 的幂、或者某字段被删除换类型,底层默克尔树的形状就变了——原先对字段七做的证明,换版后指向完全不同的树位置。验证方(轻客户端合约、嵌入式设备固件)被迫跟着每次分叉升级,哪怕它关心的字段语义一个字没变,升级有时还得走安全委员会投票。EIP-7495 就是要让”字段的地址”像门牌号一样终身不变。
渐进容器的三条承诺
提案引入新 SSZ 类型 ProgressiveContainer,配一个 active_fields 位向量声明哪些位置住着字段。三条设计承诺。第一,泛化索引稳定:Square 容器把 side 放 0 号位、color 放 2 号位(1 号位留空),Circle 把 radius 放 1 号位、color 同样在 2 号位——两者共享同一棵树的坐标框架,字段挪版本不换位置,删除字段就在树上留空洞。第二,证明随字段数生长:底层用渐进默克尔树(依赖 EIP-7916),树按需增长, prover 写的证明在字段数变化后依然有效。第三,序列化紧凑:序列化与普通容器完全一致,缺席字段不占一个字节,反序列化、JSON 映射也都沿用普通容器规则——线上数据格式不变,变的只是默克尔化那一步。默克尔根计算时额外把 active_fields 位向量混合进去(≤256 位打包后与根哈希相混),让”这个字段不存在”与”这个字段等于零”在根上可区分,这是防止跨版本根碰撞的安全设计。
边界与代价
提案划了几条红线:零字段的容器非法(序列化长度为零,列表就没法定位元素个数);active_fields 超过 256 项非法;结尾是 0 的位向量非法(等价于可缩短);1 的个数必须等于字段数。为什么 256 封顶?一个机器字的混合最简单、与列表长度混合的设计对称,且实践够用——主网的信标状态容器也就四十来个字段,真接近上限再嵌一层子容器即可。为什么不顺手做 Optional 类型?提案明确推迟:现有需求不依赖它,位向量未来可以兼职表达可选性。代价在另一边:渐进树比完整二叉树的默克尔化路径稍长, prover 与全节点的哈希次数略增,换来的是验证器升级周期从”每次分叉”拉长到”字段语义真变时”。
现状与配套
EIP-7495 状态 Review(2023 年 8 月创建,依赖 7916),配套采纳案 EIP-7688(把渐进容器与渐进列表铺进共识结构)状态也是 Review——这套机制尚未进入主网信标链数据结构,属于推进中而非已落地。它服务的读者很具体:以太坊轻客户端合约(依托 EIP-4788 读信标根的那类)、跨链桥验证器、状态less 场景的 proof 工具链。对普通用户,它是那种”看不见的减震器”型改进:哪天跨链桥不再因为一次分叉停机升级,多半就有这类向前兼容设计的功劳。
与执行层邻居的分工
别把 7495 和执行层的存储布局方案混为一谈。ERC-7201 给 Solidity 智能合约的内部存储槽位做哈希命名,解决的是同一地址上多个合约代码共享存储时的撞槽问题;7495 服务的是信标链侧的 SSZ 容器,保证的是轻客户端默克尔证明跨版本存活。两者的相似只在”给数据钉门牌”这一层抽象,机制、环境、威胁模型全都不同:前者防的是开发者互相踩踏,后者防的是时间冲刷——合约存储的风险来自同代代码,SSZ 容器的风险来自未来分叉。以太坊为此同时养着两套序列化世界观:执行层的 RLP 与共识层的 SSZ,前者简洁、后者天生便于证明,7495 完全在 SSZ 一侧。读任何”存储布局”话题先问自己:说的是哪一层?这个问题能过滤掉大半混淆。
快速问答
问:这跟智能合约里的存储槽冲突问题像吗? 答:思路同族——都是给数据位置钉门牌号。ERC-7201 用哈希命名空间隔离 Solidity 存储槽,7495 用固定泛化索引隔离默克尔位置,机制无关但哲学一致。
问:留空洞不是浪费哈希吗? 答:空洞位置只贡献一个固定的零叶子哈希,代价被渐进树摊薄,换来跨版本证明存活。
问:现在客户端实现了吗? 答:以提案文本为准——Review 状态的类型已在 remerkleable 等库有参考实现与随机测试,共识结构的采纳由 7688 走流程。
风险提示:本文是数据结构提案科普,不构成投资建议;类型与参数以当期规范文本为准。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。