いるねすのブログ

働きたくない系SEが無駄に遊んだ記録

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

  1. (TypeScriptのみ) JavaScript へのトランスパイル
    • Go のコンパイルは chaincode のインストール時に行われてるように見えていたが、TypeScript のトランスパイルはこの時点で行う
    • つまり、実装言語は TypeScript だとしても、実際に chaincode としてインストールされるのは(トランスパイルされた) JavaScript ということになる。
  2. docker-compose で必要なノードを起動する
    • 設定ファイルは ../basic-network/docker-compose.yml
    • 前回までは crypto-config を生成していたが、今回は最初から出来てる
      • ../basic-network/generate.sh で作ることもできるっぽいが、なんか微妙に違うものができる
        • generate 時の設定ファイル ../basic-network/crypto-configl.yamlorderer および org1 の設定のみがある
    • 今回作成するのは以下。なお全てのノードは 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 データを持っている
  3. mychannel チャンネルを作成
    • 設定は ../basic-network/channel.tx
    • これまた既に作成済み。元となるものは ../basic-network/configtx.yaml
      • チャンネル参加者は orderer および peer0.org1 のみ。
  4. mychannelpeer0.org1 を join
    • mchannel.block も作成済み。
  5. mychannel に ChainCode fabcar v1.0 をインストール
    • ChainCode のパスは上述の通り
  6. mychannel の ChainCode fabcar v1.0 をインスタンス
  7. mychannel の ChainCode fabcar に対し 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 ドキュメントはコレ。

fabric-sdk-node.github.io

  1. ../../basic-network/connection.jsonccp として読み込み
    • 当該ファイルは今回のシステムの構成情報を記述してある。
    • 以下、CA の URL を得るために使用している
  2. new FabricCAServices() で CA に接続
  3. wallet = new FileSystemWallet() として ./wallet を使用
  4. identity = await ca.enroll({ enrollmentID: 'admin' ... }) して CA に admin を登録。
  5. X509WalletMixin.createIdentity(identity...) で、上で取得した鍵と証明書、MSPID (=Org1MSP) から Identity を生成
  6. wallet.import('admin', identity)walletadmin として 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 はランダムな値で、毎回違う値になる。
  • adminJSON ファイルで、以下のようなかんじ。
{
  "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.comclientadmin に発行した証明書であることがわかる。
    • これらは 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

  1. ../../basic-network/connection.jsonccp として読み込み
    • 当該ファイルは今回のシステムの構成情報を記述してある。
    • 以下、CA の URL を得るために使用している
  2. new FileSystemWallet() として ./wallet を使用
  3. gateway.connect(ccp, {wallet, identity: 'admin' ...})ゲートウェイに接続
  4. secret = await ca.register(...) でユーザを作成
    • Hyperledger Fabric SDK for node.js Class: FabricCAServices
    • CA に対し admin の権限で実行
    • client ロールをもつ user1@org1.department1 ユーザを作成する
    • secretuser1 のパスワード(自動生成)
    • まだ作っただけで登録は済んでいない。次の enroll() ではじめて登録される。
  5. await ca.enroll(), X509WalletMixin.createIdentity(), wallet.import()walletuser1 を保存
    • 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 のそれと同じというのが謎
    • あとでしらべる
  • 先ほど同様user1certificate 部分を平文に戻してみると以下
    • ca.org1.example.comclientadmin に発行した証明書であることがわかる。
    • 1.2.3.4.5.6.7.8.1: という属性が追加されており、ユーザ作成時に指定した affiliationrole などの追加情報が埋め込まれている
      • これが 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 の内側まで入っていくよ、という所なのだが、話が長くなりそうなので今回はここで中断。

次回はこの続きを読んでいくよ。