fabcar项目启动过程分析

打开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
}

(结束)

发布了40 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/LUCKWXF/article/details/104238329