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

[ブロックチェーン] BluemixでOpen Blockchainを動作させよう!

More than 3 years have passed since last update.

BluemixでOpen Blockchainが使えるようになりました。Open BlockchainはEthreum同様コードを埋め込むタイプのスマートコントラクトが実装されているブロックチェーンです。この記事では、このコードを実行させる手順を解説します。

Bluemixの準備

2016年3月ごろよりBluemixにブロックチェーンのサービスがβ版ではありますが、提供されるようになりました。この記事ではこのブロックチェーンサービスを使用します。そのため以下の準備が必要です。

  • Bluemixのアカウント
    • 現在は30日間限定ですが無料でしかもクレジットカードの登録も必要なくBluemixのアカウントを作成できます。
  • ブロックチェーンサービスの起動
    • 組織、地域、スペースを作成が必要です。
    • その後の手順はこちらを行ってください。

以上を行うと以下のような画面が表示されます。
bc0616.png

これで3台のノード(検証ノード×2 + 認証ノード)が自動的に構築されOpen Blockchainが利用可能になります。

Open Blockchain

Bluemixのブロックチェーンサービスは内部でOpen Blockchainが動いています。Open Blockchainはオープンソースなので自分でノードを立てることもできますが、Bluemixを使うとお手軽なのでこちらをここでは使用します。

Chaincode

Open Blockchainでは取引をユーザが定義します。そして取引の定義が記述されたものをChaincodeと呼びます。

Chaincodeの中身はソースコードで現在はGo言語でのみ記述することができ以下の3つの関数で構築されます。

  • Init関数
    • 初期化処理を記述する
    • 後述のデプロイ操作時に実行される
  • Invoke関数
    • 一般的な取引に当たるようなものを記述する
  • Query関数
    • データの参照を行うような処理を記述する

Open Blockchainを使う

ベースURIとenrollIDの確認

Bluemixのブロックチェーンサービスを起動した時の画面を開き下図赤枠のAPIsのタブを開いてください。

base.png

  • ベースURI

この青枠がAPIのベースURIです。たまに表示されないことがあるのでその時は更新やサービスの再起動などを試してください。

  • enrollID

緑枠をクリックするとenrollIDとそのシークレットキーの組が表示されます。(ユーザによって権限が違うかもしれません。dashboarduser_*****というユーザだとこの後の操作を行えることを確認しています。)

ログイン

Open Blockchainではセキュリティの項目を有効にしているとChaincodeの実行にログインしているenrollIDが必要になります。
そのためにまずはログインします。

ログインでは

<ベースURI>/registrar

# 例) https://ab12cde3-45gh-6i78-900-abcf1234567d_vp1-api.blockchain.ibm.com:443/registrar 

に対し以下のjsonを投げることになります

{ 
  "enrollId": "<enrollID>", 
  "enrollSecret": "<シークレットキー>" 
} 

なのでcurlでやると以下のような感じになります。

curl -H "Content-type: application/json" \
-X POST \
-d '{ "enrollId": "<enrollID>", 
"enrollSecret": "<シークレットキー>" 
} \
' <ベースURI>/registrar

そして結果が

{"OK": "Login successful for user '********'."}

というように返ってきます。
これでログインは完了です。

Chaincodeの実行

Open Blockchainでトランザクションは以下の3つのステップで行われます。

  1. Chaincodeのデプロイ
    • ブロックチェーン上にChaincodeを取り込ませることでChaincodeで定義された取引(Init, Invoke, Query)が実行可能になる
    • デプロイを行うと同時にInit関数が実行される
  2. トランザクションの実行
    • デプロイしたChaincodeのInvoke関数を呼び出しトランザクションを生成する
  3. データの参照
    • トランザクションにより追加・変更されたデータを参照するためQuery関数を呼び出す

ここからは用意したChaincodeのサンプル
https://github.com/ko-he-/tech-circle_blockchain/tree/master/example02
を使って上記3ステップを行なっていきます。

Chaincodeのサンプル

今回実行するChaincodeのサンプル
https://github.com/ko-he-/tech-circle_blockchain/tree/master/example02
は以下のものです。

package main

import (
        "errors"
        "fmt"

        "github.com/hyperledger/fabric/core/chaincode/shim"
        )

type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
    if len(args) != 0 {
        fmt.Println("Error: Incorrect number of arguments. Expecting 0")
        return nil, errors.New("Incorrect number of arguments. Expecting 0")
    }

    return nil, nil
}

func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
    var key string
    var value string
    var err error

    if len(args) != 2 {
        return nil, errors.New("Incorrect number of arguments. Expecting 2")
    }

    key = args[0]
    value = args[1]
    valbyte := []byte(value)


    err = stub.PutState(key, valbyte)
    if err != nil {
        return nil, err
    }


    return nil, nil
}


func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
    if function != "query" {
        return nil, errors.New("Invalid query function name. Expecting \"query\"")
    }
    var key string
    var err error

    if len(args) != 1 {
        return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
    }

    key = args[0]

    valbytes, err := stub.GetState(key)
    if err != nil {
        jsonResp := "{\"Error\":\"Failed to get state for " + key + "\"}"
        return nil, errors.New(jsonResp)
    }

    if valbytes == nil {
        jsonResp := "{\"Error\":\"Nil amount for " + key + "\"}"
        return nil, errors.New(jsonResp)
    }

    message := "Key:" + key + " Value:" + string(valbytes)
    return []byte(message), nil
}

func main() {
    err := shim.Start(new(SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}

このChaincodeでは

  • Init関数
    • なにもしない
  • Invoke関数
    • ブロックチェーン上にkeyとvalueのペアで文字列を保存
  • Qquery関数
    • keyからvalueを呼び出し表示

を行なっています。

Chaincodeのデプロイ(Init)

Chaincodeをデプロイして定義した取引を有効にしていきます。

デプロイでは、Chaincodeがある場所のpathを指定して実行します。今回はGithub上に置いてあるのでそこを指定します。また、Go言語のファイル自体ではなく、それが入っているフォルダを指定することも注意してください。

APIの実行は

<ベースURI>/chaincode

# 例) https://ab12cde3-45gh-6i78-900-abcf1234567d_vp1-api.blockchain.ibm.com:443/chaincode 

に対し以下のjsonを投げることになります。
この後のInvoke、Queryの実行もAPIのエンドポイントは同じです。

{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "path": "https://github.com/ko-he-/tech-circle_blockchain/example02"
    },
    "ctorMsg": {
      "function": "init",
      "args": [
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}

なのでcurlでやると以下のような感じになります。

curl -H "Content-type: application/json" \
-X POST \
-d '{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "path": "https://github.com/ko-he-/tech-circle_blockchain/example02"
    },
    "ctorMsg": {
      "function": "init",
      "args": [
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}' \
<ベースURI>/chaincode

返ってくる結果は

{"jsonrpc":"2.0","result":{"status":"OK","message":"**************"}

このmessageの値がchaincodeIDになります。
この後のInvoke、QueryではこのchaincodeIDを使ってトランザクションを生成します。

jsonのパラメータの解説

先ほど入力したjsonのパラメータは以下のものでした。
デプロイとこの後のInvoke・QueryではChaincodeIDの中が変わるので注意してください。

jsonrpc JSON-RPCのバージョン
method 実行するメソッド名
params type Chaincodeのタイプ(1はGo言語)
chaincodeID path Chaincodeのパス (デプロイのみ)
name ChaincodeのID(デプロイ以外)
ctorMsg function, args 実行時にChaincodeに渡される引数
secureContext 実行するユーザID
id requestとresponseの組を
識別するためのもの

トランザクションの実行(Invoke)

先ほどデプロイしたChaincodeを実行します。
まずはデータの保存のInvoke関数を呼び出します。

先ほどと同じく

<ベースURI>/chaincode

# 例) https://ab12cde3-45gh-6i78-900-abcf1234567d_vp1-api.blockchain.ibm.com:443/chaincode 

に対し以下のjsonを投げることになります。

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "<Chaincode ID>"
    },
    "ctorMsg": {
      "function": "invoke",
      "args": [
        "A101", "Book"
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}

なのでcurlでやると以下のような感じになります。

curl -H "Content-type: application/json" \
-X POST \
-d '{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "<Chaincode ID>"
    },
    "ctorMsg": {
      "function": "invoke",
      "args": [
        "A101", "Book"
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}' \
<ベースURI>/chaincode

返ってくる結果は

{"jsonrpc":"2.0","result":{"status":"OK","message":"******"},"id":0}

このmessageの値はこのトランザクションのUUIDになりますがこの後特に使用することはありません。

ワールドステート

先ほどのInvokeの実行では"A101"というkeyに"Book"というvalueの
ペアで保存しました。このようにブロックチェーン上で保存されるデータのことをOpen Blockchainではワールドステートと呼びます。

ワールドステートはこのようにkeyとvalueのペアでかつvalueはbyte配列になっている必要があり、このinvoke関数でも一度、文字列のvalueをbyte配列に変換しています。

データの参照(Query)

Invokeで保存した"A101"というkeyからそのvalueを参照します。

先ほどと同じく

<ベースURI>/chaincode

# 例) https://ab12cde3-45gh-6i78-900-abcf1234567d_vp1-api.blockchain.ibm.com:443/chaincode 

に対し以下のjsonを投げることになります。

{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "<Chaincode ID>"
    },
    "ctorMsg": {
      "function": "query",
      "args": [
        "A101"
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}

なのでcurlでやると以下のような感じになります。

curl -H "Content-type: application/json" \
-X POST \
-d '{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "<Chaincode ID>"
    },
    "ctorMsg": {
      "function": "query",
      "args": [
        "A101"
      ]
    },
    "secureContext": "<ユーザID>"
  },
  "id": 0
}' \
<ベースURI>/chaincode

返ってくる結果は

{"jsonrpc":"2.0","result":{"status":"OK","message":"Key:A101 Value:Book"},"id":0}

となり、messageが"Key:A101 Value:Book"隣っているので先ほど実行したInvokeの結果を参照できたことが確認できました。

終わり

以上がOpen Blockchainの基本操作です。
次はよりChaincodeの書き方などについてまとめたいと思います。

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