1. 程式人生 > >PBFT && RBFT演算法流程

PBFT && RBFT演算法流程

PBFT && RBFT演算法流程以及其實現(上)

這篇文章主要是講一下RBFT中共識演算法流程以及節點的加入的流程。在下一篇部落格中,將使用Java實現該演算法。

傳統的PBFT演算法無法動態的新增和刪除結點,高魯棒拜占庭容錯演算法RBFT(Robust Byzantine Tolerance)演算法實現了該功能。

在RBFT演算法中,有幾個變數我們需要知道:f,N,quorum

  • N ; 代表結點的數量。
  • f :代表PBFT中最多能容忍的錯誤的結點$ f = \lfloor\frac{N-1} { 3} \rfloor$
  • quorum:達到共識需要的結點數量 $quorum = \lceil \frac {N + f +1 }{2 }\rceil $

因此在PBFT演算法中,為了能夠容忍f個錯誤,需要的結點數量是$3f+1$

在RBFT演算法中,有一個主節點和多個從結點,其中主節點是通過選舉產生的,負責對客戶端發來的交易進行打包處理,而從節點很簡單,進行共識認證以及主結點的選取。

RBFT && PBFT的常規流程

下面是來自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常規流程具體分為如下幾個步驟:

  1. 交易轉發階段: 客戶端將交易傳送到區塊鏈中的任意節點(包括共識節點與記賬節點),其中記賬節點在收到交易後會主動轉發給與其相連的共識節點;而共識節點在收到客戶端的交易後將其廣播給其他共識節點,這樣所有共識節點的交易池中都會維護一份完整的交易列表;
  2. PrePrepare階段: 主節點按照如下策略進行打包:使用者可以根據需求自定義打包的超時時間(batch timeout)與打包的最大區塊大小(batch size),主節點在超時時間內收集到了足夠多(超過最大區塊大小個數)的交易或者超時時間到達後仍未收集到足夠多的交易都會觸發主節點的打包事件。主節點將交易按照接收的時間順序打包成塊,並進行驗證,計算執行結果,最後將定序好的交易資訊連同驗證結果等寫入PrePrepare訊息中廣播給所有共識節點,開始三階段處理流程;
  3. Prepare階段: 從節點在收到主節點的PrePrepare訊息後,首先進行訊息合法性檢查,檢查當前的檢視與區塊號等資訊,檢查通過後向共識節點廣播Prepare訊息;
  4. Commit階段: 從節點在收到(quorum-1)個Prepare訊息以及相應的PrePrepare訊息後進行驗證,並將驗證結果與主節點寫入PrePrepare訊息中的驗證結果進行比對,比對結果一致則廣播Commit表明本節點同意主節點的驗證結果,否則直接發起ViewChange表明本節點認為主節點存在異常行為,需要切換主節點;
  5. 寫入賬本: 所有共識節點在收到quorum個Commit訊息後將執行結果寫入本地賬本。

以上的過程還是很簡單的,就是主節點發送交易資訊,如果大部分的從結點(也就是quorum個結點)同意,則這個交易資訊會被寫入所有結點的區塊(少數服從多數)。

在前面我們可以發現,從節點是可以懷疑主節點的,也就是說從節點可以發起請求進行重新選舉,得到一個新的主節點(這個在主節點被攻擊或者宕機是非常有效的)。

主節點的生成以及變遷

在PBFT以及RBFT中,都有檢視(View),這個值從零開始只增不減。那麼我們如何得到主節點呢?或者說重新選舉,選擇誰為主節點。

設:結點數為N,當前檢視為view,則主結點的id為:

$$primaryId = (view +1) mod N$$

下面的引用還是來自hyperchain,畢竟有圖能夠理解的更好。其中:

  • nullRequest 訊息的目的是檢視主節點是不是線上

檢視變更流程


上圖中,Primary 1為拜占庭節點,需要進行ViewChange。在RBFT中的ViewChange流程如下:

  1. 從節點在檢測到主節點有異常情況(沒有按時收到nullRequest訊息)或者接收到來自其他f+1個節點的ViewChange訊息之後會向全網廣播ViewChange訊息,自身view從v更改為v+1;
  2. 新檢視中主節點收到N-f 個ViewChange訊息後,根據收到的ViewChange訊息計算出新檢視中主節點開始執行的checkpoint和接下來要處理的交易包,封裝進NewView訊息並廣播,發起VcReset;
  3. 從節點接收到NewView訊息之後進行訊息的驗證和對比,如果通過驗證,進行VcReset,如果不通過,傳送ViewChange訊息,進行又一輪ViewChange;
  4. 所有節點完成VcReset之後向全網廣播FinishVcReset;
  5. 每個節點在收到N-f個FinishVcReset訊息之後,開始處理確定的checkpoint後的交易,完成整個ViewChange流程。

由於共識模組與執行模組之間是非同步通訊的,而ViewChange之後執行模組可能存在一些無用的validate快取,因此共識模組需要在ViewChange完成之前通知執行模組清除無用的快取,RBFT通過VcReset事件主動通知執行模組清除快取,並在清理完成之後才能完成ViewChange。

RBFT中結點動態的增添和刪除

在前面我們知道,PBFT演算法是無法實現結點動態的增刪的,而新的演算法RBFT實現了該功能。

結點的增加和刪除當然會遵守共識原則,下面還是來自hyperchain的介紹。畢竟別人介紹的比我好多了,我就不多介紹了。

簡單點來說,就是新加入的結點會向區塊鏈中的已經存在的結點申請加入,如果存在的結點同意的話,則就加入成功,然後新加入的結點會發送recovery訊息(關於recovery可以看hyperchain的介紹),目的是為了讓自己與區塊鏈中結點的內容保持一致。然後新加入的結點會要求進行重新選舉主節點(因為N已經發生改變),然後完成主節點的更改。

新增節點流程


上圖中,Replica 5為待新增的節點。RBFT節點的動態新增節點流程如下:

  1. 新增節點Replica 5通過讀取配置檔案資訊,主動向現有節點發起連線,確認所有節點連線成功後更新自身的路由表,併發起recovery;
  2. 現有節點接收到Replica 5的連線請求後確認同意該節點加入,然後向全網廣播AddNode訊息,表明自己同意該新節點加入整個共識網路;
  3. 當現有節點收到N條(N為現有區塊鏈共識網路中節點總數)AddNode訊息後,更新自身的路由表,隨後開始迴應新增節點的共識訊息請求(在此之前,新增節點的所有共識訊息是不予處理的);
  4. Replica 5完成recovery之後,向全網現有節點廣播ReadyForN請求;
  5. 現有節點在收到ReadyForN請求後,重新計算新增節點加入之後的N,view等資訊,隨後將其與PQC訊息封裝到AgreeUpdateN訊息中,進行全網廣播;
  6. Replica 5加入後的共識網路會產生一個新的主節點,該主節點在收到N-f個AgreeUpdateN訊息後,以新的主節點的身份傳送UpdateN訊息;
  7. 全網所有節點在收到UpdateN訊息之後確認訊息的正確性,進行VCReset;
  8. 每個節點完成VCReset後,全網廣播FinishUpdate訊息;
  9. 節點在收到N-f個FinishUpdate訊息後,處理後續請求,完成新增節點流程。

這篇文章基本上就是從hyperchain上面copy上來的,在這裡僅僅是做一個筆記用。如果想了解更多,建議參考官方文件。這一篇主要是為了弄清楚PBFT or RBFT的流程,這幾天在看《區塊鏈底層設計 Java實戰》一直沒弄得太懂,然後程式碼也寫的沒頭緒。這裡不得不感謝牛冬(這本書的作者)大佬,很熱心的回答我的問題(真沒想到加作者的微信竟然加成功了O(∩_∩)O~~)。

哦,還得掉頭髮,想一想怎麼實現這些演算法……


參考

  1. hyperchain:https://hyperchain.readthedocs.io/zh_CN/latest/consensus.html#