這篇文章主要是講一下RBFT中共識算法流程以及節點的加入的流程。在下一篇博客中,將使用Java實現該算法。html
傳統的PBFT算法沒法動態的添加和刪除結點,高魯棒拜占庭容錯算法RBFT(Robust Byzantine Tolerance)算法實現了該功能。node
在RBFT算法中,有幾個變量咱們須要知道:f,N,quorum算法
所以在PBFT算法中,爲了可以容忍f個錯誤,須要的結點數量是$3f+1$緩存
在RBFT算法中,有一個主節點和多個從結點,其中主節點是經過選舉產生的,負責對客戶端發來的交易進行打包處理,而從節點很簡單,進行共識認證以及主結點的選取。微信
下面是來自hyperchain的關於RBFT流程的一些介紹:網絡
RBFT常規流程
RBFT的常規流程保證了區塊鏈各共識節點以相同的順序處理來自客戶端的交易。RBFT同PBFT的容錯能力相同,須要至少3f+1個節點才能容忍f個拜占庭錯誤。下圖爲最少集羣節點數下的共識流程,其N=4,f=1。圖中的Primary1爲共識節點動態選舉出來的主節點,負責對客戶端發來的交易進行排序打包,Replica2,3,4爲從節點。全部節點執行交易的邏輯相同並可以在主節點失效時參與新主節點的選舉。併發
常規流程
RBFT共識保留了PBFT原有的三階段處理流程(PrePrepare、Prepare、Commit)的同時增長了重要的交易驗證(validate)環節,在保證對交易執行順序達成共識的同時也保證了對區塊驗證結果的共識。異步
RBFT常規流程在原生的PBFT算法中穿插了交易驗證環節,主節點將交易打包成塊後先行驗證,並將驗證結果包含到PrePrepare消息中進行全網廣播,這樣PrePrepare消息中既包含了排好序的交易信息也包含了區塊驗證結果。從節點在收到主節點的PrePrepare消息後先檢查消息的合法性,檢查經過後廣播Prepare消息代表本節點贊成主節點的排序結果;在收到(quorum-1)個Prepare消息後從節點纔會開始驗證區塊,並將驗證結果與主節點的驗證結果進行比對,比對結果一致則廣播Commit代表本節點贊成主節點的驗證結果,不然直接發起ViewChange代表本節點認爲主節點有異常行爲。RBFT常規流程具體分爲以下幾個步驟:svg
- 交易轉發階段: 客戶端將交易發送到區塊鏈中的任意節點(包括共識節點與記帳節點),其中記帳節點在收到交易後會主動轉發給與其相連的共識節點;而共識節點在收到客戶端的交易後將其廣播給其餘共識節點,這樣全部共識節點的交易池中都會維護一份完整的交易列表;
- PrePrepare階段: 主節點按照以下策略進行打包:用戶能夠根據需求自定義打包的超時時間(batch timeout)與打包的最大區塊大小(batch size),主節點在超時時間內收集到了足夠多(超過最大區塊大小個數)的交易或者超時時間到達後仍未收集到足夠多的交易都會觸發主節點的打包事件。主節點將交易按照接收的時間順序打包成塊,並進行驗證,計算執行結果,最後將定序好的交易信息連同驗證結果等寫入PrePrepare消息中廣播給全部共識節點,開始三階段處理流程;
- Prepare階段: 從節點在收到主節點的PrePrepare消息後,首先進行消息合法性檢查,檢查當前的視圖與區塊號等信息,檢查經過後向共識節點廣播Prepare消息;
- Commit階段: 從節點在收到(quorum-1)個Prepare消息以及相應的PrePrepare消息後進行驗證,並將驗證結果與主節點寫入PrePrepare消息中的驗證結果進行比對,比對結果一致則廣播Commit代表本節點贊成主節點的驗證結果,不然直接發起ViewChange代表本節點認爲主節點存在異常行爲,須要切換主節點;
- 寫入帳本: 全部共識節點在收到quorum個Commit消息後將執行結果寫入本地帳本。
以上的過程仍是很簡單的,就是主節點發送交易信息,若是大部分的從結點(也就是quorum個結點)贊成,則這個交易信息會被寫入全部結點的區塊(少數服從多數)。區塊鏈
在前面咱們能夠發現,從節點是能夠懷疑主節點的,也就是說從節點能夠發起請求進行從新選舉,獲得一個新的主節點(這個在主節點被攻擊或者宕機是很是有效的)。
在PBFT以及RBFT中,都有視圖(View),這個值從零開始只增不減。那麼咱們如何獲得主節點呢?或者說從新選舉,選擇誰爲主節點。
設:結點數爲N,當前視圖爲view,則主結點的id爲:
$$primaryId = (view +1) mod N$$
下面的引用仍是來自hyperchain,畢竟有圖可以理解的更好。其中:
視圖變動流程
上圖中,Primary 1爲拜占庭節點,須要進行ViewChange。在RBFT中的ViewChange流程以下:
- 從節點在檢測到主節點有異常狀況(沒有按時收到nullRequest消息)或者接收到來自其餘f+1個節點的ViewChange消息以後會向全網廣播ViewChange消息,自身view從v更改成v+1;
- 新視圖中主節點收到N-f 個ViewChange消息後,根據收到的ViewChange消息計算出新視圖中主節點開始執行的checkpoint和接下來要處理的交易包,封裝進NewView消息並廣播,發起VcReset;
- 從節點接收到NewView消息以後進行消息的驗證和對比,若是經過驗證,進行VcReset,若是不經過,發送ViewChange消息,進行又一輪ViewChange;
- 全部節點完成VcReset以後向全網廣播FinishVcReset;
- 每一個節點在收到N-f個FinishVcReset消息以後,開始處理肯定的checkpoint後的交易,完成整個ViewChange流程。
因爲共識模塊與執行模塊之間是異步通訊的,而ViewChange以後執行模塊可能存在一些無用的validate緩存,所以共識模塊須要在ViewChange完成以前通知執行模塊清除無用的緩存,RBFT經過VcReset事件主動通知執行模塊清除緩存,並在清理完成以後才能完成ViewChange。
在前面咱們知道,PBFT算法是沒法實現結點動態的增刪的,而新的算法RBFT實現了該功能。
結點的增長和刪除固然會遵照共識原則,下面仍是來自hyperchain的介紹。畢竟別人介紹的比我好多了,我就很少介紹了。
簡單點來講,就是新加入的結點會向區塊鏈中的已經存在的結點申請加入,若是存在的結點贊成的話,則就加入成功,而後新加入的結點會發送recovery消息(關於recovery能夠看hyperchain的介紹),目的是爲了讓本身與區塊鏈中結點的內容保持一致。而後新加入的結點會要求進行從新選舉主節點(由於N已經發生改變),而後完成主節點的更改。
新增節點流程
上圖中,Replica 5爲待新增的節點。RBFT節點的動態新增節點流程以下:
- 新增節點Replica 5經過讀取配置文件信息,主動向現有節點發起鏈接,確認全部節點鏈接成功後更新自身的路由表,併發起recovery;
- 現有節點接收到Replica 5的鏈接請求後確認贊成該節點加入,而後向全網廣播AddNode消息,代表本身贊成該新節點加入整個共識網絡;
- 當現有節點收到N條(N爲現有區塊鏈共識網絡中節點總數)AddNode消息後,更新自身的路由表,隨後開始迴應新增節點的共識消息請求(在此以前,新增節點的全部共識消息是不予處理的);
- Replica 5完成recovery以後,向全網現有節點廣播ReadyForN請求;
- 現有節點在收到ReadyForN請求後,從新計算新增節點加入以後的N,view等信息,隨後將其與PQC消息封裝到AgreeUpdateN消息中,進行全網廣播;
- Replica 5加入後的共識網絡會產生一個新的主節點,該主節點在收到N-f個AgreeUpdateN消息後,以新的主節點的身份發送UpdateN消息;
- 全網全部節點在收到UpdateN消息以後確認消息的正確性,進行VCReset;
- 每一個節點完成VCReset後,全網廣播FinishUpdate消息;
- 節點在收到N-f個FinishUpdate消息後,處理後續請求,完成新增節點流程。
這篇文章基本上就是從hyperchain上面copy上來的,在這裏僅僅是作一個筆記用。若是想了解更多,建議參考官方文檔。這一篇主要是爲了弄清楚PBFT or RBFT的流程,這幾天在看《區塊鏈底層設計 Java實戰》一直沒弄得太懂,而後代碼也寫的沒頭緒。這裏不得不感謝牛冬(這本書的做者)大佬,很熱心的回答個人問題(真沒想到加做者的微信居然加成功了O(∩_∩)O~~)。
哦,還得掉頭髮,想想怎麼實現這些算法……