作者:鄭翊
目錄
- 什麼是共識機制
- 拜占庭將軍問題
- CAP原理
- 定義
- 應用
- 拜占庭問題的常規解法
- 口頭協議
- 書面協議
- PBFT
- 比特幣中對於拜占庭問題的解法
- PoW
- Bitcoin
- Ethereum
- PoS
- Peercoin PoS v1
- Blackcoin PoS v2
- Blackcoin & Qtum PoS v3
- Ethereum Casper
- Delegated Methods
- EOS DPOS
- NEO DBFT
- PoW
- 非拜占庭問題下的解法
- Paxos
- Raft
- 總結
- 參考資料
什麼是共識機制
區塊鏈從本質上而言是一種分散式賬本技術。傳統的賬本,通常會以資料庫的形式,集中儲存在銀行或公司的伺服器節點上。而在區塊鏈的網路中,每個節點都會保有一份完整的賬本,且所有節點的賬本內容完全一致。每個節點都可以根據自己本地的賬本去查詢交易,也可以往賬本中新增交易。
這樣就帶來了一個問題,如果所有節點同時一起寫入賬本資料,那麼肯定資料會不一致。因此需要一種機制來保證區塊鏈中的每一區塊只能由一個節點來負責寫入,並且讓所有其他節點一致認同這次寫入。如何選出寫入賬本資料的節點,這就是共識機制。
拜占庭將軍問題
拜占庭將軍問題[1][2](Byzantine Generals Problem)是對上述場景的一種建模。拜占庭將軍問題是一個共識問題: 首先由Leslie Lamport與另外兩人在1982年提出,被稱為The Byzantine Generals Problem或者Byzantine Failure。核心描述是軍中可能有叛徒,卻要保證進攻一致,由此引申到計算領域,發展成了一種容錯理論,即拜占庭容錯(BFT,Byzantine Fault Tolerance)。
拜占庭將軍問題可以描述如下:
拜占庭帝國想要進攻一個強大的敵人,為此派出了10支軍隊去包圍這個敵人。這個敵人雖不比拜占庭帝國,但也足以抵禦5支常規拜占庭軍隊的同時襲擊。基於一些原因,這10支軍隊不能集合在一起單點突破,必須在分開的包圍狀態下同時攻擊。他們任一支軍隊單獨進攻都毫無勝算,除非有至少6支軍隊同時襲擊才能攻下敵國。他們分散在敵國的四周,依靠通訊兵相互通訊來協商進攻意向及進攻時間。困擾這些將軍的問題是,他們不確定他們中是否有叛徒,叛徒可能擅自變更進攻意向或者進攻時間。在這種狀態下,拜占庭將軍們能否找到一種分散式的協議來讓他們能夠遠端協商,從而贏取戰鬥?這就是著名的拜占庭將軍問題。
解決問題的難點在於,將軍中可能出現叛徒,叛徒可以通過選擇性地傳送訊息,從而達到混淆進攻決策的目的。假設有9位將軍投票,其中1名叛徒。8名忠誠的將軍中出現了4人投進攻,4人投撤離的情況。這時候叛徒可能故意給4名投進攻的將領送信表示投票進攻,而給4名投撤離的將領送信表示投撤離。這樣一來在4名投進攻的將領看來,投票結果是5人投進攻,從而發起進攻;而在4名投撤離的將軍看來則是5人投撤離。這樣各支軍隊的一致協同就遭到了破壞。
拜占庭將軍問題對應到分散式系統中,可以表述為分散式的節點間需要對某一個message達成共識(只要過半數節點認同這個message即可)。節點之間可以交換資訊,但是由於惡意節點的存在,惡意節點會發布錯誤的訊息,或是給不同的節點傳送不同的訊息。在這樣的場景下,怎樣設計一種機制去讓節點能夠達成共識的問題。
拜占庭問題的傳統解法
口頭協議
首先明確口頭協議的定義。我們將滿足以下三個條件的方式稱為口頭協議:
- 每個被髮送的訊息都能夠被正確的投遞
- 資訊接收者知道是誰傳送的訊息
- 能夠知道缺少的訊息
Lamport論證得出結論:將軍之間採用口頭協議進行通訊,若叛徒數少於1/3,則拜占庭將軍問題可解。也就是說,若叛徒數為m,當將軍總數n至少為3m+1時,問題可解。本文中不再詳細介紹通訊機制和論證過程,有興趣的讀者可以查閱文章[1]中“口頭協議”一節和[2]中的“Early solutions”下的第一種。
書面協議
在口頭協議上加上一個條件,使之成為書面協議
- 傳送者對訊息加上簽名,簽名不可偽造,一旦被篡改即可發現,而叛徒的簽名可被其他叛徒偽造;
- 任何人都可以驗證簽名的可靠性。
可以論證,在將軍之間使用書面協議通訊的基礎上,不管將軍總數n和叛徒數量m,忠誠的將軍總能達到一致。書面協議的本質就是引入了簽名系統,這使得所有訊息都可以追溯到底有誰認同了它。這一優勢,大大節省了成本,他化解了口頭協議中1/3要求,只要採用了書面協議,忠誠的將軍就可以達到一致。即惡意的節點不超過半數,分散式系統就能達成共識。對推導細節感興趣的讀者可以同樣參照[1][2]。
PBFT
實用拜占庭容錯協議(PBFT,Practical Byzantine Fault Tolerance)是Miguel Castro (卡斯特羅)和Barbara Liskov(利斯科夫)在1999年提出來的,解決了原始拜占庭容錯演算法(即上文中的口頭協議)效率不高的問題,將演算法複雜度由指數級降低到多項式級,使得拜占庭容錯演算法在實際系統應用中變得可行。
PBFT演算法的結論是n>=3f+1 n是系統中的總節點數,f是允許出現故障的節點數。換句話說,如果這個系統允許出現f個故障,那麼這個系統必須包括n個節點,才能解決故障。這和上文口頭協議的結論一樣,或者這麼說,PBFT是優化了口頭協議機制的效率,但是結論並未改變。
PBFT演算法的步驟,詳見[1][3]
- 取一個副本作為主節點(圖中0),其他的副本作為備份;
- 使用者(圖中C)向主節點傳送訊息請求;
- 主節點通過廣播將請求傳送給其他節點(圖中1、2、3);
- 所有節點執行請求並將結果發回使用者端;
- 使用者端需要等待f+1個不同副本節點發回相同的結果,即可作為整個操作的最終結果。
CAP原理
為了便於理解比特幣中對於拜占庭問題的解法(PoW、PoS等),先看一下著名的CAP原理[4],對於共識演算法的設計有指導意義。CAP 原理最早由 Eric Brewer 在 2000 年,ACM 組織的一個研討會上提出猜想,後來 Lynch 等人進行了證明。該原理被認為是分散式系統領域的重要原理。
定義
分散式計算系統不可能同時確保一致性(Consistency)、可用性(Availability)和分割槽容忍性(Partition),設計中往往需要弱化對某個特性的保證。
- 資料一致性(Consistency):如果系統對一個寫操作返回成功,那麼之後的讀請求都必須讀到這個新資料;如果返回失敗,那麼所有讀操作都不能讀到這個資料,對呼叫者而言資料具有強一致性(strong consistency) (又叫原子性 atomic、線性一致性 linearizable consistency)
- 服務可用性(Availability):所有讀寫請求在一定時間內得到響應,可終止、不會一直等待
- 分割槽容錯性(Partition-tolerance):在網路分割槽的情況下,被分隔的節點仍能正常對外服務
在某時刻如果滿足AP,分隔的節點同時對外服務但不能相互通訊,將導致狀態不一致,即不能滿足C;如果滿足CP,網路分割槽的情況下為達成C,請求只能一直等待,即不滿足A;如果要滿足CA,在一定時間內要達到節點狀態一致,要求不能出現網路分割槽,則不能滿足P。C、A、P三者最多隻能滿足其中兩個。
分割槽容錯性
這裡重點講一下對分割槽容錯性的理解,便於大家理解CAP。Partition字面意思是網路分割槽,即因網路因素將系統分隔為多個單獨的部分,有人可能會說,網路分割槽的情況發生概率非常小啊,是不是不用考慮P,保證CA就好。要理解P,我們看回CAP證明中P的定義:
In order to model partition tolerance, the network will be allowed to lose arbitrarily many messages sent from one node to another.
網路分割槽的情況符合該定義,網路丟包的情況也符合以上定義,另外節點當機,其他節點發往當機節點的包也將丟失,這種情況同樣符合定義。現實情況下我們面對的是一個不可靠的網路、有一定概率當機的裝置,這兩個因素都會導致Partition,因而分散式系統實現中P是一個必須項,而不是可選項。
弱化一致性
對結果一致性不敏感的應用,可以允許在新版本上線後過一段時間才更新成功,期間不保證一致性。
例如網站的CSS、JS等,通常都設定了一定的快取時間。超過快取時間才會重新去伺服器獲取最新的版本。
弱化可用性
對結果一致性很敏感的應用,特別是交易相關的應用場景,通常會用到鎖、事務等概念。
例如銀行取款機,當系統故障時候會拒絕服務。Paxos、Raft 等演算法,主要處理這種情況。
弱化分割槽容忍性
現實中,網路分割槽出現概率減小,但較難避免。某些關係型資料庫、ZooKeeper 即為此設計。一旦有部分節點網路通訊出現故障,則暫停這部分節點,不再提供對外服務。
比特幣中對於拜占庭問題的解法
拜占庭問題之所以難解,在於任何時候系統中都可能存在多個提案(因為提案成本很低),並且要完成最終的一致性確認過程十分困難,容易受干擾。但是一旦確認,即為最終確認。
比特幣的區塊鏈網路在設計時提出了創新的 PoW(Proof of Work) 演算法思路。一個是限制一段時間內整個網路中出現提案的個數(增加提案成本),另外一個是放寬對一致性確認的需求,約定好大家都確認並沿著已知最長的鏈進行拓寬。系統的最終確認是概率意義上的存在。這樣,即便有人試圖惡意破壞,也會付出很大的經濟代價(付出超過系統一半的算力)。
或者通俗來說,比特幣的PoW共識弱化了拜占庭問題中對於一致性的要求,在同一時刻訪問不同比特幣的節點,所得到的共識並不一致,且一致性還會隨著時間改變(分叉的情況)。但是可用性和分支容錯性都得到了提升。
後來的各種 PoX 系列演算法,也都是沿著這個思路進行改進,採用經濟上的懲罰來制約破壞者。
PoW
Bitcoin
Bitcoin的共識協議,可以參照Mastering Bitcoin[5]中有詳細的描述。其步驟如下:
- 本地維持所有未被確認的交易,稱之為交易池,每新接收到一筆交易就加入到交易池中
- 本地維持整個區塊鏈,每新接收到一個block,則加入到區塊鏈中,並根據最長鏈原則確定主鏈
- 當新接收到的block加入到區塊鏈的時候,開始挖礦
- 構建一個空的block,選取交易池中費率最高的交易填充block,費率的定義為 交易費/交易大小
- 根據主鏈,填充block header中的previous block hash欄位
- 根據block中所有交易的交易費和挖礦獎勵,構建coin base交易。挖礦獎勵大約 每四年(或準確說是每210,000個塊)減少一半,開始時為2009年1月每個區塊獎勵50個比特幣
- 修改block header中的nonce, timestamp, merkle root(通過修改coinbase data),讓hash(block header) < difficulty,其中difficulty是根據近期block的產出時間來計算的,保證每個block產出的時間大致是10分鐘左右
- 由於滿足hash要求的block head只能通過大量遍歷獲得,所以挖礦的過程需要消耗大量的算力,直到得到合適的欄位取值為止
- 釋出得到的block,其他節點驗證通過後加入區塊鏈中
2010 年左右,挖礦還是一個很有前途的行業。但是現在,建議還是不要考慮了,因為從概率上說,由於當前參與挖礦的計算力實在過於龐大(已經超出了大部分的超算中心),獲得比特幣的收益已經眼看要 cover 不住電費了。
從普通的 CPU(2009 年)、到後來的 GPU(2010 年) 和 FPGA(2011 年末)、到後來的 ASIC 礦機(2013 年初,目前單片算力已達每秒數百億次 Hash 計算)、再到現在眾多礦機聯合組成礦池。短短數年間,比特幣礦機的技術走完了過去幾十年的積體電路技術進化歷程,並且還頗有創新之處。
Ethereum
由於ASIC礦機被大量運用在比特幣的挖礦過程中,所以如果出現其他基於hash運算達到共識的區塊鏈,則很容易受到原本服務於比特幣的ASIC礦機攻擊。因此Ethereum在設計其PoW共識演算法的時候,就意識到應該讓演算法在普通的個人電腦上執行更有優勢,從而避免被ASIC進行攻擊。
Ethash設計時就明確兩大目標:
- 抵禦礦機效能(ASIC-resistance),團隊希望CPU也能參與挖礦獲得收益。
- 輕客戶端可快速驗證(Light client verifiability)。
基於以上兩個目標,開發團隊最後倒騰出來的Ethash挖礦時基本與CPU效能無關,卻和記憶體大小和記憶體頻寬成正相關。不過在實現上還是借鑑了SHA3的設計思路,但是使用的”SHA3_256” ,”SHA3_512”與標準實現很不同。
Ethash基本流程是這樣的[6]:對於每一個塊,首先計算一個種子(seed),該種子只和當前塊的資訊有關;然後根據種子生成一個32M的隨機資料集(Cache);緊接著根據Cache生成一個1GB大小的資料集合(DAG),DAG可以理解為一個完整的搜尋空間,挖礦的過程就是從DAG中隨機選擇元素(類似於比特幣挖礦中查詢合適Nonce)再進行雜湊運算。可以從Cache快速計算DAG指定位置的元素,進而雜湊驗證。此外還要求對Cache和DAG進行週期性更新,每1000個塊更新一次,並且規定DAG的大小隨著時間推移線性增長,從1G開始,每年大約增長7G左右。
PoS
可以看到,PoW會存在兩點問題:
- 費電。無論是比特幣的共識還是以太坊的Ethash,挖礦的過程中都帶來了巨大的電力消耗。網上有報導稱,現在每挖一個比特幣的成本在6000-8000美元之間;比特幣現在每天消耗的電量相當於一個小國家的耗電量。
- 礦池的優勢。隨著算力的不斷提升,單個礦機挖出一枚幣的概率降到了極低。因此,很多礦機的擁有者聯合在了一起形成礦池。礦池中的礦機並行地分擔計算量,當挖出新的block獲得獎勵後,再根據計算量的貢獻分享獎勵。礦池的出現導致了比特幣的中心化。從下圖中可以看出,65%的算力集中在了5大礦池的手裡。如果這些礦池對比特幣網路進行攻擊,則網路會面臨較大的風險。
因此,業內提出了PoS(Proof of Stake)[7]的思想:
- 把生產block的工作交給擁有更多token的人,擁有的越多,作為block producer的概率越高
- 生產block的過程中得到token獎勵,可以理解為持有token帶來的利息
- 擁有大量token的人如果攻擊網路,則會造成token價格的下降,對這些人是不利的,所以這些block producer攻擊網路的意願較低
- 生產block只需證明自己持有的token即可,不需要消耗多少算力,節約能源
圍繞以上PoS的思想,各個區塊鏈系統有不同的PoS實現,以下將依次介紹
Peercoin PoS v1
最初的一版PoS由Peercoin設計實現[8]。其中,使用者要產出block必須滿足以下條件
hash(stake_modifier, current_time, UTXO) < coin(UTXO) * age(UTXO) * difficulty
複製程式碼
具體解釋如下
- 使用者在每一秒時間(current_time),遍歷自己所有的UTXO,代入上述公式中,看是否能滿足不等式條件;如果滿足,就把相應的UTXO記錄在block中,併發布block(見4)
- stake_modifier是對前一個block中部分欄位hash後的值,加入這一項是為了防止使用者提前預知自己何時有權挖礦
- difficulty會根據近期的block產出時間動態調整,保證block產出時間間隔穩定
- 由於每秒只需要完成和自己UTXO數量相等的hash計算,所以需要的算力較低
- 從不等式可以看出,持有的UTXO越多、UTXO中token數額越大(coin(UTXO))、UTXO持有時間越長(age(UTXO),或稱之為幣齡),不等式越容易成立,越容易進行挖礦
- 生成block的獎勵設定為了coin(UTXO) * age(UTXO),即UTXO數額越大持有時間越長,獎勵越高
- 為了將符合條件的UTXO記錄進block,並且相容原本的PoW模式,Peercoin設計了coinstake的邏輯
- 保留原本第一個transaction為coinbase,但要求輸入數量必須等於1,且輸入的prevout欄位必須置空值,輸出數量必須大於等於1
- 令第二個transaction為coinstake,要求輸入數量大於等於1,且第一個輸入為滿足條件的UTXO,輸出數量大於等於2,且第一個輸出必須置空值,第二個輸出為block獎勵
該版本的PoS面臨著如下的問題
- 因為構造新的block沒有算力成本,所以當區塊鏈出現fork的時候,使用者有可能會傾向於同時在多個branch一起挖礦來獲得潛在更高的收益,這樣製造了大量的分支,破壞了一致性。這個問題多次被以太坊團隊提及,並稱之為nothing at stake問題[12],以太坊在其PoS方案CASPER中致力於解決該問題,下文Ethereum Casper一節中將詳細描述
- 出現了攢幣齡的現象,即關閉節點,直到age(UTXO)足夠大的時候再啟動節點挖礦,從而節省電力,這樣引起了線上節點數太少系統脆弱的問題
- 可以攢夠足夠的幣齡後,保證自己有足夠的UTXO能夠連續生產block,從而發動double-spend攻擊
Blackcoin PoS v2
Blackcoin在Peercoin的基礎上進行了修改,從而緩解了上述問題,主要改動如下,全部改動參見[9]
- 去掉了不等式公式右邊的age(UTXO),從而解決了問題3中攢幣齡然後進行double-spend的現象;但是block獎勵還是使用了幣齡,因此並不能完全解決問題2中節點關閉的現象
- 優化了stake_modifier的計算邏輯,讓使用者提前預知自己有權挖礦時間的難度更大了
Blackcoin & Qtum PoS v3
Blackcoin又在v2的基礎上改進得到了v3[10],然後Qtum對v3又進行了修改並應用[11]。主要改動點描述如下,全部改動請參照[10][11]
- 把block獎勵改成固定值,解決了問題2
- 規定500個block之前的UTXO才能參與挖礦,緩解挖礦過於頻繁帶來的潛在風險
Ethereum Casper
Ethereum在其白皮書中承諾最終將從PoW過渡到PoC,並且其PoC的方案,名叫CASPER[12],正在積極開發中。CASPER一個主要改進點是其將致力於解決nothing at stake問題,主要的方式是懲罰在多個分支上同時進行挖礦的使用者,甚至讓這些使用者失去用於stake的那部分token。其方案描述如下:
- 使用者質押自己的一部分token進入智慧合約,然後開始挖礦
- 如果成功挖到block並被網路接受,則使用者獲得獎勵
- 如果使用者被系統發現試圖進行nothing at stake行為,則其質押的token將被銷燬
但對於nothing at stake問題,業界一直是有爭議的[13]。主要觀點就是執行這種攻擊的代價太高,而且對攻擊者是毫無收益的。這和PoW的前提假設一樣,擁有大量礦機的人可以對比特幣發動double-spend等攻擊,但是這樣的攻擊對其並無收益,且會損失大量算力,所以這種攻擊並沒有大量發生。
Delegated Methods
以上的PoW和PoS的挖礦過程,是全網所有節點共同參與的,每一時刻都有成千上萬個節點同時去爭取產出下一個block,因此會時有發生區塊鏈分叉(fork)的問題。即同一時刻,兩個節點同時產出了next block,但由於網路時延的問題,block產出的時候兩個節點並不知道有其他節點已經產出了另一個block,因此這兩個block都被髮布到了網路中。[5]中對分叉的問題有詳細的描述,可以進行參考。
正是由於分叉的存在,block的產出時間間隔不能太短。各區塊鏈通過動態調整的挖礦難度,將block時間間隔穩定在自己期望的水平。例如最初比特幣的間隔是10分鐘,後續的以太坊是15秒左右。如果時間間隔進一步調短(即降低挖礦難度),分叉問題就會大量顯現,不利於共識的達成和系統的穩定。
block產出時間過長導致了兩個問題:
- 交易確認所需的時間過長。通常來說,一筆交易進入區塊鏈後,都建議經過6個block之後才真正確認交易,因為6個block之後想要再分叉並且追趕主鏈的難度已經超乎想象了。因此,在區塊鏈上確認交易需要分鐘級別的時間。
- TPS (Transactions Per Second) 受到制約。TPS受到了block generation time和max block size的共同制約。其中max block size的存在是為了防止DOS攻擊等因素[14],有一定的天花板,因而縮減block generation time至關重要
為了縮短block產出時間,delegated開頭命名的系列方法被提了出來。其基本思想就是,選出少量的代表來負責生產block。這樣即使縮短block的時間間隔,也不會有嚴重的分叉發生。甚至可以使用PBFT這種沒有分叉的方法來達成代表之間的一致共識。
EOS DPOS
EOS提出的DPOS方案[15],其步驟簡述如下
- 持有token的使用者可以對候選的block producer進行投票;雖然沒有看到對投票過程的詳細設計,但是相關文章中提到了一種可選的方法,即使用者在生成交易的時候,把自己的投票包含在交易中
- 得票最高的n個使用者被選為代表,在下一個週期中負責產出block,目前n=21
- 打亂代表的順序後,各代表開始依次生產block。每個代表都有自己固定的時間區間,需要在自己的區間中完成block的生產釋出。目前這個區間是3秒,即在正常情況下每3秒產出一個block
- 每個代表在生產block的時候,需要找當時唯一的最長鏈進行生產,不能在其他分支上進行生產
- EOS論證了在這種機制下,只要n>=3f+1(n是系統中的總節點數,f是允許出現的惡意節點數),則共識能夠達成
通過上述方法,EOS保證了較短的block生產時間(3秒),且因為給每個生產者設定了固定的時間區間,則block的產出不會因為某個候選節點的延遲而延遲。EOS的文章中詳細論述了各種節點異常情況下的共識達成,有興趣可以參考。
NEO DBFT
NEO的共識機制也是先選代表,和EOS的不同之處在於,代表之間是按照PBFT的方式達成共識的。由於上文中已經描述了PBFT演算法,所以這裡就不再解釋DBFT的原理了,有興趣的讀者可以參照[16]
非拜占庭問題下的解法
以上的演算法都是在拜占庭問題建模下的共識演算法,以下將介紹“非拜占庭問題”。在拜占庭問題中,我們認為每個節點是可以進行惡意的攻擊的,即節點在傳遞訊息的過程中,可以給不同節點傳遞不同的訊息,從而破壞共識。這種場景是符合開放的網路環境的。
而在較為封閉的網路環境中,比如我們常說的私有鏈,或是公司內部的一些分散式系統中,每個節點是可信的,不會存在惡意的攻擊者。節點在傳遞訊息的過程中,只會因為網路不穩定或是節點掛掉出現漏傳、重傳訊息的情形。因此,有一類演算法是用於解決在這種場景下的共識問題,因此我們稱這種場景建模為非拜占庭問題。
Paxos
早在1990年,Leslie Lamport(即 LaTeX 中的"La",微軟研究院科學家,獲得2013年圖靈獎)向ACM Transactions on Computer Systems (TOCS)提交了關於Paxos演算法的論文The Part-Time Parliament。幾位審閱人表示,雖然論文沒什麼特別的用處,但還是有點意思,只是要把Paxos相關的故事背景全部刪掉。Leslie Lamport心高氣傲,覺得審閱人沒有絲毫的幽默感,於是撤回文章不再發表。直到1998年,使用者開始支援Paxos,Leslie Lamport重新發表文章,但相比1990年的版本,文章沒有太大的修改,所以還是不好理解。於是在2001年,為了通俗性,Leslie Lamport簡化文章發表了Paxos Made Simple,這次文中沒有一個公式。
但事實如何?大家不妨讀一讀Paxos Made Simple。Leslie Lamport在文中漸進式地、從零開始推匯出了Paxos協議,中間用數學歸納法進行了證明。可能是因為表述順序的問題,導致這篇文章似乎還是不好理解。所以這裡我摘錄了一篇對Paxos描述的中文文件[17],供參考。
想要看懂Paxos中共識達成的機制較為簡單,其基本來說就是一個二次確認的過程。
- 首先由使用者向網路中所有節點發出提議n,n是提議的編號
- 節點收到提議n後
- 若編號n比之前接受的提議請求都要大,則承諾將不會接收提議編號比n小的提議,並且帶上之前接受的提議中編號小於n的最大的提議{n0, v0},n0是編號,v0是內容(如果之前沒接受過提議則返回空的訊息)
- 否則不予理會
- 使用者得到了多數節點的承諾後
- 如果發現承諾的節點返回的都是空,則向所有節點傳送自己本次提議的{n, v},讓大家接受
- 否則,從所有節點返回中選擇n0最大的v0,作為提議的值,提議編號仍然為n,即向所有節點傳送{n, v0}讓大家接受
- 節點接收到提議後,如果該提議編號不違反自己做過的承諾,則接受該提議。
Paxos證明了在這種機制下,只要掛掉的節點小於半數,則能實現系統的共識。
Raft
Paxos協議是第一個被證明的一致性演算法,但是Paxos的論文非常難懂,導致基於Paxos的工程實踐和教學都十分頭疼,於是Raft在設計的過程中,就從可理解性出發,使用演算法分解和減少狀態等手段,目前已經應用非常廣泛。可以這麼理解,Raft改進了Paxos的機制,便於理解和在實際場景中程式設計實現。
Raft的詳細描述可以參照[18],由於篇幅所限本文就不詳細介紹了。
總結
本文的目的是列舉目前區塊鏈系統中,已經應用的主流共識機制,並附帶介紹了Paxos和Raft這兩種非拜占庭問題下的共識演算法,便於對所有共識演算法有更好的理解。由於所涉及的演算法較多,所以本文並未對演算法的細節進行特別詳細的描述,而是羅列了相關的參考文獻,便於讀者更加詳細地去了解演算法細節。
本文的主要貢獻是描述了各個演算法的設計思路、使用場景,也許可以使讀者瞭解每個演算法是怎麼想出來的以及怎麼使用。另外,本文還對比了演算法之間的優缺點,便於讀者去了解演算法的不同。
還有一些正在測試中或是開發中的共識機制,將在後續文章中進一步闡述。
參考資料
[1] 拜占庭共識機制
[3] 實用拜占庭容錯演算法PBFT
[4] 分散式系統理論基礎 - CAP
[6] Ethash
[7] Cryptocurrencies without Proof of Work
[8] PPC:一種P2P(點對點)的權益證明(Proof of Stake)密碼學貨幣
[9] BlackCoin's Proof-of-Stake Protocol v2
[10] Security Analysis of Proof-of-Stake Protocol v3.0
[11] The missing explanation of Proof of Stake Version 3
[12] Proof of Stake FAQ
[13] Qtum's PoS vs CASPER (and the nothing-at-stake problem)
[14] Block size limit controversy
[15] EOS.IO Technical White Paper
[16] NEO共識機制
[17] 微信PaxosStore:深入淺出Paxos演算法協議
[18] Raft一致性演算法筆記