ZK-rollup长期以来一直被视为以太坊扩展的终局。然而,尽管它们对以太坊扩展路线图很重要,但在几个关键点上仍然存在广泛的不确定性:
zk-rollup到底是什么?
特定于应用程序的rollup和通用rollup之间有什么区别?
zk-EVM rollup是什么?EVM等效和EVM兼容等术语的实际含义是什么么,它们如何适用于rollup?
zk-rollup生态系统的现状怎么样,对我的项目意味着什么?
如果你是一名希望了解以太坊扩展的下一阶段的开发人员,本文(希望)会有所帮助。
ZK-Rollup
ZK-rollup是通过一个简单的观察成为可能的:STARKs或SNARKs等证明系统允许以次线性处理来验证线性数量的交易。我们可以利用这一特性来创建大规模可扩展的区块链交易处理,具体如下:
1、用户在L1上的zk-rollup智能合约中锁定他们的资产。
2、用户将涉及这些资产的交易提交给L2的sequencer,该sequencer将这些交易收集成有序的批次,并为每个批次生成一个有效性证明(例如STARK/SNARK)和聚合状态更新。
3、这个状态更新和证明被提交给我们的L1 zk-rollup智能合约并由其验证,用于更新我们的L1状态。
4、用户可以使用这个L1状态(取决于不同的数据可用性机制)来检索他们的资产,从而实现完全的自我托管和 "以太坊安全性"。
简化的ZK-Rollup架构
验证证明的gas成本与被证明的交易数量呈次线性关系,与直接使用L1相比,允许更大的规模。要想更详细地了解这个过程,我推荐阅读Vitalik的Rollup不完整指南或Delphi新发布的Rollup全面指南。
特定于应用的Rollup
到目前为止,所有生产级的zk-rollup都是我们称之为 "特定于应用的rollup"。在特定于应用的rollup中,rollup支持固定数量的 "状态转换"(例如交易),由rollup运行者定义。这对于过度优化常见的用例是非常有用的,例如:
Loopring—支付和交换
Immutable—NFT铸造和交易,游戏
dydx —永续合约交易
特定于应用的rollup在扩展特定的、已熟知的问题方面非常出色。如果你的项目需求可以通过特定于应用的rollup来满足,你的用例可能会得到更好的性能,更好的用户体验和更好定价,因为它们缺乏通用性是一个巨大的优势。例如,在Immutable,我们能够通过对NFT交易费用补贴免费的NFT铸造和转移来消除gas费用——这种权衡只因rollup的状态转换的可预测性质而成为可能。
然而,许多项目希望能够创建自己的自定义逻辑和智能合约,独立于rollup运营商,这在特定于应用的rollup中是不可能的。此外,许多DeFi项目需要 "可组合性",或与其他项目进行交互的能力(例如,许多DeFi项目使用Uniswap作为价格预言机)。只有当你的rollup不仅支持自定义代码,而且支持可以由任何用户部署的原生智能合约时,可组合性才有可能实现。为了实现这一点,我们需要修改我们的zk-rollup架构,以扩大每个组件的运用。
这种灵活性的增加要付出几个代价:性能大大降低,rollup参数的可定制性降低,以及更高的费用。然而,最大的代价是根本没有实现通用的zk-rollup,当然也没够实现批量生产的zk-rollup。但这种情况正在开始改变。
StarkNet目前已经在主网上运行。
3个独立的项目(zkSync, Polygon Hermez/zkEVM和Scroll)都在ETH CC 2022大会上宣布,他们将成为第一个到达主网的 "zkEVM"。
这些公告值得深入研究,因为这些团队不只是宣布了通用的rollup,他们还宣布了 "zkEVM"。随后,推特上出现了很多围绕 "EVM兼容性"、"EVM等效性"、"真正的zkEVM "以及哪种方法更优越的争论。对于应用开发者来说,这些对话往往是噪音——所以本文的目的是解析这些术语、设计决策和理念,并解释它们对开发者的实际影响。
让我们从头开始:什么是EVM?
了解EVM
以太坊虚拟机(EVM)是执行以太坊交易的运行环境,最初在以太坊黄皮书中定义,后来被一系列以太坊改进提案(EIP)修改。它由以下部分组成:
一个用于执行程序的标准 "机器",每笔交易都有的易失性 "存储器",可以写入交易的持久性 "存储器 "和一个操作 "堆栈"
~约140个定价的 "操作码",在该机器中执行状态转换。
图表来自https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf
我们虚拟机的一些操作码例子:
堆栈操作—PUSH1 (向堆栈中添加东西)
算术操作—ADD(添加数字),SUBTRACT。
状态操作—SSTORE(存储数据),SLOAD(加载数据)。
交易操作— CALLDATA, BLOCKNUMBER (返回关于当前执行的交易的信息)
一个EVM程序只是一系列操作码和参数。当这些程序被表示为一个连续的代码区块时,我们称其结果为 "字节码"(通常表示为十六进制字符串)。
通过将大量这些操作码组合成一个执行序列,我们可以创建任意的程序。以太坊使用定制的虚拟机,而不是调整现有的虚拟机,因为它有独特的需求:
每个操作都必须有 "成本",以防止滥用(因为所有节点运行所有交易)
每个操作都必须是确定性的(因为所有节点都必须在交易执行后就状态达成一致)
我们需要区块链特有的概念(如智能合约、交易)
一些复杂的操作必须是原语(如密码学)
交易必须沙盒化,没有I/O或外部状态访问
EVM是第一个图灵完整的区块链虚拟机,于2015年发布。它有一些设计上的局限性,但其巨大的先发优势和随后的广泛采用为以太坊创造了巨大的独特性——它是迄今为止整个领域中最经得起考验的智能合约基础设施。
由于以太坊的主导地位,许多后来的区块链都直接采用了这个运行时环境。例如,Polygon和BNBChain是以太坊的直接分叉,因此使用EVM作为其运行时间。值得注意的是,EVM并不是一成不变的,在EIP1559等升级中经常被修改。由于其他区块链需要时间来更新,或者在一些地方与以太坊有分歧,它们往往运行的是一个稍微过时的EVM版本,并且可能难以跟上变化——这一事实会让以太坊的核心开发者感到沮丧。
以太坊兼容性
然而,人们所说的 "EVM链 "通常不仅仅是反映这个运行时环境。以下是一些始于以太坊的标准,它们已成为事实上的全球标准:
Solidity(一种高级语言,可编译成EVM字节码)
以太坊的JSON-RPC客户端API(用于与以太坊节点交互)
ERC20/ERC721(Ethereum代币标准)
ethers.js(一个与以太坊交互的网络库)
以太坊的密码学(例如,keccak256作为哈希函数,secp256k1上的ECDSA签名)
从技术上讲,你的链可以有EVM运行时间,而不支持上述的一些或全部。然而,遵守这些标准使得在你的新链上使用以太坊工具变得非常容易。一个很好的例子是Polygon,它除了使用上述所有工具外,还能够运行分叉版本的Etherscan(Polygonscan),使用Hardhat等以太坊开发者工具,并在Metamask等钱包中被支持为不同的以太坊 "网络"。Nansen和Dune等工具最初都是针对以太坊的,因此增加对新的EVM区块链的支持很简单。新的钱包,新的NFT市场——如果以太坊的界面和你的链的界面之间的唯一区别是链的ID,你很可能会成为第一个且最容易添加的。话虽如此,这些工具是为以太坊打造的——只要你开始修改你的区块链(例如更大的区块,更快的区块时间),你就面临破坏它们的风险。没有完美的兼容性这回事。
尽管如此,针对以太坊标准的工具和应用程序的数量为新的区块链创造了巨大的动力,使其只是反映以太坊标准。任何不支持上述标准的区块链在涉及开发者工具时都会自动落后,并有可能随着EVM生态系统的发展而进一步落后。
我认为,"EVM兼容 "一词实际上不足以描述这里的网络效应——我们实际上描述的是 "以太坊兼容",并远远超出智能合约执行环境,延伸到整个以太坊生态系统和工具集。
为了应对这一点,Solana等非EVM区块链不得不创建完全平行的生态系统,这将降低它们的速度,并使其更难吸引现有的开发者。然而,不需要遵守这些标准确实让非EVM区块链有能力对以太坊工具集进行更根本的改变,从而更积极地将自己与以太坊区分开。创建一个EVM区块链非常简单——但为什么有人会使用你的区块链而不是其他数百个 "速度快的EVM区块链 "中的一个。如果你能克服需要建立一个成功的平行链和生态系统的困难,Solana已经表明,a)你可以吸引优秀的原生应用程序(如MagicEden,Phantom),b)如果商业激励足够,EVM起源项目仍然会支持你(如Opensea增加Solana支持)。
ZK-EVM
公共通用rollup都有一个共同的目标:开发者和用户尽可能快地生成网络效果。这需要创造最高性能的rollup技术,拥有最好的BD团队,并进行最早或最有效的营销。然而,所有rollup团队(出于上述原因)都对以下问题感到非常担忧:
将现有以太坊合约(和开发者)迁移到其rollup中
由现有EVM工具支持(如钱包、市场等)
实现这两个目标的最简单方法是创建一个“zkEVM”:一个通用rollup,将EVM作为其智能合约引擎运行,并保持与上述以太坊生态系统的通用接口的兼容性。
然而,这并不像我们从头开始创建新的L1区块链时那样容易。我们的目标是运行EVM字节码——但ZK证明需要将它们证明的所有计算语句转换为非常特定的格式——一个“代数线路(algebraic circuit)”,然后可以编译成STARK或SNARK。为了快速了解“线路”,这里有一个例子(使用更直观的布尔电路(boolean circuit)作为代数线路的特例)。在基于这个简单电路的zkSNARK系统中,我们的证明者希望说服验证者他们了解产生真输出的输入(𝑥1 = 1, 𝑥2 = 1, 𝑥3=0)。这是一个非常简单的电路,具有有限数量的逻辑门(logic gates)——我相信你可以想象编码一个电路需要多少逻辑门,证明复杂的智能合约交互,特别是涉及密码学的交互!
为了理解这个编译过程的每一步,我推荐阅读Vitalik的从零到英雄的SNARK指南,以及Eli Ben-Sasson关于不同证明系统的讨论。然而,这种更深层次的理解对于我们的目的来说并不是必要的——只需记住,为了支持EVM计算,我们必须将所有EVM程序转换为这些电路,以便以后能够证明它们。
一般来说,有以下几种方法可以做到这一点:
通过将EVM执行轨迹转换为可验证电路,直接证明EVM执行跟踪
创建一个自定义虚拟机,将EVM操作码映射到该虚拟机的操作码中,然后在该自定义环境中证明跟踪的正确性
创建一个自定义虚拟机,将Solidity转换为自定义虚拟机的字节码(直接或通过自定义高级语言),并在你的自定义环境中进行验证
方案1:证明EVM执行轨迹
Scroll
让我们从最直观的方法开始:证明EVM执行轨迹本身,这种方法目前正由Scroll团队(与Ethereum基金会的Privacy Scaling Group一起)进行研究。为了实现这个目标,我们将需要:
为一些密码累加器设计一个电路(允许我们验证我们正在准确地读取存储和加载正确的字节码)
设计一个电路,将字节码与真正的执行跟踪连接起来
为每个操作码设计一个电路(使我们能够证明每个操作码的读、写和计算的正确性)
在电路中直接实现每一个EVM操作码是具有挑战性的,但由于这种方法完全反映了EVM,它对可维护性和工具支持有很大好处。下图显示,Scroll和Ethereum之间唯一的理论差异是实际的运行环境。然而,值得注意的是,Scroll目前并没有通过这种机制支持所有的EVM操作码。
Optimism团队对此写了一篇精彩的讨论,尽管是在optimistic rollup的背景下。Optimism最初创建了一个定制的Optimistic虚拟机(OVM),作为他们rollup的执行环境。OVM是 "以太坊兼容的",这意味着它可以运行修改后的Solidity代码,但低水平失配的几个领域意味着以太坊工具和复杂的代码经常需要重新编写。由于这个原因,Optimism改用 "EVM等效",直接使用确切的EVM标准,并正在开发第一个EVM等效的欺诈证明系统。然而,optimistic rollup不需要担心电路或验证器的效率——Optimism的正确选择可能不是我们rollup的正确选择。
方案2:自定义虚拟机+操作码支持
这种认识促使团队采用上面提到的 "EVM兼容"的方法:创建一个具有优化性能的自定义虚拟机,然后将EVM字节码直接转换为虚拟机的字节码。
Polygon
一个专注于这种方法的团队是Polygon Hermez(最近改名为Polygon zkEVM)。Polygon的方法是建立一个zkEVM( "操作码级的等价物"),这听起来最初与Scroll采取的方法相似。然而,与Scroll不同的是,Polygon的备用运行时("zkExecutor")运行定制的 "zkASM''操作码,而不是EVM操作码,来优化EVM解析(即减少限制的数量,直接证明EVM)。Hermez团队将此描述为 "基于操作码的方法",因为核心挑战是在他们的定制虚拟机中重新创建每一个EVM操作码(你可以在这里查看代码),这样它们就可以快速从EVM字节码变成可验证的格式。
这些中间步骤为维护和潜在的错误创造了更大的表面积,但对于实现高性能的证明来说是必要的。最终,重要的是要清楚,你的程序不是在反映电路中的EVM的zkEVM中运行,它们是在备用的 "zkExecutor "运行时中运行,它与EVM本身相似但不同。
由于这个原因,可能会与在此系统上运行的现有L1应用程序和工具有一些不兼容,尽管大多数Solidity代码可以照常运行。Polygon宣称与 "100%的现有以太坊工具"兼容,并承诺遵守JSON-RPC,他们在文档中提到了这一点。在实践中,这种说法可能是理想的,这将依赖于以太坊本身变得对SNARK更加友好。
Polygon的方法产生了比Scroll更高性能的rollup(当然是在中短期内):
大量的自定义代码,因为我们需要创建zkASM
可能需要开发人员修改他们的L1代码或工具框架
随着时间的推移,与以太坊的偏移可能会扩大
方案3:自定义虚拟机+转译器
上述解决方案在 "使EVM适用于zk-rollup"方面投入了大量的开发时间,将兼容性置于长期性能和扩展性之上。还有一个选择:创建一个全新的、专门的虚拟机,然后在上面添加对以太坊工具的支持,作为一个附加层。
StarkNet
这是StarkWare对StarkNet中取的方法,它是目前进展最快的通用rollup。StarkNet运行一个定制的智能合约虚拟机(Cairo VM),并有自己的低级语言(Cairo),两者都是为智能合约rollup而建。这意味着StarkNet没有开箱即用的以太坊兼容性——正如我们之前看到的,即使是操作码级别的虚拟机级别的兼容性也也可能会影响rollup的性能。
然而,Nethermind团队(与StarkWare合作)创建了Warp转译器,它能够将任意的Solidity代码转换为Cairo VM字节码。Warp的目标是使普通的Solidity合约可以移植到StarkNet上——实现许多以太坊开发者在 "EVM兼容性 "方面的主要目标。然而,在实践中,有一些Solidity的功能是Warp不支持的,包括低级别的调用(完整的列表可以在这里找到)。
这种构建智能合约rollup的方法是保持 "Solidity兼容":你没有在EVM内执行程序,也没有保持与任何其他以太坊接口的兼容性,但Solidity开发人员将能够编写可用于你的rollup的代码。因此,你可以保持与以太坊类似的开发者体验,而不必损害你的rollup的基础层。
然而,这种方法需要做出几项折衷。首先,建立自己的虚拟机是具有挑战性的——以太坊团队已经有超过五年的时间来解决EVM的问题,并且仍然在频繁地进行升级和修复。更多的自定义rollup将允许更好的性能,但你将失去由每条其他链和rollup对EVM进行的集体改进的好处。
其次,通过转译器支持Solidity有可能失去可组合性——如果开发者同时用CAIRO和Solidity编写合约,那么支持两者之间接口的工具有很大的可能性是脆弱的。到目前为止,绝大多数的StarkNet项目都直接使用CAIRO,它们可能不容易与未来的Solidity项目组合。最后,可能也是最重要的一点,StarkNet团队目前的目标不是与其他以太坊组件兼容——他们正在推出自己的客户端API、javascript库和钱包系统,这将迫使兼容以太坊的工具手动添加StarkNet支持。这极具挑战性,但并非不可能——如上所述,Solana已经成功地使其自定义标准得到一些以太坊工具的尊重,但将依靠StarkWare团队的能力来吸引那些不介意重建的开发者。
然而,如果他们能够成功地做到这一点,StarkWare团队将寻求通过第一个为Zk-rollup优化的智能合约虚拟机复制EVM的先发优势。
zkSync
另一个采用这种策略的项目是zkSync。zkSync已经创建了他们自己的虚拟机(SyncVM),它是基于寄存器的,并定义了自己的AIR (代数中间代码表示) 。然后,他们建立了一个专门的编译器,将Yul(一种中间语言,可以为不同的EVM版本编译成字节码,就像低级别的Solidity一样)编译成LLVM-IR,然后将其编译成指令,用于他们的自定义虚拟机。这与StarkWare采取的方法类似,但理论上提供了围绕基础语言的更多灵活性(尽管目前只支持Solidity 0.8.x)。zkSync团队最初创建了他们自己的类似CAIRO的语言 (Zinc),但他们已经将大部分精力转移到了Solidity编译器上,以使L1开发者的迁移更加简单。总的来说,他们的策略是重用更多的以太坊工具集——我希望他们的客户端API等也能更 "兼容以太坊"。
zkSync利用这个自定义虚拟机来提供非EVM兼容的功能,如账户抽象(Account Abstraction),这一直是以太坊核心协议的目标。这是自定义虚拟机所提供的好处的一个很好的例子——你不必等待以太坊建立新的功能!
下图进行了总结,你可以清楚地看到每个团队所遵循的不同策略:
Vitalik的zkEVM类型
Vitalik Buterin关于zkEVM的博客文章强调了rollup团队目前面临的基本困境:EVM并不是为 "可验证 "的程序建立的。事实上,正如我们通过上面的分析所显示的,你越是寻求与以太坊兼容,你的 "可验证格式 "中的程序的性能就越差。Vitalik根据与现有EVM基础设施的兼容程度,确定了通用rollup的几个大类别。
我对其观点的唯一拓展是注意到,即使在每个 "类型"中,也有很大程度的变化——我们正在处理一个范围,而不是完全细分的类别。从开发者体验的角度来看,对应用层进行单一的、小的改变的第3类rollup与第2类rollup有更多的共同点,第3类rollup对应用层进行了全面的改变,但在技术上没有引入新的虚拟机而成为第4类。
智能合约Rollup的现状
鉴于理解上述内容所需的细节,我们发明了一堆关于以太坊兼容性的语言,这并不奇怪。事实上,没有一个zk-rollup能完美地反映EVM在所有情况下的行为——这是一个程度问题,当涉及到可维护性和性能而不仅仅是兼容性时,每个团队所做的详细选择最终将是最重要的。我的观点是,下面的定义是最清晰和最一致的:
至关重要的是要明白,上述方法中没有任何一种在本质上是优越的——这是分类,而不是分等级。它们都做出了不同的权衡:更容易建立、维护和升级,性能更高,更容易与现有工具兼容。最终,领先的rollup也将由更好的分销和营销来决定,而不是纯粹的技术能力。话虽如此,做出正确的基本技术决定无疑有很大的优势。Scroll对EVM标准的热忱承诺是否能使他们轻松应对任何EVM的升级?另一个团队更务实的方法是否能帮助他们更快进入市场?StarkWare的自定义虚拟机+转译器的方法是否会被证明是一个更坚实的长期基础?另一个团队会不会最终从这个领域的先行者无疑会犯的错误中学到东西,并将他们击败?归根结底,以太坊发展的当前时刻的美妙之处在于,我们有不同的团队在以不同的方法推动一个共同的目标。
但在我们得意忘形之前,也应该对目前智能合约rollup的准备情况保持清醒的头脑。每个团队都有强烈的动机将自己营销为 "即将接管世界"——但以太坊上最早也要到2022年底才会有 "生产级 "的智能合约推出,而其中许多团队要到2023年才会准备好。根据StarkNet的发展历程,我们应该能预期从一个rollup进入测试网开始,至少要经过一年的迭代,才能使该rollup准备好支持主网上一致的生产级交易量。
由于这种不成熟的状态,对于那些需要规模而又不影响以太坊安全的开发者来说,特定于应用的rollup仍然是最有力的选择。事实上,即使是在通用rollup可用和更广泛地集成后,我预计在可预见的未来,特定于应用的rollup的性能、定制和可靠性仍将在某些用例(如交易所、NFT铸造/交易)中占据优势。
额外的Rollup因素
尽管本文的主要重点是,这并不全是关于以太坊生态系统兼容性与性能的问题!还有一些其他因素影响着你是否应该在特定的通用rollup上构建。我建议考虑的几个主要附加标准如下:
费用:这些rollup会以原生代币、ETH、还是两者的复杂组合来收取费用?费用结构对用户和开发者的体验有很大的影响,因为rollup通常需要拥有费用代币来支付计算费用。
证明和排序:所有的rollup都需要一个实体,负责给交易排序和产生证明。今天,大多数特定于应用的rollup是 "单排序器",它以弹性为代价产生更高的吞吐量。大多数通用rollup最初是作为单排序器rollup开始的,但他们通常有计划随着时间的推移将这个排序器去中心化。
自我托管:Zk-rollup的核心承诺是能够在保持以太坊安全的同时释放规模。然而,许多通用的rollup目前没有一个明确的机制,能够在出现恶意或不可用的排序器的情况下恢复用户资产。
数据可用性:正如介绍中提到的,自我托管的保证取决于故障情况下状态数据的可用性。然而,完全的数据可用性为用户引入了额外的成本。这在特定于应用的rollup世界中已经被广泛使用(例如Validiums,Volitions),但每个通用的rollup需要单独添加这个功能。
总结
智能合约rollup是以太坊扩展路线图中令人难以置信的一部分。在与现有的以太坊工具集的关系中,这些rollup所做的不同权衡证明了以太坊开发者生态系统多样性。
然而,目前关于EVM兼容性的讨论通常没有抓住重点。从开发者的角度来看,所有这些rollup都将支持Solidity代码。真正的以太坊兼容是一个更大的挑战,但它实际上有实质性的权衡,开发者应该在投入到rollup之前意识到这一点。
为了提高透明度,我希望看到每个rollup团队对以下问题提供更清晰的答案:
L1和L2在运行时间上的确切差异是什么?哪些操作码将在L2上被修改?任何其他的虚拟机特性(如费用结构)与L1相比是否会有所不同?
你的自定义虚拟机的形式规约在哪里,它的性能比其他方案强还是弱?
这次升级将对其他以太坊接口(如客户端API)做出多少改变,会破坏以太坊工具吗?
你的rollup什么时候在测试网上线?什么时候在主网上线?能否支持持续的生产吞吐量,即1000+自定义合约吞吐量?
你预计什么时候能支持用户资产的完全自我托管,以及在通用的rollup环境下会是什么样的?
一旦这些rollup在测试网上发布,这些问题应该更容易回答。在此之前,我希望看到这些团队继续发布更多的技术细节,说明他们的解决方案将作出的确切权衡,以及这将如何影响智能合约和工具开发者。
随着合并在即,经过战斗考验的特定于应用程序的rollup在生产中,并且通用的rollup将在明年进入主网,以太坊扩展的未来就在眼前。