笔者一直以来想学习一下PBFT
的完整工程实践。但在网上搜了很多源码和博客,都没能找到一份比较独立且完整的PBFT
实现。无奈之下,只能从Hyperledger Fabric
的代码中学习其PBFT
共识部分的代码。 因此,接下来的系列博客中,笔者将介绍在Fabric
中是如何实现PBFT
共识算法的。
I. 写在前面
为方便读者查阅,本系列博客的链接整理如下:
A. 源码版本及获取
Fabric
在0.6
版本中采用了PBFT
,因此在从github中下载了源代码后,需要首先切换到v0.6.0-preview
分支。PBFT
共识相关的代码主要包含在fabric/consensus
和fabric/consensus/pbft
路径下。前者包含了各种共识算法都需要的一些工具类,后者重点实现了PBFT
共识。
B. 对TestNetwork函数的测试
查看fabric/consensus/pbft
路径下的代码,可以看到有很多测试文件。每个测试文件中又包含了若干个测试函数。这里我们选取了pbft-core_test.go
文件中的TestNetwork
测试函数。通过解读该函数,基本上可以了解PBFT
代码的运行流程。
为降低流程分析的复杂度,首先将pbft-core_test.go
中L258行的validator
值改为4
。如下所示:
1 | // [pbft-core_test.go]TestNetwork |
II. 构建测试网络
以下从TestNetwork
函数开始源码的解读。TestNetwork
函数的主体代码如下所示:
1 | // [pbft-core_test.go]TestNetwork |
TestNetwork
函数首先调用makePBFTNetwork
函数生成了一个包含4
个节点的PBFT
网络,后者的代码主体如下。 1 | // [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]makePBFTNetwork |
makePBFTNetwork
函数L159行首先定义了一个用于生成endpoint
的函数,其中每个endpoint
代表了一个节点。endpoint
其实是一个接口,为进行测试,源码中实现了一个testEndpoint
类。L160行利用makeTestEndpoint
函数生成了testEndpoint
类的实例。 为实现pbft
的测试,还在pbft-core_mock_test.go
文件的L29行定义了一个辅助类pbftEndpoint
。该辅助类将一个节点的多个功能部分进行了组合。 节点的核心功能由pbftCore
类实现,因此在L170行调用newPbftCore
函数生成了pbftCore
类的实例。 需要注意的是,L519行只是定义了生成endpoint
的函数,该函数在L179行传入到makeTestnet
函数中进行了调用。makeTestnet
函数生成了代表当前测试网络的testnet
类的一个实例。该实例包含了若干个endpoint
,定义了一个msgs
变量和一个filterFn
函数。testnet
的具体定义如下所示。 1 | // [pbft-core_mock_test.go] TestNetwork -> [pbft-core_mock_test.go]makePBFTNetwork -> testnet |
III. 生成测试数据
回到TestNetwork
函数,在生成测试网络后,该函数进一步生成了测试数据,并将其传入到节点0
(即Primary
节点)中。TestNetwork
函数的相关代码如下所示:
1 | // [pbft-core_test.go]TestNetwork |
TestNetwork
函数的L261行调用createPbftReqBatch
函数生成类为RequestBatch
的测试数据。该测试数据在L262行被发送到第0个节点中。由前面的介绍可知,net
的第0个pbftEndpoint
即代表第0个节点。 pbftEndpoint
类的定义如下。pbftEndpoint
类中定义了一个Manager
类别的变量,Manager
实际上是一个接口。由makePBFTNetwork
函数的L162行可知,该变量实际上实例化了一个managerImpl
类。后者是Manager
接口的实现类。 1 | // [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]pbftEndpoint |
managerImpl
类中定义了类别为chan Event
的events
变量,并定义Queue
函数返回该变量,相关代码如下所示: 1 | // [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]pbftEndpoint -> [events.go]managerImpl |