Booster Rollups:zkEVM 作为 ZK 协处理器,打开可扩展性大门

Boosterrollup是一种通用的协处理器,可以扩展L1上的交易执行和存储,保留L1上的所有状态,可以用作完全独立的EVM环境、ZK协处理器或介于两者之间的任何设备。它可以用于父层的所有智能合约,也可以用于多个L2之间共享的新层,以共享数据。

摘要由 Mars AI 生成

本摘要由 Mars AI 模型生成,其生成内容的准确性、完整性还处于迭代更新阶段。

上一篇文章讲述了我们如何利用Booster rollup以通用、合理的方式扩展存储和交易执行。在本篇文章中,我们将介绍另一种可能的用例,其中rollup 仅用于帮助扩展交易,同时将所有状态保留在 L1 上。这实际上使它成为了一个协处理器,几乎没有硬性的可扩展性限制。

但首先要回顾一下,因为有些定义已经改变:

定义

Booster rollup是执行交易的rollup,就像在 L1 上执行交易一样,可以访问所有 L1 状态,但它们也有自己的存储空间。这样,执行和存储都在 L2 上进行扩展,而 L1 环境则作为共享基础。换句话说,每个 L2 都是 L1 的反映,L2 通过对交易执行和存储进行分片,直接扩展了 L1 上部署的所有应用程序的区块空间。

Booster rollup可通过多种方式扩展链。单个Booster rollup实例可同时用作完全独立的 EVM 环境、ZK 协处理器或介于两者之间的任何设备。

新的预编译

L1CALL:允许读写 L1 状态。

L1SANDBOXCALL:允许读写 L1 状态,但在调用结束时,L1 状态的变化会被还原。

L1DELEGATECALL:执行存储在 L1 上的智能合约,但所有存储读写都使用 L2 状态。

这些定义使用L1,但实际上它只是指父链的状态。

作为 ZK 协处理器的 Booster rollups

Booster rollup 允许使用 ZK-EVM 将所有 L1 智能合约工作转移到 L2,同时保留 L1 上的所有状态。L1 上所需的唯一工作就是验证 ZK 证明,并将最终状态更新应用回 L1 智能合约。这样,就可以将Booster rollup 作为 ZK 协处理器,用于父层的所有智能合约,当然也可以用于一个或多个特定的智能合约。例如,可以为整个 L1 层设置一个Booster rollup,同时在 L2 层的每个应用程序上设置额外的Booster rollup作为 ZK 协处理器。当然,一般来说,可以一起批量处理的事情越多,效率就越高。

这当然与其他ZK协处理器(如zkUniswap 2和Axiom)非常相似,只是在这些情况下,一些特定的功能是在链下处理的。在Booster rollup中,无论在何处执行交易,都会维护相同的L1环境。这意味着在证明方面有额外的开销,因为逻辑不是以最有效的方式编写的,但是根据用例,拥有一个单一的通用解决方案,可以用最少的工作被所有智能合约使用,这似乎是一个有趣的权衡。当然,仍然有理由尽可能优化某些任务,因此它们是互补的。

另一个有趣的用例是,不将此方法用于L1,而是用于在多个L2之间共享的新层,就像我们将L1状态用于共享数据一样。这更灵活一些,因为我们可以对该共享层有更多的控制。因此,我们可以做一些事情,比如自动让所有智能合约具有applyStateUpdates功能,有一种方法将最新的共享层状态根暴露给EVM,并允许在必要时恢复共享层(允许状态更新更乐观地应用于稍后的zk证明)。

实现

我们通过(重新)在L2上引入L1CALL预编译来实现这一点。L1CALL针对L1状态执行交易,并且像在L1上一样应用存储写操作,就像L1SANDBOXCALL一样。与L1SANDBOXCALL不同的是,当调用结束时,所有存储写入都会被丢弃,我们在所有L1调用中跟踪结果L1状态,同时在列表中记录这些调用期间发生的所有L1存储更新。如果是第一次更新智能合约的存储槽,则将(contract, storage_slot) = value添加到此列表中。如果(contract, storage_slot)已经在列表中,则简单地用新值更新该值。随后,Booster rollup智能合约使用包含所有L1状态更改的列表,将这些更改应用到L1智能合约,L1智能合约被L2交易修改:

可扩展性

想要支持这类协处理器模式的智能合约需要在其L1智能合约中实现此功能。

这种方法在智能合约中的效率非常高,只有有限数量的存储槽会被大量的L2交易更新(比如投票智能合约),或者某些操作需要大量昂贵的逻辑才能在L1上直接完成。大多数情况下,需要在链上提供的数据量也仅限于状态变化列表。

局限性

有一些限制是我们无法解决的(至少在L1上),因为一些状态变化不容易被模拟。

nonce只能通过从一个帐户进行交易来更改,因此我们不能在L1上将它们设置为特定的值。

ETH直接绑定在L1上的账户,无法通过SSTORE进行更改。这意味着所有通过L1CALL的交易,msg.value都需要为0。

使用CREATE/CREATE2的契约部署也不可能只使用SSTORE。但是,当我们将它们作为特殊情况处理时,在技术上可以支持它们。

重放保护

L2交易的重放保护是一个有趣的问题。L2交易可以直接针对L1状态执行交易,但不可能在不执行L1交易的情况下更新L1上的EOA帐户的nonce(重放保护对于实现applyStateUpdates函数的智能钱包很有效)。这意味着L2交易确实需要使用使用L2存储的帐户的nonce,这是防止ZK-EVM协处理器完全无状态工作的唯一原因(当然不包括L1状态)。可以通过要求用户执行L1交易来创建L2交易来解决该问题,但这会使交易变得更加昂贵,并极大地限制了可能的可扩展性改进。

费用支付

交易费用的支付可以在L2上完成,这将是最通用和最有效的方式。如果可能的话,也可以通过在智能合约中向用户收取费用来实现(例如,AMM的交换费用)。当然,如果需要额外的L1状态改变,可能会降低效率。

DA要求

L1状态增量是唯一需要推送到链上的数据。然而,为能够创建L2区块/交易,需要知道L2上的帐户的名称,但系统的安全性并不依赖于它(因为所有状态仍然在L1上)。

如果在L2上处理费用支付,则该数据也需要在链上可用,但如果L2余额仅用于支付费用,则余额将很低,因此风险也很低。

同步

Booster rollup的输入是前一个 L1 区块的 L1 区块哈希。该区块哈希包含L1状态根在前一个L1块之后。这是EVM中当前可用的最新状态根。这意味着ZK-EVM协处理器需要作为触及L1区块中相关L1状态的第一个交易运行,否则我们执行交易的状态就过时了。这可以很容易地避免,但是如果由于某种原因需要将L1和L2交易组合在一起,则会限制灵活性。如果有办法将当前的 L1 状态根暴露给 EVM,这种不灵活性就可以得到解决。

混合和匹配L1和协处理器区块也需要立即应用状态更改,否则L1交易将针对过时的状态执行。这使我们无法乐观地应用 L2 的状态更改,因此我们急需 ZKP。这可以通过使用一个中间共享层来解决,而不是直接在L1上工作,这样当区块数据无效时,就可以回滚。如果没有L1交易修改与L2交易相同的状态,则状态增量可以延迟应用于L1。

Chaining rollups

在每个L2区块之后更新的L1状态根被公开为公共输入。这允许多个L2在最新的L1状态上一起工作,因为这是由早期的L2区块更新的。通过将工作拆分到多个rollup(当然执行仍然是顺序的),这有助于扩展在多个L2上不易并行化的工作。例如,可以在rollup A上执行AMM交易,这些交易都会更新池的状态,然后让rollup B根据rollup A之后的状态继续执行,最后将最新的AMM状态应用回L1智能合约。这使得它成为跨 L2 共享序列数据的一种便捷方式。

转载声明:本文 由CoinON抓取收录,观点仅代表作者本人,不代表CoinON资讯立场,CoinON不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。若以此作为投资依据,请自行承担全部责任。

声明:图文来源于网络,如有侵权请联系删除

风险提示:投资有风险,入市需谨慎。本资讯不作为投资理财建议。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 2023年11月8日 上午7:08
下一篇 2023年11月8日 下午1:08

相关推荐

Booster Rollups:zkEVM 作为 ZK 协处理器,打开可扩展性大门

星期三 2023-11-08 13:08:27

上一篇文章讲述了我们如何利用Booster rollup以通用、合理的方式扩展存储和交易执行。在本篇文章中,我们将介绍另一种可能的用例,其中rollup 仅用于帮助扩展交易,同时将所有状态保留在 L1 上。这实际上使它成为了一个协处理器,几乎没有硬性的可扩展性限制。

但首先要回顾一下,因为有些定义已经改变:

定义

Booster rollup是执行交易的rollup,就像在 L1 上执行交易一样,可以访问所有 L1 状态,但它们也有自己的存储空间。这样,执行和存储都在 L2 上进行扩展,而 L1 环境则作为共享基础。换句话说,每个 L2 都是 L1 的反映,L2 通过对交易执行和存储进行分片,直接扩展了 L1 上部署的所有应用程序的区块空间。

Booster rollup可通过多种方式扩展链。单个Booster rollup实例可同时用作完全独立的 EVM 环境、ZK 协处理器或介于两者之间的任何设备。

新的预编译

L1CALL:允许读写 L1 状态。

L1SANDBOXCALL:允许读写 L1 状态,但在调用结束时,L1 状态的变化会被还原。

L1DELEGATECALL:执行存储在 L1 上的智能合约,但所有存储读写都使用 L2 状态。

这些定义使用L1,但实际上它只是指父链的状态。

作为 ZK 协处理器的 Booster rollups

Booster rollup 允许使用 ZK-EVM 将所有 L1 智能合约工作转移到 L2,同时保留 L1 上的所有状态。L1 上所需的唯一工作就是验证 ZK 证明,并将最终状态更新应用回 L1 智能合约。这样,就可以将Booster rollup 作为 ZK 协处理器,用于父层的所有智能合约,当然也可以用于一个或多个特定的智能合约。例如,可以为整个 L1 层设置一个Booster rollup,同时在 L2 层的每个应用程序上设置额外的Booster rollup作为 ZK 协处理器。当然,一般来说,可以一起批量处理的事情越多,效率就越高。

这当然与其他ZK协处理器(如zkUniswap 2和Axiom)非常相似,只是在这些情况下,一些特定的功能是在链下处理的。在Booster rollup中,无论在何处执行交易,都会维护相同的L1环境。这意味着在证明方面有额外的开销,因为逻辑不是以最有效的方式编写的,但是根据用例,拥有一个单一的通用解决方案,可以用最少的工作被所有智能合约使用,这似乎是一个有趣的权衡。当然,仍然有理由尽可能优化某些任务,因此它们是互补的。

另一个有趣的用例是,不将此方法用于L1,而是用于在多个L2之间共享的新层,就像我们将L1状态用于共享数据一样。这更灵活一些,因为我们可以对该共享层有更多的控制。因此,我们可以做一些事情,比如自动让所有智能合约具有applyStateUpdates功能,有一种方法将最新的共享层状态根暴露给EVM,并允许在必要时恢复共享层(允许状态更新更乐观地应用于稍后的zk证明)。

实现

我们通过(重新)在L2上引入L1CALL预编译来实现这一点。L1CALL针对L1状态执行交易,并且像在L1上一样应用存储写操作,就像L1SANDBOXCALL一样。与L1SANDBOXCALL不同的是,当调用结束时,所有存储写入都会被丢弃,我们在所有L1调用中跟踪结果L1状态,同时在列表中记录这些调用期间发生的所有L1存储更新。如果是第一次更新智能合约的存储槽,则将(contract, storage_slot) = value添加到此列表中。如果(contract, storage_slot)已经在列表中,则简单地用新值更新该值。随后,Booster rollup智能合约使用包含所有L1状态更改的列表,将这些更改应用到L1智能合约,L1智能合约被L2交易修改:

可扩展性

想要支持这类协处理器模式的智能合约需要在其L1智能合约中实现此功能。

这种方法在智能合约中的效率非常高,只有有限数量的存储槽会被大量的L2交易更新(比如投票智能合约),或者某些操作需要大量昂贵的逻辑才能在L1上直接完成。大多数情况下,需要在链上提供的数据量也仅限于状态变化列表。

局限性

有一些限制是我们无法解决的(至少在L1上),因为一些状态变化不容易被模拟。

nonce只能通过从一个帐户进行交易来更改,因此我们不能在L1上将它们设置为特定的值。

ETH直接绑定在L1上的账户,无法通过SSTORE进行更改。这意味着所有通过L1CALL的交易,msg.value都需要为0。

使用CREATE/CREATE2的契约部署也不可能只使用SSTORE。但是,当我们将它们作为特殊情况处理时,在技术上可以支持它们。

重放保护

L2交易的重放保护是一个有趣的问题。L2交易可以直接针对L1状态执行交易,但不可能在不执行L1交易的情况下更新L1上的EOA帐户的nonce(重放保护对于实现applyStateUpdates函数的智能钱包很有效)。这意味着L2交易确实需要使用使用L2存储的帐户的nonce,这是防止ZK-EVM协处理器完全无状态工作的唯一原因(当然不包括L1状态)。可以通过要求用户执行L1交易来创建L2交易来解决该问题,但这会使交易变得更加昂贵,并极大地限制了可能的可扩展性改进。

费用支付

交易费用的支付可以在L2上完成,这将是最通用和最有效的方式。如果可能的话,也可以通过在智能合约中向用户收取费用来实现(例如,AMM的交换费用)。当然,如果需要额外的L1状态改变,可能会降低效率。

DA要求

L1状态增量是唯一需要推送到链上的数据。然而,为能够创建L2区块/交易,需要知道L2上的帐户的名称,但系统的安全性并不依赖于它(因为所有状态仍然在L1上)。

如果在L2上处理费用支付,则该数据也需要在链上可用,但如果L2余额仅用于支付费用,则余额将很低,因此风险也很低。

同步

Booster rollup的输入是前一个 L1 区块的 L1 区块哈希。该区块哈希包含L1状态根在前一个L1块之后。这是EVM中当前可用的最新状态根。这意味着ZK-EVM协处理器需要作为触及L1区块中相关L1状态的第一个交易运行,否则我们执行交易的状态就过时了。这可以很容易地避免,但是如果由于某种原因需要将L1和L2交易组合在一起,则会限制灵活性。如果有办法将当前的 L1 状态根暴露给 EVM,这种不灵活性就可以得到解决。

混合和匹配L1和协处理器区块也需要立即应用状态更改,否则L1交易将针对过时的状态执行。这使我们无法乐观地应用 L2 的状态更改,因此我们急需 ZKP。这可以通过使用一个中间共享层来解决,而不是直接在L1上工作,这样当区块数据无效时,就可以回滚。如果没有L1交易修改与L2交易相同的状态,则状态增量可以延迟应用于L1。

Chaining rollups

在每个L2区块之后更新的L1状态根被公开为公共输入。这允许多个L2在最新的L1状态上一起工作,因为这是由早期的L2区块更新的。通过将工作拆分到多个rollup(当然执行仍然是顺序的),这有助于扩展在多个L2上不易并行化的工作。例如,可以在rollup A上执行AMM交易,这些交易都会更新池的状态,然后让rollup B根据rollup A之后的状态继续执行,最后将最新的AMM状态应用回L1智能合约。这使得它成为跨 L2 共享序列数据的一种便捷方式。