Hyperledger Fabric application combat (8)– smart contract deployment script

1. Chaincode deployment script idea

In the previous chapter, we analyzed the network startup script of test-netwok, which includes the chain code deployment part. We sorted out the chain code deployment ideas by analyzing the deployCC of test-netwok, and then wrote the freenet network chain code deployment script.

  • pakeageChaincode(): Pack the chaincode chaincode into a predetermined format (tar.gz file);
  • installChaincode(): Install the packaged chaincode on the required peer node;
  • queryInstalled(): Query whether the chaincode has been installed on the peer node;
  • approveForMyOrg():Multiple members approve the chain code, and the nodes on each peer should be consistent;
  • checkCommitReadiness(): to check whether a chaincode meets the standard of the channel, that is, whether it reaches the established multi-member approval setting;
  • commitChaincodeDefinition(): install the chaincode to the channel;
  • queryCommitted(): Whether the organization query of the channel has been submitted to the channel;

The Fabric2.X version optimizes the chaincode life cycle. The current chaincode logic is relatively clear and easy to understand. Each organization on the channel runs the business according to a code logic, and each step is quite reasonable and easy to understand.

2. Chaincode deployment script writing

The overall logic of the chaincode deployment script is relatively simple. As an official case, the script in test-network must be quite complete, so if you are not familiar with the shell script, it will seem difficult. Some of the shell script functions are only used as a whole. Understand, with the ultimate goal of understanding the general idea and adjusting the chaincode deployment script, it is very error-prone to modify and write.

2.1 Chaincode packaging and installation

The public parameter configuration of the chaincode script, CC_COLL_CONFIG is not needed yet.

CHANNEL_NAME="$1"
DELAY="$2"
MAX_RETRY="$3"
VERBOSE="$4"
CC_NAME="$5"
CC_VERSION="$6"
CC_END_POLICY="$9"
#CC_COLL_CONFIG="${10}"
CC_INIT_FCN="${11}"
CC_SRC_LANGUAGE="${12}"
: ${CHANNEL_NAME:="rentsign"}
: ${DELAY:="10"}
: ${MAX_RETRY:="3"}
: ${VERBOSE:="false"}
: ${CC_NAME:="freerent"}
: ${CC_VERSION:="v1"}
: ${CC_SEQUENCE:="1"}
# combined with cliup working directory
#: ${CC_COLL_CONFIG:="./network/artifacts/collections_config.json"}
: ${CC_INIT_FCN:="init"}
: ${CC_SRC_LANGUAGE:="golang"}

CC_RUNTIME_LANGUAGE=golang

#import utils
.scripts/env-var.sh

infoln "Deploy chaincode in $DOMAIN_OF_NETWORK network"
debugln " - CHANNEL_NAME: '$CHANNEL_NAME'"
debugln " - CC_NAME: '$CC_NAME'"
debugln " - CC_SRC_PATH: '$CC_SRC_PATH'"
debugln " - CC_SRC_LANGUAGE: '$CC_SRC_LANGUAGE'"
debugln " - CC_VERSION: '$CC_VERSION'"
#debuglen " - CC_COLL_CONFIG: '$CC_COLL_CONFIG'"


## Install chaincode
infoln "Installing chaincode on supervisor"
for peer in 0 1 2 ;
  installChaincode supervisor $peer
done

infoln "Installing chaincode on rentalcrop"
for peer in 0 1;
  installChaincode rentalcrop $peer
done

infoln "Installing chaincode on agency"
for peer in 0 1;
  installChaincode agency $peer
done

## query whether the chaincode is installed
queryInstalled supervisor 0
queryInstalled rentalcrop 0
queryInstalled agency 0

## approve the definition for dispatcher
approveForMyOrg supervisor 0

## check whether the chaincode definition is ready to be committed
checkCommitReadiness supervisor ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"
checkCommitReadiness rentalcrop ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"
checkCommitReadiness agency ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"

## now approve also for aggregator
approveForMyOrg rentalcrop 0


Chaincode packaging: --path is the location of the chaincode, which is different from the official script. Note that it is the mapping location in the docker container, because the script runs in In the cliup container; --label: used to specify the chaincode label, which is used to identify the chaincode after installation; the --lang flag is used to specify the chaincode language.

packageChaincode() {
  set -x
  go env -w GOPROXY=https://goproxy.io,direct
  go env -w GO111MODULE=on
  peer lifecycle chaincode package ${CC_NAME}.tar.gz --path ${CC_SRC_PATH} --lang ${CC_SRC_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"
}

**Chaincode installation:** Here, a total of 7 nodes are installed with chaincode. The script function has two parameters, which are the organization name and the node name.

# installChaincode ORG PEER
installChaincode() {
  ORG=$1
  PEER=$2
  setGlobals $ORG $PEER
  peer lifecycle chaincode install /opt/gopath/src/github.com/hyperledger/fabric/${CC_NAME}.tar.gz > &log.txt
  res=$?
  { set + x; } 2>/dev/nulls
  cat log.txt
  verifyResult $res "Chaincode installation on peer$PEER.${ORG_NAME} has failed"
  successln "Chaincode is installed on peer $PEER.${ORG_NAME}"
}

## Install chaincode
infoln "Installing chaincode on supervisor"
for peer in 0 1 2 ;
  installChaincode supervisor $peer
done

infoln "Installing chaincode on rentalcrop"
for peer in 0 1;
  installChaincode rentalcrop $peer
done

infoln "Installing chaincode on agency"
for peer in 0 1;
  installChaincode agency $peer
done

2.2 Chaincode query and approval

Before the approval of the chain code, you can query the status of the chain code installation. The main purpose of approving the chain code is to achieve a consensus on the content, version, endorsement policy, and data collection of the chain code. Generally, most members on the channel approve the chaincode, and the chaincode can be submitted to the channel.

In the approveForMyOrg() function, the environment variable is set to the corresponding approved node through the setGlobals function; the --sequence parameter is an integer for tracking The number of times the chaincode has been defined or updated;

# queryInstalled ORG PEER
queryInstalled() {
  ORG=$1
  PEER=$2
  peer lifecycle chaincode queryinstalled > &log.txt
  res=$?
  { set + x; } 2>/dev/null
  cat log.txt
}

#approveForMyOrg ORG PEER
approveForMyOrg() {
  ORG=$1
  PEER=$2
  setOrdererGlobals 0
  setGlobals $ORG $PEER

  peer lifecycle chaincode approveformyorg \
      -o "$CORE_ORDERER_ADDRESS" \
      --tls true\
      --cafile $CORE_ORDERER_TLS_ROOTCERT_FILE \
      --channelID $CHANNEL_NAME \
      --name ${CC_NAME} \
      --version ${CC_VERSION} \
      --package-id ${PACKAGE_ID} \
      --sequence ${CC_SEQUENCE} \
    res=$?
  verifyResult $res "Chaincode definition approved on peer $PEER.${ORG_NAME} failed"
  successln "Chaincode definition approved on peer $PEER.${ORG_NAME}"
}

## query whether the chaincode is installed
queryInstalled supervisor 0
queryInstalled rentalcrop 0
queryInstalled agency 0

## approve the definition for dispatcher
approveForMyOrg supervisor 0

After the supervisor organization approves, we can query the status of the chaincode on the channel, which organizations have approved which chaincode, and the query will return a json to inform which organizations in the channel have approved
Ready. Subsequent steps are the same for Rentalcrop organization and AgencyMSP organization.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-Ovuvmsvr-1679127201138) (https://secure2.wostatic.cn/static/j7MEiTSBmeUA2RG5z3tbxH/image.png?auth_key =1679125851-npXxabAFgaCJ1t4sgtRfDq-0-0cdfc9cd4cc0908d0bad1f16dcab322c)]

checkCommitReadiness() {
  ORG=$1
  shift 1
  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 -le $MAX_RETRY ]; do
    if [ $COUNTER -gt 1 ]; then sleep $DELAY;
    set -x
    peer lifecycle chaincode checkcommit readiness \
      --channelID $CHANNEL_NAME \
      --name ${CC_NAME} \
      --version ${CC_VERSION} \
      --sequence ${CC_SEQUENCE} \
      --signature-policy "${CC_END_POLICY}" \
      --output json > &log.txt
    res=$?
    { set + x; } 2>/dev/null
    let rc=0
    for var in "$@"; do
      grep "$var" log.txt & amp;>/dev/null || let rc=1
    done
    COUNTER=$(expr $COUNTER + 1)
  done
  cat log.txt
  if test $rc -eq 0; then
  else
  the fi
}

# Currently only approved by the supervisor organization.
checkCommitReadiness supervisor ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"
checkCommitReadiness rentalcrop ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"
checkCommitReadiness agency ""SupervisorMSP": true" ""RentalcropMSP": false" ""AgencyMSP": false"

After inquiry and approval by three organizations:

2.3 Chaincode submission and viewing

The definition of the chain code on the channel can be confirmed if the policy conditions of the chain code installation are met. Confirming the definition of the chain code will generate a transaction, and the transaction needs to be sorted and dropped. The last step is each node Go to the ledger to query whether the chaincode definition transaction is successful. The logic of the function and the meaning of the parameters have basically been covered above.

commitChaincodeDefinition() {
  setOrdererGlobals 0
  parsePeerConnectionParameters $@
  res=$?
  verifyResult $res "Invoke transaction failed due to uneven number of peer and org parameters "
  set -x
  peer lifecycle chaincode commit \
    -o "$CORE_ORDERER_ADDRESS" \
    --tls \
    --cafile $CORE_ORDERER_TLS_ROOTCERT_FILE \
    --channelID $CHANNEL_NAME \
    --name $CC_NAME\
    $PEER_CONN_PARMS\
    --version ${CC_VERSION} \
    --sequence ${CC_SEQUENCE} \
    --signature-policy "${CC_END_POLICY}" \
    --waitForEventTimeout 300s > &log.txt
    res=$?
    { set + x; } 2>/dev/null

  cat log.txt
  verifyResult $res "Chaincode definition commit failed on peer0. ${ORG_NAME} failed"
  successln "Chaincode definition committed"
}

# queryCommitted ORG
queryCommitted() {
  ORG=$1
  setGlobals $ORG 0
  EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc"
  infoln "Querying chaincode definition on peer0.${ORG_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 -le $MAX_RETRY ]; do
    if [ $COUNTER -gt 1 ]; then sleep $DELAY;
    infoln "Attempting to Query committed status on peer0. ${ORG_NAME}, 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 & amp; & amp; VALUE=$(cat log.txt | grep -o '^Version: '$CC_VERSION', Sequence: [0-9], Endorsement Plugin: escc, Validation Plugin: vscc')
    test "$VALUE" = "$EXPECTED_RESULT" & amp; & amp; let rc=0
    COUNTER=$(expr $COUNTER + 1)
  done
  cat log.txt
  if test $rc -eq 0; then
    successln "Query chaincode definition successfully on peer0. ${ORG_NAME}"
  else
    fatalln "After $MAX_RETRY attempts, Query chaincode definition result on peer0. ${ORG_NAME} is INVALID"
  the fi
}

## now that we know for sure both orgs have approved, commit the definition
commitChaincodeDefinition supervisor 0 rentalcrop 0 agency 0

## query on both orgs to see that the definition committed successfully
queryCommitted supervisor
query Committed rental crop
query Committed agency

3. Current application complete directory

At present, a basic multi-node network has been deployed. The main directory of the current project is as follows. Here we mainly sort out the directories under the network file.

The directory structure layout in network is a bit different from test-network, and the design may not be very reasonable, but the core is the mapping of directories in docker-compose, which is relatively error-prone, docker will not make mistakes, and if the path file does not exist, it will not exists, whether it is a path error or a mapping path error.