您的位置 首页 Defi-NFT

一文了解分形扩展,如何如何使不同 Rollup 之间的桥接便宜

本文档的基本主题是关于分形扩展(fractal scaling)将是什么样子,如何使不同 Rollup 之间的桥接便宜,以及如何使整个分形系统安全。

我们从分形扩展开始,然后我们关注 Rollup 之间的桥接,首先是针对用户,然后是针对智能合约。

然后我们讨论 Rollup 安全性问题:退出策略和所需的 数据可用性(DA)。我们发现现有的解决方案不具备可扩展性,并提出我们的解决方案,即后代 Rollup 的通用共识机制。

然后我们将这个解决方案概括为两部分,第一个概括部分使大多数后代 rollup 能够控制父 rollup,从而在存在恶意父层的情况下更容易退出 Rollup。第二个概括部分用新的 rollup 共识代替 L1 PoS 共识机制(基本上使共识机制能够处理分叉)。

在此之后,我们塑造了树形结构,以使生成的系统具有快速的确认时间和对每个节点的低数据要求。最后,我们总结一下我们的结果:一种分形扩展方法,使交易吞吐量在节点数量上接近线性○(N/log (N)),并且具有○(log (n))最终性时间,和○(log (N)))存储要求。

本文档大纲:

  • 我们首先总结了 ZK rollup 的分形扩展,以及为什么需要在不同的 rollup 之间进行桥接,而不是通过 L1 路由所有内容。
  • 我们继续概述当前的桥接解决方案:无信任 swap、权限桥接、路由和池化路由,并讨论它们的缺点。
  • 桥接

1)然后我们将我们的桥接解决方案描述为一种极端形式的池化路由,它的好处,以及它的不同版本如何部署。

2)然后我们扩展这个桥接,以便智能合约可以使用它。这分为两部分,首先我们启用智能合约来确认桥接过3)程,或者如果没有确认,我们使他们能够通过父 Rollup 路由交易(这很昂贵,但它只是一个后备选项)。

4)然后我们看一下这个分片设置中 AMM 的示例。

  • 安全性

1)然后我们看看 Rollup 的安全性,以及它们如何仅依赖于 L1 的安全性。我们讨论了两种不同的安全退出解决方案,第一个大致是 Starkex 应用程序如何实现安全性,第二个是 Starknet 如何实现它。我们将看到,在尝试进行迭代 Rollup 时,这些解决方案都无法扩展。然后,我们讨论了一种可扩展的退出方式,但如果大多数后代 Rollup 是诚实的,则该机制不是仅依赖于 L1 安全性,而是允许后代 Rollup(父Rollup)退出。

2)然后我们将这个解决方案概括为两部分。第一个概括使大多数后代 Rollup 能够控制父 Rollup,因此如果父层是恶意的,则必须离开的不是大量后代 Rollup,而是单个父层。如果父层和后代之间存在冲突,这在经济上是有意义的,因为父节点比后代节点少。第二个概括用新的 Rollup 共识代替 L1 PoS 共识机制。为此,共识机制必须能够处理 L1 级别的分叉。

3)在此之后,我们查看使该结构在确认时间(交易被确认和不可逆所需的时间)和所需数据存储方面最有效的树状结构。我们在这里意识到两件事,第一是树的窄和深是有意义的(每个 Rollup 应该只有几个子 Rollup),第二,每个 Rollup 的内容(除了子 Rollup ZKP)可以是外部化到单独的Rollup中,使父Rollup包含 ZKP。

  • 最后,我们总结一下我们的结果:一种能够在节点数量上实现近乎线性○( N /log(N))交易吞吐的分形扩展方法。

Zk Rollups 和当前桥接

首先,我们回顾现有的分形扩展和桥接格局。

Zk Rollup

首先让我们看一下类似分形的多层 ZK Rollup 扩展解决方案。 在第一张图中,我们有虚拟机(矩形),它们将压缩状态作为 ZKP 输出到树中更高的 VM。 ZKP 由父层上的 ZKP 验证者智能合约进行验证。

图 1. 基本设置

当状态更新发生时,在我们的映像中,VM 4 会使用内部事务进行更新,托管组 VM 中的 ZKP 会更新,并且托管 VM 的 ZKP 也会发生变化。 这会将树向上传播到 L1,即 VM -1。 我们用紫色来展示它。

图 2. 一个简单的状态更新

在此设置中,桥接是将数据从一个 VM 传输到树的不同分支上的另一个 VM 的行为,而不会给 L1 带来负担。 这是必要的,因为可以假设不同的 Rolllup 在 tx 吞吐量中是恒定大小的,并且如果所有内容都通过它路由,L1 将无法处理吞吐量。

当前的桥接格局

无需信任的桥领域已经被 Hop、Celer、deBridge 或 Connext 等协议饱和占据。首先,我们将这些协议的机制大体分类,发现存在一种三难困境。然后我们简要说明摆脱三难困境的方法、成本以及如何将其用于理想的桥接解决方案。

桥接的第一个选项是将您的资金从源 Rollup 路由到 L1,然后再路由到目标Rollup。这个选项是无需信任的,但是如果每个人都使用这个选项,它会使 L1 过载,所以这个选项总是很昂贵。但是,如果您与其他人一起筹集资金,如果您要去同一个目的地,则可以减轻成本。这是池化路由。这本质上就是 Hop 网络的桥接方式。当从 L3 或更深的地方开始时,可​​以在 L2 上进一步汇集不同的池。但是,此池只能用于在发送和接收 Rollup 上拥有大量用户的应用程序。

或者,您可以直接在层之间进行(例如 Connext)。尽管这些系统比通过 L1 更快且更便宜,但这些系统只会将您在一条链上的资金交换为另一条链上的资金,这意味着需要有一些其他机制来补偿各层之间的净资金流动。这会产生额外的成本,但更重要的是意味着这种方法实际上依赖于其他解决方案(例如池化路由)。

还有另一种直接在各层之间进行的方式,这是由一个授权机构完成的,该机构在每一层(例如 Wormhole)上烧毁和铸造桥接的代币。该权限通常采用较小区块链的形式,并且必须信任这些小区块链存在安全风险。这种系统的缺点是显而易见的。

三难困境

正如我们所看到的,我们有一个三难困境:系统无法满足所有三个必需的属性:1. 无需信任,2. 不接触 L1,3. 进行真正的代币转移而不仅仅是代币交换。这样做的原因是,如果我们有真正的转账而不是交换,那么资金必须在一层销毁,然后在另一层铸造。这种铸造只有在燃烧已经发生的情况下才能发生。确认燃烧发生需要信任某个权威,或者需要从 L1 传递的消息,因为这两层仅通过 L1 不信任地连接。这就是三难困境存在的原因。

图 3. 三难困境,选择2。

Stargate

在写完这篇文章之后,我发现了 Stargate。他们使用了我将概述的类似想法,即基于区块状态哈希的交易成员证明。更糟糕的是,他们使用的是相同的“桥接三难困境”!但是,他们的三难困境选择不同,它是关于“即时保证最终性、统一流动性和原生资产交易”。它们还在不同的 L1 之间进行桥接,而不是在分形树上。在我们的分类中,它们不是无需信任的,并且只进行交换。更重要的是,我们文档的主要部分是第二个安全部分,我们的桥接过程针对文档该部分中描述的结构进行了优化。

虚拟代币与桥代币

如果我们想避免 L1 费用,并且不想在 L1 上转移资金,我们只能使用虚拟代币进行交易,类似于 Hop 协议 hTokens。但是这些可以用它们所代表的真实代币支持 L1。这些虚拟代币可以根据需要进行燃烧和铸造。随着时间的推移,这些可能会在每次 Rollup 中超过本地桥代币,因为转移到其他 Rollup 会更便宜。但是,它们的安全性会降低,因为对单个汇总的攻击可能会危及 L1 上所有锁定的资金。因此,仅将这些令牌部署在足够受信任的 Rollup 上才有意义。

我们无需信任的桥接

三难困境的“解决方案”

在我们的桥接中,我们做出了不同的妥协。如果我们将销毁与 ZKP* 中的 L1 状态根链接在一起,我们可以无信任地确认虚拟代币已在发送者链上销毁。这足以证明目标链,因为它们可以无信任地访问 L1 状态根,并且这样的 ZKP 不能被伪造。

作为一种解决方案,这实际上是池化路由的一种极端形式,因为它不仅有效地将桥事务与目标链的其他桥接事务进行池化,而且还与 Rollup 中发生的所有其他事务进行池化。因此,当 Rollup 的 ZKP 在父链上发生变化时,就是包含销毁的“池化”交易。

所以在这个解决方案中,我们在三难困境中做出的妥协是消息不必通过 L1,我们只需要通过 ZKP-s 间接包含在 L1 中。这种证明可以在链下进行,这很便宜。验证必须在链上进行,但只能在目的链进行,如果那是第 n 层,这意味着那里的计算成本很低。 L1 哈希需要从 L1 向下传递,但这是无信任的,而且数据量不大。考虑到这一点,我们可以解释这种桥接方法的机制。

*技术说明:可以通过 ZKP 进行这种链接,因为 L_n 上的销毁通过 Merkle 树包含在 L_n 状态哈希中,并且此状态哈希通过 L_n 的 ZKP 包含在 L_n-1 状态中。反复重复这个过程,我们可以将 ZKP-s 链接在一起,直到到达 L1。

新桥接

现在我们进入有趣的部分,从 VM 3 向 VM 2 无需信任地发送交易。 首先,事务必须在 VM 3 上发送。这会将树向上传播到根。 现在我们可以创建一个包含 L1 哈希的 ZKP,并证明交易发生了。 我们用红色三角形表示。

图 4. 开始一笔交易

现在我们可以创建一个包含这个 ZKP 的交易。我们可以在 VM 2 上发送这个 tx。VM 2 可以访问 L1 的哈希,所以它可以验证这个交易是有效的。现在它可以相应地更新其状态。这意味着事务发生了,桥接完成了。

然后我们还可以生成一个黄色三角形 ZKP,表示接收已发生,我们稍后将使用它。

图 5. 接收交易

因此,在 VM 3 上发送了事务,在 VM 2 上可以声明它。我们已经实现了我们的目标,这种方法是去信任的,我们没有产生 L1 成本,并且我们确实在不同层之间转移了资金。

桥接总结

在这里,我们解释了一种传输虚拟代币的机制,这意味着它必须在发送者上销毁并在接收 Rollup 上铸造。但是当然,任何类型的数据甚至函数调用都可以通过这种方法进行桥接,价格与其他人使用这种方法的程度无关。另一个优点是绝对不涉及 L1 费用,因为它与汇总的其他用户共享。该解决方案的缺点是证明验证,这是一项必须在链上进行的大量计算,即使仅在目标层也是如此。最后一点,这个解决方案需要特殊的智能合约来验证 ZKP 并铸造代币。

自动桥接和分片 VM

这种桥接方法很棒,但它有一个弱点:智能合约不能使用它。理想情况下,智能合约还可以将资金连接到其他 Rollup,然后他们可以进行函数调用,并且不同 Rollup 之间将具有互操作性。到目前为止,我们还没有这种能力。

如果我为自己桥接资金,并且不执行桥接的接收部分,那么我只会失去资金。智能合约需要确保实际收到交易。(顺便说一句,我们在向子 Rollup 发送事务时确实有这种保证,因为子 Rollup 的新 ZKP 必须使用发送给它的事务。)本节是关于即使在发送到父汇总时也有这种保证,从而实现智能合约使用这种桥接机制在树中的任何地方发送数据。

通常没有这样的保证,因为接收 Rollup 可能已失败并停止更新。但是我们可以保证,如果接收 Rollup 继续更新,他们将不得不将交易作为输入。我们通过 L1 路由交易来保证这一点。但正如我们所知,这很昂贵,而且无法扩展。所以我们只使用路由作为故障保护,而且大多数时候会使用一个捷径:我们的直接桥接方法。如果有机器人扫描树,并在 Rollup 之间传递交易,那么我们可以使用我们的桥接方法发送、接收和确认交易。但是,如果这种桥接没有发生,我们必须恢复到路由。这意味着在发送方 Rollup 上发送事务后,必须冻结汇总,直到它确认收到了事务,或者直到它开始通过 L1 路由事务。

桥接以解决自动桥接

我们的目标是,如果智能合约通过我们之前的桥接方法将交易发送到另一个 Rollup,那么目标 Rollup 必须接收交易。

发送者 Rollup 不能单独发送事务,它需要一个外部机器人来完成。但是如果机器人确实促进了这种信息传输,那么它可以很容易地验证交易确实通过了,我们只需要使用我们的桥接方法桥接一个 ZKP 确认交易已收到!

继续我们之前的图像,在 VM 2 收到交易后,可以计算黄色三角形 ZKP(我们在上一步中没有使用这个 ZKP)。可以将此 ZKP 发送回 VM 3 进行确认。这类似于 VM 2 收到交易时的先前更新。导入此验证会解冻 VM 3 的状态,它们可以再次进行事务和内部状态更新。这种确认和冻结是必要的,这样资金就不会丢失,如果 VM 3 发送了一些东西,VM 2 需要接收它。

图 6. 确认交易

后备选项

但是,如果没有机器人将交易发送到接收链,或者将确认带回来,会发生什么?已经有一种方法可以激励 Rollup 执行操作:强制操作。这由使用 Starkex 且可能没有抗审查性的应用程序使用,它允许用户将交易发送到 L1 上的 ZKP 验证者合约,并且证明者必须在给定的时间范围内处理交易,否则有冻结应用程序的风险。我们可以在这里使用相同的方法!如果运行该层的节点不确认交易发生,那么唯一可能的 ZKP 更新是交易被推上树的那一次。在此之后,它必须向上推向发送方和接收方的共同原始方,然后进一步的强制操作可以将交易拉到接收方。这意味着存在三个选项,事务被确认,通过强制操作路由,或者其中一个 Rollup 在未完成强制操作后停止更新。

这是万一 VM 3 和 VM 2 出现一些通信错误或其中一个被破坏时的故障保护机制。这对应于恢复到在此设置中传递的传统消息,这意味着我们将消息向上传递到根,然后将其拉向接收者。

如果 VM 2 没有收到 ZKP,或者 VM 3 没有收到确认,那么最后两个图像(图 5 和图 6)不会发生。这意味着交易已发送,但仍需要接收。在这种情况下,节点 3 的状态被锁定,他们可以通过将原始交易的 ZKP 向上推向父节点来解锁它。然后,父母将其向上推到必要的高度,在本例中为 VM -1。

图 7. 向上推送交易

在事务被向上推送之后,应该只能在他们将事务拉取并处理到他们的 VM 时才能更新他们的状态。

图 8. 向下推送交易

以 AMM 为例的分片虚拟机

借助这种互操作性属性,智能合约可以调用并将数据发送到其他 Rollup。有了这个,在每个 Rollup 上都有多个 AMM-s 比为一个可以处理来自和到所有其他 Rollup 的事务的 AMM 有一个单独的 Rollup 更有意义。

AMM 可以托管在抗审查和去中心化的 Rollup 上。这将使用我们的桥接方法与其他 Rollup 通信,这意味着其他 Rollup 和此 Rollup 需要根据状态根进行验证的智能合约。一旦我们有了这个,调用智能合约将在发送者 Rollup 上销毁一种类型的虚拟代币,AMM Rollup 可以通过机器人接收此交易,将资金转换为另一种类型的虚拟代币,并将其发送回原始 Rollup。然后可以铸造新型的虚拟代币。

操作方法、激励措施

现在我们看到可以将不同的 Rollup 视为处理单个大型 VM 的不同部分的单独分片。Rollup 之间的消息传递需要对机器人进行激励,或者由用户自己完成。这是基于 Rollup 的开放性质,如果 Rollup 的主机接受消息,仍然可以发送到关闭的 Rollup。

安全性,以及迭代退出的问题

Rollup 仅依赖于 L1 安全性。安全性有两个部分,一方面它意味着验证所有事务和状态更新是否正确,ZK rollups 擅长于 ZK 证明。但安全性也意味着避免 Rollup 运营商的审查,并能够在运营商停止的情况下继续更新 Rollup。这是必要的,这样用户的资金就不会被锁定在 Rollup 中。即使对于 Rollup 而言,满足这些条件也并非易事,我们将在后面看到。仅依赖 L1 的安全性意味着 L1 节点应该能够在审查/失败的情况下从 Rollup 中收回资金。

从广义上讲,有两种主要方法可以解决 Rollup 安全性的第二部分。

  • 第一个是 Starkex 使用的,它专注于在失败的情况下不信任地退出汇总。
  • 第二种解决方案是确保 rollup 的共识以去中心化、抗审查的方式运行,为 L1 节点提供足够的数据可用性,以便在失败的情况下继续共识机制。这就是 Starknet 的目标。

到目前为止,我们一直在讨论 L2 之间的桥接。但我们也可以做 L3、L4 等。这使得计算的执行成本更低,但增加了安全问题,因为迭代 Rollup 意味着我们必须信任的多个顺序退出或多个共识机制。在考虑安全性时,我们也会考虑这些层的安全性。

随着迭代 Rollup,安全性在 L2 上变得越来越重要,就像 L2 节点开始审查事务或停止更新 L2 状态一样,这会破坏所有 L3、L4 Rollup 的网络。

无需信任的退出

第一个解决方案是提供类似于 Starkex 的 Rollup 退出。这意味着我们可以通过在 L1 上进行事务来退出 L2,然后 L2 将不得不处理该事务或冻结。这是强制交易。这仍然不完美,因为 L2 可能会冻结,在这种情况下我们的资金就会丢失。不过这可以解决。我们可以首先在 L1 上证明我们在 L2 中有一些资金。然后 L1 上的 ZKP 验证者智能合约应该允许我们从 L2 退出,而无需更新 L2 状态。

正在退出 Rollup 的 Rollup

这种退出策略甚至可以用于智能合约。这意味着在 L1 上证明包含所有数据的智能合约是 L2 的一部分,然后在 L1 上重新部署它的数据。

使用这种方法,我们甚至可以不用任何东西退出 L2,而是使用 L3 的 ZKP 验证者智能合约。这意味着在 L1 上重新部署 L3,使其成为 L2。这意味着子 Rollup 可以退出父 Rollup。

图 9. 准备退出

图 10. 正在退出

图 11. 退出后更新

数据挑战

但是也存在一些技术问题。为了构建退出证明,必须在 L1 上发布一些数据,以便我们的证明可以得到验证。例如,智能合约的哈希可能会在 L1 上与 L2 的 ZKP 一起发布。然后用智能合约很容易退出 L2,我们只需要知道我们智能合约的所有数据来组成证明。不幸的是,这是站不住脚的,将每个智能合约的数据放到 L1 上会是太多的数据。

在另一端,我们可以将尽可能少的数据量放在 L1 上,即 L2 的状态哈希。然后,如果我们拥有 L2 的所有数据,我们还可以通过 Merkle 树组成一个证明,证明我们的智能合约实际上是 L2 的状态哈希的一部分。为此,我们需要知道 L2 的状态,以便我们可以证明我们的智能合约是其中的一部分。

所以这里我们有三个选择:要么 Rollup 只是部分无信任(冻结更新),我们需要以不可扩展的方式在链上推送数据,或者我们需要以其他方式解决数据可用性(DA)问题。解决 DA 问题有一个更便宜的版本,我们将在下一节讨论 L2 安全性的其他解决方案时看到,使 L2 共识机制与 L1 上的 DA 一起工作。

通过 L2 共识机制实现安全性

Starknet 目前的目标是去中心化 Rollup 的操作员角色(=sequencer 和 prover)。这将使抗审查成为可能。除此之外,当一个新的 ZKP 被推送到 L1 时,L2 的状态差异也会作为调用数据推送到 L1。这解决了 L2 的数据可用性(DA)问题,因为 L1 节点可以查询 L1 上的事件以了解状态差异。如果所有 L2 节点都失败了,那么我们可以根据 L1 上过去的事件重建 L2 状态。这允许 L2 共识系统是无需许可的。这也相对便宜,因为 L1 上的 calldata 很便宜。

但是,此解决方案无法扩展到迭代 Rollup,我们将再次遇到数据可用性(DA)问题。如果我们在 L2 上运行 L3,并且 L2 和 L3 运营者同时失败,则 L3 状态差异也必须推送到 L1(在这种情况下,解决方案无法扩展,因为我们必须推送越来越多的数据到 L1,因为添加了越来越多的层),或者如果它们只被推送到 L2,那么它们会随着 L2 事件的丢失而丢失,我们只保存 L1 上的状态。

这意味着我们在尝试为多个 Rollup 确保这种共识机制时会遇到数据可用性问题。与之前的解决方案的相似之处很明显,我们要么必须将 L3 的数据作为 calldata 推送到 L1,要么我们必须找到其他方法使数据可用于子 Rollup 节点。这真正意味着,在无需许可的共识机制下,Rollup 安全问题实际上是数据可用性(DA)问题。

正如我们所看到的,无论是推送到 L1 存储还是推送到 L1 calldata 都不是一个适合迭代 Rollup 的解决方案。对于迭代 Rollup,我们需要直接解决子 Rollup 的 DA 问题,而不依赖于 L1。

迭代安全的挑战

正如我们所见,解决安全问题有两种选择,将数据推送到 L1,或将数据提供给子节点。Starknet 的目标是融合这两种解决方案,将数据作为 calldata 推送到 L1。这是数据可用性解决方案,因为这个 calldata 不能在 L1 上使用以确保安全,但由于 L1 安全性,数据可供所有人使用。然而,它继承了“上推数据”解决方案的一个坏特性,即它不能很好地扩展迭代 Rollup。但如果您只想依赖 L1 的安全性,这是必要的。

在这里我们可以做一个权衡:我们不需要 L2 纯粹依赖 L1 的安全性。不完全依赖 L1 的安全性意味着 L1 节点与 L2 的关系不会是不信任的,如果发生故障,它们将无法访问 L2 状态。相反,我们将依靠另一种共识机制来解决 DA 问题。这将意味着 L2 新共识机制中的额外信任假设,但如果我们能够解决迭代 Rollup 的安全性,那么这是值得的。我们可以在此共识中包含的节点必须包括 L2 节点和后代 Rollup,即 L3、L4 节点。保证他们的数据可用性的最佳方式是什么?

挑战

解决 L2 节点的 L2 DA 问题很容易,毕竟它们是 L2 节点,所以一个 PoS 共识机制就足够了。子节点更难。让我们勾勒出这些问题。

  • 后代节点需要接收 L2 状态的 DA,即使它们对 L2 状态上的每个智能合约都不感兴趣。
  • L2 节点也应该能够在没有子节点权限的情况下更新 L2 状态。
  • 如果 L2 节点更新,但不将新数据发送给后代节点,则后代节点仍需要根据它们进行 DA 的状态退出。
  • 这意味着如果后代节点存在 DA 问题并且子节点想要使用先前的 L2 状态哈希退出,则旧 L2 状态的一些证据应该保留在 L1 上。
  • 但是,我们不想将所有先前的 L2 状态哈希存储在 L1 上,因为这会导致状态膨胀。
  • 后代节点不应该能够使用任意旧的 L2 状态退出 L2,因为退出意味着反转退出 Rollup 的潜在更新。

如果后代节点对 L1 上的旧 L2 状态哈希具有一定的决策权,我们就可以解决所有这些问题。如果他们中的大多数人有状态哈希的 DA,他们需要能够向 L1 发出信号。我们只保留最后一个状态哈希,其中大多数 DA,旧的应该被擦除,以节省 L1 上的空间。但是删除旧哈希的另一个更重要的原因是后代 Rollup 需要有一个最终性时间,当它们不能再使用非常旧的哈希退出 L2 时,从而将它们的状态恢复到该哈希中的状态。这也意味着,子 Rollup 状态不是在到达 L1 时才被认为已完成,而是当大多数后代节点以可证明的方式为其提供 DA 时。

后代节点有时需要获取 DA,他们可以在提交更新之前执行此操作。子节点的出口只有在紧急情况下才会在尝试更新获取 DA,但发现没有提供时才起作用。然后他们可以使用 L1 上的旧状态退出。他们可能没有 DA 用于 L1 上的旧哈希,因为大多数后代节点可能自我们上次特定 Rollup 以来已经更新。这不是问题,就好像我们在 Rollup 节点中有一个诚实的多数,那么至少一个诚实的 Rollup 确实具有与当前旧哈希关联的数据(并将共享该数据)。

机制

我们可以根据这些原则创建共识机制。共识机制作为 L2 节点的正常 PoS 工作。当子 rollup 想要更新其 ZKP 时,它需要请求 L2 状态。如果他们收到它,那么他们就有 DA,他们将其存储起来,以防需要退出 L2。收到后,他们可以推送 ZKP 更新。这意味着我们可以将 ZKP 更新和 DA 绑定在一起,子节点只有在拥有 DA 时才会更新其 ZKP。这种方法允许我们“测量”后代节点的 DA,并且只考虑在 L1 上接受 L2 哈希,如果有足够的后代节点已经更新到它。这意味着 L1 上必须有多个 L2 哈希,最旧的哈希是大多数后代节点接受的最后一个哈希。

这种测量是如何发生的?与 L1 类似,在每次 Rollup 中,我们必须为每个子 ZKP 验证者合约存储子 Rollup 状态的不同哈希值,有些较旧,有些较新。这些哈希中的每一个都代表一个时间点。(为了同步时间,我们将使用 L1 的块号。)对于每个这样的哈希,(表示时间和子 Rollup 上的相应状态),我们将有一个数字对 (a, b),其中“a”告诉我们如何从那时起,许多后代节点都推送了更新,“b”为我们提供了后代节点的总数。这里“a”随着每个子 ZKP 更新而变化,而“b”通常是恒定的。我们将根据子 Rollup 对计算 Rollup 对。对于 Rollup,每个状态对应一个时间(=L1 区块编号),类似于子 Rollup。推送更新时,相应的状态哈希将具有接受率 (0, D+1)(其中 D 是后代的总数),因为没有子节点稍后推送状态,并且 Rollup 之后也没有更新那个哈希(你在推送下一个更新后得到一个状态的 DA,所以初始数字是 0)。之后,每次 ZKP 更新都会更改该哈希的接受率(并且还会添加新的哈希)。当子 Rollup 有对 (a_1, b_1), (a_2, b_2), (a_3, b_3) 时,我们计算新的接受率:(a_1+ a_2 +a_3+1, b_1 +b_2 +b_3+1=D+1 ) 比我们的哈希值晚。当这个接受率达到 50% 时,我们不必为 rollup 本身存储退出的早期哈希值。

图 12. 衡量后代接受度

(注意:在上述计算中,所有 rollup 的权重相同。这意味着在部署 rollup 时,必须授予权限。否则可能会通过创建任意数量的 rollup 来进行 sybil 攻击。为简单起见,此权限可以通过 staking 机制。其他不需要许可的加权解决方案是可能的,但那些需要不同的信任要求,即对树中较高的节点的更多信任。)

当 L2 节点停止与其后代(假设 L3 节点)共享数据时会发生什么,假设大多数 L3 节点是诚实的?L3 节点可以访问一些先前的 L2 状态,并且该状态具有仍在 L1 上的哈希。L3 节点可以使用此哈希退出 L2,并将其 Rollup 移动到分形树中的其他位置。

使用这种退出机制,我们将不会在 L1 上建立数据。需要存储在 L1 上的数据是 L2 的旧哈希。如果我们假设 Rollup 以恒定的速度更新(例如 1 区块/15 秒),那么大多数汇总确认更新所需的时间为○(d)○(log (N)),(其中 N 为总 Rollup 数,d 是平均深度)。所以存储在 L1 上的哈希数也将与此成正比。我们实际上将建立大量数据的地方是底部,每个节点都必须记录其每个祖先 Rollup 的数据,这意味着深度 d 处的○(d) 的数据(退出需要此数据)。

流动性共识

可以有另一种退出 L2 Rollup 的方法。毕竟,如果 L2 节点是恶意的,那么它们会破坏所有 L3、L4……Rollup 的树。这意味着所有 Rollup 节点中的少数(L2 节点)破坏了所有后代节点的 L2。更糟糕的是,所有后代 Rollup 都必须单独退出!如果大多数后代节点可以简单地用新节点替换 L2 节点,这将容易得多。(这意味着更改一些指定谁可以将更新推送到 L1 的公钥。)对于 L2 Rollup,这仅意味着 L2 节点将不得不退出其在 L1 上的状态,而不是所有后代节点。

图 13. 多替换 L2 比退出更高效,但简单的方法行不通

在这种情况下,如果 L3 节点在更新之前没有收到 L2 节点的数据,则需要告知其他 L3 rollup。这些 Rollup 节点验证 DA 是否受到威胁。大多数 L3 节点需要能够对 L2 的 ZKP 进行“紧急控制”。为了防止任何人采取“紧急控制”,我们可以将每个 L3 节点的公钥存储在 L1 上。这在迭代时无法扩展,我们还必须存储 L4、L5 密钥。为了以可扩展的方式解决这个问题,我们可以使用限制因素,即任何人都不能更新 L3 ZKP,只有 L3 节点(或其后代,如果他们采取紧急控制)。所以这里的 L3 ZKP 验证者智能合约不仅仅是任何智能合约,而是在 L2 的共识机制中处于特殊的位置。

因此,当 L3 节点意识到 L2 节点没有为 L1 上的最新 L2 状态提供 DA 后,它们会采用它们拥有 DA 并位于 L1 上的旧 L2 状态。他们每个人都可以将一个新的 ZKP 推送到这个 L2 状态,从而“选举”新的 L2 节点(更改公钥)。然后,新的 L2 节点(刚才选为)然后可以接收旧的 L2 状态和新的 ZKP,然后将其提示,并将新的 L2 ZKP 推向 L1。(这里 L1 上的 L2 哈希是“分叉的”,因为由先前节点推送到 L1 的 L2 状态(我们没有 DA 的状态)也在 L1 上。但是,这个 L2 状态不被接受大多数后代节点,所以这实际上不是分叉(一旦大多数后代节点接受了更新,更新就完成了。))

对于旧的 L2 节点的安全性也有保证,在紧急控制发生后,它们仍然具有 L2 Rollup 的状态。所以他们可以在 L1 上退出。

图 14. 成功替换 L2,绕过恶意父节点

(注意:这里有一个潜在的受害者,如果每个 L2 节点和大多数 L3 Rollup 都是恶意的,那么子节点可能无法访问 L2 状态,并且也可能被排除在新的紧急更新之外。在这种情况下,他们的数据丢失了,他们无法在 L1 上回收它,因为他们无法访问 L2 数据。如果我们不能信任大多数 Rollup,这只是一个关键因素。)

这种方法可以用于迭代 Rollup 吗?是的,可以,我们可以对 L4 节点使用相同的原理。当 L3 和 L2 节点都是恶意的,而 L4 节点没有恶意时,L4 节点可以先控制更新旧 L3 状态的旧 L4 的 ZKP,然后再控制更新旧 L2 状态的 L3 的 ZKP。可以控制和更新 L1 上的 L2 的 ZKP,它仍然具有旧的 L2 状态哈希。因此,通过这种方法,我们可以将安全退出策略转变为一个共识系统,该系统依赖于大多数 Rollup 的诚实。

这是第一个提议的逻辑结果,毕竟我们可以将测量视为接受状态更新的 Stakers(后代节点)。状态更新由单个提议者(L2)提出。如果提议者行为不端,则会选择一个新的提议者。

更换 L1

免责声明:这部分还有待进一步研究。大致轮廓清晰,快速停止分叉的精确模拟仍然需要仔细分析。

到目前为止,我们有一个带有传统(PoW/PoS)共识系统的底层 L2。这很好,与这个系统兼容,我们有可能在分形树中的不同 Rollup 之间进行并行事务,这些事务由它们的共同共识机制有效地保护。但是,我们这里有两个独立的共识机制,rollup 共识和 L2 的 PoS。其实我们可以在每一层去掉 PoS 共识机制,毕竟 rollup 共识机制已经保证了 DA,验证者合约验证有效性,L1 上 PoS 停止分叉。这意味着单个节点可以运行单个层,并由所有后代节点验证。

一个更雄心勃勃的目标是用 rollup 共识机制取代 L1 PoS 共识机制。这将使单个节点能够运行 L1,类似于每个 Rollup。为此我们需要问,L1 PoS 目前提供了哪些 Rollup 共识没有提供的内容?答案是分叉,每次 Rollup 都会检查有效性,但是我们使用 L1 来停止 L2 的分叉,因此也间接地停止了更深的层。

要将 PoS 替换为 rollup 共识,我们需要确保 L1 节点不能自行对 L1 进行分叉(如果大多数后代 rollup 也是恶意的,则分叉无法避免)。我们想要的是,如果我们可以让这个 rollup 共识机制更强大,那么后代 rollup 就可以在 L1 级别停止分叉。我们已经有一种方法来衡量后代 rollup 是否接受父 rollup 状态,即它们向其推送 ZKP,并且在每个 rollup 上,我们可以测量后代 rollup 接受该状态的百分比。然而,在讨论分叉时,这还不够,因为同一个 ZKP 可以发布到多个分叉。然而,我们可以阻止这种情况,因为 ZKP 还可以包括 L1 状态哈希的选择。当一个 rollup 从它的子节点接收 ZKP 时,每个子节点也会给它一个 L1 状态哈希,它接受它作为历史的有效选择。如果这些状态哈希是一致的(意味着它们在 L1 状态中彼此跟随),那么 Rollup 可以证明这一点,并及时选择最新的。然后他们可以包含这个最新的哈希(或者甚至可能选择一个后来的哈希),并将它包含在他们自己的 ZKP 中并将其传递给他们的父级。当 L1 收到不同的 ZKP 和包含的 L1 哈希时,它将无法将 ZKP 包含到两个分叉中,因为包含的哈希恰好选择了它可以添加到的一个分叉。此时 L1 将无法产生新的有效区块,因此就好像节点停止工作一样。

图 15. 分叉

使用传统的 L1,它隐含地保证总是有新的区块,但情况并非如此。幸运的是,我们在 rollup 共识中已经有了一个方法,如果一个 rollup 节点停止更新,后代节点可以继续更新系统,他们采取紧急控制,为父 rollup 选择一个新节点(记住每个 rollup 可以由一个单独的节点),新的父节点可以发布新的 ZKP。我们在这里也可以这样做,每个节点可以运行一个虚拟 L0 节点,仅查看 L1 节点是否推送有效更新(这些更新也必须被足够多的后代节点接受,如上一段所述)。如果 L1 节点不推送更新,则认为 L1 节点有故障/恶意,并且必须由 L2 节点选举一个新节点(旧的 L1 节点也可以质押一些代币,这些代币可能会被罚没). 如果 L2 节点没有选举 L1 节点,它们也被认为是故障/恶意的,它们也需要重新选举。

因此,分叉选择、检查更新和选举的方法一起使 L1 能够由受通用 Rollup 共识机制保护的单个节点运行,这样如果 L1 节点尝试分叉,L1 状态将停止更新,如果 L1 状态停止更新,子节点可以选举新的 L1 节点,同时惩罚旧的节点。

这样一来,L1-L2 的传统安全模型就可以逆转了。不再是许多 L1 节点存储数据并为 Rollup 创建安全性(例如在 Danksharding 中,Rollup 数据发布到 L1),而是许多不同的 Rollup 节点在树中存储和保护其祖先数据,因此为 L1 创建安全性。

速度、效率和数量

快速总结目前的结果,我们有一个分形扩展解决方案,每个 rollup 运行在单个节点上,rollup 之间直接无信任地桥接,所有 rollup 都使用通用共识机制保护,L1 也包含在这个共识机制中这样可以避免分叉。

使用这种机制的每个节点最重要的约束是什么?我们有两个,第一个是确认时间,即更新被包含到 L1 状态以及大多数节点确认该交易的时间(这意味着推送他们自己的 ZKP)。另一个约束是存储的数据量,至于每个 rollup 的安全性,它们必须存储每个父 rollup 的数据。我们如何提高效率、减少确认时间并最大限度地减少存储的数据?

到目前为止,我们还没有讨论树的形状。对于给定数量的 N 个 rollup,有多种方法可以将它们分布到树中,但从广义上讲,有两个大的选择,我们可以有一个宽的和浅的树,每个 rollup 都有大量的子节点,但是树的深度很小,或者我们可以有一个又深又窄的树,每个 rollup 都托管少量的其他 rollup。

在当前的实现中,我们有宽和浅的选项,因为我们有一个相对较大的 L1 和较大的 L2,因为 L1 保证了安全性,所以迭代 Rollup 不太安全,并且没有办法在不同 Rollup 之间直接桥接资金,所以靠近 L1(大部分活动发生的地方)是有道理的。

在这个新环境中,这些问题无关紧要,我们有一个共同的共识机制和直接桥接,因此树中的位置不太相关。这使我们能够考虑树的深而窄的形状。这是加快节点确认时间并最小化存储数据的有效方法。(检查快速估算的实际数字。)

使父状态更新更快的另一种方法是通过将其“自己的”状态(VM 的不是子节点的 ZKP 的部分)清空到单独的 ZKP 和 VM 中来最小化每个 Rollup。在图片中,我们用圆圈显示了这些 VM,而仅托管 ZKP-s 的实际 Rollup 的 VM 是矩形。这使得更新更快,因为不需要证明整个状态,只需要证明它的 ZKP。这也最小化了存储的数据,因为只需要存储 ZKP,而不是状态本身。这已经是我们描述树的方式了,每组 VM 中有 4 个 ZKP-s,3 个对应于子 VM,1 个对应于状态。

图 16. 新布局

一旦树被缩小并且树中较高节点的状态大小被最小化,较低的节点就有可能存储它们的祖先群 VM。这意味着为树中的 n 个节点存储 4 PSlog (n)=4 PSd 数据,树的深度为 d,PS 是平均证明大小。确认时间也是 4 Cd,其中 C 是证明单个 ZKP 验证的时间。

概括

在 ZK Rollup 的分形扩展中,需要在不同 Rollup 之间进行桥接。我们首先概述了当前的解决方案是什么,以及它们的缺点。然后我们描述了我们的桥接解决方案,它的好处是:价格稳定,可用于传输任何类型的数据。然后我们推广这种桥接,给发送者 rollup 保证交易被接收。这种保证使智能合约能够完成桥接过程,而不仅仅是能够启动它。这意味着桥接可以处理 rollup 之间的函数调用。这使得不同的层托管分片虚拟机的不同分片,这从根本上依赖于 L1 的安全性。然后我们查看分形扩展的安全要求,我们发现当前的解决方案无法扩展。然后我们提出了我们自己的 rollup 共识机制来解决安全问题。然后我们扩展它,这样单层的失败并不意味着每个后代节点都必须退出。然后我们将这种共识机制扩展到 L1,这样就不可能进行分叉。最后我们看看树结构和使机制更高效的方法。

快速估算

  1. 如果具有 N 个节点的树的宽度为 w>3(每个节点有 w 个子节点),深度为 d=log_w (N),那么如果我们将这棵树重构为 w'=3 宽,保持节点数 N'=N,则新的深度变为 d'=log_3 (N)=log_w (N) log_3 (w)=dlog_3 (w)。如果证明时间与子节点的数量成线性关系,那么每个父节点处理更新需要 (C * w * d) 时间(其中 C 是某个常数),如果树很窄,情况会更糟,因为然后这变成 (C * 3 * log_3 (w)* d)(我们假设 C 是相同的常数)。因此,使树变窄是有意义的。
  2. 此外,由于我们可以在这棵树中进行不涉及 L1 的交易,并且 DA 问题在本地解决,我们可以让“区块大小”(我们近似为给定时期内的新交易总数)线性增长与节点的数量,(与节点数量的根线性相比,就像在 Celestia 中一样)。我们有这种线性,因为多个事务可以在不同节点之间并行发生。这意味着并行事务可以在不同的硬件上执行。(Starknet 中也存在并行化交易的尝试,但它只是虚拟分离,因为所有交易都将由同一个证明者证明)。
  3. 然而,与单层区块链相比,有一个缺点,tx 的最终确定不是即时的。确认一笔交易需要 4*C*d 时间,其中 C 是证明一个 ZKP 验证所需的时间。由于发送方节点无法将多个事务并行发送到其他 Rollup,因此这个时间很重要。
  4. 前面的几点共同给出了我们的交易吞吐量,即交易数量/最终确定时间。这是○(N/log (N))。

常见问题解答:这如何阻止节点 3 上的双重支出?内部 VM 逻辑和 ZKP 更新阻止了双花。您只能通过获取先前的 VM 状态和 ZKP 证明来更新父节点中的 ZKP,验证此 ZKP 证明了先前的状态,并将有效的 VM tx 应用于 VM 状态,从而产生结果 VM。现在我们可以进行整个计算,对其进行 ZKP,并更新之前的 ZKP。此方法停止双重花费,因为在父节点上只接受一个有效的状态转换。

热门文章

发表回复

您的电子邮箱地址不会被公开。