shimada-kの日記

ソフトウェア・エンジニアのブログです

IBM Blockchainでソリッドステートを作る

この記事は「ネクスト(Lifull) Advent Calendar 2016」21日目の記事として書かれました。

qiita.com

前回の投稿からかなり時間が空いてしまいました。今年も年の瀬ですね。

なぜ年の「瀬」というかというと、「瀬」には「流れの速い」という意味があるそうです。またツケ払いが多かった江戸時代には年末にツケの清算がなされたことから、めまぐるしい時期ということで年末のことを「年の瀬」ということになったらしいです。

はじめに

私はFinTech系の事業に携わっておりますので、ぜひブロックチェーンについて議論したいと思いました。

昨年にはマウントゴックスの事件などありキナ臭い印象が広がっているかもしれません。しかしマウントゴックスの破綻とブロックチェーンの技術自体には何の因果関係もありません。

2016年には三菱UFJが仮想通貨に参入したり、2017年度の税制改正ではビットコインの購入に際しては消費税を課税しないなど、ブロックチェーンを使用した仮想通貨は徐々に社会的な認知度をあげていると言えます。

闇雲にブロックチェーンについてレポートを書いてみるものいまいちモチベーションが上がりませんので、今回は「攻殻機動隊 S.A.C. SSS」のソリッドステートを取り上げてみることにしてみました。

フライト記録は改竄しておけよ

最低限の説明は必要でしょう。「攻殻機動隊 S.A.C. SSS」は2011年に公開された劇場版・攻殻機動隊です。「攻殻機動隊 S.A.C. 2nd GIG」で草薙素子が9課を去ってから2年後が舞台となっており、少子高齢化社会を背景にして新たな組織となった9課の苦悩と、超ウィザード級ハッカー傀儡廻(くぐつまわし)」との電子戦が描かれています。

sss.ph9.jp

ソリッドステートとは全自動老人介護システム内の誘拐インフラのことです。虐待を受けている子供を身寄りのない老人の子供としてデータを書き換えるシステムを指しています。

f:id:shimada-k:20161220232356p:plain

少子高齢化時代の対策として、厚生労働省の職員が開発したシステムとされています。

少子化が叫ばれるなか、年間5万人もの6歳未満の子供が無意味に命を落としていることを。

児童相談所や警察など関係機関が事態を把握していたにもかかわらず防ぐことができなかったものだ。

どこかで聞いたような話です。2011年の作品ながら、現在を言い当てているようです。

ソリッドステートの本質は記憶を改竄することだと思います。なにせ子供の親を入れ替えないといけないのですから。親と子供の記憶は最低限書き換えが必要ですし、親類やその他周辺関係者の記憶も書き換える必要があるでしょう。

警告を無視したな

さて、本題に入りましょう。ブロックチェーンを使った仕組みを作るということは、チェーンコードを書くということです。今回はIBM Blockchainを使います。

IBM BlockchainとはIBM Bluemix上で動かせるアプリケーションフレームワークです。GUIで操作できAPIを叩いてデプロイできます。IBM BluemixとはIBMが提供するPaaSです。30日間の無料トライアル期間があります。

IBM Bluemix http://www.ibm.com/developerworks/jp/bluemix/

IBM Blockchainのサービスでは4つのピアを動かすことができます。

f:id:shimada-k:20161220234608p:plain

IBM Blockchainで自作のチェーンコードを動かす場合、APIメニューを使用することになります。

f:id:shimada-k:20161220234618p:plain

APIメニューではリクエストを送信して検証するためのUIを提供しています。curlを使って自前でリクエストすることもできますが、開発時はこちらを使ったほうが格段にはかどります。

委ねてみるわ ゴーストの囁きに

チェーンコード

IBM Blockchainでは Hyperledger Fabricというブロクチェーンを基盤に採用しています。本家のHyperledgerプロジェクトから派生したインキュベーションプロジェクト、という位置づけです。オープンソースで公開されています。

Hyperledger Project https://www.hyperledger.org/

HyperledgerではDeploy,Invoke,Queryの3種類のメソッドを使います。Deployはデプロイ時に使用するもの、Invokeはデータの新規追加、更新、削除。Queryは参照です。

今回はInvokeでデータを書き換え、他のピアでもデータが書き換わっていることをQueryで確認します。

IBM Blockchain上で動いている4つのピアは個々人の記憶の塊だと見立てます。

記憶のデータは以下のような構造にしました。戸籍データのようなものです。

type Family struct{
    Sex int `json:"sex"`
    Birthday string `json:"birthday"`
    SpouseId string `json:"spouse_id"`
    FatherId string `json:"father_id"`
    MotherId string `json:"mother_id"`
    ChildId string `json:"child_id"`
}

データの改竄フローは以下のように実装しました。

  1. 父の持つ子供IDを消す(hospital)
  2. 母の持つ子供IDを消す(hospital)
  3. 子供の両親IDを消す(plugged)
  4. 子供の父親IDを老人IDに変更する(adopted)

ちなみに「攻殻機動隊 S.A.C. SSS」では老人は理解した上でソリッドステートに加担していたので、作品中では明確にされていませんが老人は自分の子だとは認識していなかったと思われます。そのため老人のデータ(記憶)は変更しないことにします。

実装したチェーンコードはgistにあげておきました。

動かしてみる

下記のリスクエストでデプロイします。IBM BlockchainのAPIメニューから行います。ピアは0を指定しています。ユーザはuser_type1_0でログインしています。

 {
     "jsonrpc": "2.0",
     "method": "deploy",
     "params": {
         "type": 1,
         "chaincodeID": {
             "path": "https://github.com/shimada-k/learn-chaincode/finished"
         },
         "ctorMsg": {
             "function": "init",
             "args": [
                 "hello"
             ]
         },
         "secureContext": "user_type1_0"
     },
     "id": 0
 }

データを準備する

Invoke:addを使用してデータを追加します。あらかじめ老人、子供、子供の父母のデータを作成しておきました。

老人

老人は80歳という設定です。身寄りのない老人ということで配偶者と子供はありません。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\": 1,\"birthday\": \"1936-12-21\",\"spouse_id\": \"\",\"father_id\": \"8b77fb747eda782e202f85f3c7e5df850200977a053527fccbc3914d50ee98b5\",\"mother_id\": \"194f138b39f10252c32bd1cc95b9144da7688954c56eb014c3b7c4759ce33735\",\"child_id\": \"\"}"
  },
  "id": 0
}
子供の父

父親は38歳(1978年生まれ)です。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\": 1,\"birthday\": \"1978-02-20\",\"spouse_id\": \"57001488396447b13c743ec4b3e6f7c6f01a53022c7141a8188d6677bf599fa4\",\"father_id\": \"786580bfbb1477f9f00c2bb3566ad52f204067d52d2756a9b4ea408ffbe74152\",\"mother_id\": \"e81727115da92778c19055bd2839bf6c3105224062958e28d7d2317de8a7cdd6\",\"child_id\": \"65152f7fb723e1f385bab62bdc18673209e2324f356f895bf516365cc62834e2\"}"
  },
  "id": 0
}
子供の母

母親は36歳です。sex:1は男性、sex:2は女性としています。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\": 2,\"birthday\": \"1980-08-14\",\"spouse_id\": \"7b451b73ce0614147b01edb102f318a7496ebb533dde28e1fd80c370770f6279\",\"father_id\": \"ff5b8a198f9f96f89ca2aa483c927d58ab7f42563df7c24b47992fdf3cddccea\",\"mother_id\": \"c2dff7c37bbc245dc93ce572476254bd287860e1cebd2b5f36181748fd1f5a54\",\"child_id\": \"65152f7fb723e1f385bab62bdc18673209e2324f356f895bf516365cc62834e2\"}"
  },
  "id": 0
}
子供

子供は6歳です。当然ながら配偶者と子供はいません。father_idとmother_idはすでに追加したIDを登録しています。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\": 1,\"birthday\": \"2010-11-03\",\"spouse_id\": \"\",\"father_id\": \"7b451b73ce0614147b01edb102f318a7496ebb533dde28e1fd80c370770f6279\",\"mother_id\": \"57001488396447b13c743ec4b3e6f7c6f01a53022c7141a8188d6677bf599fa4\",\"child_id\": \"\"}"
  },
  "id": 0
}

データが揃ったのでいよいよ理不尽に損なわれてしまうゴーストの再利用を一部始終、追体験してみましょう。 Invokeでデータを書き換え、Queryで書き換わったことを確認します。

まずはデータの書き換えからです。リクエストするJSONを示します。

父の持つ子供IDを消す(hospital)

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "hospital",
      "args": [
        "7b451b73ce0614147b01edb102f318a7496ebb533dde28e1fd80c370770f6279"
      ]
    },
    "secureContext": "user_type1_0"
  },
  "id": 0
}

母の持つ子供IDを消す(hospital)

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "hospital",
      "args": [
        "57001488396447b13c743ec4b3e6f7c6f01a53022c7141a8188d6677bf599fa4"
      ]
    },
    "secureContext": "user_type1_0"
  },
  "id": 0
}

子供の両親IDを消す(plugged)

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "plugged",
      "args": [
        "65152f7fb723e1f385bab62bdc18673209e2324f356f895bf516365cc62834e2"
      ]
    },
    "secureContext": "user_type1_0"
  },
  "id": 0
}

子供の父親IDを老人IDに変更する(adopted)

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "adopted",
      "args": [
        "65152f7fb723e1f385bab62bdc18673209e2324f356f895bf516365cc62834e2",
        "2d9dc1dcf4330422f5594f0325b01b9326df7554c58f34a29e51a43970d5bbbd"
      ]
    },
    "secureContext": "user_type1_0"
  },
  "id": 0
}

次にデータが書き換わったことをQueryで確認しましょう。

両親のデータを確認する

父親
{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\":1,\"birthday\":\"1978-02-20\",\"spouse_id\":\"57001488396447b13c743ec4b3e6f7c6f01a53022c7141a8188d6677bf599fa4\",\"father_id\":\"786580bfbb1477f9f00c2bb3566ad52f204067d52d2756a9b4ea408ffbe74152\",\"mother_id\":\"e81727115da92778c19055bd2839bf6c3105224062958e28d7d2317de8a7cdd6\",\"child_id\":\"\"}"
  },
  "id": 0
}

子供IDが消えていますね。

母親のデータ
{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\":2,\"birthday\":\"1980-08-14\",\"spouse_id\":\"7b451b73ce0614147b01edb102f318a7496ebb533dde28e1fd80c370770f6279\",\"father_id\":\"ff5b8a198f9f96f89ca2aa483c927d58ab7f42563df7c24b47992fdf3cddccea\",\"mother_id\":\"c2dff7c37bbc245dc93ce572476254bd287860e1cebd2b5f36181748fd1f5a54\",\"child_id\":\"\"}"
  },
  "id": 0
}

こちらも子供IDが無くなっています。

子供のデータを確認する

子供のデータを確認してみましょう。父親が老人のIDに書き換わっているはずです。

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\":1,\"birthday\":\"2010-11-03\",\"spouse_id\":\"\",\"father_id\":\"2d9dc1dcf4330422f5594f0325b01b9326df7554c58f34a29e51a43970d5bbbd\",\"mother_id\":\"\",\"child_id\":\"\"}"
  },
  "id": 0
}

いいですね。父親IDが老人のIDに書き換わり、母親IDは空です。

別のピアで確認してみる

ブロックチェーンですから、他のピア上でも同一のデータ処理が行われているはずです。

上述の処理はピア0で行っているのでピア1でも確認してみます。APIメニューの上部でピアを切り替え、registerでuser_type2_0でログインしてQueryしてみましょう。

父親のデータ

request

{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "read",
      "args": [
        "7b451b73ce0614147b01edb102f318a7496ebb533dde28e1fd80c370770f6279"
      ]
    },
    "secureContext": "user_type2_0"
  },
  "id": 0
}

response

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\":1,\"birthday\":\"1978-02-20\",\"spouse_id\":\"57001488396447b13c743ec4b3e6f7c6f01a53022c7141a8188d6677bf599fa4\",\"father_id\":\"786580bfbb1477f9f00c2bb3566ad52f204067d52d2756a9b4ea408ffbe74152\",\"mother_id\":\"e81727115da92778c19055bd2839bf6c3105224062958e28d7d2317de8a7cdd6\",\"child_id\":\"\"}"
  },
  "id": 0
}

・子供のデータ

request

{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "a027a646d118ca8513ae6854ca455ab6d3c1bf0c6ce331dfc384a7a406605114e2be6c7c46abbb3aaec8986a93327b8dbb5b2c399b3a7ff02eea48dac7184e74"
    },
    "ctorMsg": {
      "function": "read",
      "args": [
        "65152f7fb723e1f385bab62bdc18673209e2324f356f895bf516365cc62834e2"
      ]
    },
    "secureContext": "user_type2_0"
  },
  "id": 0
}

response

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "{\"sex\":1,\"birthday\":\"2010-11-03\",\"spouse_id\":\"\",\"father_id\":\"2d9dc1dcf4330422f5594f0325b01b9326df7554c58f34a29e51a43970d5bbbd\",\"mother_id\":\"\",\"child_id\":\"\"}"
  },
  "id": 0
}

ピア1でも同一のデータが得られました。これで他のピアでも同期が取れていることが分かりました。これで記憶の改竄がおこなれ、無事に誘拐が完了されました。

攻殻機動隊 S.A.C. SSS」においても、カ・ルマのアジトにいた子供達を見て、ボーマが「記憶の一部が消されていて、IDが別の物に書き換えられているらしい事も分かった。」と言っています。

おわりに

今回はIBM Blockchainを使用してブロックチェーンを利用した仕組みを実装してみました。ハマったところをいくつか書いておきます。

開発はOSX環境で行いましたが、home brewでインストールしたGoのバージョンが古くてビルドできなくて悩みました。IBMのサンプルプロジェクトではGo 1.6推奨と書かれていますがOSX Sierraでは1.6でもコンパイルできませんでした。最新版を入れた方が手戻りが少ないかもしれません。

IBMのサンプルプロジェクトではビルドの環境も作っていますが、チェーンコードをデプロイするだけであれば不要です。ただデプロイして動かなかった場合に切り分けするために、ビルド環境を作りデプロイ前にビルドすることを強くお勧めします。

またデプロイ時のレスポンスでchaincodeIDが帰ってくるのですが、これが毎回同じだとデプロイでチェーンコードが変化していないことになります。

原因は/finishedの中身を更新していなかったことです。/startの中にスケルトンコードが入っているのでその中をひたすらcommit & pushしていたのですが、それでは当然ながら/finishedの中が変化していません。英語のチュートリアルを流し読みしていると気づきませんでした。

IBM Bluemixが本来有料のサービスということもありますが、今後はもっとローカライズされた情報が充実していき、より多くの人にとって敷居の低いものになっていくといいですね。

冒頭でも書きましたが、「攻殻機動隊 S.A.C. SSS」は社会問題を先取りして捉えています。2016年には「保育園落ちた日本死ね!!!*1」というブログ記事が公開され国会で話題になりました。待機児童の問題は主に都市部が深刻ですが、負担にあえぐ現役世代の声が顕在化した事象といえます。

一方高齢化問題としては、2025年問題を控えて社会保障制度の見直しが喫緊の課題です。2017年度から医療保険介護保険の見直しが入ります。年金カット法案と称されつつも国民年金法改正案*2が採決されました。

2017年はどのような年になるでしょうか。とりあえず都内に保育園が増えてくれるとありがたいですね。少子化問題社会保障制度の見直しを含めた高齢化問題は引き続き最優先事項です。

それにしても、ネットは広大だわ。もう既に、私達の知らない次の社会が生まれ始めている・・・


本記事は犯罪としての誘拐を肯定又は助長するものではありません