snap/2 - 基于BALs的状态恢复

该EIP提出了将以太坊的snap协议从v1升级到v2的方案。核心变化是用基于EIP-7928引入的区块级访问列表(BALs)的状态恢复机制,取代了迭代获取Merkle树节点的方法。新协议定义了BALs的请求与响应消息,并详细阐述了基于BALs的同步算法,旨在提升快照同步的效率和鲁棒性。

摘要

本 EIP 将 snap 协议从版本 1 升级到版本 2,移除了 GetTrieNodes (0x06) / TrieNodes (0x07),并用 GetBlockAccessLists (0x06) / BlockAccessLists (0x07) 取代它们,以实现 snap 同步期间基于 BAL 的状态修复。

动机

EIP-7928 引入了区块级访问列表 (BAL),它捕获每个区块的所有状态更改,并通过 block-access-list-hash 提交到区块头。有了可用的 BAL,snap 同步的修复阶段——该阶段通过 GetTrieNodes 迭代地获取单个 Merkle trie 节点以解决状态不一致性——可以完全取代。

同步节点不再通过多次往返发现和获取 trie 节点,而是下载在同步期间前进的区块的 BAL,并顺序应用状态差异。每个 BAL 都根据其头承诺进行验证。需要追赶的区块集是预先知道的,从而消除了迭代发现。

规范

协议版本

协议版本从 snap/1 递增到 snap/2。对等节点在 RLPx 能力握手期间协商版本。

已移除的消息

消息 ID 原因
GetTrieNodes 0x06 被基于 BAL 的修复取代
TrieNodes 0x07 被基于 BAL 的修复取代

新消息

释放的消息 ID 被重用于 BAL 交换。

GetBlockAccessLists (0x06)

[request-id: P, [blockhash₁: B_32, blockhash₂: B_32, ...]]

请求给定区块哈希的 BAL。每个请求的哈希数量受限于实现定义的限制。

BAL 仅适用于 EIP-7928 激活后的区块,并在其中定义的保留期内可用。

注意:

  • 节点必须始终响应查询。
  • 如果节点没有请求区块哈希的 BAL,它必须在该位置返回一个空条目(零长度字节切片)。
  • 响应节点可以返回更少的条目(服务 QoS 限制),从尾部截断。返回的条目必须保留请求顺序。
  • 节点应该EIP-7928 定义的保留期内保留孤立(非规范)区块的 BAL。由于请求以区块哈希为键,孤立的 BAL 可以像规范 BAL 一样被提供。保留它们使得同步节点可以在超过枢轴区块的 reorgs 中恢复,而无需重新启动同步。

BlockAccessLists (0x07)

[request-id: P, [block-access-list₁, block-access-list₂, ...]]

GetBlockAccessLists 的响应。每个元素都与请求中的区块哈希按位置对应。在 BAL 不可用的区块处返回空 BAL(零长度字节切片)。

BlockAccessLists 响应的推荐软限制为 10 MiB。

未更改的消息

消息 0x00–0x05 (GetAccountRange, AccountRange, GetStorageRanges, StorageRanges, GetByteCodes, ByteCodes) 与 snap/1 保持不变。

验证

收到的 BAL 必须通过计算 keccak256(rlp.encode(bal)) 并与相应区块头中的 block-access-list-hash 进行比较来验证。有关 BAL 编码格式,请参阅 EIP-7928

同步算法

snap/2 用基于 BAL 的追赶取代了 trie 修复:

  1. 下载区块头并识别链头。
  2. 选择一个枢轴区块 P,它足够落后于链头(例如 HEAD-64),以减少 P 被 reorg 的可能性,同时保持足够新,以便服务对等节点仍然在内存中持有其状态。
  3. 通过 GetAccountRangeGetStorageRangesGetByteCodes 批量下载 P 处的状态。
  4. 在状态下载期间,链条向前推进,枢轴从 P 切换到新区块 P+K(通常 K 为 64)。因为一旦枢轴前进,服务对等节点可能不再保留 P 处的状态,所以同步节点通过 GetBlockAccessLists 获取 P+1 到 P+K 的 BAL,在本地应用状态差异,并立即使用 P+K 作为新的同步目标。每个 BAL 在应用前都根据其头哈希进行验证。
  5. 如果在步骤 4 中枢轴进一步前进,则对新生成的区块重复此过程。
  6. 重新计算并验证状态根与最新区块头进行比对。

如果链条重组(reorgs)超过枢轴区块 P,设 W 为旧链和新规范链的共同祖先。同步节点收集旧分叉上 W+1 到 P 的 BAL,识别在旧分叉上被修改但未在新分叉上被修改的状态条目,在本地删除这些条目,并通过 GetAccountRange / GetStorageRanges 重新获取它们。然后应用新规范链上从 W+1 开始的 BAL,并以新的枢轴继续同步。如果所需的孤立 BAL 不可用,节点必须丢弃状态并重新启动同步。

基本原理

独立协议与 eth/71

这遵循了既定的 snap 设计理念。GetByteCodeseth 复制到 snap 的原因相同:

此功能从 eth/65 复制到 snap,以允许 eth 长期仅作为链维护协议,并将同步原语移至卫星协议。

同步原语属于卫星协议。snap 是可选的,并且独立版本化;在此处复制 BAL 交换避免了将同步功能与 eth 耦合。

移除 GetTrieNodes

基于 BAL 的修复使得 trie 节点获取以进行状态协调变得不必要。移除这些消息避免了维护两种修复机制,并释放了消息 ID 以供重用。

消息 ID 重用

消息 ID 的作用域限定在协议版本内,并在 RLPx 能力握手期间进行协商。snap/1 对等节点永远不会收到 snap/2 消息。

向后兼容性

此 EIP 需要推出一个新的协议版本,snap/2。旧客户端继续使用 snap/1。snap/2 仅对 Amsterdam 后区块有意义,因为 block-access-list-hash 头字段 (EIP-7928) 在更早的区块中不存在。snap/2 对等节点必须也运行 eth/71 或更高版本,因为 snapeth 的一个依赖卫星协议。

对于正在同步数据的节点,如果同时支持 snap/1 和 snap/2,它应该使用 snap/1 或 snap/2 进行状态同步;不建议同时运行两者。一旦同步阶段完成,节点可以为两个协议提供请求服务。

安全考虑

放大攻击

GetBlockAccessLists 请求可以触发比请求本身大得多的响应。实现应该应用速率限制,并遵守 10 MiB 的软响应限制。

不可用数据

对可用区块返回空条目的对等节点可能是行为不端或合法地修剪了数据。实现应该跟踪对等节点的可靠性,并降低不可靠对等节点的优先级。

应用顺序

BAL 必须按严格的区块顺序应用,并在应用前验证每个 BAL 哈希。错误的顺序或错误分叉的 BAL 会产生无效的状态根,这将在最终状态根验证期间被检测到。

版权

版权和相关权利通过 CC0 放弃。

  • 原文链接: github.com/nerolation/EI...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Nerolation
Nerolation
江湖只有他的大名,没有他的介绍。