【2020年11月】Hyperledger Fabricのtest-networkをlocalhost外から繋がるように調整したった。

# Hyperledger Fabricのtest-networkをlocalhost外から繋がるようにしたい。

Hyperledger Fabricの入り口、[fabric-samples](https://github.com/hyperledger/fabric-samples)のtest-networkなのですが、これは`localhost`からの接続専用で他のマシンからつなぐことはできません。

チームでブロックチェーンアプリを開発する場合、各人がそれぞれHyperledgerのネットワークを立ち上げるのはマシンリソースの無駄でございます。

そこで社内ネットワークから接続可能なHyperledgerネットワークを立ち上げてみたいと思います。

以下で test-network をlocalhost以外のドメインに対応させる~~奮戦記~~手順をご紹介したいと思います。

## 前提条件

今回はDNSチャレンジでもちゃんと通るSSL用のワイルドカードドメイン `sslip.io`[^1]を使用し、実際にはドメイン名のないIPアドレスだけの社内ネットでちゃんと使えるドメインの設定をやってまいります。

また今回は`network.sh`を叩く際に"-ca"オプションを使用するので、`CRYPTO="Certificate Authorities"`の処理を使用します。`CRYPTO = "cryptogen"`側の処理は実施しないので、**`organizations/cryptogen`以下の設定ファイルは使用しません**。

また今回はとりあえず動かすのを目標とするので"Org3"を追加するスクリプトや設定はいじりません。

それではやっていきましょう！

[^1]: SSL用ダイナミックドメインの[https://sslip.io/](https://sslip.io/) は[https://192.168.1.5.sslip.io](https://192.168.1.5.sslip.io)でも同じサイトにアクセスされます。

# 1. docker-compose の修正
まずそもそものタネであるdockerコンテナの設定をいじります。
コンテナに設定できる環境変数などはdockerhubなどのマニュアルをご覧いただくのが手っ取り早いかと思います。[^2]

[^2]: Peerのコンテナは→ https://hub.docker.com/r/hyperledger/fabric-peer 、CAについては→ https://hyperledger-fabric-ca.readthedocs.io/en/release-1.4/operations_guide.html の熟読がおすすめです。

## 1-1. CA
まずはCAのコンテナをいじります。

```yaml:test-network/docker/docker-compose-ca.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
  test:

services:

  ca_org1:
    image: hyperledger/fabric-ca:$IMAGE_TAG
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_NAME=ca-org1
      - FABRIC_CA_SERVER_CSR_HOSTS=localhost,10-0-1-4.sslip.io
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_PORT=7054
    ports:
      - "7054:7054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ../organizations/fabric-ca/org1:/etc/hyperledger/fabric-ca-server
    container_name: ca_org1
    networks:
      - test

  ca_org2:
    image: hyperledger/fabric-ca:$IMAGE_TAG
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_NAME=ca-org2
      - FABRIC_CA_SERVER_CSR_HOSTS=localhost,10-0-1-4.sslip.io
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_PORT=8054
    ports:
      - "8054:8054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ../organizations/fabric-ca/org2:/etc/hyperledger/fabric-ca-server
    container_name: ca_org2
    networks:
      - test

  ca_orderer:
    image: hyperledger/fabric-ca:$IMAGE_TAG
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_NAME=ca-orderer
      - FABRIC_CA_SERVER_CSR_HOSTS=localhost,10-0-1-4.sslip.io
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_PORT=9054
    ports:
      - "9054:9054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ../organizations/fabric-ca/ordererOrg:/etc/hyperledger/fabric-ca-server
    container_name: ca_orderer
    networks:
      - test
```
環境変数の`FABRIC_CA_SERVER_CSR_HOSTS`を追加してCSRで受付可能なドメイン名を指定します。ここで指定される`10-0-1-4.sslip.io`を社内サーバーのIPアドレスに置き換えてください。
この設定で後ほど`fabric-ca-client`コマンドからリクエストするSSL証明書のドメインに許可を与えています。

## 1-2. Orderer,Peer

続いてOrder,Peerコンテナの設定を修正します。以下のようにいたしました。

```yaml:test-network/docker/docker-compose-test-net.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: "2"

volumes:
  orderer.10-0-1-4.sslip.io:
  peer0.org1.10-0-1-4.sslip.io:
  peer0.org2.10-0-1-4.sslip.io:

networks:
  test:

services:
  orderer.10-0-1-4.sslip.io:
    container_name: orderer.10-0-1-4.sslip.io
    image: hyperledger/fabric-orderer:$IMAGE_TAG
    environment:
      - FABRIC_LOGGING_SPEC=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_LISTENPORT=7050
      - 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]
      - 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
    volumes:
      - ../system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
      - ../organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp:/var/hyperledger/orderer/msp
      - ../organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/:/var/hyperledger/orderer/tls
      - orderer.10-0-1-4.sslip.io:/var/hyperledger/production/orderer
    ports:
      - 7050:7050
    networks:
      - test

  peer0.org1.10-0-1-4.sslip.io:
    container_name: peer0.org1.10-0-1-4.sslip.io
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      #Generic peer variables
      - 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}_test
      - FABRIC_LOGGING_SPEC=INFO
      #- FABRIC_LOGGING_SPEC=DEBUG
      - CORE_PEER_TLS_ENABLED=true
      - 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
      # Peer specific variabes
      - CORE_PEER_ID=peer0.org1.10-0-1-4.sslip.io
      - CORE_PEER_ADDRESS=peer0.org1.10-0-1-4.sslip.io:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org1.10-0-1-4.sslip.io:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.10-0-1-4.sslip.io:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.10-0-1-4.sslip.io:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
      - /var/run/:/host/var/run/
      - ../organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/msp:/etc/hyperledger/fabric/msp
      - ../organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls:/etc/hyperledger/fabric/tls
      - peer0.org1.10-0-1-4.sslip.io:/var/hyperledger/production
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    ports:
      - 7051:7051
    networks:
      - test

  peer0.org2.10-0-1-4.sslip.io:
    container_name: peer0.org2.10-0-1-4.sslip.io
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      #Generic peer variables
      - 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}_test
      - FABRIC_LOGGING_SPEC=INFO
      #- FABRIC_LOGGING_SPEC=DEBUG
      - CORE_PEER_TLS_ENABLED=true
      - 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
      # Peer specific variabes
      - CORE_PEER_ID=peer0.org2.10-0-1-4.sslip.io
      - CORE_PEER_ADDRESS=peer0.org2.10-0-1-4.sslip.io:9051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:9051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org2.10-0-1-4.sslip.io:9052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.10-0-1-4.sslip.io:9051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.10-0-1-4.sslip.io:9051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
      - /var/run/:/host/var/run/
      - ../organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/msp:/etc/hyperledger/fabric/msp
      - ../organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls:/etc/hyperledger/fabric/tls
      - peer0.org2.10-0-1-4.sslip.io:/var/hyperledger/production
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    ports:
      - 9051:9051
    networks:
      - test
```
`example.com`を`10-0-1-4.sslip.io`に全置換でOKかと思いますが、キモはコンテナ間でも`grpc://peer0.org2.10-0-1-4.sslip.io`のURLなどで通信できるように、コンテナ名にも`peer0.org2.10-0-1-4.sslip.io`というドメイン名込みの名前を当てております。

# 2. configtx.yaml の修正

引き続き`configtx.yaml`の修正を行います。

```yaml:test-network/configtx/configtx.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

---
...
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: OrdererOrg

        # ID to load the MSP definition as
        ID: OrdererMSP

        # MSPDir is the filesystem path which contains the MSP configuration
        MSPDir: ../organizations/ordererOrganizations/10-0-1-4.sslip.io/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('OrdererMSP.admin')"

        OrdererEndpoints:
            - orderer.10-0-1-4.sslip.io:7050

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

        # ID to load the MSP definition as
        ID: Org1MSP

        MSPDir: ../organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org1MSP.peer')"

        # leave this flag set to true.
        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.org1.10-0-1-4.sslip.io
              Port: 7051

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

        # ID to load the MSP definition as
        ID: Org2MSP

        MSPDir: ../organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org2MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org2MSP.peer')"

        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.org2.10-0-1-4.sslip.io
              Port: 9051

...
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.
    Channel: &ChannelCapabilities
        # V2_0 capability ensures that orderers and peers behave according
        # to v2.0 channel capabilities. Orderers and peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 capability.
        # Prior to enabling V2.0 channel capabilities, ensure that all
        # orderers and peers on a channel are at v2.0.0 or later.
        V2_0: true

    # Orderer capabilities apply only to the orderers, and may be safely
    # used with prior release peers.
    # Set the value of the capability to true to require it.
    Orderer: &OrdererCapabilities
        # V2_0 orderer capability ensures that orderers behave according
        # to v2.0 orderer capabilities. Orderers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 orderer capability.
        # Prior to enabling V2.0 orderer capabilities, ensure that all
        # orderers on channel are at v2.0.0 or later.
        V2_0: true

    # Application capabilities apply only to the peer network, and may be safely
    # used with prior release orderers.
    # Set the value of the capability to true to require it.
    Application: &ApplicationCapabilities
        # V2_0 application capability ensures that peers behave according
        # to v2.0 application capabilities. Peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 application capability.
        # Prior to enabling V2.0 application capabilities, ensure that all
        # peers on channel are at v2.0.0 or later.
        V2_0: true
...
Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities
...
Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    OrdererType: etcdraft
    
    # Addresses used to be the list of orderer addresses that clients and peers
    # could connect to.  However, this does not allow clients to associate orderer
    # addresses and orderer organizations which can be useful for things such
    # as TLS validation.  The preferred way to specify orderer addresses is now
    # to include the OrdererEndpoints item in your org definition
    Addresses:
        - orderer.10-0-1-4.sslip.io:7050

    EtcdRaft:
        Consenters:
        - Host: orderer.10-0-1-4.sslip.io
          Port: 7050
          ClientTLSCert: ../organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/server.crt
          ServerTLSCert: ../organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/server.crt

    # 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

        # Absolute Max Bytes: The absolute maximum number of bytes allowed for
        # the serialized messages in a batch.
        AbsoluteMaxBytes: 99 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

    # Organizations is the list of orgs which are defined as participants on
    # the orderer side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Orderer policies, their canonical path is
    #   /Channel/Orderer/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        # BlockValidation specifies what signatures must be included in the block
        # from the orderer for the peer to validate it.
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"

...
Channel: &ChannelDefaults
    # Policies defines the set of policies at this level of the config tree
    # For Channel policies, their canonical path is
    #   /Channel/<PolicyName>
    Policies:
        # Who may invoke the 'Deliver' API
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        # Who may invoke the 'Broadcast' API
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        # By default, who may modify elements at this config level
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"

    # Capabilities describes the channel level capabilities, see the
    # dedicated Capabilities section elsewhere in this file for a full
    # description
    Capabilities:
        <<: *ChannelCapabilities

...
Profiles:

    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
    TwoOrgsChannel:
        Consortium: SampleConsortium
        <<: *ChannelDefaults
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
            Capabilities:
                <<: *ApplicationCapabilities

```
ここも`example.com`を`10-0-1-4.sslip.io`に全置換でOKかと思います。

# 3. organizations以下の設定ファイル・スクリプトの修正

前提条件で挙げたように`organizations/cryptogen`は使用せず、以降では`fabric-ca`以下のスクリプトを修正していきます。

## 3-1. registerEnroll.sh の修正

OrdererやPeerのユーザーを登録する`registerEnroll.sh`を修正します。

```shell:test-network/organizations/fabric-ca/registerEnroll.sh
#!/bin/bash

source scriptUtils.sh

function createOrg1() {

  infoln "createOrg1 :: Enroll the CA admin"
  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/

  export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/
  #  rm -rf $FABRIC_CA_CLIENT_HOME/fabric-ca-client-config.yaml
  #  rm -rf $FABRIC_CA_CLIENT_HOME/msp

  set -x
  fabric-ca-client enroll -u https://admin:adminpw@10-0-1-4.sslip.io:7054 --caname ca-org1 --csr.hosts 'localhost,org1,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  echo 'NodeOUs:
  Enable: true
  ClientOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-7054-ca-org1.pem
    OrganizationalUnitIdentifier: client
  PeerOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-7054-ca-org1.pem
    OrganizationalUnitIdentifier: peer
  AdminOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-7054-ca-org1.pem
    OrganizationalUnitIdentifier: admin
  OrdererOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-7054-ca-org1.pem
    OrganizationalUnitIdentifier: orderer' >${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/config.yaml

  infoln "Register peer0"
  set -x
  fabric-ca-client register --caname ca-org1 --id.name peer0 --id.secret peer0pw --id.type peer --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  infoln "Register user"
  set -x
  fabric-ca-client register --caname ca-org1 --id.name user1 --id.secret user1pw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  infoln "Register the org admin"
  set -x
  fabric-ca-client register --caname ca-org1 --id.name org1admin --id.secret org1adminpw --id.type admin --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers
  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io

  infoln "Generate the peer0 msp"
  set -x
  fabric-ca-client enroll -u https://peer0:peer0pw@10-0-1-4.sslip.io:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/msp --csr.hosts peer0.org1.10-0-1-4.sslip.io --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/msp/config.yaml

  infoln "Generate the peer0-tls certificates"
  set -x
  fabric-ca-client enroll -u https://peer0:peer0pw@10-0-1-4.sslip.io:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls --enrollment.profile tls --csr.hosts peer0.org1.10-0-1-4.sslip.io --csr.hosts localhost --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/ca.crt
  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/signcerts/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/server.crt
  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/keystore/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/server.key

  mkdir -p ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/tlscacerts
  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/tlscacerts/ca.crt

  mkdir -p ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/tlsca
  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/tlsca/tlsca.org1.10-0-1-4.sslip.io-cert.pem

  mkdir -p ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/ca
  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/msp/cacerts/* ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/ca/ca.org1.10-0-1-4.sslip.io-cert.pem

  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users
  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/User1@org1.10-0-1-4.sslip.io

  infoln "Generate the user msp"
  set -x
  fabric-ca-client enroll -u https://user1:user1pw@10-0-1-4.sslip.io:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/User1@org1.10-0-1-4.sslip.io/msp --csr.hosts 'localhost,org1,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/User1@org1.10-0-1-4.sslip.io/msp/config.yaml

  mkdir -p organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/Admin@org1.10-0-1-4.sslip.io

  infoln "Generate the org admin msp"
  set -x
  fabric-ca-client enroll -u https://org1admin:org1adminpw@10-0-1-4.sslip.io:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/Admin@org1.10-0-1-4.sslip.io/msp --csr.hosts 'localhost,org1,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/Admin@org1.10-0-1-4.sslip.io/msp/config.yaml

}

function createOrg2() {

  infoln "createOrg2 :: Enroll the CA admin"
  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/

  export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/
  #  rm -rf $FABRIC_CA_CLIENT_HOME/fabric-ca-client-config.yaml
  #  rm -rf $FABRIC_CA_CLIENT_HOME/msp

  set -x
  fabric-ca-client enroll -u https://admin:adminpw@10-0-1-4.sslip.io:8054 --caname ca-org2 --csr.hosts 'localhost,org2,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  echo 'NodeOUs:
  Enable: true
  ClientOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-8054-ca-org2.pem
    OrganizationalUnitIdentifier: client
  PeerOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-8054-ca-org2.pem
    OrganizationalUnitIdentifier: peer
  AdminOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-8054-ca-org2.pem
    OrganizationalUnitIdentifier: admin
  OrdererOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-8054-ca-org2.pem
    OrganizationalUnitIdentifier: orderer' >${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/config.yaml

  infoln "Register peer0"
  set -x
  fabric-ca-client register --caname ca-org2 --id.name peer0 --id.secret peer0pw --id.type peer --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  infoln "Register user"
  set -x
  fabric-ca-client register --caname ca-org2 --id.name user1 --id.secret user1pw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  infoln "Register the org admin"
  set -x
  fabric-ca-client register --caname ca-org2 --id.name org2admin --id.secret org2adminpw --id.type admin --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers
  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io

  infoln "Generate the peer0 msp"
  set -x
  fabric-ca-client enroll -u https://peer0:peer0pw@10-0-1-4.sslip.io:8054 --caname ca-org2 -M ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/msp --csr.hosts peer0.org2.10-0-1-4.sslip.io --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/msp/config.yaml

  infoln "Generate the peer0-tls certificates"
  set -x
  fabric-ca-client enroll -u https://peer0:peer0pw@10-0-1-4.sslip.io:8054 --caname ca-org2 -M ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls --enrollment.profile tls --csr.hosts peer0.org2.10-0-1-4.sslip.io --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/ca.crt
  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/signcerts/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/server.crt
  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/keystore/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/server.key

  mkdir -p ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/tlscacerts
  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/tlscacerts/ca.crt

  mkdir -p ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/tlsca
  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/tlsca/tlsca.org2.10-0-1-4.sslip.io-cert.pem

  mkdir -p ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/ca
  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/msp/cacerts/* ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/ca/ca.org2.10-0-1-4.sslip.io-cert.pem

  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users
  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/User1@org2.10-0-1-4.sslip.io

  infoln "Generate the user msp"
  set -x
  fabric-ca-client enroll -u https://user1:user1pw@10-0-1-4.sslip.io:8054 --caname ca-org2 -M ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/User1@org2.10-0-1-4.sslip.io/msp --csr.hosts 'localhost,org2,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/User1@org2.10-0-1-4.sslip.io/msp/config.yaml

  mkdir -p organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/Admin@org2.10-0-1-4.sslip.io

  infoln "Generate the org admin msp"
  set -x
  fabric-ca-client enroll -u https://org2admin:org2adminpw@10-0-1-4.sslip.io:8054 --caname ca-org2 -M ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/Admin@org2.10-0-1-4.sslip.io/msp --csr.hosts 'localhost,org2,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/Admin@org2.10-0-1-4.sslip.io/msp/config.yaml

}

function createOrderer() {

  infoln "createOrderer :: Enroll the CA admin"
  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io

  export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io
  #  rm -rf $FABRIC_CA_CLIENT_HOME/fabric-ca-client-config.yaml
  #  rm -rf $FABRIC_CA_CLIENT_HOME/msp

  set -x
  fabric-ca-client enroll -u https://admin:adminpw@10-0-1-4.sslip.io:9054 --caname ca-orderer --csr.hosts 'localhost,orderer,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  echo 'NodeOUs:
  Enable: true
  ClientOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-9054-ca-orderer.pem
    OrganizationalUnitIdentifier: client
  PeerOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-9054-ca-orderer.pem
    OrganizationalUnitIdentifier: peer
  AdminOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-9054-ca-orderer.pem
    OrganizationalUnitIdentifier: admin
  OrdererOUIdentifier:
    Certificate: cacerts/10-0-1-4-sslip-io-9054-ca-orderer.pem
    OrganizationalUnitIdentifier: orderer' >${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/msp/config.yaml

  infoln "Register orderer"
  set -x
  fabric-ca-client register --caname ca-orderer --id.name orderer --id.secret ordererpw --id.type orderer --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  infoln "Register the orderer admin"
  set -x
  fabric-ca-client register --caname ca-orderer --id.name ordererAdmin --id.secret ordererAdminpw --id.type admin --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers
  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/10-0-1-4.sslip.io

  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io

  infoln "Generate the orderer msp"
  set -x
  fabric-ca-client enroll -u https://orderer:ordererpw@10-0-1-4.sslip.io:9054 --caname ca-orderer -M ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp --csr.hosts 'localhost,orderer,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp/config.yaml

  infoln "Generate the orderer-tls certificates"
  set -x
  fabric-ca-client enroll -u https://orderer:ordererpw@10-0-1-4.sslip.io:9054 --caname ca-orderer -M ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls --enrollment.profile tls --csr.hosts 'localhost,orderer,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/ca.crt
  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/signcerts/* ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/server.crt
  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/keystore/* ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/server.key

  mkdir -p ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp/tlscacerts
  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp/tlscacerts/tlsca.10-0-1-4.sslip.io-cert.pem

  mkdir -p ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/msp/tlscacerts
  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/tls/tlscacerts/* ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/msp/tlscacerts/tlsca.10-0-1-4.sslip.io-cert.pem

  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io/users
  mkdir -p organizations/ordererOrganizations/10-0-1-4.sslip.io/users/Admin@10-0-1-4.sslip.io

  infoln "Generate the admin msp"
  set -x
  fabric-ca-client enroll -u https://ordererAdmin:ordererAdminpw@10-0-1-4.sslip.io:9054 --caname ca-orderer -M ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/users/Admin@10-0-1-4.sslip.io/msp --csr.hosts 'localhost,*.10-0-1-4.sslip.io' --tls.certfiles ${PWD}/organizations/fabric-ca/ordererOrg/tls-cert.pem
  { set +x; } 2>/dev/null

  cp ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/msp/config.yaml ${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/users/Admin@10-0-1-4.sslip.io/msp/config.yaml

}
```
ここでの修正でのキモはSSL証明書のCSRでlocalhost以外のホストをリクエストしている箇所です。`fabric-ca-client`の引数にて` --csr.hosts`で必要なホスト名を追記しています。
また微妙な修正ですが、`fabric-ca-client`の吐き出すpemファイルのファイル名にドメイン名が含まれますが、ピリオドがハイフンになっているのでここは注意が必要です。具体的には`msp/config.yaml`に`echo`する処理でpemのファイル名を直書きしている箇所がありますが、ここでドメインの`.sslip.io`が`-sslip-io`に置換されております。

## 3-2. ccp-generate.sh の修正

続いてコネクションプロファイルを生成する`ccp-generate.sh`の修正を行います。

```shell:test-network/organizations/ccp-generate.sh
#!/bin/bash

function one_line_pem {
    echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`"
}

function json_ccp {
    local PP=$(one_line_pem $4)
    local CP=$(one_line_pem $5)
    sed -e "s/\${ORG}/$1/" \
        -e "s/\${P0PORT}/$2/" \
        -e "s/\${CAPORT}/$3/" \
        -e "s#\${PEERPEM}#$PP#" \
        -e "s#\${CAPEM}#$CP#" \
        organizations/ccp-template.json
}

function yaml_ccp {
    local PP=$(one_line_pem $4)
    local CP=$(one_line_pem $5)
    sed -e "s/\${ORG}/$1/" \
        -e "s/\${P0PORT}/$2/" \
        -e "s/\${CAPORT}/$3/" \
        -e "s#\${PEERPEM}#$PP#" \
        -e "s#\${CAPEM}#$CP#" \
        organizations/ccp-template.yaml | sed -e $'s/\\\\n/\\\n          /g'
}

ORG=1
P0PORT=7051
CAPORT=7054
PEERPEM=organizations/peerOrganizations/org1.10-0-1-4.sslip.io/tlsca/tlsca.org1.10-0-1-4.sslip.io-cert.pem
CAPEM=organizations/peerOrganizations/org1.10-0-1-4.sslip.io/ca/ca.org1.10-0-1-4.sslip.io-cert.pem

echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.10-0-1-4.sslip.io/connection-org1.json
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.10-0-1-4.sslip.io/connection-org1.yaml

ORG=2
P0PORT=9051
CAPORT=8054
PEERPEM=organizations/peerOrganizations/org2.10-0-1-4.sslip.io/tlsca/tlsca.org2.10-0-1-4.sslip.io-cert.pem
CAPEM=organizations/peerOrganizations/org2.10-0-1-4.sslip.io/ca/ca.org2.10-0-1-4.sslip.io-cert.pem

echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.10-0-1-4.sslip.io/connection-org2.json
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.10-0-1-4.sslip.io/connection-org2.yaml

```
ここでは単に`pem`ファイルのパスを修正でOKです。

## 3-3. コネクションプロファイルテンプレートの修正

コネクションプロファイルのテンプレートである`ccp-template.json`や`ccp-template.yaml`を修正します。
`json`と`yaml`では修正内容が同じなので`json`のみ掲載します。

```json:test-network/organizations/ccp-template.json
{
    "name": "test-network-org${ORG}",
    "version": "1.0.0",
    "client": {
        "organization": "Org${ORG}",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "300"
                }
            }
        }
    },
    "organizations": {
        "Org${ORG}": {
            "mspid": "Org${ORG}MSP",
            "peers": [
                "peer0.org${ORG}.10-0-1-4.sslip.io"
            ],
            "certificateAuthorities": [
                "ca.org${ORG}.10-0-1-4.sslip.io"
            ]
        }
    },
    "peers": {
        "peer0.org${ORG}.10-0-1-4.sslip.io": {
            "url": "grpcs://peer0.org${ORG}.10-0-1-4.sslip.io:${P0PORT}",
            "tlsCACerts": {
                "pem": "${PEERPEM}"
            },
            "grpcOptions": {
                "ssl-target-name-override": "peer0.org${ORG}.10-0-1-4.sslip.io",
                "hostnameOverride": "peer0.org${ORG}.10-0-1-4.sslip.io"
            }
        }
    },
    "certificateAuthorities": {
        "ca.org${ORG}.10-0-1-4.sslip.io": {
            "url": "https://ca.org${ORG}.10-0-1-4.sslip.io:${CAPORT}",
            "caName": "ca-org${ORG}",
            "tlsCACerts": {
                "pem": [
                    "${CAPEM}"
                ]
            },
            "httpOptions": {
                "verify": false
            }
        }
    }
}
```
ドメインの`example.com`を修正するのはもちろんですが、CAやPeerのアクセス先を`localhost`から`sslip.io`に修正します。

# 4. scripts以下の修正

引き続き`scripts/`以下のファイルを修正してまいります。

## 4-1. envVar.shの修正

ここではドメイン名の全置換でOKです。

```shell:test-network/scripts/envVar.sh
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#

# This is a collection of bash functions used by different scripts

source scriptUtils.sh

export CORE_PEER_TLS_ENABLED=true
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp/tlscacerts/tlsca.10-0-1-4.sslip.io-cert.pem
export PEER0_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/peers/peer0.org1.10-0-1-4.sslip.io/tls/ca.crt
export PEER0_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/peers/peer0.org2.10-0-1-4.sslip.io/tls/ca.crt
export PEER0_ORG3_CA=${PWD}/organizations/peerOrganizations/org3.10-0-1-4.sslip.io/peers/peer0.org3.10-0-1-4.sslip.io/tls/ca.crt

# Set OrdererOrg.Admin globals
setOrdererGlobals() {
  export CORE_PEER_LOCALMSPID="OrdererMSP"
  export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/orderers/orderer.10-0-1-4.sslip.io/msp/tlscacerts/tlsca.10-0-1-4.sslip.io-cert.pem
  export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/ordererOrganizations/10-0-1-4.sslip.io/users/Admin@10-0-1-4.sslip.io/msp
}

# Set environment variables for the peer org
setGlobals() {
  local USING_ORG=""
  if [ -z "$OVERRIDE_ORG" ]; then
    USING_ORG=$1
  else
    USING_ORG="${OVERRIDE_ORG}"
  fi
  infoln "Using organization ${USING_ORG}"
  if [ $USING_ORG -eq 1 ]; then
    export CORE_PEER_LOCALMSPID="Org1MSP"
    export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.10-0-1-4.sslip.io/users/Admin@org1.10-0-1-4.sslip.io/msp
    export CORE_PEER_ADDRESS=peer0.org$1.10-0-1-4.sslip.io:7051
  elif [ $USING_ORG -eq 2 ]; then
    export CORE_PEER_LOCALMSPID="Org2MSP"
    export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.10-0-1-4.sslip.io/users/Admin@org2.10-0-1-4.sslip.io/msp
    export CORE_PEER_ADDRESS=peer0.org$1.10-0-1-4.sslip.io:9051

  elif [ $USING_ORG -eq 3 ]; then
    export CORE_PEER_LOCALMSPID="Org3MSP"
    export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG3_CA
    export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.10-0-1-4.sslip.io/users/Admin@org3.10-0-1-4.sslip.io/msp
    export CORE_PEER_ADDRESS=peer0.org$1.10-0-1-4.sslip.io:11051
  else
    errorln "ORG Unknown"
  fi

  if [ "$VERBOSE" == "true" ]; then
    env | grep CORE
  fi
}

# parsePeerConnectionParameters $@
# Helper function that sets the peer connection parameters for a chaincode
# operation
parsePeerConnectionParameters() {

  PEER_CONN_PARMS=""
  PEERS=""
  while [ "$#" -gt 0 ]; do
    setGlobals $1
    PEER="peer0.org$1"
    ## Set peer addresses
    PEERS="$PEERS $PEER"
    PEER_CONN_PARMS="$PEER_CONN_PARMS --peerAddresses $CORE_PEER_ADDRESS"
    ## Set path to TLS certificate
    TLSINFO=$(eval echo "--tlsRootCertFiles \$PEER0_ORG$1_CA")
    PEER_CONN_PARMS="$PEER_CONN_PARMS $TLSINFO"
    # shift by one to get to the next organization
    shift
  done
  # remove leading space for output
  PEERS="$(echo -e "$PEERS" | sed -e 's/^[[:space:]]*//')"
}

verifyResult() {
  if [ $1 -ne 0 ]; then
    fatalln "$2"
  fi
}
```

## 4-2. createChannel.shの修正

チャンネル生成スクリプトを修正します。

```shell:test-network/scripts/createChannel.sh
#!/bin/bash

source scriptUtils.sh

CHANNEL_NAME="$1"
DELAY="$2"
MAX_RETRY="$3"
VERBOSE="$4"
: ${CHANNEL_NAME:="mychannel"}
: ${DELAY:="3"}
: ${MAX_RETRY:="5"}
: ${VERBOSE:="false"}

# import utils
. scripts/envVar.sh

if [ ! -d "channel-artifacts" ]; then
	mkdir channel-artifacts
fi

createChannelTx() {

	set -x
	configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/${CHANNEL_NAME}.tx -channelID $CHANNEL_NAME
	res=$?
	{ set +x; } 2>/dev/null
	if [ $res -ne 0 ]; then
		fatalln "Failed to generate channel configuration transaction..."
	fi

}

createAncorPeerTx() {

	for orgmsp in Org1MSP Org2MSP; do

	infoln "Generating anchor peer update transaction for ${orgmsp}"
	set -x
	configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/${orgmsp}anchors.tx -channelID $CHANNEL_NAME -asOrg ${orgmsp}
	res=$?
	{ set +x; } 2>/dev/null
	if [ $res -ne 0 ]; then
		fatalln "Failed to generate anchor peer update transaction for ${orgmsp}..."
	fi
	done
}

createChannel() {
	setGlobals 1
	# Poll in case the raft leader is not set yet
	local rc=1
	local COUNTER=1
	while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ] ; do
		sleep $DELAY
		set -x
		peer channel create -o orderer.10-0-1-4.sslip.io:7050 -c $CHANNEL_NAME --ordererTLSHostnameOverride orderer.10-0-1-4.sslip.io -f ./channel-artifacts/${CHANNEL_NAME}.tx --outputBlock ./channel-artifacts/${CHANNEL_NAME}.block --tls --cafile $ORDERER_CA >&log.txt
		res=$?
		{ set +x; } 2>/dev/null
		let rc=$res
		COUNTER=$(expr $COUNTER + 1)
	done
	cat log.txt
	verifyResult $res "Channel creation failed"
	verifyResult $res "Received block: 0"
	successln "Channel '$CHANNEL_NAME' created"
}

# queryCommitted ORG
joinChannel() {
  ORG=$1
  setGlobals $ORG
	local rc=1
	local COUNTER=1
	## Sometimes Join takes time, hence retry
	while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ] ; do
    sleep $DELAY
    set -x
    peer channel join -b ./channel-artifacts/$CHANNEL_NAME.block >&log.txt
    res=$?
    { set +x; } 2>/dev/null
		let rc=$res
		COUNTER=$(expr $COUNTER + 1)
	done
	cat log.txt
	verifyResult $res "After $MAX_RETRY attempts, peer0.org${ORG} has failed to join channel '$CHANNEL_NAME' "
}

updateAnchorPeers() {
  ORG=$1
  setGlobals $ORG
	local rc=1
	local COUNTER=1
	## Sometimes Join takes time, hence retry
	while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ] ; do
    sleep $DELAY
    set -x
		peer channel update -o orderer.10-0-1-4.sslip.io:7050 --ordererTLSHostnameOverride orderer.10-0-1-4.sslip.io -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile $ORDERER_CA >&log.txt
    res=$?
    { set +x; } 2>/dev/null
		let rc=$res
		COUNTER=$(expr $COUNTER + 1)
	done
	cat log.txt
  verifyResult $res "Anchor peer update failed"
  successln "Anchor peers updated for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME'"
  sleep $DELAY
}

verifyResult() {
  if [ $1 -ne 0 ]; then
    fatalln "$2"
  fi
}

FABRIC_CFG_PATH=${PWD}/configtx

## Create channeltx
infoln "Generating channel create transaction '${CHANNEL_NAME}.tx'"
createChannelTx

## Create anchorpeertx
infoln "Generating anchor peer update transactions"
createAncorPeerTx

FABRIC_CFG_PATH=$PWD/../config/

## Create channel
infoln "Creating channel ${CHANNEL_NAME}"
createChannel

## Join all the peers to the channel
infoln "Join Org1 peers to the channel..."
joinChannel 1
infoln "Join Org2 peers to the channel..."
joinChannel 2

## Set the anchor peers for each org in the channel
infoln "Updating anchor peers for org1..."
updateAnchorPeers 1
infoln "Updating anchor peers for org2..."
updateAnchorPeers 2

successln "Channel successfully joined"

exit 0
```
ここでもドメイン名の修正に加えて`localhost`の修正も行います。

## 4-3. deployCC.shの修正

チェインコードをデプロイする`deployCC.sh`を修正していきます。

```shell:test-network/scripts/deployCC.sh
#!/bin/bash

source scriptUtils.sh

CHANNEL_NAME=${1:-"mychannel"}
CC_NAME=${2:-"basic"}
CC_SRC_PATH=${3:-"NA"}
CC_SRC_LANGUAGE=${4:-"go"}
CC_VERSION=${5:-"1.0"}
CC_SEQUENCE=${6:-"1"}
CC_INIT_FCN=${7:-"NA"}
CC_END_POLICY=${8:-"NA"}
CC_COLL_CONFIG=${9:-"NA"}
DELAY=${10:-"3"}
MAX_RETRY=${11:-"5"}
VERBOSE=${12:-"false"}

println "executing with the following"
println "- CHANNEL_NAME: ${C_GREEN}${CHANNEL_NAME}${C_RESET}"
println "- CC_NAME: ${C_GREEN}${CC_NAME}${C_RESET}"
println "- CC_SRC_PATH: ${C_GREEN}${CC_SRC_PATH}${C_RESET}"
println "- CC_SRC_LANGUAGE: ${C_GREEN}${CC_SRC_LANGUAGE}${C_RESET}"
println "- CC_VERSION: ${C_GREEN}${CC_VERSION}${C_RESET}"
println "- CC_SEQUENCE: ${C_GREEN}${CC_SEQUENCE}${C_RESET}"
println "- CC_END_POLICY: ${C_GREEN}${CC_END_POLICY}${C_RESET}"
println "- CC_COLL_CONFIG: ${C_GREEN}${CC_COLL_CONFIG}${C_RESET}"
println "- CC_INIT_FCN: ${C_GREEN}${CC_INIT_FCN}${C_RESET}"
println "- DELAY: ${C_GREEN}${DELAY}${C_RESET}"
println "- MAX_RETRY: ${C_GREEN}${MAX_RETRY}${C_RESET}"
println "- VERBOSE: ${C_GREEN}${VERBOSE}${C_RESET}"

CC_SRC_LANGUAGE=$(echo "$CC_SRC_LANGUAGE" | tr [:upper:] [:lower:])

FABRIC_CFG_PATH=$PWD/../config/

# User has not provided a path, therefore the CC_NAME must
# be the short name of a known chaincode sample
if [ "$CC_SRC_PATH" = "NA" ]; then
  infoln "Determining the path to the chaincode"
  # first see which chaincode we have. This will be based on the
  # short name of the known chaincode sample
  if [ "$CC_NAME" = "basic" ]; then
    println $'\e[0;32m'asset-transfer-basic$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-basic"
  elif [ "$CC_NAME" = "events" ]; then
    println $'\e[0;32m'asset-transfer-events$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-events"
  elif [ "$CC_NAME" = "secured" ]; then
    println $'\e[0;32m'asset-transfer-secured-agreeement$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-secured-agreement"
  elif [ "$CC_NAME" = "ledger" ]; then
    println $'\e[0;32m'asset-transfer-ledger-agreeement$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-ledger-queries"
  elif [ "$CC_NAME" = "private" ]; then
    println $'\e[0;32m'asset-transfer-private-data$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-private-data"
  elif [ "$CC_NAME" = "sbe" ]; then
    println $'\e[0;32m'asset-transfer-sbe$'\e[0m' chaincode
    CC_SRC_PATH="../asset-transfer-sbe"
  else
    fatalln "The chaincode name ${CC_NAME} is not supported by this script. Supported chaincode names are: basic, events, ledger, private, sbe, secured"
  fi

  # now see what language it is written in
  if [ "$CC_SRC_LANGUAGE" = "go" ]; then
    CC_SRC_PATH="$CC_SRC_PATH/chaincode-go/"
  elif [ "$CC_SRC_LANGUAGE" = "java" ]; then
    CC_SRC_PATH="$CC_SRC_PATH/chaincode-java/"
  elif [ "$CC_SRC_LANGUAGE" = "javascript" ]; then
    CC_SRC_PATH="$CC_SRC_PATH/chaincode-javascript/"
  elif [ "$CC_SRC_LANGUAGE" = "typescript" ]; then
    CC_SRC_PATH="$CC_SRC_PATH/chaincode-typescript/"
  fi

  # check that the language is available for the sample chaincode
  if [ ! -d "$CC_SRC_PATH" ]; then
    fatalln "The smart contract language \"$CC_SRC_LANGUAGE\" is not yet available for the \"$CC_NAME\" sample smart contract"
  fi
## Make sure that the path the chaincode exists if provided
elif [ ! -d "$CC_SRC_PATH" ]; then
  fatalln "Path to chaincode does not exist. Please provide different path"
fi

# do some language specific preparation to the chaincode before packaging
if [ "$CC_SRC_LANGUAGE" = "go" ]; then
  CC_RUNTIME_LANGUAGE=golang

  infoln "Vendoring Go dependencies at $CC_SRC_PATH"
  pushd $CC_SRC_PATH
  GO111MODULE=on go mod vendor
  popd
  successln "Finished vendoring Go dependencies"

elif [ "$CC_SRC_LANGUAGE" = "java" ]; then
  CC_RUNTIME_LANGUAGE=java

  infoln "Compiling Java code..."
  pushd $CC_SRC_PATH
  ./gradlew installDist
  popd
  successln "Finished compiling Java code"
  CC_SRC_PATH=$CC_SRC_PATH/build/install/$CC_NAME

elif [ "$CC_SRC_LANGUAGE" = "javascript" ]; then
  CC_RUNTIME_LANGUAGE=node

elif [ "$CC_SRC_LANGUAGE" = "typescript" ]; then
  CC_RUNTIME_LANGUAGE=node

  infoln "Compiling TypeScript code into JavaScript..."
  pushd $CC_SRC_PATH
  npm install
  npm run build
  popd
  successln "Finished compiling TypeScript code into JavaScript"

else
  fatalln "The chaincode language ${CC_SRC_LANGUAGE} is not supported by this script. Supported chaincode languages are: go, java, javascript, and typescript"
  exit 1
fi

INIT_REQUIRED="--init-required"
# check if the init fcn should be called
if [ "$CC_INIT_FCN" = "NA" ]; then
  INIT_REQUIRED=""
fi

if [ "$CC_END_POLICY" = "NA" ]; then
  CC_END_POLICY=""
else
  CC_END_POLICY="--signature-policy $CC_END_POLICY"
fi

if [ "$CC_COLL_CONFIG" = "NA" ]; then
  CC_COLL_CONFIG=""
else
  CC_COLL_CONFIG="--collections-config $CC_COLL_CONFIG"
fi

# import utils
. scripts/envVar.sh

packageChaincode() {
  ORG=$1
  setGlobals $ORG
  set -x
  peer lifecycle chaincode package ${CC_NAME}.tar.gz --path ${CC_SRC_PATH} --lang ${CC_RUNTIME_LANGUAGE} --label ${CC_NAME}_${CC_VERSION} >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  verifyResult $res "Chaincode packaging on peer0.org${ORG} has failed"
  successln "Chaincode is packaged on peer0.org${ORG}"
}

# installChaincode PEER ORG
installChaincode() {
  ORG=$1
  setGlobals $ORG
  set -x
  peer lifecycle chaincode install ${CC_NAME}.tar.gz >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  verifyResult $res "Chaincode installation on peer0.org${ORG} has failed"
  successln "Chaincode is installed on peer0.org${ORG}"
}

# queryInstalled PEER ORG
queryInstalled() {
  ORG=$1
  setGlobals $ORG
  set -x
  peer lifecycle chaincode queryinstalled >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  PACKAGE_ID=$(sed -n "/${CC_NAME}_${CC_VERSION}/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt)
  verifyResult $res "Query installed on peer0.org${ORG} has failed"
  successln "Query installed successful on peer0.org${ORG} on channel"
}

# approveForMyOrg VERSION PEER ORG
approveForMyOrg() {
  ORG=$1
  setGlobals $ORG
  set -x
  peer lifecycle chaincode approveformyorg -o 10-0-1-4.sslip.io:7050 --ordererTLSHostnameOverride orderer.10-0-1-4.sslip.io --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  verifyResult $res "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME' failed"
  successln "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME'"
}

# checkCommitReadiness VERSION PEER ORG
checkCommitReadiness() {
  ORG=$1
  shift 1
  setGlobals $ORG
  infoln "Checking the commit readiness of the chaincode definition on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
  local rc=1
  local COUNTER=1
  # continue to poll
  # we either get a successful response, or reach MAX RETRY
  while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
    sleep $DELAY
    infoln "Attempting to check the commit readiness of the chaincode definition on peer0.org${ORG}, Retry after $DELAY seconds."
    set -x
    peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} --output json >&log.txt
    res=$?
    { set +x; } 2>/dev/null
    let rc=0
    for var in "$@"; do
      grep "$var" log.txt &>/dev/null || let rc=1
    done
    COUNTER=$(expr $COUNTER + 1)
  done
  cat log.txt
  if test $rc -eq 0; then
    infoln "Checking the commit readiness of the chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
  else
    fatalln "After $MAX_RETRY attempts, Check commit readiness result on peer0.org${ORG} is INVALID!"
  fi
}

# commitChaincodeDefinition VERSION PEER ORG (PEER ORG)...
commitChaincodeDefinition() {
  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
  set -x
  peer lifecycle chaincode commit -o 10-0-1-4.sslip.io:7050 --ordererTLSHostnameOverride orderer.10-0-1-4.sslip.io --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name ${CC_NAME} $PEER_CONN_PARMS --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  verifyResult $res "Chaincode definition commit failed on peer0.org${ORG} on channel '$CHANNEL_NAME' failed"
  successln "Chaincode definition committed on channel '$CHANNEL_NAME'"
}

# queryCommitted ORG
queryCommitted() {
  ORG=$1
  setGlobals $ORG
  EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc"
  infoln "Querying chaincode definition on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
  local rc=1
  local COUNTER=1
  # continue to poll
  # we either get a successful response, or reach MAX RETRY
  while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
    sleep $DELAY
    infoln "Attempting to Query committed status on peer0.org${ORG}, Retry after $DELAY seconds."
    set -x
    peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} >&log.txt
    res=$?
    { set +x; } 2>/dev/null
    test $res -eq 0 && VALUE=$(cat log.txt | grep -o '^Version: '$CC_VERSION', Sequence: [0-9]*, Endorsement Plugin: escc, Validation Plugin: vscc')
    test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
    COUNTER=$(expr $COUNTER + 1)
  done
  cat log.txt
  if test $rc -eq 0; then
    successln "Query chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
  else
    fatalln "After $MAX_RETRY attempts, Query chaincode definition result on peer0.org${ORG} is INVALID!"
  fi
}

chaincodeInvokeInit() {
  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
  set -x
  fcn_call='{"function":"'${CC_INIT_FCN}'","Args":[]}'
  infoln "invoke fcn call:${fcn_call}"
  peer chaincode invoke -o 10-0-1-4.sslip.io:7050 --ordererTLSHostnameOverride orderer.10-0-1-4.sslip.io --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n ${CC_NAME} $PEER_CONN_PARMS --isInit -c ${fcn_call} >&log.txt
  res=$?
  { set +x; } 2>/dev/null
  cat log.txt
  verifyResult $res "Invoke execution on $PEERS failed "
  successln "Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME'"
}

chaincodeQuery() {
  ORG=$1
  setGlobals $ORG
  infoln "Querying on peer0.org${ORG} on channel '$CHANNEL_NAME'..."
  local rc=1
  local COUNTER=1
  # continue to poll
  # we either get a successful response, or reach MAX RETRY
  while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do
    sleep $DELAY
    infoln "Attempting to Query peer0.org${ORG}, Retry after $DELAY seconds."
    set -x
    peer chaincode query -C $CHANNEL_NAME -n ${CC_NAME} -c '{"Args":["queryAllCars"]}' >&log.txt
    res=$?
    { set +x; } 2>/dev/null
    let rc=$res
    COUNTER=$(expr $COUNTER + 1)
  done
  cat log.txt
  if test $rc -eq 0; then
    successln "Query successful on peer0.org${ORG} on channel '$CHANNEL_NAME'"
  else
    fatalln "After $MAX_RETRY attempts, Query result on peer0.org${ORG} is INVALID!"
  fi
}

## package the chaincode
packageChaincode 1

## Install chaincode on peer0.org1 and peer0.org2
infoln "Installing chaincode on peer0.org1..."
installChaincode 1
infoln "Install chaincode on peer0.org2..."
installChaincode 2

## query whether the chaincode is installed
queryInstalled 1

## approve the definition for org1
approveForMyOrg 1

## check whether the chaincode definition is ready to be committed
## expect org1 to have approved and org2 not to
checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": false"
checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": false"

## now approve also for org2
approveForMyOrg 2

## check whether the chaincode definition is ready to be committed
## expect them both to have approved
checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": true"
checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": true"

## now that we know for sure both orgs have approved, commit the definition
commitChaincodeDefinition 1 2

## query on both orgs to see that the definition committed successfully
queryCommitted 1
queryCommitted 2

## Invoke the chaincode - this does require that the chaincode have the 'initLedger'
## method defined
if [ "$CC_INIT_FCN" = "NA" ]; then
  infoln "Chaincode initialization is not required"
else
  chaincodeInvokeInit 1 2
fi

exit 0
```
ここでもドメイン名の修正が主ですが、`peer`コマンドの接続先が`localhost`になっているのでここの修正も必要です。

# 5. Fabricネットワークの起動

メインの`network.sh`は修正なしでOKです。以下のコマンドでネットワーク起動とチェーンコードのデプロイを行います。

```shell
$ cd test-network 
$ ./network.sh up createChannel -ca
...
$ ./network.sh deployCC -ccn basic -ccl javascript
```
ここではサンプルの'asset-transfer-basic/chaincode-javascript'をデプロイします。

# 6. サンプルアプリの修正

チェーンコードを叩くサンプルアプリの側を修正いたします。ここでは'asset-transfer-basic/application-javascript'を使用してみます。

## 6-1. AppUtil.jsの修正

共通ライブラリとしてインクルードされている`AppUtil.js`ではコネクションプロファイルの定義ファイルのパスが決め打ちになっております。
これを修正します。

```js:test-application/javascript/AppUtil.js
/*
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

const fs = require('fs');
const path = require('path');

exports.buildCCPOrg1 = () => {
	// load the common connection configuration file
	const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.10-0-1-4.sslip.io', 'connection-org1.json');
	const fileExists = fs.existsSync(ccpPath);
	if (!fileExists) {
		throw new Error(`no such file or directory: ${ccpPath}`);
	}
	const contents = fs.readFileSync(ccpPath, 'utf8');

	// build a JSON object from the file contents
	const ccp = JSON.parse(contents);

	console.log(`Loaded the network configuration located at ${ccpPath}`);
	return ccp;
};

exports.buildCCPOrg2 = () => {
	// load the common connection configuration file
	const ccpPath = path.resolve(__dirname, '..', '..', 'test-network',
		'organizations', 'peerOrganizations', 'org2.10-0-1-4.sslip.io', 'connection-org2.json');
	const fileExists = fs.existsSync(ccpPath);
	if (!fileExists) {
		throw new Error(`no such file or directory: ${ccpPath}`);
	}
	const contents = fs.readFileSync(ccpPath, 'utf8');

	// build a JSON object from the file contents
	const ccp = JSON.parse(contents);

	console.log(`Loaded the network configuration located at ${ccpPath}`);
	return ccp;
};

exports.buildWallet = async (Wallets, walletPath) => {
	// Create a new  wallet : Note that wallet is for managing identities.
	let wallet;
	if (walletPath) {
		wallet = await Wallets.newFileSystemWallet(walletPath);
		console.log(`Built a file system wallet at ${walletPath}`);
	} else {
		wallet = await Wallets.newInMemoryWallet();
		console.log('Built an in memory wallet');
	}

	return wallet;
};

exports.prettyJSONString = (inputString) => {
	if (inputString) {
		return JSON.stringify(JSON.parse(inputString), null, 2);
	}
	else {
		return inputString;
	}
}
```
ここで設定ファイルのパスが固定なのも、ねぇ。。。

## 6-2. app.jsの修正

app.jsでは修正ポイントは接続先の設定を取得する箇所と接続時の`asLocalhost`を`false`にするだけです。

```js:asset-transfer-basic/application-javascript/app.js
...
const caClient = buildCAClient(FabricCAServices, ccp, 'ca.org1.10-0-1-4.sslip.io');
...
			await gateway.connect(ccp, {
				wallet,
				identity: org1UserId,
				discovery: { enabled: true, asLocalhost: false }
			});


```

修正は以上で終了です。

# 7. サンプルアプリの実行

上記の修正が終わりましたら以下のコマンドでサンプルアプリを実行します。

```shell
$ cd asset-transfer-basic/application-javascript
$ node app.js
```

Hyperledgerのデバッグログを有効にする場合は以下のような環境変数での実行もおすすめです。

```shell
$ HFC_LOGGING='{"debug":"console"}' node app.js
```
`HFC_LOGGING`でログレベルの設定が可能です。

以上、お疲れ様でした！

## 参照する公式ガイド

- [Hyperledger Fabric CA v1.4 マニュアル: https://hyperledger-fabric-ca.readthedocs.io/](https://hyperledger-fabric-ca.readthedocs.io/en/release-1.4/index.html)
- [Hyperledger Fabric v2 マニュアル: https://hyperledger-fabric.readthedocs.io](https://hyperledger-fabric.readthedocs.io/en/release-2.2/)
- [fabric-samples README: https://github.com/hyperledger/fabric-samples](https://github.com/hyperledger/fabric-samples#getting-started-with-the-fabric-samples)

# 感想など

fabric-samples/test-network のスクリプトですが、やはりfabric-samplesのサンプルのチェーンコードを動かすため**だけ**の環境構築スクリプトですね。
上記の修正量をみていただければわかるかと思いますが**ほとんど応用がきかない**スクリプトです。
まぁ、ゼロから設定するのは~~心が折れる~~かなりしんどいのでネットワークの設定を理解するとっかかりにはなりますが、元々は`localhost`限定の設定なのでSSL関連の設定がほとんど省略されており、単純な修正だけで全く動きませんでした。。。

いや〜なかなか、辛かったです。