本文为万向区块链技术中心研究组撰写,文章尝试对PBFT算法的正确性证实以及算法优化等内容做一个介绍。算法
本部分介绍PBFT算法的正确性证实。安全
PBFT算法提供的安全性(safety)的具体含义是,对于全部本地确认(commit locally)的客户端请求来讲,系统中全部正常副本节点都会就这些请求的消息序号达成一致。并发
上述的“达成一致”,其含义又分为两种:性能
同一视图中的消息序号一致:对于全部在同一视图中本地确认的客户端请求来讲,各正常副本节点就其消息序号会达成一致。
新旧视图中的消息序号一致:对于在新旧视图中本地确认的客户端请求来讲,各正常副本节点就其消息序号会达成一致。区块链
接下来分别证实上述两种“一致”是成立的。优化
1. 在同一视图中,任何一个请求 m ,若是其已经本地确认过,也就是说,至少对于某一个正常副本节点 i 来讲,prepared(m, v, n, i) 为 true , 以前已经证实过,此时,对于任意的正常副本节点 j (j也能够是 i) 来讲,prepared(m’, v, n, j) 都为 false 。这里 m’ 是不一样于 m 的另外一个请求,也就是说 D(m’) 不等于 D(m) 。这就意味着对于全部在同一视图中本地确认的客户端请求来讲,各正常副本节点就其消息序号会达成一致,第一个性质成立。spa
2. 如今考虑存在视图变动的状况。首先,在视图 v 中,对于任意一个请求 m 来讲,若是其在 某个正常副本节点 i 完成了本地确认,假设其消息序号为 n 。那么,就有 committed(m, v, n) 为 true 。 这也意味着存在一个节点集合R1, 其中至少含有 f+1 个正常副本节点,而且对于其中每个节点 i ,prepared(m, v, n, i) 为 true。.net
而后,考虑系统最终变动视图到 v' 的状况。在从视图 v 变动到 v' 的过程当中,此时变动没有完成,正常副本节点在接收到 new-view 消息以前,不会接受视图 v' 上的预准备消息。
可是,对于视图 v 变动到 v'的任意一个有效的 new-view 消息来讲,其中包含 2f+1 个有效的view-change 消息。这些消息来自不一样的副本节点,记它们组成的集合为R2。R1和R2至少有一个相同的元素,也就是相同的节点。否则的话,它们总的节点个数将为(f+1) + (2f+1) = 3f+2,这与咱们假定的系统总节点个数 3f+1 不符。blog
所以,假设这个共同的正常副本节点为 k 。对于请求 m 来讲,只有可能存在下面两种状况:new-view 消息中,存在 view-change 消息,其中包含的最新稳定检查点对应的消息序号大于 m 的序号 n 。new-view 消息中全部的 view-change 消息中包含的最新稳定检查点对应的消息序号不大于m的序号n。get
对于第一种状况,根据视图变动协议,新视图 v' 中,全部正常副本节点不会接受序号为n或小于n的消息。
对于第二种状况,m 将会被传播到新视图 v'中,由于根据视图变动协议,min-s≤n。视图变动完成后,在 v' 中,算法将针对编号为 n 的请求 m 从新运行三阶段协议。这就使得全部正常副本节点会达成一致,而不会出现下面这种状况:
另外一个不一样于 m 的请求 m' , 其在视图 v 中分配的序号为 n ,且在新视图中 v' 完成本地确认。
综合上面 1 和 2 的证实,就证实了算法在同一视图和视图变动过程当中,都会保证本地确认的请求的序号在全部正常副本节点中会达成一致,从而保证了算法的安全性(safety)。
对于PBFT算法来讲,为了保证系统的活性(liveness),当节点没法执行客户端请求时,须要变动到新的视图。同时,视图变动也须要进行合理控制,只在须要时才进行,不然频繁的视图变动会影响到系统的活性。这就须要保证如下两点:
系统中至少 2f+1 个正常副本节点处于同一视图中时,这种状态尽量长时间地保持;
每次视图变动时,上述时间间隔须要快速增加,好比以指数形式增加。
PBFT算法经过以下三种方法来保证上述两点:
1. 为了防止视图变动太快开始,当一个节点发送 view-change 消息后,在等待接收 2f+1 个 view-change消息时,会同时启动定时器,其超时时间设置为 T。若是视图变动没有在 T 时间内完成,或者在新视图中请求没有在该时间间隔内完成,则会触发新的视图变动。此时,算法会调整超时时间,将其设置为原来的两倍,即 2T 。
2. 除了上述的定时器超时触发节点发送 view-change 消息外,当其接收到来自 f+1 个不一样节点的有效view-change 消息,而且变动的目标视图大于节点当前视图时,也会触发节点发送 view-change 消息。这能够防止节点过晚启动视图变动。
3. 基于上述第二点的规则,失效节点没法经过故意发送 view-change 消息来触发频繁的视图变动从而干扰系统的运行。由于失效节点最多只能发送 f 条消息,达不到 f+1 的触发条件。失效节点是主节点时,可能会触发视图变动,可是连续的视图变动最多只会是 f 个,以后主节点就是正常节点。所以,基于以上的规则,系统能够保证活性。
本部分介绍PBFT算法的优化。这些优化方式应用于算法的正常操做中,能够提高算法的性能,同时能够保持系统的安全性和活性。
能够采用三种方法减小系统通讯量:
1. 向客户端发送回复的消息摘要,而不是回复的原始内容客户端指定一个特定的副本节点,从该节点接收完整的回复内容,而只从其余全部节点处接收回复的摘要。经过判读摘要与回复的一致性以及对回复计数,能够确保接收到正确的回复。若是客户端接收不到正确结果,就会按正常流程从新请求系统,并接收不一样节点的完整回复。
2. 请求在副本节点prepared后,节点即试探性地执行请求,并发送结果。客户端只要收到 2f+1 个匹配的结果,就能够确保该结果的正确性。也就是说,该请求最终会确认(至少f+1 个正常副本节点的本地确认)。若是客户端没法获得正确结果,就从新发送请求,系统执行正常流程。一个被试探性执行的请求,有可能在视图变动过程当中被中断,并被替换为一个空请求。此时,已经执行过请求的节点能够经过 new-view 消息中的最新的稳定检查点或本地的检查点来更新状态(取决于哪一个序号更大)。
3. 针对只读操做,客户端将请求广播到每个副本节点。各节点判断请求确实为只读且知足条件后,直接执行请求,并发送回复到客户端。客户端收到 2f+1 个相同的回复,即为正确结果;不然客户端以前设置的重发请求定时器将触发超时,使得客
户端重发请求,系统执行正常流程。
这种优化的前提条件是,副本节点在执行请求以前,需确保以前全部请求都已确认,而且被执行。
使用公钥签名的方式验证消息存在以下不足:
相似于RSA这样的签名算法,签名速度比较慢;
其余公钥密码系统,如椭圆曲线公钥密码系统,虽然签名更快,可是验签更慢。
PBFT算法实际上在正常流程中采用 MAC(Message Authentication Code,消息验证码) 认证消息,由于它具备以下优势,使得算法相对于以前的算法性能提高了一个数量级以上:
MAC 计算速度快;
经过适当优化,能够减小其长度;
经过对authenticator(vector of MAC)的使用,可使验证时间为常量,而生成时间只随着节点数量线性增加。
具体来讲,PBFT算法中使用 MAC 和公钥签名的具体场景是:
全部正常操做流程中使用 MAC 验证消息;
视图变动中的消息:view-change, new-view,以及出现错误时,使用公钥签名。这些场景的出现频率相对较低,从而对算法的性能影响较小。
关联阅读: