上一篇寫了分佈式一致性協議相關理論與算法,那些算法不可用於區塊鏈系統之中,不可防止做惡狀況,只能容忍節點宕機、網絡分區等狀況。html
這節,咱們一塊兒看看區塊鏈中經常使用的共識算法。先來看看爲何分佈式網絡須要共識?web
如圖,白軍軍隊實力強大,且居於要地,藍軍被白軍隔開成爲了兩個軍隊,只有兩個藍軍達成一致(具體幾點幾分開始進攻白軍),方可打敗白軍。但藍軍一、藍軍2要想達成一致,必須使用信使穿過白軍領地進行互相通訊,才能同時進攻取勝。但因爲白軍可能抓捕信使,致使兩方藍軍沒法達成共識狀況。因此兩軍問題表達的是,信道不可信(消息丟失,超時等),若是存在可信信道,則兩軍問題可解。算法
兩軍通訊,就像TCP的三次握手,須要雙方發送而且獲得反饋才能確認彼此以收到正確消息達到共識。安全
拜占庭將軍問題是一個共識問題: 首先是由**萊斯利·蘭伯特(Leslie Lamport)**及其餘兩人於1982年提出,被稱爲Byzantine Failure。核心描述是軍中可能有叛徒,卻要保證進攻一致。與分佈式系統類比,節點中有做惡節點,也可能被黑客攻擊。網絡
圖是醜了一點,你們將就了[捂臉哭]。編輯器
拜占庭帝國想要進攻一個強大的城市,爲此派出了10支軍隊去包圍這個敵人。這個敵人雖不比拜占庭帝國,但也足以抵禦5支常規拜占庭軍隊的同時襲擊。基於一些緣由,這10支軍隊不能集合在一塊兒單點突破,必須在分開的包圍狀態下同時攻擊。他們任一支軍隊單獨進攻都毫無勝算,除非有至少6支軍隊同時襲擊才能攻下敵國。他們分散在敵國的四周,依靠通訊兵相互通訊來協商進攻意向及進攻時間。困擾這些將軍的問題是,他們不肯定他們中是否有叛徒,叛徒可能擅自變動進攻意向或者進攻時間。在這種狀態下,拜占庭將軍們可否找到一種分佈式的協議來讓他們可以遠程協商,從而贏取戰鬥?這就是著名的拜占庭將軍問題。分佈式
應該明確的是,拜占庭將軍問題中並不去考慮通訊兵是否會被截獲或沒法傳達信息等問題,即消息傳遞的信道是可信安全的。Lamport已經證實了在消息可能丟失的不可靠信道上試圖經過消息傳遞的方式達到一致性是不可能的。如下已假定信道是安全可靠的ide
這個問題說究竟是一個關於一致性和正確性的算法問題,這個算法是針對的是忠誠的將軍,由於叛徒能夠不傳,或者亂傳消息搗亂。咱們就是要在有叛徒的干擾下,找到一個容忍干擾的算法——BFT(Byzantine fault tolerance)拜占庭容錯。區塊鏈
能夠看出,兩軍問題是拜占庭將軍問題的特例。spa
什麼能夠稱爲拜占庭錯誤?
做惡節點,或者被黑客攻擊的節點。節點宕機、網絡分區、超時等都不是拜占庭錯誤。
拜占庭將軍問題中:每個將軍都須要與全部將軍進行通訊,已得知其餘將軍的進攻安排,從而達到共識。因此拜占庭將軍問題可簡化爲司令——副官模型。一個司令,多個副官,須要一致性協議保證,司令發出的命令,多個副官能夠獲得一致的結果。
一個司令把本身的命令傳遞給n-1個副官,使得:
一致性:全部忠誠的副官遵照一個命令(結果集中的大多數 n/2+1)。
正確性:若司令是忠誠的,每個忠誠的副官遵照他發出的命令。(若將軍是做惡的,則只須要遵照第一條)
f爲拜占庭錯誤節點數,也是BFT能夠容忍的叛徒數量。
反證法,若是n<3f+1 即當f= 1時,n = 3。
因此得出n<3f+1時沒法達到拜占庭容錯,須要n>=3f+1。具體推導可看參考裏的論文,或者李永樂老師的視頻。
BFT假設信道沒有問題,也就是不考慮消息不可達、消息丟失、亂序、重複、網絡分區等狀況。Miguel Castro (卡斯特羅)和 Barbara Liskov (利斯科夫)在1999年發表的論文《 Practical Byzantine Fault Tolerance 》中首次提出 pbft 算法,該算法容錯數量也知足 3f+1<=n。
pbft 算法的基本流程主要有如下四步:
客戶端發送請求給主節點
主節點廣播請求給其它節點,節點執行 pbft 算法的三階段共識流程。
節點處理完三階段流程後,返回消息給客戶端。
客戶端收到來自 f+1 個節點的相同消息後,表明共識已經正確完成。
圖片來於源論文截圖,此圖中主節點是忠誠的,編號3節點是拜占庭節點(叛徒)。
PBFT是三階段提交協議。
完成後響應客戶端。客戶端收到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(proof-of-work) 使用計算一個合法的隨機數,來增長做惡節點的成本。由於你想做惡,就須要計算合法nonce,若是想要更改某個區塊的信息,就須要從那個區塊開始,從新計算全部後置區塊的合法nonce,成本巨大且不可能實現。因此比特幣依靠POW安全運行快十年之久。想要了解POW的能夠看一看我以前的文章:比特幣入門
POS:股權證實。大白話就是:持有的幣量越多,持有的越久(幣齡:好比你持有100個幣,持有一天,就是100幣齡),能夠挖礦的機率越大,得到的幣就會越多。好比Dash幣,擁有1000Dash,就能夠成爲master,成爲master就有機會去挖礦。POS會讓富有的人越富有,但幣齡到達某一個值時,會重置爲0。這樣就能夠更換新的人來進行挖礦,避免貧富差距過大。
DPOS:委託權益證實。一般被理解的DPOS在於Delegated(委託),將本身的權益委託給超級節點,選出超級節點代爲出塊,本身根據委託權益的比例得到利息。有興趣的能夠看看Bitshares、Steem、EOS、Asch等項目。
我從0到1參與過兩條公鏈開發,咱們選用的也是DPOS思想,都是自研的DPOS算法。我理解的DPOS是,經過某種規則選出見證者節點(也能夠理解爲超級節點),這些節點只負責在礦工打包出區塊後對區塊進行共識,驗證等。而礦工則能夠經過其餘方式選取,選取方式就能夠多種多樣,能夠採用積分、能夠採用信用分(發送的交易數、持有的幣量、部署的合約數量、對全網的貢獻等),只要可以保證全網使用相同的數據,計算出來的結果是惟一的,可驗證追溯的,那就沒有問題。
見證者節點之間的共識就頗有意思,基本思想離不開BFT,由於要防止做惡節點。你有什麼好的想法,能夠互相討論。
本文從兩軍問題,到拜占庭將軍問題,以及如何解決拜占庭將軍問題,引出了BFT,PBFT。最後泛談了區塊鏈中常見的共識算法,共識算法主要理解思想,我的認爲不應被某種算法禁錮,可根據實際狀況進行思惟擴展,可能就會創造出更優雅的共識算法。
重要:文中有錯誤之處,敬請各位大佬指出。也歡迎對區塊鏈有興趣的小夥伴進行討論交流。
參考連接:
美團技術團隊:共識算法系列之一:raft和pbft算法