區塊鏈學習——HyperLedger-Fabric v1.0 啟動過程分析
本章我們從
fabric v1.0
的e2e_cli
示例開始分析整個啟動過程以及在過程中的一些配置檔案
首先呢,還是確保你的基本環境已經搭建完成,v1.0原始碼和映象也都下載完畢
fabric啟動過程中的相關指令碼檔案解析
network_setup.sh指令碼檔案
在原始碼目錄下的network_setup.sh
檔案是官方提供的快速部署測試的一個自動化指令碼,接下來我們看一下在啟動這個檔案時都做了什麼:
在上圖中我們只是截取了啟動函式,在這個函式中可以清楚的看出在啟動中呼叫了generateArtifacts.sh
和docker-compose-cli.yaml
兩個檔案,這兩個檔案的作用分別是:
generateArtifacts.sh:生成所需的證書(crypto-config資料夾)和通道相關的配置檔案(channel-artifacts資料夾)
docker-compose-cli.yaml:描述的是這個示例網路的拓撲結構
generateArtifacts.sh指令碼檔案
我們繼續分析在network_setup.sh
中呼叫generateArtifacts.sh
檔案具體又做了什麼呢
在generateArtifacts.sh
中一共有3個函式:replacePrivateKey()
、generateCerts()
和generateChannelArtifacts()
generateCerts():
在上圖中可以看到這個函式使用工具cryptogen和
crypto-config.yaml
檔案來生成所需的證書檔案和公私鑰。我們可以看一下
crypto-config.yaml
檔案:Name和Domain是指該org的名字和域名,Template.Count是指該org中的節點數量,Users.Count是指該org中包含的user數量.
OrdererOrgs: - Name: Orderer Domain: example.com Specs: - Hostname: orderer # --------------------------------------------------------------------------- PeerOrgs: - Name: Org1 Domain: org1.example.com Template: Count: 2 Users: Count: 1 # --------------------------------------------------------------------------- - Name: Org2 Domain: org2.example.com Template: Count: 2 Users: Count: 1
generateChannelArtifacts():
在上圖中可以看到這個函式使用工具configtxgen和configtx.yaml檔案來生成創世區塊以及通道相關的配置檔案。而configtx.yaml檔案裡主要是一些org的配置項資訊,如ID、Host、Port等,除此之外還指明瞭orderer的共識方式為solo等一些的基礎的配置項資訊。
docker-compose-cli.yaml指令碼檔案
docker-compose-cli.yaml
檔案描述了這個示例網路的拓撲結構,如下,包含:
- orderer:1個
- org1:peer0(錨節點),peer1
- org2:peer0(錨節點),peer1
- cli:對上面的容器節點進行管理
- 為什麼cli能夠對上面的容器進行管理呢?
因為cli是經過網路中其他節點進行授權認可的,而認可的憑證就是公私鑰
#command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'
檔案中上面這一行是筆者故意註釋掉的,使docker-compose-cli.yaml
檔案啟動時不會自動去執行script.sh
指令碼,而這個指令碼就是自動建立、加入通道以及鏈碼相關操作的自動化指令碼,而在下面,我們將自己動手來一步步完成這些步驟,從而加深對fabric啟動過程的理解。
version: '2'
services:
orderer.example.com:
extends:
file: base/docker-compose-base.yaml
service: orderer.example.com
container_name: orderer.example.com
peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org1.example.com
peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org2.example.com
peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org2.example.com
cli:
container_name: cli
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- 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
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
#command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'
volumes:
- /var/run/:/host/var/run/
- ../chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- orderer.example.com
- peer0.org1.example.com
- peer1.org1.example.com
- peer0.org2.example.com
- peer1.org2.example.com
啟動e2e示例
接下來我們將實際動手啟動一下官方提供的示例:
生成證書以及金鑰
首先我們進入下載的fabric原始碼目錄/root/go/src/github.com/hyperledger/fabric
,執行make cryptogen
命令,生成cryptogen
可執行程式,如有報錯,則在文章最後一部分有筆者自己遇到的錯誤,可自行檢視;
接下來進入cd examples/e2e_cli/
目錄執行../../build/bin/cryptogen generate --config=./crypto-config.yaml
,則會在本目錄下生成crypto-config
資料夾,存放生成公私鑰和證書。
生成創世區塊以及通道相關的配置檔案
返回到fabric
目錄,執行make configtxgen
命令,生成configtxgen
可執行程式
接下來還是進入cd examples/e2e_cli/
目錄
生成創世區塊:
../../build/bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
生成通道相關的配置檔案:
../../build/bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
生成org1和org2錨節點所需的配置檔案:
../../build/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
../../build/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
執行完上述命令後,再執行tree channel-artifacts/
(需安裝tree命令yum install tree
),可以看見如下圖生成的檔案的目錄結構:
啟動
啟動所需的一切都準備完畢,接下來我們啟動fabric網路
docker-compose -f docker-compose-cli.yaml up
另起一個終端,執行docker ps
,可以看到如下圖,啟動了1個orderer,4個peer(分屬2個org),1個cli
建立通道
進入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
建立通道:
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA
執行完該命令後系統會打印出下圖,並且會在cli中生成1個mychannel.block
檔案,在後續中,其他的節點想要加入我們建立的這個通道,就必須使用這個檔案。
將節點加入通道
- 在
docker-compose-cli.yaml
檔案中其實指明瞭啟動時就預設連線的是org1.peer0
節點,所以直接將其加入通道即可
peer channel join -b $CHANNEL_NAME.block
執行結果如下:
- 在這裡我們只是將
org1.peer0
節點加入了mychannel
這個通道,同樣我們再將org1.peer1
節點也加入通道,不過這裡就需要修改環境變數,使其指向我們需要加入通道的節點後,再將節點加入通道。
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/Admin\@org1.example.com/msp
export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
peer channel join -b $CHANNEL_NAME.block
執行結果如下:
- 將
org2.peer0
節點加入通道:
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/Admin\@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
peer channel join -b $CHANNEL_NAME.block
執行結果如下:
- 將
org2.peer1
節點加入通道:
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/Admin\@org2.example.com/msp
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
peer channel join -b $CHANNEL_NAME.block
執行結果如下:
更新錨節點
錨節點的作用是為了方便組織(org)之間的通訊,1個組織(org)可以擁有1個或多個錨節點負責與其他組織進行通訊,然後將結果同步到其他節點。
更新org1
的錨節點org1.peer0
,首先連線到org1.peer0
再執行更新
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/Admin\@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile $ORDERER_CA
更新org2
的錨節點org2.peer0
,首先連線到org2.peer0
再執行更新
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/Admin\@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile $ORDERER_CA
部署測試鏈碼
在上上一步中我們已經將org1和org2的一共4個peer都加入名為mychannel
的這個通道,接下來我們開始安裝鏈碼,此時我們在上一步命令執行結束後仍連線的是org2.pee1
節點,因為鏈碼安裝時並沒有產生交易,因此是不會影響通道內的其他節點,可以說鏈碼安裝其實是一個本地化操作,所以,如果我們想在不同的節點中呼叫鏈碼的話,就需要安裝4次鏈碼(因為我們目前只有4個節點)
- 安裝鏈碼:
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
執行結果如下:
- 例項化鏈碼(-o:指定orderer的地址)
鏈碼例項化其實可以看作是一筆特殊的交易,鏈碼在某個節點例項化以後,其資訊就會被廣播到通道內的所有節點,如果另外1個節點又再一次對這個鏈碼例項化的話就會衝突。
peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init", "a", "100", "b", "200"]}' -P "OR ('Org1MSP.member', 'Org2MSP.member')"
- 呼叫鏈碼
上面一步我們的鏈碼例項化已經完成,初始時a賬戶100元,b賬戶200元,我們先查詢一下a的餘額,驗證一下
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query", "a"]}'
執行結果如下:
接下來我們呼叫鏈碼使a給b轉賬50元
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke", "a","b","50"]}'
執行結果如下:
現在我們需要在另外1個節點org1.peer0
上查詢org2.peer1
節點上發生的交易是否成功
需要先連線到org1.peer0
上,需要再一次安裝鏈碼,但不需要例項化
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/Admin\@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
再一次安裝完鏈碼後我們呼叫鏈碼查詢a的餘額
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query", "a"]}'
執行結果如下:
最後我們檢視正在執行中的容器,可以看到如下:
錯誤
- 執行
make cryptogen
命令如有報錯
解決方案:yum install libtool-ltdl-devel
最後呢,說明一下,作者也是剛入坑的小白,這篇文章也就是分享一下個人的理解,方便以後檢視。如果對你有幫助的話,非常榮幸,如果有不對的地方,歡迎留言指正!
參考文章
部落格園深藍居