Help us understand the problem. What is going on with this article?

Hyperledger Fabric のチェーンコードを実装する

More than 1 year has passed since last update.

オープンソースのブロックチェーン Hyperledger Fabric を試してみる の続き

Hyperledger Fabric のチェーンコードを書いてみたときのメモです。
Bluemix 上の IBM Blockchain を使っています。

途中までのメモ書きなので、また随時書き足していく予定です。

チェーンコードとは

チェーンコードは Fabric ネットワーク上にデプロイされ、トランザクションを処理するプログラムコードです。
Fabric では、スマートコントラクトをチェーンコードとして実現しています。

今現在、Fabric がサポートしているチェーンコードの開発言語は Go と Java で、JavaScript も近い将来に追加されるとのことです。
今回は Go を使ってチェーンコードを書いていきます。

開発言語については Q&A で取り上げられています:
http://hyperledger-fabric.readthedocs.io/en/latest/FAQ/chaincode_FAQ/

チェーンコードを書いてみる

今回は、IBM Blockchain の learn-chaincode にチェーンコード実装のチュートリアルがあるため、それに沿って進めてみます。
https://github.com/IBM-Blockchain/learn-chaincode

サンプルのチェーンコードをクローンする

まず https://github.com/IBM-Blockchain/learn-chaincode をフォークし、ローカル環境の $GOPATH/src/github.om/<GITHUB_ID>/ にクローンします。

% cd $GOPATH
% mkdir -p src/github.com/<YOUR_GITHUB_ID_HERE>/
% cd src/github.com/<YOUR_GITHUB_ID_HERE>/
% git clone https://github.com/<YOUR_GITHUB_ID_HERE>/learn-chaincode.git

GOPATH は Go のワークスペースの場所を指します。未設定の場合は、以下のように設定してください。
(GOPATH について: http://golang-jp.org/doc/code.html#GOPATH)

export GOPATH=$HOME/.go
export PATH=$PATH:$GOPATH/bin

その他、Go の環境セットアップについては以降割愛します。Go についての基礎はこちら。
- Go 言語のインストール http://golang.jp/install
- Go コードの書き方 http://golang-jp.org/doc/code.html

クローンしたリポジトリには、startfinished の二つのバージョンのチェーンコードがあります。

start にあるチェーンコードを変更しつつ、迷ったら finished を都度参照するという形で進めます。

ローカル環境でビルドを確認する

次に start のチェーンコードをローカル環境でビルドしてみて、正常に実行可能かの確認をします。

% cd $GOPATH/src/github.com/<YOUR_GITHUB_ID_HERE>/learn-chaincode/start
% go build ./
chaincode_start.go:23:2: cannot find package "github.com/hyperledger/fabric/core/chaincode/shim" in any of:
        /Users/<USER_NAME>/.anyenv/envs/goenv/versions/1.4/src/github.com/hyperledger/fabric/core/chaincode/shim (from $GOROOT)
        /Users/<USER_NAME>/.go/src/github.com/hyperledger/fabric/core/chaincode/shim (from $GOPATH)

ビルドするとエラーが出ました。環境設定が上手くいっていないようなので、以下を確認します。
https://github.com/IBM-Blockchain/learn-chaincode/blob/6827af167c8e46c289c1cb23d96b36fe97846875/docs/setup.md

Hyperledger Fabric が必要なようなので、クローンします。
Bluemix 上の IBM Blokchain では v0.5-developer-preview が使用されているので、それをローカルにクローンします。

% mkdir -p $GOPATH/github.com/hyperledger
% cd $GOPATH/github.com/hyperledger
% git clone -b v0.5-developer-preview https://github.com/hyperledger-archives/fabric.git

また、v0.5-developer-preview に対応しているのは v1.0 ブランチなので、そちらに切り替えます。

% cd $GOPATH/src/github.com/<YOUR_GITHUB_ID_HERE>/learn-chaincode
% git checkout v1.0

これで再度ビルドします。

% cd $GOPATH/src/github.com/<YOUR_GITHUB_ID_HERE>/learn-chaincode/start
% go build ./
% ls
chaincode_start.go start

今度は上手くいきました。ビルド結果の start が作成されています。

チェーンコードを書き換える

作成したコードはこちらにあります。
https://github.com/kyrieleison/learn-chaincode/blob/v1.0/start/chaincode_start.go

チェインコードを書くときには、3つの関数(init, invoke, query)と main 関数が必要です。

  • init
    • チェーンコードをデプロイしたときに呼び出される関数で、チェーンコードに必要な初期化処理を行います
    • 今回は初期化処理として、与えられた引数を hello_world キーに対するバリューとしてステートに追加しています
  • invoke
    • 何か実作業を行うための関数を呼び出したいときに呼び出す関数で、チェーン上のブロックにグループ分けされたトランザクションとして記録されます。function パラメータを受取って、その関数を実行するようにします
    • 今回は function パラメータとして write を受け取ったとき、二つの引数のうち一つをキー、もう一つをそのキーのバリューとしてステートに書き込みます
  • query
    • チェーンコードのステートを照会するときに呼び出す関数で、キーバリュー型のステートを取得します
    • 今回は function パラメータとして read を受け取ったとき、その引数をキーとしてステートを取得し、バリューを返します

REST API で確認する

チェーンコードがデプロイ・実行・参照できるかを、IBM Blockchain の REST API で確認してみます。

チェーンコードの操作にはユーザログインが必要なので、Registrar API で任意のユーザにログインします。

POST https://b43adcdd35ba429d9a5045427432ee82-vp2.us.blockchain.ibm.com:444/registrar
{
  "enrollId": "<ENROLL_ID>",
  "enrollSecret": "<ENROLL_SECRET>"
}

{
  "OK": "Login successful for user '<ENROLL_ID>'."
}

無事にログインできたら、Chaincode API でチェインコードをデプロイします。chaincodeID.path には、自分のフォークしたリポジトリのパスを指定します。

POST https://b43adcdd35ba429d9a5045427432ee82-vp2.us.blockchain.ibm.com:444/chaincode
{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "path": "https://github.com/kyrieleison/learn-chaincode/start"
    },
    "ctorMsg": {
      "function": "init",
      "args": [
        "hi there"
      ]
    },
    "secureContext": "<ENROLL_ID>"
  },
  "id": 1
}

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32001,
    "message": "Deployment failure",
    "data": "Error when deploying chaincode: Error getting chaincode package bytes: Error getting code 'go get' failed with error: 'exit status 2'\n# github.com/kyrieleison/learn-chaincode/start\n/go/_usercode_/440950172/src/github.com/kyrieleison/learn-chaincode/start/chaincode_start.go:41: undefined: shim.ChaincodeStubInterface\n/go/_usercode_/440950172/src/github.com/kyrieleison/learn-chaincode/start/chaincode_start.go:50: undefined: shim.ChaincodeStubInterface\n/go/_usercode_/440950172/src/github.com/kyrieleison/learn-chaincode/start/chaincode_start.go:63: undefined: shim.ChaincodeStubInterface\n"
  },
  "id": 1
}

デプロイが失敗しました。
undefined: shim.ChaincodeStubInterface... というエラーが出ていますが、これは v2.0 のAPIです。
v1.0 のブランチに対してコードをプッシュしていて、しかし パスに指定していた https://github.com/kyrieleison/learn-chaincode/start はデフォルトブランチである master ブランチのコードを go get するため、v2.0 のコードが読み込まれてエラーになったようです。

そこで、リポジトリにある v1.0 ブランチを、デフォルトブランチに変更して再度実行してみました。

POST https://b43adcdd35ba429d9a5045427432ee82-vp2.us.blockchain.ibm.com:444/chaincode
{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "path": "https://github.com/kyrieleison/learn-chaincode/start"
    },
    "ctorMsg": {
      "function": "init",
      "args": [
        "hi there"
      ]
    },
    "secureContext": "<ENROLL_ID>"
  },
  "id": 1
}

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

無事にデプロイに成功し、チェーンコードIDが返ってきました。

続けて、チェーンコードを実行してみます。chaincodeID に返ってきたハッシュを指定し、function に実行したい関数名(ここでは write)、args に関数へ渡したい引数(ここでは hi therego away)を指定します。

POST https://b43adcdd35ba429d9a5045427432ee82-vp2.us.blockchain.ibm.com:444/chaincode
{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "25b17bfcb3236793de06648ca4a094e2922af5f21ff68431486205b1c59e3fbede189133b4a71ba04af63ee061a11ef7a705f6a4ed01409377bf705865b0c51c"
    },
    "ctorMsg": {
      "function": "write",
      "args": [
        "hi there", "go away"
      ]
    },
    "secureContext": "<ENROLL_ID>"
  },
  "id": 1
}

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "a9e2faeb-feb2-4753-a0a4-ab3f9738f165"
  },
  "id": 1
}

チェーンコードが実行され、トランザクションの UUID が返ってきました。

最後はステートが更新されたのかを確認するため、ステートを参照します。
実行時と同様に chaincodeID に返ってきたハッシュを指定し、function に実行したい関数名(ここでは read)、args に関数へ渡したい引数(ここでは hi there というキー)を指定します。

POST https://b43adcdd35ba429d9a5045427432ee82-vp2.us.blockchain.ibm.com:444/chaincode
{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "25b17bfcb3236793de06648ca4a094e2922af5f21ff68431486205b1c59e3fbede189133b4a71ba04af63ee061a11ef7a705f6a4ed01409377bf705865b0c51c"
    },
    "ctorMsg": {
      "function": "read",
      "args": [
        "hi there"
      ]
    },
    "secureContext": "<ENROLL_ID>"
  },
  "id": 1
}

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

hi there というキーに対して、go away というバリューが返ってきました。
これでチェーンコードが実行されたことできちんとステートが更新されていることが分かりました。

チェーンコードを書くのに役立つコードやドキュメント

Hyperledger Fabric の examples/chaincode に Go と Java のサンプルコードがあるので、どういったことができるのか参考になると思います。
公式ドキュメントでは chaincode_example02.go がよく使われています。
https://github.com/hyperledger/fabric/tree/master/examples/chaincode

また、ソースコードは fablic/core/chaincode にあります。
https://github.com/hyperledger/fabric/tree/master/core/chaincode

チェーンコードAPIのドキュメントはこちらにあるので、本格的に始める場合は参照すると良さそうです。
https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした