事件經過
臺北時間 2020 年 11 月 11 日下午,以太坊社區知名的節點服務 Infura 被曝出 API 服務出錯,并因此導致了多個依賴于 Infura 來構建的服務的崩潰,或者前端顯示不正確,
就 Infura 自身而言,可以把它理解為一個公開的以太坊節點,這個節點會接收請求并返回一定的服務,比如幫忙轉發交易、比如檢查某筆交易上鏈了沒有,又或者某個賬戶的狀態如何,實際上,只要自己部署一個以太坊節點,就能提供跟 Infura 同樣的服務。但它的特殊性在于,Infura 的大部分服務都是免費的,因此很多服務(包括交易所)都選擇了依賴 Infura 來向自身播報以太坊區塊鏈的狀態,免去了自己部署節點的麻煩。
也正因此,Infura 出錯,理論上波及面會很廣,在事件發散的過程中,甚至還有人揚言 “以太坊會分叉(或者正在發生分叉)”。理由是兩個不同的區塊瀏覽器(Etherscan 和 Blockchair)上,對同一個塊高顯示了兩個不同的區塊(但是這兩個區塊之后的區塊,兩個瀏覽器的顯示是一致的)。
但很顯然,以太坊根本沒有分叉。從事實上來說,兩個區塊瀏覽器所顯示的后續區塊都是相同的,這表示出塊的礦工(至少是大部分礦工)沒有以兩個不同的區塊為父塊來繼續挖礦,也沒有彼此拒絕對方的區塊,從理論上來說,只有出塊的節點彼此之間使用了不同的共識規則(因此會拒絕對方所出的塊),且都占據了一定的算力,才有可能形成分叉,
事實上,人們很快就發現了,這是因為 Infura 沒有運行最新版本的 Geth 客戶端,而某些特殊的交易觸發了這個版本的客戶端的 bug,使之宕機了。Blockchair 也是同理。所以很快就有人出來呼吁大家盡快升級 Geth 客戶端。
至臺北時間 11 日 18 時,Blockchair 團隊的 Nikita Zhavoronkov@nikzh 發表推特,解釋事件的因果關系:
- 以太坊開發者某一次對代碼的更改導致了當日以太坊區塊鏈的分裂,分裂自區塊高度 11234873 開始;
- 沒有更新客戶端的服務商,包括 Blockchair 和 Infura,就因此受害,被留在了一個少數人組成的鏈上(該鏈在 2 小時內出了 30 個塊)
- 從技術上來說,這意味著發生了一次 “未公開的硬分叉(unannounced hard fork)”
- 修復措施是升級 geth 客戶端并運行 debug.setHead(11234872)
他還表示,這件事絕不該被低估,應該被認為是 The DAO 事件之后,以太坊區塊鏈上最嚴重的一次事故。確實很奇怪,為什么會有某個錯誤僅僅導致軟體在某個時間以前的歷史版本崩潰而現有版本不崩潰?這豈非意味著,不同版本的 geth 客戶端的共識規則實際上不一樣,也就是某時某刻發生了一次不能向后兼容的共識規則改變(“硬分叉”)?此外,一個 Infura 的崩潰就導致了大面積的服務出錯,這是否意味著 Infura 已經成了一個 “單點故障” 來源?
緣由
針對上面的兩個問題,Geth 客戶端團隊的領導者 Péter Szilágyi@peter_szilagyi 都有回應,
- 從技術上來說,的確可以說是發生了 “未公開的硬分叉”,但這只是因為開發人員修復了一個沉睡了兩年多的 bug,而因為擔心公開披露這個 bug 會導致以太坊遭到攻擊,所以選擇了靜默修復。
- 人們也不該鄙視 Infura 沒有使用最新的 Geth 客戶端,從運營者的角度,不緊跟軟體的最新版本是理性的,而依賴于 Infura 的服務,是自己把這個權利交出去了,而不是別人禁止了你運行節點,所以也沒什么可抱怨的。
Peter 的回應也引起了不同的反應,一位門羅社區的人表示,在 2017 年,他們也曾因為同樣的顧慮而選擇了靜默修復 bug。當然,也有人認為,選擇靜默修復是對的,但至少應該通知大型基礎設施的提供者,只要聯系了,就能大幅減少這一漏洞所造成的破壞。
臺北時間 12 日凌晨 5:34,Peter 發布了《Geth v1.9.17 客戶端所造成破壞的事后報告》,定位了問題的來源:發布于 2019 年 11 月 7 日的 Geth v1.9.7 錯誤實現了 EIP-211;John Youngseok Yang 在 2020 年 7 月 15 日報告了該問題,于是 Geth 團隊在 7 月 20 日更新的 v1.9.17 版本中修復了這個問題,該次修復使得 Geth 客戶端在執行涉及相關規則的交易時能跟其他以太坊客戶端(如 Besu、Nethermind)相一致,但卻使 v1.9.17 版本與歷史版本的 Geth 發生了不一致,
如 Peter 所述,這個過程完全不是為了引入某個以太坊社區不知道或者不同意的共識規則,僅僅是因為寫了 bug 所以必須修復 bug,除非你管寫了 bug 也叫 “硬分叉”,否則就沒有理由管修復 bug 叫 “硬分叉”(Nikita 顯然不同意這一點,他表示這里就是發生了兩次,而不是一次,硬分叉)。
其次,到底怎么發布修復,實際上并不簡單。以太坊的硬分叉協調也需要很長時間,如果公開一個帶有嚴重危險性的 bug,在各節點升級的過程中難保不會有人嘗試攻擊,作為客戶端開發者,他考慮的更多是以太坊網路的安全性,而不是某個服務的安全性,而且,他們也并不是對所有的 bug 都采取同樣的靜默修復措施,很多都是公開修復的。
12 日上午 7:11,Optimism 團隊的 Jing is hiring for Optimism@jinglanW 出來披露了更多資訊:他們在 6 個月前復制了 Geth 客戶端的代碼庫來研究和開發 Optimistic Virtual Machine,在該過程中,他們發現了一個神秘的 bug,也修復了該 bug,但一直無法定位其來源;他們一直以為,這個 bug 可能跟團隊引入的定制化改進有關,但 11 號他們開始懷疑錯誤就存在于舊版的 geth 客戶端中,而不是因為他們引入了一些改進,于是他們看了 ethernodes.org 顯示的節點分布(并發現絕大多數節點已經升級)之后,就決定在主網上測試該 bug。因此有了后面的事情。
所以,實際上,是 Optimism 團隊發現了一個 bug,草率地決定在主網上測試該 bug 還存不存在,再加上 Geth 團隊此前選擇了靜默修復該 bug,才使得某些沒有及時升級的節點出錯了,
該如何理解和看待這件事情呢?
就事情的本因來看,這是因為客戶端團隊選擇了靜默修復一個沉睡了許久的 bug。雖然很多人認為 geth 團隊可以通過聯系基礎設施提供者來降低破壞,但我在這里還是認為,我們應該給客戶端開發人員更多的信任和尊重。我相信 Geth 客戶端團隊這么做是有理由的,他們知道絕大部分節點都在使用自己的軟體,也考慮了 bug 的沉睡時間,因此選擇了靜默修復,從事后諸葛亮的角度,當然提前通知了大的基礎設施提供者會更好,破壞會更少。但是,這樣吹毛求疵合理嗎?為什么依賴于 Infura 的服務不假設 Infura 可能崩潰?
我承認我在這里不太公正,但更公正的話,也有很多人已經說過了,我在此只想表達我對 geth 客戶端團隊的敬意,我愿意把印象分給他們,因為他們在過去提供了許許多多的工作量證明,他們值得大家的尊敬。
在靜默修復措施的執行上,當然存在提高的空間,也應該跟包括門羅和比特幣社區學習經驗。但如果只想著譴責 geth 團隊,乃至以陰謀論來揣度他們,那才是更大的不公正,
關于 “Infura 是否成為了單點故障的來源”,也分簡單的回答和復雜的回答,簡單的回答是,不是,因為就像 Peter 所說,從來沒有人禁止你部署節點,只是很多提供商自己選擇了外包。Infura 不是設計層面上必須經過的一個單點。只是因為各種各樣的原因,它成了可能是最大的節點服務提供商。
但復雜的回答是,以太坊節點的資源消耗比較大,確實是一個被低估的問題。以太坊協議的運行需要各節點完全執行區塊中包含的交易,而執行交易必須從狀態數據中取出數據、并且完成后也要將結果寫入,這個過程會涉及大量的硬碟隨機讀寫。而且,隨著狀態數據體量的擴大,讀寫的效率要求也會提高,前些年熱議的 “狀態膨脹” 問題,在當前的以太坊上還沒有解決。運行節點的門檻高,節點的數量自然就少。從善意的角度看,如果以太坊節點的運行門檻降低,我相信會有更多人自建節點(畢竟更安全),而不是選擇依賴于 Infura,
但這個問題的解決,同樣依賴于以太坊客戶端開發者和研究人員的智慧,無狀態性,可以說是解決狀態膨脹問題的終極方案。而在終極方案變得可行之前,我們仍然需要客戶端開發者,為我們貢獻更高效率的客戶端,
所以,確實發生了一件事,也確實暴露出了一些問題、指出了我們學習和進步的方向。但解決這些問題,離不開我們對社區中不同團體的理解和尊重,遠離陰謀論,遠離惡意和自作聰明的嘲諷,弄清楚問題的根源,思考其實質和改進方案。我們做的事情,才決定了我們是誰,