本文是 ZKStack 协议升级的技术结构探索系列的第一部分,介绍了 ZKChain 生态系统中用于安全跨链通信的三个关键 Merkle 树实现:L2ToL1LogsTree、ChainTree 和 SharedTree,分别从叶子节点、大小和根节点三个方面详细阐述了这些树的结构和功能。这些树的合理架构, 能够确保 ZKChain 及其结算层之间安全且可验证的通信。
这个分为两部分的文章系列探讨了即将到来的 ZKStack 协议升级的技术结构,该升级引入了一个 ZKChain 生态系统,该生态系统能够轻松创建新的 rollup ZKChain,内置跨链功能,并通过在另一个 ZKChain 而不是 L1 上进行结算来降低结算成本。
第一部分描述了三个关键的 Merkle 树实现,这些实现构成了 ZKChain 生态系统中安全跨层通信的支柱,即 L2ToL1LogsTree、ChainTree 和 SharedTree。
第二部分阐述了这种树层次结构最重要的用例,即一个 ZKChain 在另一个 ZKChain 上结算,而不是直接在 L1 上结算,方法是为其跨链代币转账构建递归证明。
这个分为两部分的文章系列描述了截至撰写本文时的 ZKChain 生态系统的当前状态及其内部程序。随着生态系统的发展,所描述的某些功能将来可能会更新。
让我们深入研究这些支持生态系统的关键树数据结构的细节。对于每棵树,我们系统地探讨它的:
有用的术语 (Useful Terminology)
Gateway ZKChain。我们将在本系列的下一部分进一步探讨 Gateway 链。DiamondProxy 中。在第一部分中,我们从相对于其结算层的通用角度描述这些树。在这里,我们使用 L2 来指代通用的 ZKChain,使用 L1 来指代其结算层。
这棵树由每个已提交批次的所有从 L2 发起的跨链交易组成。因此,每个批次都有自己的 L2ToL1LogsTree。它在每个 L2 链上构建,其中包含 L2 交易产生的、应通知 L1 的日志。 无论 ZKChain 是在 L1 上还是在另一个 ZKChain 上结算,或者它本身是否是结算层,所有 ZKChain 的 L2ToL1LogsTree 的构造方式都相同。

L2ToL1LogL2ToL1Log 叶子由每个批次的 L2 交易的消息或日志形成,包括但不限于:
一般来说,不需要 L1 通信的常规 L2 交易不包括在 L2ToL1Logs 中。 相反,L2 状态差异发布在 L1 上,以确保数据可用性。
16_384这棵树具有 2^14 的固定大小 个叶子,这使得它异常大,高度为 14 层。 但它可能非常稀疏,这意味着有很多空叶子。 在这种情况下,它的构造需要用默认值 填充它,表示一个空叶子。 因此,这棵树有足够的空间用于未来的高吞吐量链。
LocalLogsRootHash通过以通常的方式哈希 L2ToL1LogsTree merkle 树,可以得到局部根,称为 LocalLogsRootHash,它由 16_384 个叶子构造而成。
请注意,正如本系列的下一部分将解释的那样,这不是在发布批次时提交到结算层的根。 为了获得批次的根,LocalLogsRootHash 进一步与 sharedTree 的根在右侧连接,以生成 fullRootHash。(sharedTree 的面纱将在下面很快被揭开。)
当创建一个新的 ZKChain 时,它的 ChainTree 在 L1 上的 MessageRoot 合约以及 ZKChain 的结算层(如果它与 L1 不同)中启动。每个 ZKChain 都有自己的 ChainTree。
尽管 MessageRoot 合约在所有 L2 ZKChain 的创世块处强制部署,但只有结算层才拥有非平凡的 ChainTree(以及 SharedTree,我们稍后会看到)。 与 L2toL1LogsTree 不同,链的 ChainTree 不位于其自身链上,而是位于其结算层的 MessageRoot 合约中。
通常,结算层负责跟踪每个在其上结算的 ZKChain 的最新 ChainTree。 它的目的是将有关成功结算批次的所有信息提交到单个根哈希中。

chainBatchRoot当来自该 ZKChain 的新批次在结算层结算时,ZKChain 的 ChainTree 会增长一个新叶子。 因此,这棵树代表了从 L2 到 L1 的所有成功执行的批次的记录。这棵树使用 DynamicIncrementalMerkle.Byte32PushTree 数据结构表示。
构造叶子的方法是,首先将来自每个批次的已提交根,即 fullRootHash(即 L2toL1LogsTree 和 SharedTree 的根的连接),加上前缀 BATCH_LEAF_PADDING,然后加上后缀相应的 batchNumber,然后再将其全部哈希为大小为 32 字节的适当叶子。
与具有固定大小的 L2ToL1LogsTree 不同,ChainTree 是一种动态结构,它随着链的结算层上每个新执行的批次而递增增长。树的叶子总数等于已在该层结算的批次数。但是,如果一条链已从一个结算层迁移到另一个结算层,则这棵树会分裂。当一条链迁移回来时,先前停滞的 ChainTree 将继续增长。因此,如果发生迁移,则 ChainTree 的叶子的索引可能与其批号不对应。
动态性质使其能够有效地适应链的实际吞吐量,而无需预定的空间分配。
chainRoot通过以通常的方式哈希 ChainTree 叶子,可以得到 chainRoot。对于每个结算 ZKChain,每当执行一个新批次时,此根都会更新,并立即用于更新 SharedTree 的相应叶子。
SharedTree 中的每个叶子都对应于一个结算 ZKChain 的 ChainTree 根。SharedTree 位于 MessageRoot 合约中,这意味着与所有结算 ZKChain 的 ChainTrees 所在的合约相同。请注意,与 ChainTree 类似,虽然所有 ZKChain 共享相同的设计并具有 SharedTree,但只有结算层的 SharedTree 是非平凡的。不充当结算层的 ZKChain 将只暴露一个表示默认 SharedTree 的根。
SharedTree 的目的是将所有结算 ZKChain 的 ChainTrees 中包含的所有批次信息提交到单个根哈希中。

chainRoot当一个新的 ZKChain 首次添加或迁移到该层时,结算层的 SharedTree 会长出一个新的叶子。每个叶子对应于一条链。这棵树使用 FullMerkle.FullTree 数据结构表示,该数据结构将所有叶子和节点值保存在存储中。
每个叶子都由 哈希 带有其 chainId 的 chainRoot 的填充版本形成,称为 ChainIdLeaf。 每次 ZKChain 的 ChainTree 根更新时(即,每当结算一个批次时),它在 SharedTree 中的相应叶子都会更新。
除非添加新的 ZKChain,否则 SharedTree 的大小不会增长。 随着每个新批次的结算,ShareTree 保持其大小,但会更新其根。 因此,与 ChainTree 的大小相比,SharedTree 的预期大小较小,并且上限为 100 的最大值。 请注意,在非结算层中,SharedTree 本质上是空的。
aggregatedRoot对任何结算 ChainTree 的每次更新都会触发对 aggregatedRoot 的相应更新。 在不是结算层的 ZKChain 上,aggregatedRoot 始终是使用其自身的 chainId初始化的默认哈希。 但是,在列入白名单的结算层上,这是对所有在该处结算的 ZKChain 的整个交易历史的承诺。
这三个 Merkle 树共同构成了一个复杂的密码体系结构,可确保 ZKChain 及其结算层之间的安全、可验证的通信。
在第二部分中,我们将探讨当 ZKChain 在另一个 ZKChain 上结算时,这种分层结构最重要的应用,即所谓的 Gateway 链,它是目前唯一列入白名单的结算层。 我们将说明如何为跨链代币转账的具体用例构建递归证明。
- 原文链接: openzeppelin.com/news/in...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!