# Starknet的EVM兼容之路：Kakarot zkEVM 101

By [CYNIC](https://paragraph.com/@cynicsong) · 2024-03-09

---

![](https://storage.googleapis.com/papyrus_images/6fdf55b32a5a1c203d083364b5306706128325fd2ba8d2a3d5c9ff680fef2f84.png)

TL;DR

*   虚拟机是一个软件仿真的计算机系统，为程序提供执行环境。它可以模拟各种硬件设备，使程序在受控且兼容的环境中运行。以太坊虚拟机（EVM）是一种基于栈的虚拟机，用于执行以太坊智能合约。
    
*   zkEVM是一种集成了零知识证明/有效性证明技术的EVM。它允许使用零知识证明验证EVM的执行过程，而无需所有验证者重新执行EVM。市场上有各种zkEVM产品，每个产品都有自己的方法和设计。
    
*   需要zkEVM的原因在于对在Layer 2上支持智能合约执行的虚拟机的需求。此外，一些项目选择使用zkEVM来利用EVM的广泛用户生态系统，并设计更友好于零知识证明的指令集。
    
*   Kakarot是使用Cairo语言在Starknet上实现的zkEVM。它以Cairo智能合约的形式模拟了EVM的堆栈、内存、执行和其他方面。Kakarot面临与Starknet帐户系统的兼容性、成本优化和稳定性等挑战，因为Cairo语言尚处于实验阶段。
    
*   Warp是将Solidity代码转换为Cairo代码的转换器，在高级语言级别提供兼容性。另一方面，Kakarot通过实现EVM的操作码和预编译，提供了在EVM级别的兼容性。
    

什么是虚拟机？
-------

要讲清楚什么是虚拟机，必须先讲当今主流的冯诺依曼架构下的计算机执行流程。运行在计算机上的种种程序，通常是由高级语言经过层层转化，最终生成机器可理解的机器码完成执行的。根据转化为机器码的方式不同，高级语言可以大致分为编译型语言与解释型语言。

![](https://storage.googleapis.com/papyrus_images/9f55f816870e462e5b2a366716e42efb8e5ce32a5ac05f7253da7927186d7a37.png)

编译型语言是指在代码的编写完成后，需要经过编译器的处理，将高级语言代码转换成机器码，生成可执行文件。一次编译就可以多次以较高效率执行。编译型语言的优点是因为在编译时已经将代码转换为机器码，因此执行速度快，并且可以在没有编译器的环境下运行程序，便于用户使用，不需要安装额外的软件。常见的编译型语言包括C，C++，Go等。

与编译型语言相对应的是解释型语言。解释型语言是指代码通过解释器逐行解释执行，直接运行在计算机上，每次运行都要重新进行翻译过程。解释型语言的优点是开发效率高，代码易于调试，但执行速度相对较慢。常见的解释型语言包括Python，JavaScript，Ruby等。

> 需要强调，语言从本质上并不区分编译型和解释型，只是在最初设计时会有一些倾向。C/C++绝大多数情况下是编译执行，但是也可以解释执行（Cint、Cling）。很多传统意义上的解释型语言，现在是编译成中间代码在虚拟机上执行（Python、Lua）。

知道了物理机的执行流程，现在来讲虚拟机。

为什么需要虚拟机？
---------

首先是为了提供一个执行环境，以太坊为了达到其最初“世界计算机”的愿景，需要一个图灵完备的执行环境，来为编程提供支持。之所以用虚拟机而不是直接转换为机器码，在各个机器上执行，可能是考虑1、兼容性（可以类比JVM）2、执行环境可控（每一条指令都由虚拟机负责解释执行，这意味着可以对程序执行的每一个流程进行控制，虚拟机作为一个沙盒环境，对权限控制，调试都有诸多好处。尤其是在权限的控制中，可以避免一些恶意程序对原生系统的破坏）（最重要的，可能是因为原生的不能支持Gas的设计，Gas可以维持系统运行，防止DDoS攻击破坏系统安全）

![](https://storage.googleapis.com/papyrus_images/0cdca837e8a351088635536021db18e4c0e4800f58528908748fa7d19943a1b7.png)

虚拟机通常通过模拟不同的硬件设备来提供一个虚拟的计算机环境。不同的虚拟机可以模拟的硬件设备有所不同，但通常包括CPU、内存、硬盘、网络接口等。

以以太坊虚拟机EVM为例，EVM是一种基于堆栈的虚拟机，它被用于执行以太坊智能合约。EVM通过模拟CPU、内存、存储器和栈等硬件设备来提供一个虚拟的计算机环境。

![](https://storage.googleapis.com/papyrus_images/7de707ef74291f65fc0ff73c2e18c704826da18273b42986dcedfacce6b583fd.png)

具体来说，EVM是一种基于堆栈的虚拟机，它使用堆栈来存储数据和执行指令。EVM的指令集包括各种操作码，例如算术操作、逻辑操作、存储操作、跳转操作等，这些指令可以在EVM的堆栈上执行，从而完成智能合约的执行。

EVM模拟的内存和存储器是用于存储智能合约的状态和数据的设备。EVM将内存和存储器视为两个不同的区域，它可以通过读取和写入内存和存储器来访问智能合约的状态和数据。

EVM模拟的栈用于存储指令的操作数和结果。EVM的指令集中的大多数指令都是基于堆栈的，它们从栈中读取操作数并将结果推回栈中。

总之，EVM通过模拟CPU、内存、存储器和栈等硬件设备来提供一个虚拟的计算机环境，它可以执行智能合约的指令并存储智能合约的状态和数据。在实际运行中，EVM会将智能合约的字节码加载到内存中，并通过执行指令集来执行智能合约的逻辑。EVM实际取代的是上图中操作系统+硬件的部分。

EVM的设计过程，显然是自下而上的，先敲定了模拟的硬件环境（堆栈、内存），再根据对应的环境设计了自己的一套汇编指令集（Opcode）与字节码（Bytecode）。尽管汇编指令集是给人看的，但是涉及到很多底层知识，对开发者的要求较高，开发起来也较繁琐，所以需要高级语言，屏蔽晦涩繁琐的底层调用，为开发者提供更好的体验。EVM由于其汇编指令集的的定制化设计，很难直接利用传统的高级语言，索性重新一个新的高级语言以适配该虚拟机。以太坊社区为了EVM执行效率设计了两种编译型的高级语言——Solidity和Vyper。Solidity自不必强调，Vyper是Vitalik针对Solidity中存在的部分缺陷进行改进后设计的EVM高级语言，但是在社区没有获得很高的采用度，于是渐渐淡出历史舞台。

什么是zkEVM
--------

简单来讲，zkEVM就是运用零知识证明/有效性证明技术的EVM，让EVM的执行过程，可以通过零知识证明/有效性证明来更高效、低成本地验证，而不需要所有验证者都重新进行EVM的执行过程。

市场上的zkEVM产品众多，赛道火热，主要玩家包括Starknet, zkSync, Scroll, Taiko, Linea, Polygon zkEVM（原Polygon Hermez） 等，被vitalik分为了5类（1、2、2.5、3、4）。具体的内容可以查看Vitalik的博客。

[https://vitalik.ca/general/2022/08/04/zkevm.html](https://vitalik.ca/general/2022/08/04/zkevm.html)

为什么需要zkEVM
----------

这个问题需要从两方面来看。

最初的zk Rollup尝试，都只能实现较为简单的转账、交易功能，例如zkSync Lite, Loopring等。但是曾经沧海难为水，用惯了以太坊上图灵完备的EVM，当无法通过编程创造多样的应用时，人们便开始呼唤L2上的虚拟机。撰写智能合约的需求，是为一。

![](https://storage.googleapis.com/papyrus_images/e198616b337a2307a0a4d63c940be4d73ebb019a501f7f7f779f4c46d03b2b69.png)

由于EVM中部分设计对于生成零知识证明/有效性证明不友好，部分玩家选择了在底层使用对于零知识证明/有效性证明友好的指令集，例如Starknet的Cairo Assembly和zkSync的Zinc Instruction。但是大家同时也都不愿放弃EVM庞大的用户生态，于是选择在上层兼容EVM，是3、4类zkEVM。还有部分玩家仍然坚持EVM传统指令集Opcode，将精力放在为Opcode生成更高效的证明上，是1、2类zkEVM。EVM的庞大生态，是为二。

![](https://storage.googleapis.com/papyrus_images/18e5ff175dfca69e424276d0c2dfe5df7eb7e7ce5c92f971313d029f2b103b54.png)

Kakarot：虚拟机上的虚拟机？
-----------------

为什么能够在虚拟机上再做一个虚拟机？这个事情对于计算机从业者而言是司空见惯的，但是对于不了解计算机的用户可能没那么显然。其实很好理解，这就好像搭积木，只要下层足够牢固（有图灵完备的执行环境），就可以无上限地往上层叠加积木。但是不论搭了多少层，最后的执行还是要交给最底层的物理硬件去处理，所以层数增高会导致效率的降低。同时，由于不同积木的设计不同（虚拟机设计不同），随着积木越搭越高，积木倒塌的可能性就越大（运行出错），也就需要更高的技术水平支撑。

Kakarot是在Starknet上用Cairo语言实现的一个EVM，以Cairo智能合约形式去模拟EVM中堆栈、内存、执行等内容。相对而言，实现EVM并不是什么难事，除了使用率最高的Go-Ethereum中用Golang编写的EVM，现存的还有使用Python, Java, JavaScript, Rust编写的EVM。

![](https://storage.googleapis.com/papyrus_images/44c583e5ab9dfd920ab6bf9b05b050ff6b0bfeab7a736044aa25e439e931740a.png)

Kakarot zkEVM的技术难点在于，协议是作为Starknet链上合约存在的，这就带来了两个关键的问题。

1.  兼容性 Starknet使用的是和以太坊完全不同的账户体系，以太坊中账户分为EOA（外部拥有账户）和CA（合约账户），然而Starknet中支持原生的账户抽象，所有账户都是合约账户。同时，由于使用的密码学算法不同，用户无法使用同一个熵在Starknet中生成与以太坊相同的地址。
    
2.  成本 由于kakarot zkEVM是作为合约存在于链上的，所以对于代码实现有着较高的要求，需要尽可能地面向Gas进行优化，降低交互成本。
    
3.  稳定性 与使用Golang, Rust, Python等传统高级语言不同，Cairo语言仍然处于试验阶段，从Cairo 0到Cairo 1再到Cairo 2（或者如果你喜欢的话，Cairo 1 version 2），官方团队仍然在不断修改语言特性。同时，Cairo VM还未得到足够的测试，不排除后续大规模重写的可能。
    

kakarot协议由五个主要的组件组成（GitHub文档中写的是四个，未包含EOA，本文为了便于读者理解做了调整）：

*   Kakarot (Core)：负责执行以太坊形式的交易，同时为以太坊用户提供对应的Starknet账户
    
*   Contract Accounts：以太坊意义上的CA，负责存储合约的字节码、合约中变量状态
    
*   Externally Owned Accounts：以太坊意义上的EOA，负责将以太坊交易转发给Kakarot Core
    
*   Account Registry: 存储以太坊账户和Starknet账户的对应关系。
    
*   Blockhash Registry：Blockhash作为一个特殊的Opcode，需要过去的区块数据，而Kakarot无法在链上直接获取到数据。该组件存储`block_number -> block_hash`的映射关系，由管理员写入，提供给Kakarot Core。
    

![](https://storage.googleapis.com/papyrus_images/22c2bfea606bd4164a0d806618271e2a6dc055bda9f6a096fc1c7d2e68678c22.png)

据kakarot CEO [Elias Tazartes](https://github.com/Eikix)反馈，在团队的最新版本中，放弃了Account Resister的设计，改为直接使用一个31bytes的Starknet地址到20位EVM地址的mapping来保存对应关系。在未来，为了提高互操作性以及允许Starknet合约注册自己的EVM地址，可能会重新使用Account Register的设计。

Starknet上兼容EVM：Warp与kakarot有什么差异
--------------------------------

按照Vitalik定义的zkEVM类型而言，Warp属于Type-4，而kakarot当前属于Type-2.5。

![](https://storage.googleapis.com/papyrus_images/62ec50843a5aafd24d43b1065825374320e83de67041a0e809a8beb733dffb5b.png)

Warp是一个将Solidity代码转化为Cairo代码的转译器，之所以不叫编译器，大概是因为输出的Cairo仍是高级语言。通过Warp，Solidity开发者可以维持原先的开发状态，而不需要学习新的Cairo语言。对于很多项目方而言，Warp降低了进入Starknet生态的门槛，不需要使用Cairo重写大量的工程代码。

转译的思想虽然简单，但是兼容性也是最差的，有部分Solidity代码无法很好地翻译为Cairo，涉及到账户体系、密码算法等代码逻辑需要修改源代码才能完成迁移，具体的不支持特征可见[Warp文档](https://nethermindeth.github.io/warp/docs/get_around_unsupported_features/)。例如，许多项目会对EOA账户与合约账户的执行逻辑进行区分，但是Starknet中所有账户都是合约账户，这部分的代码就需要修改后才能进行转译。

Warp是在高级语言层面的兼容，kakarot是在EVM层面的兼容。

EVM的全部重写，Opcode与Pre-compile的逐条实现，让kakarot拥有了更高原生的兼容性。毕竟，在相同的虚拟机（EVM）中执行，总是要比在不同的虚拟机（Cairo VM）中执行来得更兼容一些。Account Registry、Blockhash Registry更是巧妙地屏蔽了不同体系下的差异，把对用户的迁移摩擦降到最小。

![](https://storage.googleapis.com/papyrus_images/c4222b2ddd2eb94d63f9ae4be847575f3c4477df3be113df46f2ba47a14e7110.png)

Kakarot 团队介绍
------------

![](https://storage.googleapis.com/papyrus_images/23ff1affe43ad5db190e7daec645019eb8281d8e7316e061a3446d7cdd52cfed.png)

感谢kakarot团队对本文提出的宝贵意见，特别是[Elias Tazartes](https://github.com/Eikix)。Thank you, sir!

---

*Originally published on [CYNIC](https://paragraph.com/@cynicsong/starknet-evm-kakarot-zkevm-101)*
