再读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发送请求:, c的signature;
2、primary会对req分配一个序号seq n,生成pre-prepare:<,signature,m>;并广播到副本节点reps.
3、rep节点收到pre-prepare,如果满足一下条件则接受:

  • 签名校验,这个可以防止primary篡改client的消息;消息内容的digest对比,防止消息内容篡改
  • 判断是否和自己处于同一View
  • 判断是否接受过同一View,seq但digest不同的请求
  • 判断请求的seq是否处于水位线之内

4、如果副本节点i接受pre-prepare,则进入prepare阶段,广播,i的签名。
5、如果节点满足以下条件则认为prepared:

  • 一个消息m,处于view v,seqnum 为n的pre-prepare,并收到该消息的来自2f个其他不同节点的prepare消息,也就是检查:
    • 同一view
    • 同一seq
    • 同一digest

6、当处于prepared,则进入Commit阶段,广播,signature;
7、如果收到2f+1个commit,则执行,并把结果返回client.
8、当Client收到f+1个相同结果,则认为执行成功,因为最多有f个错误,收到f+1个相同结果说明都是对的。

checkpoint协议

主要因为在共识过程中要保存message到log,为减少存储的消息,会有一个稳定状态的检查,如果达到稳定状态则删除之前的消息。
每隔一段时间会产生一个checkpoint,,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、广播,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后,广播,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处于之间的,产生新的view v+1中的pre-prepare message,这里主要有两种情况:
      • 1、如果P集合中中至少存在一个sequence num 大于稳定checkpoint n的已经prepared的Pm结合,这时primary会产生,signature;其中d是sequence n的在V中最高view number的request digest.
      • 2、如果P集合中不存在Pm,则产生,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,这个问题上文已经做了陈述
  • 通过签名和摘要等来判断消息是否被篡改,收到的消息是否正确,一般会对消息摘要进行私钥签名

你可能感兴趣的:(区块链,共识算法)