文章目錄
- 1. 寫在前面
- 1.1 原始碼版本及獲取
- 1.2 對TestNetwork函式的測驗
- 2. 構建測驗網路
- 3. 生成測驗資料
1. 寫在前面
筆者一直以來想學習一下PBFT的完整工程實踐,但在網上搜了很多原始碼和博客,都沒能找到一份比較獨立且完整的PBFT實作,無奈之下,只能從Hyperledger Fabric的代碼中學習其PBFT共識部分的代碼,
因此,接下來的系列博客中,筆者將介紹在Fabric中是如何實作PBFT共識演算法的,
為方便讀者查閱,本系列博客的鏈接整理如下:
- Fabric中PBFT原始碼解讀 (1)
- Fabric中PBFT原始碼解讀 (2)
- Fabric中PBFT原始碼解讀 (3)
- Fabric中PBFT原始碼解讀 (4)
- Fabric中PBFT原始碼解讀 (5)
1.1 原始碼版本及獲取
Fabric在0.6版本中采用了PBFT,因此在從github中下載了源代碼后,需要首先切換到v0.6.0-preview分支,PBFT共識相關的代碼主要包含在fabric/consensus和fabric/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 Event的events變數,并定義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
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/246600.html
標籤:區塊鏈
上一篇:Go語言基礎(一)
