以太坊 layer2: optimism 源碼學習 (一)
作者:林冠宏 / 指尖下的幽靈。轉載者,請: 務必標明出處。
GitHub : //github.com/af913337456/
出版的書籍:
前序:
對於區塊鏈每個階段的風口產品,我都會挑選其中某個研究其源碼,當作學習並增加經驗。早前看的是
zkSync
,難度巨大而能力有限,遂轉於Optimism
。
本次是系列文章,這是第一篇。
這裡就不說什麼是 Layer2 了,可以去網路搜索其它文章來閱讀。在 Layer2 的擴容方案中目前有 3 種,Rollups
是其中一種,稱為打包
。打包又分兩大派別:
- 樂觀打包,Optimistic rollups;
- 零知識打包, ZK rollups。;
這兩派的風格各異,特點突出。Optimistic rollups
對智慧合約
的支援可以說是完全兼容,而 ZK rollups
目前對智慧合約支援不友好,但是在交易提款
上鏈這塊非常快、更安全卻計算量巨大,技術難度複雜。關於它們的對比
,我後續再寫篇文章詳細說說
目錄:
- Op 簡介
- Op 的程式組件
- 如何使用 Op
- 源碼分析 — 充值與提現
- L1 合約層源碼
- L2 層源碼
- 提現
1. 正題,Op 簡介
Layer2 是公鏈下的第二層。比如Android系統下的底層軟體。
Optimism,下面簡稱 Op,是基於 Optimistic rollups
方案所實現的 Layer2 應用,下面簡稱 L2。作用是幫助 以太坊
擴容以及加速交易。
特點如下:
- 提款到 Layer1 的周期,約一周。下面簡稱 L1;
- 速度,L2 內交易,極快,手續費很低;
- 通用性,EVM 兼容,基於以太坊的修改
- 技術複雜度,簡單;
- 鏈下成本,低。鏈上成本,高;
- 交易安全保證,基於默克爾樹–樹根哈希的
欺詐證明
; - 源碼://github.com/ethereum-optimism/optimism
2. Op 的程式組件
雖說 Op 是個 L2 應用,但它的組成程式組件非常多。我這裡列出會和我本文內容相關的組件:
合約
,這些會被部署在 L1 公鏈上面,由 L2 組件或用戶來調用,包含不限於有:L2 側鏈
,基於 geth 源碼改造的鏈,運行在 Op 生態里;L1StandardBridge.sol
垮鏈橋合約,用來處理充值 Token 到 Op 地址或從 Op 地址提現到 L1 地址 所用;CanonicalTransactionChain.sol
規範處理L2 --> L1
的交易,下面簡稱CTC
;L1CrossDomainMessenger.sol
跨鏈信使合約,裡面主要編寫進行了各種要觸發跨鏈事件的函數。
DataTransportLayer
,定時掃描 L1 區塊,從中獲取到TransactionEnqueued
事件,並存儲到LevelDB
資料庫;Sequencer
:- 接受用戶發來 L2 的交易;
- 定期從資料庫中獲取
DataTransportLayer
存儲的TransactionEnqueued
事件數據,並把交易在 L2 鏈中執行,使之正常被打包到 L2 區塊中;
Batch-Submitter
,定期從 L2 區塊中將交易數據以打包的形式組裝到交易:- 打包批量交易
txBatch
提交到 L1 的CTC
合約; - 打包批量狀態
stateBatch
提交到 L1 的StateCommitmentChain.sol
- 之後這些交易進入
等待挑戰
窗口,挑戰方式就是欺詐證明
;
- 打包批量交易
Relayer
,定時從 L2 區塊中過濾交易中的SentMessage
事件數據:- 判斷當前交易是否過了挑戰時間;
- 為此交易生成證明,調用 L1 上的
L1CrossDomainMessenger.relayMessage
函數,使之完成合約檢查
然後在內部調用目標合約,最終在 L1 完成 L2 交易的最終目的;
它們的組合通訊流程圖如下:
注:
目前所有的 Op 組建,都由官方運行著,欺詐證明還在完善。用戶必須要相信官方不會做惡。
3. 如何使用 Op
使用 Op 網路分兩種情況:
- 直接使用原生 Token 進行交易,即以太坊,那麼:
- 需要先在 L1 訪問
L1StandardBridge.sol
進行充值到 Op; - 充值結束後,到賬了,可以進行 Op 網路內的交易活動;
- 提現到 L1 的地址;
- 流程到這裡閉環
- 需要先在 L1 訪問
- 其他協議,比如 ERC-20:
- 先去 Op 網路部署對應的合約;
- 在 L1 的
L1StandardBridge.sol
充值 Token 到 L2 地址; - 到賬後,便可自由交易。提現動作和 ETH 的一樣。
4. 源碼分析 — 充值與提現
充值部分 — L1 合約層源碼
按照流程,用戶需要調用 L1 上的 L1StandardBridge.sol
智慧合約充值,如下圖所示:
注意,payable
就是 solidity 語法中標明可以接收 ETH 的語法糖。此時充值 ETH 到了 Op 的 L1StandardBridge 跨鏈橋合約中。
上圖,函數走完了,都沒有痕迹告訴我們如何在為 L2 的地址充值了 ETH,我們只需要留意其中的 IL2ERC20Bridge.finalizeDeposit.selector
這一行。這裡設置了一個 L2 到時需要調用的函數。
上圖,結合我們前面的結論 DataTransportLayer
,會定時掃描 L1 區塊,從中獲取到 TransactionEnqueued
事件,並存儲到 LevelDB
資料庫。
所以在 _sendXDomainMessag
內部,最終會觸發 emit TransactionEnqueued
事件。L1 層面的閉環結束
ERC-20 的充值也是一樣的,只是函數不一樣。如下圖:
// TransactionEnqueued 事件在 enqueue 內發生
function _sendXDomainMessage(
address _canonicalTransactionChain,
bytes memory _message,
uint256 _gasLimit
) internal {
// slither-disable-next-line reentrancy-events
ICanonicalTransactionChain(_canonicalTransactionChain).enqueue(
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
_gasLimit,
_message
);
}
充值部分 — L2 層源碼
在這裡我們主要看 Sequencer
的是如何執行 TransactionEnqueued
中的交易到 L2 的。
在 Sequencer
的啟動中,首先是它會進入一個定時從資料庫中獲取交易的函數,如下圖所示:
接下來的調用鏈是: s.sequnece --> syncQueueToTip --> syncQueue --> syncQueneTransaction
如下圖所示,在 syncQueneTransaction
中,調用 GetEnqueue
從遠程介面即 DataTransportLayer
服務中獲取目標交易數據。最後執行 applyTransaction
執行交易
回到前面合約層的 IL2ERC20Bridge.finalizeDeposit.selector
這一句,最後交易的執行會走到 L2 合約層的 L2ERC20Bridge
合約的 finalizeDeposit
函數,如下圖所示,最終 mint 操作完成充值流程,至此閉環。
提現
內容比較多,提現留給下一篇。持續關注