Hyperledger Fabricのchaincodeで個人情報を検索します
Hyperledger Fabric(以下HF。HLFが正式な略称なのだろうか?)のquery
メソッドで個人情報を問い合わせます。前に投稿しましたが、HFのState DB
に個人情報を持つのはよろしくないので、個人情報はRDB(PostgreSQL)から引き当てることにします。
// 最近はHFでもchaincode
をSmart 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
を追加しています。
実装しましょう
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
メソッドと同じく、GetState
でState 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から情報が取れています。前の投稿では、車がニ・キータさんのところにあってもLocation
はOwner
でした。逆にオーナーがニ・キータさんでも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含め色んな周辺システムと連携が取れそうです。ブロックチェーンをシステム間のハブの位置付けで利用するのも面白いと思いました。
ちなみに、ニ・キータさんは架空の人物です;-)
念の為。