历史链 ID 还能不能查:EIP-1965 与分叉后的签名校验 图 1
历史链 ID 还能不能查:EIP-1965 与分叉后的签名校验 · 图 1

EIP-155 把链 ID 焊进交易签名之后,重放保护解决了「交易」这一层,但另一层始终悬着:链下签名。EIP-712 结构化签名把 chainId 写进域分隔符,合约里校验「这个签名是不是给这条链签的」,用的指令是 EIP-1344 的 CHAINID——它只回答一件事:现在这条链的链 ID 是多少。这个「现在」在大多数日子里没问题,可一旦某次硬分叉改了链 ID(历史上以太坊对 ETC 的分叉就是最直白的例子),麻烦就来了:一份 chainId 为旧值的合法签名,在新链上的合约里会被判定无效——哪怕签名本身、消息本身都完好无损。

EIP-1965 由 Ronan Sandford 在 2019 年 4 月 20 日提出(它引用同一作者的 EIP-1959 作为理论基础),状态 Stagnant,从未进入任何主网升级。它的问题设定很精确:给合约一个历史查询能力——「链 ID X 在区块号 N 是否有效?」方案是新增一个预编译,输入两个 32 字节值(待测链 ID、待测区块号),返回 0x1 或 0x0。规则上把链 ID 的生命周期定义为「从其引入的块起有效,直到被下一个链 ID 替换」;提案明确链 ID 只在硬分叉时被替换,所以有效区间是一段段首尾相接的历史。成本上它论证得很克制:查询本质是沿区块哈希历史走一段,费用不超过 G_blockhash 加 G_verylow 一档,并且承认随着历史上链 ID 数量增长,价格可能需要再调。

为什么不用智能合约自己缓存历代链 ID?提案给出的理由带着一层安全考虑:合约缓存需要有人写入,写入者的链只能记录「它认为的」分叉史;少数派链发起的分叉场景下(原文以当时视角讨论多数派与少数派分叉的两种剧本),链下签好的一份消息理应在分叉两侧都可被验证,「所有分叉前签的消息在所有分叉的后代上都应保持有效,唯一要防的是把签名带到另一条无关链上重放」。把查询下沉到协议层的预编译,等于让每条链用自己的区块历史自证家门,不依赖任何外部登记。这也呼应它对 EIP-1344 的批评:只查最新链 ID 会让合约拿它做重放保护时「顺手杀死」旧签名,对用户可能造成灾难性后果。

这份提案停摆的原因不难从档案里读出来:链 ID 变更在实践中极其罕见,主流 L2 与主网各自稳定持有自己的链 ID,签名域里跨分叉验证的真痛点长期由「链 ID 不变」这一社会事实兜底;预编译要占共识层预算、要全客户端实现,为一件低概率事件定价很难通过成本审议。但它标记的问题并没有消失:账户抽象、跨链意图签名、需要长期有效的许可签名,这些 2019 年之后才爆发的场景,全部把「签名的链有效性」从边缘问题推向工程日常。哪天链 ID 的历史查询需求再次压过来,EIP-1965 大概率还会被翻出来当起点。

顺手补一段现场用法:假设你要部署一个跨两条同名分叉链都能验证的许可签名,最稳妥的姿势仍是 EIP-712 的域分隔符写死双方共同认可的链 ID 常量,并在部署前确认目标链此后不会变更它;把「历史验证」留给未来的协议能力,是 2019 年以来绝大多数项目的实际选择。反过来说,任何声称「自动适应未来分叉」的链下签名方案,都值得先问一句:它靠谁记账这段历史。

快速问答

问:今天的合约能查历史链 ID 吗? 答:没有协议级方法。合约能做的只是校验当前 CHAINID,或者在应用层自己登记分叉历史并承担信任。

问:它和 EIP-155、EIP-1344 是什么关系? 答:EIP-155 在交易里绑链 ID,EIP-1344 让合约读到「现在的」链 ID,EIP-1965 想补的是「过去任意块号上的」链 ID——三者是同一条防重放线上的三层。

风险提示:链上校验规则与签名域参数属于协议细节,迁移资产或升级签名方案前请以实际链的行为验证为准,本文不构成投资建议。

历史链 ID 还能不能查:EIP-1965 与分叉后的签名校验 图 2
历史链 ID 还能不能查:EIP-1965 与分叉后的签名校验 · 图 2