撰文:Dankrad Feist,以太坊基金會
編輯:南風
特別感謝Vitalik Buterin, Hsiao-Wei Wang 和Caspar Schwarz-Schilling 的反饋和評論。
摘要:出於安全性和可活性的考慮,以太坊選擇了多客戶端架構。為了鼓勵質押者(Stakers) 客戶端設置的多樣化,以太坊協議針對關聯性故障(correlated failures)的懲罰是更高的。因此,對於運行一個市場份額佔少數的客戶端的質押者而言,如果該客戶端出現bug,那麼該質押者通常只會損失適度的金額,而如果該質押者運行一個市場份額占主導性地位的客戶端,那麼在該客戶端遭遇bug 時該質押者將可能遭遇損失全部的質押金。因此,負責任的質押者應該審視當下的客戶端分佈格局,並選擇運行一個不那麼流行的客戶端。
01. 為何我們需要多個客戶端?
有許多論點認為,單一客戶端架構更加可取。開發多個客戶端會帶來巨大的開銷,這就是為什麼我們還沒有看到任何其他區塊鍊網絡認真地追求提供多客戶端的原因所在。
那麼,為什麼以太坊的目標是多客戶端架構呢?客戶端是非常複雜的代碼,可能包含bugs。其中最糟糕的是所謂的“共識bugs”,即區塊鏈核心狀態轉換邏輯bugs。一個經常被引用的例子就是所謂的“無限貨幣供應” bug,出現這種bug 的客戶端將接受(認可) 一筆鑄造任意數量的ETH 的交易。如果某人在某個客戶端中發現了這種bug,而且在此人抵達安全出口(即通過混合器或交易所來使用這筆資金) 之前未被阻止,那麼這將導致ETH 的價值大幅縮水。
如果每個人都運行相同的客戶端,停止這情況將需要人工干預,因為在這種情況下,區塊鏈、所有智能合約和交易所將照常運行。攻擊者甚至可能僅需要幾分鐘時間就能成功地發起一場攻擊,並充分地將資金分散,使得只回滾該攻擊者的交易變得無法實現。根據被鑄造的ETH 數量,以太坊社區將很可能協調將以太坊回滾至此次攻擊發生之前的狀態(這需要在確定和修復該bug 之後進行)。
現在讓我們看看當我們有多個客戶端時會發生什麼。有兩種可能的情況:
包含該bug 的客戶端承載著少於50%的網絡總質押金。該客戶端將生產出一個這樣的區塊,該區塊中包含了一筆利用該bug 來鑄造ETH 的交易。讓我們稱這條鍊為A 鏈。
然而,絕大多數運行另一個不存在該bug 的客戶端的質押者將忽略該區塊,因為該區塊是無效的(對於該客戶端而言,這筆鑄造ETH 的操作就是無效的)。因此,運行該客戶端的質押者(驗證者) 將構建另一條鏈,我們稱之為B 鏈,這條鏈不包含這個無效的區塊。
由於正確的客戶端占主導地位,B 鏈將累積更多的證明(attestations)。因此,即便那個有共識bug 的客戶端也會投票給B 鏈;其結果是,B 鏈將會累積100% 的投票,而A 鏈將會消亡。區塊鏈將繼續前進,就好像該bug 從未發生一樣。
絕大多數質押者使用了這個有bug 的客戶端。在這種情況下,A 鏈將累積絕大多數投票。但由於B 鏈僅擁有不到50% 的證明,因此那個有bug 的客戶端永遠也不會有理由從A 鏈切換至B 鏈。因此,我們將看到區塊鏈分裂。如下圖所示:
上述第一種情況是理想的情況。這種情況很可能會產生一個孤塊(orphaned block),大多數用戶不會注意到該孤塊。開發者可以調試客戶端,修復該bug,一切都很好。第二種情況顯然並不理想,但相比於總共只有一個客戶端(即單一客戶端架構) 而言,這仍然是一個更好的結果,大多數人將很快發現有了一條分叉鏈(你可以通過運行幾個客戶端來自動監測到),交易所將很快暫停存款,DeFi 用戶在鏈分裂被解決之前也可以謹慎行事。基本上來說,與單一客戶端架構相比,這仍然給了我們一個大的閃爍的紅燈警告,允許保護我們免受最壞的結果。
上述第二種情況中,如果這個有bug 的客戶端是由超過2/3 的質押者運行,那麼這種情況將更糟糕,因為該客戶端將會敲定那條無效的鏈(即A 鏈)。對此我們將在下文更多地闡述。
有些人認為鏈分裂是如此災難性,以至於這本身就是作為支持單一客戶端架構的論據。但是請注意,鏈分裂只是由於客戶端中的一個bug 而發生的。就單一客戶端架構而言,如果你想要修復這個bug 並將區塊鏈返回至之前的狀態,那麼你必須回滾至該bug 發生之前的區塊,而這與鏈分裂一樣糟糕!所以,就多客戶端架構而言,儘管鏈分裂聽起來很糟糕,但在客戶端出現嚴重bug 的情況下,鏈分裂實際上是一個特性,而不是一個bug。至少你能知道發生了嚴重的問題。
02. 激勵客戶端多樣性:反相關性懲罰
如果驗證者的質押金被分配到多個客戶端上,這顯然對網絡有利,最好的情況是每個客戶端持有的質押金少於總質押金的1/3。這將使得網絡在面臨任何單個客戶端bug 時都具有彈性。但質押者為什麼要在意這一點呢?如果網絡對於質押者沒有任何激勵機制,那麼他們不太可能願意承擔切換至另一個少數派客戶端產生的成本。
不幸的是,我們不能直接基於驗證者選擇運行哪個客戶端來對其進行獎勵。沒有一種客觀的方法來衡量這一點。
然而,當你運行的客戶端發生了bug 時,你不能倖免。這正是反相關性懲罰(anti-correlation penalties)起作用的地方:其中的理念是,如果你運行的驗證者進行了惡意行為,那麼你將受到的懲罰將會因為有更多其他驗證者在大約同一時間犯了錯誤而變得更高。換句話說,你會因為關聯性故障而受到懲罰。
在以太坊中,你(驗證者) 會因為兩種行為而被罰沒(get slashed):
在同一個區塊高度簽名兩個區塊。
創建可被罰沒的證明(環繞投票或雙重投票)。
當你(驗證者) 被罰沒時,通常不會損失所有的資金。在撰寫本文時(信標鏈Altair 分叉),默認的懲罰實際上是非常小的:你只會損失0.5 ETH,也即大約是你質押的32 ETH 的1.5%(最終這會增加到1 ETH,也即3%)。
然而,這裡有一個問題:有一個額外的懲罰,取決於你的驗證者被罰沒之前和之後的4096 個epochs (大約18 天) 時間內的所有其他罰沒事件。在此期間,你將受到與這些罰沒總額成比例的罰沒。這可能比最初的懲罰要大得多。目前(信標鏈Altair 分叉)是這樣設置的,如果在此期間(你被罰沒之前和之後的18 天內)有超過50% 的全部質押金額被罰沒了,那麼你將損失你的全部資金。最終,這將被設置為如果1/3 的質押者被罰沒,那麼你將損失你的所有質押金。之所以設置為1/3,是因為這是導致一次共識失敗的最少質押金數額。如下圖所示:
上圖:藍線表示當前(信標鏈Altair 升級之後) 的懲罰;紅線表示最終將設置的懲罰。
另一個反相關性懲罰:Quadratic Inactivity Leak
驗證者失效的另一種方式是離線。驗證者離線也是會受到懲罰,但此機制非常不同。我們不將這種懲罰稱為“罰沒”(slashing),而且這種離線的懲罰通常是很輕微的:在正常操作下,離線的驗證者會受到的懲罰金額,與他們在這段時間通過正確地驗證本來可以獲得的獎勵相當。在撰寫本文時,驗證者的年收益率是4.8%。如果你的驗證者離線了幾小時或幾天(例如由於暫時的互聯網中斷而離線),那麼可能沒什麼可緊張的。
但是,如果當超過1/3 的驗證者離線時,情況將變得完全不同。此時,信標鏈將無法敲定區塊,這威脅到了共識協議的一個基本屬性,即活性(liveness)。在這樣的場景中,要恢復信標鏈的活性,就要使用所謂的“quadratic inactivity leak”機制。如果驗證者在區塊鏈停止敲定的同時還在繼續離線,那麼該驗證者將受到的懲罰將隨著時間呈二次方增長。最初這種懲罰是非常低的;在大約4.5 天之後,離線的驗證者將損失1% 的質押金。然而,在大約10 天之後,將損失5% 的質押金,大約21 天之後將損失20% 的質押金(這些是當前信標鏈Altair 設置的值,這些值將在未來翻倍)。如下圖所示:
這種機制的設計是為了在發生一場災難性事件導致大量驗證者離線的情況下,使得區塊鏈能夠盡快恢復敲定區塊。當離線的驗證者損失越來越多他們的質押金時,他們將逐漸被踢出網絡,從而在驗證者總數中所佔的份額越來越小,當這些離線的驗證者質押金減少至小於網絡總質押金的1/3 時,剩餘的在線驗證者將重新佔據區塊鏈共識所需的2/3 多數,從而允許他們敲定區塊鏈。
然而,還有一種情況與此相關:在某些情況下,驗證者無法再對有效鏈進行投票,因為他們不小心將自己鎖在了一條無效鏈中。我們在下文中將對此進一步解釋。
03. 運行一個主導性客戶端有多糟糕?
為了理解其中的危險之處,讓我們來看一下三種類型的故障事件:
大規模罰沒事件:由於某個bug,運行主導性客戶端(即大多數驗證者都選擇使用的客戶端)的驗證者將對可罰沒事件進行簽名。
大規模離線事件:由於某個bug,運行主導性客戶端的所有驗證者都離線。
無效區塊事件:由於某個bug,運行主導性客戶端的所有驗證者都對一個無效區塊進行證明。
還有其他類型的大規模故障和罰沒可能會發生,但我將自己限制在這些與客戶端bug 相關的事件上(這些是你在選擇運行哪個客戶端時應該考慮的問題)。
場景1:雙重簽名
這可能是大多數驗證者運營商最擔心的情況:一個bug 導致驗證者客戶端對可罰沒事件進行了簽名。其中一個例子是兩個證明(attestations) 對同一個目標epoch 進行投票,但使用了不同的有效負載(這就是所謂的“雙重簽名”(Double Signing))。由於這是一個客戶端bug,因此不僅僅只有一個質押者需要擔心,所有運行了這個特定客戶端的質押者都需要擔心了。當這種行為被發現時,罰沒將會演變成一場血洗:所有相關的質押者都將損失100% 的質押金。這是因為,我們此處考慮的是這些質押者運行的是一個主導性客戶端(即大多數質押者都選擇使用的客戶端);而如果相關的客戶端承載的質押金只佔網絡總質押金的10%(即該客戶端並非主導性客戶端),那麼“只有“大約20%的相關質押金會被罰沒(這是信標鏈Altair 升級以來的罰沒力度;當最終的懲罰參數生效時,這個比例將會增加至30%。)
這種情況所帶來的損失顯然是極端的,但我也認為這是極不可能的。滿足成為可被罰沒的證明的條件很簡單,這就是為什麼要構建驗證者客戶端(validator clients, VCs) 來強制執行它們。驗證者客戶端是一個小型的、經過良好審計的軟件,這種規模級別的漏洞是不太可能出現的。
到目前為止,我們已經看到了一些罰沒情況,但據我所知,它們都是由於運營者操作不當造成的——幾乎所有這些都是由於運營者在多個地點運行同一個驗證者造成的。由於這些是非相關行為,罰沒的數額很小。
場景2:大規模離線事件
對於這個場景,我們假設主導性客戶端存在一個bug,當這個bug 被觸發時,會導致該客戶端崩潰。一個非法區塊已經被整合到區塊鏈中,每當這個主導性客戶端遇上該區塊時,該客戶端就會離線,使其無法參與任何進一步的共識。由於該主導性客戶端現在離線了,此時Inactivity Leaks懲罰機制就啟動了。
客戶端開發者將爭先恐後地讓一切恢復正常。實際上,在幾個小時內,最多幾天內,他們將發布一個bug 修復來消除該崩潰。在此期間,質押者也可以選擇簡單地切換至另一個客戶端。只要有足夠的質押者切換至另一個客戶端,使得有超過2/3 的驗證者在線,那麼這個quadratic inactivity leak 懲罰機制就會停止。在修復這個有bug 的客戶端之前,這種情況並非不可能發生。
這種場景並非不可能發生(導致客戶端崩潰的bugs 是最常見的bug 類型),但由此導致被懲罰的總金額可能不到受影響的質押金的1%。
場景3:無效區塊
對於這種場景,我們考慮這樣一種情況,即主導性客戶端存在一個bug,該bug 導致客戶端生產了一個無效區塊,並且接受該區塊為有效區塊——也即是說,當使用這個主導性客戶端的驗證者看到了這個無效區塊時,他們將視其為有效區塊,並證明(投票給) 該區塊。
我們將這條包含了這個無效區塊的鏈稱為A 鏈。一旦這個無效區塊被生產了,會發生兩件事情:
所有其他正常運行的客戶端將會忽視這個無效區塊,並在最近的有效區塊頭之上構建一條單獨的區塊鏈,我們稱之為B 鏈。所有正常運行的客戶端將投票給B 鏈並繼續構建這條鏈。如下圖所示。
這個有bug 的主導性客戶端將會把A 鍊和B 鏈都視為有效鏈。因此,該客戶端會投票給當下它認為是最“重”的任何一條鏈。
我們需要區分三種情況:
這個有bug 的主導性客戶端承載了少於1/2 的總質押金。這種情況下,所有其他正常運行的客戶端將會投票給B 鏈並繼續構建B 鏈,最終使B 鏈成為最重的那條鏈。此時,即便是這個有bug 的客戶端也將會切換至B 鏈。除了會生產一個或幾個孤塊之外,沒有什麼糟糕的事情會發生。這是一個令人高興的情況,也是為什麼網絡中有著主導性客戶端之外的其他客戶端是非常重要的。
這個有bug 的主導性客戶端承載了超過1/2 但少於2/3 的總質押金。這種情況下,我們將看到有兩條鏈被構建—— A 鏈由這個有bug 的客戶端構建,B 鏈由其他客戶端構建。這兩條鏈都不具有2/3 驗證者的絕對優勢,因此這兩條鏈都無法敲定區塊。當這種情況發生時,開發者們將爭相理解為什麼會有兩條鏈。當他們發現A 鏈中有一個無效區塊時,他們可以繼續修復有bug 的主導性客戶端。一旦bug 修復完成,該客戶端將把A 鏈視為無效鏈,並開始構建B 鏈,從而運行B 鏈能夠實現區塊敲定。對於用戶而言,這種區塊是非常具有破壞性的。雖然弄清楚哪條鍊是有效鏈所需的這個時間預計是短暫的(可能不到1 小時),但區塊鏈很可能在幾個小時內(甚至一天時間) 都無法敲定區塊。但對於質押者來說,即便是那些在運行這個有bug 的主導性客戶端的質押者而言,他們受到的懲罰依然相對較小:他們會因為構建無效的A 鏈而不是參與B 鏈的共識而受到“inactivity leak”懲罰,但由於這持續的時間很可能不到一天時間,因此相應的懲罰可能不到1%的質押金。
這個有bug 的主導性客戶端承載了超過2/3 的質押金。在這種情況下,這個有bug 的主導性客戶端將不僅僅會構建A 鏈,實際上還會有足夠的質押金來“敲定”A 鏈。需要注意的是,該客戶端是唯一認為A 鏈已被敲定的客戶端,而所有其他正常運行的客戶端則將A 鏈視為無效鏈。但是,由於Casper FFG 協議的運作方式,當一名驗證者敲定了A 鏈時,該驗證者將無法再在不被罰沒的情況下參與到另一條與A 鏈相衝突的鏈中,除非這條鏈能夠被敲定。因此,一旦A 鏈已經被敲定,那麼運行這個有bug 的客戶端的驗證者就陷入了一個可怕的困境:他們已經投票給了A 鏈,但A 鍊是無效鏈;他們也無法構建B 鏈,因為B 鏈當下還無法實現敲定。甚至是對他們的客戶端進行bug 修復也無法幫助他們,因為他們已經發送了違規投票。當前將發生的情況是非常痛苦的:無法敲定區塊的B 鏈將啟動Inactivity Leak 懲罰機制,在接下來幾週內,A 鏈上的驗證者將損失他們的質押金,直到有足夠多的質押金被銷毀了,從而使得B 鏈恢復敲定。假設A 鏈上的質押者們一開始擁有網絡中70% 的質押金,那麼他們將至少損失79% 的質押金,因為這是他們的質押金數量要減少至代表網絡中少於1/3 的質押金所必須損失的數量。此時,B 鏈將恢復敲定,所有質押金都可以切換至B 鏈。區塊鏈將再次恢復健康狀態,但在此之前的這種破壞性將持續數週,數百萬ETH 在此過程中被銷毀。
顯然,上述第三種情況就是一場災難。這就是為什麼我們非常希望不要讓任何一個客戶端擁有超過2/3 總質押金。這樣無效區塊就永遠不會被敲定,這種災難就永遠不會發生。
04. 風險分析
那麼我們應如何評估這些情況呢?一個典型的風險分析策略是評估事件發生的可能性(我們使用數字1 代表極不可能,數字5 代表相當可能) 以及影響(數字1 代表非常低,數字5 代表災難性)。最重要的風險是那些在這兩個指標上得分較高的風險,由影響和可能性的乘積表示。
基於上表,到目前為止風險最高的是場景3。當一個客戶端擁有2/3 質押金的絕對多數時,這是相當災難性的情況,這也是一個相對可能出現的情況。為了強調這樣的bug 是多麼容易發生,最近在Kiln 測試網發生了一個類似的bug:在這個案例中,Prysm 客戶端確實在提出一個區塊之後才發現它是錯誤的,並且並沒有證明該區塊。假如當時Prysm 客戶端將該區塊視為有效區塊,並且假如這是發生在以太坊主網(而不是測試網) 上,那麼我們將會面臨場景3 中的第三種情況——因為Prysm 客戶端目前在以太坊主網中擁有2/3 的絕對多數。因此,如果目前你正在運行Prysm 客戶端,你可能會失去所有的資金,這是一個非常現實的風險,你應該考慮切換客戶端。
雖然上述場景1 可能是人們最擔心的情況,但其風險評級相對較低。原因在於,我認為發生場景1 這種情況的可能性非常低,因為我認為驗證者客戶端軟件在所有客戶端中都很好地被實現了,不太可能生產出可被罰沒的證明或區塊。
如果目前我在運行主導性客戶端,並且對於切換客戶端顧慮重重,那麼我有什麼選擇呢?
切換客戶端可能是一項重大的任務。它也伴隨著一些風險。如果罰沒數據庫沒有被正確地遷移至新設置,那會怎樣呢?可能會有被罰沒的風險,而這完全違背了我們切換客戶端的目的。
對於那些擔心這種問題的人,我還建議有另一個選擇:可以讓你的驗證者設置保持原樣(無需取出密鑰等等),僅僅切換信標節點。這是極低的風險,因為只要驗證者客戶端按預期工作,它就不會雙重簽名,因此也就不會被罰沒。尤其是如果你運營著大型驗證者業務,使得更改驗證者客戶端(或遠程簽名者) 基礎設施的成本非常昂貴,並且可能需要審計,那麼這可能是一個很好的選擇。如果新設置執行起來並沒有像預期中的那樣好,也能夠輕鬆地切換回原來的客戶端,或者可以嘗試切換至另一個非主導性客戶端。
這樣做的好處是,在切換信標節點時,你幾乎不用擔心:這可能對你造成的最糟糕的事情是暫時離線。這是因為信標節點本身永遠無法自己生成可被罰沒的消息。如果你運行的是非主導性客戶端,你不可能會面臨上述場景3 的情況,因為即便你投票給了一個無效區塊,該區塊也無法獲得足夠的投票來被敲定。
那執行客戶端呢?
我在上文中撰寫的內容適用於共識客戶端,包括Prysm、Lighthouse、Nimbus、Lodestar 和Teku,截至撰寫本文時,Prysm 可能擁有網絡上2/3 的絕對多數。
所有這些都以相同的方式應用於執行客戶端。如果Go-ethereum(此客戶端很可能會在合併之後成為占主導性的執行客戶端) 生產了一個無效區塊,那麼該區塊可能會被敲定,因此將導致出現上文所述場景3 的災難性情況。
幸運的是,我們現在已經有其他3 個執行客戶端處於生產就緒中:Nethermind、Besu 以及Erigon。如果你是一名質押者,我非常建議你運行這其中一個執行客戶端。如果你運行的是一個非主導性客戶端,其中的風險是相當低的!但如果你運行的是主導性客戶端,那麼你面臨著損失所有資金的嚴重風險!
編者註:本譯文有所刪減,英文原文參見👇
https://dankradfeist.de/ethereum/2022/03/24/run-the-majority-client-at-your-own-peril.html#A2-Why-can’t-the-buggy-client-switch-to-chain-B-once-it-has-finalized-chain-A
**本文僅代表原作者觀點,不構成任何投資意見或建議。
聲明:本內容為作者獨立觀點,不代表0x财经 立場,且不構成投資建議,請謹慎對待,如需報導或加入交流群,請聯繫微信:VOICE-V。
來源:Unitimes 原創