作者:Cynic

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 級別的兼容性。

什麼是虛擬機?

要講清楚什麼是虛擬機,必須先講當今主流的馮諾依曼架構下的計算機執行流程。運行在計算機上的種種程序,通常是由高級語言經過層層轉化,最終生成機器可理解的機器碼完成執行的。根據轉化為機器碼的方式不同,高級語言可以大致分為編譯型語言與解釋型語言。

Kakarot:探索Starknet的EVM兼容之路

編譯型語言是指在代碼的編寫完成後,需要經過編譯器的處理,將高級語言代碼轉換成機器碼,生成可執行文件。一次編譯就可以多次以較高效率執行。編譯型語言的優點是因為在編譯時已經將代碼轉換為機器碼,因此執行速度快,並且可以在沒有編譯器的環境下運行程序,便於用戶使用,不需要安裝額外的軟件。常見的編譯型語言包括C,C++,Go 等。

與編譯型語言相對應的是解釋型語言。解釋型語言是指代碼通過解釋器逐行解釋執行,直接運行在計算機上,每次運行都要重新進行翻譯過程。解釋型語言的優點是開發效率高,代碼易於調試,但執行速度相對較慢。常見的解釋型語言包括Python,JavaScript,Ruby 等。

需要強調,語言從本質上並不區分編譯型和解釋型,只是在最初設計時會有一些傾向。 C/C++ 絕大多數情況下是編譯執行,但是也可以解釋執行(Cint、Cling)。很多傳統意義上的解釋型語言,現在是編譯成中間代碼在虛擬機上執行(Python、Lua)。

知道了物理機的執行流程,現在來講虛擬機。

虛擬機通常通過模擬不同的硬件設備來提供一個虛擬的計算機環境。不同的虛擬機可以模擬的硬件設備有所不同,但通常包括CPU、內存、硬盤、網絡接口等。

以以太坊虛擬機EVM 為例,EVM 是一種基於堆棧的虛擬機,它被用於執行以太坊智能合約。 EVM 通過模擬CPU、內存、存儲器和棧等硬件設備來提供一個虛擬的計算機環境。

Kakarot:探索Starknet的EVM兼容之路

具體來說,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 的博客。

為什麼需要zkEVM

這個問題需要從兩方面來看。

最初的zk Rollup 嘗試,都只能實現較為簡單的轉賬、交易功能,例如zkSync Lite, Loopring 等。但是曾經滄海難為水,用慣了以太坊上圖靈完備的EVM,當無法通過編程創造多樣的應用時,人們便開始呼喚L2 上的虛擬機。撰寫智能合約的需求,是為一。

Kakarot:探索Starknet的EVM兼容之路

由於EVM 中部分設計對於生成零知識證明/ 有效性證明不友好,部分玩家選擇了在底層使用對於零知識證明/ 有效性證明友好的指令集,例如Starknet 的Cairo Assembly 和zkSync 的Zinc Instruction。但是大家同時也都不願放棄EVM 龐大的用戶生態,於是選擇在上層兼容EVM,是3、4 類zkEVM。還有部分玩家仍然堅持EVM 傳統指令集Opcode,將精力放在為Opcode 生成更高效的證明上,是1、2 類zkEVM。 EVM 的龐大生態,是為二。

Kakarot:探索Starknet的EVM兼容之路

Kakarot:虛擬機上的虛擬機?

為什麼能夠在虛擬機上再做一個虛擬機?這個事情對於計算機從業者而言是司空見慣的,但是對於不了解計算機的用戶可能沒那麼顯然。其實很好理解,這就好像搭積木,只要下層足夠牢固(有圖靈完備的執行環境),就可以無上限地往上層疊加積木。但是不論搭了多少層,最後的執行還是要交給最底層的物理硬件去處理,所以層數增高會導致效率的降低。同時,由於不同積木的設計不同(虛擬機設計不同),隨著積木越搭越高,積木倒塌的可能性就越大(運行出錯),也就需要更高的技術水平支撐。

Kakarot 是在Starknet 上用Cairo 語言實現的一個EVM,以Cairo 智能合約形式去模擬EVM 中堆棧、內存、執行等內容。相對而言,實現EVM 並不是什麼難事,除了使用率最高的Go-Ethereum 中用Golang 編寫的EVM,現存的還有使用Python, Java, JavaScript, Rust 編寫的EVM。

Kakarot:探索Starknet的EVM兼容之路

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。

Kakarot:探索Starknet的EVM兼容之路

據kakarot CEO Elias Tazartes反饋,在團隊的最新版本中,放棄了Account Resister 的設計,改為直接使用一個31bytes 的Starknet 地址到20 位EVM 地址的mapping 來保存對應關係。在未來,為了提高互操作性以及允許Starknet 合約註冊自己的EVM 地址,可能會重新使用Account Register 的設計。

Starknet 上兼容EVM:Warp 與kakarot 有什麼差異

按照Vitalik 定義的zkEVM 類型而言,Warp 屬於Type-4,而kakarot 當前屬於Type-2.5。

Kakarot:探索Starknet的EVM兼容之路

Warp 是一個將Solidity 代碼轉化為Cairo 代碼的轉譯器,之所以不叫編譯器,大概是因為輸出的Cairo 仍是高級語言。通過Warp,Solidity 開發者可以維持原先的開發狀態,而不需要學習新的Cairo 語言。對於很多項目方而言,Warp 降低了進入Starknet 生態的門檻,不需要使用Cairo 重寫大量的工程代碼。

轉譯的思想雖然簡單,但是兼容性也是最差的,有部分Solidity 代碼無法很好地翻譯為Cairo,涉及到賬戶體系、密碼算法等代碼邏輯需要修改源代碼才能完成遷移,具體的不支持特徵可見Warp 文檔。例如,許多項目會對EOA 賬戶與合約賬戶的執行邏輯進行區分,但是Starknet 中所有賬戶都是合約賬戶,這部分的代碼就需要修改後才能進行轉譯。

Warp 是在高級語言層面的兼容,kakarot 是在EVM 層面的兼容。

EVM 的全部重寫,Opcode 與Pre-compile 的逐條實現,讓kakarot 擁有了更高原生的兼容性。畢竟,在相同的虛擬機(EVM)中執行,總是要比在不同的虛擬機(Cairo VM)中執行來得更兼容一些。 Account Registry、Blockhash Registry 更是巧妙地屏蔽了不同體系下的差異,把對用戶的遷移摩擦降到最小。

Kakarot:探索Starknet的EVM兼容之路

Kakarot 團隊

Kakarot:探索Starknet的EVM兼容之路

感謝kakarot 團隊對本文提出的寶貴意見,特別是Elias Tazartes。 Thank you, sir!