連載 [第3回] :
  Hyperledger Fabric再入門

Hyperledger Fabricのアーキテクチャとchaincodeのデプロイ

2020年10月2日(金)
西島 直

はじめに

前回はHyperledger fabric-samplesを利用して、自動車の所有者を管理するchaincodeを動かしました。いくつかのトランザクションを発行して、ブロックチェーンのブロックが積まれていく様子を確認できたかと思います。

しかし、エンドースメントポリシーを満たさないトランザクションはブロックが積まれましたが、値は反映されませんでした。今回は、なぜそのようになったのか、Hyperledger Fabricのアーキテクチャと共に解説します。また、前回コマンドを実行したchaincodeのデプロイについても触れていきます。

Hyperledger Fabricアーキテクチャ

Hyperledger Fabricには「CA」「orderer」「peer」という3つのノードがあります。CAは許可型ブロックチェーンを実現するための重要な役割をもつ認証局で、組織のメンバーに証明書の発行や失効ができます。

Ordererはトランザクションの順序を決め、ブロックに変換して検証とコミットのためpeerにブロックを配布します。コンセンサス(合意形成)にはKafkaやRaftを使用しますが、Kafkaは非推奨になっているため、現在ではRaftが標準で利用されます。今後はPBFT(Practical Byzantine Fault Tolerance)を実装する予定です。

Peerは台帳(後述)を維持し、台帳の読み書き操作を行うchaincodeを実行します。Peerは各組織に1つ以上あり、異なる組織のpeer間で相互に状況を確認するため、ゴシッププロトコルを用いて通信を行います。組織の中で外部と通信を行う代表的なpeerを「anchor peer」と呼びます。Anchor peer同士が通信し合い、anchor peerが知っているすべてのpeerについて情報交換をします。

台帳とブロックとワールドステート

Hyperledger Fabricにおける台帳(ledger)は、複数のトランザクションを含むブロックとワールドステート(world stateまたはstate database)から構成されています。銀行口座に例えると、利用可能な残高がワールドステートで、今までの取引履歴がブロックです。ワールドステートは今までの取引履歴を計算することで算出でき、最新の残高で取引を実行します。

検証(Validation)

Hyperledger fabricでは、全てのトランザクションの値を反映するわけではありません。Hyperledger fabricは分散システムであり、タイミングによっては参照したワールドステートが最新ではない可能性があります(ファントムリード)。また、エンドースメント直後にOrdererからブロックを受け取りワールドステートに反映してしまい、エンドースメントした結果と最新のワールドステートの値が異なることもあります。

これらを防ぐために、Execute-Order-ValidateアーキテクチャのValidationフェーズでトランザクションの値を確認しています。Validateフェーズは各トランザクションがエンドースメントポリシーを満たしているか、またはタイミングによってはエンドースメントを受け取った後で新しいブロックが積まれてトランザクションの結果が変わり、結果の不一致が起きてないかを検証しています。

Validationフェーズの検証により、トランザクションが無効になっても、すでにOrderフェーズでそのトランザクションを含んだブロックでハッシュ値を計算しているため、そのトランザクションは削除できません。したがって、それら無効なトランザクションの値はワールドステートに反映されません。

反映されない理由

前回でも解説したように、エンドースメントポリシーを満たさないトランザクションは検証の仕組みにより、ブロックとしては積まれてもワールドステートには反映されません。そのため、ワールドステートの値を取得するためにqueryを実行するとValidationフェーズで有効となった最新のトランザクションの値が取得されます。

スマートコントラクト「chaincode」

ビジネスで取引をするには、ルールなどを決めた契約を取り交わす必要があります。この契約が当事者同士の相互作用を決めるビジネスモデルになります。このモデルをコードで表現したものがスマートコントラクトで、Hyperledger Fabricではスマートコントラクトのことを「chainocde」と呼びます。

chaincodeはGoやNode.js、Javaで記述できます。dockerコンテナ内で動作し、アプリケーションから送信されたトランザクションを介して台帳の状態を操作します。Channel上に1つ以上のchaincodeをインストールでき、chaincodeからほかのchaincodeを呼び出すこともできます。

chaincodeのデプロイ方法

前回のfabric-samplesを利用して、どのようにchaincodeをデプロイしているのか詳しく見てみましょう。test-networkのnetwork.shでは、環境構築後にchannelを構築し、chaincodeをデプロイしました。Chaincodeのデプロイは次のような手順で行っています。

Cat fabric-samples/test-network/scripts/deployCC.sh
(中略)
packageChaincode 1
(中略)
installChaincode 1
(中略)
installChaincode 2
(中略)
queryInstalled 1
(中略)
approveForMyOrg 1
(中略)
checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": false"
checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": false"
(中略)
approveForMyOrg 2
(中略)
checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": true"
checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": true"
(中略)
commitChaincodeDefinition 1 2
(中略)
chaincodeInvokeInit 1 2
(中略)

1. パッケージング
3行目のpackageChaincodeでは、Org1がchaincodeのソースコードと必要なモジュールをtarファイルにパッケージングしています。Fabric sdkやchaincode内で定義したパッケージを取得(Nodejsであればnpm、Goであればvendering)してtarファイルにパッケージ化します。前回と同様に、./network.sh deployCCを実行した際に同じディレクトリにfabcar.tar.gzのファイルが生成されます。これは1つの組織が代表して行っても良いですし、各組織がそれぞれ行っても大丈夫です。

2. インストール
5、7行目で、パッケージングしたchaincodeを組織Org1とOrg2それぞれのpeerにインストールしています。エンドースメントを行う必要があるpeer全てにインストールしますが、エンドースメントしないpeerというものもあり、それはブロックを保存するだけのpeerです。

3. 承認
11、16行目で、インストールしたchaincodeを各組織(Org1とOrg2)で承認します。承認を行うコマンドのパラメータにはchaincodeの名前やバージョン、エンドースメントポリシーなどがあります。承認はこれらの各組織のパラメータの投票として機能します。組織間でこれらのパラメータの提案に対して一貫性を持つ必要があります。

4. コミット
十分な数の組織がchaincodeのパラメータを承認すると、21行目でchannelにコミットしています。13、14、18、19行目で各組織(Org1とOrg2)が提案したパラメータを確認しています。承認が必要な数の組織数はConfigtx/configtx.yaml(下記)で確認できます。19行目のLifecycleEndorsementのRuleには“MAJORITY Endorsement”と記載されているので、過半数以上の承認があればコミットが可能です。

Cat configtx/configtx.yaml
(中略)
Application: &ApplicationDefaults
(中略)

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
(中略)

5. 初期化
chaincodeがコミットされるとchaincodeを使用できるようになりますが、chaincodeは初期化が必要なため、chaincod内に定義されたInit関数を呼び出します(deployCC.shの23行目)。

このように、chiancodeのデプロイは複数組織で行います。ブロックチェーンは複数組織での業務で利用されるため、それぞれの組織の合意を得たプロセスで行われる必要があります。

おわりに

今回は、Hyperledger Fabricのアーキテクチャとchaincodeのデプロイについて解説しました。ブロックチェーンは普通のシステムと違って異なる組織が登場するため、それぞれ協調してchaincodeを開始する必要があります。その方法は、fabric-samplesのスクリプトを見れば理解できるでしょう。

次回は、実際にchaincodeを開発してみたいと思います。

株式会社日立製作所

研究開発グループ デジタルテクノロジーイノベーションセンタ OSSテクノロジーラボラトリ員
OSSの評価・検証・機能開発、upstream活動、社内外へのOSS普及に従事。
Linux KernelやKVM、OpenStackでOSSコミュニティの参加した経験を持つ。
現在はHyperledgerコミュニティに参加しブロックチェーンの普及に勤めている。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています