JoTech

日々学んだことを垂れ流します

ブロックチェーン基盤 Hyperledger Fabric v1.0 アプリケーションの実装

はじめに

今回はHyperledger Fabricのサンプルアプリケーションを動かしてみます。本エントリは次のページで紹介されている手順に従って進めていきます。

Writing Your First Application — hyperledger-fabricdocs master documentation

実行環境

  • Max OS High Sierra Version 10.13
  • Docker version 17.09.0-ce
  • Docker Compose version 1.16.1
  • Go version 1.9
  • Node.js version 8.6

Hyperledger Fabricのダウンロード

次のコマンドを実行します。

$ mkdir ~/fabric
$ cd ~/fabric
$ curl -sSL https://goo.gl/Q3YRTi | bash

これによりブロックチェーンネットワークを構築するために必要な次のバイナリを入手します。

  • cryptogen
  • configtxgen
  • configtxlator
  • peer
$ ls bin
configtxgen     configtxlator       cryptogen       get-docker-images.sh    orderer         peer

スクリプトはHyperledger FabricのdockerイメージをDocker Hubよりダウンロードします。

$ docker images
REPOSITORY                     TAG                    IMAGE ID            CREATED             SIZE
hyperledger/fabric-ca          latest                 2736904862db        10 days ago         218MB
hyperledger/fabric-ca          x86_64-1.1.0-preview   2736904862db        10 days ago         218MB
hyperledger/fabric-tools       latest                 c584c20ac82b        10 days ago         1.42GB
hyperledger/fabric-tools       x86_64-1.1.0-preview   c584c20ac82b        10 days ago         1.42GB
hyperledger/fabric-couchdb     latest                 5b8a15e6e972        10 days ago         1.57GB
hyperledger/fabric-couchdb     x86_64-1.1.0-preview   5b8a15e6e972        10 days ago         1.57GB
hyperledger/fabric-kafka       latest                 cf09c5534ef9        10 days ago         1.37GB
hyperledger/fabric-kafka       x86_64-1.1.0-preview   cf09c5534ef9        10 days ago         1.37GB
hyperledger/fabric-zookeeper   latest                 ac127485fdc7        10 days ago         1.37GB
hyperledger/fabric-zookeeper   x86_64-1.1.0-preview   ac127485fdc7        10 days ago         1.37GB
hyperledger/fabric-orderer     latest                 2fccc91736df        10 days ago         159MB
hyperledger/fabric-orderer     x86_64-1.1.0-preview   2fccc91736df        10 days ago         159MB
hyperledger/fabric-peer        latest                 337f3d90b452        10 days ago         165MB
hyperledger/fabric-peer        x86_64-1.1.0-preview   337f3d90b452        10 days ago         165MB
hyperledger/fabric-javaenv     latest                 cd459b218651        10 days ago         1.49GB
hyperledger/fabric-javaenv     x86_64-1.1.0-preview   cd459b218651        10 days ago         1.49GB
hyperledger/fabric-ccenv       latest                 82489d1c11e8        10 days ago         1.35GB
hyperledger/fabric-ccenv       x86_64-1.1.0-preview   82489d1c11e8        10 days ago         1.35GB

開発環境のセットアップ

Hyperledger Fabricのサンプルをgitでcloneします。

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

以降では次のfabcarディレクトリで作業します。

$ cd fabcar
$ ls
enrollAdmin.js  invoke.js   package.json    query.js    registerUser.js startFabric.sh

念のためdockerコンテナとネットワークを削除しておきます。

$ docker rm -f $(docker ps -aq)
$ docker network prune

すでに以降の作業を実施済みの場合には次のコマンドでfabcarチェインコード用のdockerイメージも削除します。

$ docker rmi dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba

アプリケーションの実行に必要なライブラリをインストールするため次のコマンドを実行します。 以降ではCAサーバにアクセスするためにnode_modules/fabric-ca-client、 peerやordering serviceと対話するためにnode_modules/fabric-clientを使用していきます。

$ npm install

続けて次のスクリプトを実行することでネットワークを起動します。このコマンドはFabricの各コンテナを用意します。 fabcarネットワークの詳細はこちらに説明があります。
Understanding the Fabcar Network — hyperledger-fabricdocs master documentation

$ ./startFabric.sh
$ docker images
REPOSITORY                                                                                               TAG                    IMAGE ID            CREATED             SIZE
dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba   latest                 bf75bac8b3f9        2 minutes ago       151MB
...
$ docker ps
CONTAINER ID        IMAGE                                                                                                    COMMAND                  CREATED             STATUS              PORTS                                            NAMES
b4b2e2be6dc7        dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba   "chaincode -peer.a..."   4 minutes ago       Up 4 minutes                                                         dev-peer0.org1.example.com-fabcar-1.0
a4f01226a050        hyperledger/fabric-tools                                                                                 "/bin/bash"              6 minutes ago       Up 6 minutes                                                         cli
dbce2a81cb36        hyperledger/fabric-peer                                                                                  "peer node start"        7 minutes ago       Up 7 minutes        0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp   peer0.org1.example.com
c83fd30320e2        hyperledger/fabric-couchdb                                                                               "tini -- /docker-e..."   7 minutes ago       Up 7 minutes        4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp       couchdb
0dd907f8cce3        hyperledger/fabric-orderer                                                                               "orderer"                7 minutes ago       Up 7 minutes        0.0.0.0:7050->7050/tcp                           orderer.example.com
86ef00f4705d        hyperledger/fabric-ca                                                                                    "sh -c 'fabric-ca-..."   7 minutes ago       Up 7 minutes        0.0.0.0:7054->7054/tcp                           ca.example.com

ユーザの登録

前述のネットワーク立ち上げ時にadminユーザが認証局(CA)に登録されています。
enrollAdmin.jsでadminの電子証明書(eCert)を取得します。 このプログラムは公開鍵と秘密鍵をhfc-key-storeに作成し、証明書署名要求(CSR)で公開鍵証明書を発行します。
続けて、registerUser.jsではadminユーザでCAと通信しLedgerにアクセスするuser1ユーザを登録します。このプログラムもまた、CSRを実行し証明書と鍵をhfc-key-storeに出力します。

$ node enrollAdmin.js
$ node registerUser.js
$ ls hfc-key-store/
admin                                   
...-pub
...-priv
user1
...-pub
...-priv

Ledgerの参照

query.jsを使用し、fabcarチェインコードのqueryAllCarsを呼び出します。

fabric-samples/fabcar/query.js

const request = {
    chaincodeId: 'fabcar',
    fcn: 'queryAllCars',
    args: ['']
};
$ node query.js
Store path:.../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"}}]

実行したチェインコードの関数は次の通りです。

fabric-samples/chaincode/fabcar/fabcar.go

func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {

    startKey := "CAR0"
    endKey := "CAR999"

    resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)

LedgerにアクセスするAPIの仕様はこちらにあります。 godoc.org github.com

Ledgerの更新

fabcarチェインコードのcreateCarで新たなCARをLedgerに追加します。

fabric-samples/fabcar/invoke.js

var request = {
    chaincodeId: 'fabcar',
    fcn: 'createCar',
    args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'],
    chainId: 'mychannel',
    txId: tx_id
};

fabric-samples/chaincode/fabcar/fabcar.go

func (s *SmartContract) createCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

    if len(args) != 5 {
        return shim.Error("Incorrect number of arguments. Expecting 5")
    }

    var car = Car{Make: args[1], Model: args[2], Colour: args[3], Owner: args[4]}

    carAsBytes, _ := json.Marshal(car)
    APIstub.PutState(args[0], carAsBytes)

    return shim.Success(nil)
}
$ node invoke.js 
Store path:.../fabric-samples/fabcar/hfc-key-store
Successfully loaded user1 from persistence
Assigning transaction_id:  97ae720f071443b8f73b5ab1e8ed1a87d8a04ba3904479f24cdb146486edcbfa
Transaction proposal was good
Successfully sent Proposal and received ProposalResponse: Status - 200, message - "OK"
info: [EventHub.js]: _connect - options {}
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

最後にCAR10が正しく追加されているかを確認します。 fabcarのqueryCarに引数CAR10を渡し、query.jsを実行します。

query.js

const request = {
    chaincodeId: 'fabcar',
    fcn: 'queryCar',
    args: ['CAR10']
};

fabric-samples/chaincode/fabcar/fabcar.go

func (s *SmartContract) queryCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

    if len(args) != 1 {
        return shim.Error("Incorrect number of arguments. Expecting 1")
    }

    carAsBytes, _ := APIstub.GetState(args[0])
    return shim.Success(carAsBytes)
}
$ node query.js 
Store path:.../fabric-samples/fabcar/hfc-key-store
Successfully loaded user1 from persistence
Query has completed, checking results
Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"}

期待通りの結果が得られました。

さいごに

本エントリではサンプルアプリケーションfabcarを動かしてみました。 Ledgerにアクセスするアプリケーションの実装イメージが少し湧いた気がします。
次回はまだ未定ですが、JavaアプリケーションからHyperledger Fabric SDKを使用してみたいと考えてます。