背景
从事区块链相关研发几年了,共识这一块接触过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,这个问题上文已经做了陈述
- 通过签名和摘要等来判断消息是否被篡改,收到的消息是否正确,一般会对消息摘要进行私钥签名
来源:CSDN
作者:卢舍那
链接:https://blog.csdn.net/yunlilang/article/details/103804110