[HyperledgerIroha]Peerの追加方法

# 記事の内容
Hyperledger IrohaでPeerを追加する方法です。

この記事で構築する環境は下図の通りです。
![Iroha1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476876/c91c74b6-3849-7bc4-b274-43e937cb4d16.png)

本来、一つのVMにPeerを複数作っても耐障害性を考えるとあまり意味がない気がします。
私も勉強用に下図の構成で作ってみたのですが、上手くいかなかった点の考察も踏まえて記録を残します。

![Iroha2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476876/1bf21462-1da7-d207-131f-32f8a51c108a.png)

# 環境構築手順
## 前提条件
・Dockerがインストールされている

## iroha関連のコンテナ準備
### gitクローン
~~~
$ cd ~
$ git clone https://github.com/hyperledger/iroha --depth=1
~~~

### iroha用のネットワーク構築
~~~
$ docker network create iroha-network
~~~

### blockstoreの構築
blockstoreはpeer毎に用意するので、今回の環境では３つ作成します。

~~~
$ docker volume create blockstore1
$ docker volume create blockstore2
$ docker volume create blockstore3
~~~

### PostgresSQLのコンテナ作成
それぞれのpeer用のpostgresSQLのコンテナを作成します。
名称やポートなどはそれぞれ変えてます。

~~~
# iroha1用
$ docker run --name some-postgres1 \
 -e POSTGRES_USER=postgres \
 -e POSTGRES_PASSWORD=mysecretpassword \
 -p 15432:5432 \
 --network=iroha-network \
 -d postgres:9.5 

# iroha2用
$ docker run --name some-postgres2 \
 -e POSTGRES_USER=postgres \
 -e POSTGRES_PASSWORD=mysecretpassword \
 -p 25432:5432 \
 --network=iroha-network \
 -d postgres:9.5 

# iroha3用
$ docker run --name some-postgres3 \
 -e POSTGRES_USER=postgres \
 -e POSTGRES_PASSWORD=mysecretpassword \
 -p 35432:5432 \
 --network=iroha-network \
 -d postgres:9.5 
~~~

## irohaの設定ファイル修正
追加するpeerに合わせて設定ファイルを修正する必要があります

### ノード用のキーペアを作成する
irohaの鍵は「ed25519」という方式で作る必要があります。
この記事ではpythonでの作り方を紹介します。

~~~ key_generate.py
from iroha import IrohaCrypto

private_key = IrohaCrypto.private_key()
public_key = IrohaCrypto.derive_public_key(private_key)

print('public  key:' + str(public_key))
print('private key:' + str(private_key))
~~~

このプログラムを３回実行してノード用の鍵を３個作成します。

~~~
# node1用
public  key:b'ad456d0433db192e78026cb0d12870bec20e2264041759d648e7af8268945dd2'
private key:b'2e93b266eff7adb139155d7b47e00c97967c89f9de65ecdccc89942676db5044'

# node2用
public  key:b'2231fa8d74f764fb3018cc59111f66c09542805720fe5f7b814e29cf95130ecb'
private key:b'58a15765b77acc3eadfbf166fd0111e18b3b1114972fad682b1fec81f3d8ce7a'

# node3用
public  key:b'63e250b6532e327613b4ee0e826d346c5e473ef8377b33cca5e5b4e369cba8cb'
private key:b'4d7b8c49a5bb8a5e5274c52ad14ed43867f984cab64eda87d308e94c35efc443'
~~~

作成したキーは以下のディレクトリに保存します。
保存する内容はb'公開鍵'の公開鍵の部分だけです。

~~~
$ cd ~/iroha/example
$ vi node1.pub
$ vi node1.priv
$ vi node2.pub
$ vi node2.priv
$ vi node3.pub
$ vi node3.priv
~~~

### genesis.blockの修正
irohaではブロックチェーンの初期化時にアカウントの作成やpeerの追加などを設定することができます。
その設定内容をgenesis.blockに記録しておきます。

修正ポイントは以下の点になります。
・addPeerコマンドを追加する
・addressをiroha1～iroha3にする
・peerKeyには前の手順で作成した公開鍵（public key）を設定する

~~~ genesis.block
{
   "block_v1":{
     "payload":{
        "transactions":[
           {
              "payload":{
                 "reducedPayload":{
                    "commands":[
                       {
                          "addPeer":{
                             "peer":{
                                "address":"iroha1:10001",
                                "peerKey":"ad456d0433db192e78026cb0d12870bec20e2264041759d648e7af8268945dd2"
                             }
                          }
                       },
                       {
                          "addPeer":{
                             "peer":{
                                "address":"iroha2:10001",
                                "peerKey":"2231fa8d74f764fb3018cc59111f66c09542805720fe5f7b814e29cf95130ecb"
                             }
                          }
                       },
                       {
                          "addPeer":{
                             "peer":{
                                "address":"iroha3:10001",
                                "peerKey":"63e250b6532e327613b4ee0e826d346c5e473ef8377b33cca5e5b4e369cba8cb"
                             }
                          }
                       },
                       {
                          "createRole":{
                             "roleName":"admin",
                             "permissions":[
                                "can_add_peer",
                                "can_add_signatory",
                                "can_create_account",
                                "can_create_domain",
                                "can_get_all_acc_ast",
                                "can_get_all_acc_ast_txs",
                                "can_get_all_acc_detail",
                                "can_get_all_acc_txs",
                                "can_get_all_accounts",
                                "can_get_all_signatories",
                                "can_get_all_txs",
                                "can_get_blocks",
                                "can_get_roles",
                                "can_read_assets",
                                "can_remove_signatory",
                                "can_set_quorum"
                             ]
                          }
                       },
                       {
                          "createRole":{
                             "roleName":"user",
                             "permissions":[
                                "can_add_signatory",
                                "can_get_my_acc_ast",
                                "can_get_my_acc_ast_txs",
                                "can_get_my_acc_detail",
                                "can_get_my_acc_txs",
                                "can_get_my_account",
                                "can_get_my_signatories",
                                "can_get_my_txs",
                                "can_grant_can_add_my_signatory",
                                "can_grant_can_remove_my_signatory",
                                "can_grant_can_set_my_account_detail",
                                "can_grant_can_set_my_quorum",
                                "can_grant_can_transfer_my_assets",
                                "can_receive",
                                "can_remove_signatory",
                                "can_set_quorum",
                                "can_transfer"
                             ]
                          }
                       },
                       {
                          "createRole":{
                             "roleName":"money_creator",
                             "permissions":[
                                "can_add_asset_qty",
                                "can_create_asset",
                                "can_receive",
                                "can_transfer"
                             ]
                          }
                       },
                       {
                          "createDomain":{
                             "domainId":"test",
                             "defaultRole":"user"
                          }
                       },
                       {
                          "createAsset":{
                             "assetName":"coin",
                             "domainId":"test",
                             "precision":2
                          }
                       },
                       {
                          "createAccount":{
                             "accountName":"admin",
                             "domainId":"test",
                             "publicKey":"313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910"
                          }
                       },
                       {
                          "createAccount":{
                             "accountName":"test",
                             "domainId":"test",
                             "publicKey":"716fe505f69f18511a1b083915aa9ff73ef36e6688199f3959750db38b8f4bfc"
                          }
                       },
                       {
                          "appendRole":{
                             "accountId":"admin@test",
                             "roleName":"admin"
                          }
                       },
                       {
                          "appendRole":{
                             "accountId":"admin@test",
                             "roleName":"money_creator"
                          }
                       }
                    ],
                    "quorum":1
                 }
              }
           }
        ],
        "txNumber":1,
        "height":"1",
        "prevBlockHash":"0000000000000000000000000000000000000000000000000000000000000000"
     }
   }
}
~~~

### peer2、3用の作業ディレクトリを準備する
以下のコマンドでディレクトリをコピーする

~~~
$ cd ~/iroha
$ cp -r example example1
$ cp -r example example2
~~~

### config.dockerの修正
config.dockerにirohaデーモンが接続するpostgresSQLの接続情報が記載されているので修正します。
修正箇所はpostgresの接続するコンテナ名を修正します。

以下の内容はiroha1用になります。iroha2,3については「some-postgres」の末尾をそれぞれ1,2に変更します。
変更するファイルは一つ前の手順で作成したexample1,example2配下のファイルを変更します。

~~~ ~/iroha/example/config.docker
{
  "block_store_path" : "/tmp/block_store/",
  "torii_port" : 50051,
  "internal_port" : 10001,
  "pg_opt" : "host=some-postgres1 port=5432 user=postgres password=mysecretpassword",
  "max_proposal_size" : 10,
  "proposal_delay" : 5000,
  "vote_delay" : 5000,
  "mst_enable" : false,
  "mst_expiration_time" : 1440,
  "max_rounds_delay": 3000,
  "stale_stream_max_rounds": 2
}
~~~

### irohaコンテナの作成
irohaコンテナを3つ作成します。
この作業は後のログ確認をしやすくするためにもコンソール３つ開いてやります。

iroha1用コンソール

~~~
$ cd ~/
$ docker run -it --name iroha1 \
-p 51051:50051 \
-v $(pwd)/iroha/example:/opt/iroha_data \
-v blockstore:/tmp/block_store \
--network=iroha-network \
--entrypoint=/bin/bash \
hyperledger/iroha:develop

$ irohad --config config.docker --genesis_block genesis.block --keypair_name node1
~~~

iroha2用コンソール

~~~
$ cd ~/
$ docker run -it --name iroha2 \
-p 52051:50051 \
-v $(pwd)/iroha/example1:/opt/iroha_data \
-v blockstore:/tmp/block_store \
--network=iroha-network \
--entrypoint=/bin/bash \
hyperledger/iroha:develop

$ irohad --config config.docker --genesis_block genesis.block --keypair_name node2
~~~

iroha3用コンソール

~~~
$ cd ~/
$ docker run -it --name iroha3 \
-p 53051:50051 \
-v $(pwd)/iroha/example2:/opt/iroha_data \
-v blockstore:/tmp/block_store \
--network=iroha-network \
--entrypoint=/bin/bash \
hyperledger/iroha:develop

$ irohad --config config.docker --genesis_block genesis.block --keypair_name node3
~~~

irohadを起動するとpeer間の通信が始まります。
以下のログが出なければ通信が出来ています。

~~~
[2020-07-12 07:16:41.189637262][W][Irohad/AsyncNetworkClient]: RPC failed: Connect Failed
~~~

問題なくpeer間の通信が出来れば任意のirohaコンテナでトランザクションを発行すると他のpeerに伝播されます。

# 複数VM上での環境構築
冒頭の「記事の内容」にある2枚目の構成ですが、接続先を上述の手順に従って環境構築を行うとpeer間通信に失敗します。
Dockerの仕組みを詳しく理解出来ていないのですが、「some-posetgres」コンテナと「iroha」コンテナにネットワークの設定をしているので、そのネットワークに属しているコンテナ間での通信しか出来ていないようです。

iroha-networkの状態は以下の通りです。

~~~
$ docker network inspect iroha-network
[
    {
        "Name": "iroha-network",
        "Id": "7f1bece6bdc22c6b19c37d27688aade48f79ed535fc4559596b8ba37adb5ae32",
        "Created": "2020-07-06T10:05:55.231024539+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "0ecae19bc240761655a43ad873c21c88988f95a3e9166061039d739848c2627e": {
                "Name": "iroha2",
                "EndpointID": "830fc0b25dbc28d354d1f7ec3dc28bdc0f566fc1bdaba1bbc41e6e92538052fc",
                "MacAddress": "02:42:ac:12:00:07",
                "IPv4Address": "172.18.0.7/16",
                "IPv6Address": ""
            },
            "677a6d75ac0a03f06f1a52b4e75d5419ca276bcde64b99128d0d047ac3ad0f34": {
                "Name": "iroha3",
                "EndpointID": "afb8c6a29e3289ea37979d2fe282084b5ba04973bd4f6a10fed37827f18c60cd",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "7e6cbf92da619affbc28d163a31fd34bfc4c93ea92591e351247e321747d3f68": {
                "Name": "some-postgres3",
                "EndpointID": "a59da433970aec949b0d165fd3665d20b9ec88ddb9e47458cb4161309f4e0700",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "7efea6ca37944fa3fefc3f9fc9ce10159110626d968a3cb31df8fc46c235d26b": {
                "Name": "some-postgres2",
                "EndpointID": "9efc395b1c924d3dc19486b759c85ba2412176acc4c930448ebb21efb48e30ba",
                "MacAddress": "02:42:ac:12:00:05",
                "IPv4Address": "172.18.0.5/16",
                "IPv6Address": ""
            },
            "9a50c10cefa20a294e9e1435d397c26fb8d55b85321f78047ec55fdde0f41089": {
                "Name": "iroha1",
                "EndpointID": "d29d34a95ca89be928c054b4c6207c5e2d9c5d53138b158a9a3e8dde36d9a4f3",
                "MacAddress": "02:42:ac:12:00:06",
                "IPv4Address": "172.18.0.6/16",
                "IPv6Address": ""
            },
            "c91191410d2d0224ef4ad816305a0bc3d39864e72777de2eab1ec3038599bcf8": {
                "Name": "some-postgres1",
                "EndpointID": "78d8fe9782659cf99d161781e1dc91662ebb7bfb7042cce54bbf615169fc8110",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
~~~

恐らくですが、Dockerのオーバーレイネットワークというホストを跨ったコンテナ同士のネットワークを構築する仕組みを利用すれば接続が出来そうです。

ちなみにですが、「some-postgres」、「iroha」コンテナに「--network」の設定をしなかった場合、irohaデーモンの起動時に初期化に失敗します。

オーバーレイネットワークを使用した環境構築はおいおい試してみることにします。