打开fabric-samples-release-1.4\fabcar目录发现存在4个文件夹java、javascirpt、javascript-low-level、typescript,对应了各语言版本的调用chaincode客户端程序。
startFabric.sh脚本是启动该项目的shell脚本,我们从分析这个脚本入手。
①如下代码:CC_SRC_LANGUAGE:根据源代码语言类型,确定智能合约路径CC_SRC_PATH:
CC_SRC_LANGUAGE=`echo "$CC_SRC_LANGUAGE" | tr [:upper:] [:lower:]`
if [ "$CC_SRC_LANGUAGE" = "go" -o "$CC_SRC_LANGUAGE" = "golang" ]; then
CC_RUNTIME_LANGUAGE=golang
CC_SRC_PATH=github.com/chaincode/fabcar/go
elif [ "$CC_SRC_LANGUAGE" = "java" ]; then
CC_RUNTIME_LANGUAGE=java
CC_SRC_PATH=/opt/gopath/src/github.com/chaincode/fabcar/java
elif [ "$CC_SRC_LANGUAGE" = "javascript" ]; then
CC_RUNTIME_LANGUAGE=node # chaincode runtime language is node.js
CC_SRC_PATH=/opt/gopath/src/github.com/chaincode/fabcar/javascript
elif [ "$CC_SRC_LANGUAGE" = "typescript" ]; then
CC_RUNTIME_LANGUAGE=node # chaincode runtime language is node.js
CC_SRC_PATH=/opt/gopath/src/github.com/chaincode/fabcar/typescript
echo Compiling TypeScript code into JavaScript ...
pushd ../chaincode/fabcar/typescript
npm install
npm run build
popd
echo Finished compiling TypeScript code into JavaScript
else
echo The chaincode language ${CC_SRC_LANGUAGE} is not supported by this script
echo Supported chaincode languages are: go, javascript, and typescript
exit 1
fi
②删除存在的hfc-key-store
# clean the keystore
rm -rf ./hfc-key-store
③启动网络过程,创建通道并加入各节点。
# launch network; create channel and join peer to channel
cd ../first-network
echo y | ./byfn.sh down
echo y | ./byfn.sh up -a -n -s couchdb
fabcar項目需要进入…/first-network并利用./byfn.sh脚本进行启动,这个要注意。
byfn.sh [-c ] [-t ] [-d ] [-f ] [-s ] [-l ] [-o ] [-i ] [-a] [-n] [-v]"
‘up’ - bring up the network with docker-compose up" //采用docker-compose up 启动;
-a - launch certificate authorities (no certificate authorities are launched by default) //启用证书颁发机构
-n - do not deploy chaincode (abstore chaincode is deployed by default)" //不部署职能合约
-s - the database backend to use: goleveldb (default) or couchdb" 数据库后端使用:goleveldb(默认)或couchdb
export PATH=${PWD}/../bin:${PWD}:$PATH
export FABRIC_CFG_PATH=${PWD}
上面是进入./byfn.sh环境变量设置,将当前目录上级bin目录加入环境变量中,bin目录包含了configtxgen configtxlator cryptogen 等工具,否则后面这些工具命令无法使用。
还有一种做法是将这些工具加入到 /usr/local/bin/中,授权可执行。就在任何目录中可以执行了。
#Create the network using docker compose
if [ "${MODE}" == "up" ]; then
networkUp
elif [ "${MODE}" == "down" ]; then ## Clear the network
networkDown
elif [ "${MODE}" == "generate" ]; then ## Generate Artifacts
generateCerts
replacePrivateKey
generateChannelArtifacts
elif [ "${MODE}" == "restart" ]; then ## Restart the network
networkDown
networkUp
elif [ "${MODE}" == "upgrade" ]; then ## Upgrade the network from version 1.2.x to 1.3.x
upgradeNetwork
else
printHelp
exit 1
fi
这里mode参数为up,调用脚本的 networkUp 函数。
networkUp() : #生成所需的证书、genesis块并启动网络
# Generate the needed certificates, the genesis block and start the network.
# 生成所需的证书、genesis块并启动网络
function networkUp() {
#做一些基本的完整性检查,以确保合适的fabric版本
#二进制文件/images是可用的
checkPrereqs
# generate artifacts if they don't exist
# 如果组件配置不存在,则生成它们
if [ ! -d "crypto-config" ]; then #如果不存在生成crypto-config目录
#使用加密工具生成组织证书 具体参见 附录1- generateCerts()
generateCerts
#使用docker-compose-e2e-template。用私有密钥文件名替换常量
#由cryptogen工具生成并输出docker-compose 具体参见 附录2- replacePrivateKey()
replacePrivateKey
#生成orderer genesis块、通道配置事务和锚点对等更新事务,参见附录3-generateChannelArtifacts()
generateChannelArtifacts
fi
## 默认初始为:COMPOSE_FILE=docker-compose-cli.yaml
COMPOSE_FILES="-f ${COMPOSE_FILE}"
## 本例: CERTIFICATE_AUTHORITIES=true;
if [ "${CERTIFICATE_AUTHORITIES}" == "true" ]; then
## COMPOSE_FILE_CA=docker-compose-ca.yaml
COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_CA}"
##将CA私钥设置成环境变量中BYFN_CA1_PRIVATE_KEY、BYFN_CA2_PRIVATE_KEY
export BYFN_CA1_PRIVATE_KEY=$(cd crypto-config/peerOrganizations/org1.example.com/ca && ls *_sk)
export BYFN_CA2_PRIVATE_KEY=$(cd crypto-config/peerOrganizations/org2.example.com/ca && ls *_sk)
fi
if [ "${CONSENSUS_TYPE}" == "kafka" ]; then
COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_KAFKA}"
elif [ "${CONSENSUS_TYPE}" == "etcdraft" ]; then
COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_RAFT2}"
fi
#COMPOSE_FILE_COUCH=docker-compose-couch.yaml
if [ "${IF_COUCHDB}" == "couchdb" ]; then
COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_COUCH}"
fi
## default image tag IMAGETAG="latest"
##启动网络 docker-compose-cli.yaml; docker-compose-ca.yaml、docker-compose-couch.yaml
##docker-compose-cli.yaml 使用到了base目录下docker-compose-base.yaml、peer- ##base.yaml
IMAGE_TAG=$IMAGETAG docker-compose ${COMPOSE_FILES} up -d 2>&1
docker ps -a
if [ $? -ne 0 ]; then
echo "ERROR !!!! Unable to start network"
exit 1
fi
if [ "$CONSENSUS_TYPE" == "kafka" ]; then
sleep 1
echo "Sleeping 10s to allow $CONSENSUS_TYPE cluster to complete booting"
sleep 9
fi
if [ "$CONSENSUS_TYPE" == "etcdraft" ]; then
sleep 1
echo "Sleeping 15s to allow $CONSENSUS_TYPE cluster to complete booting"
sleep 14
fi
# now run the end to end script
#现在运行端到端脚本#
#CHANNEL_NAME="mychannel"
#CLI_DELAY=3
#LANGUAGE=golang
#CLI_TIMEOUT=10
#VERBOSE=false
#NO_CHAINCODE=true
#下面将实现 createChannel 创建通道、各节点加入通道、更新组织锚节点操作
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE $NO_CHAINCODE
if [ $? -ne 0 ]; then
echo "ERROR !!!! Test failed"
exit 1
fi
}
创建通道:createChannel()
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
加入通道 joinChannel () #各节点循环加入
peer channel join -b $CHANNEL_NAME.block >&log.txt
更新锚节点:updateAnchorPeers()
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
④ 安装链码、实例化链码、初始化账本
安装链码:Installing smart contract on peer0.org1.example.com
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
-e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \
cli \
peer chaincode install \
-n fabcar \
-v 1.0 \
-p "$CC_SRC_PATH" \
-l "$CC_RUNTIME_LANGUAGE"
安装链码: “Installing smart contract on peer0.org2.example.com”
docker exec \
-e CORE_PEER_LOCALMSPID=Org2MSP \
-e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \
-e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \
-e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \
cli \
peer chaincode install \
-n fabcar \
-v 1.0 \
-p "$CC_SRC_PATH" \
-l "$CC_RUNTIME_LANGUAGE"
实例化链码 : “Instantiating smart contract on mychannel”
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode instantiate \
-o orderer.example.com:7050 \
-C mychannel \
-n fabcar \
-l "$CC_RUNTIME_LANGUAGE" \
-v 1.0 \
-c '{"Args":[]}' \
-P "AND('Org1MSP.member','Org2MSP.member')" \
--tls \
--cafile ${ORDERER_TLS_ROOTCERT_FILE} \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE}
初始化账本:
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C mychannel \
-n fabcar \
-c '{"function":"initLedger","Args":[]}' \
--waitForEvent \
--tls \
--cafile ${ORDERER_TLS_ROOTCERT_FILE} \
--peerAddresses peer0.org1.example.com:7051 \
--peerAddresses peer0.org2.example.com:9051 \
--tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \
--tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE}
附录
# 附录1-generateCerts():使用加密工具生成组织证书
# Generates Org certs using cryptogen tool
function generateCerts() {
which cryptogen #测试一下cryptogen工具是否能执行。
if [ "$?" -ne 0 ]; then
echo "cryptogen tool not found. exiting"
exit 1
fi
echo
echo "##########################################################"
echo "##### Generate certificates using cryptogen tool #########"
echo "##########################################################"
#如果目录crypto-config存在就删除。
if [ -d "crypto-config" ]; then
rm -Rf crypto-config
fi
set -x
#按照crypto-config.yaml生成组织证书
cryptogen generate --config=./crypto-config.yaml
res=$?
set +x
if [ $res -ne 0 ]; then
echo "Failed to generate certificates..."
exit 1
fi
echo
echo "Generate CCP files for Org1 and Org2"
#生成org1,org2的 CCP files
./ccp-generate.sh
}
按照crypto-config.yaml生成组织证书
生成org1,org2的 CCP files ,这里要调用ccp-generate.sh脚本,需要使用cpp-template.json 、ccp-templdate.yaml 两个模版文件生成。最终生成了 connection-org1.json、connection-org1.yaml、 connection-org2.json、connection-org2.yaml四个CCP files。
#附录2-replacePrivateKey():使用docker-compose-e2e-template。用私有密钥文件名替换常量,由cryptogen工具生成并输出docker-compose
# 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
function replacePrivateKey() {
# sed on MacOSX does not support -i flag with a null extension. We will use
# 't' for our back-up's extension and delete it at the end of the function
ARCH=$(uname -s | grep Darwin)
if [ "$ARCH" == "Darwin" ]; then
OPTS="-it"
else
OPTS="-i"
fi
# Copy the template to the file that will be modified to add the private key
# 将模板复制到将被修改以添加私钥的文件中
cp docker-compose-e2e-template.yaml docker-compose-e2e.yaml
# The next steps will replace the template's contents with the
# actual values of the private key file names for the two CAs.
#接下来的步骤将用两个ca的私钥文件名的实际值替换模板的内容。
CURRENT_DIR=$PWD
cd crypto-config/peerOrganizations/org1.example.com/ca/
PRIV_KEY=$(ls *_sk)
cd "$CURRENT_DIR"
sed $OPTS "s/CA1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
cd crypto-config/peerOrganizations/org2.example.com/ca/
PRIV_KEY=$(ls *_sk)
cd "$CURRENT_DIR"
sed $OPTS "s/CA2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
# If MacOSX, remove the temporary backup of the docker-compose file
if [ "$ARCH" == "Darwin" ]; then
rm docker-compose-e2e.yamlt
fi
}
#附录3-generateChannelArtifacts():生成orderer genesis块、通道配置事务和锚点对等更新事务
# Generate orderer genesis block, channel configuration transaction and
# anchor peer update transactions
function generateChannelArtifacts() {
which configtxgen
if [ "$?" -ne 0 ]; then
echo "configtxgen tool not found. exiting"
exit 1
fi
echo "##########################################################"
echo "######### Generating Orderer Genesis block
######### 生成Orderer Genesis block ######################"
echo "##########################################################"
# Note: For some unknown reason (at least for now) the block file can't be
# named orderer.genesis.block or the orderer will fail to launch!
echo "CONSENSUS_TYPE="$CONSENSUS_TYPE
set -x
## 默认的 CONSENSUS_TYPE="solo" 在脚本最前面有定义。
if [ "$CONSENSUS_TYPE" == "solo" ]; then
configtxgen -profile TwoOrgsOrdererGenesis -channelID $SYS_CHANNEL -outputBlock ./channel-artifacts/genesis.block
elif [ "$CONSENSUS_TYPE" == "kafka" ]; then
configtxgen -profile SampleDevModeKafka -channelID $SYS_CHANNEL -outputBlock ./channel-artifacts/genesis.block
elif [ "$CONSENSUS_TYPE" == "etcdraft" ]; then
configtxgen -profile SampleMultiNodeEtcdRaft -channelID $SYS_CHANNEL -outputBlock ./channel-artifacts/genesis.block
else
set +x
echo "unrecognized CONSESUS_TYPE='$CONSENSUS_TYPE'. exiting"
exit 1
fi
res=$?
set +x
if [ $res -ne 0 ]; then
echo "Failed to generate orderer genesis block..."
exit 1
fi
echo
echo "#################################################################"
echo "### Generating channel configuration transaction 'channel.tx' ###"
echo "#################################################################"
set -x
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
res=$?
set +x
if [ $res -ne 0 ]; then
echo "Failed to generate channel configuration transaction..."
exit 1
fi
echo
echo "#################################################################"
echo "####### Generating anchor peer update for Org1MSP ##########"
echo "#################################################################"
set -x
## channel name 默认为 "mychannel" CHANNEL_NAME="mychannel"
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
res=$?
set +x
if [ $res -ne 0 ]; then
echo "Failed to generate anchor peer update for Org1MSP..."
exit 1
fi
echo
echo "#################################################################"
echo "####### Generating anchor peer update for Org2MSP ##########"
echo "#################################################################"
set -x
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate \
./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
res=$?
set +x
if [ $res -ne 0 ]; then
echo "Failed to generate anchor peer update for Org2MSP..."
exit 1
fi
echo
}
(结束)