此文創作於2020-4-30
所使用的docker
、Fabric
、fabric-samples
均爲最新版本latest
本文主要翻譯於Building Your First Network
對於環境的搭建,不再過多敘述,CSDN的很多大佬都寫過相關博客,大家可以去借鑑一些。
放上一篇自己的博客(部分不多敘述的內容):fabric-samples的安裝
這裏直接描述first-network
:
-
進入該文件中:
cd first-network
-
爲了防止有網絡啓動中,關閉所有網絡:
./byfn.sh -m down
-
(!!!)在很多的教程中,首先執行這個命令:生成下面的文件。我對於這種生成方式並不贊同,包括一些教學視頻中的做法。先不執行這個命令,看我下面的分析,你可能就會明白,上面這個命令是多此一舉,在這個命令的基礎上執行其他命令,甚至可能會導致一些錯誤。./byfn.sh -m generate
-
首先讓我們運行該
cryptogen
工具。我們的二進制文件位於bin
目錄中,因此我們需要提供工具所在的相對路徑。
../bin/cryptogen generate --config=./crypto-config.yaml
生成的cert
和key
將輸出到目錄first-network/crypto-config
下。
您應該在終端中看到以下內容:
org1.example.com
org2.example.com
- 接下來,我們需要告訴該
configtxgen
工具在哪裏尋找configtx.yaml
需要提取的 文件。我們將在當前的工作目錄中告訴它:
export FABRIC_CFG_PATH=$PWD
- 然後,我們將調用該
configtxgen
工具來創建gensis.block
(你沒看錯,也就是3中圖片所展示的其中一個文件,這裏又重新生成一遍):
../bin/configtxgen -profile SampleMultiNodeEtcdRaft -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
orderer
的創始塊和我們將要後續創建的artifacts
將輸出到channel-artifacts
目錄中。上面命令中的channelID
是系統通道的名稱。
- 創建通道配置交易網絡(生成了
channel.tx
,3的其中一個文件)
接下來,我們需要創建通道交易artifacts
。確保替換$CHANNEL_NAME
或設置CHANNEL_NAME
爲可在以下說明中使用的環境變量:
export CHANNEL_NAME=mychannel && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
請注意,在創建網絡的創世區塊時,
TwoOrgsChannel
配置文件使用你指定的orderer
服務配置。
- 接下來,我們將在正在構建的通道上爲
Org1
定義錨點。同樣,請確保$CHANNEL_NAME
爲以下命令替換或設置環境變量。
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
現在,我們將在同一通道上爲Org2定義錨點:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
- 啓動網絡
如果您
byfn.sh
以前運行了上面的示例,請確保在繼續操作之前關閉了測試網絡(./byfn.sh -m down
)。
我們將利用腳本來啓動我們的網絡。docker-compose
文件引用了我們先前下載的鏡像,並使用我們先前生成的genesis.block
。
首先,讓我們開始我們的網絡:
docker-compose -f docker-compose-cli.yaml -f docker-compose-etcdraft2.yaml up -d
如果要查看網絡的實時日誌,請不要提供該-d
標誌。如果讓日誌流傳輸,則需要打開第二個終端以執行CLI
調用。
- 創建並加入頻道
回想一下,我們使用上面
configtxgen
“ 創建通道配置交易”部分中的
工具創建了通道配置交易。您可以使用configtx.yaml
傳遞給configtxgen
工具的相同或不同的配置文件,重複該過程以創建其他通道配置事務。然後,您可以重複本節中定義的過程以在網絡中建立其他通道。
我們將使用以下命令輸入CLI容器:
docker exec -it cli bash
如果成功,您應該看到以下內容:
bash-5.0#
- 接下來,作爲創建通道請求的一部分,我們將把在“ 創建通道配置事務”部分(稱爲
channel.tx
)中創建的生成的通道配置事務工件傳遞給orderer
。
export CHANNEL_NAME=mychannel
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
請注意
--cafile
,我們作爲此命令的一部分進行了傳遞。這是orderer
根證書的本地路徑,使我們可以驗證TLS
握手。
該命令返回一個創世塊-
<CHANNEL_NAME.block>
我們將使用它來加入頻道。它包含在中指定的配置信息。channel.tx
如果您未對默認通道名稱進行任何修改,則該命令將返回標題爲的原型mychannel.block
。
如果peer0.org2.example.com想要加入通道,完整命令應該是這樣的:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel join -b mychannel.block
上面直接執行是因爲默認配置了:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
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
- 這部分的內容可能解釋的有些模糊,大家還是參考這個文檔Create & Join Channel部分吧。
- 更新錨節點
更新通道定義以將定義Org1
的錨點爲peer0.org1.example.com
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
現在更新通道定義,將定義Org2
的錨點爲peer0.org2.example.com
。與Org2
錨節點定義的命令相同,我們需要在此調用之前加上適當的環境變量。peer channel join
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
- 安裝並定義一個鏈碼:
我們將利用一個簡單的現有鏈碼。要學習如何編寫自己的鏈碼,請參閱《開發人員鏈碼》教程。
應用程序通過chaincode
與區塊鏈賬本進行交互。因此,我們需要在每個將執行並認可我們交易的peer
上安裝一個鏈碼。但是,在我們與鏈碼進行交互之前,通道成員需要就建立鏈碼治理的鏈碼的定義達成共識。
我們需要打包鏈碼,然後才能將其安裝在我們的peer
上。對於您創建的每個軟件包,您需要提供一個鏈碼軟件包標籤作爲鏈碼的描述。使用以下命令打包,以Go,Node.js或Java chaincode爲示例。
# GO
# before packaging Go chaincode, vendoring Go dependencies is required like the following commands.
cd /opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/abstore/go
GO111MODULE=on go mod vendor
cd -
# this packages a Go chaincode.
# make note of the --lang flag to indicate "golang" chaincode
# for Go chaincode --path takes the relative path from $GOPATH/src
# The --label flag is used to create the package label
peer lifecycle chaincode package mycc.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/abstore/go/ --lang golang --label mycc_1
# Node.js
# this packages a Node.js chaincode
# make note of the --lang flag to indicate "node" chaincode
# for node chaincode --path takes the absolute path to the Node.js chaincode
# The --label flag is used to create the package label
peer lifecycle chaincode package mycc.tar.gz --path /opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/abstore/javascript/ --lang node --label mycc_1
# Java chaincode
# this packages a java chaincode
# make note of the --lang flag to indicate "java" chaincode
# for java chaincode --path takes the absolute path to the Java chaincode
# The --label flag is used to create the package label
peer lifecycle chaincode package mycc.tar.gz --path /opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/abstore/java/ --lang java --label mycc_1
上面的每個命令都會創建一個名爲的鏈碼包mycc.tar.gz
,我們可以使用它在peer
節點上安裝鏈碼。發出以下命令以將軟件包安裝在Org1
的peer0
上。
# this command installs a chaincode package on your peer
peer lifecycle chaincode install mycc.tar.gz
您還可以通過查詢對等方以獲取有關已安裝軟件包的信息來找到鏈碼軟件包標識符.
# this returns the details of the chaincode packages installed on your peers
peer lifecycle chaincode queryinstalled
上面的命令將返回與安裝命令相同的軟件包標識符。您應該看到類似於以下內容的輸出:
Installed chaincodes on peer:
Package ID: mycc_1:3397596e15672b85021e71928435b5b3cb18181ead9b70d2fc19d32a6b240246, Label: mycc_1
我們將來的命令將需要軟件包ID,所以讓我們繼續將其保存爲環境變量。將對等生命週期鏈碼queryinstalled
命令返回的軟件包ID粘貼 到以下命令中。軟件包ID可能對於所有用戶而言都不相同,因此您需要使用從控制檯返回的軟件包ID來完成此步驟。
# Save the package ID as an environment variable.
CC_PACKAGE_ID=mycc_1:3a8c52d70c36313cfebbaf09d8616e7a6318ababa01c7cbe40603c373bcfe173
mycc
的背書政策設置爲要求來自Org1
和Org2
的peer
的背書。因此,我們還需要在Org2
中的peer
上安裝chaincode
。
修改以下四個環境變量以將安裝命令作爲Org2
發出:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:9051
CORE_PEER_LOCALMSPID="Org2MSP"
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
現在,將chaincode
軟件包安裝到Org2
的peer0
上。以下命令將安裝鏈碼,並返回與我們作爲Org1
發出的安裝命令相同的標識符。
# this installs a chaincode package on your peer
peer lifecycle chaincode install mycc.tar.gz
因爲我們將環境變量設置爲可以作爲Org2
進行操作,所以可以使用mycc定義Org2
鏈碼。允許分配給每個組織內的peer
,因此該命令不需要針對組織內的每個peer
。
# this approves a chaincode definition for your org
# make note of the --package-id flag that provides the package ID
# use the --init-required flag to request the ``Init`` function be invoked to initialize the chaincode
peer lifecycle chaincode approveformyorg --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
所有組織都必須先同意定義,然後才能使用鏈碼。修改以下四個環境變量以用作Org1:
# Environment variables for PEER0
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
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
現在,您可以將mycc鏈碼的定義允許爲Org1。
# this defines a chaincode for your org
# make note of the --package-id flag that provides the package ID
# use the --init-required flag to request the Init function be invoked to initialize the chaincode
peer lifecycle chaincode approveformyorg --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
一旦足夠數量的渠道成員批准了鏈碼定義,一個成員就可以將該定義提交給渠道。默認情況下,大多數通道成員需要批准定義才能提交。通過發出以下查詢,可以檢查鏈碼定義是否準備就緒,可以按組織查看當前的批准:
# the flags used for this command are identical to those used for approveformyorg
# except for --package-id which is not required since it is not stored as part of
# the definition
peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
該命令將生成一個JSON映射作爲輸出,以顯示通道中的組織是否已批准checkcommitreadiness命令中提供的鏈碼定義。在這種情況下,假設兩個組織都已批准,我們將獲得:
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
由於兩個渠道成員都批准了該定義,因此我們現在可以使用以下命令將其提交給渠道。您可以以Org1或Org2的形式發出此命令。請注意,該交易針對Org1和Org2中的同級收集簽註。
# this commits the chaincode definition to the channel
peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID $CHANNEL_NAME --name mycc --version 1.0 --sequence 1 --init-required --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
- 調用鏈碼
將鏈碼定義提交到通道後,我們準備調用鏈碼並開始與分類帳進行交互。我們要求Init
使用--init-required
標誌在鏈碼定義中執行該功能 。結果,我們需要將--isInit
標誌傳遞給它的第一次調用,並將參數提供給Init
函數。發出以下命令來初始化鏈碼並將初始數據放在分類帳中。
# be sure to set the -C and -n flags appropriately
# use the --isInit flag if you are invoking an Init function
peer chaincode invoke -o orderer.example.com:7050 --isInit --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["Init","a","100","b","100"]}' --waitForEvent
第一次調用將啓動chaincode容器。我們可能需要等待容器啓動。Node.js圖像將花費更長的時間。
query
讓我們查詢鏈碼,以確保正確啓動了容器並填充了狀態數據庫。查詢的語法如下
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
Invoke
現在讓我們10從a移至b。該事務將剪切一個新塊並更新狀態數據庫。調用的語法如下:
# be sure to set the -C and -n flags appropriately
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}' --waitForEvent
查詢結果:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
顯示:
Query Result: 90