Docker Composeを使ってHyperledger Fabricのサンプルチェーンコードfabcarを試してみる

# はじめに

以下書籍を参考にHyperledger Fabricのサンプルチェーンコードfabcarを試したのでまとめておきます。


* [ブロックチェーン技術の教科書](https://www.amazon.co.jp/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%83%81%E3%82%A7%E3%83%BC%E3%83%B3%E6%8A%80%E8%A1%93%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E4%BD%90%E8%97%A4-%E9%9B%85%E5%8F%B2/dp/4863542437/ref=sr_1_1?ie=UTF8&qid=1525396206&sr=8-1&keywords=%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%83%81%E3%82%A7%E3%83%BC%E3%83%B3%E6%8A%80%E8%A1%93%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8)

サンプルのチェーンコードfabcarはDocker Composeの用意があり、チェーンコードの実行リクエストをしてみることで処理の流れをみることができるのでとりあえず試したい方には最適だと思います。

なお後述しますがgRPCのバージョンアップ対応をする必要があるのでそこだけ書籍と手順が異なります。

# 環境

* Mac 
* Docker version 18.03.0-ce, build 0520e24
* Hyperledger Fabric v1.05
* node v8.11.1

# 手順

まずは環境の準備をしていきます。

```
# Docker HubからDocker Imageの取得
$ curl -sSL https://goo.gl/byy2Qj | bash -s 1.0.5

# サンプルチェーンコードがまとまっているリポジトリをclone
$ git clone https://github.com/hyperledger/fabric-samples.git

# Node.jsライブラリのインストール
$ cd fabric-samples/fabcar/
$ npm install
$ npm install --save-dev grpc@1.10.1
$ npm install --save composer-cli@0.18.1 composer-client@0.18.1 composer-rest-server@0.18.1

# サンプル環境の起動(../basic-network/docker-compose.yml のdocker-compose upしてます)
$ ./startFabric.sh 
```

gRPCのバージョンを指定しているのは下記issueに詳しいですが今回のfabcarのチェーンコードを試そうとすると後述のinvoke.jsを実行するときにプロパティが見つからない、というエラーが出るための対応です。

* [Cannot read property 'getConnectivityState' #3948](https://github.com/hyperledger/composer/issues/3948)
* [Error on composer network ping --card #3944](https://github.com/hyperledger/composer/issues/3944)

ここまで正常にできていると以下のようにDocker composeによってコンテナが起動されているのが確認できます。

```
$ docker-compose ps
         Name                       Command               State                       Ports                     
----------------------------------------------------------------------------------------------------------------
ca.example.com           sh -c fabric-ca-server sta ...   Up      0.0.0.0:7054->7054/tcp                        
cli                      /bin/bash                        Up                                                    
couchdb                  tini -- /docker-entrypoint ...   Up      4369/tcp, 0.0.0.0:5984->5984/tcp, 9100/tcp    
orderer.example.com      orderer                          Up      0.0.0.0:7050->7050/tcp                        
peer0.org1.example.com   peer node start                  Up      0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp
```

構築できた環境に対してadminユーザとuser1の登録をしていきます。

```
# Adminユーザのエンロール実行
$ node enrollAdmin.js
# user1の登録とエンロール実行
$ node registerUser
```

ここで一度クエリをなげてみます。

```
$ node query.js 
Store path:/Users/masayuki5160/Documents/workspace/fabric-samples/fabcar/hfc-key-store
Successfully loaded user1 from persistence
Query has completed, checking results
Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},{"Key":"CAR1", "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},{"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},{"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},{"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},{"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},{"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},{"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},{"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},{"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]
```

初期状態だと上記のような感じで台帳に記録されています。
ここで用意されているinvoke.jsを利用して台帳に書き込みをしてみます。
まずはinvoke.js内にあるrequestオブジェクトに下記のように修正をします。

```
$ vim invoke.js
$ git diff
diff --git a/fabcar/invoke.js b/fabcar/invoke.js
index 1c0270a..323921c 100644
--- a/fabcar/invoke.js
+++ b/fabcar/invoke.js
@@ -61,8 +61,8 @@ Fabric_Client.newDefaultKeyValueStore({ path: store_path
        var request = {
                //targets: let default to the peer assigned to the client
                chaincodeId: 'fabcar',
-               fcn: '',
-               args: [''],
+               fcn: 'createCar',
+               args: ['CAR10', 'Honda', 'Accord', 'Black', 'Tom'],
                chainId: 'mychannel',
                txId: tx_id
        };
```

これで準備ができたので実際に台帳に書き込みをします。

```
$ node invoke.js 
Store path:/Users/masayuki5160/Documents/workspace/fabric-samples/fabcar/hfc-key-store
Successfully loaded user1 from persistence
Assigning transaction_id:  44047eb06410122a3bb59c845fe018e4d5dc3e250e61455be069f8f326214b6a
Transaction proposal was good
Successfully sent Proposal and received ProposalResponse: Status - 200, message - "OK"
The transaction has been committed on peer localhost:7053
Send transaction promise and event listener promise have completed
Successfully sent transaction to the orderer.
Successfully committed the change to the ledger by the peer
```

user1の認証がされてエンドーサーによるトランザクションの提案の承認後(エンドースメント完了)、Ordererにトランザクションが送信され台帳が各peerで更新された、ということがログで出ているんだと思います。
(認識違ってたらどなたか指摘をw)

改めてquery.jsを実行して台帳を確認すると追加したCAR10が入っているのが確認できます。

```
$ node query.js 
Store path:/Users/masayuki5160/Documents/workspace/fabric-samples/fabcar/hfc-key-store
Successfully loaded user1 from persistence
Query has completed, checking results
Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},{"Key":"CAR1", "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},{"Key":"CAR10", "Record":{"colour":"Black","make":"Honda","model":"Accord","owner":"Tom"}},{"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},{"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},{"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},{"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},{"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},{"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},{"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},{"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]
```

# まとめ

今回試したのはクライアントとしてトランザクションの提案をしチェーンコードの実行リクエストをするところですがどういったフローで処理が流れていくか確認するにはちょうどいいなと思います。

Hyperledger Fabricはまだ勉強中なので違っている点などありましたらぜひフィードバックください！