Ethereum 效能瓶頸與改善方案
本文將介紹 Ethereum 的效能瓶頸以及將交易執行從共識中拆分出去如何能提升效能。
先備知識包含
- TPS、Gas Limit
- 區塊鏈(Bitcoin、Ethereum)的運作:節點、網路、區塊、EVM
- 知道 Sharding 和 Rollup 的概念
Ethereum 的效能?
大家對區塊鏈比較熟悉的效能指標是每秒交易數量,Transactions Per Second(TPS),例如 Bitcoin 的 TPS 是 7,平均每秒處理 7 筆交易。如果把這個指標套用到 Ethereum 上,會以當前的 Gas Limit(30m)、單純轉帳的 Gas Cost(21k)、區塊時間 12 秒來計算:30m/21k/12 ≈ 119 TPS,平均每秒處理 119 筆轉帳。但 Ethereum 會單純用來轉帳嗎?隨著在 Ethereum 上開發的應用越來越多,絕大多數的交易不是單純的轉帳,因此這也是為什麼 TPS 不適合用來當作 Ethereum 的效能指標。
不過今天的重點不會放在區塊鏈該用哪一個效能指標,而是介紹 Ethereum 效能的瓶頸及如何突破這個瓶頸。所以我們姑且繼續用 TPS 來衡量 Ethereum 的效能。
調整協議參數來增加 TPS?
在往下介紹瓶頸和解決方法之前,要先介紹一下在設計解決方法時需要考慮的一個重點(尤其是對 Ethereum 來說) — 中心化程度。
很多人會有疑問,為什麼不把 Gas Limit 往上調就好了,這樣每個區塊不就可以收入更多交易了嗎?或是為什麼不把區塊時間縮短?網路有這麼慢嗎?需要 12 秒的時間來確保新的區塊有足夠時間被送到網路的各個角落?
你可以不斷去上調 Gas Limit,讓你的鏈能處理更多交易,但隨著交易越來越多,節點同步區塊會耗時越來越久,最後能跟上的節點會越來越少,節點也就越來越中心化。
同樣的道理也適用在縮短區塊時間上,把區塊時間縮短成 5 秒、3 秒,最後留下來的都是網路速度快的,甚至是地緣近的節點群組。
除了普通人自己運行的節點跟不上的影響外,Solo 的礦工也會越來越少,因為負擔不起更快的網路、處理速度更快的機器,最終收益下滑導致他離開網路或加入礦池,同樣也造成節點中心化。
目前的區塊時間及 Gas Limit 都是有經過計算和評估的,可以看 Vitalik 的解釋。
Ethereum 的效能瓶頸
一條區塊鏈由很多元件組成:共識、網路、交易驗證,也因此有很多影響效能的因素。是達成共識的速度太慢?還是網路傳輸的速度太慢?還是交易驗證的速度太慢?對 Ethereum 來說,最大的效能瓶頸不是達成共識的速度,也不是網路傳輸的速度,而是交易驗證的速度。
註:這個瓶頸也適用其他「EVM 兼容鏈」,不論你今天共識演算法有多厲害、每秒可以達成多少 TPS,只要你交易驗證包含 EVM 執行,你的整體效能就一定快不過 EVM 執行的速度。
如果不能調整協議參數,不如調整節點規格?
前面段落有提到協議參數設定的依據,並不是調整協議參數就能無後顧之憂地增加 TPS。那不如反過來調整節點規格?
如果今天瓶頸是網路速度,那直覺就是假設節點網路速度要夠快就好了;如果今天瓶頸是硬碟讀取速度,那就假設節點都有夠大夠快的硬碟不就好了?但它們的代價都是一樣的:越來越少節點能夠符合規格,網路的節點就會越來越少、越來越中心化。
註:當然這還是看人取捨,你可以說你的網路只要有 21 個節點就夠去中心化了、你可以說硬體升級的速度會比節點負載上升的速度還快,所以不用擔心超負荷,但 Ethereum 一路走來一直都是以追求最大化地去中心化為目標,如果要讓越多節點能順利同步區塊,就不能隨意拉高節點性能的假設。
接下來要進入正題,介紹提升效能的其中一個方法:將交易執行從共識拆分出去。
將交易執行從共識拆分出去
為什麼效能會被交易驗證速度綁住?因為我們要親自執行過每一筆交易,確認交易是合法的、別人的執行結果和我的執行結果是一樣的,才收入這筆交易、這個區塊,才達成共識。也就是共識和交易執行是綁在一起的。這就導致了即便你的共識演算法一秒可以對 1000 筆交易達成共識,你實際上 TPS 卻只有 100,因為你節點一秒就只能執行、驗證 100 筆交易。
註:在意識到瓶頸出在 EVM 的效能後,當然最先想到的就是要換一個更快的 VM,也就是幾年前還經常聽到的 EWASM — Ethereum + WebAssembly,但後來研究方向已經轉往其他地方。
如果我們把共識和交易執行拆開:驗證節點在收到一筆交易時不再執行該筆交易,而是單純檢查交易發起人有沒有足夠的錢來支付把他的交易資料收進區塊裡的費用。當節點不需執行交易,效能就不再受到交易執行效能的限制,也就是 EVM 的限制。在這個模型下,PoW 礦工或 PoS 驗證者都可以專注在對「交易資料」達成共識,不需煩惱「交易執行」,這時候 TPS 就只受限於共識達成的速度或是網路傳輸的速度。
單純對「資料」達成共識,而不是對「執行結果」達成共識。
註:什麼是把交易資料收進區塊裡的費用?想像一個區塊可以裝任意資料:塗鴉或到此一遊的訊息都可以,但區塊大小不是無上限,而是 1 MB,因此每一筆交易都要支付手續費來爭取被收進區塊的權利,且交易資料越大手續費越高。(不能讓任何人都可以零成本地丟資料上去,這不是 IPFS。)
你可能會覺得很奇怪,如果節點都不執行交易,誰來告訴我我剛剛拿 300 USD 到 Uniswap 上去換,到底換到多少 ETH?其實這樣的模式並不是要套用在目前你熟悉的 ETH1 中的。在介紹這樣的模式要怎麼實現之前,先快速複習一下 Sharding 和 Rollup。
Sharding
在 Sharding(ETH2 的其中一部分)中,Beacon Chain(以下簡稱 BC) 的區塊會收入各條 Shard Chain(以下簡稱 SC)的區塊資訊,所以當 BC 驗證者對 BC 的區塊達成共識,也就同時對 SC 的區塊達成共識。
Rollup
Rollup Sequencer 把交易打包送到 L1 上,利用 L1 的安全性,確保交易的排序。只要 L1 沒有被攻擊、沒有 re-org,就可以確定交易順序沒有改變。只要確定了交易順序,任何人都能獨自算出當前 Rollup 的狀態。
假設初始狀態是 A 有 10 元,B 有 5 元,C 有 0元,你知道目前有三筆交易且交易排序是:
Tx1: A →$5 → C
Tx2: B →$2 →A
Tx3: C →$3 →A
則你一定可以算出最新的狀態是 A有 10 元,B 有 3元,C 有 2元。
雖然 Rollup 並不是真的將共識及執行拆開(Rollup 的 Sequencer 還是要執行過交易才會決定要不要把交易收進區塊),但有一個相似的地方是:Rollup 的交易對 L1 來說是沒有意義的。L1 驗證者只負責收入 Rollup 交易進區塊裡而不會實際執行它,Rollup 節點才會挑出屬於他 Rollup 的交易並執行。
Sharding + Rollup
Shard Chain 將會成為放置 Rollup 交易資料的鏈(如同今天 Rollup 的交易是放在 L1 區塊裡),再由 BC 對 SC 區塊達成共識,確保 SC 區塊裡的交易排序。Rollup 再從 SC 區塊中挑出自己的交易來執行。
Execution Environment / Execution Layer
從 Sharding 和 Rollup 的例子可以看到,BC 或 L1 的驗證者是針對資料(Data)達成共識,他們不會去解讀這些 Data,而是交給 Rollup 自己去解讀。Rollup 的角色在這個模式裡就稱為 Execution Environment 或是 Execution Layer:負責解讀 Data,例如把 Data 解讀成一筆 Uniswap 交易然後執行。
不同 Rollup 有各自的協議設計:Optimism 有自己的 VM、自己的收費方式,Arbitrum 也是,StarkNet 也是,zkSync 也是,但他們都是透過 L1 的安全性來確保交易順序,再以各自的協議去依序解讀 Data、執行交易。他們各自的協議就如同不同的 Execution Environment。
回到前面提到的問題:誰來告訴我我的 300 USD 在 Uniswap 上換到多少 ETH?答案是 Rollup 節點而不是 L1 節點或 SC 節點,因為在共識和交易執行拆分的設計底下,L1 或 SC 只是用來存放資料的。
Celestia
最後想要介紹一個以「共識、執行分開」的概念為核心的鏈 — Celestia。Celestia 驗證者對 Celestia 區塊達成共識,這個區塊裡面所包含的資料要怎麼解讀,則交給 Execution Layer(就像 Rollup 解讀 L1 或 SC 的資料),對一個 Execution Layer 來說,一個 Celestia 區塊裡包含的資料可能有意義,也可能沒有意義(沒意義則忽略它)。
Celestia 看起來就很像 ETH2 裡 BC + SC + Rollup 的組合,但除了它沒有 Sharding 的設計之外(Sharding 是好是壞目前還是見仁見智),它還有內建 Data Availability 機制,確保區塊資料(Data)是可取得的,否則空有 Execution Layer 但拿不到 Data,還是沒辦法執行。
Special thanks to Chih-Cheng Liang, Ping Chen, Kevin Chia and Chang-Wu Chen for reviewing and improving this post