hyperledger中文文档学习-4-构建第一个fabric网络

接下来的操作都将在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 '' seconds and CLI delay of '' 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 '' seconds and CLI delay of '' 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=
+ 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
-- ::11.852 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::11.980 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::11.981 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.009 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::12.009 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.034 UTC [common.tools.configtxgen] doOutputBlock -> INFO Generating genesis block
-- ::12.040 UTC [common.tools.configtxgen] doOutputBlock -> INFO Writing genesis block
+ res=
+ set +x #################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
-- ::12.181 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::12.230 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.260 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::12.260 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.261 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO Generating new channel configtx
-- ::12.262 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml
-- ::12.274 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml
-- ::12.281 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO Writing new channel tx
+ res=
+ set +x #################################################################
####### Generating anchor peer update for Org1MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
-- ::12.424 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::12.472 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.498 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::12.499 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.501 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Generating anchor peer update
-- ::12.506 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Writing anchor peer update
+ res=
+ set +x #################################################################
####### Generating anchor peer update for Org2MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
-- ::12.650 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::12.703 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.729 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::12.729 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::12.729 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Generating anchor peer update
-- ::12.734 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Writing anchor peer update
+ res=
+ 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 '' seconds and CLI delay of '' seconds
Continue? [Y/n] y
proceeding ...
./byfn.sh: line : configtxlator: command not found

解决办法可见:hyperledge工具-configtxlator

编译好该工具后,再次运行该语句,返回结果为:

vagrant@ubuntu-xenial:~/fabric-samples/first-network$ ./byfn.sh up
Starting for channel 'mychannel' with CLI timeout of '' seconds and CLI delay of '' seconds
Continue? [Y/n] y
proceeding ...
LOCAL_VERSION=1.4.
DOCKER_IMAGE_VERSION=1.4.
=================== 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=
+ 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
-- ::42.879 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::42.970 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::42.970 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.001 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::43.002 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.027 UTC [common.tools.configtxgen] doOutputBlock -> INFO Generating genesis block
-- ::43.032 UTC [common.tools.configtxgen] doOutputBlock -> INFO Writing genesis block
+ res=
+ set +x #################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
-- ::43.135 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::43.176 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.201 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::43.201 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.201 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO Generating new channel configtx
-- ::43.202 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml
-- ::43.209 UTC [common.tools.configtxgen.encoder] NewChannelGroup -> WARN Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml
-- ::43.213 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO Writing new channel tx
+ res=
+ set +x #################################################################
####### Generating anchor peer update for Org1MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
-- ::43.322 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::43.361 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.388 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::43.388 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.388 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Generating anchor peer update
-- ::43.391 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Writing anchor peer update
+ res=
+ set +x #################################################################
####### Generating anchor peer update for Org2MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
-- ::43.499 UTC [common.tools.configtxgen] main -> INFO Loading configuration
-- ::43.541 UTC [common.tools.configtxgen.localconfig] Load -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.566 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO orderer type: solo
-- ::43.566 UTC [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO Loaded configuration: /home/vagrant/fabric-samples/first-network/configtx.yaml
-- ::43.566 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Generating anchor peer update
-- ::43.569 UTC [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO Writing anchor peer update
+ res=
+ 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: -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=
+ set +x
-- ::46.000 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::46.030 UTC [cli.common] readBlock -> INFO Received block:
===================== Channel 'mychannel' created ===================== Having all peers join the channel...
+ peer channel join -b mychannel.block
+ res=
+ set +x
-- ::46.084 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::46.105 UTC [channelCmd] executeJoin -> INFO Successfully submitted proposal to join channel
===================== peer0.org1 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block
+ res=
+ set +x
-- ::49.165 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::49.194 UTC [channelCmd] executeJoin -> INFO Successfully submitted proposal to join channel
===================== peer1.org1 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block
+ res=
+ set +x
-- ::52.263 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::52.292 UTC [channelCmd] executeJoin -> INFO Successfully submitted proposal to join channel
===================== peer0.org2 joined channel 'mychannel' ===================== + peer channel join -b mychannel.block
+ res=
+ set +x
-- ::55.354 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::55.378 UTC [channelCmd] executeJoin -> INFO Successfully submitted proposal to join channel
===================== peer1.org2 joined channel 'mychannel' ===================== Updating anchor peers for org1...
+ peer channel update -o orderer.example.com: -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=
+ set +x
-- ::58.440 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::58.455 UTC [channelCmd] update -> INFO 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: -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=
+ set +x
-- ::01.512 UTC [channelCmd] InitCmdFactory -> INFO Endorser and orderer connections initialized
-- ::01.526 UTC [channelCmd] update -> INFO 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=
+ set +x
-- ::04.590 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default escc
-- ::04.590 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default vscc
-- ::04.756 UTC [chaincodeCmd] install -> INFO Installed remotely response:<status: 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=
+ set +x
-- ::04.816 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default escc
-- ::04.816 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default vscc
-- ::04.964 UTC [chaincodeCmd] install -> INFO Installed remotely response:<status: payload:"OK" >
===================== Chaincode is installed on peer0.org2 ===================== Instantiating chaincode on peer0.org2...
+ peer chaincode instantiate -o orderer.example.com: --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=
+ set +x
-- ::05.023 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default escc
-- ::05.023 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 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 ... secs
+ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
+ res=
+ set +x ===================== Query successful on peer0.org1 on channel 'mychannel' =====================
Sending invoke transaction on peer0.org1 peer0.org2...
+ peer chaincode invoke -o orderer.example.com: --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: --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: --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=
+ set +x
-- ::35.812 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO Chaincode invoke successful. result: status:
===================== 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=
+ set +x
-- ::35.864 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default escc
-- ::35.864 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO Using default vscc
-- ::35.993 UTC [chaincodeCmd] install -> INFO Installed remotely response:<status: 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 ... secs
+ res=
+ set +x ===================== 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:=""}
: ${LANGUAGE:="golang"}
: ${TIMEOUT:=""}
: ${VERBOSE:="false"}
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
COUNTER=
MAX_RETRY= 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 if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
set -x
peer channel create -o orderer.example.com: -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
res=$?
set +x
else
set -x
peer channel create -o orderer.example.com: -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 ; do
for peer in ; 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 #将组织org1中的peer0设置为锚节点
echo "Updating anchor peers for org2..."
updateAnchorPeers #将组织org2中的peer0设置为锚节点 ## Install chaincode on peer0.org1 and peer0.org2,在两个锚节点上安装链码,即智能合约
echo "Installing chaincode on peer0.org1..."
installChaincode
echo "Install chaincode on peer0.org2..."
installChaincode # Instantiate chaincode on peer0.org2,然后实例化锚点peer0.org2上的链码,将链码上的值设为{"Args":["init","a","","b",""]}
# 这个链码在peer0.org2.example.com被实例化。实例化过程将链码添加到channel上,并启动peer节点对应的容器,并且初始化和链码服务有关的键值对。
# 示例的初始化的值是[”a“,”“,”b“,”“]。实例化的结果是一个名为dev-peer0.org2.example.com-mycc-.0的容器启动了
# 实例化过程同样为背书策略传递相关参数。策略被定义为-P "AND ('Org1MSP.peer','Org2MSP.peer'),意思是任何交易必须被Org1和Org2同时背书。
# 只需要通过一个节点对链码进行实例化,用于将链码添加到channel上,之后从别的节点上调用或查询链码是就会直接生成容器来进行操作
echo "Instantiating chaincode on peer0.org2..."
instantiateChaincode # Query chaincode on peer0.org1,然后我们从peer0.org1节点查看链码
# 一个针对a的查询发往peer0.org1.example.com。链码服务已经被安装在了peer0.org1.example.com,因此这次查询将启动一个名为dev-peer0.org1.example.com-mycc-.0的容器。
# 查询的结果也将被返回。因为没有写操作,因此查询的结果的值将为100
# 第三个参数用于作为EXPECTED_RESULT,用于查看得到的值是否与期望相符
echo "Querying chaincode on peer0.org1..."
chaincodeQuery # Invoke chaincode on peer0.org1 and peer0.org2
# 一次invoke被发往peer0.org1.example.com,从a转移10到b
# 输入参数为0 , 1说明invoke在peer0.org1上运行, 2说明需要两者对交易进行背书
echo "Sending invoke transaction on peer0.org1 peer0.org2..."
chaincodeInvoke ## Install chaincode on peer1.org2
#然后链码被安装到peer1.org2.example.com
echo "Installing chaincode on peer1.org2..."
installChaincode # Query on chaincode on peer1.org2, check if the result is
# 一个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 echo
echo "========= All GOOD, BYFN execution completed =========== "
echo echo
echo " _____ _ _ ____ "
echo "| ____| | \ | | | _ \ "
echo "| _| | \| | | | | | "
echo "| |___ | |\ | | |_| | "
echo "|_____| |_| \_| |____/ "
echo exit

调用的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 [ $ -ne ]; then
echo "!!!!!!!!!!!!!!! "$" !!!!!!!!!!!!!!!!"
echo "========= ERROR !!! FAILED to execute End-2-End Scenario ==========="
echo
exit
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=$
ORG=$
if [ $ORG -eq ]; 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 ]; then
CORE_PEER_ADDRESS=peer0.org1.example.com:
else
CORE_PEER_ADDRESS=peer1.org1.example.com:
fi
elif [ $ORG -eq ]; 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 ]; then
CORE_PEER_ADDRESS=peer0.org2.example.com:
else
CORE_PEER_ADDRESS=peer1.org2.example.com:
fi elif [ $ORG -eq ]; 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 ]; then
CORE_PEER_ADDRESS=peer0.org3.example.com:
else
CORE_PEER_ADDRESS=peer1.org3.example.com:
fi
else
echo "================== ERROR !!! ORG Unknown =================="
fi if [ "$VERBOSE" == "true" ]; then
env | grep CORE
fi
} updateAnchorPeers() {
PEER=$
ORG=$
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: -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: -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 times
joinChannelWithRetry() {
PEER=$
ORG=$
setGlobals $PEER $ORG #根据输入的参数来定义相应的变量值,用于之后的配置 set -x
peer channel join -b $CHANNEL_NAME.block >&log.txt
res=$?
set +x
cat log.txt
if [ $res -ne -a $COUNTER -lt $MAX_RETRY ]; then
COUNTER=$(expr $COUNTER + )
echo "peer${PEER}.org${ORG} failed to join the channel, Retry after $DELAY seconds"
sleep $DELAY
joinChannelWithRetry $PEER $ORG
else
COUNTER=
fi
#查看添加节点到通道操作结果是否错误,错误则返回错误信息
verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to join channel '$CHANNEL_NAME' "
} installChaincode() {
PEER=$
ORG=$
setGlobals $PEER $ORG
VERSION=${:-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=$
ORG=$
setGlobals $PEER $ORG
VERSION=${:-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: -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: --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=$
ORG=$
setGlobals $PEER $ORG set -x
peer chaincode upgrade -o orderer.example.com: --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=$
ORG=$
setGlobals $PEER $ORG
EXPECTED_RESULT=$
echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== "
local rc=
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
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 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}')
test "$VALUE" = "$EXPECTED_RESULT" && let rc=
# 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 && VALUE=$(cat log.txt | egrep '^[0-9]+$')
test "$VALUE" = "$EXPECTED_RESULT" && let rc=
done
echo
cat log.txt
if test $rc -eq ; 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
fi
} # fetchChannelConfig <channel_id> <output_json>
# Writes the current channel config for a given channel to a JSON file
fetchChannelConfig() {
CHANNEL=$
OUTPUT=$ 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: -c $CHANNEL --cafile $ORDERER_CA
set +x
else
set -x
peer channel fetch config config_block.pb -o orderer.example.com: -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[].payload.data.config >"${OUTPUT}"
set +x
} # signConfigtxAsPeerOrg <org> <configtx.pb>
# Set the peerOrg admin of an org and signing the config update
signConfigtxAsPeerOrg() {
PEERORG=$
TX=$
setGlobals $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=$
ORIGINAL=$
MODIFIED=$
OUTPUT=$ 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 [ $(($# % )) -ne ]; then #$#即传入参数的个数
exit
fi PEER_CONN_PARMS=""
PEERS=""
while [ "$#" -gt ]; do
setGlobals $ $
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指向了$,因此下次循环$ $2得到的是输入参数$ $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: -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: --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…" hours ago Up hours dev-peer1.org2.example.com-mycc-1.0
8eb3f4c949f9 dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9 "chaincode -peer.add…" hours ago Up hours dev-peer0.org1.example.com-mycc-1.0
8614784a271a dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b "chaincode -peer.add…" hours ago Up hours dev-peer0.org2.example.com-mycc-1.0
aa96d57cf2fe hyperledger/fabric-tools:latest "/bin/bash" hours ago Up hours cli
35cd12cdebae hyperledger/fabric-peer:latest "peer node start" hours ago Up hours 0.0.0.0:->/tcp peer1.org1.example.com
9fbc87c27537 hyperledger/fabric-peer:latest "peer node start" hours ago Up hours 0.0.0.0:->/tcp peer1.org2.example.com
fd76d0279fd2 hyperledger/fabric-peer:latest "peer node start" hours ago Up hours 0.0.0.0:->/tcp peer0.org2.example.com
c7a8e06f4fe0 hyperledger/fabric-peer:latest "peer node start" hours ago Up hours 0.0.0.0:->/tcp peer0.org1.example.com
6b7d3f42e11e hyperledger/fabric-orderer:latest "orderer" hours ago Up hours 0.0.0.0:->/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":""} 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":""}
ex02 Invoke
Aval = , Bval = vagrant@ubuntu-xenial:~/fabric-samples/first-network/channel-artifacts$ docker logs dev-peer0.org2.example.com-mycc-1.0
ex02 Init
Aval = , Bval =
ex02 Invoke
Aval = , Bval =

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: '' 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:
- 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: '' 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
上一篇:Docker最全教程——数据库容器化(十)


下一篇:阿里云ECS训练营_Day03_微擎的安装与使用