LoginSignup
7
10

More than 5 years have passed since last update.

Hyperledger fabric(v0.6)でchaincodeの開発環境を構築する

Last updated at Posted at 2016-10-15

※2016/11/17追記
11/10にIBM Blockchainがβ版からv1.0になったので加筆しました。合わせてIBM Blockchainのfabricのversionは0.6.1となっています。

背景

今話題のオープンソースのブロックチェーンHyperledger fabricですが、環境を手軽に使えるという意味で私のような初心者は普段BluemixからIBM Blockchainのサービス(Starter Developer plan)を使っています。しかし、Bluemix側のサービスの計画メンテやネットワーク不具合などの原因で使用できなくなることが多々あります。例えば、最近だと新規のブロックチェーンのサービス追加が1週間以上に渡って停止されていたりしました。どうもネットワークに問題らしくデプロイに20分かかりますよーとのこと。

error.png

こうなると厄介なのはchaincodeの開発時で、長時間待ってデプロイは成功してもいざinvoke/query等で不具合が出た時は心が折れそうになります。これは一例ですが、他にもBluemix自体のレスポンスの遅さにストレスを感じてしまうことがあります。そうなるとPaaSの有難味はわかりつつも不要なデプロイ済みのchaincodeやブロックを増やさないためにも自前の環境を用意しておきたいところ。そういうわけでとりあえずchaincodeのテスト環境だけfabricのリポジトリから構築してみよう、とfabricのドキュメントを参考に見よう見まねで作ってみました。

開発環境構築の方法

公式ドキュメントの開発環境セットアップ方法によるとfabricの開発環境構築には大別して3つの方法があります。

  • Vagrantによる構築
  • Docker for Mac/Windowsを使用する方法
  • Docker ToolBoxを使用している場合

後者2つはDocker-composeを利用して各peerをDockerコンテナとして起動する方法です。しかし私の場合会社の開発環境がWindowsマシン(32bit)なのでDockerの動作対象外ということで、今回は1番目のVagrantによる環境構築を行ってみました。

fabricリポジトリのクローン

とりあえず適当な作業ディレクトリにfabricのリポジトリをクローンしてきます。

cd <WORKING_DIR>
git clone https://github.com/hyperledger/fabric.git

なお、fabricのmasterブランチ(v0.7)は現在アーキテクチャ変更の最中で、RESTサービスのpeerからの分離を進めています。2016/11/18時点ではmasterを使ってもREST-APIは未実装で使用できません。chaincodeのインターフェースなども変わっておりv0.6との互換性はないのでテスト目的に合わせたバージョンを取得しましょう。IBM-Blockchainの場合「サービス状況」タブから使用されているfabricのバージョンを調べることができます。

version2.png

コミットハッシュをもとに該当するバージョンを取得します。

cd <WORKING_DIR>/fabric
git checkout ee5b85c20f70b07bfd4fb6fb4dd023d49d9cbfc9

VMセットアップ

開発環境用のセットアップファイルのあるディレクトリに移動します。
cd <WORKING_DIR>/fabric/devenv

ディレクトリの中にはLinux仮想マシンを立ち上げるためのVagrantfileやセットアップ用のシェルスクリプトが用意されています。そのままで使えますが、仮想サーバ建てるのでリソースはそれなりに食います。嫌だーという人はAWS等に建てましょう。

Vagrantfile
vb.customize ['modifyvm', :id, '--memory', '4096']
    vb.cpus = 2

ちょっと弄って?1024MB/1CPUという値にしたらうちの会社の貧弱な32bitWindowsマシンでも動いてくれました。(それでも一応chaicodeのテストはできました)
vagrant up
初回起動は30分ぐらい待ちます。
仮想サーバが起動したらvagrant sshするだけです。

ここからは仮想サーバ上での作業となります。先程ローカルにクローンしたfabricのディレクトリはVagrantによって仮想サーバ上の$GOPATH/src/hyperledger配下に共有されています。
まずはchaincodeを登録するための開発用peerノードをビルドします。

cd $GOPATH/src/github.com/hyperledger/fabric/
make peer

ビルドが終わるとpeerコマンドから開発オプションを付けてpeerを起動できます。

peer node start --peer-chaincodedev

register & enrollされた特定のユーザにしかトランザクションを実行させたくない、という場合は
CORE_SECURITY_ENABLED=true CORE_SECURITY_PRIVACY=true peer node start --peer-chaincodedev
でセキュリティオプションを有効にできます。今回はとにかくchaincodeを動かせればいい、という目的なのでセキュリティ設定はなしで進めます。
上のセキュリティ設定も含めたpeerの設定はpeer/core.yamlに定義されておりpeer node start実行時に読み込まれます。例えばREST-APIの設定は下記のラインで定義されています。

core.yaml
rest:
    # The address that the REST service will listen on for incoming requests.
    address: 0.0.0.0:7050

peer自体はLinux仮想マシン上でdockerコンテナとして起動され、Vagrantのポートフォワーディングの設定によってlocalhost:7050でホストマシンからREST-APIを利用できるというわけですね。(REST-APIについては後述)

Vagrantfile
 config.vm.network :forwarded_port, guest: 7050, host: 7050 # Openchain REST services

chaincodeの準備

さて、peerだけ立ち上げても主役がいないことには意味が無いのでchaincodeを準備します。peerを起動したのとは別のターミナルを立ち上げて作業をしていきます。
今回使うchaincode

IBM Blockchainではデプロイ時にパスとしてgithubのURLを指定しないといけないのですが、fabricではローカルのchaincodeもデプロイできます。別のターミナルを起動して、$GOPATH/src/以下にchaincodeを置くためのディレクトリを作成します。$GOPATH/srcの下であればどこでも良いようですが、ここでは$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/go/sampleとします。sample.goを配置し、ビルドします。

go build

chaincodeの登録

chaincodeの開発モード(devモード)ではchaincode名を指定してdeployする必要があります。正確にはChaincodeSpecつまりJSON-RPC 2.0形式のリクエストにおいてdeployメソッドに渡すparamschaincodeID.nameフィールドの指定が必須です(※)。しかし名前は単に付ければ良いわけではなく、deployの前段階としてchaincodeの登録(register)という作業で名前を登録する必要があります。IBM Blockchainには存在しない手順なのでIBM Blockchain利用者は注意しましょう。
とはいっても1行で終わりです。chaincodeをビルドした先で、

CORE_CHAINCODE_ID_NAME=mycc CORE_PEER_ADDRESS=0.0.0.0:7051 ./sample

これで実行可能バイナリsampleがmyccという名前で登録できました。命名ルール等はなく、任意の名前が登録可能です。(とはいえ識別しやすい名前を付けましょう)registerに成功すると
[shim] DEBU : Received REGISTERED, ready for invocations
というメッセージが出るのでついdeployを飛ばしてinvokeから実行したくなりますが、register後でもdeployは必要です。

※ちなみにP2Pのネットワークを立ち上げる本番モード(netモード)ではchaincodeID.pathの指定が必須です。常にnetモードで動作しているIBM-Blockchainではgithubのパス等を指定する必要があるというわけです。

REST-APIへのリクエスト

あとはcurlやらPostmanで先程のREST-APIのエンドポイントに対してdeploy→invoke/queryの順でリクエストを投げていくだけです。

  • Block
    • GET /chain/blocks/{Block}
  • Blockchain
    • GET /chain
  • Chaincode
    • POST /chaincode
  • Network
    • GET /network/peers
  • Registrar
    • POST /registrar
    • DELETE /registrar/{enrollmentID}
    • GET /registrar/{enrollmentID}
    • GET /registrar/{enrollmentID}/ecert
    • GET /registrar/{enrollmentID}/tcert
  • Transactions
    • GET /transactions/{UUID}

今回はlocalhost:7050/chaincodeに対するリクエストボディを作成し、PostmanからREST-APIの/chaincodeエンドポイントに対してPOSTしてみます。注意点としては、リクエストパラメータのctorMsgフィールドは今までのIBM Blockchain(v0.5-developer-preview)では下記のように関数名と引数を別々に渡していました。

"ctorMsg": {
  "function": "string",
  "args": [
    "string"
      ]
 },

しかしv0.6ではfunctionフィールドはargsに統合され、関数名をargs[0]として受取り、引数をargs[1]以降に設定するように変更されています。

"ctorMsg": {
  "args": ["string"]
},

とはいえv0.6ではv0.5-developer-previewと互換性があり旧形式のリクエストも正常に受け付けられる仕様になっています。(IBM Blockchainのデフォルトではv0.5の形式のリクエストパラメータが設定されます)。しかし今後のバージョンでは廃止されると思われるので今回はv0.6形式でREST-APIリクエストを作成します。

Deploy

deploy時に初期化関数initが実行されます。deployは少なくともargs[0](関数名)があればOKです。今回は引数を取らないので関数名のみを入れています。

{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID":{
        "name": "mycc"
    },
    "ctorMsg": {
      "args": ["init"]
    }
  },
  "id": 1
}

無事に帰ってきました。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "mycc"
  },
  "id": 1
}

Invoke

次にinvokeのリクエストをPOSTしてみましょう。ここでは単一のキーに文字列を格納するだのトランザクションです。args[1]で書き込まれる値を指定します。

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "args": ["write", "This is my first chaincode"]
    }
  },
  "id": 3
}

結果が帰ってきたらトランザクションによってfabricにおけるworld state(世界の状態)が変更されたということです。と大げさに言いますが("key1","This is my first chaincode")というペアがKVSに格納されたということです。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "0b694fb0-6cfb-490b-9f28-e619ac2531f8"
  },
  "id": 3
}

Query

記録された値をqueryで確認してみましょう。args[1]でキーを指定してworld stateの値を取得します。

{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "args": ["read", "key1"]
    }
  },
  "id": 3
}
{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "This is my first chaincode"
  },
  "id": 3
}

デプロイも早く、いちいちタブでログ画面を開かなくてもログを標準出力に出してくれるしテストは格段に快適になりました。これなら不具合が出ても自分でトラブルシューティングできますしね。次はdockerを使ってpeerネットワークやコンセンサスアルゴリズムの検証環境も構築して試してみたいところ。

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10