再讀PBFT算法

背景

從事區塊鏈相關研發幾年了,共識這一塊接觸過pbft\kafka\raft,當然還有最經典的比特幣的工作量證明,這個在上一篇比特幣原理一文有講述。對pbft一開始從fabric0.6開始,論文也看了幾遍,後來共識換成了kafka\raft。pbft就沒有繼續研究下去,最近接觸一個區塊鏈底層平臺,採用pbft。因此這裏又把論文讀了一遍,總結一下心得體會,對一些比較難理解的地方進行梳理。

PBFT算法

爲什麼是3f+1?

關於分佈式系統裏能夠容拜占庭錯誤的節點數n>3f+1,這個結論早在1982年圖靈獎得主lamport《The Byzantine Generals Problem》已經證明過:當將軍總數大於3f時,叛徒數小於等於f時,忠誠將軍能夠達成一致,其算法複雜度爲指數O(n^(f+1))。

圖靈獎得主Barbara Liskov和其學生Miguel Castro在1999年發表的論文《Practical Byzantine Fault Tolerance》中首次提出pbft算法,該算法容錯數量也滿足3f+1<=n,算法複雜度爲O(n^2)讓容拜占庭錯誤的共識算法可用於工程實踐。

下面是自己的一些理解及簡單證明,至於詳細的證明論述可以參考Lamport論文。例如A、B、C三位將軍,忠誠將軍應該執行進攻命令;A是叛徒,向B發送撤退指令,向C發送進攻指令。這時對於B將軍來講,他分不清A是叛徒還是C是叛徒。

證明

設總結點數爲N,作惡的拜占庭節點數爲 f,法定人數爲Q。

  • 要滿足liveness必須:
    Q <= N - f
    因爲如果共識算法需要的Q大於N-f,則當f個拜占庭故障節點都主動破壞時,算法必然不能執行下去。

  • 要滿足safety必須:
    2Q - N > f
    因爲任何兩個quorum的交集(2Q - N)中必須有非拜占庭故障節點大於f個。如果2Q - N <= f,此時f個節點同時加入到兩個Quorum中說不同的話,系統內會同時通過兩個不同的意見,此時系統一致性無法滿足。

  • 因此
    N + f < 2Q <= 2(N - f)
    N > 3f
    Q_min=2f+1

PBFT共識協議

1、client向Primary發送請求:<REQUEST,o,t,c>, c的signature;
2、primary會對req分配一個序號seq n,生成pre-prepare:<<PRE-PREPARE, v, n,d>,signature,m>;並廣播到副本節點reps.
3、rep節點收到pre-prepare,如果滿足一下條件則接受:

  • 簽名校驗,這個可以防止primary篡改client的消息;消息內容的digest對比,防止消息內容篡改
  • 判斷是否和自己處於同一View
  • 判斷是否接受過同一View,seq但digest不同的請求
  • 判斷請求的seq是否處於水位線之內<h,H>

4、如果副本節點i接受pre-prepare,則進入prepare階段,廣播<PREPARE,v,n,d,i>,i的簽名。
5、如果節點滿足以下條件則認爲prepared:

  • 一個消息m,處於view v,seqnum 爲n的pre-prepare,並收到該消息的來自2f個其他不同節點的prepare消息,也就是檢查:
    • 同一view
    • 同一seq
    • 同一digest

6、當處於prepared,則進入Commit階段,廣播<COMMIT, v, n, D(m), i>,signature;
7、如果收到2f+1個commit,則執行,並把結果返回client.
8、當Client收到f+1個相同結果,則認爲執行成功,因爲最多有f個錯誤,收到f+1個相同結果說明都是對的。

checkpoint協議

主要因爲在共識過程中要保存message到log,爲減少存儲的消息,會有一個穩定狀態的檢查,如果達到穩定狀態則刪除之前的消息。
每隔一段時間會產生一個checkpoint,<CHECKPOINT,n,d,i>,signature;如果rep收到2f+1個checkpoint,則認爲此時seq爲n,處於穩定狀態,n之前的消息可以刪除。並更新水位線,h=n、H=h+k。

viewchange協議

當primary節點掛掉後,viewchange協議保證了liveness。

副本節點rep收到request時如果timer還沒啓動則啓動timer直到該交易執行完成;

1、如果timer time out了,則會view change,這時只接收checkpoint,view-change,new-view消息,其他不接收

2、廣播<VIEW-CHNAGE,v+1,n,C,P,i>,signature消息到所有節點,其中:

  • n:最近一個節點 rep i 的穩定checkpoint s 的sequence num
  • C:是2f+1個checkpoint消息的集合,以此證明穩定checkpoint s的正確性
  • P是Pm的集合,主要是sequence num 大於n 的已經在節點i prepared的request m的集合。
    • Pm包括request m的valid的2f+1個pre-prepare message、valid的被不同節點簽名的同一view、同一sequence num、同一digest的prepare消息。

3、當view v+1的primary節點收到來自其他2f個節點的view v+1的view-change後,廣播<NEW-VIEW,v+1,V,O>,signature到其它節點,其中:

  • V:primary節點收到的view v+1的view-change messages,包括primary自己的
  • O:是pre-prepare的集合,按照下面規則計算得出:
    • 1、primary計算出checkpoint中最小的sequence num:min-s;在V集合中計算出prepare message的最大sequence num:max-s.
    • 2、primary節點對sequence num處於<min-s,max-s>之間的,產生新的view v+1中的pre-prepare message,這裏主要有兩種情況:
      • 1、如果P集合中中至少存在一個sequence num 大於穩定checkpoint n的已經prepared的Pm結合,這時primary會產生<PRE_PREPARE,v+1,n,d>,signature;其中d是sequence n的在V中最高view number的request digest.
      • 2、如果P集合中不存在Pm,則產生<PRE_PREPARE,v+1,n,d-null>,signature,d-null是一個特殊的null request的消息摘要

4、接下來,Primary會把O中消息記錄到自己log中,如果min-s latest stable checkpoint的seq num,也把seq-num爲min-s的checkpoint 記錄到log中。併除去stable checkpoint以前的消息。

5、副本節點接受view v+1的new-view message,如果滿足:

  • 簽名正確
  • view-change message裏面的消息內容正確
  • set O正確:會按照primary節點生成O的方式重新生成一遍
    然後副本節點會把消息添加到log中同primary節點一樣,並廣播O中消息的prepares,並把這些prepare記錄到log中,進入view v+1.

協議使得重新執行min-s到max-s的消息,但避免重新執行client的request,利用存儲在自己log中的消息。
有些節點可能丟失 request message或者stable checkpoint s,因爲在new-view message中沒有傳遞,這些內容可以通過向其他節點同步來獲得。

幾點心得體會

  • pre-prepare、prepare保證了同一view的消息有序;prepare、commit和view change保證不同view之間的消息有序
  • 爲什麼是3f+1,這個問題上文已經做了陳述
  • 通過簽名和摘要等來判斷消息是否被篡改,收到的消息是否正確,一般會對消息摘要進行私鑰簽名
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章