原文:Specular,由 DeFi 之道翻译编辑。
几周前,我们宣布了 Specular—一个具有新颖 EVM 本地设计的 Optimistic Rollup—并且很高兴看到我们的 Twitter 线程激发了关于如何最好地设计此类系统的兴奋和讨论。在这篇文章中,我们想澄清一下我们认为 EVM 原生方法相对于其他 Optimistic rollup 方法的一些关键优势,包括 Optimism 和 Arbitrum 正在进行的工作,通过在较低级别 VM 上定义的欺诈证明系统来追求 EVM 等效性。
在我们开始之前,这篇文章假设您对 optimistic rollup (ORU) 有基本的了解;以及现代以太坊 ORU 如何依赖负责裁决争议的链上交互式欺诈证明机制。可以在此处找到对相关先前工作的广泛调查。
背景
Optimism 和 Arbitrum 正在推出一种利用现有以太坊客户端基础设施的新架构,以便与现有的以太坊工具和 L2 智能合约(称为 EVM 等效性)完全兼容。由客户端执行导致的状态转换争议通过链上验证的交互式欺诈证明 (IFP) 解决。为了支持 IFP,客户端程序被编译为较低级别的目标 VM(例如 MIPS 或 WASM),可以在(MIPS/WASM)指令级别为其构建状态转换证明。然后将生成的二进制文件提交到链上,允许链上验证者以较低级别 VM 语义的粒度强制执行其执行。
至关重要的是,这种较低级别的 VM 方法完全不知道 EVM 的存在及其语义。因此,它不是按照意图强制执行 EVM 语义[1],而是强制执行较低级别的语义来执行据称实现了 EVM 的特定二进制文件。因此,这种设计技术 (1) 排除了多个以太坊客户端程序[2]的无许可和信任最小化参与;(2) 导致难以独立审计且无法正式验证的臃肿、过大的可信计算库(TCB);(3) 遭受频繁触发但不透明的升级过程的困扰,进一步增加了安全审计开销。
为了解决这些问题,我们主张采用我们认为更简单、更自然的 EVM 原生方法来处理 IFP。也就是说,我们建议在单个 EVM 指令级别显式地在链上执行 EVM 语义。下面我们将描述这种设计相对于较低级别的 VM 方法的一些优点。
客户端多元化
虽然以太坊网络由包括 Geth、Besu 和 Erigon 在内的不同客户端运行(然而目前采用率不足),但当前的 L2 解决方案还没有接近支持客户端多样性。这很重要,因为我们希望防止由软件错误/漏洞引起的无效 ORU 状态转换因为未检测到和无可争议而出差错。
Optimism 团队提出了一种潜在的解决方案,该解决方案通过为许多列入白名单的客户端程序中的每一个包括一个链上二进制承诺,将较低级别的 VM 方法扩展到多客户端设置。验证者必须准备好参与涉及其中任何一个的挑战阶段,只有在他们设法赢得所调用的挑战阶段的门槛时才能赢得整体争议。
这种方法只提供外在的客户多样性,而不是证明系统本身的内在。每个客户都有自己的独立证明系统与之关联。事实上,这只是一种通用的纵深防御技术,任何 Rollup 都可以在使用多数票组合不同证明系统的方案中使用(例如,甚至将 Optimistic Rollup 和 ZK-rollup 组合到一个多重证明系统中))。虽然它可能会提供一些客户端多样性的表象,但在单独使用时会引入多个问题:
1.客户端程序的参与是许可的。也就是说,客户端程序的编译二进制文件必须作为白名单程序提交到链上,才能被允许参与争议解决。
此外,由于二进制承诺随版本的变化而变化,Optimism 的治理过程也处于升级任何客户端程序(甚至只是其编译工具链)的关键路径上。理想情况下:客户端程序可以参与和升级,而无需经过 ORU 的治理。
2.有一个强大的信任假设,即大多数客户端程序正确地实现了 EVM。这可以解释为 K-of-N 版本 或 N-of-N 版本编程。
正如我们在下一节中指出的,这尤其成问题,因为客户端程序难以审计。理想情况下:只需一个客户端程序即可正确实现 EVM(即使用经典的 N 版本编程)。
3. 验证者别无选择,只能准备运行每个列入白名单的客户端程序来解决争议。
由于争议过程中的额外冗余,这不仅昂贵且缓慢,而且操作上也更加复杂,因为验证者必须学习如何配置和运行每个程序。操作复杂性随着客户数量的增加而增加,对可以包含多少客户端程序设置了实际限制。
总而言之,我们认为这种设计不能有效地分配信任——客户端程序包含是许可的,必须信任大多数人才能正确实现 EVM 语义,并且支持的数量实际上会受到信任、devops 和一般操作复杂性问题的限制。
我们的方法提供了内在的客户端多样性,因为链上验证者对客户端程序是不可知的。所有客户端都使用相同的证明系统进行交互。任何支持 EVM 语义的程序都可以无许可参与,并且只有一个程序必须实现正确的语义才能检测/争议故障。验证者还可以真正选择运行他们最熟悉的任何客户端程序,从而提供更简单的 devops。
因此,EVM 本地 ORU 为无需许可、信任最小化的客户端多样性提供支持。虽然这两种方法都可以检测恶意注入的状态转换(例如,由无效交易引起的),但只有 EVM 本地方法能够可靠地检测和解决错误/漏洞。
可审计性
ORU 的 TCB 必须是可审计的和/或可正式验证的,以确保其可信度。现有的 ORU 达不到这个目标。
客户端程序信任假设
在较低级别的 VM 方法中:因为链上验证者在目标 ISA 指令级别(而不是较高级别的 EVM 语义)强制执行客户端程序,因此仅检查验证者不足以确定等价性将强制语义与 EVM 的语义相比较。ORU VM 的强制语义由列入白名单的客户端二进制文件隐式确定。如果不审计整个客户端程序和编译器,就不可能先验地确定这些语义是否等同于 EVM 语义。而在外部客户端多样性的情况下,这个问题会进一步恶化,因为语义是由多数共识决定的(通过争议机制表现出来),需要对所有或至少大多数客户端程序和编译器进行审计。
因此,TCB 不仅包括验证者,还包括每个客户端程序,以及与每个程序关联的编译器工具链和二进制提交生成器。TCB 臃肿的规模和复杂性造成了明显的软件错误/漏洞风险,这些风险可能会影响 ORU 的安全性,并相应地增加审计开销。
我们强调,它不像捎带由上游客户端程序(即 Geth)的维护者进行的安全审计那么简单,因为该程序必须定制以支持一步证明生成(请参阅此处和此处的 Geth 分叉)。此外,由于链上验证者无法访问存储区块、交易和帐户/存储状态的以太坊数据库,因此他们必须插入原像预言机组件以允许 MIPS/WASM 代码查询数据库。
在 EVM 本地方法中,EVM 语义由链上验证者明确实施。由于无需许可和信任最小化的客户端多样性,ORU 的整体安全性不会在很大程度上依赖于任何单个客户端程序的正确性。因此,EVM 本地 ORU 的 TCB 仅包括链上验证者。这很好,因为 TCB 的有限范围允许它更容易审计,并且相对于正式的 EVM 规范完全可以正式验证,正如我们在下面谈到的那样。
验证者信任假设
EVM 本地和较低级别的 VM 方法都在 TCB 中包含一步形式验证者。虽然较低级别的 VM 验证者可能更易于实施和审计(由于指令集较小),但考虑到端到端实施和/或审计系统其余部分的难度——尤其是客户端和编译器。
此外,形式验证——尤其是 KEVM——使竞争环境更加公平。KEVM 是使用支持 Solidity 智能合约形式验证的 K-Framework 实现的 EVM 的可执行形式规范。因此,KEVM 是 Specular 的完美补充,因为它提供了正式的规范和一套验证工具,使我们能够正式验证我们的链上验证者。我们正在积极参与这一研究方向,目前正在与 KEVM 团队合作探索利用 KEVM 的各种方法。
另一方面,正式验证采用低级别 VM 方法的 ORU 的 TCB 是不可行的。虽然可以正式验证 MIPS 验证者,但这并不能保证 EVM 语义的执行。为了实现这样的保证,Geth 本身——连同它的编译工具链——必须经过形式验证;然而,鉴于这些程序的复杂、计算无界和并发的性质,这实际上是不可能的。
因此,EVM 本地 ORU 的 TCB 可以根据现有的、经过充分测试的正式规范进行形式验证,而较低级别的 VM 方法则不能。
编译器信任假设
在较低级别的 VM 方法中,引入了高度定制的编译工具链来支持一步证明生成。然而,这个工具链并不成熟。编译器和目标 ISA 都是定制的(参见此处和此处)。Nitro 为原像预言机和收件箱添加了几个自定义 WASM 操作码,而 Cannon 则添加了几个自定义 MIPS 系统调用。目标运行时模型也受到若干约定或约束的修改和约束。例如,Nitro 和 Cannon 都对内存进行了默克化处理,以实现简洁的一步证明,而不会泄露整个内存空间。Cannon 还要求将编译后的程序和输入/输出加载到内存的特定位置。此外,Nitro 和 Cannon 都将浮点指令替换为软浮点实现(参见此处和此处)。@pepyakin 写了一篇很棒的博客文章,它涉及到使用 WASM 作为目标 ISA 的其他复杂性。
这些定制中的任何一个都可能无意中改变已编译的 Geth 二进制文件的行为,因此必须进行广泛的审计。鉴于编译器工具链的不成熟,x86 Geth 和 MIPS/WASM Geth 之间的一致性不能被视为给定的。
EVM 本地方法没有任何这些问题——正常的执行和争议解决在相同的抽象层面上运行,并且在实践中密切共享代码路径。
TCB 升级
频率
虽然以太坊客户端程序经常升级,但以太坊协议本身往往一年只硬分叉几次。实际修改 EVM 语义的硬分叉甚至更少见,大约一年一次。此外,许多这些更改(例如共识)不会影响执行语义。因此,与采用较低级别 VM 方法的 ORU 相比,EVM 本地 ORU 的 TCB 需要相对较少的升级。相比之下,较低级别的 VM 方法需要每次客户端升级时都升级 L1 合约,因为更改必须反映在链上新的二进制承诺中。
此外,我们预计以太坊协议和 EVM 规范最终会以某种形式稳定下来。这有两个含义:
从长远来看,EVM 本地 ORU 的 TCB(或等效意义上的链上验证者)的升级频率将会降低——最终趋于零。另一方面,个别客户端程序可能会继续经历旨在提高性能和修复错误的升级,从而在较低级别的 VM 方法中触发频繁必要的 TCB 升级。EVM 本地 ORU 可以与以太坊同步稳定。这是因为负责开发 Specular 的社区可能会放弃其 L1 合约升级密钥,而不会失去向客户提供性能升级和错误修复的能力。另一方面,一旦 Optimism 团队扔掉了钥匙(正如他们所说的那样),就不可能及时进行此类升级(如果有的话)。这使得这样做是一项风险更高的工作,即使外部客户多样性计划提供了轻微的保护措施——以至于它可能永远不够安全,无法摆脱它们。
因此,我们认为放弃(快速)升级密钥的最安全和最实用的途径是通过 EVM 本地 ORU 设计。
透明度
较低级别 VM 方法中 TCB 的大小和复杂性导致升级过程不透明。例如,客户端的升级方式不如以太坊规范透明,后者需要经过慎重的提议 (EIP) 流程。对特定于 ORU 的工具链组件的升级,例如 Golang-to-ISA 编译器,仍然更不透明。
在我们的方法中,语义验证与实现这些语义的客户端程序之间存在明显的区别。因此,更容易辨别升级是否会潜在地影响语义的解释——审计人员只需要查看 L1 合约源代码中的差异。
结论
由于上述原因,我们相信 EVM 本地设计可提供卓越的安全性和信任属性。
感谢 Patrick McCorry 对这篇文章的反馈和意见。
附录
在本节中,我们对 @kelvinfichter 深思熟虑的博文中的具体摘录做出回应,他在博文中总结了(他的观点)两种方法之间的权衡。虽然这篇文章承认了上述大部分观点,但它也提出了一些有趣的问题。
升级
Optimism 基本可以在不触碰任何智能合约的情况下自由修改客户端代码
二元承诺仍然必须改变。在治理过程中如何处理对安全关键合约代码的修改和对合约中编译和提交的安全关键客户端代码的修改之间应该没有有意义的区别。任何一方的修改都会对较低级别 VM 方法中 Rollup 的安全性产生不利影响。
此外,虽然确实任何人都可以计算客户端代码版本之间的差异,以查看升级中发生了什么变化,但在实践中审核跨越数万到数十万个 LoC 的代码库的更改更具挑战性,因为任何给定修改的影响都不太清楚。此外,由于客户端的更改不需要传播到证明,EVM 更新不会触发新的智能合约审计。原生 EVM 故障证明必然受上游 EVM 更改的支配。以太坊硬分叉大约每年两次,并且这些硬分叉中至少有一个通常会引入 EVM 调整(一些比其他更多,例如在伦敦硬分叉中引入 EIP-1559)。如果本地 EVM 证明系统想要维持上游 EVM 等效性,则必须升级证明合约。
在 EVM 本地方法中需要审计的相同硬分叉也可能会在较低级别的 VM 方法中触发审计。在我们看来,单个客户端的工程/审计工作的差异并不显着——正如前面所讨论的,EVM 原生方法在多客户端案例中领先。
引入新功能
尝试在 EVM 之外引入新功能时,具有本地 EVM 证明的系统可能会更加困难。以调用数据(calldata)压缩为例 […]
我们同意 EVM 范围之外的某些功能(例如调用数据(calldata)压缩)可能有助于为用户实现低交易成本(尽管最近数据可用性层的发展利用了对以太坊的现有信任,这可能不是立即需要的)。较低级别的 VM 方法在这里确实具有更大的灵活性。然而,所有的希望都不会消失。
通过将 L2 扩展与 EVM 语义分离,我们可以专注于确保链上验证者的安全性。可以引入不同的验证者来支持 L2 扩展,从而保持核心 EVM 验证者独立且完整。我们目前计划插入零知识证明技术来验证此类扩展。虽然在 SNARK 中执行 EVM 语义可能很复杂,但数据压缩(calldata)等 L2 扩展更易于处理,因为语义规范完全在我们的控制之下(因此可以设计为对 SNARK 友好)。我们注意到,这仍然是一个正在进行的研究领域。
工程努力
本地 EVM 证明合约比低级证明复杂得多,以至于即使构建单个原生 EVM 证明也将是一项巨大的工程工作。然而,KEVM 的存在意味着有可能形式验证证明的 EVM 方面的正确性。
鉴于迄今为止我们为构建 Specular 所投入的工程资源数量,我们认为这是一个高估。此外,如上所述并在帖子中承认,许多问题实际上可以通过形式的方法来解决。
脚注
[1] 我们使用术语 EVM 语义,包括以太坊黄皮书中定义的交易间和交易内语义。
[2] 为了消除歧义,我们将实现以太坊的软件称为客户端程序,并将它们的实例(即运行该软件的实际节点)称为客户端。