PBFT的简单分享

本篇文章将对PBFT共识算法提出的原因以及实现的过程做一个简单的剖析,其中会对其过程做一个深入简单的思考,若有错误,请及时联系作者。

拜占庭将军问题最早由 Leslie Lamport 在 20 世纪 80 年代提出。拜占庭是东罗马帝国的首都,在战争中,分布在各个驻地的将军们需要通过信使传递消息来制定统一的作战计划。为了防止将军中有叛徒通过篡改行动计划影响军队一致的行动,将军们要制定一个协议,使 得忠诚的将军们能够达成一致,并且一定数量内的叛徒不能影响一致的达成。要求解拜占庭将军问题,须满足以下两个条件:
(1)忠诚的将军收到的命令必须相同;
(2)如果一个将军是忠诚的,那么他发送的命令也必须和每个忠诚将军收到的命令相同。
在分布式计算领域中,把任何观察者从不同角度看都表现出不同症状的缺陷定义为拜占庭缺陷(Byzantine Fault),把在需要共识的系统中由于拜占庭缺陷导致丧失系统服务的故障称为拜占庭故障(Byzantine Failure)。而寻找一种实用的解决拜占庭将军问题的算法一直是分布式计算领域重要的研究方向。在有拜占庭缺陷的分布式系统中,所有进程都有一个初始值,所谓共识问题,即寻找一个满足以下三个属性的算法或协议:
(1)一致性(Agreement):所有非拜占庭进程都必须同意一个值
(2)正确性(Validity):若所有非拜占庭进程拥有的初始值相同,那么所有非拜占庭进程所同意的值必须为同一个初始值;
(3)可结束性(Termination):每个非拜占庭进程最终必须确定一个值。
区块链系统中,分布式账本记账共识问题与拜占庭将军问题类似,区块链网络上的记账节点相当于将军,而节点之间的信息传递相当于信使。Lamport 提出的原始的拜占庭容错机制由于要展示其理论上的可行性而过于复杂,难以理解并且实用性较差。时钟同步机制的使用也使得算法的复杂度随节点数量的增加呈指数级增加。1999 年,Castro 等人提出了 PBFT(实用拜占庭容错)算法,将拜占庭协议的运行复杂度从指数级别降低到了多项式级别,大大提升了拜占庭协议的可用性。PBFT 是一类状态机拜占庭系统,该协议要求节点共同维护一个状态,并且采取一致的行动。该协议由一致性协议、检查点协议和视图转换协议三部分构成

在讲述共识算法PBFT之前,首先要知道,在分布式系统中,一致性算法都要提供safety以及liveness。

  • safety:原意是指不会出现错误情况,一致性中指操作时正确的,得到相同的结果
  • liveness:操作过程能在有限时间内完成

拜占庭算法在失效节点数量不超过(n-1)/3 的情况下同时保证安全性和活性(safety & liveness)。

  • 安全性是指副本复制服务满足线性一致性(linearizability),就像中心化系统一样原子化执行操作。安全性要求失效副本的数量不超过上限,但是对客户端失效的数量和是否与副本串谋不做限制。系统通过访问控制来限制失效客户端可能造成的破坏,审核客户端并阻止客户端发起无权执行的操作。同时,服务可以提供操作来改变一个客户端的访问权限。因为算法保证了权限撤销操作可以被所有客户端观察到,这种方法可以提供强大的机制从失效的客户端攻击中恢复。
  • 算法不依赖同步提供安全性,因此必须依靠同步提供活性。否则,这个算
    法就可以被用来在异步系统中实现共识,而这是不可能的(由 Fischer1985 的论文证明)。本文的算法保证活性,即所有客户端最终都会收到针对他们请求的回复,只要失效副本的数量不超过(n-1)/3,并且延迟 delay(t)不会无限增长。这个 delay(t)表示 t 时刻发出的消息到它被目标最终接收的时间间隔,假设发送者持续重传直到消息被接收。这时一个相当弱的同步假设,因为在真实系统中网络失效最终都会被修复。但是这就规避了 Fischer1985 提出的异步系统无法达成共识的问题。

在这里插入图片描述

  • 第一阶段:request
    客户端向主节点发送request请求,request包括请求的内容以及请求的摘要,<REQUEST,o,t,c>,其中o代表需要执行的操作,t代表请求时客户端追加的时间戳,c代表客户端标识。客户端需要对请求签名。

  • 第二阶段:pre-prepare
    主节点收到客户端发送的request之后,首先检查request是否合理,如果合理,向此request请求添加一个唯一编号n(用来将这些合理的请求进行编号,同时在垃圾回收当中会运用到),再向每一个副本节点广播<<PRE-PREPARE,v,n,d>,m>,其中d代表消息内容的摘要,m代表消息内容,v代表视图编号,n代表主节点给每一个节点的编号,此编号必须在[h,H]之间,水线的低值 h 与最近稳定检查点的序列号相同,而水线的高值 H=h+k,k 需要足够大才能使副本不至于为了等待稳定检查点而停顿。此详细原因将同view change 一同讲到,<PRE-PREPARE,v,n,d>进行主节点签名。
    注意:每一个节点都有自己的视图编号,视图编号的作用:将每一个节点编号,方便进行view changes(防止因主节点出现拜占庭错误导致系统无法继续运行),关于view changes我们将在后面详细讲到。

  • 第三阶段:prepare
    各位副本节点在收到了来自主节点广播的pre-prepare之后,
    ①首先验证主节点pre-prepare的消息签名是否正确
    ②然后检验是否在同一v下,收到编号n,签名不同的<<PRE-PREPARE,v,n,d>,m>
    ③之后检查d和d(m)是否一致
    ④检查n是否在[h,H]区间内

    若①-④都未出现问题,那么广播<PREPARE,v,n,d,i>,给其他节点(包括主节点),其中i代表当前节点的编号,v,n,d含义与上述相同,在这里就不做过多描述<PREPARE,v,n,d,i>进行副本节点i的签名,记录pre-prepare和prepare消息到log中,用于view change过程中恢复未完成的请求操作。
    理解:由主节点发出的pre-prepare中可能会认为消息摘要d和消息内容m发送的有点冗余,这里面的消息摘要为消息内容加密后的内容,但我这里认为在第三阶段第③步很好的解释了这一点,主节点将<PRE-PREPARE,v,n,d>进行签名,消息内容是无保留的广播给各个节点,那么各个节点如何验证此签名是主节点呢?通过主节点的公钥验证签名,若消息经过单向加密之后得到的消息摘要结果与之一致,则证明此消息正确。

  • 第四阶段:commit
    ①检查本节点收到的prepare请求签名是否正确
    ②检查是否已经收到了同一视图v下的n
    ③检查n是否在[h,H]区间内
    ④检查d是否和当前已经收到的<<PRE-PREPARE,v,n,d>,m>中的d相同

    如果满足前四点条件,同时收到了2f+1个验证通过的prepare消息,那么广播<COMMIT,v,n,d,i>给其他节点(包括主节点),其中v,n,d,i和上述prepare消息内容相同,<COMMIT,v,n,d,i>进行副本节点i的签名,记录COMMIT消息到日志中,用于view change过程中恢复未完成的请求操作,记录其他副本节点发送的prepare消息到log中。

  • 第五阶段:reply
    ①主节点和副本节点收到commit消息之后检查消息签名是否正确
    ②检查当前副本节点是否收到了同一视图下的n
    ③检查d和d(m)是否一致
    ④检查n是否在[h,H]区间内

    如果满足前四点条件同时收到2f+1个验证通过的commit,运行客户端的请求操作o,同时返回<REPLY,v,t,c,i,r>给客户端,r为请求操作结果,客户端如果收到f+1个相同的reply消息,说明客户端发起的请求已经达到全网共识,否则客户端需要判断是否需要重新发送请求给主节点,记录其他副本节点发送的commit消息到log中。

  • 为什么拜占庭的节点总数必须≥3f+1,同时实用拜占庭容错机制最多只能容忍f个恶意节点,f代表恶意节点和故障节点?
    答:假设忠诚的将军数量为T,恶意节点数量为F,为了最后达成共识,那么若T的数量小于或者等于F,最后客户端无法判别共识的结果,也就是说,当拿到两份票数一样的选票甚至是应该被认可的那张选票还少于恶意作恶的选票,那么会导致此共识的失败,所以,达成共识必须在T>F的情况下。那么在分布式系统中,我们容忍故障节点F个,也就是忠诚的将军因为某种自身的情况下,不能传递信息,那么主节点能够收到的有效T信息的数量就为T-F,在恶意节点数量为F的情况下,必须保证T-F>F,即是T>2F,总节点的个数就为N=T+F>3F
    什么是View change?
    对于view change,其作用主要有两点:①、防止主节点是恶意节点的时候导致不能达成共识,从而保证算法的liveness;②防止主节点是故障节点导致在一定时间内,分布式系统不能完成共识,系统等待。
    View Change的核心因素只有一个:怀疑当前的主节点在有限的时间内,无法达成一致

view change中文翻译即为视图转化,这里我把他理解为主节点轮换。
发生view change的两种情况:
①、当主节点为恶意节点的时候 在这里插入图片描述各个节点之间等不到2f+1个相同信息(因为每个节点收到的消息都不一致)
在这里插入图片描述各个节点,死等……等一个时间片
在这里插入图片描述等一个时间片都等不到
在这里插入图片描述换队长!
在这里插入图片描述②、当主节点为故障节点的时候,客户端发送request请求给主节点,主节点长时间为响应,客户端将消息发送给副本节点,副本节点使用定时器,若超过定时器则判定主节点为故障节点,并向其他节点发送view changes请求,开启视图更换。

View change的过程如下:
在这里插入图片描述从节点判定主节点有问题时,会向其他节点发送 view-change 消息,当前存活节点中编号最小的节点则将按序成为下一个主节点;当新的主节点收到 2f 个其他节点的视图编号为v+1 的 view-change 消息时,则证明足够多的节点已经判定当前主节点存在问题,那么下一个主节点就会向其他节点广播 new-view 消息。需要注意的是,从节点没有权利发起 new-view事件,而下一个主节点发送 new-view 消息后会将上个视图未处理完的请求执行完。其他节点对 new-view 消息验证通过后,就会开始处理当前主节点发来的 pre-pare 消息,至此,整个系统进入编号为 v+1 的视图 。该过程的流程如图所示,图中 v 表示上一个视图的编号,i 表示节点的编号,n 表示 i 节点的 stable checkpoint 的编号,C 表示 2f+1 个节点的有效checkpoint 信息的集合,P 表示 i 节点中上一个视图中编号大于 n 并且达到 prepared 状态的请求消息的集合,V 表示新的主节点接收到的有效视图编号为 v+1 的 view-change 的消息的集合,new-view 消息中 O 为 pre-prepare 消息的集合。

为何是收到2f+1个消息,就能证明节点已经判定当前主节点存在问题?
首先,当收到2f+1个消息时,在作恶节点数量为f的前提下,已经可以确定哪个消息为真,也就是说,剩下未收到的节点的消息不影响最终的结果,同时还可以避免收到3f个消息带来的不必要的网络延迟。
在这里插入图片描述由此可以看出,当收到了2f+1个commit之后便可执行下一步reply操作,此时不影响最终结果.

关于PBFT的垃圾回收
为了节省内存,系统需要一种将日志中的 无异议消息记录 删除的机制。为
了保证系统的安全性,副本节点在删除自己的消息日志前,需要确保至少 f+1个正常副本节点执行了消息对应的请求,并且可以在视图变更时向其他副本节点证明。另外,如果一些副本节点错过部分消息,但是这些消息已经被所有正常副本节点删除了,这就需要通过传输部分或者全部服务状态实现该副本节点的同步。因此,副本节点同样需要证明状态的正确性。
在每一个操作执行后都生成这样的证明是非常消耗资源的。因此,证明过
程只有在请求序号可以被某个常数(比如 100)整除的时候才会周期性地进
行。我们将这些请求执行后得到的状态称作 检查 点( checkpoint ) ,并且将具有证明的检查点称作 稳定检查点( stable checkpoint ) 。
副本节点保存了服务状态的多个逻辑拷贝,包括最新的稳定检查点,零个
或者多个非稳定的检查点,以及一个当前状态。写时复制技术可以被用来减少存储额外状态拷贝的空间开销。
检查点的正确性证明的生成过程如下:当副本节点 i 生成一个检查点后,
向其他副本节点广播检查点消息<CHECKPOINT,n,d,i>,这里 n 是最近一个影响状态的请求序号,d 是状态的摘要。每个副本节点都默默地在各自的日志中收集并记录其他节点发过来的检查点消息,直到收到来自 2f+1 个不同副本节点的具有相同序号 n 和摘要 d 的检查点消息。 这 2f+1 个消息就是这个检查点的正确性证明 。
具有证明的检查点成为稳定检查点,然后副本节点就可以将所有序号小于
等于 n 的预准备、准备和确认消息从日志中删除。同时也可以将之前的检查点和检查点消息一并删除。

文献参考:
[1]PBFT 算法研究报告 -----2016 趣链科技
[2]再读PBFT算法 -----卢舍那
[3]Practical Byzantine Fault Tolerance ----Miguel Castro and Barbara Liskov Massachusetts Institute of Technology
[4]A New Paradigm for Collision-free Hashing: Incrementality at Reduced Cost. In Advances inCryptology ------M. Bellare and D. Micciancio.
[5]A Correctness Proof for a Practi-cal Byzantine-Fault-Tolerant Replication Algorithm ------M. Castro and B. Liskov.
[6]AsynchronousConsensusandBroadcastProtocols ------G.Brachaand S.Toueg.
[7]Impossibility of Distributed Consensus With One Faulty Process ------M. Fischer, N. Lynch, and M. Paterson
[8]对PBFT算法的一点理解 -------yijiull
[9]PBFT算法流程补充(一):视图变更、垃圾回收及状态机不确定性 -----WXblockchain1
[10]区块链四:共识机制——PBFT算法深入讲解 ----蠢物
[11]深入浅出PBFT算法原理 ------jfkidear
[12]PBFT ------北海几经夏
[13]区块链中实用拜占庭容错共识机制的研究与改进 ------王若琪,徐明昆
[14]PBFT共识算法的改进及其应用研究 --李腾
[15]基于改进PBFT算法防御区块链中sybil攻击的研究 --赖英旭 薄尊旭 刘静

源码参考:https://github.com/corgi-kx/blockchain_consensus_algorithm/tree/master/pbft

猜你喜欢

转载自blog.csdn.net/qq_52696089/article/details/120861167