前 Arbitrum 技術大使,解讀 Arbitrum 的不同元件及合約之間是怎麼交互的

作者:羅奔奔,前 Arbitrum 技術大使,極客 web3 貢獻者

封面:Arbitrum

圖片

本文是 Arbitrum 前技術大使 及 智慧合約自動化審計公司 Goplus Security 前聯合創始人羅奔奔 對 Arbitrum One 的技術解讀。

因為中文圈子裡涉及 Layer2 的文章或資料,缺乏對 Arbitrum 乃至 OP Rollup 的專業解讀,本文試圖通過科普 Arbitrum 的運轉機理,填補這一領域的空缺。 由於 Arbitrum 本身的結構太複雜,文在盡可能簡化的基礎上,還是超過了 1 萬字篇幅,所以分成了上下兩篇,建議作為參考資料收藏轉發!

圖片

Rollup 排序器簡述

Rollup 擴容的原理可以概括為兩點:

成本優化:將大部分運算與存儲任務移交至 L1 鏈下也即 L2 上。 L2 大多是運行在單台伺服器也即排序器(Sequencer/Operator)上的一條鏈。

排序器在觀感上接近於一台中心化伺服器,在「區塊鏈不可能三⻆」中捨棄「去中心化」來換取 TPS 與成本上的優勢。 使用者可以讓 L2 來代替乙太坊處理交易指令,成本比在乙太坊上交易要低得多。

圖片
(圖源:BNB Chain)

安全保障L2 上的交易內容與交易后的狀態,會同步至乙太坊 L1,通過合約來校驗 狀態轉換的有效性。  同時,乙太坊上會保留 L2 的歷史記錄,排序器即便永久宕機,他人也可以通過乙太坊上的記錄,還原出整個 L2 的狀態。

從根本上來說,Rollup 的安全性是基於乙太坊的。  排序器如果不知道某個帳戶的私鑰,就無法用該帳戶的名義發起交易,或者無法篡改該帳戶的資產餘額(即便這麼做了,也很快被識破)。

雖然排序器作為系統中樞帶有中心化色彩,但在成熟度比較高的 Rollup 方案中,中心化排序器僅能實施交易審查等軟性作惡行為,或者惡意宕機,但在理想狀態的 Rollup 方案中,有相應的手段進行遏制(比如強制提款或排序證明等抗審查機制)。

圖片
(路印協定在 L1 上的合約源碼中設置的,供使用者調用的強制提款函數)

而防止 Rollup 排序器作惡的狀態校驗方式,分為欺詐證明(Fraud Proof)和有效性證明(Validity Proof)兩類。 使用欺詐證明的 Rollup 方案稱為 OP Rollup(Optimistic Rollup,OPR),而因為一些歷史包袱,使用有效性證明的 Rollup 往往被稱為 ZK Rollup(Zero-knowledge Proof Rollup,ZKR),而不是 Validity Rollup。

Arbitrum One 是典型的 OPR,它部署在 L1 上的合約,並不主動驗證提交過來的數據,樂觀地認為這些數據沒有問題。 如果提交的數據有錯誤,L2 的驗證者節點會主動發起挑戰。

因此 OPR 也暗含一條信任假設:任意時刻至少有一個誠實的 L2 驗證者節點。  而 ZKR 的合約則通過密碼學計算,主動但低成本地驗證排序器提交的數據。

圖片
(樂觀 Rollup 運轉方式)
圖片
(ZK Rollup 運轉方式)

本文會深度介紹樂觀式 Rollup 中的龍頭專案——Arbitrum One,覆蓋整個系統的方方面面,仔細閱讀完後你將對 Arbitrum 和樂觀式 Rollup/OPR 有深刻的理解。

Arbitrum 的核心元件與工作流程

核心合約:

Arbitrum 最重要的合約包括 SequencerInbox, DelayedInbox, L1 Gateways, L2 Gateways, Outbox, RollupCore, Bridge 等。  後續將詳細介紹。

排序器 Sequencer:

接收使用者交易並進行排序,計算交易結果,並迅速(通常<1s)返還給用戶回執。 使用者往往在幾秒內就能看到自己的交易在 L2 上鏈,體驗就如同 Web2 平臺。

同時,排序器還會在乙太坊鏈下即時廣播最新產生的 L2 Block,任何一個 Layer2 節點都可以異步的接收。 但此時,這些 L2 Block 不具備最終確定性,可以被排序器回滾掉。

每隔幾分鐘,排序器會將排序后的 L2 交易數據進行壓縮,聚合成批次(Batch),提交至 Layer1 上的收件匣合約 SequencerInbox,以保證數據可用性和 Rollup 協定的運轉。 一般而言,被提交至 Layer1 上的 L2 數據無法回滾,可以具備最終確定性。

圖片

從以上流程中我們可以概括:Layer2 有自己的節點網路,但這些節點數量稀少,且一般沒有公鏈慣用的共識協定,所以安全性是很差的,必須要依附於乙太坊來保證,數據發佈的可靠性與狀態轉換的有效性。

Arbitrum Rollup 協定:

定義 Rollup 鏈的區塊 RBlock 的結構,鏈的延續方式,RBlock 的發佈,以及挑戰模式流程等一系列的合約。  注意,這裡說的 Rollup 鏈並不是大家理解的 Layer2 帳本,而是 Arbitrum One 為了施展欺詐證明機制,而獨立設置的一條抽象出來的「鏈狀數據結構」。

一個 RBlock 可以包含多個 L2 區塊的結果,而且數據也迥異,它的數據實體 RBlock 存儲在 RollupCore 的一系列合約中。 如果一個 RBlock 存在問題,Validator 將面向該 RBlock 的提交者對其進行挑戰。

驗證者 Validator:

Arbitrum 的驗證者節點其實是 Layer2 全節點的特殊子集,目前有白名單准入。

圖片Validator 根據排序器提交至 SequencerInbox 合約的交易批次 batch,來創建新的 RBlock(Rollup 區塊,也叫斷言 assertion),並監控當前 Rollup 鏈的狀態,對排序器提交的錯誤數據進行挑戰。

主動型的 Validator 需要事先在 ETH 鏈上質押資產,有時我們也稱其為 Staker。 不進行質押的 Layer2 節點雖然也可以監控 Rollup 的運行動態,向使用者發送異常報警等,但無法在 ETH 鏈上直接對排序器提交的錯誤數據進行干預。

圖片

挑戰:

基礎步驟可以概括為多輪互動式細分、單步證明。 在細分環節,挑戰雙方先對有問題的交易數據進行多輪回合制細分,直至分解出有問題的那一步操作碼指令,並進行驗證。  多輪細分-單步證明 “ 這種範式,被 Arbitrum 開發者認為是欺詐證明中最節省 gas 的實現方式。  所有環節都在合約控制之下,沒有一方可以作弊。

挑戰期:

由於 OP Rollup 的樂觀 optimistic 本質,每個 RBlock 提交上鏈後,合約並不主動檢查,預留給驗證者一段時間視窗期去證偽。  此時間視窗即為挑戰期,在 Arbitrum One 主網上為 1 周。 挑戰期結束后,該 RBlock 才會被最終確認,塊內對應的從 L2 傳遞到 L1 的消息(比如通過官方橋執行的提款操作)才能被放行。

ArbOS, Geth, WAVM:

Arbitrum 採用的虛擬機名為 AVM,包含 Geth 和 ArbOS 兩部分。 Geth 是以太坊最常用的用戶端軟體,Arbitrum 對其進行了輕量化的修改。 ArbOS 負責所有 L2 相關的特殊功能,如網路資源管理、生成 L2 區塊、與 EVM 協同工作等。 我們將兩者的組合視為一個 Native AVM,也就是 Arbitrum 採用的虛擬機。 WAVM 是把 AVM 的代碼編譯為 Wasm 後的結果。 Arbitrum 挑戰流程中,最後的那個「單步證明」,驗證的就是 WAVM 指令。

在此,我們可以將上述各個元件之間的關係和工作流用下圖來表示:

圖片

L2 交易生命週期

一筆 L2 交易的處理流程如下:

1.  使用者向排序器發送交易指令。

2.  排序器先對待處理交易進數位簽名等數據的驗證,剔除無效交易,並進行排序和運算。

3.  排序器將交易回執發送給使用者(通常都非常快),但這只是排序器在 ETH 鏈下進行的「預處理」,處於 Soft Finality 的狀態,並不可靠。 但對於信任排序器的使用者(大部分使用者),可以樂觀的認為交易已經完成,不會被回滾。

4.  排序器將預處理后的交易原始數據,高度壓縮后封裝為一個 Batch(批次)。

5.每隔一段時間(受到數據量、ETH 擁堵程度等因素影響),排序器會向 L1 上的 Sequencer Inbox 合約發佈交易 Batch。  此時可認為,交易已擁有最終性 Hard Finality。

圖片

Sequencer Inbox 合約

合約會接收排序器提交的交易 batch,保證數據可用性。 深入地看,SequencerInbox 中的 batch 數據完整記錄了 Layer2 的交易輸入資訊,即使排序器永久宕機,任何人都可以根據 batch 的記錄還原 Layer2 的當前狀態,接替故障/跑路的排序器。

用物理的方式理解,我們所看到的 L2,只是 SequencerInbox 中 batch 的投影,光源則是 STF。 因為光源 STF 不會輕易變化,所以影子的形狀只由充當物體的 batch 來決定。

Sequencer Inbox 合約又稱為快箱,排序器專門向其提交已經被預處理的交易,且只有排序器可向其提交數據。  對應快箱的是慢箱 Delayer Inbox,其功能在後續流程中會有描述。

Validator 會一直監聽 SequencerInbox 合約,每當排序器向該合約發佈 Batch 後,就會拋出一個鏈上事件,Validator 監聽到這個事件發生后,就會去下載 batch 數據,在本地執行後,向 ETH 鏈上的 Rollup 協定合約發佈 RBlock 。

Arbitrum 的 bridge 合約內有個叫累加器 accumulator 的參數,會針對新提交的 L2 batch,以及慢 Inbox 上新接收的交易數和資訊,進行記錄。
(排序器向 SequencerInbox 不斷提交 batch)
(Batch 的具體資訊,data 字段對應著 Batch 數據,這部分數據尺寸很大,截圖沒顯示完)

SequencerInbox 合約有兩個主要函數:

add Sequencer L2Batch From Origin(),排序器每次都會調用該函數向 Sequencer Inox 合約提交 Batch 數據。

force Inclusion(),該函數任何人都可以調用,用於實現抗審查交易。 這個函數的生效方式,會在後面談到 Delayed Inbox 合約時詳細解釋。

上述兩個函數都會調用 bridge.enqueueSequencerMessage(),來更新 bridge 合約內的累加器參數 accumulator。

Gas 定價

顯然,L2 的交易不可能免費,因為這樣會引來 DoS 攻擊,另外則是排序器 L2 本身的運行成本,以及在 L1 上提交數據都會有開銷。 使用者在 Layer2 網路內發起交易時,gas 費的結構如下:

佔用 Layer1 資源產生的數據發佈成本,主要來自於排序器提交的 batch(每個 batch 有很多使用者的交易),成本最終由交易發起者們均攤。 數據發佈產生的手續費定價演算法是動態的,排序器會根據近期的盈虧狀況、batch 大小、當前乙太坊 gas 價格進行定價。

使用者因佔用 Layer2 資源產生的成本,設定了一個可以保證系統穩定運行的,每秒處理的 gas 上限(目前 Arbitrum One 是 700 萬)。 L1 和 L2 的 gas 指導價格均由 ArbOS 跟蹤並調整,公式暫時不在此贅述。

雖然具體的 gas 價格計算過程比較複雜,但使用者無需感知到這些細節,可以明顯感到 Rollup 交易費用比 ETH 主網便宜的多。

樂觀式欺詐證明

回顧上文,L2 實際上只是排序器在快箱中提交的交易輸入 batch 的投影,也即:Transaction Inputs -> STF -> State Outputs。 輸入已經確定,STF 是不變的,則輸出結果也是確定的,而欺詐證明和 Arbitrum Rollup 協定這套系統就是把輸出的狀態根,以 RBlock(aka 斷言)的形式發佈到 L1 上並對其進行樂觀式證明的一套系統。

在 L1 上有排序器發佈的輸入數據,也有驗證者發佈的輸出狀態。 我們再仔細考量一下,是否有必要向鏈上發佈 Layer2 的狀態呢?

因為輸入已經完全決定了輸出,而輸入數據是公開可見的,再提交輸出結果-狀態似乎是多餘的? 但這種想法忽略了 L1-L2 兩個系統之間實際上需要狀態結算,也即 L2 向 L1 方向的提現行為,需要有對狀態的證明。
在搭建 Rollup 的時候,一條最核心的思想就是把大部分運算和存儲放到 L2 上來規避 L1 高昂的費用,這也就意味著,L1 並不知道 L2 的狀態,它僅僅説明 L2 排序器發佈全體交易的輸入數據,但並不負責計算出 L2 的狀態。

而提現行為,本質上是依照 L2 給出的跨鏈消息,從 L1 的合約裡解鎖相應資金,划轉到使用者的 L1 帳戶中或完成其他事情。

此時 Layer1 的合約就會問:你在 Layer2 上的狀態是怎樣的,怎麼證明你真的擁有這些聲明要跨走的資產。 這個時候使用者要給出對應該的 Merkle Proof 等。

圖片

所以,如果我們構建一條沒有提現功能的 Rollup,理論上不向 L1 進行狀態同步是可以的,也不需要欺詐證明等狀態證明系統(雖然可能帶來其他問題)。 但在現實應用中,這顯然是不可行的。

所謂的樂觀式證明中,合約不會去檢查提交到 L1 的輸出狀態是否正確,樂觀地認為一切都是準確無誤的。  樂觀證明系統會假設,在任意時刻都有至少一名誠實的 Validator,如果出現錯誤的狀態,則通過欺詐證明進行挑戰。

這麼設計的好處是,不需要主動驗證每一個發佈到 L1 上的 RBlock,避免浪費 gas。 實際上對於 OPR 而言,對每一個斷言進行驗證也是不現實的,因為每個 Rblock 都包含著一或多個 L2 區塊,要在 L1 上去對每筆交易重新執行一遍,與直接在 L1 上執行 L2 交易無異,這就失去了 Layer2 擴容的意義。

而 ZKR 不存在這個問題,因為 ZK Proof 有簡潔性,只需要驗證一個很小的 Proof,不需要真地去執行該 Proof 背後所對應的許多條交易。 所以 ZKR 並不是樂觀式運行,每次發佈狀態都會有 Verfier 合約進行數學驗證。
欺詐證明雖然不能像零知識證明那樣具有高度的簡潔性,但 Arbitrum 使用了一種「多輪分割-單步證明」的輪流式交互流程,最終需要證明的僅僅是單一的虛擬機操作碼,成本相對較小。

Rollup 協定

我們先來看一下,發起挑戰和啟動證明的入口,也即 Rollup 協定是如何工作的。

Rollup 協定的核心合約是 RollupProxy.sol,在保證數據結構一致的情況下,使用了一個罕見的雙重代理結構,一個代理對應兩個實現 RollupUserLogic.sol 和 RollupAdminLogic.sol,在 Scan 等工具中目前還無法很好的解析。

另外還有 ChallengeManager.sol 合約負責管理挑戰,OneStepProver 系列合約來判定欺詐證明。

圖片
(圖源:L2BEAT 官網)

在 RollupProxy 中,記錄由不同 Validator 提交的一系列 RBlock(aka 斷言),也即下圖中的方塊:綠色-已確認,藍色-未確認,黃色-已證偽。

圖片

RBlock 中包含了自上一個 RBlock 以來,一個或多個 L2 區塊執行后的最終狀態。  這些 RBlock 在形態上構成了一條形式上的 Rollup Chain(注意 L2 帳本本身相區別)。 在樂觀情況下,這條 Rollup Chain 應該是沒有分叉的,因為有分叉意味著有 Validator 提交了彼此衝突的 Rollup Block。

要提出或認同斷言,需要驗證者先為該斷言質押一定數量的 ETH,成為 Staker。 這樣在發生挑戰/欺詐證明時,輸者的質押品將被罰沒,這是保障驗證者誠實行為的經濟學基礎。

圖中右下角的 111 號藍色塊最終會被證偽,因為其父塊 104 號區塊是錯誤的(黃色)。

此外,驗證者 A 提出了 106 號 Rollup Block,而 B 不同意,對其進行挑戰。

圖片

在 B 發起挑戰後,ChallengeManager 合約負責驗證對挑戰步驟的細分過程:

1. 細分是一個雙方輪流互動的過程,一方對某個 Rollup Block 中包含的歷史數據進行分段,另一方指出是哪部分數據片段有問題。 類似於二分法(實際是 N/K)不斷漸進縮小範圍的一個過程。

2. 之後,可以繼續定位至哪條交易及結果有問題,再進一步細分至該交易中有爭議的某條機器指令。

3.ChallengeManager 合約只檢查對原始數據進行細分后,產生的『數據片段』是否有效。

4. 當挑戰者和被挑戰者定位到了將被挑戰的那條機器指令後,挑戰者調用 oneStepProveExecution(),發送單步欺詐證明,證明這條機器指令的執行結果有問題。

圖片

單步證明

單步證明是整個 Arbitrum 的欺詐證明的核心。 我們看一下單步證明具體證明的是什麼內容。

這需要先理解 WAVM,Wasm Arbitrum Virtual Machine,它是一個由 ArbOS 模組和 Geth(乙太坊用戶端)核心模組共同編譯成的虛擬機。  由於 L2 與 L1 有許多截然不同的地方,原始的 Geth 核心必須經過羽量修改,並且配合 ArbOS 一起工作。

所以,L2 上的狀態轉換其實是 ArbOS+Geth Core 的共同手筆。

圖片

Arbitrum 的節點用戶端(排序器、驗證者、全節點等),是將上述 ArbOS+Geth Core 處理的程式,編譯為節點主機能直接處理的原生機器代碼(for x86/ARM/PC/Mac/etc.)。

如果把編譯后得到的目標語言更改為 Wasm,就得到了驗證者生成欺詐證明時使用的 WAVM,而驗證單步證明的合約上,類比的也是 WAVM 虛擬機的功能。

那為什麼在生成欺詐證明時,要編譯為 Wasm 位元組碼?  主要還是因為,驗證單步欺詐證明的合約,要用乙太坊智慧合約類比出 能處理某套指令集的虛擬機 VM,而 WASM 易於在合約上實現類比。

圖片

但 WASM 相比於 Native 機器代碼,運行速度略慢,所以只有在欺詐證明生成及驗證的時候,Arbitrum 的節點/合約才會用到 WAVM。

在之前的多輪互動細分后,單步證明最終證明的是 WAVM 指令集中的單步指令。

下面的代碼中可以看到,OneStepProofEntry 首先要判定,待證明指令的操作碼屬於哪個類別,再調用相應的 prover 如 Mem,Math 等,將單步指令傳入該 prover 合約。

圖片

最終結果 afterHash 會回到 ChallengeManager,如果該哈希與 Rollup Block 上記錄的,指令運算後的哈希不一致,則挑戰成功。 如果一致,則說明 Rollup Block 上記錄的這個指令運行結果沒問題,挑戰失敗。

圖片

在下一篇文章中,我們將解析 Arbitrum 乃至於 Layer2 與 Layer1 之間處理跨鏈消息/橋接功能 的合約模組,並進一步闡明,一個真正意義的 Layer2 應該怎麼實現抗審查。

免責聲明:作為區塊鏈資訊平臺,本站所發佈文章僅代表作者及嘉賓個人觀點,與 Web3Caff 立場無關。 文章內的資訊僅供參考,均不構成任何投資建議及要約,並請您遵守所在國家或地區的相關法律法規。