Hyperledger Fabric と戯れる part.3
Writing Your First Application
予告通り、Writing Your First Application チュートリアルに進む。
hyperledger-fabric.readthedocs.io
startFabric.sh xxx
各ノードを構築して chaincode のインストール・インスタンス化まで実施。
xxx に javascript|typescript|go を指定することで chaincode の実装言語を選べる。デフォルトは Go だがチュートリアル的には JavaScript で説明している。 前回までの BYFN では Go をつかってたし、せっかくだから今回はチュートリアル通りに JavaScript でやってみる。好みではないんだけどね。
なお、それぞれの chaincode のソースコードは ../chaincode/fabcar
に置いてある。
javascript-low-level
というディレクトリがあるが、これは v1.4 以前のプログラムモデルによる実装。詳細は以下を参照。
hyperledger-fabric.readthedocs.io
- (TypeScriptのみ) JavaScript へのトランスパイル
- Go のコンパイルは chaincode のインストール時に行われてるように見えていたが、TypeScript のトランスパイルはこの時点で行う
- つまり、実装言語は TypeScript だとしても、実際に chaincode としてインストールされるのは(トランスパイルされた) JavaScript ということになる。
docker-compose
で必要なノードを起動する- 設定ファイルは
../basic-network/docker-compose.yml
- 前回までは
crypto-config
を生成していたが、今回は最初から出来てる../basic-network/generate.sh
で作ることもできるっぽいが、なんか微妙に違うものができる- generate 時の設定ファイル
../basic-network/crypto-configl.yaml
はorderer
およびorg1
の設定のみがある
- generate 時の設定ファイル
- 今回作成するのは以下。なお全てのノードは
basic
ネットワークに含まれる。ca.example.com
- CA サーバ。今回初出。
ca.org1
の証明書と鍵をもつ
orderer.example.com
- Orderer
orderer
の証明書と鍵をもつpeer0.org1
の証明書と鍵をもつ
peer0.org1.example.com
- peer. 今回は 1 Organization, 1 Peer 構成ということになる
peer0.org1
の証明書と鍵をもつorg1
の User1 と Admin の証明書と鍵をもつ
couchdb
- CouchDB. 台帳の最新状況を保持するためのもの。今回初出。
cli
peer0.org1
に対する操作がセットアップされている- 全
crypto-config
データを持っている
- 設定ファイルは
mychannel
チャンネルを作成- 設定は
../basic-network/channel.tx
- これまた既に作成済み。元となるものは
../basic-network/configtx.yaml
- チャンネル参加者は
orderer
およびpeer0.org1
のみ。
- チャンネル参加者は
- 設定は
mychannel
にpeer0.org1
を joinmchannel.block
も作成済み。
mychannel
に ChainCodefabcar
v1.0 をインストール- ChainCode のパスは上述の通り
mychannel
の ChainCodefabcar
v1.0 をインスタンス化mychannel
の ChainCodefabcar
に対しinitLedger()
を invoke- 動作確認がてら初期データの挿入を行っている模様
- 以下を読み進めればわかる事だが、呼ばれているのは
../fabcar/javascript/lib/fabcar.js
クライアント側セットアップ
上記で chaincode の使用準備は整ったが、このままでは peer コマンド経由で叩くくらいしか使い道がない。 したがってクライアントアプリの構築をする。
startFabric.sh
の出力を見てもわかるとおり、クライアントアプリの実装言語を選んで cd
し、ビルドコマンドを叩くだけ。
クライアントアプリは JavaScript か TypeScript が選べ、また ChainCode 同様 v1.4 以前のプログラムモデルによる javascript-low-level
もある。
ここも TypeScript はトランスパイルの 1 手間がかかるだけで大した違いはないっぽいので、素直にチュートリアルの指示通り JavaScript を選択した。
node enrollAdmin.js
クライアント用の Admin ユーザを登録。ざっくり読んでいく。
なお、Client側 (以下 SDK) API ドキュメントはコレ。
../../basic-network/connection.json
をccp
として読み込み- 当該ファイルは今回のシステムの構成情報を記述してある。
- 以下、CA の URL を得るために使用している
new FabricCAServices()
で CA に接続wallet = new FileSystemWallet()
として./wallet
を使用- 現時点では
./wallet
は空ディレクトリ - Hyperledger Fabric SDK for node.js Class: FileSystemWallet
- 現時点では
identity = await ca.enroll({ enrollmentID: 'admin' ... })
して CA にadmin
を登録。- Hyperledger Fabric SDK for node.js Class: FabricCAServices
- レスポンスには
admin
の証明書と秘密鍵、ルート証明書が含まれる
X509WalletMixin.createIdentity(identity...)
で、上で取得した鍵と証明書、MSPID (=Org1MSP
) から Identity を生成wallet.import('admin', identity)
でwallet
にadmin
としてidentity
を登録
これで wallet に admin
が登録される。
-
./wallet
は以下のようになる。
$ tree wallet wallet └── admin ├── 81e6bfa(略)691478-priv ├── 81e6bfa(略)691478-pub └── admin 1 directory, 3 files
81e6bfa(略)691478-priv
,81e6bfa(略)691478-pub
は名前の通り中身はそれぞれ秘密鍵と公開鍵81e6bfa(略)691478
はランダムな値で、毎回違う値になる。
admin
は JSON ファイルで、以下のようなかんじ。
{ "name": "admin", "mspid": "Org1MSP", "roles": null, "affiliation": "", "enrollmentSecret": "", "enrollment": { "signingIdentity": "31b577222c67(略)73516ea3c2483a", "identity": { "certificate": "-----BEGIN CERTIFICATE-----\nMIICAjCCA(略)BAd8GA=\n-----END CERTIFICATE-----\n" } } }
-
certificate
部分は証明書なので平文に戻してみると以下ca.org1.example.com
がclient
のadmin
に発行した証明書であることがわかる。- これらは
ca.enroll
時に生成されたもので、../../basic-network/crypto-config
にあるAdmin@ca.org1.example.com
等の cert とは異なるもの。
$ Cat wallet/admin/admin \ | jq -r '.enrollment.identity.certificate' \ | openssl x509 -inform PEM -text -noout
Certificate: Data: Version: 3 (0x2) Serial Number: 02:af:ba:bd:ec:(略):c0:6c:27:1c:66 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: Apr 17 07:34:00 2019 GMT Not After : Apr 16 07:39:00 2020 GMT Subject: OU=client, CN=admin Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:1d:36:c3:b7:64:20:03:7f:82:39:f8:58:2d:37: (略) 5d:3a:c9:72:0b 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: 67:49:65:58:49:(略):86:CA:A9:96:F7:91 X509v3 Authority Key Identifier: keyid:42:39:AA:(略):6A:57:36:5E:49:7C Signature Algorithm: ecdsa-with-SHA256 30:44:02:20:7c:7c:58:29:d9:5e:db:6a:91:af:1b:3b:19:8d: (略) 16:60:52:00:0c:91:58:3a:f0:75:88:ae:3d:15:1f:df
node registerUser.js
../../basic-network/connection.json
をccp
として読み込み- 当該ファイルは今回のシステムの構成情報を記述してある。
- 以下、CA の URL を得るために使用している
new FileSystemWallet()
として./wallet
を使用- 現時点では、
./wallet
には./wallet/admin
だけが存在している - Hyperledger Fabric SDK for node.js Class: FileSystemWallet wallet を使用することで client の admin として振舞える
- 現時点では、
gateway.connect(ccp, {wallet, identity: 'admin' ...})
でゲートウェイに接続- Hyperledger Fabric SDK for node.js Class: Gateway
- これで、各ノードに対し
wallet
を使用して接続し、client
のadmin
として振舞える
secret = await ca.register(...)
でユーザを作成- Hyperledger Fabric SDK for node.js Class: FabricCAServices
- CA に対し
admin
の権限で実行 client
ロールをもつuser1@org1.department1
ユーザを作成するsecret
はuser1
のパスワード(自動生成)- まだ作っただけで登録は済んでいない。次の
enroll()
ではじめて登録される。
await ca.enroll()
,X509WalletMixin.createIdentity()
,wallet.import()
でwallet
にuser1
を保存admin
の時と全く同じ。
これで wallet に user1
が登録される。
-
./wallet
は以下のようになる。
$ tree wallet wallet ├── admin │ ├── 81bab1e(略)724a0e-priv │ ├── 81e6bfa(略)691478-priv │ ├── 81e6bfa(略)691478-pub │ └── admin └── user1 ├── 81bab1e(略)724a0e-priv ├── 81bab1e(略)724a0e-pub └── user1 2 directories, 7 files
user1
ディレクトリができ、鍵ペアと証明書が新たに追加されたadmin
の下に新しい秘密鍵が増え、user1
のそれと同じというのが謎- あとでしらべる
- 先ほど同様
user1
のcertificate
部分を平文に戻してみると以下ca.org1.example.com
がclient
のadmin
に発行した証明書であることがわかる。1.2.3.4.5.6.7.8.1:
という属性が追加されており、ユーザ作成時に指定したaffiliation
やrole
などの追加情報が埋め込まれている- これが MSP で使用されるのだろう、たぶん。
Certificate: Data: Version: 3 (0x2) Serial Number: 28:38:98:15:77:(略):48:ce:39:9c:58 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: Apr 17 09:26:00 2019 GMT Not After : Apr 16 09:31:00 2020 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:52:7b:ef:f4:49:b7:30:07:e6:a1:40:e7:90:70: (略) 6a:9f:ae:ce:5d 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: 5C:B5:E3:84:9F:(略):0B:C6:10:55:AF:38 X509v3 Authority Key Identifier: keyid:42:39:AA:(略):6A:57:36:5E:49:7C 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:45:02:21:00:e9:10:09:8b:4b:d8:29:c8:e8:e8:52:b4:2f: (略) 79:02:91:e1:04:32:af:65:b1:6e:42:ea:09:ab:72:33:86
今日はここで中断
さあこれから query と invoke を叩いて SDK 側だけじゃなく ChainCode の内側まで入っていくよ、という所なのだが、話が長くなりそうなので今回はここで中断。
次回はこの続きを読んでいくよ。