Skip to main content

概要

Statesync 是将状态同步到接近当前最新块的目标区块的过程。同步节点(“客户端”)向其他最新的验证者(“服务器”)请求数据,以帮助其从当前视图进展到目标视图;服务器依赖 MonadDb 中的元数据高效响应请求。 由于当前最新块是一个移动目标,statesync 完成后,客户端会发起另一次 statesync 请求以更接近当前最新块,或者如果在追赶范围内则重放已排队的区块。

方法

Statesync 是将存储在 MonadDb 中的状态同步到接近当前最新块的目标区块的过程。 当前最新块是一个移动目标,所以在 statesync 运行时,同步节点会存储目标区块之外的新区块,statesync 完成后,通过正常执行重放这些额外的区块以赶上当前最新块。目标区块可能在此过程中被更新多次。 Statesync 遵循客户端-服务器模型,statesync 请求者是客户端,服务 statesync 请求的验证者节点是服务器。

Statesync 包含的数据

MonadDb 存储与区块执行相关的各种数据。然而,只有一部分是完全参与活跃集合所必需的,因此包含在 statesync 中:
  • 账户,包括余额、代码和存储
  • 最后 256 个区块头(用于验证正确性)
为了均匀分配负载,上述每一项都被拼接成数据块。客户端将每个数据块分配给一个服务器,该服务器在同步完成之前一直是该数据块的对等节点。 服务器从可用对等节点列表中随机选择。客户端维持一定数量的会话,最多为配置的最大值。如果服务器无响应,客户端的 statesync 请求将超时并从另一台服务器请求。

版本控制和验证

为了效率,客户端按从最不最近更新到最近更新的顺序请求状态,在过程接近尾声时收敛到最新块。服务器提供相对于客户端最新区块的差异。 statesync_requests 在上面的示例中,statesync 客户端向分配给前缀 p 的 statesync 服务器连续发起三次请求。对于每个请求,指定五个参数:
  • prefix - 默克尔帕特里夏树的前缀
  • i - 起始区块号
  • j - 结束区块号
  • target - 目标区块号
  • last_target - 上一个目标区块号,用于推断要发送的删除
因为可能有多轮 statesync(在 statesync 发生时,链在推进,目标区块可能需要调整),j 相对于目标区块缓冲了某个偏移量 B,以避免重传 MPT 中最近使用的节点。当 itarget 区块足够接近时,如上面最后一轮所示,statesync 客户端将请求 j = target 此时,如果 target 距离链最新块的差值小于 statesync_threshold(默认为 600 个区块),则 statesync 结束,状态根将被验证。target 和最新块之间的任何剩余区块将通过 blocksync 同步。如果 target 距离链最新块超过 statesync_threshold 个区块,将开始新一轮 statesync。 在区块执行期间,服务器将版本与节点内容一起存储。因此,在收到 statesync 请求时,服务器能够快速缩小相关子树的范围并提交读请求,这些请求是极易并行的。

信任假设

Statesync 客户端信任来自 statesync 服务器的请求数据(包括状态根和父哈希)是正确的。目前是根据质押权重从验证者集合中随机采样,但客户端可以选择将特定的已知提供者列入白名单作为 statesync 服务器。 当前实现在整个传输完成后,通过比较状态根来验证传输的数据。因为工作是在多个服务器之间分割的,单个服务器发送无效数据可能导致状态根不匹配,且无法归因于故障服务器。在这种情况下的唯一补救措施是重试整个传输,让故障服务器有机会再次导致操作失败。 目前正在实施变更,以在每个服务器的基础上验证传输的数据。当发生故障服务器发送无效数据时,statesync 客户端可以 丢弃并重试受影响的前缀。此外,它可以识别故障服务器,记录错误,并可能将其列入黑名单,不再对其发起后续请求。