可用於區塊鏈的共識演算法

guo935809915發表於2020-08-09

 

 

引言

上一篇寫了分散式一致性協議相關理論與演算法,那些演算法不可用於區塊鏈系統之中,不可防止作惡情況,只能容忍節點當機、網路分割槽等情況。

這節,我們一起看看區塊鏈中常用的共識演算法。先來看看為什麼分散式網路需要共識?

兩軍問題

如圖,白軍軍隊實力強大,且居於要地,藍軍被白軍隔開成為了兩個軍隊,只有兩個藍軍達成一致(具體幾點幾分開始進攻白軍),方可戰勝白軍。但藍軍1、藍軍2要想達成一致,必須使用信使穿過白軍領地進行互相通訊,才能同時進攻取勝。但由於白軍可能抓捕信使,導致兩方藍軍無法達成共識情況。所以兩軍問題表達的是,通道不可信(訊息丟失,超時等),如果存在可信通道,則兩軍問題可解。

兩軍通訊,就像TCP的三次握手,需要雙方傳送並且得到反饋才能確認彼此以收到正確訊息達到共識。

拜占庭將軍問題

拜占庭將軍問題是一個共識問題: 首先是由**萊斯利·蘭伯特(Leslie Lamport)**及其他兩人於1982年提出,被稱為Byzantine Failure。核心描述是軍中可能有叛徒,卻要保證進攻一致。與分散式系統類比,節點中有作惡節點,也可能被黑客攻擊。

圖是醜了一點,大家將就了[捂臉哭]。

拜占庭帝國想要進攻一個強大的城市,為此派出了10支軍隊去包圍這個敵人。這個敵人雖不比拜占庭帝國,但也足以抵禦5支常規拜占庭軍隊的同時襲擊。基於一些原因,這10支軍隊不能集合在一起單點突破,必須在分開的包圍狀態下同時攻擊。他們任一支軍隊單獨進攻都毫無勝算,除非有至少6支軍隊同時襲擊才能攻下敵國。他們分散在敵國的四周,依靠通訊兵相互通訊來協商進攻意向及進攻時間。困擾這些將軍的問題是,他們不確定他們中是否有叛徒,叛徒可能擅自變更進攻意向或者進攻時間。在這種狀態下,拜占庭將軍們能否找到一種分散式的協議來讓他們能夠遠端協商,從而贏取戰鬥?這就是著名的拜占庭將軍問題。

應該明確的是,拜占庭將軍問題中並不去考慮通訊兵是否會被截獲或無法傳達資訊等問題,即訊息傳遞的通道是可信安全的。Lamport已經證明了在訊息可能丟失的不可靠通道上試圖通過訊息傳遞的方式達到一致性是不可能的。以下已假定通道是安全可靠的

這個問題說到底是一個關於一致性和正確性的演算法問題,這個演算法是針對的是忠誠的將軍,因為叛徒可以不傳,或者亂傳訊息搗亂。我們就是要在有叛徒的干擾下,找到一個容忍干擾的演算法——BFT(Byzantine fault tolerance)拜占庭容錯。

可以看出,兩軍問題是拜占庭將軍問題的特例。

什麼可以稱為拜占庭錯誤?

作惡節點,或者被黑客攻擊的節點。節點當機、網路分割槽、超時等都不是拜占庭錯誤。

如何解決拜占庭將軍問題?

司令副官模型

拜占庭將軍問題中:每一個將軍都需要與所有將軍進行通訊,已得知其他將軍的進攻安排,從而達到共識。所以拜占庭將軍問題可簡化為司令——副官模型。一個司令,多個副官,需要一致性協議保證,司令發出的命令,多個副官可以得到一致的結果。

一個司令把自己的命令傳遞給n-1個副官,使得:

一致性:所有忠誠的副官遵守一個命令(結果集中的大多數 n/2+1)。

正確性:若司令是忠誠的,每一個忠誠的副官遵守他發出的命令。(若將軍是作惡的,則只需要遵守第一條)

BFT為什麼需要節點數n>=3f+1?

f為拜占庭錯誤節點數,也是BFT可以容忍的叛徒數量。

反證法,如果n<3f+1 即當f= 1時,n = 3。

  1. 如果司令是忠誠的,一個副官忠誠,一個副官叛徒。當司令傳送進攻命令給兩個副官,兩個副官會彼此詢問司令的命令是什麼,這時候叛徒副官就會偽造假命令,說司令給他的命令是撤退,那忠誠副官就懵了,因為他收到的是進攻命令,此時忠誠副官不知道司令是叛徒還是另一個副官是叛徒。
  2. 如果司令是叛徒,兩個副官是忠誠的。司令分別給兩個副官一個進攻,一個撤退;兩個副官通訊時發現彼此收到的命令不一致,也無法達成共識。

所以得出n<3f+1時無法達到拜占庭容錯,需要n>=3f+1。具體推導可看參考裡的論文,或者李永樂老師的視訊。

PBFT(Practical Byzantine Fault Tolerance)

BFT假設通道沒有問題,也就是不考慮訊息不可達、訊息丟失、亂序、重複、網路分割槽等情況。Miguel Castro (卡斯特羅)和 Barbara Liskov (利斯科夫)在1999年發表的論文《 Practical Byzantine Fault Tolerance 》中首次提出 pbft 演算法,該演算法容錯數量也滿足 3f+1<=n。

pbft 演算法的基本流程主要有以下四步:

  1. 客戶端傳送請求給主節點

  2. 主節點廣播請求給其它節點,節點執行 pbft 演算法的三階段共識流程。

  3. 節點處理完三階段流程後,返回訊息給客戶端。

  4. 客戶端收到來自 f+1 個節點的相同訊息後,代表共識已經正確完成。

圖片來於源論文截圖,此圖中主節點是忠誠的,編號3節點是拜占庭節點(叛徒)。

PBFT是三階段提交協議。

  1. 客戶端將請求傳送給主節點,主節點打包為pre-prepare訊息分發給系統中的副本。
  2. 副本節點收到主節點傳送的pre-prepare訊息,並驗證;驗證通過後廣播prepare訊息。注意:主節點不廣播prepare訊息。
  3. 所有節點(包括主節點)在一定時間範圍內收到驗證通過的,不同的2f個prepare(包含自己的)訊息後,開始廣播commit訊息。
  4. 所有節點收到2f+1個commit訊息後,今天提交操作。

完成後響應客戶端。客戶端收到f+1個訊息後即可確定操作共識結束。

為什麼客戶端只需要f+1個訊息呢?

假設如果沒有收到f個訊息,但無法判斷那f個節點就是拜占庭節點,所以可能最壞的情況下,收到的訊息中有f個是拜占庭節點的發出的,那要保持容錯性,就需要忠誠的節點數量大於拜占庭節點數量(多數派),即f+1個忠誠節點。所以客戶端只需要收到f+1個相同訊息,就可以斷定已經共識成功了。

這也是PBFT容錯只能f個,n>=f+f+(f+1) = 3f + 1。

PBFT還有一個View的概念,使用View進行主節點切換。當副本節點與主節點間的心跳超時, 就會發起檢視變更,進行主節點切換。每次檢視變更,view=view+1。

主節點 = view % n 。 可以看出,PBFT使用輪詢當選主節點。我們看prepare階段,如果主節點是作惡節點,這個階段是無法收到2f個prepare訊息的,因為主節點會像叢集中傳送多個不同的訊息,此時大家收到的不一致,就判斷主節點有問題,就會進行檢視變更,重選主節點。

比特幣的POW共識

POW(proof-of-work) 使用計算一個合法的隨機數,來增加作惡節點的成本。因為你想作惡,就需要計算合法nonce,如果想要更改某個區塊的資訊,就需要從那個區塊開始,重新計算所有後置區塊的合法nonce,成本巨大且不可能實現。所以比特幣依靠POW安全執行快十年之久。想要了解POW的可以看一看我之前的文章:比特幣入門

POS(Proof of Stake)共識

POS:股權證明。大白話就是:持有的幣量越多,持有的越久(幣齡:比如你持有100個幣,持有一天,就是100幣齡),可以挖礦的概率越大,獲得的幣就會越多。比如Dash幣,擁有1000Dash,就可以成為master,成為master就有機會去挖礦。POS會讓富有的人越富有,但幣齡到達某一個值時,會重置為0。這樣就可以更換新的人來進行挖礦,避免貧富差距過大。

DPOS(Delegated Proof of Stake)共識

DPOS:委託權益證明。通常被理解的DPOS在於Delegated(委託),將自己的權益委託給超級節點,選出超級節點代為出塊,自己根據委託權益的比例獲得利息。有興趣的可以看看Bitshares、Steem、EOS、Asch等專案。

我從0到1參與過兩條公鏈開發,我們選用的也是DPOS思想,都是自研的DPOS演算法。我理解的DPOS是,通過某種規則選出見證者節點(也可以理解為超級節點),這些節點只負責在礦工打包出區塊後對區塊進行共識,驗證等。而礦工則可以通過其他方式選取,選取方式就可以多種多樣,可以採用積分、可以採用信用分(傳送的交易數、持有的幣量、部署的合約數量、對全網的貢獻等),只要能夠保證全網使用相同的資料,計算出來的結果是唯一的,可驗證追溯的,那就沒有問題。

見證者節點之間的共識就很有意思,基本思想離不開BFT,因為要防止作惡節點。你有什麼好的想法,可以互相討論。

總結

本文從兩軍問題,到拜占庭將軍問題,以及如何解決拜占庭將軍問題,引出了BFT,PBFT。最後泛談了區塊鏈中常見的共識演算法,共識演算法主要理解思想,個人認為不該被某種演算法禁錮,可根據實際情況進行思維擴充套件,可能就會創造出更優雅的共識演算法。

重要:文中有錯誤之處,敬請各位大佬指出。也歡迎對區塊鏈有興趣的小夥伴進行討論交流。

參考連結

拜占庭將軍問題論文

李永樂老師關於“拜占庭將軍問題”視訊

拜占庭將軍問題深入探討

PBFT論文

美團技術團隊:共識演算法系列之一:raft和pbft演算法

相關文章