詳解 Kakarot zkEVM:Starknet 的 EVM 兼容之路
撰文: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 級別的相容性。
什麼是虛擬機?
要講清楚什麼是虛擬機,必須先講當今主流的馮諾依曼架構下的計算機執行流程。運行在計算機上的種種程序,通常是由高級語言經過層層轉化,最終生成機器可理解的機器碼完成執行的。根據轉化為機器碼的方式不同,高級語言可以大致分為編譯型語言與解釋型語言。
編譯型語言是指在代碼的編寫完成後,需要經過編譯器的處理,將高級語言代碼轉換成機器碼,生成可執行文件。一次編譯就可以多次以較高效率執行。編譯型語言的優點是因為在編譯時已經將代碼轉換為機器碼,因此執行速度快,並且可以在沒有編譯器的環境下運行程序,便於用戶使用,不需要安裝額外的軟體。常見的編譯型語言包括 C,C++,Go 等。
與編譯型語言相對應的是解釋型語言。解釋型語言是指代碼通過解釋器逐行解釋執行,直接運行在計算機上,每次運行都要重新進行翻譯過程。解釋型語言的優點是開發效率高,代碼易於調試,但執行速度相對較慢。常見的解釋型語言包括 Python,JavaScript,Ruby 等。
需要強調,語言從本質上並不區分編譯型和解釋型,只是在最初設計時會有一些傾向。C/C++ 絕大多數情況下是編譯執行,但是也可以解釋執行(Cint、Cling)。很多傳統意義上的解釋型語言,現在是編譯成中間代碼在虛擬機上執行(Python、Lua)。
知道了物理機的執行流程,現在來講虛擬機。
虛擬機通常通過模擬不同的硬體設備來提供一個虛擬的計算機環境。不同的虛擬機可以模擬的硬體設備有所不同,但通常包括 CPU、內存、硬碟、網路介面等。
以以太坊虛擬機 EVM 為例,EVM 是一種基於堆疊的虛擬機,它被用於執行以太坊智能合約。EVM 通過模擬 CPU、內存、儲存器和堆疊等硬體設備來提供一個虛擬的計算機環境。
具體來說,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 上的虛擬機。撰寫智能合約的需求,是為一。
由於 EVM 中部分設計對於生成零知識證明 / 有效性證明不友好,部分玩家選擇了在底層使用對於零知識證明 / 有效性證明友好的指令集,例如 Starknet 的 Cairo Assembly 和 zkSync 的 Zinc Instruction。但是大家同時也都不願放棄 EVM 龐大的用戶生態,於是選擇在上層相容 EVM,是 3、4 類 zkEVM。還有部分玩家仍然堅持 EVM 傳統指令集 Opcode,將精力放在為 Opcode 生成更高效的證明上,是 1、2 類 zkEVM。EVM 的龐大生態,是為二。
Kakarot:虛擬機上的虛擬機?
為什麼能夠在虛擬機上再做一個虛擬機?這個事情對於計算機從業者而言是司空見慣的,但是對於不了解計算機的用戶可能沒那麼顯然。其實很好理解,這就好像搭積木,只要下層足夠牢固(有圖靈完備的執行環境),就可以無上限地往上層疊加積木。但是不論搭了多少層,最後的執行還是要交給最底層的物理硬體去處理,所以層數增高會導致效率的降低。同時,由於不同積木的設計不同(虛擬機設計不同),隨著積木越搭越高,積木倒塌的可能性就越大(運行出錯),也就需要更高的技術水平支撐。
Kakarot 是在 Starknet 上用 Cairo 語言實現的一個 EVM,以 Cairo 智能合約形式去模擬 EVM 中堆疊、內存、執行等內容。相對而言,實現 EVM 並不是什么難事,除了使用率最高的 Go-Ethereum 中用 Golang 編寫的 EVM,現存的還有使用 Python, Java, JavaScript, Rust 編寫的 EVM。
Kakarot zkEVM 的技術難點在於,協議是作為 Starknet 鏈上合約存在的,這就帶來了兩個關鍵問題。
- 相容性 Starknet 使用的是和以太坊完全不同的帳戶體系,以太坊中帳戶分為 EOA(外部擁有帳戶)和 CA(合約帳戶),然而 Starknet 中支持原生的帳戶抽象,所有帳戶都是合約帳戶。同時,由於使用的密碼學算法不同,用戶無法使用同一個熵在 Starknet 中生成與以太坊相同的地址。
- 成本 由於 kakarot zkEVM 是作為合約存在於鏈上的,所以對於代碼實現有著較高的要求,需要儘可能地面向 Gas 進行優化,降低互動成本。
- 穩定性 與使用 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 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。
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 團隊
感謝 kakarot 團隊對本文提出的寶貴意見,特別是Elias Tazartes。Thank you, sir!