化險為夷:以太坊柏林硬分叉之前存在一個嚴重的狀態問題

來源 | Ethereum Blog

作者 | Martin Holst Swende & Peter Szilagyi

Martin Holst Swende 及 Peter Szilagyi 於 2021 年 5 月 18 日發布

原標題:《化險為夷:以太坊的狀態問題

本篇博文的目的在於正式揭露以太坊平台在柏林硬分叉之前的一個嚴重且顯而易見的問題。

State 狀態

我們先從以太坊和及其“狀態”的背景開始梳理。

以太坊的狀態由 patricia-merkle trie 組成,一種前綴樹。本文不會深入技術細節,簡單來說隨着狀態增長,樹的分支會越來越密集。每個加入的賬戶都是一片新葉子。在樹根之間和葉子之間,存在大量的“中間”節點。

為了查找某個特定賬戶,或是說這顆巨樹中的一片“葉子”,從樹根再通過中間節點,需要按序解決 6-9 個哈希才能最終對我們所尋找的數據進行哈希計算。

簡而言之,每執行一次查找賬戶的 trie 查詢,都要執行 8-9 個解析操作。每次解析操作都是一次數據庫查詢,而每次數據庫查詢都可能是任意數量的實際磁盤操作。磁盤操作的數量難以預估,但是由於 trie 密鑰是加密哈希 (抗衝突),因此密鑰是“隨機的”,這對任何數據庫來說都是最糟糕的情況。

隨着以太坊的發展,一直以來都有必要提高樹訪問操作的 gas 費用。2016 年 10 月,在經歷了“上海攻擊”時間之後,以太坊網絡在區塊高度 2,463,000 進行了Tangerine Whistle 硬分叉,其中包含 EIP 150,大舉提升了某些操作的 gas 成本,並引入了大量更改以防禦 DoS 攻擊。

另一次對 gas 費用的提升是在 2019 年 12 月的Istanbul 升級中,激活了EIP 1884。

EIP-1884 針對 gas 費用引入了以下改動:

➤SLOAD 從 200 提升至 800 gas

➤BALANCE 從 400 提升至 700 gas (並添加了一個更便宜的 SELFBALANCE)

➤EXTCODEHASH 從 400 提升至 700 gas

出現的問題

2019 年 3 月,Martin Swende 當時在進行一些 EVM 操作碼性能的測定。之後的 EIP-1884 就是基於該調查而成的。在 EIP-1884 被激活的前幾個月,Broken Metre 發布了這篇論文 (2019/9)。

兩位以太坊安全研究員,Hubert Ritzdorf 和 Matthias Egli,與論文的作者之一 Daniel Perez 將一個漏洞“武器化”,提交給了以太坊的漏洞賞金 (bug bounty) 項目。這是在 2019 年 10 月 4 日。

建議大家閱讀這份他們提交的完整文檔,寫得很詳盡。

同日,在一個專門用於討論跨客戶端安全性的頻道中,來自 Geth、Parity 和 Aleth 的開發者都得知了這份文檔。

這個漏洞的本質在於觸發隨機的 trie 查詢。以下是一個簡單的示例:

化險為夷:以太坊柏林硬分叉之前存在一個嚴重的狀態問題

在其報告中,研究員們通過 eth_call 對同步了主網的節點執行了這個 payload,以下是他們執行過程中的數據,耗費了一千萬 gas:

➤ 消耗一千萬 gas 的 EXTCODEHASH (400 gas)

  • Parity: ~90s
  • Geth: ~70s

➤ 消耗一千萬 gas 的 EXTCODEHASH (700 gas)

  • Parity : ~50s
  • Geth : ~38s

顯而易見,EIP-1884 的更改確實在降低該攻擊的影響上起到了幫助,但還遠遠不夠。

當時已經臨近在大阪的開發者大會。在開發者大會上,這個問題的信息分享給了主網的客戶端開發者。我們也和 Hubert、Mathias 以及 Greg Markou (來自 Chainsafe,當時也在進行一些 ETC 的工作) 見面了。ETC 的開發者也收到了這份報告。

隨着 2019 年臨近尾聲,我們知道這個問題比之前預期的要嚴重,惡意交易可能將區塊時間提升到分鐘範圍。更糟的是,開發者社區對 EIP-1884 感到不滿,因為 EIP-1884 破壞了一些合約流程,而且用戶和礦工都非常希望提高區塊的 gas limit。

此外,僅兩個月後的 2019 年 12 月,Parity Ethereum 宣布停止運維,而 OpenEthereum 接管了代碼庫的維護工作。

隨後搭建了一個新的客戶端協調頻道,Geth、Nethermind、OpenEthereum 和 Besu 的開發者在此繼續進行協作。

解決方案

我們意識到要解決這個問題,必須要雙管齊下。一種方法是通過以太坊協議以某種方式在協議層解決該問題。最好不要破壞合約,並且避免波及“良好”行為,但仍要設法防止攻擊。

第二種方式是通過軟件工程來解決,修改客戶端中的數據模型和結構。

協議層的工作

關於如何處理這些類型的攻擊的第一個版本在這裡。2020 年 2 月,正式發布為 EIP 2583。其理念是,每當一次 Trie 查找導致未命中時,施加一次罰款。

但是,Peter 找到了應對方法,即“shielded relay”攻擊,可以有效地限制這種懲罰的上限 (約為 800)。

對未命中查詢進行懲罰的問題在於,首先需要進行查找,以確定是否施加懲罰。但是如果剩餘的 gas 不足以支付罰款,已執行了未付費的消耗。即使確實會導致拋出異常,也可以將這些狀態讀取包裝到嵌套調用中,允許外部呼叫者繼續重複攻擊而無需支付 (全部) 罰款。

因為這個原因,這個 EIP 被放棄了,我們也在尋找更好的替代方案。

➤ Alexey Akhunov 提出了 Oil 的概念,gas 的第二來源,但和 gas 在本質上不一樣,因為它對執行層不可見,並可能導致事務全局回滾。

➤ Martin 在 2020 年 5 月也撰寫了一個類似的提案 (Gas And Karma)

在對這些不同機制進行迭代的同時,Vitalik Buterin 提議直接提高 gas 成本,並且保留訪問列表。2020 年 8 月,Martin 和 Vitalik 開始完善 EIP-2929 及配套的 EIP-2930。

EIP-2929 有效地解決了許多之前的問題。

➤ 與無條件提升 gas 成本的 EIP-1884 相比,EIP-2929 只提升了未訪問部分的 gas 成本。這導致凈成本提升了不足一個百分點。

➤ 加上 EIP-2930,不會對任何合約流程造成破壞

➤ 並且能夠在不造成破壞的前提下進一步調整 gas 成本

2021 年 4 月 15 日,這兩個 EIP 都在 Berlin 升級中被激活了。

開發工作

Peter 在 2019 年 10 月提出的解決方案是“動態狀態快照” (dynamic state snapshots)。

快照是用於以平面格式存儲以太坊狀態的輔助數據結構,在 Geth 節點的實時操作期間,可以完全在線構建。快照的好處在於充當狀態訪問的加速結構:

➤ 無需通過 O(log N) 次磁盤讀取 (x LevelDB 開銷) 來訪問一個賬戶或存儲插槽,快照可以提供直接的 O(1)訪問時間 (x LevelDB 開銷)。

➤ 快照支持每項條目以 O(1) 複雜度迭代賬戶和存儲,這使遠程節點能夠以比以前便宜得多的方式檢索順序狀態數據。

➤ 快照還啟用了更多奇特的用例,例如離線修剪狀態 Trie 或遷移到其他數據格式。

快照的缺點在於原始帳戶和存儲數據實際上是重複的。對於主網來說這意味着將佔用額外的 25GB SSD 空間。

動態快照的概念從 2019 年中就已經發軔,起初的目的主要是推動快照同步的實現。當時 Geth 團隊在忙於許多“大項目”。

➤ 離線狀態修剪

➤ 動態快照+快照同步

➤ 通過分片化狀態實現 LES (Light Ethereum Subprotocol) 狀態分發

然而,最終決定將快照的優先級排到最前,將其他項目暫時擱置。這為後來的 snap/1 同步算法奠定了基礎,並於2020年3月合併。

隨着“動態快照”功能的發布,我們有了一些喘息的空間。如果以太坊網絡受到攻擊,那將是痛苦的,是的,但是至少有可能通知用戶啟用快照。完整生成快照將花費大量時間,並且當時尚無法同步快照,但是網絡至少可以繼續運行。

總結

2021 年的三月到四月,snap/1 協議在 geth 客戶端中實現了,使得通過新的基於快照的算法進行同步成為可能。雖然仍不是默認的同步模式,但這是很重要的一個步驟,使快照不僅可用作攻擊防護措施,並且對於用戶來說也是一項重要優化。

在協議方面,柏林升級於 2021 年 4 月完成。

以下是在我們的 AWS 監控環境中制定的一些基準:

➤ 柏林升級之前,無快照,25M gas: 14.3s

➤ 柏林升級之前,有快照,25M gas: 1.5s

➤ 柏林升級之後,無快照,25M gas: ~3.1s

➤ 柏林升級之後,有快照,25M gas: ~0.3s

大致的數據顯示柏林升級能夠將攻擊的效率降低 5 倍,快照能夠將其降低 10 倍,總計將影響降低了 50 倍。

我們估計目前在主網 (15M gas),對於未使用快照的 geth 節點來說,有可能創建執行時間在 2.5-3 秒的區塊。對於非快照節點來說,隨着狀態增長這個數字會持續惡化。

如果通過 gas 退還來增加區塊內的有效 gas 使用量,則可能會進一步加劇為 (最大) 2 倍。隨着 EIP 1559 的實施,區塊的 gas limit 的彈性會更大,並且在臨時爆發中會再增加 2 倍(ELASTICITY_MULTIPLIER)。

至於實施這種攻擊的可行性,攻擊者購買一整個區塊的成本約為幾個 ETH (100 Gwei 時 15M gas 為1.5 ETH)。

為什麼現在公布?

這個風險其實一直以來都是一個“公開的秘密”,已經不止一次被意外公開披露,並且在核心開發者會議中多次被提及,但並未涉及細節。

現在既然已經實施了柏林升級,geth 的節點也在默認情況下使用快照同步,因此我們估計現在的威脅性已經非常低了,現在是時候對幕後工作進行全面公開了。

重要的是,讓社區有機會了解一些變更背後的原因,而這些變更會對用戶體驗造成負面影響,例如 gas 成本增加和限制 gas 返還。

本文由 Martin Holst Swende 和 Peter Szilagyi 在 2021-04-23 寫就。並於 2021-04-26 與基於以太坊的項目進行分享,2021-05-18 公開發布。

點擊“閱讀原文”獲取文章內部鏈接!

原文鏈接:https://blog.ethereum.org/2021/05/18/eth_state_problems/

本文鏈接:https://www.8btc.com/article/6638245

轉載請註明文章出處

(0)
上一篇 2021-05-21 13:19
下一篇 2021-05-21 13:59

相关推荐