1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Hyperledger Fabricで個人情報をクエリする(RDB連携)

Last updated at Posted at 2020-06-22

Hyperledger Fabricのchaincodeで個人情報を検索します

Hyperledger Fabric(以下HF。HLFが正式な略称なのだろうか?)のqueryメソッドで個人情報を問い合わせます。前に投稿しましたが、HFのState DBに個人情報を持つのはよろしくないので、個人情報はRDB(PostgreSQL)から引き当てることにします。
// 最近はHFでもchaincodeSmart contractと呼ぶようになっている気がします。

環境について

動作環境については次の通りです。前回の投稿と(ry

Ubuntu 18.04.4 LTS
docker-compose 1.26.0
docker 19.03.11
HF 2.1.1
go 1.14.4
PostgreSQL(Dockerイメージ) 12.3(latest)

下準備

下準備をします。

RDBのテーブル定義

新しく個人情報用のテーブルを定義しました。DBasset内にownerテーブルを定義しました。

asset=# \d owner
                     Table "public.owner"
 Column  |       Type        | Collation | Nullable | Default 
---------+-------------------+-----------+----------+---------
 id      | character(17)     |           | not null | 
 name    | character varying |           | not null | 
 country | character varying |           | not null | 
 city    | character varying |           | not null | 
 addr    | character varying |           | not null | 
Indexes:
    "owner_pkey" PRIMARY KEY, btree (id)

asset=#

名前と住所が入っているので危ないですね。idは車体番号(VIN)を利用して、同じくVINをKeyにしているState DBと紐付けることにします。

何はなくともダミーデータ

とりあえず1件だけ、マイカー「Mira Qiita」のオーナー情報を登録しました。

asset=# SELECT * FROM owner WHERE id = 'JMYMIRAGINO200302';
        id         |      name       | country |   city    |   addr    
-------------------+-----------------+---------+-----------+-----------
 JMYMIRAGINO200302 | ニ・キータ | 日本  | 東京都 | 足立区
(1 row)

asset=#

「ニ・キータ」さんの個人情報が入っています;-)
ニ・キータさんは足立区に住んでいるんですね。足立区は「修羅の国」と揶揄されることがあるのですが、同じ足立区民として心が痛いです…

chaincodeを書く

さっそくコーディングしましょう。

データ構造の定義

新しいデータを扱うので、新しいデータ構造を定義しました。

// データ構造の定義
type Asset struct {
        Year     string `json:"year"`     // 初度登録年
        Month    string `json:"month"`    // 初度登録月
        Mileage  int    `json:"mileage"`  // 走行距離(km)
        Battery  int    `json:"battery"`  // バッテリーライフ(%)
        Location string `jasn:"location"` // 位置
}
type AssetWithOwner struct {
        Name    string  // 名前
        Country string  // 国
        City    string  // 都道府県
        Addr    string  // 市区町村
        Record  *Asset
}

構造体AssetWithOwnerを追加しています。

実装しましょう

asset.goから抜粋
func (s *SmartContract) QueryAssetWithOwner(ctx contractapi.TransactionContextInterface, key string) (*AssetWithOwner, error) {
        fmt.Println("QueryAssetWithOwner")

        assetAsBytes, err := ctx.GetStub().GetState(key)

        if err != nil {
                return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
        }

        if assetAsBytes == nil {
                return nil, fmt.Errorf("%s does not exist", key)
        }

        asset := new(Asset)
        _ = json.Unmarshal(assetAsBytes, asset)

        db, err := sql.Open("postgres", "host=pgsql port=5432 user=postgres password=secret dbname=asset sslmode=disable")
        defer db.Close()
        if err != nil {
                return nil, fmt.Errorf("sql.Open: %s", err.Error())
        }

        sql := "SELECT * FROM owner WHERE id = '" + key + "';"
        rows, err := db.Query(sql)
        if err != nil {
                return nil, fmt.Errorf("db.Query: %s", err.Error())
        }

        var id string
        awo := new(AssetWithOwner)
        for rows.Next() {
                rows.Scan(&id, &awo.Name, &awo.Country, &awo.City, &awo.Addr)
                awo.Record = asset
        }

        return awo, nil
}

新規メソッドQueryAssetWithOwnerを実装しました。通常のqueryメソッドと同じく、GetStateState DBから情報をGETした後、RDBから個人情報を検索してAssetWithOwner構造体へ両方を合体セットしています。
SQL文は文字列を整形して作っています。VINはユニークなidなので、1件しか検索できない前提で書いてあります。2件以上見つかったら後勝ちになるでしょう:-(
当初、何も考えず文字列変数Keyを使っていたのですが上手くいかず。PostgresSQLのコンテナに入って手打ちでSQL文を叩いても上手くいかず…なぜか問い合わせたKey文字列が小文字になってしまうんです:-(

asset=# SELECT * FROM owner WHERE id = JMYMIRAGINO200302;
ERROR:  column "jmymiragino200302" does not exist
LINE 1: SELECT * FROM owner WHERE id = JMYMIRAGINO200302;
                                       ^
asset=#

数時間ハマった挙げ句、シングルクォーテーションで挟めば良いことが分かりました。RDBなんて普段使わないから、そんなローカルルールは知らないよ!
「なぜ小文字になる!!」「なぜ小文字になる!」「なぜ小文字になるのよ(涙)」「ワケワカメ」(数時間経過)
論理的な仕様ではないと思うのですが。大昔のDOSも大文字と小文字を区別しなかったけど、レガシーなソリューションにはそういう名残があるのかしら:-|

動作確認

実際にQueryしてみましょう!

# ./QueryAssetWithOwner.sh | jq
{
  "Name": "ニ・キータ",
  "Country": "日本",
  "City": "東京都",
  "Addr": "足立区",
  "Record": {
    "year": "2003",
    "month": "02",
    "mileage": 43871,
    "battery": 100,
    "Location": "QIITA東京販売"
  }
}
#

ちゃんとRDBから情報が取れています。前の投稿では、車がニ・キータさんのところにあってもLocationOwnerでした。逆にオーナーがニ・キータさんでもLocationが別の場所だと誰が真のオーナーかは分からなかったのです。
個人情報を加えることで、
「オーナーがニ・キータさんの車がQIITA東京販売に存在する」ということが分かるようになります。
履歴情報も見てみましょう。

# ./GetHistoryOfAsset.sh | jq
[
  {
    "TxId": "9b99263e5b75378af40e8466d28dd85654e3b8e427572a6ae038501a8dfebe97",
    "Timestamp": "2020-06-22 21:52:52 +0000 UTC",
    "IsDelete": false,
    "Record": {
      "year": "2003",
      "month": "02",
      "mileage": 43871,
      "battery": 100,
      "Location": "QIITA東京販売"
    }
  }
]
#

履歴情報には個人情報が残っていないですね。個人情報保護法対策もバッチリ(?)です。

最後に

ブロックチェーンの主キーをマスターにして、レガシーRDB含め色んな周辺システムと連携が取れそうです。ブロックチェーンをシステム間のハブの位置付けで利用するのも面白いと思いました。

ちなみに、ニ・キータさんは架空の人物です;-)
念の為。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?