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

# 1. 生成Fabric证书

我们可以自己组建一个Fabric网路, 网络结构如下:

网络中唯一的通道: itcastchannel

  • 排序节点 1 个 -> 测试
    • 排序节点组织名: OrgOrderer
    • .....组织ID: OrgOrdererMSP
    • 排序节点组织访问的根域名:
      • itcast.com
    • 排序节点组织中唯一的节点访问二级域名:
      • orderer.itcast.com
  • 组织个数 2 个, 分别为go和cpp, 每个组织分别有两个peer节点, 用户个数为3
    • go组织
      • 组织名: OrgGo
      • 组织ID: OrgGoMSP
      • 访问组织的域名: orggo.itcast.com
      • 锚节点: peer0这个节点
    • cpp组织
      • 组织名: OrgCpp
      • 组织ID: OrgCppMSP
      • 访问组织的域名: orgcpp.itcast.com
      • 锚节点: peer1这个节点
机构名称 组织标识符 组织ID
Go学科 OrgGo OrgGoMSP
CPP OrgCpp OrgCppMSP

# 1.1 命令介绍

$ cryptogen --help
$ cryptogen generate --config=配置文件

# 1.2 配置文件的编写

# crypto-config.yaml
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: OrgOrderer
    Domain: itcast.com

    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs below for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer

# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: OrgGo
    Domain: orggo.itcast.com
    EnableNodeOUs: false

    # ---------------------------------------------------------------------------
    # "CA"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of the CA for this
    # organization.  This entry is a Spec.  See "Specs" section below for details.
    # ---------------------------------------------------------------------------
    # CA:
    #    Hostname: ca # implicitly ca.org1.example.com
    #    Country: US
    #    Province: California
    #    Locality: San Francisco
    #    OrganizationalUnit: Hyperledger Fabric
    #    StreetAddress: address for org # default nil
    #    PostalCode: postalCode for org # default nil

    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of hosts in your
    # configuration.  Most users will want to use Template, below
    #
    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
    #   - Hostname:   (Required) The desired hostname, sans the domain.
    #   - CommonName: (Optional) Specifies the template or explicit override for
    #                 the CN.  By default, this is the template:
    #
    #                              "{{.Hostname}}.{{.Domain}}"
    #
    #                 which obtains its values from the Spec.Hostname and
    #                 Org.Domain, respectively.
    #   - SANS:       (Optional) Specifies one or more Subject Alternative Names
    #                 to be set in the resulting x509. Accepts template
    #                 variables {{.Hostname}}, {{.Domain}}, {{.CommonName}}. IP
    #                 addresses provided here will be properly recognized. Other
    #                 values will be taken as DNS names.
    #                 NOTE: Two implicit entries are created for you:
    #                     - {{ .CommonName }}
    #                     - {{ .Hostname }}
    # ---------------------------------------------------------------------------
    # Specs:
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #     SANS:
    #       - "bar.{{.Domain}}"
    #       - "altfoo.{{.Domain}}"
    #       - "{{.Hostname}}.org6.net"
    #       - 172.16.10.31
    #   - Hostname: bar
    #   - Hostname: baz

    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    # Allows for the definition of 1 or more hosts that are created sequentially
    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
    # You may override the number of nodes (Count), the starting index (Start)
    # or the template used to construct the name (Hostname).
    #
    # Note: Template and Specs are not mutually exclusive.  You may define both
    # sections and the aggregate nodes will be created for you.  Take care with
    # name collisions
    # ---------------------------------------------------------------------------
    Template:
      Count: 2
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default
      # SANS:
      #   - "{{.Hostname}}.alt.{{.Domain}}"

    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 3

  # ---------------------------------------------------------------------------
  # Org2: See "Org1" for full specification
  # ---------------------------------------------------------------------------
  - Name: OrgCpp
    Domain: orgcpp.itcast.com
    EnableNodeOUs: false
    Template:
      Count: 2
    Users:
      Count: 3

# 1.3 证书文件的生成


# 2. 创始块文件和通道文件的生成

# 2.1 命令介绍

$ configtxgen --help 
  # 指定生成的创始块文件的名字
  `-outputBlock string`
  # 指定创建的通道的名字/ID
  `-channelID string`
  # 指定生成的通道文件的名字
  `-outputCreateChannelTx string`
  # 指定configtx.yaml的Profiles中的关键字
  `-profile string`
  # 生成锚节点更新文件
  `-outputAnchorPeersUpdate string`
  # 指定组织的名字
  `-asOrg string`

# 2.2 配置文件编写

# configtx.yaml
---
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
Organizations:

    # SampleOrg defines an MSP using the sampleconfig.  It should never be used
    # in production but may be used as a template for other definitions
    - &OrdererOrg
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: OrgOrderer

        # ID to load the MSP definition as
        ID: OrgOrdererMSP

        # MSPDir is the filesystem path which contains the MSP configuration
        MSPDir: crypto-config/ordererOrganizations/itcast.com/msp

    - &OrgGo
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: OrgGo

        # ID to load the MSP definition as
        ID: OrgGoMSP

        MSPDir: crypto-config/peerOrganizations/orggo.itcast.com/msp

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.orggo.itcast.com
              Port: 7051

    - &OrgCpp
        # DefaultOrg defines the organization which is used in the sampleconfig
        # ID to load the MSP definition as
        ID: OrgGoMSP

        MSPDir: crypto-config/peerOrganizations/orggo.itcast.com/msp

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.orggo.itcast.com
              Port: 7051

    - &OrgCpp
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: OrgCpp

        # ID to load the MSP definition as
        ID: OrgCppMSP

        MSPDir: crypto-config/peerOrganizations/orgcpp.itcast.com/msp

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer1.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 define features which must be
#   present in a fabric binary for that binary to safely participate in the
#   fabric network.  For instance, if a new MSP type is added, newer binaries
#   might recognize and validate the signatures from this type, while older
#   binaries without this support would be unable to validate those
#   transactions.  This could lead to different versions of the fabric binaries
#   having different world states.  Instead, defining a capability for a channel
#   informs those binaries without this capability that they must cease
#   processing transactions until they have been upgraded.  For v1.0.x if any
#   capabilities are defined (including a map with all capabilities turned off)
#   then the v1.0.x peer will deliberately crash.
#
################################################################################
Capabilities:
    # Channel capabilities apply to both the orderers and the peers and must be
    # supported by both.  Set the value of the capability to true to require it.
    Global: &ChannelCapabilities
        # V1.1 for Global is a catchall flag for behavior which has been
        # determined to be desired for all orderers and peers running v1.0.x,
        # but the modification of which would cause incompatibilities.  Users
        # should leave this flag set to true.
        V1_1: true

    # Orderer capabilities apply only to the orderers, and may be safely
    # manipulated without concern for upgrading peers.  Set the value of the
    # capability to true to require it.
    Orderer: &OrdererCapabilities
        # V1.1 for Order is a catchall flag for behavior which has been
        # determined to be desired for all orderers running v1.0.x, but the
        # modification of which  would cause incompatibilities.  Users should
        # leave this flag set to true.
        V1_1: true

    # Application capabilities apply only to the peer network, and may be safely
    # manipulated without concern for upgrading orderers.  Set the value of the
    # capability to true to require it.
    Application: &ApplicationCapabilities
        # V1.2 for Application is a catchall flag for behavior which has been
        # determined to be desired for all peers running v1.0.x, but the
        # modification of which would cause incompatibilities.  Users should
        # leave this flag set to true.
        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 is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

################################################################################
#
#   SECTION: Orderer
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for orderer related parameters
#
################################################################################
Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    # Available types are "solo" and "kafka"
    OrdererType: solo

    Addresses:
        - orderer.itcast.com:7050

Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    # Available types are "solo" and "kafka"
    OrdererType: solo

    Addresses:
        - orderer.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: 100

        # Absolute Max Bytes: The absolute maximum number of bytes allowed for
        # the serialized messages in a batch.
        AbsoluteMaxBytes: 32 MB

        # Preferred Max Bytes: The preferred maximum number of bytes allowed for
        # the serialized messages in a batch. A message larger than the preferred
        # max bytes will result in a batch larger than preferred max bytes.
        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 is the list of orgs which are defined as participants on
    # the orderer side of the network
    Organizations:

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

    Genesis:
        Capabilities:
            <<: *ChannelCapabilities
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *OrgGo
                    - *OrgCpp
    Channel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *OrgGo
                - *OrgCpp
            Capabilities:
                <<: *ApplicationCapabilities

# 2.3 文件生成

  • 生成创始块文件

    # 创始块文件的名字自己指定, 后缀 block
    $ configtxgen -profile Genesis -outputBlock genesis.block
    
  • 生成通道文件

    # 通道文件名字字节指定, 后缀 tx
    # -channelID 对应的通道名, 如果没有指定, 会使用默认的名字 -> mychannel
    $ configtxgen -profile Channel -outputCreateChannelTx channel.tx -channelID itcastchannel
    
  • 生成锚节点更新文件 -> 这个操作可选, 不是必须做的, 锚节点发生变化, 必须要做

    $ configtxgen -profile Channel -outputAnchorPeersUpdate goAnchorPeer.tx -channelID itcastchannel -asOrg OrgGo[这是组织名]
    # 更新cpp组织
    configtxgen -profile Channel -outputAnchorPeersUpdate cppAnchorPeer.tx -channelID itcastchannel -asOrg OrgCpp
    

# 3. docker-compose启动容器

# 3.1 orderer节点使用的环境变量

ORDERER_GENERAL_LOGLEVEL
 - 日志级别, 级别越高, 写的日志越少
 - `critical | error | warning | notice | info | debug
ORDERER_GENERAL_LISTENADDRESS
 - 当前orderer节点监听的地址, 指定当前orderer节点对应的主机地址即可, 也可以写0.0.0.0 == 自动绑定
ORDERER_GENERAL_GENESISMETHOD
 - 生成创始区块的时候, 数据来源
 - 帮赋值为 file, 数据来自于文件
ORDERER_GENERAL_GENESISFILE
 - 创始块文件, 从宿主机挂载到orderer节点的
ORDERER_GENERAL_LOCALMSPID
 - 当前orderer节点的组织ID, 从configtx.yaml中找
ORDERER_GENERAL_LOCALMSPDIR
 - 当前orderer节点的msp账号目录
 - crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp
ORDERER_GENERAL_TLS_ENABLED
 - 通信过程中是否需要加密, 值: true/false
ORDERER_GENERAL_TLS_PRIVATEKEY
 - TLS通信使用的私钥
ORDERER_GENERAL_TLS_CERTIFICATE
 - TLS通信的证书文件
ORDERER_GENERAL_TLS_ROOTCAS
 - TLS通信的根证书
查找目录参考:
crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls

# 3.2 peer节点使用的环境变量

CORE_PEER_ID
 - 当前peer节点的名字, 随便起名
CORE_PEER_ADDRESS
 - 当前peer节点的地址, 书写格式: IP/域名:端口(7051)
CORE_PEER_GOSSIP_BOOTSTRAP
 - 当前节点连接那个节点进行数据传播
 - 值是一个节点的地址: ip/域名:端口
 - 如果当前peer节点是组织中启动的第一个节点: 需要指定自己的地址
 - 如果当前peer节点不是组织中启动的第一个节点: 可以是自己, 或者是当前组织中任意其他节点
CORE_PEER_GOSSIP_EXTERNALENDPOINT
 - 设置当前节点是否被外部感知
 - 值就是当前节点的地址: IP/域名:端口(7051)
CORE_PEER_LOCALMSPID
 - 当前节点所属的组织的组织ID
 - 在configtx.yaml
CORE_VM_ENDPOINT
 - 对应是本地的一个套接字文件: docker.sock, 这个文件是给docker服务器使用的
 - 值是固定的: unix:///host/var/run/docker.sock
CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE
 - 容器启动所在的网络的名字
 - 通过docker network ls 查看
CORE_LOGGING_LEVEL
 - 日志级别
CORE_PEER_TLS_ENABLED
 - 是否使用tls加密
CORE_PEER_GOSSIP_USELEADERELECTION
 - 是不是自动选择leader节点
 - leader节点: 代表组织和orderer节点通信
 - 选择leader节点有两种方式: 
    - 系统选择: 选择的挂了, 重新选择一个
    - 手动指定: 指定的挂了, leader节点就没有了
 - true: 系统选择, false: 手动指定
CORE_PEER_GOSSIP_ORGLEADER
 - 当前peer节点是不是leader节点
 - 值true/false
 - 如果CORE_PEER_GOSSIP_USELEADERELECTION=true
  	CORE_PEER_GOSSIP_ORGLEADER = false
 - 如果CORE_PEER_GOSSIP_USELEADERELECTION=false
    CORE_PEER_GOSSIP_ORGLEADER = true -> 在某一个节点中指定为true, 其余false
CORE_PEER_PROFILE_ENABLED
 - 值为true/fasle
 - 在peer内部又一PROFILE服务器, 指定这个服务器默认开启还是关闭, 一般设置为true
CORE_PEER_TLS_CERT_FILE
 - tls通信使用的证书
CORE_PEER_TLS_KEY_FILE
 - tls通信私钥文件
CORE_PEER_TLS_ROOTCERT_FILE
 - tls根证书文件

# 3.3 客户端节点使用的环境变量

GOPATH
 - 在客户端容器中 go 的工作目录
CORE_VM_ENDPOINT
 - 对用宿主机的本地套接字文件 docker.sock
 - unix:///host/var/run/docker.sock, 值 是固定的
CORE_LOGGING_LEVEL
 - 客户端日志级别
CORE_PEER_ID
 - 当前客户端节点的名字, 字节起名
CORE_PEER_ADDRESS
 - 当前客户端要连接的peer节点的地址
 - IP/域名:端口[7051]
CORE_PEER_LOCALMSPID
 - 要连接的peer节点所属的组织的组织ID
CORE_PEER_TLS_ENABLED
 - 通信的时候是不是使用tls加密
CORE_PEER_TLS_CERT_FILE
 - tls通信的证书
CORE_PEER_TLS_KEY_FILE
 - tls通信使用的私钥文件
CORE_PEER_TLS_ROOTCERT_FILE
 - tls通信根证书文件
CORE_PEER_MSPCONFIGPATH
 - 访问peer节点对用的用户的账号信息
 - 示例目录: crypto-config/peerOrganizations/orggo.example.com/users/Admin@orggo.example.com/msp

# 3.4 配置文件编写

# docker-compose.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer.itcast.com:
  peer0.orggo.itcast.com:
  peer1.orggo.itcast.com:
  peer0.orgcpp.itcast.com:
  peer1.orgcpp.itcast.com:

networks:
  byfn:

services:

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

  peer0.orggo.itcast.com:
    container_name: peer0.orggo.itcast.com
    extends:
      file:  docker-compose-base.yaml
      service: peer0.orggo.itcast.com
    networks:
      - byfn

  peer1.orggo.itcast.com:
    container_name: peer1.orggo.itcast.com
    extends:
      file:  docker-compose-base.yaml
      service: peer1.orggo.itcast.com
    networks:
      - byfn

  peer0.orgcpp.itcast.com:
    container_name: peer0.orgcpp.itcast.com
    extends:
      file:  docker-compose-base.yaml
      service: peer0.orgcpp.itcast.com
    networks:
      - byfn

  peer1.orgcpp.itcast.com:
    container_name: peer1.orgcpp.itcast.com
    extends:
      file:  docker-compose-base.yaml
      service: peer1.orgcpp.itcast.com
    networks:
      - byfn

  cli:
    container_name: cli
    image: hyperledger/fabric-tools
    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/
        - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - orderer.itcast.com
      - peer0.orggo.itcast.com
      - peer1.orggo.itcast.com
      - peer0.orgcpp.itcast.com
      - peer1.orgcpp.itcast.com
    networks:
      - byfn

# docker-compose-base.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

services:

  orderer.itcast.com:
    container_name: orderer.itcast.com
    image: hyperledger/fabric-orderer
    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=OrgOrdererMSP
      - 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/itcast.com/orderers/orderer.itcast.com/msp:/var/hyperledger/orderer/msp
    - ./crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/tls/:/var/hyperledger/orderer/tls
    - orderer.itcast.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.itcast.com/peers/peer0.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ./crypto-config/peerOrganizations/orggo.itcast.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=peer0.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=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgCppMSP
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ./crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer1.orgcpp.itcast.com:/var/hyperledger/production
    ports:
      - 10051:7051
      - 10053:7053

# peer-base.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

services:
  peer-base:
    image: hyperledger/fabric-peer
    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
      - 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

# 3.5 启动容器

# 启动
$ docker-compose up -d
Creating network "itcast_byfn" with the default driver
Creating volume "itcast_peer1.orggo.itcast.com" with default driver
Creating volume "itcast_peer0.orgcpp.itcast.com" with default driver
Creating volume "itcast_orderer.itcast.com" with default driver
Creating volume "itcast_peer0.orggo.itcast.com" with default driver
Creating volume "itcast_peer1.orgcpp.itcast.com" with default driver
Creating peer0.orgcpp.itcast.com ... done
Creating peer1.orgcpp.itcast.com ... done
Creating peer0.orggo.itcast.com  ... done
Creating peer1.orggo.itcast.com  ... done
Creating orderer.itcast.com      ... done
Creating cli                     ... done
# 容器查看
$ docker-compose ps
         Name                 Command       State                        Ports                      
----------------------------------------------------------------------------------------------------
cli                       /bin/bash         Up                                                      
orderer.itcast.com        orderer           Up      0.0.0.0:7050->7050/tcp                          
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

# 关闭
$ docker-compose down -v   
Stopping cli                     ... done
Stopping peer1.orggo.itcast.com  ... done
Stopping orderer.itcast.com      ... done
Stopping peer0.orgcpp.itcast.com ... done
Stopping peer1.orgcpp.itcast.com ... done
Stopping peer0.orggo.itcast.com  ... done
Removing cli                     ... done
Removing peer1.orggo.itcast.com  ... done
Removing orderer.itcast.com      ... done
Removing peer0.orgcpp.itcast.com ... done
Removing peer1.orgcpp.itcast.com ... done
Removing peer0.orggo.itcast.com  ... done
Removing network itcast_byfn
Removing volume itcast_peer1.orggo.itcast.com
Removing volume itcast_peer0.orgcpp.itcast.com
Removing volume itcast_orderer.itcast.com
Removing volume itcast_peer0.orggo.itcast.com
Removing volume itcast_peer1.orgcpp.itcast.com
go@kevin:~/itcast$ docker-compose up -d
Creating network "itcast_byfn" with the default driver
Creating volume "itcast_peer1.orggo.itcast.com" with default driver
Creating volume "itcast_peer0.orgcpp.itcast.com" with default driver
Creating volume "itcast_orderer.itcast.com" with default driver
Creating volume "itcast_peer0.orggo.itcast.com" with default driver
Creating volume "itcast_peer1.orgcpp.itcast.com" with default driver
Creating peer0.orgcpp.itcast.com ... done
Creating peer1.orgcpp.itcast.com ... done
Creating peer0.orggo.itcast.com  ... done
Creating peer1.orggo.itcast.com  ... done
Creating orderer.itcast.com      ... done
Creating cli                     ... done
WARNING: The COMPOSE_PROJECT_NAME variable is not set. Defaulting to a blank string.
Creating network "itcast_byfn" with the default driver
Creating volume "itcast_peer1.orggo.itcast.com" with default driver
Creating volume "itcast_peer0.orgcpp.itcast.com" with default driver
Creating volume "itcast_orderer.itcast.com" with default driver
Creating volume "itcast_peer0.orggo.itcast.com" with default driver
Creating volume "itcast_peer1.orgcpp.itcast.com" with default driver
-- 创建的网络命名:
 - 根据当前docker-compose启动的目录来对网络进行命名的
CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=itcast_byfn  -> 创建出来的网络名

# 4. Peer操作

对peer节点的操作, 都是通过客户端连接对应的peer节点,

  • 完成通道的创建
  • 加入通道
  • 安装链码
  • 初始化链码
  • 链码调用
  • 数据查询

而不是直接进入到peer节点上进行操作的

docker exec -it peer节点容器名 bash -> 不这样操作

首先要进入到客户端容器中

docker exec -it cli bash

通过客户端连接到任意一个peer节点上就可以进行创建通道的操作了

# 4.1 创建通道

# 通道创建操作, 只需要操作一次
# 创建通道的操作执行一次就可以了, 执行完成之后, 会生成一个通道文件
$ peer channel create [flags], 常用参数为:
	`-o, --orderer: orderer节点的地址
	`-c, --channelID: 要创建的通道的ID, 必须小写, 在250个字符以内
	`-f, --file: 由configtxgen 生成的通道文件, 用于提交给orderer
	-t, --timeout: 创建通道的超时时长, 默认为5s
	`--tls: 通信时是否使用tls加密
	`--cafile: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径.
# orderer节点pem格式的tls证书文件路径参考: 
crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem

$ peer channel create -o orderer节点地址[orderer.itcast.com:7050] -c itcastchannel -f channel.tx --tls true --cafile 
	-o: orderer节点地址, orderer.itcast.com:7050
	-c: itcastchannel
	-f: 通道文件, ./channel-artifacts/channel.tx -> 容器路径
	--tls: true/false
	--cafile: 根据容器路径进行查找, 要用绝对路径

CAFILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem
$ peer channel create -o orderer.itcast.com:7050 -c itcastchannel -f ./channel-artifacts/channel.tx --tls true --cafile $CAFILE

$ root@f409ce0ade91:/opt/gopath/src/github.com/hyperledger/fabric/peer# ls
channel-artifacts  crypto  `itcastchannel.block -> 通道创建成功之后, 生成的文件

# 4.2 加入通道

# 当前网络中所有peer节点都需要加入到通道中, 都是通过客户端操作来完成的
$ peer channel join[flags], 常用参数为:
	`-b, --blockpath: 通过 peer channel create 命令生成的通道文件 
$ peer channel join -b itcastchannel.block -> 当前节点加入到了通道中

# 4.3 更新锚节点

# 当前组织的锚节点发生变化的时候, 才需要更新
# 每个组织的锚节点更新需要依次做
$ peer channel update [flags], 常用参数为:
	`-o, --orderer: orderer节点的地址
	`-c, --channelID: 要创建的通道的ID, 必须小写, 在250个字符以内
	`-f, --file: 由configtxgen 生成的组织锚节点文件, 用于提交给orderer
	`--tls: 通信时是否使用tls加密
	`--cafile: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径.
$ peer channel update -o orderer.itcast.com:7050 -c itcastchannel -f ./channel-artifacts/goAnchorPeer.tx --tls true --cafile $CAFILE

# 4.4 安装链码

# 每个peer节点都需要安装链码, 链码安装完成, peer节点才能根据业务逻辑对账本进程操作
$ peer chaincode install [flags], 常用参数为:
	-c, --ctor: JSON格式的构造参数, 默认是"{}"
	`-l, --lang: 编写chaincode的编程语言, 默认值是 golang
	`-n, --name: chaincode的名字
	`-p, --path: chaincode源代码的目录, 从 $GOPATH/src 路径后开始写
	`-v, --version: 当前操作的chaincode的版本, 适用这些命令install/instantiate/upgrade
$ peer chaincode install -l golang -n itcastcc -p github.com/chaincode -v v1.0

# 4.5 链码初始化

背书策略:

  • 背书: 交易被确认的过程
  • fabric网络中交易执行需要先模拟交易, 模拟交易的过程就是背书的过程, 这个过程会按照指定的背书策略来执行

两个组织,

  • go
    • peer0.orggo.itcast.com
    • peer1.orggo.itcast.com
  • cpp
    • peer0.orgcpp.itcast.com
    • peer1.orgcpp.itcast.com

交易方式:

  • Go组织里边的节点同意, 即可完成

    OR (go组织.成员)

    ​ 组织ID.member

  • Cpp组织里边的节点同意, 即可完成

    OR(cpp组织.成员)

  • Go组织和Cpp组织里边的节点同意, 即可完成

    AND (go组织.成员, cpp组织.成员)

# 链码的初始化, 只需要做一次
$ peer chaincode instantiate [flags], 常用参数为:
	`-o, --orderer: orderer节点的地址
	`-C,--channelID:当前命令运行的通道,默认值是“testchainid"。
	`-c, --ctor:JSON格式的构造参数,默认值是“{}"
	`-l,--lang:编写Chaincode的编程语言,默认值是golang
	`-n,--name:Chaincode的名字。
	`-P,--policy:当前Chaincode的背书策略。
	`-v,--version:当前操作的Chaincode的版本,适用于install/instantiate/upgrade等命令
	`--tls: 通信时是否使用tls加密
	`--cafile: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径.
 $ peer chaincode instantiate -o orderer.itcast.com:7050 -C itcastchannel -l golang -n itcastcc -v v1.0 --tls true --cafile $CAFILE -P "AND ('OrgGoMSP.member', 'OrgCppMSP.member')" -c '{"Args":["init", "a", "100", "b", "200"]}'
   - init -> 链码中的初始化函数
   - "a", "100", "b", "200" -> init函数的参数
   - 链码中的操作:
     "a":100
     "b":200
     将这两个数据写入账本中
     
CAFILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem
peer chaincode instantiate -o orderer.itcast.com:7050 -C testchannel -l golang -n testcc -v 1.0 --tls true --cafile $CAFILE -P "AND ('OrgGoMSP.member', 'OrgCppMSP.member')" -c '{"Args":["init", "a", "100", "b", "200"]}'     

# 4.6 查询

$ peer chaincode query [flags], 常用参数为:
	`-n,--name:Chaincode的名字。
	`-C,--channelID:当前命令运行的通道,默认值是“testchainid"
	`-c, --ctor:JSON格式的构造参数,默认值是“{}"
	-x,--hex:是否对输出的内容进行编码处理
	-r,--raw:是否输出二进制内容
	-t, --tid: 指定当前查询的编号
$ peer chaincode query -n itcastcc -C itcastchannel -c '{"Args":["query", "a"]}'

# 4.7 交易

$ peer chaincode invoke [flags], 常用参数为:
	`-o, --orderer: orderer节点的地址
	`-C,--channelID:当前命令运行的通道,默认值是“testchainid"
	`-c, --ctor:JSON格式的构造参数,默认值是“{}"
	`-n,--name:Chaincode的名字
	`--tls: 通信时是否使用tls加密
	`--cafile: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径.
	`--peerAddresses: 指定要连接的peer节点的地址
	`--tlsRootCertFiles: 连接的peer节点的TLS根证书, 必须是绝对路径
# 连接的peer节点的TLS根证书查找路径参考:
/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
# example
# -c '{"Args":["invoke","a","b","10"]}'
ROORCERT1=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
ROORCERT2=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/ca.crt
$ peer chaincode invoke -o orderer.itcast.com:7050 --tls true --cafile $CAFILE -C itcastchannel -n itcastcc -c '{"Args":["invoke","a","b","10"]}' --peerAddresses peer0.orggo.itcast.com:7051 --tlsRootCertFiles $ROORCERT1 --peerAddresses peer1.orgcpp.itcast.com:7051 --tlsRootCertFiles $ROORCERT2

# 因为只给一个节点安装了链码
Error: error endorsing invoke: rpc error: code = Unknown desc = access denied: channel [itcastchannel] creator org [OrgGoMSP] - proposal response: <nil>

CAFILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem
ROORCERT1=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
ROORCERT2=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/ca.crt
peer chaincode invoke -o orderer.itcast.com:7050 --tls true --cafile $CAFILE -C testchannel -n testcc -c '{"Args":["invoke","a","b","10"]}' --peerAddresses peer0.orggo.itcast.com:7051 --tlsRootCertFiles $ROORCERT1 --peerAddresses peer0.orgcpp.itcast.com:7051 --tlsRootCertFiles $ROORCERT2

# 5. 通过客户端切换操作的节点

# 看docker-compose 配置文件中关于 客户端容器的设置 -> 环境变量
- CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051 # 客户端连接的peer节点
- 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
  • go组织的peer0

    export CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
    export CORE_PEER_LOCALMSPID=OrgGoMSP
    export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/Admin@orggo.itcast.com/msp
    export 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
    export 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
    export 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
    
  • go组织的peer1

    export CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051
    export CORE_PEER_LOCALMSPID=OrgGoMSP
    export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/Admin@orggo.itcast.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/ca.crt
    export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/server.crt
    export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/server.key
    
  • cpp组织的peer0

    export CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051
    export CORE_PEER_LOCALMSPID=OrgCppMSP
    export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/users/Admin@orgcpp.itcast.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/ca.crt
    export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/server.crt
    export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/server.key
    
  • cpp组织的peer1

    export CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051
    export CORE_PEER_LOCALMSPID=OrgCppMSP
    export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/users/Admin@orgcpp.itcast.com/msp
    export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/ca.crt
    export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/server.crt
    export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/server.key
    
上次更新: 6/21/2023, 2:56:12 AM