接下來的操作都將在hyperledge環境安裝構建的虛擬機的環境下進行
參考https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/
1》運行實例
先下載hyperledger fabric samples示例
vagrant@ubuntu-xenial:~$ git clone https://github.com/hyperledger/fabric-samples.git Cloning into 'fabric-samples'... remote: Enumerating objects: 2705, done. remote: Total 2705 (delta 0), reused 0 (delta 0), pack-reused 2705 Receiving objects: 100% (2705/2705), 923.26 KiB | 323.00 KiB/s, done. Resolving deltas: 100% (1350/1350), done. Checking connectivity... done.
然后進入其的first-network目錄,因為下面要運行的目錄都必須運行在這個目錄下,否則提供的一些腳本可能無法找到對應的二進制:
vagrant@ubuntu-xenial:~$ ls
fabric-samples vagrant@ubuntu-xenial:~$ cd fabric-samples/first-network/ vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ls base docker-compose-cli.yaml docker-compose-org3.yaml byfn.sh docker-compose-couch-org3.yaml eyfn.sh channel-artifacts docker-compose-couch.yaml org3-artifacts configtx.yaml docker-compose-e2e-template.yaml README.md crypto-config.yaml docker-compose-kafka.yaml scripts
在這個文檔中提供一個完全注釋的腳本byfn.sh
,利用這些Docker鏡像可以快速引導一個由4個代表2個不同組織的peer節點以及一個排序服務節點的Hyperledger fabric
網絡。它還將啟動一個容器來運行一個將peer節點加入channel、部署實例化鏈碼服務以及驅動已經部署的鏈碼執行交易的腳本
首先我們能夠使用命令./byfn.sh -h來查看腳本的幫助信息:
vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh -h
Usage:
byfn.sh <mode> [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>] [-l <language>] [-o <consensus-type>] [-i <imagetag>] [-v] <mode> - one of 'up', 'down', 'restart', 'generate' or 'upgrade' - 'up' - bring up the network with docker-compose up - 'down' - clear the network with docker-compose down - 'restart' - restart the network - 'generate' - generate required certificates and genesis block - 'upgrade' - upgrade the network from version 1.3.x to 1.4.0 -c <channel name> - channel name to use (defaults to "mychannel") -t <timeout> - CLI timeout duration in seconds (defaults to 10),即如果你選擇不設置它,那么CLI容器將會在腳本執行完之后退出 -d <delay> - delay duration in seconds (defaults to 3) -f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml) -s <dbtype> - the database backend to use: goleveldb (default) or couchdb -l <language> - the chaincode language: golang (default) or node -o <consensus-type> - the consensus-type of the ordering service: solo (default) or kafka -i <imagetag> - the tag to be used to launch the network (defaults to "latest") -v - verbose mode byfn.sh -h (print this message) 一般來說,應該先生成需要的證書和創世區塊,然后運行該網絡,如:
(下面使用自定義的channel名,指明使用數據庫couchdb,鏡像標簽為1.4.0,並聲明使用node語言) byfn.sh generate -c mychannel byfn.sh up -c mychannel -s couchdb byfn.sh up -c mychannel -s couchdb -i 1.4.0 byfn.sh up -l node byfn.sh down -c mychannel byfn.sh upgrade -c mychannel 當然,你也可以完全使用默認的配置: byfn.sh generate byfn.sh up byfn.sh down
1)generate
首先我們先將需要的證書和創世區塊構建好,運行的過程中出現一個問題:
vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh generate Generating certs and genesis block for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds Continue? [Y/n] y proceeding ... cryptogen tool not found. exiting
需要知道什么是cryptogen,可見:hyperledge工具-cryptogen
運行該./byfn.sh generate命令會執行三個函數:
- generateCerts :先生成證書
- replacePrivateKey :然后使用docker-compose-e2e-template.yaml文件,用上面那一步使用cryptogen工具生成的私鑰文件名來替換docker-compose-e2e-template.yaml文件中的常量,即CA1_PRIVATE_KEY和CA2_PRIVATE_KEY,並輸出到特定於此配置的docker-compose-e2e.yaml文件中,來構建docker-compose-e2e.yaml文件
- generateChannelArtifacts :生成排序服務節點使用的創世區塊、創建通道使用的通道配置交易以及更新通道用的錨節點交易
generateChannelArtifacts中使用了configtxgen工具,詳情可見hyperledge工具-configtxgen
然后現在重新運行一次該命令:

Using docker-compose-e2e-template.yaml, replace constants with private key file names generated by the cryptogen tool and output a docker-compose.yaml specific to this configuration vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ls #一開始的文檔情況 base docker-compose-cli.yaml docker-compose-org3.yaml byfn.sh docker-compose-couch-org3.yaml eyfn.sh channel-artifacts docker-compose-couch.yaml org3-artifacts configtx.yaml docker-compose-e2e-template.yaml README.md crypto-config.yaml docker-compose-kafka.yaml scripts vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh generate #成功執行命令 Generating certs and genesis block for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds Continue? [Y/n] y proceeding ... /hyperledger/fabric/.build/bin/cryptogen #開始生成證書 ########################################################## ##### Generate certificates using cryptogen tool ######### ########################################################## + cryptogen generate --config=./crypto-config.yaml org1.example.com org2.example.com + res=0 + set +x /hyperledger/fabric/.build/bin/configtxgen ########################################################## ######### Generating Orderer Genesis block ############## ########################################################## CONSENSUS_TYPE=solo + '[' solo == solo ']' + configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block 2019-03-08 09:31:11.852 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-08 09:31:11.980 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 002 orderer type: solo 2019-03-08 09:31:11.981 UTC [common.tools.configtxgen.localconfig] Load -> INFO 003 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.009 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 004 orderer type: solo 2019-03-08 09:31:12.009 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 005 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.034 UTC [common.tools.configtxgen] doOutputBlock -> INFO 006 Generating genesis block 2019-03-08 09:31:12.040 UTC [common.tools.configtxgen] doOutputBlock -> INFO 007 Writing genesis block + res=0 + set +x ################################################################# ### Generating channel configuration transaction 'channel.tx' ### ################################################################# + configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel 2019-03-08 09:31:12.181 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-08 09:31:12.230 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.260 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-08 09:31:12.260 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.261 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 005 Generating new channel configtx 2019-03-08 09:31:12.262 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN 006 Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml 2019-03-08 09:31:12.274 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN 007 Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml 2019-03-08 09:31:12.281 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 008 Writing new channel tx + res=0 + set +x ################################################################# ####### Generating anchor peer update for Org1MSP ########## ################################################################# + configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP 2019-03-08 09:31:12.424 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-08 09:31:12.472 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.498 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-08 09:31:12.499 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.501 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update 2019-03-08 09:31:12.506 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update + res=0 + set +x ################################################################# ####### Generating anchor peer update for Org2MSP ########## ################################################################# + configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP 2019-03-08 09:31:12.650 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-08 09:31:12.703 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.729 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-08 09:31:12.729 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-08 09:31:12.729 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update 2019-03-08 09:31:12.734 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update + res=0 + set +x vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ls #生成了一個新文件夾crypto-config,一個文件docker-compose-e2e.yaml,文件夾channel-artifacts中也有變動 base docker-compose-cli.yaml docker-compose-org3.yaml byfn.sh docker-compose-couch-org3.yaml eyfn.sh channel-artifacts docker-compose-couch.yaml org3-artifacts configtx.yaml docker-compose-e2e-template.yaml README.md crypto-config docker-compose-e2e.yaml scripts crypto-config.yaml docker-compose-kafka.yaml
查看生成的新文件夾:
vagrant@ubuntu-xenial:~/fabric-samples/first-network$ cd channel-artifacts/
#生成了對應的創世區塊和交易文件
#其中系統鏈創世區塊只包含Org1和Org2的msp信息,應用通道配置channel.tx中指定mychannel中包含組織Org1和Org2 vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ ls channel.tx genesis.block Org1MSPanchors.tx Org2MSPanchors.tx vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ cd ..
#該文件夾下存儲的是生成的證書等信息
#在crypto-config中生成了Org1、Org2、Org3和Org4四個組織的msp信息 vagrant@ubuntu-xenial:~/fabric-samples/first-network$ cd crypto-config/ vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config$ ls ordererOrganizations peerOrganizations vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config$ cd ordererOrganizations/ vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/ordererOrganizations$ ls example.com vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/ordererOrganizations$ cd .. vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config$ cd peerOrganizations/ vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/peerOrganizations$ ls org1.example.com org2.example.com vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/peerOrganizations$ cd org1.example.com/ vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com$ ls ca msp peers tlsca users
新生成的docker-compose-e2e.yaml將相應的值給替換了,為:
FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA1_PRIVATE_KEY #變為: FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/b3eb7fc42dbd21...d535f51c53fe4067112e1f5034d_sk command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/CA1_PRIVATE_KEY -b admin:adminpw -d' #變為: command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/b3eb7fc42dbd21...d535f51c53fe4067112e1f5034d_sk -b admin:adminpw -d' FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA2_PRIVATE_KEY #變為: FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/9efd46a4ae0d71...7077b28639bf492b863c573cda85f78218_sk command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/CA2_PRIVATE_KEY -b admin:adminpw -d' #變為: command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/9efd46a4ae0d71...7077b28639bf492b863c573cda85f78218_sk -b admin:adminpw -d'
上面第一步生成我們各種網絡實體的所有證書和密鑰,genesis block
用於引導排序服務,以及配置Channel
所需要的一組交易配置集合。
2)up——啟動程序
出現一個問題:
vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh up Starting for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds Continue? [Y/n] y proceeding ... ./byfn.sh: line 122: configtxlator: command not found
解決辦法可見:hyperledge工具-configtxlator
編譯好該工具后,再次運行該語句,返回結果為:

vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh up Starting for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds Continue? [Y/n] y proceeding ... LOCAL_VERSION=1.4.1 DOCKER_IMAGE_VERSION=1.4.0 =================== WARNING =================== Local fabric binaries and docker images are out of sync. This may cause problems. =============================================== /hyperledger/fabric/.build/bin/cryptogen ########################################################## ##### Generate certificates using cryptogen tool ######### ########################################################## + cryptogen generate --config=./crypto-config.yaml org1.example.com org2.example.com + res=0 + set +x /hyperledger/fabric/.build/bin/configtxgen ########################################################## ######### Generating Orderer Genesis block ############## ########################################################## CONSENSUS_TYPE=solo + '[' solo == solo ']' + configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block 2019-03-10 02:00:42.879 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-10 02:00:42.970 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 002 orderer type: solo 2019-03-10 02:00:42.970 UTC [common.tools.configtxgen.localconfig] Load -> INFO 003 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.001 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 004 orderer type: solo 2019-03-10 02:00:43.002 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 005 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.027 UTC [common.tools.configtxgen] doOutputBlock -> INFO 006 Generating genesis block 2019-03-10 02:00:43.032 UTC [common.tools.configtxgen] doOutputBlock -> INFO 007 Writing genesis block + res=0 + set +x ################################################################# ### Generating channel configuration transaction 'channel.tx' ### ################################################################# + configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel 2019-03-10 02:00:43.135 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-10 02:00:43.176 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.201 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-10 02:00:43.201 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.201 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 005 Generating new channel configtx 2019-03-10 02:00:43.202 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN 006 Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml 2019-03-10 02:00:43.209 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN 007 Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml 2019-03-10 02:00:43.213 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 008 Writing new channel tx + res=0 + set +x ################################################################# ####### Generating anchor peer update for Org1MSP ########## ################################################################# + configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP 2019-03-10 02:00:43.322 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-10 02:00:43.361 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.388 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-10 02:00:43.388 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.388 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update 2019-03-10 02:00:43.391 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update + res=0 + set +x ################################################################# ####### Generating anchor peer update for Org2MSP ########## ################################################################# + configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP 2019-03-10 02:00:43.499 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration 2019-03-10 02:00:43.541 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.566 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo 2019-03-10 02:00:43.566 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml 2019-03-10 02:00:43.566 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update 2019-03-10 02:00:43.569 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update + res=0 + set +x Creating network "net_byfn" with the default driver Creating volume "net_peer0.org2.example.com" with default driver Creating volume "net_peer1.org2.example.com" with default driver Creating volume "net_peer1.org1.example.com" with default driver Creating volume "net_peer0.org1.example.com" with default driver Creating volume "net_orderer.example.com" with default driver Creating orderer.example.com ... Creating peer0.org2.example.com ... Creating orderer.example.com Creating peer0.org1.example.com ... Creating peer1.org1.example.com ... Creating peer1.org2.example.com ... Creating peer0.org2.example.com Creating peer0.org1.example.com Creating peer1.org1.example.com Creating peer1.org1.example.com ... done Creating cli ... Creating cli ... done ____ _____ _ ____ _____ / ___| |_ _| / \ | _ \ |_ _| \___ \ | | / _ \ | |_) | | | ___) | | | / ___ \ | _ < | | |____/ |_| /_/ \_\ |_| \_\ |_| Build your first network (BYFN) end-to-end test + peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --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 Channel name : mychannel Creating channel... + res=0 + set +x 2019-03-10 02:00:46.000 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:46.030 UTC [cli.common] readBlock -> INFO 002 Received block: 0 ===================== Channel 'mychannel' created ===================== Having all peers join the channel... + peer channel join -b mychannel.block + res=0 + set +x 2019-03-10 02:00:46.084 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:46.105 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel ===================== peer0.org1 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block + res=0 + set +x 2019-03-10 02:00:49.165 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:49.194 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel ===================== peer1.org1 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block + res=0 + set +x 2019-03-10 02:00:52.263 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:52.292 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel ===================== peer0.org2 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block + res=0 + set +x 2019-03-10 02:00:55.354 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:55.378 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel ===================== peer1.org2 joined channel 'mychannel' ===================== Updating anchor peers for org1... + peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --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 + res=0 + set +x 2019-03-10 02:00:58.440 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:00:58.455 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update ===================== Anchor peers updated for org 'Org1MSP' on channel 'mychannel' ===================== Updating anchor peers for org2... + peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --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 + res=0 + set +x 2019-03-10 02:01:01.512 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized 2019-03-10 02:01:01.526 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update ===================== Anchor peers updated for org 'Org2MSP' on channel 'mychannel' ===================== Installing chaincode on peer0.org1... + peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/ + res=0 + set +x 2019-03-10 02:01:04.590 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc 2019-03-10 02:01:04.590 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc 2019-03-10 02:01:04.756 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > ===================== Chaincode is installed on peer0.org1 ===================== Install chaincode on peer0.org2... + peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/ + res=0 + set +x 2019-03-10 02:01:04.816 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc 2019-03-10 02:01:04.816 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc 2019-03-10 02:01:04.964 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > ===================== Chaincode is installed on peer0.org2 ===================== Instantiating chaincode on peer0.org2... + peer chaincode instantiate -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 mychannel -n mycc -l golang -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P 'AND ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')' + res=0 + set +x 2019-03-10 02:01:05.023 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc 2019-03-10 02:01:05.023 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc ===================== Chaincode is instantiated on peer0.org2 on channel 'mychannel' ===================== Querying chaincode on peer0.org1... ===================== Querying on peer0.org1 on channel 'mychannel'... ===================== Attempting to Query peer0.org1 ...3 secs + peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}' + res=0 + set +x 100 ===================== Query successful on peer0.org1 on channel 'mychannel' ===================== Sending invoke transaction on peer0.org1 peer0.org2... + 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 mychannel -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"]}' + res=0 + set +x 2019-03-10 02:01:35.812 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 ===================== Invoke transaction successful on peer0.org1 peer0.org2 on channel 'mychannel' ===================== Installing chaincode on peer1.org2... + peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/ + res=0 + set +x 2019-03-10 02:01:35.864 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc 2019-03-10 02:01:35.864 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc 2019-03-10 02:01:35.993 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > ===================== Chaincode is installed on peer1.org2 ===================== Querying chaincode on peer1.org2... ===================== Querying on peer1.org2 on channel 'mychannel'... ===================== + peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}' Attempting to Query peer1.org2 ...4 secs + res=0 + set +x 90 ===================== Query successful on peer1.org2 on channel 'mychannel' ===================== ========= All GOOD, BYFN execution completed =========== _____ _ _ ____ | ____| | \ | | | _ \ | _| | \| | | | | | | |___ | |\ | | |_| | |_____| |_| \_| |____/ vagrant@ubuntu-xenial:~/fabric-samples/first-network$
查看實現代碼:
networkUp()函數首先回去檢查是否存在crypto-config文件夾,如果不存在,會先執行一遍./byfn.sh generate實現的操作:
# generate artifacts if they don't exist if [ ! -d "crypto-config" ]; then generateCerts replacePrivateKey generateChannelArtifacts fi
當各個條件都滿足后,就會啟動網絡:
# now run the end to end script
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
scripts/script.sh代碼為:
#!/bin/bash echo echo " ____ _____ _ ____ _____ " echo "/ ___| |_ _| / \ | _ \ |_ _|" echo "\___ \ | | / _ \ | |_) | | | " echo " ___) | | | / ___ \ | _ < | | " echo "|____/ |_| /_/ \_\ |_| \_\ |_| " echo echo "Build your first network (BYFN) end-to-end test" echo CHANNEL_NAME="$1" DELAY="$2" LANGUAGE="$3" TIMEOUT="$4" VERBOSE="$5" : ${CHANNEL_NAME:="mychannel"} : ${DELAY:="3"} : ${LANGUAGE:="golang"} : ${TIMEOUT:="10"} : ${VERBOSE:="false"} LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` COUNTER=1 MAX_RETRY=10 CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" if [ "$LANGUAGE" = "node" ]; then CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" fi if [ "$LANGUAGE" = "java" ]; then CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/java/" fi echo "Channel name : "$CHANNEL_NAME # import utils . scripts/utils.sh createChannel() { setGlobals 0 1 if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt res=$? set +x else set -x peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt res=$? set +x fi cat log.txt verifyResult $res "Channel creation failed" echo "===================== Channel '$CHANNEL_NAME' created ===================== " echo } joinChannel () { for org in 1 2; do for peer in 0 1; do joinChannelWithRetry $peer $org #joinChannelWithRetry函數是scripts/utils.sh中定義的函數 echo "===================== peer${peer}.org${org} joined channel '$CHANNEL_NAME' ===================== " sleep $DELAY echo done done } ## Create channel,先創建通道 echo "Creating channel..." createChannel ## Join all the peers to the channel,將org1的peer0、peer1和org2的peer0、peer1添加到通道中,以及利用$CHANNEL_NAME.block去創建一條鏈 echo "Having all peers join the channel..." joinChannel #現在我們有了由4個peer節點以及2個組織構成的信道。這是我們的TwoOrgsChannel配置文件。 #peer0.org1.example.com和peer1.org1.example.com屬於Org1;peer0.org2.example.com和peer1.org2.example.com屬於Org2 #這些關系是通過crypto-config.yaml定義的,MSP路徑在docker-compose文件中被指定 ## Set the anchor peers for each org in the channel,為每一個組織在通道中設置錨節點,updateAnchorPeers函數是scripts/utils.sh中定義的函數 #updateAnchorPeers函數通過攜帶channel的名字傳遞Org1MSPanchors.tx和Org2MSPanchors.tx配置到排序服務來實現anchor peer的更新 echo "Updating anchor peers for org1..." updateAnchorPeers 0 1 #將組織org1中的peer0設置為錨節點 echo "Updating anchor peers for org2..." updateAnchorPeers 0 2 #將組織org2中的peer0設置為錨節點 ## Install chaincode on peer0.org1 and peer0.org2,在兩個錨節點上安裝鏈碼,即智能合約 echo "Installing chaincode on peer0.org1..." installChaincode 0 1 echo "Install chaincode on peer0.org2..." installChaincode 0 2 # Instantiate chaincode on peer0.org2,然后實例化錨點peer0.org2上的鏈碼,將鏈碼上的值設為{"Args":["init","a","100","b","200"]} # 這個鏈碼在peer0.org2.example.com被實例化。實例化過程將鏈碼添加到channel上,並啟動peer節點對應的容器,並且初始化和鏈碼服務有關的鍵值對。 # 示例的初始化的值是[”a“,”100“,”b“,”200“]。實例化的結果是一個名為dev-peer0.org2.example.com-mycc-1.0的容器啟動了 # 實例化過程同樣為背書策略傳遞相關參數。策略被定義為-P "AND ('Org1MSP.peer','Org2MSP.peer'),意思是任何交易必須被Org1和Org2同時背書。 # 只需要通過一個節點對鏈碼進行實例化,用於將鏈碼添加到channel上,之后從別的節點上調用或查詢鏈碼是就會直接生成容器來進行操作 echo "Instantiating chaincode on peer0.org2..." instantiateChaincode 0 2 # Query chaincode on peer0.org1,然后我們從peer0.org1節點查看鏈碼 # 一個針對a的查詢發往peer0.org1.example.com。鏈碼服務已經被安裝在了peer0.org1.example.com,因此這次查詢將啟動一個名為dev-peer0.org1.example.com-mycc-1.0的容器。 # 查詢的結果也將被返回。因為沒有寫操作,因此查詢的結果的值將為100 # 第三個參數用於作為EXPECTED_RESULT,用於查看得到的值是否與期望相符 echo "Querying chaincode on peer0.org1..." chaincodeQuery 0 1 100 # Invoke chaincode on peer0.org1 and peer0.org2 # 一次invoke被發往peer0.org1.example.com,從a轉移10到b # 輸入參數為0 1 0 2,0 1說明invoke在peer0.org1上運行,0 1 0 2說明需要兩者對交易進行背書 echo "Sending invoke transaction on peer0.org1 peer0.org2..." chaincodeInvoke 0 1 0 2 ## Install chaincode on peer1.org2 #然后鏈碼被安裝到peer1.org2.example.com echo "Installing chaincode on peer1.org2..." installChaincode 1 2 # Query on chaincode on peer1.org2, check if the result is 90 # 一個query請求被發往peer1.org2.example.com用於查詢a的值。 # 這將啟動第三個鏈碼容器名為dev-peer1.org2.example.com-mycc-1.0。返回a的值為90,正確地反映了之前的交易,a的值被轉移了10 echo "Querying chaincode on peer1.org2..." chaincodeQuery 1 2 90 echo echo "========= All GOOD, BYFN execution completed =========== " echo echo echo " _____ _ _ ____ " echo "| ____| | \ | | | _ \ " echo "| _| | \| | | | | | " echo "| |___ | |\ | | |_| | " echo "|_____| |_| \_| |____/ " echo exit 0
調用的scripts/utils.sh代碼為:

# # Copyright IBM Corp All Rights Reserved # # SPDX-License-Identifier: Apache-2.0 # # This is a collection of bash functions used by different scripts 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 PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt PEER0_ORG3_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt # verify the result of the end-to-end test verifyResult() { if [ $1 -ne 0 ]; then echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!" echo "========= ERROR !!! FAILED to execute End-2-End Scenario ===========" echo exit 1 fi } # Set OrdererOrg.Admin globals setOrdererGlobals() { CORE_PEER_LOCALMSPID="OrdererMSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/Admin@example.com/msp } #根據輸入的參數來定義相應的變量值,用於之后的配置 setGlobals() { PEER=$1 ORG=$2 if [ $ORG -eq 1 ]; then CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp if [ $PEER -eq 0 ]; then CORE_PEER_ADDRESS=peer0.org1.example.com:7051 else CORE_PEER_ADDRESS=peer1.org1.example.com:8051 fi elif [ $ORG -eq 2 ]; then CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp if [ $PEER -eq 0 ]; then CORE_PEER_ADDRESS=peer0.org2.example.com:9051 else CORE_PEER_ADDRESS=peer1.org2.example.com:10051 fi elif [ $ORG -eq 3 ]; then CORE_PEER_LOCALMSPID="Org3MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG3_CA CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp if [ $PEER -eq 0 ]; then CORE_PEER_ADDRESS=peer0.org3.example.com:11051 else CORE_PEER_ADDRESS=peer1.org3.example.com:12051 fi else echo "================== ERROR !!! ORG Unknown ==================" fi if [ "$VERBOSE" == "true" ]; then env | grep CORE fi } updateAnchorPeers() { PEER=$1 ORG=$2 setGlobals $PEER $ORG #根據輸入的參數來定義相應的變量值,用於之后的配置 if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt res=$? set +x else set -x peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt res=$? set +x fi cat log.txt #查看添加錨節點操作結果是否錯誤,錯誤則返回錯誤信息 verifyResult $res "Anchor peer update failed" echo "===================== Anchor peers updated for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME' ===================== " sleep $DELAY echo } ## Sometimes Join takes time hence RETRY at least 5 times joinChannelWithRetry() { PEER=$1 ORG=$2 setGlobals $PEER $ORG #根據輸入的參數來定義相應的變量值,用於之后的配置 set -x peer channel join -b $CHANNEL_NAME.block >&log.txt res=$? set +x cat log.txt if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then COUNTER=$(expr $COUNTER + 1) echo "peer${PEER}.org${ORG} failed to join the channel, Retry after $DELAY seconds" sleep $DELAY joinChannelWithRetry $PEER $ORG else COUNTER=1 fi #查看添加節點到通道操作結果是否錯誤,錯誤則返回錯誤信息 verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to join channel '$CHANNEL_NAME' " } installChaincode() { PEER=$1 ORG=$2 setGlobals $PEER $ORG VERSION=${3:-1.0} set -x peer chaincode install -n mycc -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt res=$? set +x cat log.txt #查看添加鏈碼到錨點的操作結果是否錯誤,錯誤則返回錯誤信息 verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has failed" echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== " echo } instantiateChaincode() { PEER=$1 ORG=$2 setGlobals $PEER $ORG VERSION=${3:-1.0} # while 'peer chaincode' command can get the orderer endpoint from the peer # (if join was successful), let's supply it directly as we know it using # the "-o" option if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x #-P "AND ('Org1MSP.peer','Org2MSP.peer')說明可以使用Org1MSP.peer和Org2MSP.peer同時進行背書 peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt res=$? set +x else set -x peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt res=$? set +x fi cat log.txt verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed" echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== " echo } upgradeChaincode() { PEER=$1 ORG=$2 setGlobals $PEER $ORG set -x 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 "AND ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" res=$? set +x cat log.txt verifyResult $res "Chaincode upgrade on peer${PEER}.org${ORG} has failed" echo "===================== Chaincode is upgraded on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== " echo } chaincodeQuery() { PEER=$1 ORG=$2 setGlobals $PEER $ORG EXPECTED_RESULT=$3 echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== " local rc=1 local starttime=$(date +%s) # continue to poll # we either get a successful response, or reach TIMEOUT while test "$(($(date +%s) - starttime))" -lt "$TIMEOUT" -a $rc -ne 0 do sleep $DELAY echo "Attempting to Query peer${PEER}.org${ORG} ...$(($(date +%s) - starttime)) secs" set -x peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt res=$? set +x test $res -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}') test "$VALUE" = "$EXPECTED_RESULT" && let rc=0 # removed the string "Query Result" from peer chaincode query command # result. as a result, have to support both options until the change # is merged. test $rc -ne 0 && VALUE=$(cat log.txt | egrep '^[0-9]+$') test "$VALUE" = "$EXPECTED_RESULT" && let rc=0 done echo cat log.txt if test $rc -eq 0; then echo "===================== Query successful on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== " else echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!" echo "================== ERROR !!! FAILED to execute End-2-End Scenario ==================" echo exit 1 fi } # fetchChannelConfig <channel_id> <output_json> # Writes the current channel config for a given channel to a JSON file fetchChannelConfig() { CHANNEL=$1 OUTPUT=$2 setOrdererGlobals echo "Fetching the most recent configuration block for the channel" if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL --cafile $ORDERER_CA set +x else set -x peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL --tls --cafile $ORDERER_CA set +x fi echo "Decoding config block to JSON and isolating config to ${OUTPUT}" set -x configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config >"${OUTPUT}" set +x } # signConfigtxAsPeerOrg <org> <configtx.pb> # Set the peerOrg admin of an org and signing the config update signConfigtxAsPeerOrg() { PEERORG=$1 TX=$2 setGlobals 0 $PEERORG set -x peer channel signconfigtx -f "${TX}" set +x } # createConfigUpdate <channel_id> <original_config.json> <modified_config.json> <output.pb> # Takes an original and modified config, and produces the config update tx # which transitions between the two createConfigUpdate() { CHANNEL=$1 ORIGINAL=$2 MODIFIED=$3 OUTPUT=$4 set -x configtxlator proto_encode --input "${ORIGINAL}" --type common.Config >original_config.pb configtxlator proto_encode --input "${MODIFIED}" --type common.Config >modified_config.pb configtxlator compute_update --channel_id "${CHANNEL}" --original original_config.pb --updated modified_config.pb >config_update.pb configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate >config_update.json echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . >config_update_in_envelope.json configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope >"${OUTPUT}" set +x } # parsePeerConnectionParameters $@ # Helper function that takes the parameters from a chaincode operation # (e.g. invoke, query, instantiate) and checks for an even number of # peers and associated org, then sets $PEER_CONN_PARMS and $PEERS parsePeerConnectionParameters() { # check for uneven number of peer and org parameters if [ $(($# % 2)) -ne 0 ]; then #$#即傳入參數的個數 exit 1 fi PEER_CONN_PARMS="" PEERS="" while [ "$#" -gt 0 ]; do setGlobals $1 $2 PEER="peer$1.org$2" PEERS="$PEERS $PEER" PEER_CONN_PARMS="$PEER_CONN_PARMS --peerAddresses $CORE_PEER_ADDRESS" if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "true" ]; then TLSINFO=$(eval echo "--tlsRootCertFiles \$PEER$1_ORG$2_CA") PEER_CONN_PARMS="$PEER_CONN_PARMS $TLSINFO" fi # shift by two to get the next pair of peer/org parameters shift shift #兩個shift的作用就是將參數從$1指向了$3,因此下次循環$1 $2得到的是輸入參數$3 $4的值,且$#由4變為2 done # remove leading space for output PEERS="$(echo -e "$PEERS" | sed -e 's/^[[:space:]]*//')" } # chaincodeInvoke <peer> <org> ... # Accepts as many peer/org pairs as desired and requests endorsement from each chaincodeInvoke() { parsePeerConnectionParameters $@ #$@為傳遞給腳本或函數的所有參數,parsePeerConnectionParameters函數的作用是獲取傳入的參數來設置$PEER_CONN_PARMS和$PEERS,輸入的參數個數需要為偶數,每個節點帶着指定的組織 res=$? #$?得到的是上個命令的退出狀態,或函數的返回值 verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters " # while 'peer chaincode' command can get the orderer endpoint from the # peer (if join was successful), let's supply it directly as we know # it using the "-o" option if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then set -x peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt res=$? set +x else set -x peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt res=$? set +x fi cat log.txt verifyResult $res "Invoke execution on $PEERS failed " echo "===================== Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME' ===================== " echo }
為了能夠正確地在賬本上進行讀寫操作,鏈碼服務必須被安裝在peer節點上。此外,每個peer節點的鏈碼服務的容器除了init
或者傳統的交易-讀/寫-針對該鏈碼服務執行(例如查詢a
的值),在其他情況下不會啟動。
交易導致容器的啟動。
當然,所有信道中的節點都持有以塊的形式順序存儲的不可變的賬本精確的備份,以及狀態數據庫來保存前狀態的快照。這包括了沒有在其上安裝鏈碼服務的peer節點(peer1.org2.example.com
如上所示)。最后,鏈碼在被安裝后將是可達狀態,因為它已經被實例化了。
此時使用docker查看容器狀態:
vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ec6368e29288 dev-peer1.org2.example.com-mycc-1.0-26c2ef32838554aac4f7ad6f100aca865e87959c9a126e86d764c8d01f8346ab "chaincode -peer.add…" 8 hours ago Up 8 hours dev-peer1.org2.example.com-mycc-1.0 8eb3f4c949f9 dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9 "chaincode -peer.add…" 8 hours ago Up 8 hours dev-peer0.org1.example.com-mycc-1.0 8614784a271a dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b "chaincode -peer.add…" 8 hours ago Up 8 hours dev-peer0.org2.example.com-mycc-1.0 aa96d57cf2fe hyperledger/fabric-tools:latest "/bin/bash" 8 hours ago Up 8 hours cli 35cd12cdebae hyperledger/fabric-peer:latest "peer node start" 8 hours ago Up 8 hours 0.0.0.0:8051->8051/tcp peer1.org1.example.com 9fbc87c27537 hyperledger/fabric-peer:latest "peer node start" 8 hours ago Up 8 hours 0.0.0.0:10051->10051/tcp peer1.org2.example.com fd76d0279fd2 hyperledger/fabric-peer:latest "peer node start" 8 hours ago Up 8 hours 0.0.0.0:9051->9051/tcp peer0.org2.example.com c7a8e06f4fe0 hyperledger/fabric-peer:latest "peer node start" 8 hours ago Up 8 hours 0.0.0.0:7051->7051/tcp peer0.org1.example.com 6b7d3f42e11e hyperledger/fabric-orderer:latest "orderer" 8 hours ago Up 8 hours 0.0.0.0:7050->7050/tcp orderer.example.com
3)查看日志
1》容器日志
vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker logs -f cli
2》鏈碼日志
vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker logs dev-peer1.org2.example.com-mycc-1.0 ex02 Invoke Query Response:{"Name":"a","Amount":"90"} vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker logs dev-peer0.org1.example.com-mycc-1.0 ex02 Invoke Query Response:{"Name":"a","Amount":"100"} ex02 Invoke Aval = 90, Bval = 210 vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker logs dev-peer0.org2.example.com-mycc-1.0 ex02 Init Aval = 100, Bval = 200 ex02 Invoke Aval = 90, Bval = 210
4)使用的docker-compose
BYFN示例給我們提供了兩種風格的Docker Compose文件,它們都繼承自docker-compose-base.yaml
1》 docker-compose-cli.yaml
該文件提供了一個CLI容器,以及一個orderer容器,四個peer容器。我們用此文件來展開這個頁面上的所有說明。

# Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer.example.com: peer0.org1.example.com: peer1.org1.example.com: peer0.org2.example.com: peer1.org2.example.com: networks: byfn: services: orderer.example.com: extends: file: base/docker-compose-base.yaml service: orderer.example.com container_name: orderer.example.com networks: - byfn peer0.org1.example.com: container_name: peer0.org1.example.com extends: file: base/docker-compose-base.yaml service: peer0.org1.example.com networks: - byfn peer1.org1.example.com: container_name: peer1.org1.example.com extends: file: base/docker-compose-base.yaml service: peer1.org1.example.com networks: - byfn peer0.org2.example.com: container_name: peer0.org2.example.com extends: file: base/docker-compose-base.yaml service: peer0.org2.example.com networks: - byfn peer1.org2.example.com: container_name: peer1.org2.example.com extends: file: base/docker-compose-base.yaml service: peer1.org2.example.com networks: - byfn cli: container_name: cli image: hyperledger/fabric-tools:$IMAGE_TAG tty: true stdin_open: true environment: - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock #- FABRIC_LOGGING_SPEC=DEBUG - FABRIC_LOGGING_SPEC=INFO - 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/Admin@org1.example.com/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./../chaincode/:/opt/gopath/src/github.com/chaincode - ./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 networks: - byfn
2》docker-compose-e2e.yaml
該文件被構造為使用Node.js SDK來運行端到端測試。除了SDK的功能之外,它主要的區別在於它有運行fabric-ca服務的容器。因此,我們能夠向組織的CA節點發送REST的請求用於注冊和登記。

vagrant@ubuntu-xenial:~/fabric-samples/first-network$ cat docker-compose-e2e.yaml # Copyright IBM Corp. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # version: '2' volumes: orderer.example.com: peer0.org1.example.com: peer1.org1.example.com: peer0.org2.example.com: peer1.org2.example.com: networks: byfn: services: ca0: image: hyperledger/fabric-ca:$IMAGE_TAG environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca-org1 - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/c46248ab640500ea3...e571e5df2a77f57e3a48_sk ports: - "7054:7054" command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/c46248ab640500ea3...e571e5df2a77f57e3a48_sk -b admin:adminpw -d' volumes: - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca_peerOrg1 networks: - byfn ca1: image: hyperledger/fabric-ca:$IMAGE_TAG environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca-org2 - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/f9ec1c2b48d9cb...c013e6bad0b60_sk ports: - "8054:7054" command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/f9ec1c2b48d9cb...c013e6bad0b60_sk -b admin:adminpw -d' volumes: - ./crypto-config/peerOrganizations/org2.example.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca_peerOrg2 networks: - byfn orderer.example.com: extends: file: base/docker-compose-base.yaml service: orderer.example.com container_name: orderer.example.com networks: - byfn peer0.org1.example.com: container_name: peer0.org1.example.com extends: file: base/docker-compose-base.yaml service: peer0.org1.example.com networks: - byfn peer1.org1.example.com: container_name: peer1.org1.example.com extends: file: base/docker-compose-base.yaml service: peer1.org1.example.com networks: - byfn peer0.org2.example.com: container_name: peer0.org2.example.com extends: file: base/docker-compose-base.yaml service: peer0.org2.example.com networks: - byfn peer1.org2.example.com: container_name: peer1.org2.example.com extends: file: base/docker-compose-base.yaml service: peer1.org2.example.com networks: - byfn
如果你在沒有運行byfn.sh
腳本的情況下,想使用docker-compose-e2e.yaml
,我們需要進行4個輕微的修改。因為
docker-compose-e2e.yaml
是通過運行byfn.sh
腳本在docker-compose-e2e-template.yaml文件的基礎上生成的,需要將docker-compose-e2e-template.yaml文件中的CA1_PRIVATE_KEY和CA2_PRIVATE_KEY值進行手動更改為對應組織的私鑰
我們需要指出本組織CA的私鑰。你可以在crypto-config
文件夾中找到這些值。舉個例子,為了定位Org1的私鑰,我們將使用crypto-config/peerOrganizations/org1.example.com/ca/
。Org2的路徑為crypto-config/peerOrganizations/org2.example.com/ca/
,如下:
vagrant@ubuntu-xenial:~/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/ca$ ls
c46248ab640...1cca3c5f4c8dae571e5df2a77f57e3a48_sk ca.org1.example.com-cert.pem
第一個文件夾的名字就是該組織的私鑰值
5)使用CouchDB
沒有試着使用這個,之后再補上
6)關於數據持久化的提示
如果需要在peer容器或者CouchDB容器進行數據持久化,一種選擇是將docker容器內相應的目錄掛載到容器所在的宿主機的一個目錄中。例如,你可以添加下列的兩行到docker-compose-base.yaml
文件中peer的約定中:
volumes: - /var/hyperledger/peer0:/var/hyperledger/production
對於CouchDB容器,你可以在CouchDB的約定中添加兩行:
volumes: - /var/hyperledger/couchdb0:/opt/couchdb/data