ZKStack 跨链架构内幕 — 第一部分:Merkle 树层级结构的深度解析

本文是关于 ZKStack 协议升级的技术结构的探索,重点介绍了构成安全跨链通信骨干的三个关键 Merkle 树实现:L2ToL1LogsTreeChainTreeSharedTree。文章详细描述了每个树的叶子节点构成、大小以及根的用途,并解释了它们在 ZKChain 生态系统中的作用,为理解跨链交互的底层机制提供了重要信息。

目录

简介

这个分为两部分的文章系列探讨了即将到来的 ZKStack 协议升级的技术结构,该升级引入了一个 ZKChain 生态系统,该生态系统可以通过结算在另一个 ZKChain 上而不是 L1 上,从而允许轻松创建新的 rollup ZKChain、内置的跨链功能和更便宜的结算成本。

第一部分描述了三个关键的 Merkle 树实现,它们构成了 ZKChain 生态系统中安全跨层通信的支柱,即 L2ToL1LogsTreeChainTreeSharedTree

第二部分阐述了该树层次结构最重要的用例,即通过为其跨链代币转账构建递归证明,来实现一个 ZKChain 在另一个 ZKChain 上结算而不是直接在 L1 上结算。

这个分为两部分的文章系列描述了截至撰写本文时 ZKChain 生态系统的当前状态及其内部流程。随着生态系统的发展,所描述的某些功能将来可能会更新。


第一部分:树的形状

让我们深入研究支持生态系统的这些关键树数据结构的细节。对于每棵树,我们系统地探索其:

  • 叶子节点:构成树的内容
  • 大小:有多大以及如何增长
  • 根节点:根节点如何使用以及它位于何处。

有用的术语

  • ZKChains:生态系统中的任何 rollup 链都被视为 ZKChain。ZKChain 可以在以太坊网络 L1 上结算,也可以在另一个 ZKChain 上结算。在本系列文章的下一部分,我们才会考虑在另一个特殊的 ZKChain 上结算而不是在 L1 上结算的 ZKChain。
  • 结算层(Settlement Layer):ZKChain 提交、验证和最终确定批次的网络。对于某些链来说,这是以太坊(L1),而对于另一些链来说,结算层可能是另一个 ZKChain。目前,唯一被列入白名单作为结算层的 ZKChain 是 Gateway ZKChain。我们将在本系列文章的下一部分进一步探讨 Gateway 链。
  • 批次(Batch):ZKChain 的批次包含来自一个或多个 L2 区块的链的交易,以及在这些区块内产生的任何其他信息,这些信息是 Settlement Layer 上重建 ZKChain 状态所必需的。
  • DiamondProxy:ZKsync 生态系统中每个 ZKChain 使用的一组智能合约,它支持结算并允许在保留存储布局的同时进行升级。ZKChain 的状态(例如,批次的 Merkle 根)保存在其结算层上的 DiamondProxy 中。

在第一部分中,我们从一般角度描述了这些树与其结算层的关系。在这里,我们使用 L2 来指代通用的 ZKChain,使用 L1 来指代它的结算层。


L2ToL1LogsTree

这棵树由每个已提交批次从 L2 到 L1 的所有启动的跨链交易组成。因此,每个批次都有自己的 L2ToL1LogsTree。它在每个 L2 链上构建,其中包含 L2 交易产生的日志,L1 应该收到这些日志的通知。无论 ZKChain 是在 L1 上还是在另一个 ZKChain 上结算,或者它本身是否是 Settlement Layer,所有 ZKChain 都以相同的方式构建 L2ToL1LogsTree

img1-2

叶子节点:L2ToL1Log

L2ToL1Log 叶子由来自每个批次的 L2 交易的消息或日志组成,包括但不限于:

  • L1 到 L2 TX 的执行状态:当 L1 到 L2 交易成功或失败时,会记录日志。如果失败,这些日志可以帮助用户恢复失败的 L1 到 L2 代币转账。
  • L2 到 L1 代币提款:当启动 L2 到 L1 提款时,会创建一个日志,例如提款原生代币。这也适用于从 L2AssetRouterL2LegacyBridge 提款。这些日志有助于最终确定 L1 上的提款,以完成 L2 到 L1 代币桥接。
  • 协议升级:当 L2 合约进行协议升级时,日志有助于更新 L1 链存储变量,确保升级得到反映。
  • 字节码发布:新部署合约的压缩未压缩字节码使用 L2ToL1Logs 发布在 L1 上。这有助于在使用 L1 上发布的状态差异重建 L2 状态时实现数据可用性。

通常,不需要 L1 通信的常规 L2 交易不包括在 L2ToL1Logs 中。相反,L2 状态差异发布在 L1 上以确保数据可用性。

大小:16_384

这棵树的固定大小为 2^14 个叶子,这使得它非常大,高度为 14 层。但是,它可能非常稀疏,这意味着有很多空叶子。在这种情况下,它的构造需要用一个默认值 表示空叶子来填充它。因此,这棵树有足够的空间供未来高吞吐量链使用。

根节点:LocalLogsRootHash

通过以通常的方式哈希 L2ToL1LogsTree Merkle 树,可以得到本地根,称为 LocalLogsRootHash,它由 16_384 个叶子构造而成。

请注意,正如本系列的下一部分将解释的那样,这不是在发布批次时提交到结算层的根。为了获得批次的根,LocalLogsRootHash 进一步与 sharedTree 的根连接在右侧,以生成 fullRootHash。(sharedTree 的幕布很快就会在下面揭开。)


链树(ChainTree)

当创建一个新的 ZKChain 时,它的 ChainTree 在 L1 上的 MessageRoot 合约以及 ZKChain 的结算层(如果它与 L1 不同)上启动。每个 ZKChain 都有自己的 ChainTree

尽管 MessageRoot 合约在所有 L2 ZKChain 的创世时都被强制部署,但只有结算层具有非平凡的 ChainTree(以及 SharedTree,我们稍后会看到)。与 L2toL1LogsTree 相比,链的 ChainTree 并不驻留在其自身链上,而是位于其结算层的 MessageRoot 合约中。

通常,结算层负责跟踪每个在其上结算的 ZKChain 的最新 ChainTree。它的目的是将有关成功结算批次的所有信息提交到单个根哈希中。

img2-2

叶子节点:chainBatchRoot

当来自此 ZKChain 的新批次在结算层结算时,ZKChain 的 ChainTree 会增长一个新的叶子。因此,这棵树表示从 L2 到 L1 所有成功执行的批次的记录。这棵树使用 DynamicIncrementalMerkle.Byte32PushTree 数据结构表示。

叶子构造方式是:首先将提交的根(即来自每个批次的 fullRootHash(即 L2toL1LogsTreeSharedTree 的根的串联))加上 BATCH_LEAF_PADDING 前缀,然后加上相应的 batchNumber 后缀,然后将其全部哈希到大小为 32 字节的适当叶子。

大小

与具有固定大小的 L2ToL1LogsTree 不同,ChainTree 是一种动态结构,它随着链的结算层上每次新的已执行批次而增量增长。树的叶子总数等于已在该层上结算的批次数量。但是,如果链已从一个结算层迁移到另一个结算层,则这棵树将拆分。当链迁移回来时,先前停滞的 ChainTree 将继续增长。因此,如果发生迁移,则 ChainTree 的叶子的索引可能与其批次号不对应。

动态特性使其可以有效地适应链的实际吞吐量,而无需预先确定的空间分配。

根节点:chainRoot

通过以通常的方式哈希 ChainTree 叶子,可以得到 chainRoot。对于每个结算的 ZKChain,每当执行新的批次时,都会更新此根,并立即用于更新 SharedTree 的相应叶子。


共享树(SharedTree)

SharedTree 中的每个叶子对应于结算 ZKChain 的 ChainTree 根。SharedTree 存在于 MessageRoot 合约中,这意味着与所有结算 ZKChain 的 ChainTree 所在的合约相同。请注意,与 ChainTree 类似,虽然所有 ZKChain 共享相同的设计并具有 SharedTree,但只有结算层的 SharedTree 是非平凡的。不充当结算层的 ZKChain 将只公开一个表示默认 SharedTree 的根。

SharedTree 的目的是将包含在所有结算 ZKChain 的 ChainTree 中的所有批次信息提交到单个根哈希中。

img3-2

叶子节点:chainRoot

当新的 ZKChain 首次添加到该层或迁移到该层时,结算层的 SharedTree 会增长一个新的叶子。每个叶子对应于一条链。这棵树使用 FullMerkle.FullTree 数据结构表示,它在存储中保存所有叶子和节点值。

每个叶子通过哈希chainRoot 的填充版本及其 chainId(称为 ChainIdLeaf)来形成。每次 ZKChain 的 ChainTree 根更新时(即每当结算批次时),SharedTree 中对应的叶子将被更新。

大小

除非添加新的 ZKChain,否则 SharedTree 的大小不会增长。随着每个新批次的结算,ShareTree 保持其大小,但更新其根。因此,与 ChainTree 相比,SharedTree 的预期大小更小,并且上限为 100。请注意,在非结算层中,SharedTree 本质上是空的。

根节点:aggregatedRoot

对任何结算 ChainTree 的每次更新都会触发对 aggregatedRoot 的相应更新。在不是结算层的 ZKChain 上,aggregatedRoot 始终是使用其自身的 chainId初始化的默认哈希。但是在列入白名单的结算层上,这是对所有在那里结算的 ZKChain 的整个交易历史的承诺。


结论

这三个 Merkle 树共同构成了一个复杂的密码学架构,确保 ZKChain 及其结算层之间的安全、可验证的通信。

在第二部分中,我们将探讨这种分层结构最重要的应用,即当 ZKChain 在另一个 ZKChain(所谓的 Gateway 链)上结算时,这是目前唯一列入白名单的结算层。我们将说明如何为跨链代币转账的具体用例构建递归证明。

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

0 条评论

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