1. 程式人生 > >Hyperledger Fabric 動態增加組織到網路中

Hyperledger Fabric 動態增加組織到網路中

本文基於Hyperledger Fabric 1.4版本。
官方文件地址:傳送門

動態新增一個組織到Fabric網路中也是一個比較重要的功能。官方文件寫的已經很詳細了,有能力的儘量還是看官方文件,本文只是根據官方文件進行整理同時兼翻譯。

1.前提條件


這個不再解釋了,前提條件自然是搭建Fabric的環境了並跑通官方的例子,具體的看這裡.

2.啟動網路


還是以官方的byfn為例好了,不多說,對Fabric有一定了解的都能明白,不明白的看上面文件:

./byfn.sh up
#或者是
./byfn.sh up -s couchdb
#區別不大,只不過換了一個數據庫而已,對本文內容沒多少關係

動態新增組織官方指令碼自動化操作就簡單執行以下命令:

./eyfn.sh up

本文重點不在這裡,因為自動化操作省略了所有的內容,固然簡單,但是仍然不懂其中過程。所以本文的重點還是下一部分,手動地一步一步完成動態增加組織。

3手動新增組織到網路中

byfn網路中的節點為:

  • Order -> orderer.example.com
  • Org1 -> peer0.org1.example.com
  • Org1 -> peer1.org1.example.com
  • Org2 -> peer0.org2.example.com
  • Org2 -> peer1.org2.example.com

而我們要新增的為:

  • Org3 -> peer0.org3.example.com
  • Org3 -> peer1.org3.example.com

在這裡,我們假設工作目錄在$GOPATH/.../fabric-samples/first-network資料夾。上面的五個節點也通過

./byfn.sh up

命令成功啟動。
Fabric網路的啟動過程總的來說沒有幾步(錨節點那部分先省略掉,對本文沒有影響):

  1. 為每一個節點生成證書檔案
  2. 生成系統通道的創世區塊(也是配置檔案)
  3. 生成通道配置檔案
  4. 啟動節點
  5. 根據通道配置檔案建立通道生成應用通道創世區塊
  6. 加入通道
  7. ...

根據這個流程來考慮動態增加節點:

  • 首先為每一個節點生成證書檔案是肯定要做的。
  • 第二步生成創世區塊(系統通道配置檔案)是不需要的
  • 第三步生成應用通道配置檔案需要變為更新應用通道配置檔案
  • 第四步啟動節點步驟不變
  • 第五步建立通道也不需要了,直接到第六步加入通道
  • ...(網路啟動之後的步驟最後再說)

既然分析完了,我們只要按照步驟完成就可以了。

3.1生成證書檔案

怎麼生成證書檔案呢,這個直接使用官方的檔案就可以了,當然有定製化需求的請自行修改。檔案在工作目錄下的org3-artifacts資料夾下的org3-crypto.yaml檔案。
這一步比較簡單,直接執行命令列工具就可以了,當然對Fabric CA比較熟悉的也可以採用手動生成證書的方法,本文為了簡便,直接使用工具生成:

cd org3-artifacts
cryptogen generate --config=./org3-crypto.yaml

完成之後在org3-artifacts目錄下生成一個crypto-config資料夾。裡面就是需要新增的新組織的證書檔案。
如果網路開啟TLS的話,在多機環境下還需要將OrdererTLS根證書拷貝一份過來用於之後的與Orderer節點進行通訊,而單機環境下也可以直接將OrdererTLS根證書掛載到之後需要啟動的Org3的容器內部。而本文采用和官方文件相同的方法,直接拷貝檔案:

cd ../ && cp -r crypto-config/ordererOrganizations org3-artifacts/crypto-config/

3.2更新通道配置檔案

接下來第三步:更新通道配置檔案,可以分為以下步驟:

  1. 獲取網路中當前通道之前最新的配置區塊
  2. 把需要更新的內容新增進去
  3. 把最新的配置檔案更新到網路中

3.2.1獲取最新的配置區塊

看一下第一步獲取網路中之前最新的配置區塊,如何獲取呢,自然是通過網路中現有的節點進行獲取,並且使從peer節點向Orderer節點發起通訊獲取配置區塊。
首先進入cli容器:

docker exec -it cli bash

配置需要的環境變數:

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 
export CHANNEL_NAME=mychannel

如果操作中途退出了cli容器,那麼再次進入時都需要重新配置環境變數.
接下來獲取之前最新的配置區塊:

peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
  • peer channel fetch: 從指定的通道獲取具體的區塊並寫入檔案。
  • config :指定獲取的區塊是配置區塊.(Fabric網路中區塊型別可分為普通交易區塊和配置區塊)
  • config_block.pb:將配置區塊寫入到這個檔案中
  • -o:指定向具體的排序節點發起通訊
  • -c:指定通道名稱
  • --tls:如果開啟了TLS則需要指定這個引數
  • --cafile:TLS根證書檔案

執行完畢後命令行會列印這些資訊:

 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
 UTC [cli.common] readBlock -> INFO 002 Received block: 4
 UTC [cli.common] readBlock -> INFO 003 Received block: 2
 UTC [channelCmd] fetch -> INFO 004 Retrieving last config block: 2

可以看到mychannel通道中共生成了5個區塊(創世區塊序號為0).但是最新的配置區塊序號為2:

  1. 配置區塊0:創世區塊
  2. 配置區塊1:組織一的錨節點更新
  3. 配置區塊2:組織二的錨節點更新
  4. 普通區塊3:例項化鏈碼
  5. 普通區塊4:呼叫鏈碼

而本文獲取到了最新的配置區塊也是是區塊2,並將該區塊寫入到了config_block.pb檔案中。

3.2.2將配置資訊新增到配置檔案中

我們已經獲取到了最新的配置檔案,接下來如何更新它呢,因為區塊內容是編碼過的,而且還包括區塊頭,元資料以及簽名等資訊,對更新配置是用不到的。所以需要先將區塊進行解碼成我們可讀的檔案,而且為了簡單化,可以將不相關的區塊頭等資訊去掉(當然不去掉也沒有問題)。
這裡用到了兩個工具:Fabric官方的命令列工具configtxlator,以及jq工具:
configtxlator工具可以幫助我們進行編解碼轉換
jq工具和Linux中的grep,awk命令較為相似,都是對資料進行處理的(當然不使用這個工具也沒什麼問題,只不過需要手動修改資料而已)。
接下來就是將區塊資訊解碼去除不相關的資訊後並以json格式儲存到檔案中:

configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
  • proto_decode :解碼操作
  • --input:需要解碼的檔案作為輸入
  • --type:輸入檔案的型別

解碼後通過jq工具提取需要的資料並儲存到了config.json檔案中。

接下來呢,就是將組織三的配置資訊寫到這裡面,組織三的配置資訊呢?我們還沒有生成它,之前只是為組織三生成了證書檔案。所以我們還需要生成組織三的配置資訊。
同樣的,用於生成配置資訊的原始檔官方也給了,在工作目錄下的org3-artifacts資料夾下的configtx.yaml檔案。
因為上一步我們將通道內的最新的配置檔案轉換為了json格式,所以這裡我們也需要將這個檔案內的配置資訊轉換為json格式:

#開啟新的終端進入以下目錄中
cd $GOPATH/.../fabric-samples/first-network/org3-argifacts/
#指定配置檔案所在路徑 或者是通過-configPath路徑指定
export FABRIC_CFG_PATH=$PWD 
#直接通過工具將配置資訊寫到org3.json檔案中。
configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json

現在讓我們回到之前的終端繼續操作,將剛剛生成的org3.json檔案新增到config.json檔案中,通過jq工具:

jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ./channel-artifacts/org3.json > modified_config.json

這一行命令就是將org3.json這個檔案新增到config.json檔案的channel_group->groups->Application->groups->Org3MSP下,並儲存到modified_config.json檔案。
接下來就是獲取原始配置檔案和新的配置檔案的不同點了,官方文件的意思是隻保留組織3的定義以及一個指向組織1與組織2的高階指標,因為沒有必要連同之前的配置檔案一起更新,所以只需要一個指標指向原配置(個人理解)。
具體的操作方法是將上面兩個json檔案編碼回去,然後使用configtxlator工具進行比較更新。
操作命令:

  • config.json檔案,編碼後輸出到config.pb檔案。
configtxlator proto_encode --input config.json --type common.Config --output config.pb
  • modified_config.json檔案,編碼後輸出到modified_config.pb檔案。
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
  • 計算兩個檔案的差異並輸出到org3_update.pb檔案:
# --original 指定原配置檔案   --updated 指定新配置檔案
configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_config.pb --output org3_update.pb

接下來還需要做一件事,就是封裝一個更新配置的檔案,將org3_update.pb寫進去,畢竟向Fabric新增組織需要更新Fabric的配置,自然是需要將配置檔案按照Fabric規定的檔案型別封裝好才能更新網路。
然後封裝配置資訊又會涉及到一些額外的資訊,說簡單點就是Fabric規定的檔案型別的識別符號之類的,所以需要我們再次解碼,然後新增這些額外的資訊進去:

configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.json

新增額外的資料:

echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json

到最後一步配置更新訊息就完成了,那就是將檔案以特定的檔案型別封裝起來:

configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb

3.2.3更新應用通道配置檔案

配置更新訊息已經處理好了,接下來就是更新到網路中了。在此時,新新增的組織資訊還沒有更新進去,所以還是需要使用之前的組織將配置進行更新,首先就是需要帶有Admin身份的多數節點進行簽名(策略這塊以後再講),所以需要每個組織中各一個節點進行簽名,首先是peer0.org1,由於之前開啟的cli容器預設身份就是peer0.org1,所以不需要配置環境變數直接進行簽名:

peer channel signconfigtx -f org3_update_in_envelope.pb

接下來是組織二的節點:

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051

實際上我們只需要進行配置檔案更新就行了,因為在配置更新操作中如果沒有簽名預設會先進行簽名的:

peer channel update -f org3_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA

如果命令列日誌打印出一下內容說明更新通道配置成功:

UTC [channelCmd] update -> INFO 002 Successfully submitted channel update

在此時,區塊5將會生成並寫到每一個節點的賬本,比如我們檢視peer0.org1的日誌資訊,可以看到以下內容:

#開啟一個新的命令列
docker logs -f peer0.org1.example.com
##日誌內容
UTC [gossip.privdata] StoreBlock -> INFO 07c [mychannel] Received block [5] from buffer
...
UTC [gossip.gossip] JoinChan -> INFO 07d Joining gossip network of channel mychannel with 3 organizations
...
UTC [committer.txvalidator] Validate -> INFO 082 [mychannel] Validated block [5] in 238ms
...
UTC [kvledger] CommitWithPvtData -> INFO 08b [mychannel] Committed block [5] with 1 transaction(s) in 238ms
...

3.4啟動節點並加入通道

到這裡,組織三的資訊已經更新到網路中了,所以我們可以啟動組織三的節點了:

docker-compose -f docker-compose-org3.yaml up -d

啟動成功後進入組織三的cli容器:

docker exec -it Org3cli bash

第一步還是配置環境變數,還記得一開始我們將排序節點的根證書複製的那一步吧,現在就派上用場了:

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 
export CHANNEL_NAME=mychannel
#檢查一下是否配置成功
echo $ORDERER_CA && echo $CHANNEL_NAME

沒問題的話就可以進行加入通道了,如果加入通道呢,肯定是需要創世區塊了,所以需要從排序節點處獲取它:

#這裡不能用peer channel fetch config ... 否則獲取到的是剛生產的區塊5,只有使用創世區塊才能加入通道
peer channel fetch 0 mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
###命令列打印出一下內容
UTC [cli.common] readBlock -> INFO 002 Received block: 0

最後加入通道:

export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer1.org3.example.com/tls/ca.crt && export CORE_PEER_ADDRESS=peer1.org3.example.com:12051
peer channel join -b mychannel.block

3.5測試

一切都沒有問題,就差測試鏈碼能不能用了。
首先這裡注意一點,在新的組織新增進通道之前,鏈碼的背書策略並沒有涉及到新的組織,所以之前的鏈碼對於新的組織是不能使用的,包括查詢,呼叫以及更新操作。但是安裝鏈碼是可以用的(前提是版本和鏈碼名稱不能全部相同),所以我們需要通過之前的組織更新鏈碼,並制定背書策略將新的組織新增進來。
切換到組織一的節點:

export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051

安裝新版本的鏈碼:

peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/
## 更新背書策略將新的組織新增進來
peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a","90","b","210"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
#測試一下更新是否成功
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
## Query Result: 90

切換回組織三的節點容器:

docker exec -it Org3cli bash
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem 
export CHANNEL_NAME=mychannel

安裝鏈碼:

peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/

安裝完測試一下:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
# Query Result: 90

查詢沒問題,呼叫一下試試:

peer chaincode invoke -o orderer.example.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'

再次查詢:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
# Query Result: 80

沒問題了,到這裡我們成功將組織三動態新增到網路中了。

3.5更新組織三的錨節點

至於這一部分,以後再補充好了。。。。。未完待