L2 - 深入理解OVM

買賣虛擬貨幣
Optimistic Rollup是Layer2潛在的一種方案。週末有點時間,在網路上翻了翻。網路上的文章,Optimistic Rollup深入技術的文章不多,介紹OVM底層技術細節的文章則更少。感興趣看了看Optimism實現的OVM功能相關的智慧合約,對Optimistic Rollup的理解很有幫助。總結一下,感興趣的小夥伴可以看看。1. Optimistic Rollup vs. zk Rollup網路上對比這兩種Rollup的方案文章不多。主要的一篇文章是:https://medium.com/matter-labs/optimistic-vs-zk-rollup-deep-dive-ea141e71e075國內也有對應的翻譯文章:https://ethfans.org/posts/optimistic-vs-zk-rollup-deep-dive

具體的效能和安全性對比,感興趣的小夥伴可以直接看這篇文章。個人覺得,因為方案都不夠成熟,目前方案能夠達到的TPS都只是理論值。沒必要太多的討論。主要說說兩種Rollup的技術實現的區別:

兩種方案都是Rollup,Layer2的所有Transaction的資訊都會作為CallData“儲存”在Layer1,並且Layer2的狀態也及時同步到Layer1。兩者的區別在於,Layer2的狀態在Layer1的正確性保證。Optimistic Rollup採用的是“檢察”的方式,任何一個節點發現Layer2的狀態的錯誤,提交相關的證明。如果錯誤的狀態被驗證,在Layer1的Layer2的狀態需要回滾,提交錯誤狀態的節點被懲罰。zk Rollup採用的方式直接了當,在向Layer1提交Layer2狀態的同時,提交相關狀態改變的證明。這些證明都是在Layer2生成。也就是說,zk Rollup在向Layer1提交Layer2狀態的同時,同時提交了Layer2狀態轉換的計算證明。這個計算證明是透過零知識證明的演算法產生。簡單的說,如果轉換的狀態複雜,生成零知識證明的時間越長。

目前,zk Rollup只是支援簡單的賬戶系統以及世界狀態,並不能支援智慧合約等複雜的世界狀態。Optimistic Rollup雖然能支援智慧合約,事實上,因為Layer1的計算能力比較弱,智慧合約的支援也比較有限。Optimistic Rollup支援的智慧合約的執行環境,類似EVM,稱為 OVM(Optimistic Virtual Machine)。

2. OVM

OVM - Optimistic Virtual Machine。OVM是Layer2交易的執行環境。因為提交到Layer1的狀態需要檢驗正確性,Layer1需要“重放”Layer2的交易,也就是說,Layer1在有些情況下需要執行OVM交易的執行。Optimistic Rollup最複雜的地方也在於此,用EVM模擬OVM,並執行Layer2的交易。

Optimism實現了EVM模擬OVM的邏輯,相關的專案的Github地址:
https://github.com/ethereum-optimism/contracts-v2

本文中使用的程式碼的最後一個提交資訊如下:

commit ca1fede6c8cb9e4eacd8205c1d53284d0c8debdc
Author: Mark Tyneway <admin@chaindaily>
Date:   Fri Oct 30 12:14:50 2020 -0700

    deploy: use layer 2 chainid (#42)

核心程式碼在contracts-v2/contracts/optimistic-ethereum/OVM目錄中。除了OVM目錄,iOVM目錄是介面定義,libraries目錄是各種庫的實現,包括編解碼,二叉樹等等。

2.1 OVM/chain

Layer1的智慧合約中用兩條鏈維護交易資訊和狀態資訊,分別是CanonicalTransactionChain和StateCommitmentChain。

Layer2的所有的交易資訊,一個個Batch的透過CallData提交到Layer1。每個Batch中的交易的Hash資訊組織成Merkle樹。簡單的說,CanonicalTransactionChain儲存的是一個個Batch交易的Merkle樹根。這些樹根用來判斷某個具體的交易是否在鏈中。

Layer2的世界狀態,透過一個個交易的狀態改變來表示。每個交易後的狀態也是透過一個個Batch提交到Layer1。每個Batch中的狀態,也再次組織成Merkle樹。這些樹根用來判斷某個狀態是否在鏈中。

具體兩條鏈的儲存資訊,可以檢視原始碼:OVM_CanonicalTransactionChain.sol和OVM_StateCommitmentChain.sol。

2.2 OVM/execute

execute是OVM在EVM執行的核心邏輯,包括ExecuteManager,StateManager以及SafetyChecker。對應的原始碼分別是:OVM_ExecutionManager.sol,OVM_SafetyChecker.sol和OVM_StateManager.sol。

ExecuteManager是整個智慧合約執行環境以及指令集的處理。OVM其實和EVM邏輯上採用同樣的指令集,但是在OVM的環境下,特別在Layer1的EVM執行OVM時,需要將這些指令集“轉義”。之所以叫OVM的原因,可能很大程度為了區分EVM,表述方便。蠻多指令需要轉義,把OVM在Layer1的實現想象成虛擬機器。這些指令包括:TIMESTAMP,CALL,STATICCALL,DELEGATECALL,GASLIMIT,SLOAD,SSTORE等等。一個交易的執行從ExecuteManager的run函式開始:

     function run(
         Lib_OVMCodec.Transaction memory _transaction,
         address _ovmStateManager
     )

run函式提供了執行的交易,以及執行交易前的狀態。

StateManager實現了智慧合約以及賬戶的儲存狀態管理。ExecuteManager在執行一個交易時會透過StateManager更新狀態。

SafetyChecker檢查OVM的指令合約中的指令集是否正常,有沒有超過目前可以執行的範圍。安全性檢查透過OVM_SafetyChecker.sol的isBytecodeSafe函式實現。

     function isBytecodeSafe(
         bytes memory _bytecode
     )
         override
         external
         pure
         returns (bool)
     {

2.3 OVM/verification

verification是OVM呼叫的業務邏輯。在Layer1,只是在驗證的時候才需要透過OVM執行判斷某個交易執行是否正確。verification邏輯中包括了BondManager(抵押管理),StateTransitioner(狀態轉換管理)和FraudVerifier(錯誤狀態驗證邏輯)。FraudVerifier邏輯是最核心的邏輯。整個驗證過程的邏輯呼叫關係如下:

透過呼叫initializeFraudVerification函式,開始讓Layer1開始驗證某個交易執行後的狀態是否正確。StateTransitioner準備交易之前的世界狀態以及交易執行的中間狀態儲存。在世界狀態準備就緒後(proveContractState/proveStorageSlot),透過呼叫ExecutionManager的run函式執行交易並更新狀態。更新後的狀態透過StateTransitioner的completeTransition函式生成世界狀態。生成的世界狀態和提交的世界狀態進行對比,如果不一致,之前提交世界狀態的節點透過BondManager進行懲罰。

仔細的分析一下FraudVerifier的initializeFraudVerification和finalizeFraudVerification函式。先從initializeFraudVerification函式開始:

     function initializeFraudVerification(
         bytes32 _preStateRoot,
         Lib_OVMCodec.ChainBatchHeader memory _preStateRootBatchHeader,
         Lib_OVMCodec.ChainInclusionProof memory _preStateRootProof,
         Lib_OVMCodec.Transaction memory _transaction,
         Lib_OVMCodec.TransactionChainElement memory _txChainElement,
         Lib_OVMCodec.ChainBatchHeader memory _transactionBatchHeader,
         Lib_OVMCodec.ChainInclusionProof memory _transactionProof
     )

_preStateRoot是之前的世界狀態的Merkle樹根。透過_preStateRootBatchHeader和_preStateRootProof可以驗證某個狀態是在StateCommitmentChain上。

     require(
             ovmStateCommitmentChain.verifyStateCommitment(
                 _preStateRoot,
                 _preStateRootBatchHeader,
                 _preStateRootProof
             ),
             "Invalid pre-state root inclusion proof."
         );

_transction資訊是需要驗證的交易資訊。透過_txChainElement,_transactionBatchHeader以及_transactionProof可以驗證某個交易是否在CanonicalTransactionChain上。

         require(
             ovmCanonicalTransactionChain.verifyTransaction(
                 _transaction,
                 _txChainElement,
                 _transactionBatchHeader,
                 _transactionProof
             ),
             "Invalid transaction inclusion proof."
         );

在確定了交易以及狀態都合法後,建立StateTransitioner準備執行交易。

         transitioners[_preStateRoot] = iOVM_StateTransitionerFactory(
             resolve("OVM_StateTransitionerFactory")
         ).create(
             address(libAddressManager),
             _preStateRootProof.index,
             _preStateRoot,
             Lib_OVMCodec.hashTransaction(_transaction)
         );

執行交易的邏輯,直接忽略,感興趣的小夥伴可以看OVM_StateTransitioner.sol的applyTransaction函式。交易執行完,透過finalizeFraudVerification函式檢查執行後的世界狀態的結果。

     function finalizeFraudVerification(
         bytes32 _preStateRoot,
         Lib_OVMCodec.ChainBatchHeader memory _preStateRootBatchHeader,
         Lib_OVMCodec.ChainInclusionProof memory _preStateRootProof,
         bytes32 _postStateRoot,
         Lib_OVMCodec.ChainBatchHeader memory _postStateRootBatchHeader,
         Lib_OVMCodec.ChainInclusionProof memory _postStateRootProof
     )

先檢查提供的兩個世界狀態是否在StateCommitmentChain上存在:

       require(
             ovmStateCommitmentChain.verifyStateCommitment(
                 _preStateRoot,
                 _preStateRootBatchHeader,
                 _preStateRootProof
             ),
             "Invalid pre-state root inclusion proof."
         );

         require(
             ovmStateCommitmentChain.verifyStateCommitment(
                 _postStateRoot,
                 _postStateRootBatchHeader,
                 _postStateRootProof
             ),
             "Invalid post-state root inclusion proof."
         );

並且,保證兩個狀態是連續的:

       require(
             _postStateRootProof.index == _preStateRootProof.index + 1,
             "Invalid post-state root index."
         );

檢視OVM執行的世界狀態是否和提交的狀態一致:

         require(
             _postStateRoot != transitioner.getPostStateRoot(),
             "State transition has not been proven fraudulent."
         );

如果不一致,需要回滾世界狀態:

         ovmStateCommitmentChain.deleteStateBatch(
             _postStateRootBatchHeader
         );

並且對提交世界狀態的節點進行懲罰:

         ovmBondManager.finalize(
             _preStateRoot,
             _postStateRootBatchHeader.batchIndex,
             publisher,
             timestamp
         );

簡單的看,OVM在EVM的模擬,涉及到兩個重要的點:1/之前世界狀態的表示 2/當前交易的執行。整個邏輯涉及到多次Layer1的交易,除此之外,還需要足夠的時間保證鏈上資料能夠同步並檢查。目前,世界狀態的挑戰過程必須在相應交易後的7天內完成:

     /// The dispute period
     uint256 public constant disputePeriodSeconds = 7 days;

總結:

Optimistic Rollup是Layer2潛在的一種方案。和zk Rollup一樣,所有Transaction的資訊都會作為CallData“儲存”在Layer1。在Layer2, Optimistic Rollup透過OVM執行智慧合約,並使用“檢察”的方式確定Layer2世界狀態在Layer1的正確性。Optimistic Rollup的難點也在OVM,需要在EVM的基礎上模擬OVM的執行,並判斷狀態的正確性。目前,Optimistic Rollup的挑戰期為7天。也就是說,只有7天前的狀態是“確定”的,不會回滾。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;