この記事は WESEEK Advent Calendar 2020 3日目の記事です。
はじめに
前回は Hyperledger fabric についての基礎知識を紹介しました。
今回は Hyperledger fabric 公式のチュートリアルを実際に動かしてみることにします。
- 基礎知識の紹介
- サンプルアプリケーションを動かすチュートリアル (この記事)
- 開発環境の整備
- CIの構築
- SDKを使ったアプリケーションの構築
事前準備
チュートリアルを動作させるために以下のツールが必要です。事前にインストールしてください。
- Docker 17.06.2-CE 以上
- Docker Compose 1.14.0 以上
- Node.js 8.9.4 以上、または 10.15.3 以上 (npm は 5.6.0 推奨)
- nvm のような複数バージョンの Node.js をインストールできるツールを利用すると便利です
- (好みで) yarn
- curl (サンプルダウンロード用)
次は、サンプルコードを clone し、fabric 関連ツール及び fabric コンポーネントの Docker image 一式をダウンロードします。
curl -sSL http://bit.ly/2ysbOFE | bash -s -- 1.4.7 1.4.7
公式チュートリアル fabcar アプリケーションを実行する
fabric ネットワークを構築する
公式チュートリアル fabcar アプリケーション に従って、Hyperledger fabric が動作する様子を体験してみましょう。
ダウンロードしたコードの中にはいくつかのサンプルアプリケーションがあります。
ここでは、fabcar
アプリケーションを実行します。
fabcar
は車の販売店が取り扱う車の情報を台帳で管理するアプリケーションの例です。
$ ls
fabric-samples
$ cd fabcar
$ ./startFabric.sh javascript
以下のようなメッセージが表示されれば正常に起動が完了しています。
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
このコマンドにより次のようなネットワークが構築され、chaincode dev-peer0.org1.example.com-fabcar-1.0
, dev-peer0.org2.example.com-fabcar-1.0
がインスタンス化されました。
Docker container は下のようになります。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4a4bd830f0a6 dev-peer0.org2.example.com-fabcar-1.0-264b0a1cb5efbecaac5cf8990339c24474dc8435c6e10f10f2be565d555d0e94 "/bin/sh -c 'cd /usr…" 4 minutes ago Up 4 minutes dev-peer0.org2.example.com-fabcar-1.0
7129758c892c dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba "/bin/sh -c 'cd /usr…" 4 minutes ago Up 4 minutes dev-peer0.org1.example.com-fabcar-1.0
fc5fcb24773b hyperledger/fabric-tools:latest "/bin/bash" 5 minutes ago Up 5 minutes cli
f52409de155a hyperledger/fabric-peer:latest "peer node start" 5 minutes ago Up 5 minutes 0.0.0.0:9051->9051/tcp peer0.org2.example.com
c80dff21f529 hyperledger/fabric-peer:latest "peer node start" 5 minutes ago Up 5 minutes 0.0.0.0:7051->7051/tcp peer0.org1.example.com
c470b0dfd851 hyperledger/fabric-peer:latest "peer node start" 5 minutes ago Up 5 minutes 0.0.0.0:8051->8051/tcp peer1.org1.example.com
83f703282bc2 hyperledger/fabric-peer:latest "peer node start" 5 minutes ago Up 5 minutes 0.0.0.0:10051->10051/tcp peer1.org2.example.com
230cf92ddd76 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" 5 minutes ago Up 5 minutes 0.0.0.0:7054->7054/tcp ca_peerOrg1
c5d3fe6eb558 hyperledger/fabric-couchdb "tini -- /docker-ent…" 5 minutes ago Up 5 minutes 4369/tcp, 9100/tcp, 0.0.0.0:6984->5984/tcp couchdb1
d5d2359b5e18 hyperledger/fabric-orderer:latest "orderer" 5 minutes ago Up 5 minutes 0.0.0.0:7050->7050/tcp orderer.example.com
45c17821a25d hyperledger/fabric-couchdb "tini -- /docker-ent…" 5 minutes ago Up 5 minutes 4369/tcp, 9100/tcp, 0.0.0.0:8984->5984/tcp couchdb3
9f655933a69d hyperledger/fabric-couchdb "tini -- /docker-ent…" 5 minutes ago Up 5 minutes 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb2
69a9ee2d0f1e hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" 5 minutes ago Up 5 minutes 7054/tcp, 0.0.0.0:8054->8054/tcp ca_peerOrg2
6f8e7b766062 hyperledger/fabric-couchdb "tini -- /docker-ent…" 5 minutes ago Up 5 minutes 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0
fabric アプリケーションを実行する
fabric アプリケーションは Node.js で実装されています。(サンプルには Java, TypeScript を使った例もあります)
一般的な Node.js アプリケーションを実行する要領で実行できます。
まずは依存関係を解決します。
$ ls
fabric-samples
$ cd fabcar/javascript
$ yarn # or npm install
fabcar/javascript ディレクトリ内にはいくつかの Node.js アプリケーションがあります。(サンプルのため機能としては薄い)
- enrollAdmin.js
- adminユーザーを登録します
- registerUser.js
- adminユーザーにより、user1を新しく作成&登録します
- invoke.js
- chaincode で定義された
createCar
トランザクションを実行します
- chaincode で定義された
- query.js
- chaincode で定義された
queryAllCars
トランザクションを検証します
- chaincode で定義された
fabric アプリケーションは fabric ネットワークで識別され、実行する権限があるユーザーがトランザクションを実行することができます。
ユーザーを識別するためには証明書が必要なので、user1 ユーザーがアプリケーションを実行するためには次の手続きが必要です。
- org1.example.com の管理者ユーザー
admin
を作成する (fabric ネットワーク作成時に既に作成済) -
admin
を登録する - トランザクション実行用の org1.example.com のメンバーユーザー
user1
を作成&登録する -
user1
の秘密鍵・証明書を使ってトランザクションを実行する
org1.example.com の管理者ユーザー admin
を登録する
まずは管理者ユーザーを登録します。
この操作により、まずは実行したローカルファイルシステム上に秘密鍵と公開鍵が作成されます。
次に、作成された公開鍵が CA へ送信され、CA により証明書が発行されます。
Hyperledger はユーザー証明書を含むユーザー情報をウォレットというデータ形式で保持します。(複数ユーザーの情報がウォレット領域にユーザー毎分類されて保存される)
$ ls wallet
# wallet配下は空
# adminを登録する
$ node enrollAdmin.js
Wallet path: /home/vagrant/work/fabric-samples.1.4.7/fabcar/javascript/wallet
Successfully enrolled admin user "admin" and imported it into the wallet
# adminの公開鍵・秘密鍵が作成され、ウォレットに登録されたことを確認する
$ ls wallet/
admin
$ ls -l wallet/admin/
total 12
-rw-rw-r-- 1 vagrant vagrant 246 Nov 30 19:57 7cafba753580ab2d4d306af5bed61ce5e3aeefd4d54083d2d4f0b37d276670e3-priv # 秘密鍵
-rw-rw-r-- 1 vagrant vagrant 182 Nov 30 19:57 7cafba753580ab2d4d306af5bed61ce5e3aeefd4d54083d2d4f0b37d276670e3-pub # 公開鍵
-rw-rw-r-- 1 vagrant vagrant 986 Nov 30 19:57 admin # ウォレット
$ cat wallet/admin/admin | jq
{
"name": "admin",
"mspid": "Org1MSP",
"roles": null,
"affiliation": "",
"enrollmentSecret": "",
"enrollment": {
"signingIdentity": "7cafba753580ab2d4d306af5bed61ce5e3aeefd4d54083d2d4f0b37d276670e3",
"identity": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIICATCCAaigAwIBAgIURWhPNsHqBR0BJXYTEIkKGE/K2M8wCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAxMTMwMTk1MjAwWhcNMjExMTMwMTk1\nNzAwWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAEMsPEEj8hMBrNC4D3gjCA7PgGHYumGQPf3Lj3uikv\n392ps1BjPzgzxB+7y1tQAOlzsSia9taJ3Um0ubYfRw7C9qNsMGowDgYDVR0PAQH/\nBAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFK/z0HzATs86aQB73aSJUIj3\nDHGKMCsGA1UdIwQkMCKAIKeFc5ZLUOE0kdaM/m4ukEGlzayUGz5AecXS8Rz2ZKJy\nMAoGCCqGSM49BAMCA0cAMEQCIFbQVPlRHfFt0FsrAYJVAvGLBBJxNFDdEdWeC6gA\nCnRsAiAychuZ/+CfG4A0TsydtvEi0K0tDPprdFUK0G1u985feg==\n-----END CERTIFICATE-----\n"
}
}
}
admin ユーザーの証明書を見てみると次のようになっています。
$ cat wallet/admin/admin | jq .enrollment.identity.certificate | tr -d '"' | sed -r -e 's/\\n/\n/g' | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
45:68:4f:36:c1:ea:05:1d:01:25:76:13:10:89:0a:18:4f:ca:d8:cf
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = US, ST = California, L = San Francisco, O = org1.example.com, CN = ca.org1.example.com
Validity
Not Before: Nov 30 19:52:00 2020 GMT
Not After : Nov 30 19:57:00 2021 GMT
Subject: OU = client, CN = admin
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:32:c3:c4:12:3f:21:30:1a:cd:0b:80:f7:82:30:
80:ec:f8:06:1d:8b:a6:19:03:df:dc:b8:f7:ba:29:
2f:df:dd:a9:b3:50:63:3f:38:33:c4:1f:bb:cb:5b:
50:00:e9:73:b1:28:9a:f6:d6:89:dd:49:b4:b9:b6:
1f:47:0e:c2:f6
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
AF:F3:D0:7C:C0:4E:CF:3A:69:00:7B:DD:A4:89:50:88:F7:0C:71:8A
X509v3 Authority Key Identifier:
keyid:A7:85:73:96:4B:50:E1:34:91:D6:8C:FE:6E:2E:90:41:A5:CD:AC:94:1B:3E:40:79:C5:D2:F1:1C:F6:64:A2:72
Signature Algorithm: ecdsa-with-SHA256
30:44:02:20:56:d0:54:f9:51:1d:f1:6d:d0:5b:2b:01:82:55:
02:f1:8b:04:12:71:34:50:dd:11:d5:9e:0b:a8:00:0a:74:6c:
02:20:32:72:1b:99:ff:e0:9f:1b:80:34:4e:cc:9d:b6:f1:22:
d0:ad:2d:0c:fa:6b:74:55:0a:d0:6d:6e:f7:ce:5f:7a
ここで証明書から次のことが読み取れます。
-
Issuer: ~, CN = ca.org1.example.com
から、認証局がca.org1.example.com
であることが読み取れます -
Subject: OU = client, CN = admin
から、ユーザーID がadmin
であり、fabric クライアント (client
) であることが読み取れます- OU はデフォルトで他に
orderer
,peer
がある - NodeOUs を有効にすることで定義をカスタムできるようです
- OU はデフォルトで他に
トランザクション実行用のユーザーを作成&登録する
管理ユーザーを登録することができました。
このユーザーを使って、他のユーザの作成や登録を行うことができます。
そこで次に admin
ユーザの identity を使ってユーザーuser1
を作成&登録します。
$ ls wallet/
admin
# user1 を作成&登録する
$ node registerUser.js
Wallet path: /home/vagrant/work/fabric-samples.1.4.7/fabcar/javascript/wallet
Successfully registered and enrolled admin user "user1" and imported it into the wallet
$ ls wallet/
admin user1
$ ls -l wallet/user1/
total 12
-rw-rw-r-- 1 vagrant vagrant 246 Nov 30 20:19 edf5c114bbb2c02c2c0c124a9dfa0f32a1769f568ef2ef2952fb0a46c933ac5e-priv
-rw-rw-r-- 1 vagrant vagrant 182 Nov 30 20:19 edf5c114bbb2c02c2c0c124a9dfa0f32a1769f568ef2ef2952fb0a46c933ac5e-pub
-rw-rw-r-- 1 vagrant vagrant 1180 Nov 30 20:19 user1
$ cat wallet/user1/user1 | jq
{
"name": "user1",
"mspid": "Org1MSP",
"roles": null,
"affiliation": "",
"enrollmentSecret": "",
"enrollment": {
"signingIdentity": "edf5c114bbb2c02c2c0c124a9dfa0f32a1769f568ef2ef2952fb0a46c933ac5e",
"identity": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIICjjCCAjWgAwIBAgIUfKQtONFnMS5U6wzquuxFdZy7iEAwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAxMTMwMjAxNTAwWhcNMjExMTMwMjAy\nMDAwWjBCMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVw\nYXJ0bWVudDExDjAMBgNVBAMTBXVzZXIxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\nQgAEw3zuvqLwxoInC4EkDoLAU3siTgRXTzlLrWJ9dcQXVSGDv+Hc9dg3ymCmniPg\nDoY95bhZuecjgFIlYZZMkBufaKOB1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0T\nAQH/BAIwADAdBgNVHQ4EFgQUhcfQZ1KzaKj43ppigFqTBVyGP90wKwYDVR0jBCQw\nIoAgp4VzlktQ4TSR1oz+bi6QQaXNrJQbPkB5xdLxHPZkonIwaAYIKgMEBQYHCAEE\nXHsiYXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiJvcmcxLmRlcGFydG1lbnQxIiwi\naGYuRW5yb2xsbWVudElEIjoidXNlcjEiLCJoZi5UeXBlIjoiY2xpZW50In19MAoG\nCCqGSM49BAMCA0cAMEQCIH87DJXFL3WM2uCRYHrpp7RGE3QhNant7yVcu0xASv3E\nAiBuIucVQKQefs8yWND74QSyguWl99o6D1n3qP7EkzpMEw==\n-----END CERTIFICATE-----\n"
}
}
}
今度は user1 の証明書を見てみましょう。
$ cat wallet/user1/user1 | jq .enrollment.identity.certificate | tr -d '"' | sed -r -e 's/\\n/\n/g' | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
7c:a4:2d:38:d1:67:31:2e:54:eb:0c:ea:ba:ec:45:75:9c:bb:88:40
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = US, ST = California, L = San Francisco, O = org1.example.com, CN = ca.org1.example.com
Validity
Not Before: Nov 30 20:15:00 2020 GMT
Not After : Nov 30 20:20:00 2021 GMT
Subject: OU = client + OU = org1 + OU = department1, CN = user1
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:c3:7c:ee:be:a2:f0:c6:82:27:0b:81:24:0e:82:
c0:53:7b:22:4e:04:57:4f:39:4b:ad:62:7d:75:c4:
17:55:21:83:bf:e1:dc:f5:d8:37:ca:60:a6:9e:23:
e0:0e:86:3d:e5:b8:59:b9:e7:23:80:52:25:61:96:
4c:90:1b:9f:68
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
85:C7:D0:67:52:B3:68:A8:F8:DE:9A:62:80:5A:93:05:5C:86:3F:DD
X509v3 Authority Key Identifier:
keyid:A7:85:73:96:4B:50:E1:34:91:D6:8C:FE:6E:2E:90:41:A5:CD:AC:94:1B:3E:40:79:C5:D2:F1:1C:F6:64:A2:72
1.2.3.4.5.6.7.8.1:
{"attrs":{"hf.Affiliation":"org1.department1","hf.EnrollmentID":"user1","hf.Type":"client"}}
Signature Algorithm: ecdsa-with-SHA256
30:44:02:20:7f:3b:0c:95:c5:2f:75:8c:da:e0:91:60:7a:e9:
a7:b4:46:13:74:21:35:a9:ed:ef:25:5c:bb:4c:40:4a:fd:c4:
02:20:6e:22:e7:15:40:a4:1e:7e:cf:32:58:d0:fb:e1:04:b2:
82:e5:a5:f7:da:3a:0f:59:f7:a8:fe:c4:93:3a:4c:13
今度は証明書から次のことが読み取れます。
-
Subject: OU = client + OU = org1 + OU = department1, CN = user1
からユーザーID がuser1
である - Hyperledger fabric 上の権限が
1.2.3.4.5.6.7.8.1
に保存されている- 詳細はAttribute-Based Access Control に書かれています
トランザクション実行用のユーザーの秘密鍵・証明書を使ってトランザクションを実行する
トランザクションを実行するユーザが準備できたので、いよいよトランザクションを実行します。
query.js
には chaincode で定義された queryAllCars
を検証するコードが記述されています。
queryAllCars
は台帳に記述された全ての車のデータを返します。
fabric ネットワークを構築した際、initLedger が実行されており、これにより 10 台の車のデータが登録されていました。
そのため、結果は 10 台の車のデータが返ってきます。
$ node query.js
Wallet path: /home/vagrant/work/fabric-samples.1.4.7/fabcar/javascript/wallet
Transaction has been evaluated, result is: [
{"Key":"CAR0","Record":{"color":"blue","docType":"car","make":"Toyota","model":"Prius","owner":"Tomoko"}},
{"Key":"CAR1","Record":{"color":"red","docType":"car","make":"Ford","model":"Mustang","owner":"Brad"}},
{"Key":"CAR2","Record":{"color":"green","docType":"car","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},
{"Key":"CAR3","Record":{"color":"yellow","docType":"car","make":"Volkswagen","model":"Passat","owner":"Max"}},
{"Key":"CAR4","Record":{"color":"black","docType":"car","make":"Tesla","model":"S","owner":"Adriana"}},
{"Key":"CAR5","Record":{"color":"purple","docType":"car","make":"Peugeot","model":"205","owner":"Michel"}},
{"Key":"CAR6","Record":{"color":"white","docType":"car","make":"Chery","model":"S22L","owner":"Aarav"}},
{"Key":"CAR7","Record":{"color":"violet","docType":"car","make":"Fiat","model":"Punto","owner":"Pari"}},
{"Key":"CAR8","Record":{"color":"indigo","docType":"car","make":"Tata","model":"Nano","owner":"Valeria"}},
{"Key":"CAR9","Record":{"color":"brown","docType":"car","make":"Holden","model":"Barina","owner":"Shotaro"}}]
コマンドだけ見ると実感は少ないと思いますが、これはブロックチェーンの台帳を読み取った結果です。
次に、台帳へ書き込みを行ってみます。
invoke.js
には chaincode で定義された createCar
を実行するコードが記述されています。
実行した後、再度 query.js
を実行すると CAR12
が追加されていることが分かります。
$ node invoke.js
Wallet path: /home/vagrant/work/fabric-samples.1.4.7/fabcar/javascript/wallet
Transaction has been submitted
# $ node query.js
Wallet path: /home/vagrant/work/fabric-samples.1.4.7/fabcar/javascript/wallet
Transaction has been evaluated, result is: [
{"Key":"CAR0","Record":{"color":"blue","docType":"car","make":"Toyota","model":"Prius","owner":"Tomoko"}},
{"Key":"CAR1","Record":{"color":"red","docType":"car","make":"Ford","model":"Mustang","owner":"Brad"}},
{"Key":"CAR12","Record":{"color":"Black","docType":"car","make":"Honda","model":"Accord","owner":"Tom"}},
{"Key":"CAR2","Record":{"color":"green","docType":"car","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},
{"Key":"CAR3","Record":{"color":"yellow","docType":"car","make":"Volkswagen","model":"Passat","owner":"Max"}},
{"Key":"CAR4","Record":{"color":"black","docType":"car","make":"Tesla","model":"S","owner":"Adriana"}},
{"Key":"CAR5","Record":{"color":"purple","docType":"car","make":"Peugeot","model":"205","owner":"Michel"}},
{"Key":"CAR6","Record":{"color":"white","docType":"car","make":"Chery","model":"S22L","owner":"Aarav"}},
{"Key":"CAR7","Record":{"color":"violet","docType":"car","make":"Fiat","model":"Punto","owner":"Pari"}},
{"Key":"CAR8","Record":{"color":"indigo","docType":"car","make":"Tata","model":"Nano","owner":"Valeria"}},
{"Key":"CAR9","Record":{"color":"brown","docType":"car","make":"Holden","model":"Barina","owner":"Shotaro"}}]
invoke.js
にはトランザクションを実行することだけが記述されていますが、内部では Hyperledger fabric におけるトランザクションの検証やコミットやブロックのブロードキャストなどの処理が行われ、その結果台帳が更新されたため query.js
が更新されています。
まとめ
Hyperledger fabric 公式のチュートリアルを実際に動かした結果を紹介しました。
Hyperledger fabric におけるユーザーを作成し、作成したユーザーの identity を使ってトランザクションを実行し、台帳を読み書きすることでシステム動作を体験しました。
次は、chaincode を実装する開発環境を構築する方法について紹介したいと思います。
※この記事は WESEEK Tips wiki に 2020/12/02 に投稿された記事の転載です。
Tips wiki では、IT企業の技術的な情報やプロジェクトの情報を公開可能な範囲で公開してます。