目录
一、network.sh
#!/bin/bash
# 工作目录,包含二进制文件路径和通道配置文件路径
ROOTDIR=$(cd "$(dirname -- "$0")" && pwd)
export PATH=${ROOTDIR}/bin:${PWD}/bin:$PATH
export FABRIC_CFG_PATH=${PWD}/configtx
export VERBOSE=false
# push to the required directory & set a trap to go back if needed
pushd ${ROOTDIR} > /dev/null
trap "popd > /dev/null" EXIT
# utils.sh脚本为打印输出信息功能,utils.sh脚本中的相关函数,如infoln、errorln、warnln、fatalln、printHelp等函数,
. scripts/utils.sh
# CONTAINER_CLI=docker & CONTAINER_CLI_COMPOSE=docker-compose
: ${CONTAINER_CLI:="docker"}
: ${CONTAINER_CLI_COMPOSE:="${CONTAINER_CLI}-compose"}
infoln "Using ${CONTAINER_CLI} and ${CONTAINER_CLI_COMPOSE}"
# Versions of fabric known not to work with the test network
NONWORKING_VERSIONS="^1\.0\. ^1\.1\. ^1\.2\. ^1\.3\. ^1\.4\."
# Step1 -> 检查二进制文件是否存在
function checkPrereqs() {
# 检查二进制文件和配置文件是否克隆下来
# 通过使用peer命令来检查fabric二进制文件是否存在
peer version > /dev/null 2>&1
# 如果二进制文件不存在 或 config目录不存在,则显示错误信息并退出
if [[ $? -ne 0 || ! -d "./config" ]]; then
errorln "Peer binary and configuration files not found.."
errorln
errorln "Follow the instructions in the Fabric docs to install the Fabric Binaries:"
errorln "https://hyperledger-fabric.readthedocs.io/en/latest/install.html"
exit 1
fi
# 用fabric tool 容器 查看网络和二进制的版本是否匹配你的docker镜像
LOCAL_VERSION=$(peer version | sed -ne 's/^ Version: //p')
DOCKER_IMAGE_VERSION=$(${CONTAINER_CLI} run --rm hyperledger/fabric-tools:latest peer version | sed -ne 's/^ Version: //p')
infoln "LOCAL_VERSION=$LOCAL_VERSION"
infoln "DOCKER_IMAGE_VERSION=$DOCKER_IMAGE_VERSION"
# 若fabric二进制文件版本与镜像版本不一致,则输出警告信息
if [ "$LOCAL_VERSION" != "$DOCKER_IMAGE_VERSION" ]; then
warnln "Local fabric binaries and docker images are out of sync. This may cause problems."
fi
# 若为版本为1.4及之前版本,则抛出错误信息(不支持1.4及之前版本)
for UNSUPPORTED_VERSION in $NONWORKING_VERSIONS; do
infoln "$LOCAL_VERSION" | grep -q $UNSUPPORTED_VERSION
if [ $? -eq 0 ]; then
fatalln "Local Fabric binary version of $LOCAL_VERSION does not match the versions supported by the test network."
fi
infoln "$DOCKER_IMAGE_VERSION" | grep -q $UNSUPPORTED_VERSION
if [ $? -eq 0 ]; then
fatalln "Fabric Docker image version of $DOCKER_IMAGE_VERSION does not match the versions supported by the test network."
fi
done
}
# Step2 -> 使用cryptogen创建组织及证书
function createOrgs() {
# 清除残留的证书文件夹
if [ -d "organizations/peerOrganizations" ]; then
rm -Rf organizations/peerOrganizations && rm -Rf organizations/ordererOrganizations
fi
# 使用 cryptogen 创建加密材料
if [ "$CRYPTO" == "cryptogen" ]; then
# 搜索cryptogen命令是否存在,存在则输出所在路径及别名,否则抛出错误信息,程序终止
which cryptogen
if [ "$?" -ne 0 ]; then
fatalln "cryptogen tool not found. exiting"
fi
infoln "Generating certificates using cryptogen tool"
infoln "Creating Org1 Identities"
set -x # 脚本调试命令,将会把下面命令打印到屏幕
# 生成组织org1且为其生成证书
cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null # 关闭脚本调试命令,之后的命令不会打印到屏幕了
# 若创建组织生成证书失败,则抛出错误信息,程序终止
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
infoln "Creating Org2 Identities"
set -x
# 生成组织org2且为其生成证书
cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null
# 若创建组织生成证书失败,则抛出错误信息,程序终止
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
infoln "Creating Orderer Org Identities"
set -x
# 生成组织orderer且为其生成证书
cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null
# 若创建组织生成证书失败,则抛出错误信息,程序终止
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
fi
#infoln "Generating CCP files for Org1 and Org2" #生成调用nodejs SDK的相关区块配置文件。
# 生成通用连接配置文件(CCP)
# 执行脚本文件,生成通用连接配置文件,json与yaml文件格式
#./organizations/ccp-generate.sh
}
# 网络启动
function networkUp() {
# Step1 -> 检查文件和版本
checkPrereqs
# Step2 -> 使用cryptogen创建组织加密材料
if [ ! -d "organizations/peerOrganizations" ]; then
createOrgs
fi
COMPOSE_FILES="-f compose/${COMPOSE_FILE_BASE} -f compose/${CONTAINER_CLI}/${CONTAINER_CLI}-${COMPOSE_FILE_BASE}"
if [ "${DATABASE}" == "couchdb" ]; then
COMPOSE_FILES="${COMPOSE_FILES} -f compose/${COMPOSE_FILE_COUCH} -f compose/${CONTAINER_CLI}/${CONTAINER_CLI}-${COMPOSE_FILE_COUCH}"
fi
# Step3 -> docker启动peer、orderer
DOCKER_SOCK="${DOCKER_SOCK}" ${CONTAINER_CLI_COMPOSE} ${COMPOSE_FILES} up -d 2>&1
$CONTAINER_CLI ps -a
if [ $? -ne 0 ]; then
fatalln "Unable to start network"
fi
# Step4 -> 创建通道
createChannel
# Step4 -> 安装链码
./network.sh deployCC -ccn basic -ccp ../chaincode/asset-transfer-basic/chaincode-go -ccl go
}
# Step4 创建通道
function createChannel() {
# 如果网络尚未启动,请启动网络
bringUpNetwork="false"
if ! $CONTAINER_CLI info > /dev/null 2>&1 ; then
fatalln "$CONTAINER_CLI network is required to be running to create a channel"
fi
# 检查是否所有容器是否准备好
CONTAINERS=($($CONTAINER_CLI ps | grep hyperledger/ | awk '{print $2}'))
len=$(echo ${#CONTAINERS[@]})
if [[ $len -ge 8 ]] && [[ ! -d "organizations/peerOrganizations" ]]; then
echo "Bringing network down to sync certs with containers"
networkDown
fi
[[ $len -lt 8 ]] || [[ ! -d "organizations/peerOrganizations" ]] && bringUpNetwork="true" || echo "Network Running Already"
if [ $bringUpNetwork == "true" ]; then
infoln "Bringing up network"
networkUp
fi
# 现在运行创建频道的脚本。此脚本使用configtxgen一次性创建通道创建事务和锚节点对等更新
scripts/createChannel.sh $CHANNEL_NAME $CLI_DELAY $MAX_RETRY $VERBOSE
}
## 调用脚本将链码部署到通道
function deployCC() {
scripts/deployCC.sh $CHANNEL_NAME $CC_NAME $CC_SRC_PATH $CC_SRC_LANGUAGE $CC_VERSION $CC_SEQUENCE $CC_INIT_FCN $CC_END_POLICY $CC_COLL_CONFIG $CLI_DELAY $MAX_RETRY $VERBOSE
if [ $? -ne 0 ]; then
fatalln "Deploying chaincode failed"
fi
}
# 关闭网络
function networkDown() {
COMPOSE_BASE_FILES="-f compose/${COMPOSE_FILE_BASE} -f compose/${CONTAINER_CLI}/${CONTAINER_CLI}-${COMPOSE_FILE_BASE}"
#COMPOSE_COUCH_FILES="-f compose/${COMPOSE_FILE_COUCH} -f compose/${CONTAINER_CLI}/${CONTAINER_CLI}-${COMPOSE_FILE_COUCH}"
#COMPOSE_CA_FILES="-f compose/${COMPOSE_FILE_CA} -f compose/${CONTAINER_CLI}/${CONTAINER_CLI}-${COMPOSE_FILE_CA}"
COMPOSE_FILES="${COMPOSE_BASE_FILES}"
# 关闭docker-compose
if [ "${CONTAINER_CLI}" == "docker" ]; then
DOCKER_SOCK=$DOCKER_SOCK ${CONTAINER_CLI_COMPOSE} ${COMPOSE_FILES} ${COMPOSE_ORG3_FILES} down --volumes --remove-orphans
elif [ "${CONTAINER_CLI}" == "podman" ]; then
${CONTAINER_CLI_COMPOSE} ${COMPOSE_FILES} ${COMPOSE_ORG3_FILES} down --volumes
else
fatalln "Container CLI ${CONTAINER_CLI} not supported"
fi
# Don't remove the generated artifacts -- note, the ledgers are always removed
if [ "$MODE" != "restart" ]; then
# Bring down the network, deleting the volumes
${CONTAINER_CLI} volume rm compose_orderer0.hmw.com compose_orderer1.hmw.com compose_orderer2.hmw.com
${CONTAINER_CLI} volume rm compose_peer0.org1.hmw.com compose_peer1.org1.hmw.com compose_peer0.org2.hmw.com compose_peer1.org2.hmw.com
#Cleanup the chaincode containers
clearContainers
#Cleanup images
removeUnwantedImages
#
${CONTAINER_CLI} kill $(${CONTAINER_CLI} ps -q --filter name=ccaas) || true
# remove orderer block and other channel configuration transactions and certs
# 删除block文件及节点文件
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf system-genesis-block/*.block organizations/peerOrganizations organizations/ordererOrganizations'
## remove fabric ca artifacts
# 删除证书文件
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/org1/msp organizations/fabric-ca/org1/tls-cert.pem organizations/fabric-ca/org1/ca-cert.pem organizations/fabric-ca/org1/IssuerPublicKey organizations/fabric-ca/org1/IssuerRevocationPublicKey organizations/fabric-ca/org1/fabric-ca-server.db'
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/org2/msp organizations/fabric-ca/org2/tls-cert.pem organizations/fabric-ca/org2/ca-cert.pem organizations/fabric-ca/org2/IssuerPublicKey organizations/fabric-ca/org2/IssuerRevocationPublicKey organizations/fabric-ca/org2/fabric-ca-server.db'
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/ordererOrg/msp organizations/fabric-ca/ordererOrg/tls-cert.pem organizations/fabric-ca/ordererOrg/ca-cert.pem organizations/fabric-ca/ordererOrg/IssuerPublicKey organizations/fabric-ca/ordererOrg/IssuerRevocationPublicKey organizations/fabric-ca/ordererOrg/fabric-ca-server.db'
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf addOrg3/fabric-ca/org3/msp addOrg3/fabric-ca/org3/tls-cert.pem addOrg3/fabric-ca/org3/ca-cert.pem addOrg3/fabric-ca/org3/IssuerPublicKey addOrg3/fabric-ca/org3/IssuerRevocationPublicKey addOrg3/fabric-ca/org3/fabric-ca-server.db'
# remove channel and script artifacts
# 删除链码包文件
${CONTAINER_CLI} run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf channel-artifacts log.txt *.tar.gz'
fi
}
# Obtain CONTAINER_IDS and remove them
# This function is called when you bring a network down
# 函数 - 清除docker容器
function clearContainers() {
# infoln函数为utils.sh脚本文件中的函数,输出信息
infoln "Removing remaining containers"
# 删除容器服务包含hyperledger-fabric的容器
${CONTAINER_CLI} rm -f $(${CONTAINER_CLI} ps -aq --filter label=service=hyperledger-fabric) 2>/dev/null || true
# 删除容器名中以dev-peer开头的容器(链码)
${CONTAINER_CLI} rm -f $(${CONTAINER_CLI} ps -aq --filter name='dev-peer*') 2>/dev/null || true
}
# Delete any images that were generated as a part of this setup
# specifically the following images are often left behind:
# This function is called when you bring the network down
# 函数 - 清除docker镜像
function removeUnwantedImages() {
infoln "Removing generated chaincode docker images"
# 删除满足条件的镜像(引用以dev-peer开头的镜像)
${CONTAINER_CLI} image rm -f $(${CONTAINER_CLI} images -aq --filter reference='dev-peer*') 2>/dev/null || true
}
# Using crpto vs CA. default is cryptogen
CRYPTO="cryptogen"
# timeout duration - the duration the CLI should wait for a response from
# another container before giving up
MAX_RETRY=5
# default for delay between commands
CLI_DELAY=3
# channel name defaults to "mychannel"
CHANNEL_NAME="mychannel"
# chaincode name defaults to "NA"
CC_NAME="NA"
# chaincode path defaults to "NA"
CC_SRC_PATH="NA"
# endorsement policy defaults to "NA". This would allow chaincodes to use the majority default policy.
CC_END_POLICY="NA"
# collection configuration defaults to "NA"
CC_COLL_CONFIG="NA"
# chaincode init function defaults to "NA"
CC_INIT_FCN="InitLedger"
# use this as the default docker-compose yaml definition
COMPOSE_FILE_BASE=compose-test-net.yaml
# docker-compose.yaml file if you are using couchdb
COMPOSE_FILE_COUCH=compose-couch.yaml
# certificate authorities compose file
COMPOSE_FILE_CA=compose-ca.yaml
# use this as the default docker-compose yaml definition for org3
COMPOSE_FILE_ORG3_BASE=compose-org3.yaml
# use this as the docker compose couch file for org3
COMPOSE_FILE_ORG3_COUCH=compose-couch-org3.yaml
# certificate authorities compose file
COMPOSE_FILE_ORG3_CA=compose-ca-org3.yaml
#
# chaincode language defaults to "NA"
CC_SRC_LANGUAGE="NA"
# default to running the docker commands for the CCAAS
CCAAS_DOCKER_RUN=true
# Chaincode version
CC_VERSION="1.0"
# Chaincode definition sequence
CC_SEQUENCE=1
# default database
DATABASE="leveldb"
# Get docker sock path from environment variable
SOCK="${DOCKER_HOST:-/var/run/docker.sock}"
DOCKER_SOCK="${SOCK##unix://}"
# Parse commandline args
## Parse mode
if [[ $# -lt 1 ]] ; then
printHelp
exit 0
else
MODE=$1
shift
fi
# parse a createChannel subcommand if used
if [[ $# -ge 1 ]] ; then
key="$1"
if [[ "$key" == "createChannel" ]]; then
export MODE="createChannel"
shift
fi
fi
# parse flags
while [[ $# -ge 1 ]] ; do
key="$1"
case $key in
-h )
printHelp $MODE
exit 0
;;
-c )
CHANNEL_NAME="$2"
shift
;;
-ca )
CRYPTO="Certificate Authorities"
;;
-r )
MAX_RETRY="$2"
shift
;;
-d )
CLI_DELAY="$2"
shift
;;
-s )
DATABASE="$2"
shift
;;
-ccl )
CC_SRC_LANGUAGE="$2"
shift
;;
-ccn )
CC_NAME="$2"
shift
;;
-ccv )
CC_VERSION="$2"
shift
;;
-ccs )
CC_SEQUENCE="$2"
shift
;;
-ccp )
CC_SRC_PATH="$2"
shift
;;
-ccep )
CC_END_POLICY="$2"
shift
;;
-cccg )
CC_COLL_CONFIG="$2"
shift
;;
-cci )
CC_INIT_FCN="$2"
shift
;;
-ccaasdocker )
CCAAS_DOCKER_RUN="$2"
shift
;;
-verbose )
VERBOSE=true
;;
* )
errorln "Unknown flag: $key"
printHelp
exit 1
;;
esac
shift
done
# Are we generating crypto material with this command?
if [ ! -d "organizations/peerOrganizations" ]; then
CRYPTO_MODE="with crypto from '${CRYPTO}'"
else
CRYPTO_MODE=""
fi
# Determine mode of operation and printing out what we asked for
if [ "$MODE" == "up" ]; then
infoln "Starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE}' ${CRYPTO_MODE}"
networkUp
elif [ "$MODE" == "createChannel" ]; then
infoln "Creating channel '${CHANNEL_NAME}'."
infoln "If network is not up, starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE} ${CRYPTO_MODE}"
createChannel
elif [ "$MODE" == "down" ]; then
infoln "Stopping network"
networkDown
elif [ "$MODE" == "restart" ]; then
infoln "Restarting network"
networkDown
networkUp
elif [ "$MODE" == "deployCC" ]; then
infoln "deploying chaincode on channel '${CHANNEL_NAME}'"
deployCC
elif [ "$MODE" == "deployCCAAS" ]; then
infoln "deploying chaincode-as-a-service on channel '${CHANNEL_NAME}'"
deployCCAAS
else
printHelp
exit 1
fi
二、utils.sh
#!/bin/bash
C_RESET='\033[0m'
C_RED='\033[0;31m'
C_GREEN='\033[0;32m'
C_BLUE='\033[0;34m'
C_YELLOW='\033[1;33m'
# Print the usage message
function printHelp() {
USAGE="$1"
if [ "$USAGE" == "up" ]; then
println "Usage: "
println " network.sh \033[0;32mup\033[0m [Flags]"
println
println " Flags:"
println " -ca <use CAs> - Use Certificate Authorities to generate network crypto material"
println " -c <channel name> - Name of channel to create (defaults to \"mychannel\")"
println " -s <dbtype> - Peer state database to deploy: goleveldb (default) or couchdb"
println " -r <max retry> - CLI times out after certain number of attempts (defaults to 5)"
println " -d <delay> - CLI delays for a certain number of seconds (defaults to 3)"
println " -verbose - Verbose mode"
println
println " -h - Print this message"
println
println " Possible Mode and flag combinations"
println " \033[0;32mup\033[0m -ca -r -d -s -verbose"
println " \033[0;32mup createChannel\033[0m -ca -c -r -d -s -verbose"
println
println " Examples:"
println " network.sh up createChannel -ca -c mychannel -s couchdb "
elif [ "$USAGE" == "createChannel" ]; then
println "Usage: "
println " network.sh \033[0;32mcreateChannel\033[0m [Flags]"
println
println " Flags:"
println " -c <channel name> - Name of channel to create (defaults to \"mychannel\")"
println " -r <max retry> - CLI times out after certain number of attempts (defaults to 5)"
println " -d <delay> - CLI delays for a certain number of seconds (defaults to 3)"
println " -verbose - Verbose mode"
println
println " -h - Print this message"
println
println " Possible Mode and flag combinations"
println " \033[0;32mcreateChannel\033[0m -c -r -d -verbose"
println
println " Examples:"
println " network.sh createChannel -c channelName"
elif [ "$USAGE" == "deployCC" ]; then
println "Usage: "
println " network.sh \033[0;32mdeployCC\033[0m [Flags]"
println
println " Flags:"
println " -c <channel name> - Name of channel to deploy chaincode to"
println " -ccn <name> - Chaincode name."
println " -ccl <language> - Programming language of chaincode to deploy: go, java, javascript, typescript"
println " -ccv <version> - Chaincode version. 1.0 (default), v2, version3.x, etc"
println " -ccs <sequence> - Chaincode definition sequence. Must be an integer, 1 (default), 2, 3, etc"
println " -ccp <path> - File path to the chaincode."
println " -ccep <policy> - (Optional) Chaincode endorsement policy using signature policy syntax. The default policy requires an endorsement from Org1 and Org2"
println " -cccg <collection-config> - (Optional) File path to private data collections configuration file"
println " -cci <fcn name> - (Optional) Name of chaincode initialization function. When a function is provided, the execution of init will be requested and the function will be invoked."
println
println " -h - Print this message"
println
println " Possible Mode and flag combinations"
println " \033[0;32mdeployCC\033[0m -ccn -ccl -ccv -ccs -ccp -cci -r -d -verbose"
println
println " Examples:"
println " network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ ./ -ccl javascript"
println " network.sh deployCC -ccn mychaincode -ccp ./user/mychaincode -ccv 1 -ccl javascript"
elif [ "$USAGE" == "deployCCAAS" ]; then
println "Usage: "
println " network.sh \033[0;32mdeployCCAAS\033[0m [Flags]"
println
println " Flags:"
println " -c <channel name> - Name of channel to deploy chaincode to"
println " -ccn <name> - Chaincode name."
println " -ccv <version> - Chaincode version. 1.0 (default), v2, version3.x, etc"
println " -ccs <sequence> - Chaincode definition sequence. Must be an integer, 1 (default), 2, 3, etc"
println " -ccp <path> - File path to the chaincode. (used to find the dockerfile for building the docker image only)"
println " -ccep <policy> - (Optional) Chaincode endorsement policy using signature policy syntax. The default policy requires an endorsement from Org1 and Org2"
println " -cccg <collection-config> - (Optional) File path to private data collections configuration file"
println " -cci <fcn name> - (Optional) Name of chaincode initialization function. When a function is provided, the execution of init will be requested and the function will be invoked."
println " -ccaasdocker <true|false> - (Optional) Default is true; the chaincode docker image will be built and containers started automatically. Set to false to control this manually"
println
println " -h - Print this message"
println
println " Possible Mode and flag combinations"
println " \033[0;32mdeployCC\033[0m -ccn -ccv -ccs -ccp -cci -r -d -verbose"
println
println " Examples:"
println " network.sh deployCCAAS -ccn basicj -ccp ../asset-transfer-basic/chaincode-java"
println " network.sh deployCCAAS -ccn basict -ccp ../asset-transfer-basic/chaincode-typescript -ccaasdocker false"
else
println "Usage: "
println " network.sh <Mode> [Flags]"
println " Modes:"
println " \033[0;32mup\033[0m - Bring up Fabric orderer and peer nodes. No channel is created"
println " \033[0;32mup createChannel\033[0m - Bring up fabric network with one channel"
println " \033[0;32mcreateChannel\033[0m - Create and join a channel after the network is created"
println " \033[0;32mdeployCC\033[0m - Deploy a chaincode to a channel (defaults to asset-transfer-basic)"
println " \033[0;32mdown\033[0m - Bring down the network"
println
println " Flags:"
println " Used with \033[0;32mnetwork.sh up\033[0m, \033[0;32mnetwork.sh createChannel\033[0m:"
println " -ca <use CAs> - Use Certificate Authorities to generate network crypto material"
println " -c <channel name> - Name of channel to create (defaults to \"mychannel\")"
println " -s <dbtype> - Peer state database to deploy: goleveldb (default) or couchdb"
println " -r <max retry> - CLI times out after certain number of attempts (defaults to 5)"
println " -d <delay> - CLI delays for a certain number of seconds (defaults to 3)"
println " -verbose - Verbose mode"
println
println " Used with \033[0;32mnetwork.sh deployCC\033[0m"
println " -c <channel name> - Name of channel to deploy chaincode to"
println " -ccn <name> - Chaincode name."
println " -ccl <language> - Programming language of the chaincode to deploy: go, java, javascript, typescript"
println " -ccv <version> - Chaincode version. 1.0 (default), v2, version3.x, etc"
println " -ccs <sequence> - Chaincode definition sequence. Must be an integer, 1 (default), 2, 3, etc"
println " -ccp <path> - File path to the chaincode."
println " -ccep <policy> - (Optional) Chaincode endorsement policy using signature policy syntax. The default policy requires an endorsement from Org1 and Org2"
println " -cccg <collection-config> - (Optional) File path to private data collections configuration file"
println " -cci <fcn name> - (Optional) Name of chaincode initialization function. When a function is provided, the execution of init will be requested and the function will be invoked."
println
println " -h - Print this message"
println
println " Possible Mode and flag combinations"
println " \033[0;32mup\033[0m -ca -r -d -s -verbose"
println " \033[0;32mup createChannel\033[0m -ca -c -r -d -s -verbose"
println " \033[0;32mcreateChannel\033[0m -c -r -d -verbose"
println " \033[0;32mdeployCC\033[0m -ccn -ccl -ccv -ccs -ccp -cci -r -d -verbose"
println
println " Examples:"
println " network.sh up createChannel -ca -c mychannel -s couchdb"
println " network.sh createChannel -c channelName"
println " network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript"
println " network.sh deployCC -ccn mychaincode -ccp ./user/mychaincode -ccv 1 -ccl javascript"
fi
}
# println echos string
function println() {
echo -e "$1"
}
# errorln echos i red color
function errorln() {
println "${C_RED}${1}${C_RESET}"
}
# successln echos in green color
function successln() {
println "${C_GREEN}${1}${C_RESET}"
}
# infoln echos in blue color
function infoln() {
println "${C_BLUE}${1}${C_RESET}"
}
# warnln echos in yellow color
function warnln() {
println "${C_YELLOW}${1}${C_RESET}"
}
# fatalln echos in red color and exits with fail status
function fatalln() {
errorln "$1"
exit 1
}
export -f errorln
export -f successln
export -f infoln
export -f warnln
三、envVar.sh
#!/bin/bash
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# This is a collection of bash functions used by different scripts
# imports
. scripts/utils.sh
export CORE_PEER_TLS_ENABLED=true
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/hmw.com/tlsca/tlsca.hmw.com-cert.pem
export PEER0_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.hmw.com/tlsca/tlsca.org1.hmw.com-cert.pem
export PEER1_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.hmw.com/tlsca/tlsca.org1.hmw.com-cert.pem
export PEER0_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.hmw.com/tlsca/tlsca.org2.hmw.com-cert.pem
export PEER1_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.hmw.com/tlsca/tlsca.org2.hmw.com-cert.pem
export PEER0_ORG3_CA=${PWD}/organizations/peerOrganizations/org3.hmw.com/tlsca/tlsca.org3.hmw.com-cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer0.hmw.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer0.hmw.com/tls/server.key
export ORDERER1_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer1.hmw.com/tls/server.crt
export ORDERER1_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer1.hmw.com/tls/server.key
export ORDERER2_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer2.hmw.com/tls/server.crt
export ORDERER2_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/hmw.com/orderers/orderer2.hmw.com/tls/server.key
# Set environment variables for the peer org
setGlobals() {
local USING_ORG=""
if [ -z "$OVERRIDE_ORG" ]; then
USING_ORG=$1
else
USING_ORG="${OVERRIDE_ORG}"
fi
infoln "Using organization ${USING_ORG}"
if [ $USING_ORG -eq 01 ]; then
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.hmw.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:8051
elif [ $USING_ORG -eq 11 ]; then
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER1_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.hmw.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:8053
elif [ $USING_ORG -eq 02 ]; then
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.hmw.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:8055
elif [ $USING_ORG -eq 12 ]; then
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER1_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.hmw.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:8057
elif [ $USING_ORG -eq 03 ]; then
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG3_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.hmw.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:11051
else
errorln "ORG Unknown"
fi
if [ "$VERBOSE" == "true" ]; then
env | grep CORE
fi
}
# Set environment variables for use in the CLI container
setGlobalsCLI() {
setGlobals $1
local USING_ORG=""
if [ -z "$OVERRIDE_ORG" ]; then
USING_ORG=$1
else
USING_ORG="${OVERRIDE_ORG}"
fi
if [ $USING_ORG -eq 01 ]; then
export CORE_PEER_ADDRESS=peer0.org1.hmw.com:8051
elif [ $USING_ORG -eq 11 ]; then
export CORE_PEER_ADDRESS=peer1.org1.hmw.com:8053
elif [ $USING_ORG -eq 02 ]; then
export CORE_PEER_ADDRESS=peer0.org2.hmw.com:8055
elif [ $USING_ORG -eq 12 ]; then
export CORE_PEER_ADDRESS=peer1.org2.hmw.com:8057
elif [ $USING_ORG -eq 3 ]; then
export CORE_PEER_ADDRESS=peer0.org3.hmw.com:11051
else
errorln "ORG Unknown"
fi
}
# parsePeerConnectionParameters $@
# Helper function that sets the peer connection parameters for a chaincode
# operation
parsePeerConnectionParameters() {
PEER_CONN_PARMS=()
PEERS=""
while [ "$#" -gt 0 ]; do
setGlobals $1
USING_ORG=$1
if [ $USING_ORG -eq 01 ]; then
PEER="peer0.org1"
elif [ $USING_ORG -eq 11 ]; then
PEER="peer1.org1"
elif [ $USING_ORG -eq 02 ]; then
PEER="peer0.org2"
elif [ $USING_ORG -eq 12 ]; then
PEER="peer1.org2"
else
errorln "ORG Unknown"
fi
## Set peer addresses
if [ -z "$PEERS" ]
then
PEERS="$PEER"
else
PEERS="$PEERS $PEER"
fi
PEER_CONN_PARMS=("${PEER_CONN_PARMS[@]}" --peerAddresses $CORE_PEER_ADDRESS)
## Set path to TLS certificate
CA=PEER0_ORG$1_CA
TLSINFO=(--tlsRootCertFiles "${!CA}")
PEER_CONN_PARMS=("${PEER_CONN_PARMS[@]}" "${TLSINFO[@]}")
# shift by one to get to the next organization
shift
done
}
verifyResult() {
if [ $1 -ne 0 ]; then
fatalln "$2"
fi
}
四、CreateChannel.sh
#!/bin/bash
# imports 导入包
# envVar.sh脚本包含节点证书的环境变量,验证执行命令结果函数verifyResult、切换组织环境变量函数setGlobals等
. scripts/envVar.sh
# utils.sh脚本为打印输出信息功能,network.sh脚本调用了utils.sh脚本中的相关函数,如infoln、fatalln等函数
. scripts/utils.sh
CHANNEL_NAME="$1"
DELAY="$2"
MAX_RETRY="$3"
VERBOSE="$4"
: ${CHANNEL_NAME:="mychannel"}
: ${DELAY:="3"}
: ${MAX_RETRY:="5"}
: ${VERBOSE:="false"}
: ${CONTAINER_CLI:="docker"}
: ${CONTAINER_CLI_COMPOSE:="${CONTAINER_CLI}-compose"}
infoln "Using ${CONTAINER_CLI} and ${CONTAINER_CLI_COMPOSE}"
# 若不存在目录channel-artifacts,则创建
if [ ! -d "channel-artifacts" ]; then
mkdir channel-artifacts
fi
# 函数 - 创建通道创世区块
createChannelGenesisBlock() {
# 搜索configtxgen命令,判断是否存在此二进制文件,若不存在,打印错误信息,程序终止
which configtxgen
if [ "$?" -ne 0 ]; then
fatalln "configtxgen tool not found."
fi
set -x #脚本调试,会将下面执行的命令输出到屏幕上
# 创建创世区块:生成创世区块mychannel.block文件,根据配置文件../configtx/configtx.yaml来创建Orderer系统通道的创世块
configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/${CHANNEL_NAME}.block -channelID $CHANNEL_NAME
res=$?
{ set +x; } 2>/dev/null
verifyResult $res "Failed to generate channel configuration transaction..."
}
# 函数 - 激活通道
createChannel() {
# 调用脚本 envVar.sh中的函数setGlobals,为org1或org2的peer节点设置环境变量,参数01对应的是org1,02对应org2
# 设置环境变量为org1
setGlobals 01
# Poll in case the raft leader is not set yet
local rc=1
local COUNTER=1
# 创建通道若未成功,可尝试5次
while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ] ; do
sleep $DELAY
set -x
# 创建通道,将执行结果信息记录到log.txt文件中
infoln "Orderer0 join channel"
osnadmin channel join --channelID $CHANNEL_NAME --config-block ./channel-artifacts/${CHANNEL_NAME}.block -o localhost:7051 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY" >&log.txt
infoln "Orderer1 join channel"
osnadmin channel join --channelID $CHANNEL_NAME --config-block ./channel-artifacts/${CHANNEL_NAME}.block -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER1_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER1_ADMIN_TLS_PRIVATE_KEY" >&log.txt
infoln "Orderer2 join channel"
osnadmin channel join --channelID $CHANNEL_NAME --config-block ./channel-artifacts/${CHANNEL_NAME}.block -o localhost:7055 --ca-file "$ORDERER_CA" --client-cert "$ORDERER2_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER2_ADMIN_TLS_PRIVATE_KEY" >&log.txt
res=$?
{ set +x; } 2>/dev/null
let rc=$res
COUNTER=$(expr $COUNTER + 1)
done
# 打印log.txt,即打印创建通道结果信息
cat log.txt
# 调用脚本 envVar.sh 中的函数verifyResult,用来验证上面执行的命令是否报错,如果报错,则打印错误信息,程序终止
verifyResult $res "Channel creation failed"
}
# joinChannel ORG
joinChannel() {
FABRIC_CFG_PATH=${PWD}/config/
ORG=$1
# 根据传递的参数设置环境变量,切换组织使用
setGlobals $ORG
local rc=1
local COUNTER=1
# peer节点加入通道若未成功,可尝试5次
while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ] ; do
sleep $DELAY
set -x
# 将节点加入通道,将执行结果信息记录到log.txt文件中
peer channel join -b $BLOCKFILE >&log.txt
res=$?
{ set +x; } 2>/dev/null
let rc=$res
COUNTER=$(expr $COUNTER + 1)
done
cat log.txt
verifyResult $res "After $MAX_RETRY attempts, peer0.org${ORG} has failed to join channel '$CHANNEL_NAME' "
}
# 函数 - 设置锚节点
setAnchorPeer() {
ORG=$1
${CONTAINER_CLI} exec cli ./scripts/setAnchorPeer.sh $ORG $CHANNEL_NAME
}
FABRIC_CFG_PATH=${PWD}/configtx
## Create channel genesis block
infoln "Generating channel genesis block '${CHANNEL_NAME}.block'"
createChannelGenesisBlock
FABRIC_CFG_PATH=${PWD}/config/
BLOCKFILE="./channel-artifacts/${CHANNEL_NAME}.block"
## Create channel
infoln "Creating channel ${CHANNEL_NAME}"
createChannel
successln "Channel '$CHANNEL_NAME' created"
## Join all the peers to the channel
infoln "Joining peer0-org1 to the channel..."
joinChannel 01
infoln "Joining peer1-org1 to the channel..."
joinChannel 11
infoln "Joining peer0-org2 to the channel..."
joinChannel 02
infoln "Joining peer1-org2 to the channel..."
joinChannel 12
## Set the anchor peers for each org in the channel
infoln "Setting anchor peer for org1..."
setAnchorPeer 01
infoln "Setting anchor peer for org2..."
setAnchorPeer 02
successln "Channel '$CHANNEL_NAME' joined"
五、setAnchorPeer.sh
#!/bin/bash
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
# import utils
. scripts/envVar.sh
. scripts/configUpdate.sh
# NOTE: this must be run in a CLI container since it requires jq and configtxlator
createAnchorPeerUpdate() {
infoln "Fetching channel config for channel $CHANNEL_NAME"
# 获取节点
# fetchChannelConfig 01 mychannel Org1MSPconfig.json
fetchChannelConfig $ORG $CHANNEL_NAME ${CORE_PEER_LOCALMSPID}config.json
infoln "Generating anchor peer update transaction for Org${ORG} on channel $CHANNEL_NAME"
if [ $ORG -eq 01 ]; then
HOST="peer0.org1.hmw.com"
PORT=8051
elif [ $ORG -eq 11 ]; then
HOST="peer1.org1.hmw.com"
PORT=8053
elif [ $ORG -eq 02 ]; then
HOST="peer0.org2.hmw.com"
PORT=8055
elif [ $ORG -eq 12 ]; then
HOST="peer1.org2.hmw.com"
PORT=8057
elif [ $ORG -eq 3 ]; then
HOST="peer0.org3.hmw.com"
PORT=11051
else
errorln "Org${ORG} unknown"
fi
set -x
# Modify the configuration to append the anchor peer
# 将锚节点添加至配置文件中
jq '.channel_group.groups.Application.groups.'${CORE_PEER_LOCALMSPID}'.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "'$HOST'","port": '$PORT'}]},"version": "0"}}' ${CORE_PEER_LOCALMSPID}config.json > ${CORE_PEER_LOCALMSPID}modified_config.json
{ set +x; } 2>/dev/null
# Compute a config update, based on the differences between
# {orgmsp}config.json and {orgmsp}modified_config.json, write
# it as a transaction to {orgmsp}anchors.tx
createConfigUpdate ${CHANNEL_NAME} ${CORE_PEER_LOCALMSPID}config.json ${CORE_PEER_LOCALMSPID}modified_config.json ${CORE_PEER_LOCALMSPID}anchors.tx
}
# 函数 - 添加Peer锚节点
updateAnchorPeer() {
peer channel update -o orderer0.hmw.com:7050 --ordererTLSHostnameOverride orderer0.hmw.com -c $CHANNEL_NAME -f ${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile "$ORDERER_CA" >&log.txt
res=$?
cat log.txt
verifyResult $res "Anchor peer update failed"
successln "Anchor peer set for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME'"
}
ORG=$1
CHANNEL_NAME=$2
setGlobalsCLI $ORG
createAnchorPeerUpdate
updateAnchorPeer
六、configUpdate.sh
#!/bin/bash
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
# import utils
. scripts/envVar.sh
# fetchChannelConfig <org> <channel_id> <output_json>
# Writes the current channel config for a given channel to a JSON file
# NOTE: this must be run in a CLI container since it requires configtxlator
fetchChannelConfig() {
ORG=$1
CHANNEL=$2
OUTPUT=$3
setGlobals $ORG
infoln "Fetching the most recent configuration block for the channel"
set -x
# 获取通道配置
peer channel fetch config config_block.pb -o orderer0.hmw.com:7050 --ordererTLSHostnameOverride orderer0.hmw.com -c $CHANNEL --tls --cafile "$ORDERER_CA"
{ set +x; } 2>/dev/null
res=$?
if [ $res -ne 0 ]; then
fatalln "Failed to fetch the most recent configuration block..."
fi
infoln "Decoding config block to JSON and isolating config to ${OUTPUT}"
set -x
# 将配置块protobuf格式转成json格式
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq .data.data[0].payload.data.config config_block.json >"${OUTPUT}"
{ set +x; } 2>/dev/null
}
# 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
# NOTE: this must be run in a CLI container since it requires configtxlator
createConfigUpdate() {
CHANNEL=$1
ORIGINAL=$2
MODIFIED=$3
OUTPUT=$4
set -x
# 将原始和修改的通道配置都转换回protobuf格式,并计算它们之间的差异
configtxlator proto_encode --input "${ORIGINAL}" --type common.Config --output original_config.pb
configtxlator proto_encode --input "${MODIFIED}" --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id "${CHANNEL}" --original original_config.pb --updated modified_config.pb --output config_update.pb
# 将配置更新包装在交易Envelope中,以创建通道配置更新交易
configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output 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 "${OUTPUT}"
{ set +x; } 2>/dev/null
}
# signConfigtxAsPeerOrg <org> <configtx.pb>
# Set the peerOrg admin of an org and sign the config update
signConfigtxAsPeerOrg() {
ORG=$1
CONFIGTXFILE=$2
setGlobals $ORG
set -x
peer channel signconfigtx -f "${CONFIGTXFILE}"
{ set +x; } 2>/dev/null
}
七、deployCC.sh
#!/bin/bash
source scripts/utils.sh
CHANNEL_NAME=${1:-"mychannel"} # 通道名称,默认mychannel
CC_NAME=${2} # 链码名称
CC_SRC_PATH=${3} # 智能合约代码所在的目录
CC_SRC_LANGUAGE=${4} # 智能合约语言(当前支持Go、Java、Javascript、Typescript)
CC_VERSION=${5:-"1.0"} # 链码版本,默认1.0
CC_SEQUENCE=${6:-"1"} # 链码被定义或者更新多少次的指数
CC_INIT_FCN=${7:-"NA"} # 链码初始化调用的函数名
CC_END_POLICY=${8:-"NA"} # 背书策略
CC_COLL_CONFIG=${9:-"NA"} #config路径
DELAY=${10:-"3"} # 延迟执行时间(单位:秒)
MAX_RETRY=${11:-"5"} # 尝试最多失败次数
VERBOSE=${12:-"false"}
println "executing with the following"
println "- CHANNEL_NAME: ${C_GREEN}${CHANNEL_NAME}${C_RESET}"
println "- CC_NAME: ${C_GREEN}${CC_NAME}${C_RESET}"
println "- CC_SRC_PATH: ${C_GREEN}${CC_SRC_PATH}${C_RESET}"
println "- CC_SRC_LANGUAGE: ${C_GREEN}${CC_SRC_LANGUAGE}${C_RESET}"
println "- CC_VERSION: ${C_GREEN}${CC_VERSION}${C_RESET}"
println "- CC_SEQUENCE: ${C_GREEN}${CC_SEQUENCE}${C_RESET}"
println "- CC_END_POLICY: ${C_GREEN}${CC_END_POLICY}${C_RESET}"
println "- CC_COLL_CONFIG: ${C_GREEN}${CC_COLL_CONFIG}${C_RESET}"
println "- CC_INIT_FCN: ${C_GREEN}${CC_INIT_FCN}${C_RESET}"
println "- DELAY: ${C_GREEN}${DELAY}${C_RESET}"
println "- MAX_RETRY: ${C_GREEN}${MAX_RETRY}${C_RESET}"
println "- VERBOSE: ${C_GREEN}${VERBOSE}${C_RESET}"
FABRIC_CFG_PATH=$PWD/config/
# User has not provided a name
# 用户尚未提供链码名称
if [ -z "$CC_NAME" ] || [ "$CC_NAME" = "NA" ]; then
fatalln "No chaincode name was provided. Valid call example: ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go"
# User has not provided a path
# 用户尚未提供链码路径
elif [ -z "$CC_SRC_PATH" ] || [ "$CC_SRC_PATH" = "NA" ]; then
fatalln "No chaincode path was provided. Valid call example: ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go"
# User has not provided a language
# 用户尚未提供链码语言
elif [ -z "$CC_SRC_LANGUAGE" ] || [ "$CC_SRC_LANGUAGE" = "NA" ]; then
fatalln "No chaincode language was provided. Valid call example: ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go"
# Make sure that the path to the chaincode exists
# 确保链码的路径存在
elif [ ! -d "$CC_SRC_PATH" ] && [ ! -f "$CC_SRC_PATH" ]; then
fatalln "Path to chaincode does not exist. Please provide different path."
fi
CC_SRC_LANGUAGE=$(echo "$CC_SRC_LANGUAGE" | tr [:upper:] [:lower:])
# do some language specific preparation to the chaincode before packaging
# 在打包之前,对链码做一些特定于语言的准备
# 智能合约 -- go
if [ "$CC_SRC_LANGUAGE" = "go" ]; then
CC_RUNTIME_LANGUAGE=golang
infoln "Vendoring Go dependencies at $CC_SRC_PATH"
# 将链码目录加入到栈中,并切换到该目录(执行cd 目录)
pushd $CC_SRC_PATH
GO111MODULE=on go mod vendor
# 删除栈顶记录,切换到删除后的目录栈中的栈顶目录
popd
successln "Finished vendoring Go dependencies"
# 智能合约 -- java
elif [ "$CC_SRC_LANGUAGE" = "java" ]; then
CC_RUNTIME_LANGUAGE=java
rm -rf $CC_SRC_PATH/build/install/
infoln "Compiling Java code..."
pushd $CC_SRC_PATH
./gradlew installDist
popd
successln "Finished compiling Java code"
CC_SRC_PATH=$CC_SRC_PATH/build/install/$CC_NAME
# 智能合约 -- javascript
elif [ "$CC_SRC_LANGUAGE" = "javascript" ]; then
CC_RUNTIME_LANGUAGE=node
# 智能合约 -- javascript
elif [ "$CC_SRC_LANGUAGE" = "typescript" ]; then
CC_RUNTIME_LANGUAGE=node
infoln "Compiling TypeScript code into JavaScript..."
pushd $CC_SRC_PATH
npm install
npm run build
popd
successln "Finished compiling TypeScript code into JavaScript"
else
fatalln "The chaincode language ${CC_SRC_LANGUAGE} is not supported by this script. Supported chaincode languages are: go, java, javascript, and typescript"
exit 1
fi
INIT_REQUIRED="--init-required"
# check if the init fcn should be called
# 检查是否应调用init fcn
if [ "$CC_INIT_FCN" = "NA" ]; then
INIT_REQUIRED=""
fi
if [ "$CC_END_POLICY" = "NA" ]; then
CC_END_POLICY=""
else
CC_END_POLICY="--signature-policy $CC_END_POLICY"
fi
if [ "$CC_COLL_CONFIG" = "NA" ]; then
CC_COLL_CONFIG=""
else
CC_COLL_CONFIG="--collections-config $CC_COLL_CONFIG"
fi
# import utils
. scripts/envVar.sh
. scripts/ccutils.sh
# 函数 -- 打包链码
packageChaincode() {
set -x
peer lifecycle chaincode package ${CC_NAME}.tar.gz --path ${CC_SRC_PATH} --lang ${CC_RUNTIME_LANGUAGE} --label ${CC_NAME}_${CC_VERSION} >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
verifyResult $res "Chaincode packaging has failed"
successln "Chaincode is packaged"
}
## 打包链码
packageChaincode
## Install chaincode on peer0.org1 and peer0.org2
## 安装链码
infoln "Installing chaincode on peer0.org1..."
installChaincode 01
infoln "Installing chaincode on peer1.org1..."
installChaincode 11
infoln "Install chaincode on peer0.org2..."
installChaincode 02
infoln "Install chaincode on peer1.org2..."
installChaincode 12
## query whether the chaincode is installed
## 查询是否安装链码
queryInstalled 01
queryInstalled 11
queryInstalled 02
queryInstalled 12
## approve the definition for org1
## Org1批准链码定义
approveForMyOrg 01
## check whether the chaincode definition is ready to be committed
## expect org1 to have approved and org2 not to
## 检查链码定义是否已准备好提交,org1已批准,org2未批准
checkCommitReadiness 01 "\"Org1MSP\": true" "\"Org2MSP\": false"
checkCommitReadiness 02 "\"Org1MSP\": true" "\"Org2MSP\": false"
## now approve also for org2
## Org2批准链码定义
approveForMyOrg 02
## check whether the chaincode definition is ready to be committed
## expect them both to have approved
## 检查链码定义是否已准备好提交,两个组织都已批准
checkCommitReadiness 01 "\"Org1MSP\": true" "\"Org2MSP\": true"
checkCommitReadiness 02 "\"Org1MSP\": true" "\"Org2MSP\": true"
## now that we know for sure both orgs have approved, commit the definition
## 既然已经确定了两个组织都批准,那就提交链码定义
commitChaincodeDefinition 01 02
## query on both orgs to see that the definition committed successfully
## 查询两个组织以查看定义是否已成功提交
queryCommitted 01
queryCommitted 02
## Invoke the chaincode - this does require that the chaincode have the 'initLedger'
## method defined
## 调用链码初始化函数
if [ "$CC_INIT_FCN" = "NA" ]; then
infoln "Chaincode initialization is not required"
else
chaincodeInvokeInit 01 02
fi
exit 0
八、ccutils.sh
#!/bin/bash
# 函数 - 安装链码
function installChaincode() {
ORG=$1
setGlobals $ORG
set -x
peer lifecycle chaincode install ${CC_NAME}.tar.gz >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
verifyResult $res "Chaincode installation on peer0.org${ORG} has failed"
successln "Chaincode is installed on peer0.org${ORG}"
}
# 函数 - 查看已安装的链码
function queryInstalled() {
ORG=$1
setGlobals $ORG
set -x
peer lifecycle chaincode queryinstalled >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
# 打印输出链码包ID
PACKAGE_ID=$(sed -n "/${CC_NAME}_${CC_VERSION}/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt)
verifyResult $res "Query installed on peer0.org${ORG} has failed"
successln "Query installed successful on peer0.org${ORG} on channel"
}
# 函数 - 组织身份批准智能合约 (每个组织都需要审批,但不是每个节点)
function approveForMyOrg() {
ORG=$1
setGlobals $ORG
set -x
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer0.hmw.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
verifyResult $res "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME' failed"
successln "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME'"
}
# 函数 - 检查链码包是否准备提交至通道中
function checkCommitReadiness() {
ORG=$1
shift 1
setGlobals $ORG
infoln "Checking the commit readiness of the chaincode definition on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
local rc=1
local COUNTER=1
# continue to poll
# we either get a successful response, or reach MAX RETRY
while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
sleep $DELAY
infoln "Attempting to check the commit readiness of the chaincode definition on peer0.org${ORG}, Retry after $DELAY seconds."
set -x
# 检查链码包是否准备提交至通道中
peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} --output json >&log.txt
res=$?
{ set +x; } 2>/dev/null
let rc=0
for var in "$@"; do
grep "$var" log.txt &>/dev/null || let rc=1
done
COUNTER=$(expr $COUNTER + 1)
done
cat log.txt
if test $rc -eq 0; then
infoln "Checking the commit readiness of the chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
else
fatalln "After $MAX_RETRY attempts, Check commit readiness result on peer0.org${ORG} is INVALID!"
fi
}
# 函数 - 将链码提交至通道中
function commitChaincodeDefinition() {
parsePeerConnectionParameters $@
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
set -x
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer0.hmw.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} "${PEER_CONN_PARMS[@]}" --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
verifyResult $res "Chaincode definition commit failed on peer0.org${ORG} on channel '$CHANNEL_NAME' failed"
successln "Chaincode definition committed on channel '$CHANNEL_NAME'"
}
# 函数 - 查看通道中已提交的链码
function queryCommitted() {
ORG=$1
setGlobals $ORG
EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc"
infoln "Querying chaincode definition on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
local rc=1
local COUNTER=1
# continue to poll
# we either get a successful response, or reach MAX RETRY
while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
sleep $DELAY
infoln "Attempting to Query committed status on peer0.org${ORG}, Retry after $DELAY seconds."
set -x
peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} >&log.txt
res=$?
{ set +x; } 2>/dev/null
test $res -eq 0 && VALUE=$(cat log.txt | grep -o '^Version: '$CC_VERSION', Sequence: [0-9]*, Endorsement Plugin: escc, Validation Plugin: vscc')
test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
COUNTER=$(expr $COUNTER + 1)
done
cat log.txt
if test $rc -eq 0; then
successln "Query chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
else
fatalln "After $MAX_RETRY attempts, Query chaincode definition result on peer0.org${ORG} is INVALID!"
fi
}
# 函数 - 调用链码中的初始化函数
function chaincodeInvokeInit() {
parsePeerConnectionParameters $@
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
set -x
fcn_call='{"function":"'${CC_INIT_FCN}'","Args":[]}'
infoln "invoke fcn call:${fcn_call}"
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer0.hmw.com --tls --cafile "$ORDERER_CA" -C $CHANNEL_NAME -n ${CC_NAME} "${PEER_CONN_PARMS[@]}" --isInit -c ${fcn_call} >&log.txt
res=$?
{ set +x; } 2>/dev/null
cat log.txt
verifyResult $res "Invoke execution on $PEERS failed "
successln "Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME'"
}
# 函数 - 调用链码中的函数查询数据
function chaincodeQuery() {
ORG=$1
setGlobals $ORG
infoln "Querying on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
local rc=1
local COUNTER=1
# continue to poll
# we either get a successful response, or reach MAX RETRY
while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
sleep $DELAY
infoln "Attempting to Query peer0.org${ORG}, Retry after $DELAY seconds."
set -x
peer chaincode query -C $CHANNEL_NAME -n ${CC_NAME} -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' >&log.txt
res=$?
{ set +x; } 2>/dev/null
let rc=$res
COUNTER=$(expr $COUNTER + 1)
done
cat log.txt
if test $rc -eq 0; then
successln "Query successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
else
fatalln "After $MAX_RETRY attempts, Query result on peer0.org${ORG} is INVALID!"
fi
}