Hyperledger Fabric v1.0でPeerをネットワークに追加する

#Hyperledger Fabric v1.0でのPeerの追加
Hyperledger Fabric v1.0（以下HFV1）ではP2Pネットワーク上にエンティティ（CAサーバ、Orderer、Peer）を追加するために証明書を発行する必要があります。
本記事ではfabric-samplesを利用して、証明書の発行からdocker-composeによるネットワークの立ち上げ、balance-tranferというサンプルアプリを実行するところまでの手順を紹介します。

大まかな流れは以下の通りです。

1. 環境構築
2. first-network/crypto-config.yaml でネットワークトポロジを定義
3. first-network/byfs.sh を実行して証明書等を生成、balance-transferディレクトリにコピー
4. 定義したネットワークトポロジに合わせて以下のファイルを修正
    + balance-transfer/artifacts/channel/docker-compose.yaml
    + balance-transfer/app/network-config.json
    + balance-transfer/testAPIs.sh
8. balance-transfer/runApp.shを実行してネットワークを立ち上げ
9. balance-transfer/testAPIs.shを実行してサンプルアプリを動かす

#環境構築
##HFV1動作環境の準備
必要要件は以下の通りです。
- Docker version 17.03.1-ce or greater
- Go programming language 1.7.x
- Node.js version 6.9.x or greater

私はMacにDockerとnode.jsをインストールして環境構築を行いました。
Windowsを使う場合は仮想化したLinux(Ubuntu)上で環境構築するのが良いと思います。
以下の方々の記事が参考になります。

Hyperledger Fabric v1.0.1 のセットアップとサンプルの実行
http://qiita.com/comeonyama/items/add6a9c77193740ab65d

最新の Hyperldeger Fabric (2017/3/17) を試してみた時のメモ
http://qiita.com/CyLomw/items/2b2c8b80511fbb2b23bc

##fabric-samplesの準備
今回はHFV1公式ドキュメントでも紹介されているfabric-samplesを用いてPeerを追加します。

1.fabric-samplesをダウンロード

```
$ git clone https://github.com/hyperledger/fabric-samples.git
$ cd fabric-samples
```

2.必要なツール等をダウンロード・インストール

```
$ curl -sSL https://goo.gl/Gci9ZX | bash
```

#ネットワーク構築
##crypto-config.yamlにネットワーク・トポロジを記述
first-network/crypto-config.yamlに構築するネットワークトポロジを記述します。
デフォルトでは

+ org1.example.comにPeerが2台
+ org2.example.comにPeerが2台

となっているので、今回はorg1.example.comにpeerを一台追加します。
crypto-config.yamlを以下のように修正して下さい。

```first-network/crypto-config.yaml
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

OrdererOrgs:
  - Name: Orderer
    Domain: example.com
    Specs:
      - Hostname: orderer

PeerOrgs:
  - Name: Org1
    Domain: org1.example.com
    CA:
       Hostname: ca # implicitly ca.org1.example.com
    Template:
      Count: 3
      SANS:
        - "localhost"
    Users:
      Count: 1

  - Name: Org2
    Domain: org2.example.com
    CA:
       Hostname: ca # implicitly ca.org1.example.com
    Template:
      Count: 2
      SANS:
        - "localhost"
    Users:
      Count: 1
```
TemplateのCountプロパティの数値が対象のorgに属するpeerの台数になります。
Org1ではPeer3台、Org2ではPeer2台になっていることがわかりますね。

この記述により構成されるネットワークトポロジは以下のようになります。

+ orderer.example.com
+ ORG1
    + ca.org1.example.com
    + peer0.org1.example.com
    + peer1.org1.example.com
    + peer2.org1.example.com
+ ORG2
    + ca.org2.example.com
    + peer0.org2.example.com
    + peer1.org2.example.com
  
各orgに複数台のPeerとそれらを認証するCAサーバが一台、
トランザクションを各Peerに振り分けるOrdererが一台という構成です。

##証明書の発行
first-network/byfn.shを利用して、証明証等やgenesis blockなどを発行します。

```
$ cd first-network
$ ./byfn.sh -m generate
```

このコマンドによりcryptogenツールとconfigtxgenツールが実行され、以下のフォルダ・ファイルが生成されます。

+ crypto-configフォルダ
    + 全エンティティの証明書等が格納されています
+ channel-artifacts/genesis.block
    + genesis blockはブロックチェーンの先頭のブロックです
+ channel-artifacts/channel.tx
    + チャネルの設定を行うためのトランザクションファイルです
  
これらのフォルダ・ファイルをbalance-transfer/artifacts/channel/ディレクトリにコピーして下さい。
すでに既存ファイルがあるので上書きしないようバックアップを忘れずに。

```
$ cp -r crypto-config ../balance-transfer/artifacts/channel/
$ cp channel-artifacts/genesis.block ../balance-transfer/artifacts/channel/genesis.block
$ cp channel-artifacts/channel.tx ../balance-transfer/artifacts/channel/mychannel.tx
```

##docker-compose.yamlの修正
新たに構築したネットワークトポロジに合わせてbalance-tranfer用のdocker-compose.yamlを以下の通り修正します。

+ CAサーバの秘密鍵ファイル名（_skで終わってるやつ）を先程生成したcrypto-configフォルダに格納されているものに書き換える
    + - FABRIC_CA_SERVER_CA_KEYFILEと- FABRIC_CA_SERVER_TLS_KEYFILEを書き換え
+ peer2.org1.example.comを追加
    + ポート番号は7059、7061を使用

修正箇所を抜粋して載せます。秘密鍵ファイル名は各自違うので注意して下さい。

```balance-transfer/artifacts/channel/docker-compose.yaml
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'

services:

  ca.org1.example.com:
    image: hyperledger/fabric-ca
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
      - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/1d64b9e9dcdaabb8bf9877b2a9dd5f23a79263ec7e338296ae85914da709dba9_sk
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
      - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/1d64b9e9dcdaabb8bf9877b2a9dd5f23a79263ec7e338296ae85914da709dba9_sk
    ports:
      - "7054:7054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ./channel/crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
    container_name: ca_peerOrg1

  ca.org2.example.com:
    image: hyperledger/fabric-ca
    environment:
      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
      - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem
      - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/2c50e4b5a61f2750515529585f480e72d8268adcd24b4eca8fa4ed1c76baab5c_sk
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem
      - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/2c50e4b5a61f2750515529585f480e72d8268adcd24b4eca8fa4ed1c76baab5c_sk
    ports:
      - "8054:7054"
    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
    volumes:
      - ./channel/crypto-config/peerOrganizations/org2.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
    container_name: ca_peerOrg2

 ・
 ・
 ・

  peer2.org1.example.com:
    container_name: peer2.org1.example.com
    extends:
      file:   base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer2.org1.example.com
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_ADDRESS=peer2.org1.example.com:7051
    ports:
      - 7059:7051
      - 7061:7053
    volumes:
        - ./channel/crypto-config/peerOrganizations/org1.example.com/peers/peer2.org1.example.com/:/etc/hyperledger/crypto/peer
    depends_on:
      - orderer.example.com
 ・
 ・
 ・

```
##network-config.jsonの修正
サンプルアプリで読み込むnetwork-configファイルを修正します。
以下のように"peer3"を新たに追加して下さい。org2の部分は変わらないので省略しています。

```balance-transfer/app/network-config.json
{
	"network-config": {
		"orderer": {
			"url": "grpcs://localhost:7050",
			"server-hostname": "orderer.example.com",
			"tls_cacerts": "../artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
		},
		"org1": {
			"name": "peerOrg1",
			"mspid": "Org1MSP",
			"ca": "https://localhost:7054",
			"peers": {
				"peer1": {
					"requests": "grpcs://localhost:7051",
					"events": "grpcs://localhost:7053",
					"server-hostname": "peer0.org1.example.com",
					"tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
				},
				"peer2": {
					"requests": "grpcs://localhost:7056",
					"events": "grpcs://localhost:7058",
					"server-hostname": "peer1.org1.example.com",
					"tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt"
				},
				"peer3": {
					"requests": "grpcs://localhost:7059",
					"events": "grpcs://localhost:7061",
					"server-hostname": "peer2.org1.example.com",
					"tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer2.org1.example.com/tls/ca.crt"
				}	
			},
			"admin": {
				"key": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore",
				"cert": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts"
			}
		},
		"org2": {
 ・
 ・
 ・
			}
		}
	}
}
```

##testAPIs.shの修正
最後の修正箇所です。ネットワーク立ち上げ後に実行するtestAPIs.shを、追加したpeerとも通信するように修正します。

やることは簡単で、org1にJoin Channel RequestとInstall Chaincode Requestを送るときに、

```
"peers": ["peer1","peer2"]
```

と対象のpeerを指定しているので、ここに先ほどnetwork-config.jsonに追加した"peer3"を追加するだけです。
修正箇所を抜粋して載せます。

```balance-transfer/testAPIs.sh
#!/bin/bash
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
 ・
 ・
 ・
sleep 5
echo "POST request Join channel on Org1"
echo
curl -s -X POST \
  http://localhost:4000/channels/mychannel/peers \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json" \
  -d '{
	"peers": ["peer1","peer2","peer3"]
}'
echo
 ・
 ・
 ・
echo "POST Install chaincode on Org1"
echo
curl -s -X POST \
  http://localhost:4000/chaincodes \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json" \
  -d '{
	"peers": ["peer1", "peer2","peer3"],
	"chaincodeName":"mycc",
	"chaincodePath":"github.com/example_cc",
	"chaincodeVersion":"v0"
}'
echo
 ・
 ・
 ・
```
以上で修正は完了になります。
#実行
##ネットワーク立ち上げ
構築したネットワークを立ち上げます。runApp.shを実行するだけです。

```
$ cd ../balance-transfer
$ ./runApp.sh
```

docker-composeにより全エンティティが起動し、REST APIの待受状態になります。
もう一つターミナルを開いて

```
$ docker ps
```
と入力すると、以下のようにPeer5台、CAサーバ2台、Ordererが立ち上がっているのが確認できます。

```
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                            NAMES
d334138a231c        hyperledger/fabric-peer      "peer node start"        12 seconds ago      Up 9 seconds        0.0.0.0:8056->7051/tcp, 0.0.0.0:8058->7053/tcp   peer1.org2.example.com
44bd27642b2f        hyperledger/fabric-peer      "peer node start"        12 seconds ago      Up 10 seconds       0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp   peer0.org2.example.com
c0b87d5f06d4        hyperledger/fabric-peer      "peer node start"        12 seconds ago      Up 11 seconds       0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp   peer0.org1.example.com
cd9bc1262841        hyperledger/fabric-peer      "peer node start"        12 seconds ago      Up 11 seconds       0.0.0.0:7056->7051/tcp, 0.0.0.0:7058->7053/tcp   peer1.org1.example.com
21b45442d6cd        hyperledger/fabric-peer      "peer node start"        12 seconds ago      Up 10 seconds       0.0.0.0:7059->7051/tcp, 0.0.0.0:7061->7053/tcp   peer2.org1.example.com
deba8e7cd87a        hyperledger/fabric-ca        "sh -c 'fabric-ca-..."   13 seconds ago      Up 12 seconds       0.0.0.0:7054->7054/tcp                           ca_peerOrg1
23de22c773c1        hyperledger/fabric-ca        "sh -c 'fabric-ca-..."   13 seconds ago      Up 12 seconds       0.0.0.0:8054->7054/tcp                           ca_peerOrg2
e6ba434454c0        hyperledger/fabric-orderer   "orderer"                13 seconds ago      Up 12 seconds       0.0.0.0:7050->7050/tcp                           orderer.example.com
```

##サンプルアプリ実行
最後にtestAPIs.shを実行して、動作を確認します。
このスクリプトは

1. Create Channel request
2. Join Channel request
3. Install chaincode
4. Instantiate chaincode
5. Invoke request
6. Chaincode Query
7. Query Block by BlockNumber
8. Query Transaction by TransactionID
9. Query ChainInfo
10. Query Installed chaincodes
11. Query Instantiated chaincodes
12. Query Channels

を順番に実行してくれます。
以下のコマンドで実行して下さい。

```
$ ./testAPIs.sh
```

最後に処理時間が表示されたら全コマンド成功です。

```
Total execution time : 51 secs ...
```

追加したpeerも動作しているか確かめたいときは、docker logs コマンドを使うと便利です。

```
$ docker logs peer2.org1.example.com
```

#最後に
以上がHFV1でのpeerの追加方法です。
手順としては面倒ですが、修正するファイルは決まっているので慣れたら簡単にできます。

新たなorg（org3.example.comなど）の追加もこれらのファイルを修正すればできます。（修正箇所は多くなりますが...）

次はせっかくREST APIを使える状態になっているので、
Ajaxを使ったブラウザで動くGUIアプリを作成できればと思います。

#参考サイト
HLV公式-Building Your First Network
http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html

GitHub-hyperledger/fabric-samples
https://github.com/hyperledger/fabric-samples