流逝的是岁月,不变的是情怀.
坚持学习,是为了成就更好的自己.
公众号[中关村程序员]

# 4 搭建第一个自己的网络

下面让我们手动搭建一个自己的fabric 网络:

  • 创建一个项目目录: 如 mkdir ~/Demo
  • orderer节点个数为1个
  • 组织个数2个
    • OrgGo
    • OrgCPP
  • OrgGo有两个peer节点, 该组织有3个用户
  • OrgCpp有两个peer节点, 该组织有4个用户

# 4.1 生成Fabric的证书

编写生成组织节点证书的配置文件,我们将其命名为: crypto-config.yaml。在里边指定组织的名称, 节点个数, 用户个数和访问节点的域名信息。

将如下写好的配置文件放入目录: ~/Demo

# crypto-config.yaml
OrdererOrgs: 				# 排序组织
  - Name: Orderer  			# 排序节点组织名称
    Domain: itcast.com  	# 排序节点组织的根域名
    Specs: 
      - Hostname: ubuntu   # 排序节点主机名, 访问该排序节点的域名: ubuntu.itcast.com
                            # “Spec”的作用是不受下面的Template模板生成规则影响,个性化指定一个域名

PeerOrgs:
  - Name: OrgGo    			  # 组织Org1名称
    Domain: orggo.itcast.com  # 组织Org1的域名
    EnableNodeOUs: true  	  # Node.js支持,java的sdk里面默认是注释掉的
   
    Template:  	# 根据上面注释的模板生成2套公私钥+证书,默认生成规则是peer0-9.组织的域名
      Count: 2  # 即生成peer0.orggo.itcast.com、peer1.orggo.itcast.com 两个节点的公私钥和证     
    Users:  	# 除了admin用户,额外生成一个普通用户
      Count: 3	# 普通用户个数为3
  - Name: OrgCPP
    Domain: orgcpp.itcast.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 4
# 配置文件编写完成, 在Demo目录下执行该命令:
$ cryptogen generate --config=./crypto-config.yaml
orggo.itcast.com
orgcpp.itcast.com
# 查看Demo目录中的文件
$ tree -L 6
.
├── crypto-config
│   ├── `ordererOrganizations
│   │   └── itcast.com
│   │       ├── ca
│   │       │   ├── 4d61535a2dd55ff1641d7331e3037d59c590feb2abc21a9be04de678b28480cb_sk
│   │       │   └── ca.itcast.com-cert.pem
│   │       ├── msp
│   │       │   ├── admincerts
│   │       │   │   └── Admin@itcast.com-cert.pem
│   │       │   ├── cacerts
│   │       │   │   └── ca.itcast.com-cert.pem
│   │       │   └── tlscacerts
│   │       │       └── tlsca.itcast.com-cert.pem
│   │       ├── orderers
│   │       │   └── ubuntu.itcast.com
│   │       │       ├── msp
│   │       │       └── tls
│   │       ├── tlsca
│   │       │   ├── e2cf6010c4360cdcf89b636789543dc8e12073ba6035fe811f6e68901370f62d_sk
│   │       │   └── tlsca.itcast.com-cert.pem
│   │       └── users
│   │           └── Admin@itcast.com
│   │               ├── msp
│   │               └── tls
│   └── `peerOrganizations
│       ├── `orgcpp.itcast.com
│       │   ├── ca
│       │   │   ├── b1d3411e8616a50f8d88bde7a68259972565541e0937294b67b09e155468c3cd_sk
│       │   │   └── ca.orgcpp.itcast.com-cert.pem
│       │   ├── msp
│       │   │   ├── admincerts
│       │   │   │   └── Admin@orgcpp.itcast.com-cert.pem
│       │   │   ├── cacerts
│       │   │   │   └── ca.orgcpp.itcast.com-cert.pem
│       │   │   ├── config.yaml
│       │   │   └── tlscacerts
│       │   │       └── tlsca.orgcpp.itcast.com-cert.pem
│       │   ├── `peers
│       │   │   ├── `peer0.orgcpp.itcast.com
│       │   │   │   ├── msp
│       │   │   │   └── tls
│       │   │   └── `peer1.orgcpp.itcast.com
│       │   │       ├── msp
│       │   │       └── tls
│       │   ├── tlsca
│       │   │   ├── 1732fcf1ac3ccfab09c6acbe767af2442b0711ea1128c1d6c1ce059b563266c8_sk
│       │   │   └── tlsca.orgcpp.itcast.com-cert.pem
│       │   └── users
│       │       ├── Admin@orgcpp.itcast.com
│       │       │   ├── msp
│       │       │   └── tls
│       │       ├── User1@orgcpp.itcast.com
│       │       │   ├── msp
│       │       │   └── tls
│       │       ├── User2@orgcpp.itcast.com
│       │       │   ├── msp
│       │       │   └── tls
│       │       ├── User3@orgcpp.itcast.com
│       │       │   ├── msp
│       │       │   └── tls
│       │       └── User4@orgcpp.itcast.com
│       │           ├── msp
│       │           └── tls
│       └── `orggo.itcast.com
│           ├── ca
│           │   ├── 33dbbd366922252ee8689e0444e8b6ffb3df3389219ad0716ee9708c2c18953d_sk
│           │   └── ca.orggo.itcast.com-cert.pem
│           ├── msp
│           │   ├── admincerts
│           │   │   └── Admin@orggo.itcast.com-cert.pem
│           │   ├── cacerts
│           │   │   └── ca.orggo.itcast.com-cert.pem
│           │   ├── config.yaml
│           │   └── tlscacerts
│           │       └── tlsca.orggo.itcast.com-cert.pem
│           ├── `peers
│           │   ├── `peer0.orggo.itcast.com
│           │   │   ├── msp
│           │   │   └── tls
│           │   └── `peer1.orggo.itcast.com
│           │       ├── msp
│           │       └── tls
│           ├── tlsca
│           │   ├── ab7a23f336678f1d8799a44aaeb8894503abb6177d6ba1740037fda952ff9bdb_sk
│           │   └── tlsca.orggo.itcast.com-cert.pem
│           └── users
│               ├── Admin@orggo.itcast.com
│               │   ├── msp
│               │   └── tls
│               ├── User1@orggo.itcast.com
│               │   ├── msp
│               │   └── tls
│               ├── User2@orggo.itcast.com
│               │   ├── msp
│               │   └── tls
│               └── User3@orggo.itcast.com
│                   ├── msp
│                   └── tls
└── crypto-config.yaml

# 4.2 创始块和通道文件的创建

Fabric是基于区块链的分布式账本, 每个账本都有自己的区块, 账本的区块链中会存储账本的交易数据,但账本的第一个区块是一个例外,该区块不存储交易数据而是存储配置信息,通常账本的第一个区块称为创始块。

我们需要些编写生成创始块文件的配置文件,配置文件名字为configtx.yaml, 该名字不要修改, 写好之后放入Demo目录中

# configtx.yaml
---
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
Organizations:
    - &OrdererOrg
        Name: OrdererOrg
        ID: OrdererMSP
        MSPDir: ./crypto-config/ordererOrganizations/itcast.com/msp

    - &OrgGo
        Name: OrgGoMSP
        ID: OrgGoMSP
        MSPDir: ./crypto-config/peerOrganizations/orggo.itcast.com/msp
        AnchorPeers:
            - Host: peer0.orggo.itcast.com
              Port: 7051

    - &OrgCPP
        Name: OrgCppMSP
        ID: OrgCppMSP
        MSPDir: ./crypto-config/peerOrganizations/orgcpp.itcast.com/msp
        AnchorPeers:
            - Host: peer0.orgcpp.itcast.com
              Port: 7051

################################################################################
#
#   SECTION: Capabilities
#
#   - This section defines the capabilities of fabric network. This is a new
#   concept as of v1.1.0 and should not be utilized in mixed networks with
#   v1.0.x peers and orderers.  
#
################################################################################
Capabilities:
    Global: &ChannelCapabilities
        V1_1: true

    Orderer: &OrdererCapabilities
        V1_1: true

    Application: &ApplicationCapabilities
        V1_2: true

################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults
    Organizations:

################################################################################
#
#   SECTION: Orderer
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for orderer related parameters
#
################################################################################
Orderer: &OrdererDefaults
    # Available types are "solo" and "kafka"
    OrdererType: solo
    Addresses:
        - ubuntu.itcast.com:7050
    # Batch Timeout: The amount of time to wait before creating a batch
    BatchTimeout: 2s
    # Batch Size: Controls the number of messages batched into a block
    BatchSize:
        # Max Message Count: The maximum number of messages to permit in a batch
        MaxMessageCount: 10
        AbsoluteMaxBytes: 99 MB
        PreferredMaxBytes: 512 KB

    Kafka:
        # Brokers: A list of Kafka brokers to which the orderer connects
        # NOTE: Use IP:port notation
        Brokers:
            - 127.0.0.1:9092
    Organizations:

################################################################################
#
#   Profile
#
#   - Different configuration profiles may be encoded here to be specified
#   as parameters to the configtxgen tool
#
################################################################################
Profiles:

    ItcastOrdererGenesis:
        Capabilities:
            <<: *ChannelCapabilities
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *OrgGo
                    - *OrgCPP
    TwoOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *OrgGo
                - *OrgCPP
            Capabilities:
                <<: *ApplicationCapabilities
# 1. 在Demo目录下创建新目录 channel-artifacts, 将生成的创始块和通道文件存储在该目录中
$ mkdir channel-artifacts
# 生成创始块文件
$ configtxgen -profile ItcastOrdererGenesis -outputBlock ./channel-artifacts/genesis.block

通道(频道)在Fabric中称为channel, 一个channel表示一个账本。fabric和其他区块链平台最大的区别是支持多账本。每个fabric中至少包含一个channel,下边我们将通过命令将通道创建出来。

# 创建channel
# channel.tx中包含了用于生产channel的信息
$ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
# 生成相关的锚点文件 - 组织1: Go
$ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/OrgGoMSPanchors.tx -channelID mychannel -asOrg OrgGoMSP
# 生成相关的锚点文件 - 组织2: CPP
$ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/OrgCppMSPanchors.tx -channelID mychannel -asOrg OrgCppMSP
# 查看channel-artifacts目录下生成的文件
$ tree channel-artifacts/
channel-artifacts/
├── channel.tx				# 通道文件
├── genesis.block			# 创始块文件
├── orgCppMSPanchors.tx		# Cpp组织锚点文件
└── orgGoMSPanchors.tx		# Go组织锚点文件

# 4.3 启动docker-compose

# 4.3.1 编写配置文件

编写docker-compose启动时加载的配置文件,默认加载的文件名为:``docker-compose.yml/yaml,可通过命令docker-compose --help查看。我们将该文件放到项目目录~/Demo`中。

# docker-compose.yml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
# compose 版本号
version: '2'
# 数据卷映射, 本地 -> docker镜像
volumes:
  ubuntu.itcast.com:
  peer0.orggo.itcast.com:
  peer1.orggo.itcast.com:
  peer0.orgcpp.itcast.com:
  peer1.orgcpp.itcast.com:

networks: # 指定容器运行的网络, 同一网络中的容器才能相互通信
  byfn:

services:
  ubuntu.itcast.com:  # 定义的第1个服务名
    extends:          # 继承自当前yaml文件或者其它文件中定义的服务
      file:   base/docker-compose-base.yaml
      # 要继承上述file文件中对应的名字叫做 ubuntu.itcast.com 的服务
      service: ubuntu.itcast.com
    container_name: ubuntu.itcast.com  # 容器名称, 可以自定义
    networks: # 指定容器启动后运行的网络名
      - byfn

  peer0.orggo.itcast.com: # 定义的第2个服务名
    container_name: peer0.orggo.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.orggo.itcast.com
    networks:
      - byfn

  peer1.orggo.itcast.com: # 定义的第3个服务名
    container_name: peer1.orggo.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.orggo.itcast.com
    networks:
      - byfn

  peer0.orgcpp.itcast.com:  # 定义的第4个服务名
    container_name: peer0.orgcpp.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.orgcpp.itcast.com
    networks:
      - byfn

  peer1.orgcpp.itcast.com:  # 定义的第5个服务名
    container_name: peer1.orgcpp.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.orgcpp.itcast.com
    networks:
      - byfn

  cli:   # 定义的第6个服务名
    container_name: cli
    image: hyperledger/fabric-tools:latest  # 指定服务的镜像名称或镜像 ID
    tty: true
    stdin_open: true
    environment:  # 环境变量设置
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=DEBUG
        #- CORE_LOGGING_LEVEL=INFO
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/Admin@orggo.itcast.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: # 指定了容器的启动顺序, 下边5个服务全部启动之后, 启动cli服务
      - ubuntu.itcast.com         # 定义的服务器名1
      - peer0.orggo.itcast.com    # 定义的服务器名2
      - peer1.orggo.itcast.com    # 定义的服务器名3
      - peer0.orgcpp.itcast.com   # 定义的服务器名4
      - peer1.orgcpp.itcast.com   # 定义的服务器名5
    networks:
      - byfn

接下来就上面 docker-compose.yaml 文件中依赖的文件docker-compose-base.yaml,根据上面的指定可以知道该文件是放到base目录中,也就是说需要在Demo目录中创建子目录base:mkdir base

# ~/Demo/base/docker-compose-base.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
services:
  ubuntu.itcast.com:  # 排序节点服务名称
    container_name: ubuntu.itcast.com
    image: hyperledger/fabric-orderer:latest
    environment:
      - ORDERER_GENERAL_LOGLEVEL=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - 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]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer
    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

  peer0.orggo.itcast.com:
    container_name: peer0.orggo.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.orggo.itcast.com
      - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orggo.example.com/peers/peer0.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orggo.example.com/peers/peer0.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer0.orggo.itcast.com:/var/hyperledger/production
    ports:
      - 7051:7051
      - 7053:7053

  peer1.orggo.itcast.com:
    container_name: peer1.orggo.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.orggo.itcast.com
      - CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer1.orggo.itcast.com:/var/hyperledger/production

    ports:
      - 8051:7051
      - 8053:7053

  peer0.orgcpp.itcast.com:
    container_name: peer0.orgcpp.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.orgcpp.itcast.com
      - CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgCppMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer0.orgcpp.itcast.com:/var/hyperledger/production
    ports:
      - 9051:7051
      - 9053:7053

  peer1.orgcpp.itcast.com:
    container_name: peer1.orgcpp.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.orgcpp.itcast.com
      - CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orgcpp.example.com/peers/peer1.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orgcpp.example.com/peers/peer1.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer1.orgcpp.itcast.com:/var/hyperledger/production
    ports:
      - 10051:7051
      - 10053:7053

在上面的docker-compose-base.yaml文件中又引用了文件peer-base.yaml,接下来我们对该文件进行修改。

# ~/Demo/base/peer-base.yaml
version: '2'
services:
  peer-base:
    image: hyperledger/fabric-peer:latest
    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=Demo_byfn
      - CORE_LOGGING_LEVEL=INFO
      #- CORE_LOGGING_LEVEL=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

# 4.3.2 通过docker-compose启动容器

docker-compose的配置文件编写完成之后, 我们就可以通过配置文件中的配置将所有节点的容器全部启动起来.

# 启动容器
# 在 ~/Demo目录下启动docker-compose, 该目录下有编写好的docker-compose.yaml文件
# 命令启动之后, 会自动加载该文件, 也可以通过-f指定要加载的yaml文件
$ docker-compose up -d 
Creating network "demo_byfn" with the default driver
Creating volume "demo_peer1.orggo.itcast.com" with default driver
Creating volume "demo_ubuntu.itcast.com" with default driver
Creating volume "demo_peer0.orgcpp.itcast.com" with default driver
Creating volume "demo_peer0.orggo.itcast.com" with default driver
Creating volume "demo_peer1.orgcpp.itcast.com" with default driver
Creating peer0.orgcpp.itcast.com ... done
Creating peer1.orgcpp.itcast.com ... done
Creating peer1.orggo.itcast.com  ... done
Creating peer0.orggo.itcast.com  ... done
Creating ubuntu.itcast.com       ... done
Creating cli                     ... done
# 查看已启动的容器
$ docker-compose ps
    Name                 Command       State                    Ports                   
-------------------------------------------------------------------------------------------
cli                      /bin/bash      Up   
peer0.orgcpp.itcast.com peer node start Up  0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp
peer0.orggo.itcast.com  peer node start Up  0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp 
peer1.orgcpp.itcast.com peer node start Up  0.0.0.0:10051->7051/tcp,0.0.0.0:10053->7053/tcp
peer1.orggo.itcast.com  peer node start Up  0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp
ubuntu.itcast.com       orderer         Up  0.0.0.0:7050->7050/tcp

# 4.4 channel管理

# 4.4.1 操作步骤

这个动作需要在cli容器中运行

  • 创建channel

    # 进入cli容器
    $ docker exec -it cli bash
    $ peer channel create -o ubuntu.itcast.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
    # 参数说明: 
    	- ubuntu.itcast.com: 连接的orderer的地址,hostname:port
    	- $CHANNEL_NAME: channel的名称,如果没有指定,默认为mychannel, 通道创建成功之后会在磁盘生成
    					 一个文件, 名字为$CHANNEL_NAME.block(通道名.block)
    	- $CORE_PEER_TLS_ENABLED: 和orderer通信时是否启用tls
    	- $ORDERER_CA: 使用tls时,所使用的orderer的证书
    

    该命令执行过程:

    • 发送消息,创建了channel,名字为$CHANNEL_NAME
    • 获取创始区块,并且用protobuf进行序列化,本地生成了一个文件$CHANNEL_NAME.block
  • 将peer节点添加到channel中

    $ peer channel join -b $CHANNEL_NAME.block
    # 参数说明:
    	$CHANNEL_NAME.block, 创建出的通道文件的名字
    
  • 将每个组织的锚节点(anchor peer)更新到orderer

    $ peer channel update -o ubuntu.itcast.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
    # 参数说明:
    	- ubuntu.itcast.com: 连接的orderer的地址,hostname:port
    	- ${CORE_PEER_LOCALMSPID}anchors.tx: 组织的锚节点文件, 是通过configtxgen指令生成的
    	- $CORE_PEER_TLS_ENABLED: 和orderer通信时是否启用tls
    	- $ORDERER_CA: 使用tls时,所使用的orderer的证书	
    

# 4.4.2 脚本编写

上述操作需要对多个节点进行操作,因此我们可以写一个脚本文件, 对这些操作进行统一处理,方便使用者进行操作。为了对编写的脚本统一管理,可以将其放入一个目录中。

我们可以在~/Demo目录下创建新的子目录scripts, 将所有的脚本文件放到里边。编写的脚本如下:

会被调用多次的操作, 我们将其放到一个单独的脚本文件中

# 该脚本文件我们命名为 utils.sh
# ~/Demo/utils.sh
# 定义一些变量, 下边的代码中会使用 
# orderer 节点的证书
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/orderers/ubuntu.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem
# Go组织peer0节点证书
PEER0_ORGGO_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
# CPP组织peer0节点证书
PEER0_ORGCPP_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/ca.crt

# 根据传递进行来的参数读取各个组织中各节点信息
# 第一次参数表示节点编号, 第二个参数表示组织编号
setGlobals() {
  PEER=$1
  ORG=$2
  if [ $ORG -eq 1 ]; then
    CORE_PEER_LOCALMSPID="OrgGoMSP"		# Go组织的ID, 在configtx.yaml中设置的
    # 客户端cli想要连接哪个节点, 就必须要设置该节点的证书路径
    CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORGGO_CA	# cli可以连接Go组织的peer0节点
    # Go组织的管理员证书
    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
    peerOrganizations/orggo.itcast.com/users/Admin@orggo.itcast.com/msp
    if [ $PEER -eq 0 ]; then
      CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051	# go组织peer0地址
    else
      CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051	# go组织peer1地址
    fi
  elif [ $ORG -eq 2 ]; then
    CORE_PEER_LOCALMSPID="OrgCppMSP"	# CPP组织ID
    CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORGCPP_CA	# cli可以连接CPP组织的peer0节点
    # CPP组织的管理员证书
    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
    peerOrganizations/orgcpp.itcast.com/users/Admin@orgcpp.itcast.com/msp
    if [ $PEER -eq 0 ]; then
      CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051	# cpp组织peer0地址
    else
      CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051	# cpp组织peer0地址
    fi
  else
    echo "================== ERROR !!! ORG Unknown =================="
  fi
  if [ "$VERBOSE" == "true" ]; then
    env | grep CORE
  fi
}

# 该函数对命令执行的结果进行验证, 如果验证失败, 直接退出, 不再执行后续操作流程
verifyResult() {
  if [ $1 -ne 0 ]; then
    echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!"
    echo "========= ERROR !!! FAILED ==========="
    echo
    exit 1
  fi
}

创建通道操作:

# 该脚本文件我们命名为createChannel.sh
# ~/Demo/createChannel.sh
# 定义一些变量, 下边的代码中会使用
CHANNEL_NAME="$1"	# 脚本文件执行时接收的第1个参数
DELAY="$2"			# 脚本文件执行时接收的第2个参数
LANGUAGE="$3"		# 脚本文件执行时接收的第3个参数
: ${CHANNEL_NAME:="mychannel"}	# 通道名,如果值为空, 变量CHANNEL_NAME值设置为mychannel
: ${DELAY:="3"}					# 延时时长,如果值为空, 变量DELAY值设置为3, 操作失败重试时使用
: ${LANGUAGE:="golang"}			# 链码语言,如果值为空, 变量LANGUAGE值设置为golang
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` # 语言转换为大写,再转换为小写
COUNTER=1			# 计数器
MAX_RETRY=5			# 操作失败,重试的次数
# 链码文件路径
CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" # go链码
if [ "$LANGUAGE" = "node" ]; then						   # node.js链码
	CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/"
fi
echo "Channel name : "$CHANNEL_NAME		# 打印通道的名字

# ====================================================
#						创建通道
# ====================================================
# 引用 utils.sh 脚本, 该文件也被创建在scripts目录中
. scripts/utils.sh
createChannel() {
	setGlobals 0 1
	if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        set -x
        # 创建通道, 不使用tls加密, 结果重定向到文件log.txt中
		peer channel create -o ubuntu.itcast.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
		res=$?	# 保存 peer channel create 命令的返回值
        set +x
	else
		set -x
		# 创建通道, 使用tls加密, 结果重定向到文件log.txt中
		peer channel create -o ubuntu.itcast.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt
		res=$?	# 保存 peer channel create 命令的返回值
		set +x
	fi
	cat log.txt	# 将log文件内容输出到终端
	verifyResult $res "Channel creation failed"	# 验证操作是否成功
	echo "===================== Channel '$CHANNEL_NAME' created ===================== "
	echo
}
# 调用创建通道的函数
createChannel

将节点添加到通道中

# 该脚本文件我们命名为joinChannel.sh
# ~/Demo/joinChannel.sh
# 定义一些变量, 下边的代码中会使用
# ====================================================
#						加入通道
# ====================================================
# 引用 utils.sh, createChannel.sh 脚本, 该文件也被创建在scripts目录中
. scripts/utils.sh
. scripts/createChannel.sh
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() {
  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' "
}
# 函数调用
joinChannel

将每个组织的锚节点(anchor peer)更新到orderer

# 该脚本文件我们命名为updateChannel.sh
# ~/Demo/updateChannel.sh
# 引用 utils.sh, createChannel.sh 脚本, 该文件也被创建在scripts目录中
. scripts/utils.sh
. scripts/createChannel.sh
updateAnchorPeers() {
  PEER=$1
  ORG=$2
  setGlobals $PEER $ORG
  if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
    set -x
    # 更新锚节点不使用tls加密, 得到的结果保存到log.txt中
    peer channel update -o ubuntu.itcast.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt
    res=$?
    set +x
  else
    set -x
    # 更新锚节点使用tls加密, 得到的结果保存到log.txt中
    peer channel update -o ubuntu.itcast.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
}
# 函数调用
echo "Updating anchor peers for orggo..."
updateAnchorPeers 0 1
echo "Updating anchor peers for orgcpp..."
updateAnchorPeers 0 2

# 4.5 chaincode安装和实例化

# 该脚本文件我们命名为installChainCode.sh
# ~/Demo/installChainCode.sh
# 引用 utils.sh, createChannel.sh 脚本, 该文件也被创建在scripts目录中
. scripts/utils.sh
. scripts/createChannel.sh
# 安装链码
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
}

# 链码初始化
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 ubuntu.itcast.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "AND ('OrgGoMSP.peer','OrgCppMSP.peer')" >&log.txt
    res=$?
    set +x
  else
    set -x
    peer chaincode instantiate -o ubuntu.itcast.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 ('OrgGoMSP.peer','OrgCppMSP.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
}

# 函数调用
# go组织的peer0, peer1安装链码
echo "Install chaincode on peer0.orggo..."
#nstallChaincode 0 1
echo "Install chaincode on peer0.orggo..."
installChaincode 0 2
# cpp组织的peer0, peer1安装链码
# go组织的peer0进行初始化
echo "Instantiating chaincode on peer0.org2..."
instantiateChaincode 0 2
上次更新: 1/14/2021, 9:13:05 AM