美文网首页
Hyperledger Fabric first-network

Hyperledger Fabric first-network

作者: AI科技智库 | 来源:发表于2020-04-15 21:48 被阅读0次

    1 first-network示例概述

    Build Your First network提供了一个 fabric 的示例网络。该示例网络中由两个组织构成,每个组织维护两个 peer 节点,演示了基于链码查询2个账户余额与转账操作。

    • 1个Orderer节点:默认使用 solo 共识
    • 4个Peer节点: 顺序编号Peer0-Peer3,并加上组织名称
    • 1个CLI命令行客户端节点:使用cryptogen和configtxgen工具生成配置文件、证书文件、创世区块等
    初始化流程图

    first-network 中有一个启动脚本 byfn.sh,利用构建的 Docker 镜像快速启动网络。该脚本会启动一个 orderer 节点和四个归属两个不同组织的 peer 节点,还将启动一个cli运行脚本,它将 peer 节点加入通道(Channel)、部署和实例化链码,并根据已部署的链码驱动交易执行,以下是byfn.sh的帮助文档。

    function printHelp() {
      echo "Usage: "
      echo "  byfn.sh <mode> [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>] [-l <language>] [-o <consensus-type>] [-i <imagetag>] [-a] [-n] [-v]"
      echo "    <mode> - one of 'up', 'down', 'restart', 'generate' or 'upgrade'"
      echo "      - 'up' - bring up the network with docker-compose up"
      echo "      - 'down' - clear the network with docker-compose down"
      echo "      - 'restart' - restart the network"
      echo "      - 'generate' - generate required certificates and genesis block"
      echo "      - 'upgrade'  - upgrade the network from version 1.3.x to 1.4.0"
      echo "    -c <channel name> - channel name to use (defaults to \"mychannel\")"
      echo "    -t <timeout> - CLI timeout duration in seconds (defaults to 10)"
      echo "    -d <delay> - delay duration in seconds (defaults to 3)"
      echo "    -f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
      echo "    -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
      echo "    -l <language> - the chaincode language: golang (default) or node"
      echo "    -o <consensus-type> - the consensus-type of the ordering service: solo (default), kafka, or etcdraft"
      echo "    -i <imagetag> - the tag to be used to launch the network (defaults to \"latest\")"
      echo "    -a - launch certificate authorities (no certificate authorities are launched by default)"
      echo "    -n - do not deploy chaincode (abstore chaincode is deployed by default)"
      echo "    -v - verbose mode"
      echo "  byfn.sh -h (print this message)"
      echo
      echo "Typically, one would first generate the required certificates and "
      echo "genesis block, then bring up the network. e.g.:"
      echo
      echo "    byfn.sh generate -c mychannel"
      echo "    byfn.sh up -c mychannel -s couchdb"
      echo "        byfn.sh up -c mychannel -s couchdb -i 1.4.0"
      echo "    byfn.sh up -l node"
      echo "    byfn.sh down -c mychannel"
      echo "        byfn.sh upgrade -c mychannel"
      echo
      echo "Taking all defaults:"
      echo "    byfn.sh generate"
      echo "    byfn.sh up"
      echo "    byfn.sh down"
    }
    

    执行./byfn.sh up -o etcdraft启动脚本,指定使用raft共识算法

    • -c:设置通道名称,默认为 mychannel
    • -t:设置 CLI 超时参数
    • -l:设置智能合约的语言,默认是 go
    • -o:设置排序服务方式,默认是 solo
    • -s:设置使用的数据库,默认是goleveldb
    • -f:指定docker-compose文件,默认是docker-compose-cli.yaml

    2 生成系统初始化启动的相关配置文件

    通过cryptogen工具生成组织成员关系和身份证书、密钥等文件。调用configtxgen工具生成节点与通道配置文件,包括Orderer节点上系统通道的创世区块文件genesis.block,新建应用通道的配置交易文件channel.tx、组织锚节点配置更新交易文件Org1MSPanchors.tx与Org2MSPanchors.tx等。
    用户执行network_setup.sh脚本启动Fabric网络,该脚本调用networkUp函数,该命令会检查网络实体的证书是否生成,如果没有则首先生成相关证书目录。

    # Generate the needed certificates, the genesis block and start the network.
    function networkUp() {
      checkPrereqs
      # generate artifacts if they don't exist
      if [ ! -d "crypto-config" ]; then
        generateCerts
        replacePrivateKey
        generateChannelArtifacts
      fi
      COMPOSE_FILES="-f ${COMPOSE_FILE}"
      if [ "${CERTIFICATE_AUTHORITIES}" == "true" ]; then
        COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_CA}"
        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
      if [ "${IF_COUCHDB}" == "couchdb" ]; then
        COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_COUCH}"
      fi
      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
      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
    }
    

    2.1 组织成员关系与身份认证等文件

    generateCerts主要执行了cryptogen generate --config=./crypto-config.yaml
    根据crypto-config.yaml生成网络成员组织结构和对应的身份证书、签名私钥等文件,并保存到默认的crypto-config目录,身份证书等文件在对应的目录msp/中,TLS证书与密钥文件保存到tls/中。

    function generateCerts() {
      which cryptogen
      if [ "$?" -ne 0 ]; then
        echo "cryptogen tool not found. exiting"
        exit 1
      fi
      echo
      echo "##########################################################"
      echo "##### Generate certificates using cryptogen tool #########"
      echo "##########################################################"
    
      if [ -d "crypto-config" ]; then
        rm -Rf crypto-config
      fi
      set -x
      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"
      ./ccp-generate.sh
    }
    

    crypto-config.yaml主要包含的fabric排序节点证书配置以及fabric组织证书配置。
    Template模板定义节点的配置模式
    Specs另外一种配置模式
    Count节点总数
    Hostname 全限定域名 命名格式
    Domain域名
    Users 添加到管理员的用户帐户数
    采用Specs模式配置了5个排序节点

    OrdererOrgs:
      - Name: Orderer
        Domain: example.com
        EnableNodeOUs: true
        Specs:
          - Hostname: orderer
          - Hostname: orderer2
          - Hostname: orderer3
          - Hostname: orderer4
          - Hostname: orderer5
    

    采用Template模式配置了两个组织,每个组织2套公私钥和证书,包含普通User数量为1

    PeerOrgs:
      - Name: Org1
        Domain: org1.example.com
        EnableNodeOUs: true
        Template:
          Count: 2
        Users:
          Count: 1
      - Name: Org2
        Domain: org2.example.com
        EnableNodeOUs: true
        Template:
          Count: 2
        Users:
          Count: 1
    

    ordererOrganizations目录:包含Orderer组织类型的身份证书.pem文件、签名私钥文件_sk文件、TLS证书(证书.crt文件和密钥.key文件)
    peerOrganizations目录:包含Peer组织类型的身份证书.pem文件、签名私钥文件
    _sk文件、TLS证书(证书.crt文件和密钥.key文件)
    这些文件通过docker-compose工具,基于docker-compose-cil.yaml、docker-compose-base.yaml等配置文件,将目录作为挂载卷到容器的指定目录。
    调用replacePrivateKey基于docker-compose-e2e-template.yaml文件创建新的配置文件docker-compose-e2e.yaml。进入Org1组织的CA目录,获取私钥文件名作为PRIV_KEY,替换docker-compose-e2e.yaml文件的CA1_PRIVATE_KEY。同理替换CA2_PRIVATE_KEY。

    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.
      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
    }
    

    2.2 节点与通道配置文件

    执行generateChannelArtifacts函数,使用configtxgen工具基于configtx.yaml创建节点与通道配置文件,包括Orderer通道的创世区块,应用通道配置配置交易文件channel.tx,锚节点配置更新交易文件Org1MSPanchors.tx和Org2MSPanchors.tx
    Orderer系统通道的创世区块
    执行configtxgen命令,创建Orderer创世区块文件genesis.block

    configtxgen -profile TwoOrgsOrdererGenesis -channelID $SYS_CHANNEL -outputBlock ./channel-artifacts/genesis.block
    

    新建应用通道的配置交易文件
    执行configtxgen命令,创建应用通道的配置交易文件channel.tx,后续执行peer channel create读取文件。

    configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
    

    锚节点配置更新交易文件
    执行configtxgen命令,创建锚节点配置更新交易文件Org1MSPanchors.tx和Org2MSPanchors.tx,后续执行peer channel update进行更新。

    configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
    configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
    

    返回到network_setup.sh脚本,判断是否启用了CouchDB标志位(默认关闭),使用docker-Compose工具执行docker-Compose-cil.yaml文件,启动Fabric网络。

    3 启动Orderer服务节点

    继续分析network_setup.sh脚本,默认COMPOSE_FILES是docker-compose-cli.yaml文件,当设置了kafka共识或者raft共识,则使用对应的yaml文件。

    docker-compose -f docker-compose-cli.yaml up -d 2>&1
    

    Orderer节点继承了docker-compose-base.yaml中的orderer.example.com配置属性,Orderer节点容器启动时执行如下命令

    orderer # 默认启动orderer start子命令
    
    配置文件 说明
    msp/* 组织成员身份证书、签名私钥
    tls/* TLS认证证书、密钥文件
    orderer.gennesis.block 系统通道创世区块

    docker-compose-cil.yaml文件

      orderer.example.com:
        extends:
          file:   base/docker-compose-base.yaml
          service: orderer.example.com
        container_name: orderer.example.com
        networks:
          - byfn
    

    继续追踪base/docker-compose-base.yaml,找到orderer.example.com服务,挂载目录和暴露7050端口。

      orderer.example.com:
        container_name: orderer.example.com
        extends:
          file: peer-base.yaml
          service: orderer-base
        volumes:
            - ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
            - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
            - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
            - orderer.example.com:/var/hyperledger/production/orderer
        ports:
          - 7050:7050
    

    orderer的配置还是引入peer-base.yaml中的orderer-base服务

      orderer-base:
        image: hyperledger/fabric-orderer:$IMAGE_TAG
        environment:
    # 日志级别INFO
          - FABRIC_LOGGING_SPEC=INFO
    # 监听地址0.0.0.0
          - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
    # 加载方式为文件
          - ORDERER_GENERAL_GENESISMETHOD=file
    # 指定创始区块的目录
          - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
    # 排序节点MSPID
          - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
    # 排序节点msp目录
          - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
    # enabled TLS
          - ORDERER_GENERAL_TLS_ENABLED=true
          - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
          - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
          - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
          - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
          - ORDERER_KAFKA_VERBOSE=true
          - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
          - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
          - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    # 启动命令
        command: orderer
    

    4 启动Peer节点

    4个Peer节点继承了docker-compose-base.yaml中对应容器名称的配置属性,Peer节点容器启动时执行如下命令

    peer node start
    
    配置文件 说明
    core.yaml 通用配置、账本配置
    msp/* 组织成员身份证书、签名私钥
    tls/* TLS认证证书、密钥文件
    channel.tx 应用通道配置交易文件
    Org1MSPanchors.tx Org1MSP组织锚节点配置更新交易文件
    Org2MSPanchors.tx Org2MSP组织锚节点配置更新交易文件

    docker-compose-cil.yaml文件中Peer节点配置。

    peer0.org1.example.com:
        container_name: peer0.org1.example.com
        extends:
          file:  base/docker-compose-base.yaml
          service: peer0.org1.example.com
        networks:
          - byfn
    
      peer1.org1.example.com:
        container_name: peer1.org1.example.com
        extends:
          file:  base/docker-compose-base.yaml
          service: peer1.org1.example.com
        networks:
          - byfn
    
      peer0.org2.example.com:
        container_name: peer0.org2.example.com
        extends:
          file:  base/docker-compose-base.yaml
          service: peer0.org2.example.com
        networks:
          - byfn
    
      peer1.org2.example.com:
        container_name: peer1.org2.example.com
        extends:
          file:  base/docker-compose-base.yaml
          service: peer1.org2.example.com
        networks:
          - byfn
    

    docker-compose-base.yaml文件中Peer节点的配置。

      peer0.org1.example.com:
        container_name: peer0.org1.example.com
        extends:
          file: peer-base.yaml
          service: peer-base
        environment:
          - CORE_PEER_ID=peer0.org1.example.com
          - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
          - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
          - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
          - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
          - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:8051
          - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
          - CORE_PEER_LOCALMSPID=Org1MSP
        volumes:
            - /var/run/:/host/var/run/
            - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
            - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
            - peer0.org1.example.com:/var/hyperledger/production
        ports:
          - 7051:7051
    

    引入peer-base.yaml中的peer-base服务

      peer-base:
        image: hyperledger/fabric-peer:$IMAGE_TAG
        environment:
          - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
          # the following setting starts chaincode containers on the same
          # bridge network as the peers
          # https://docs.docker.com/compose/networking/
          - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_byfn
          - FABRIC_LOGGING_SPEC=INFO
          #- FABRIC_LOGGING_SPEC=DEBUG
          - CORE_PEER_TLS_ENABLED=true
          - CORE_PEER_GOSSIP_USELEADERELECTION=true
          - CORE_PEER_GOSSIP_ORGLEADER=false
          - CORE_PEER_PROFILE_ENABLED=true
          - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
          - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
          - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
        command: peer node start
    

    5 CLI客户端执行script脚本

    docker-compose-cil.yaml文件中CLI客户端配置。启动完 orderer 节点、peer 节点和 CLI 容器之后,实际是调用 script.sh 脚本,该脚本是在 CLI 容器中执行,CLI 容器其实就是用户客户端,只不过是命令行客户端,运行在容器中。默认情况下CLI 的身份是 admin.org1,连接 peer0.org1 节点,执行 script.sh 脚本

    cli:
        container_name: cli
        image: hyperledger/fabric-tools:$IMAGE_TAG
        tty: true
        stdin_open: true
        environment:
          - SYS_CHANNEL=$SYS_CHANNEL
          - GOPATH=/opt/gopath
          - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
          #- FABRIC_LOGGING_SPEC=DEBUG
          - FABRIC_LOGGING_SPEC=INFO
          - CORE_PEER_ID=cli
          - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
          - CORE_PEER_LOCALMSPID=Org1MSP
          - CORE_PEER_TLS_ENABLED=true
          - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
          - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
          - 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
          - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
        command: /bin/bash
        volumes:
            - /var/run/:/host/var/run/
            - ./../chaincode/:/opt/gopath/src/github.com/chaincode
            - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
            - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
            - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
        depends_on:
          - orderer.example.com
          - peer0.org1.example.com
          - peer1.org1.example.com
          - peer0.org2.example.com
          - peer1.org2.example.com
        networks:
          - byfn
    

    script.sh脚本顺序执行默认的测试流程,包括创建新的应用通道、添加节点、更新锚节点、安装链码、实例化链码、调用链码、查询链码等操作。

    ## Check for orderering service availablility
    echo "Check orderering service availability..."
    checkOSNAvailability  //测试Orderer节点是否可用
    
    ## Create channel
    echo "Creating channel..."
    createChannel  //创建应用通道
    
    ## Join all the peers to the channel
    echo "Having all peers join the channel..."
    joinChannel  //添加Peer节点到指定的应用通道
    
    //更新通道中每个组织的锚节点配置
    ## Set the anchor peers for each org in the channel
    echo "Updating anchor peers for org1..."
    updateAnchorPeers 0
    echo "Updating anchor peers for org2..."
    updateAnchorPeers 2
    
    //Peer0/Org1与Peer2/Org2中安装链码
    ## Install chaincode on Peer0/Org1 and Peer2/Org2
    echo "Installing chaincode on org1/peer0..."
    installChaincode 0
    echo "Install chaincode on org2/peer0..."
    installChaincode 2
    
    //Peer2/Org2中实例化链码
    #Instantiate chaincode on Peer2/Org2
    echo "Instantiating chaincode on org2/peer2..."
    instantiateChaincode 2
    
    //Peer0/Org1上查询链码,检查是否100元
    #Query on chaincode on Peer0/Org1
    echo "Querying chaincode on org1/peer0..."
    chaincodeQuery 0 100
    
    //Peer0/Org1上调用链码
    #Invoke on chaincode on Peer0/Org1
    echo "Sending invoke transaction on org1/peer0..."
    chaincodeInvoke 0
    
    //Peer3/Org2上安装链码
    ## Install chaincode on Peer3/Org2
    echo "Installing chaincode on org2/peer3..."
    installChaincode 3
    
    //Peer3/Org2上查询链码,是否90元
    #Query on chaincode on Peer3/Org2, check if the result is 90
    echo "Querying chaincode on org2/peer3..."
    chaincodeQuery 3 90
    

    5.1 创建新的应用通道

    Fabric要求创建、加入与更新通道的权限必须具有通道组织的管理员身份。调用setGlobals设置全局环境变量,CLI客户端能够灵活切换指定容器的管理员角色,可以直接连接并操作指定的Peer节点,先切换到Peer0/Org1节点。
    接着采用Org1管理员身份执行peer指令,将通道配置文件Channel.tx发送给Orderer节点,创建mychananel的应用通道。如果创建成功,则返回一个创世区块block,它会存储在 peer 节点的文件系统中,包含 channel.tx 指定的通道配置信息。

    createChannel() {
        setGlobals 0 1
    
        if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
                    set -x
            peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
            res=$?
                    set +x
        else
                    set -x
            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
            res=$?
                    set +x
        fi
        cat log.txt
        verifyResult $res "Channel creation failed"
        echo "===================== Channel '$CHANNEL_NAME' created ===================== "
        echo
    }
    

    5.2 Peer节点加入应用通道

    遍历所有节点,调用setGlobals切换指定节点,执行peer指令,将Org1组织包含的Peer0/Org1和Peer1/Org1节点加入mychananel应用通道,将创世区块mychananel.block设置成命令行参数。Org2组织类似。

    joinChannel () {
        for org in 1 2; do
            for peer in 0 1; do
            joinChannelWithRetry $peer $org
            echo "===================== peer${peer}.org${org} joined channel '$CHANNEL_NAME' ===================== "
            sleep $DELAY
            echo
            done
        done
    }
    

    joinChannelWithRetry 函数中的 setGlobals 是设置 CLI 容器的环境变量的函数。例如:setGlobals 1 2 设置 CLI 的身份为 admin.org2,连接 peer1.org2 节点。
    使用 peer channel join 命令让节点加入通道,$CHANNEL_NAME.block 就是前面创建通道成功时返回的区块,该区块在上面 org1.peer0 创建通道时保持在 CLI 容器内,所以能直接使用。节点成功加入通道后会创建 CHANNEL_NAME.block 开头的链。

    joinChannelWithRetry() {
      PEER=$1
      ORG=$2
      setGlobals $PEER $ORG
    
      set -x
      peer channel join -b $CHANNEL_NAME.block >&log.txt
      res=$?
      set +x
      cat log.txt
      if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then
        COUNTER=$(expr $COUNTER + 1)
        echo "peer${PEER}.org${ORG} failed to join the channel, Retry after $DELAY seconds"
        sleep $DELAY
        joinChannelWithRetry $PEER $ORG
      else
        COUNTER=1
      fi
      verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to join channel '$CHANNEL_NAME' "
    }
    

    5.3 更新应用通道上组织的锚节点配置

    一个组织只能有一个锚节点,节点加入通道后才能进行更新,连续两次调用updateAnchorPeers,更新两个组织的锚节点配置,用Org1管理身份更新Peer0/Org1的配置,并指定锚节点配置更新文件Org1MSPanchors.tx,Org2组织同理。

    updateAnchorPeers() {
      PEER=$1
      ORG=$2
      setGlobals $PEER $ORG
    
      if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        set -x
        peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt
        res=$?
        set +x
      else
        set -x
        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
        res=$?
        set +x
      fi
      cat log.txt
      verifyResult $res "Anchor peer update failed"
      echo "===================== Anchor peers updated for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME' ===================== "
      sleep $DELAY
      echo
    }
    

    6 安装、实例化与调用链码

    6.1 安装链码

    连续两次调用installChaincode分别在Peer0/Org1和Peer2/Org2中安装chaincode_example02链码,并将链码命名为“mycc”且版本1.0,如果链码安装成功,在指定安装目录/var/hyperledger/production/chaincodes下存在name.version的链码文件。

    installChaincode() {
      PEER=$1
      ORG=$2
      setGlobals $PEER $ORG
      VERSION=${3:-1.0}
      set -x
      peer chaincode install -n mycc -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt
      res=$?
      set +x
      cat log.txt
      verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has failed"
      echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== "
      echo
    }
    

    6.2 实例化链码

    实例化链码必须在安装过链码的节点上进行,同一个通道内所有节点上相同的实例化数据在通道账本中是共享的,用户只需要在任意一个Peer节点上成功执行一次实例化链码操作,并通过排序打包后将实例化数据广播到其他节点上,通道内所有合法节点都可以访问该链码的实例化数据。
    实例化将链码添加到通道上,启动目标节点的容器,初始化与链码相关的初始值,这里的初始值为 ["a","100","b","200"]。”实例化“ 过程会产生链码的容器,例如: dev-peer0-org1.example.com-mycc-1.0 。实例化过程需要指定背书策略,通过 -P 参数设置,这里的策略定义为 AND ('Org1MSP.peer','Org2MSP.peer') ,表示任何交易必须要有 org1 和 org2 节点的共同背书。

    instantiateChaincode() {
      PEER=$1
      ORG=$2
      setGlobals $PEER $ORG
      VERSION=${3:-1.0}
    
      # 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
      if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        set -x
        peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
        res=$?
        set +x
      else
        set -x
        peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
        res=$?
        set +x
      fi
      cat log.txt
      verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed"
      echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
      echo
    }
    

    6.3 调用链码

    Peer0/Org1上调用链码查询函数chaincodeQuery和链码调用函数chaincodeQuery。查看A的余额,并从账户A中向账户B中转账10元。

    chaincodeInvoke() {
      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
      if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        set -x
        peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
        res=$?
        set +x
      else
        set -x
        peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
        res=$?
        set +x
      fi
      cat log.txt
      verifyResult $res "Invoke execution on $PEERS failed "
      echo "===================== Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME' ===================== "
      echo
    }
    

    6.4 查询链码

    Peer3/Org2上安装链码,执行查询A的余额,检查余额是否为90元,如果是说明转账成功。

    chaincodeQuery() {
      PEER=$1
      ORG=$2
      setGlobals $PEER $ORG
      EXPECTED_RESULT=$3
      echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== "
      local rc=1
      local starttime=$(date +%s)
    
      # continue to poll
      # we either get a successful response, or reach TIMEOUT
      while
        test "$(($(date +%s) - starttime))" -lt "$TIMEOUT" -a $rc -ne 0
      do
        sleep $DELAY
        echo "Attempting to Query peer${PEER}.org${ORG} ...$(($(date +%s) - starttime)) secs"
        set -x
        peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt
        res=$?
        set +x
        test $res -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}')
        test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
        # removed the string "Query Result" from peer chaincode query command
        # result. as a result, have to support both options until the change
        # is merged.
        test $rc -ne 0 && VALUE=$(cat log.txt | egrep '^[0-9]+$')
        test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
      done
      echo
      cat log.txt
      if test $rc -eq 0; then
        echo "===================== Query successful on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
      else
        echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!"
        echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
        echo
        exit 1
      fi
    }
    

    相关文章

      网友评论

          本文标题:Hyperledger Fabric first-network

          本文链接:https://www.haomeiwen.com/subject/pbqimhtx.html