Fabric中PBFT源码解读 (1)

1. 写在前面

笔者一直以来想学习一下PBFT的完整工程实践。但在网上搜了很多源码和博客,都没能找到一份比较独立且完整的PBFT实现。无奈之下,只能从Hyperledger Fabric的代码中学习其PBFT共识部分的代码。
因此,接下来的系列博客中,笔者将介绍在Fabric中是如何实现PBFT共识算法的。

为方便读者查阅,本系列博客的链接整理如下:

1.1 源码版本及获取

Fabric0.6版本中采用了PBFT,因此在从github中下载了源代码后,需要首先切换到v0.6.0-preview分支。PBFT共识相关的代码主要包含在fabric/consensusfabric/consensus/pbft路径下。前者包含了各种共识算法都需要的一些工具类,后者重点实现了PBFT共识。

1.2 对TestNetwork函数的测试

查看fabric/consensus/pbft路径下的代码,可以看到有很多测试文件。每个测试文件中又包含了若干个测试函数。这里我们选取了pbft-core_test.go文件中的TestNetwork测试函数。通过解读该函数,基本上可以了解PBFT代码的运行流程。

为降低流程分析的复杂度,首先将pbft-core_test.go中L258行的validator值改为4。如下所示:

// [pbft-core_test.go]TestNetwork
func TestNetwork(t *testing.T) {
	validatorCount := 4
	...
}

2. 构建测试网络

以下从TestNetwork函数开始源码的解读。TestNetwork函数的主体代码如下所示:

// [pbft-core_test.go]TestNetwork
func TestNetwork(t *testing.T) {
    validatorCount := 4                             // L258
    net := makePBFTNetwork(validatorCount, nil)       // L259
    ...
}

TestNetwork函数首先调用makePBFTNetwork函数生成了一个包含4个节点的PBFT网络,后者的代码主体如下。

// [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]makePBFTNetwork
func makePBFTNetwork(N int, config *viper.Viper) *pbftNetwork { // L152
    ...
    endpointFunc := func(id uint64, net *testnet) endpoint { // L159
        tep := makeTestEndpoint(id, net)
        pe := &pbftEndpoint{
			testEndpoint: tep,
			manager:      events.NewManagerImpl(),			// L162
		}
        ...
        pe.pbft = newPbftCore(id, config, pe.sc, events.NewTimerFactoryImpl(pe.manager))                     // L170
        ...
    }
    
    pn := &pbftNetwork{testnet: makeTestnet(N, endpointFunc)}   // L179
}

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的具体定义如下所示。

// [pbft-core_mock_test.go] TestNetwork -> [pbft-core_mock_test.go]makePBFTNetwork -> testnet
type testnet struct {
    debug     bool
	N         int
	closed    chan struct{}
	endpoints []endpoint
	msgs      chan taggedMsg
	filterFn  func(int, int, []byte) []byte
}

3. 生成测试数据

回到TestNetwork函数,在生成测试网络后,该函数进一步生成了测试数据,并将其传入到节点0(即Primary节点)中。TestNetwork函数的相关代码如下所示:

// [pbft-core_test.go]TestNetwork
func TestNetwork(t *testing.T) {
    ...
    reqBatch := createPbftReqBatch(1, uint64(generateBroadcaster(validatorCount)))          // L261
    net.pbftEndpoints[0].manager.Queue() <- reqBatch  // L262
    ...
}

TestNetwork函数的L261行调用createPbftReqBatch函数生成类为RequestBatch的测试数据。该测试数据在L262行被发送到第0个节点中。由前面的介绍可知,net的第0个pbftEndpoint即代表第0个节点。
pbftEndpoint类的定义如下。pbftEndpoint类中定义了一个Manager类别的变量,Manager实际上是一个接口。由makePBFTNetwork函数的L162行可知,该变量实际上实例化了一个managerImpl类。后者是Manager接口的实现类。

// [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]pbftEndpoint
type pbftEndpoint struct {                      // L29
	*testEndpoint
	pbft    *pbftCore
	sc      *simpleConsumer
	manager events.Manager
}

managerImpl类中定义了类别为chan Eventevents变量,并定义Queue函数返回该变量,相关代码如下所示:

// [pbft-core_test.go]TestNetwork -> [pbft-core_mock_test.go]pbftEndpoint -> [events.go]managerImpl
type managerImpl struct {                   // L80
	threaded  
	receiver Receiver
	events   chan Event
}

func (em *managerImpl) Queue() chan<- Event {   // L105
	return em.events
}
  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值