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]"
- 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 to use (defaults to \"mychannel\")"
-t <timeout> - CLI timeout duration in seconds (defaults to 10)"
-d - delay duration in seconds (defaults to 3)"
-f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
-s - the database backend to use: goleveldb (default) or couchdb"
-l <language> - the chaincode language: golang (default), javascript, or java"
-a - launch certificate authorities (no certificate authorities are launched by default)
-n - do not deploy chaincode (abstore chaincode is deployed by default)
-i - the tag to be used to launch the network (defaults to \"latest\")"
-v - verbose mode"
byfn.sh -h (print this message)"
Typically, one would first generate the required certificates and
genesis block, then bring up the network. e.g.:"
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 javascript"
byfn.sh down -c mychannel"
byfn.sh upgrade -c mychannel"
Taking all defaults:"
byfn.sh generate"
byfn.sh up"
byfn.sh down"
我们将使用cryptogen
工具为各种网络参与者生成加密材料(x509证书和签名密钥)。这些证书代表它们的身份,用于进行通信和交易时进行签名/验证。
Cryptogen
使用了一个文件crypto-config.yaml
,该文件包含网络拓扑,并允许我们为组织和属于这些组织的组件生成一组证书和密钥。每个组织都有一个唯一的根证书(ca-cert
),它将特定组件(peer,orderer
)绑定到该组织。通过为每个组织分配唯一的CA
证书,我们正在模仿一个典型的网络,参与的成员将使用其自己的证书颁发机构。Hyperledger Fabric
中的事务和通信由实体的私钥(key store
)签名,然后通过公钥(signcerts
)进行验证。有关证书的详情,请查看这里。
您会在此文件中注意到一个count
变量。我们使用它来指定每个组织的节点的个数;在我们的byfn
中,每个单位有两个节点。
在运行cryptogen
工具之后,生成的证书和密钥将保存到crypto-config
的文件夹中。请注意,crypto-config.yaml
文件列出了五个orderer
。它们组合成etcdraft
排序服务,并用于创建system channel
和mychannel
。
configtxgen
工具用于创建下面四个配置文件:
genesis block
configuration transaction
two anchor peer transactions
- one for each Peer Org.其中,genesis block
用于排序服务; configuration transaction
在通道被创建时生成;two anchor peer transactions
指定了通道上的两个锚节点。
Configtxgen
使用文件configtx.yaml
。该文件包含网络的定义,有三个成员-OrdererOrg
和Org1&Org2
。该文件还指定了一个联盟-SampleConsortium
-由两个节点组织组成。请注意,SampleConsortium
是在系统级配置文件中定义的,然后由通道级配置文件引用。
请特别注意此文件底部的Profiles
部分。有几个值得注意的地方:
SampleMultiNodeEtcdRaft
:生成Raft订购服务的创世块。仅在发出-o标志并指定etcdraft时使用。TwoOrgsChannel
:生成创世区块。该文件还有两点需要注意。首先,我们为每个节点组织指定锚点对等体(peer0.org1.example.com&peer0.org2.example.com
)。其次,我们指定了每个实体的MSPDir
的位置,从而将每个组织的根证书存储在orderer Genesis block
中,用于验证任何与排序服务通信的实体的签名。
首先,让我们运行cryptogen
工具。我们的二进制文件位于bin
目录中,因此我们需要提供工具所在的相对路径。
../bin/cryptogen generate --config=./crypto-config.yaml
您应该在终端中看到以下内容:
org1.example.com
org2.example.com
证书和密钥(即MSP
资料)将在first-network
下的crypto-config
下生成。
我们需要告诉configtxgen
工具在哪里找需要的configtx.yaml
文件:
export FABRIC_CFG_PATH=$PWD
然后,我们将调用configtxgen
工具来创建orderer genesis block
:
../bin/configtxgen -profile SampleMultiNodeEtcdRaft -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
orderer genesis block
和我们将要创建的后续文件将输出到first-network
下的channel-artifacts
目录中。上面命令中的channelID
是system channel
的名称。
创建channel configuration transaction
:
# The channel.tx artifact contains the definitions for our sample channel
export CHANNEL_NAME=mychannel && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
TwoOrgsChannel
配置文件将使用您在创建网络的创世纪模块时指定的排序服务配置。您应该在终端中看到类似于以下内容的输出:
2017-10-26 19:24:05.324 EDT [common/tools/configtxgen] main -> INFO 001 Loading configuration
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 003 Writing new channel tx
接下来,我们将为Org1 & Org2
定义锚点:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
docker-compose -f docker-compose-cli.yaml -f docker-compose-etcdraft2.yaml up -d
如果要查看网络的实时日志,请不要提供-d
标志。
docker-compose
使用下载的镜像,并使用我们先前生成的genesis.block
启动排序服务。
回想一下,我们在上面使用configtxgen
工具生成的channel configuration transaction
。您可以重复该过程来创建其他channel configuration transaction
。然后,在网络中建立其他通道。
我们将使用docker exec
命令进入CLI容器:
docker exec -it cli bash
为了使用peer0.org1.example.com
,我们需要设置下面四个环境变量:
# Environment variables for PEER0
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
接下来,作为创建通道请求的一部分,我们将使用命令把channel configuration transaction
( channel.tx
)传递给排序服务:
export CHANNEL_NAME=mychannel
# the channel.tx file is mounted in the channel-artifacts directory within your CLI container
# as a result, we pass the full path for the file
# we also pass the path for the orderer ca-cert in order to verify the TLS handshake
# be sure to export or replace the $CHANNEL_NAME variable appropriately
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
我们使用-c
标志指定我们的通道名称,并使用-f
标志指定我们的channel.tx
。通道名称必须全部为小写字母,少于250个字符[a-z] [a-z0-9 .-] *
。
请注意我们在此命令中传递的--cafile
。这是orderer
根证书的本地路径,用于验证TLS
握手。
此命令返回一个创世区块
,我们将使用它来加入通道。它包含channel.tx
中指定的配置信息。
现在,让我们将peer0.org1.example.com
加入该频道:
# By default, this joins ``peer0.org1.example.com`` only
# the was returned by the previous command
# if you have not modified the channel name, you will join with mychannel.block
# if you have created a different channel name, then pass in the appropriately named block
peer channel join -b mychannel.block
更改环境变量到 peer0.org2.example.com
并加入通道:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt peer channel join -b mychannel.block
// Org1
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
// Org2
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# before packaging Go chaincode, vendoring Go dependencies is required like the following commands.
cd /opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/abstore/go
GO111MODULE=on go mod vendor
cd -
# this packages a Go chaincode.
# make note of the --lang flag to indicate "golang" chaincode
# for Go chaincode --path takes the relative path from $GOPATH/src
# The --label flag is used to create the package label
peer lifecycle chaincode package mycc.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/abstore/go/ --lang golang --label mycc_1
peer0.org1安装链码(env
查看环境变量指向哪个节点,前面部分有参数可以 cp):
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
# this command installs a chaincode package on your peer
peer lifecycle chaincode install mycc.tar.gz
成功的安装命令将返回链码包标识符。您应该看到类似于以下内容的输出:
2019-03-13 13:48:53.691 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nEmycc_1:3a8c52d70c36313cfebbaf09d8616e7a6318ababa01c7cbe40603c373bcfe173" >
2019-03-13 13:48:53.691 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: mycc_1:3a8c52d70c36313cfebbaf09d8616e7a6318ababa01c7cbe40603c373bcfe173
您还可以通过查询对等方以获取有关已安装软件包的信息来找到链码软件包标识符:
# this returns the details of the chaincode packages installed on your peers
peer lifecycle chaincode queryinstalled
我们将在以后的命令中需要软件包ID,所以让我们继续并将其保存为环境变量:
# Save the package ID as an environment variable.
CC_PACKAGE_ID=mycc_1:3a8c52d70c36313cfebbaf09d8616e7a6318ababa01c7cbe40603c373bcfe173
mycc
的背书策略设置为要求Org1
和Org2
背书。因此,我们还需要在Org2
中的节点上安装chaincode
:
# Environment variables for PEER0 in Org2
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:9051
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
peer lifecycle chaincode install mycc.tar.gz
同意链码参数:
# this approves a chaincode definition for your org
# make note of the --package-id flag that provides the package ID
# use the --init-required flag to request the ``Init`` function be invoked to initialize the chaincode
peer lifecycle chaincode approveformyorg --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# Environment variables for PEER0
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
# this defines a chaincode for your org
# make note of the --package-id flag that provides the package ID
# use the --init-required flag to request the Init function be invoked to initialize the chaincode
peer lifecycle chaincode approveformyorg --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
我们可以在上面的命令中提供--signature-policy
或--channel-config-policy
参数来设置链码的背书策略。有关背书策略。
我们可以使用checkreadiness
查看成员对合约的看法,一旦足够数量的通道成员批准了链码定义,一个成员就可以将该定义提交给通道:
# the flags used for this command are identical to those used for approveformyorg
# except for --package-id which is not required since it is not stored as part of
# the definition
peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name mycc --version 1.0 --init-required --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
输出如下:
{
"Approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
由于两个成员都批准了该定义,因此我们现在可以使用以下命令将其提交。您可以以Org1
或Org2
的发出此命令。请注意,该交易需要Org1
和Org2
中的节点背书:
# this commits the chaincode definition to the channel
peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID $CHANNEL_NAME --name mycc --version 1.0 --sequence 1 --init-required --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
我们在链码定义过程中使用--init-required
标志要求执行Init
函数。所以我们需要将--isInit
标志传递给它的第一次调用,并将参数提供给Init函数。
# be sure to set the -C and -n flags appropriately
# use the --isInit flag if you are invoking an Init function
peer chaincode invoke -o orderer.example.com:7050 --isInit --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["Init","a","100","b","100"]}' --waitForEvent
第一次调用链码将启动chaincode容器。
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
现在,从a
转10
到b
。该交易将剪切一个新块并更新状态数据库。
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
我们应该看到以下内容:
Query Result: 90
Install the chaincode on an additional peer
所属组织批准一次链码定义即可,一旦其他节点尝试与该特定链式代码进行交互,就会为其启动一个链码容器。
# Environment variables for PEER1 in Org2
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
CORE_PEER_ADDRESS=peer1.org2.example.com:10051
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
# this command installs a chaincode package on your peer
peer lifecycle chaincode install mycc.tar.gz
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer channel join -b mychannel.block
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'