Fisco共识算法:PBFT

一、PBFT 与拜占庭问题

很多人喜欢玩狼人杀,我用狼人杀跟拜占庭将军问题做个类比。
在狼人杀开局的时候,你是好人,并且不知道自己的队友是谁,也不知道狼人是谁,但所有的好人都有一个共同的目的:干死狼人,好人获胜。所以游戏中需要使用技巧和策略,达成目的。
拜占庭将军问题是类似的,好的将军不知道其他将军是好的,还是坏的,但所有好的将军的目的是:行动一致,共同进退。所以,它们也需要策略达成一致。
BFT 是一类解决拜占庭将军问题的策略/算法:让非拜占庭节点达成一致的算法。在这类论文中,拜占庭节点指“坏”的将军,非拜占庭节点指“好”的将军。

PBFT 作为解决拜占庭问题的策略:非拜占庭节点不知道哪些是拜占庭节点,哪些是非拜占庭节点,PBFT 要让非拜占庭节点达成一致。PBFT算法天然适用于区块技术中,来解决共识问题。

PBFT拥有一个很大的一个特点:容错,可以在少数节点作恶场景中达成共识。它采用签名、签名验证、哈希等密码学算法确保消息传递过程中的防篡改性、防伪造性、不可抵赖性,但是PBFT只能有不少于 ( 2*f+1 ) 个非恶意节点正常工作,该系统就能达成一致性。

二、Fisco是怎么应用PBFT

1、关键概念

(1)节点ID && 节点索引
为了防止节点作恶,PBFT共识过程中每个共识节点均对其发送的消息进行签名,对收到的消息包进行验签名,因此每个节点均维护一份公私钥对,私钥用于对发送的消息进行签名,公钥作为节点ID,用于标识和验签。

  • 节点ID : 由于节点ID(公钥)就是一个很长的二进制字符串,在共识消息中包含该字段会耗费部分网络带宽,FISCO 引入了节点索引,在本地缓存一份每个节点的公钥以及对应每个节点的ID(例如:1、2、3…)的列表。发送网络消息包时,只需要带上节点索引,其他节点即可以从公共的共识节点列表中索引出节点的ID,进而对消息进行验签:
  • 节点索引 : 每个共识节点ID在这个列表中的位置。

(2)视图(view)
就是根据view和block_number来计算出在本轮共识的leader是谁。计算公式如下:

leader_idx = (view + block_number) % node_num

可以说view值就是对应leader的索引。根据上面这个公式可以看出,当没有leader不是作恶节点,block正常上链,block_number是自增的,view值是不变的,那么leader是轮流做。当leader是作恶节点,发现leader是作恶节点时,就会全局广播view+1,这是block_number是没有发生变化的,导致切换leader,从新共识。

2、共识流程

(1)系统架构流程
在这里插入图片描述
PBFT共识主要包括两个线程:
PBFTSealer: PBFT打包线程,负责从交易池取交易,并将打包好的区块封装成PBFT Prepare包,交给PBFTEngine处理;
PBFTEngine: PBFT共识线程,从PBFTSealer或者P2P网络接收PBFT共识消息包,区块验证器(Blockverifier)负责开始执行区块,完成共识流程,将达成共识的区块写入区块链,区块上链后,从交易池中删除已经上链的交易。

(2)PBFT核心流程
在这里插入图片描述
下面对三个阶段详细展开叙述。

3、三阶段

PBFT共识算法中,共识节点轮流出块,每一轮共识仅有一个leader打包区块,leader索引通过公式(block_number + current_view) % consensus_node_num计算得出。
节点计算当前leader索引与自己索引相同后,就开始打包区块。区块打包主要由PBFTSealer线程完成Prepare包,交给PBFTEngine处理进行广播。
(1)pre-prepare阶段:
每个节点都会接收到由leader节点完成Prepare包,并对prepare包做一下校验:

  • Prepare包合法性判断
  • 缓存合法的Prepare包
  • 空块判断:若Prepare请求包含的区块中交易数目是0,则触发空块视图切换,将当前视图加一,并向所有其他节点广播视图切换请求
  • 执行区块并缓存区块执行结果: 若Prepare请求包含的区块中交易数目大于0,则调用BlockVerifier区块执行器执行区块,并缓存执行后的区块
  • 产生并广播签名包:基于执行后的区块哈希,产生并广播签名包,表明本节点已经完成区块执行和验证。

也就是说,假如包内有交易,会对每一笔交易进行验证,验证后会得出一个结果,这区块能不上链,把这个结果跟自己的签名信息广播给其他节点。
(2)Prepare阶段:
本阶段,已经开始收集其他节点给出结果,并作出判断,最终是否进行上链。会做出一下校验:

  • 签名包合法性判断:主要判断签名包的哈希与pre-prepare阶段缓存的执行后的区块哈希相同
  • 缓存合法的签名包:节点会缓存合法的签名包
  • 判断pre-prepare阶段缓存的区块对应的签名包缓存是否达到2*f+1,若收集满签名包,广播Commit包,进行广播Commit包之前,要做检验给出检验结果。
  • 若收集满签名包,备份pre-prepare阶段缓存的Prepare包落盘,为了防止Commit阶段区块未提交到数据库之前超过2*f+1个节点宕机

==注意: 只要接受到f+1节点给出结果一样,就能最终判定这个区块到底是否能够上链。我们试想,作恶节点有f个,当f+1个节点给出结果时,必然有一个结果一定是正确的。 ==

(3)Commit阶段:jiu
共识节点收到Commit包后,进入Commit阶段,jiu此阶段工作流程包括:

  • Commit包合法性判断:主要判断Commit包的哈希与pre-prepare阶段缓存的执行后的区块哈希相同
  • 缓存合法的Commit包
  • 判断pre-prepare阶段缓存的区块对应的Commit包缓存是否达到2*f+1,若收集满Commit包,则将新区块落盘

此过程和Prepare阶段差不多,是为了保持全局数据一致性。

三、为什么三个阶段才能达到共识?

Prepare阶段 是一个局部一致,不是全局诚实节点的一致,即节点 i 看到了非拜占庭节点认可了 ,但整个系统包含 3f+1 个节点,异步的系统中,存在丢包、延时、拜占庭节点故意向部分节点发送 Prepare 等拜占庭行文,节点i 无法确定,其他节点也达到 Prepare节点状态做出结果。如果少于 f 个节点完成 Prepare,然后执行了上链,系统就出现了不一致。所以,前 2 个阶段的消息,并不能让非拜占庭节点完全达成一致。

四、PBFT消息转发优化

在这里插入图片描述

  • node0向{node1, node2, node3}发送PBFT消息,发现{node1, node3}不在连接列表内,则将PBFT消息msg的forwardNodes字段设置为{node1, node3},并将其转发给node2;
  • node2收到node1的PBFT消息后,判断forwardNodes字段不为空,则遍历邻居节点列表{node1, node3},并将邻居节点从forwardNodes中移除;
  • node2向node1和node3转发更新后的PBFT消息msg;
  • node1和node3收到msg后,判断forwardNodes字段为空,认为该消息已经到达了所有节点,不继续转发PBFT消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值