Hyperledger-Fabricで、Orgの追加方法

# これはなに？

* HyperledgerFabric（v1.3）で、Orgの追加方法です。
* Orgを新しく作成して、チャンネルに追加しようとしたらエラーが発生したので、備忘録として記載しています。
    * インストール方法等は記載していません。
    * チュートリアルのサンプル(`fabric-samples/basic-network/`)を元に行っています。パス等は、適宜変更してください。
        * [https://hyperledger-fabric.readthedocs.io/en/latest/tutorials.html](https://hyperledger-fabric.readthedocs.io/en/latest/tutorials.html)
* 作業環境
    * macOS High Sierra 10.13.6
    * Docker for Mac

# 完成形

* 完成形は次のような構成になります
    * ※ただし、peerについては設定していない
* Org1
    * peer0
    * peer1
* Org2
    * peer0
    * peer1

# コピー

* 今回修正対象のディレクトリを別ディレクトリに切り出して、そこで作業をしようと思います。

```
$ mkdir ~/fabrictest
$ cp -r fabric-samples/basic-network/ ~/fabrictest
$ cd ~/fabrictest
$ ls
README.md		configtx.yaml		crypto-config.yaml	generate.sh		start.sh		teardown.sh
config			crypto-config		docker-compose.yml	init.sh			stop.sh 
```

* 修正対象のファイル
    * configtx.yaml
        * Orgの追加に必要です
    * crypto-config.yaml
        * 鍵関係の作成で必要です
    * docker-compose.yml
        * Peerの追加に必要です
    * generate.sh
        * 鍵関係の作成で必要です
    * start.sh
        * ネットワークを起動させるのに必要です

# 追加方法
## Orgの追加

* Orgを追加します。
    * 対象ファイル
        * configtx.yaml

----

* `Organizations`の`&Org1`をコピペして`&Org2`を作成・修正します

``` yaml
    - &Org2
        Name: Org2MSP
        ID: Org2MSP
        MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
        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')"
        AnchorPeers:
            - Host: peer0.org2.example.com
              Port: 7051

```

----

* `Profiles`に`Org2`を追記します
    * 恐らく2箇所。

``` yaml
Profiles:
    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2 # ← ここ①
    TwoOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2 # ← ここ②
            Capabilities:
                <<: *ApplicationCapabilities
```

## 鍵生成の修正

* Org2も作成されるようにします
    * 対象ファイル
        * crypto-config.yaml

----

* `PeerOrgs`の`Org1`をコピペして、`Org2`を作成・修正します。

``` yaml
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Specs:
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #   - Hostname: bar
    #   - Hostname: baz
    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    Template:
      Count: 2
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default
    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1
  # ---------------------------------------------------------------------------
  # Org2: See "Org1" for full specification
  # ---------------------------------------------------------------------------
  - Name: Org2
    Domain: org2.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 1
```

----

* `generate.sh`も鍵生成に必要なので、修正します
* `anchor peer`を作成する処理をコピペして、`Org2`も作成されるようにします

``` bash
# generate anchor peer transaction
configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./config/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
if [ "$?" -ne 0 ]; then
  echo "Failed to generate anchor peer update for Org1MSP..."
  exit 1
fi

# generate anchor peer transaction （Org2）
configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./config/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
if [ "$?" -ne 0 ]; then
  echo "Failed to generate anchor peer update for Org2MSP..."
  exit 1
fi
```

## Peerの追加

* Peerを追加します
    * 対象ファイル
        * docker-compose.yml

----

* `services`の`peer0.org1.example.com`をコピペ＆修正して、`peer1.org1/peer0.org2/peer1.org2`を作成します
* 修正箇所は、下記になります
    * `container_name`
    * `environment`
        * `CORE_PEER_ID`
        * `CORE_PEER_LOCALMSPID`
        * `CORE_PEER_ADDRESS`
    * `ports`
    * `volumes`

* peer1.org1

``` yaml
  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    image: hyperledger/fabric-peer
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer1.org1.example.com
      - CORE_LOGGING_PEER=info
      - CORE_CHAINCODE_LOGGING_LEVEL=info
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7051
      # # 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}_basic
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
      # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
      # provide the credentials for ledger to connect to CouchDB.  The username and password must
      # match the username and password set for the associated CouchDB.
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: peer node start
    # command: peer node start --peer-chaincodedev=true
    ports:
      - 7052:7051
      - 7054:7053
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/msp/peer
        - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users
        - ./config:/etc/hyperledger/configtx
    depends_on:
      - orderer.example.com
      - couchdb
    networks:
      - basic
```

* peer0.org2

``` yaml
  peer0.org2.example.com:
    container_name: peer0.org2.example.com
    image: hyperledger/fabric-peer
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer0.org2.example.com
      - CORE_LOGGING_PEER=info
      - CORE_CHAINCODE_LOGGING_LEVEL=info
      - CORE_PEER_LOCALMSPID=Org2MSP
      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer
      - CORE_PEER_ADDRESS=peer0.org2.example.com:7051
      # # 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}_basic
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
      # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
      # provide the credentials for ledger to connect to CouchDB.  The username and password must
      # match the username and password set for the associated CouchDB.
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: peer node start
    # command: peer node start --peer-chaincodedev=true
    ports:
      - 8051:7051
      - 8053:7053
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/msp/peer
        - ./crypto-config/peerOrganizations/org2.example.com/users:/etc/hyperledger/msp/users
        - ./config:/etc/hyperledger/configtx
    depends_on:
      - orderer.example.com
      - couchdb
    networks:
      - basic
```

* peer1.org2

``` yaml
  peer1.org2.example.com:
    container_name: peer1.org2.example.com
    image: hyperledger/fabric-peer
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer1.org2.example.com
      - CORE_LOGGING_PEER=info
      - CORE_CHAINCODE_LOGGING_LEVEL=info
      - CORE_PEER_LOCALMSPID=Org2MSP
      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer
      - CORE_PEER_ADDRESS=peer1.org2.example.com:7051
      # # 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}_basic
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
      # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
      # provide the credentials for ledger to connect to CouchDB.  The username and password must
      # match the username and password set for the associated CouchDB.
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: peer node start
    # command: peer node start --peer-chaincodedev=true
    ports:
      - 8052:7051
      - 8054:7053
    volumes:
        - /var/run/:/host/var/run/
        - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/msp/peer
        - ./crypto-config/peerOrganizations/org2.example.com/users:/etc/hyperledger/msp/users
        - ./config:/etc/hyperledger/configtx
    depends_on:
      - orderer.example.com
      - couchdb
    networks:
      - basic
```

## ネットワーク起動スクリプト修正

* ネットワーク起動スクリプトを修正します。
    * 対象ファイル
        * start.sh

----

* org2も起動対象に含めます
    * `docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb
`に`peer0.org2.example.com`も含めてください

```
docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com peer0.org2.example.com couchdb
```

* org2をチャンネルに追加します
    * 下記コマンドを追加してください

```
# Join peer0.org1.example.com to the channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel join -b mychannel.block

# Join peer0.org2.example.com to the channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel fetch 0 mychannel.block -c mychannel -o orderer.example.com:7050
docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel join -b mychannel.block
```

* 上記で`docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel fetch 0 mychannel.block -c mychannel -o orderer.example.com:7050`を実行しないと、`Error: genesis block file not found open mychannel.block: no such file or directory`と言ったエラーが発生します。
    * コンテナが参照できないからのようです
    * 参考：https://lists.hyperledger.org/g/fabric/topic/17549922

----

以上で、設定が完了しました。
確認してみましょう。

# 確認

```
$ ./start.sh 

# don't rewrite paths for Windows Git Bash users
export MSYS_NO_PATHCONV=1

docker-compose -f docker-compose.yml down
Stopping peer0.org1.example.com ... done
Stopping peer0.org2.example.com ... done
Stopping couchdb                ... done
Stopping orderer.example.com    ... done
Removing peer0.org1.example.com ... done
Removing peer0.org2.example.com ... done
Removing ca.example.com         ... done
Removing couchdb                ... done
Removing orderer.example.com    ... done
Removing network net_basic

docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com peer0.org2.example.com couchdb
Creating network "net_basic" with the default driver
Creating couchdb             ... done
Creating ca.example.com         ... done
Creating orderer.example.com ... done
Creating peer0.org1.example.com ... done
Creating peer0.org2.example.com ... done

# wait for Hyperledger Fabric to start
# incase of errors when running later commands, issue export FABRIC_START_TIMEOUT=<larger number>
export FABRIC_START_TIMEOUT=10
#echo ${FABRIC_START_TIMEOUT}
sleep ${FABRIC_START_TIMEOUT}

# Create the channel
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.tx
2018-10-30 08:13:13.672 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-10-30 08:13:13.694 UTC [cli/common] readBlock -> INFO 002 Received block: 0



# Join peer0.org1.example.com to the channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel join -b mychannel.block
2018-10-30 08:13:13.903 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-10-30 08:13:14.017 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel


# Join peer0.org2.example.com to the channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel fetch 0 mychannel.block -c mychannel -o orderer.example.com:7050
2018-10-30 08:13:14.218 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-10-30 08:13:14.222 UTC [cli/common] readBlock -> INFO 002 Received block: 0
docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel join -b mychannel.block
2018-10-30 08:13:14.422 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-10-30 08:13:14.472 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

$ docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel list
2018-10-30 08:14:29.578 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined: 
mychannel

$ docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org2.example.com/msp" peer0.org2.example.com peer channel list
2018-10-30 08:14:35.141 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined: 
mychannel

```

* 無事、両方のチャンネルにOrgが追加されたことが確認できました。

# おわりに

* はじめにも書きましたが、Orgをチャンネルに追加するところでエラーが発生していました。
* 同じような人の救いになれば幸いです。
* 以上です。ありがとうございました。