化險為夷:覆盤柏林升級前以太坊一個顯而易見的狀態問題

買賣虛擬貨幣

來源 | 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提升至800gas

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

➤EXTCODEHASH從400提升至700gas

出現的問題

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) 次磁碟讀取 (xLevelDB 開銷) 來訪問一個賬戶或儲存插槽,快照可以提供直接的 O(1)訪問時間 (xLevelDB 開銷)。

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

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

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

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

➤ 離線狀態修剪

➤ 動態快照+快照同步

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

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

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

總結

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

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

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

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

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

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

➤ 柏林升級之後,有快照,25Mgas:~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/

免責聲明:

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

推荐阅读

;