Private Data

注釈

このトピックは、documentation on private data セクションのコンセプトを理解することに繋がります。

Private data collection definition

コレクション定義は1つもしくは多くのコレクションを含みます。また、コレクションには組織がリスト化したポリシー定義を含み、同様にエンドースメント時にプライベートデータの配布先やパージするかどうかを決めるプロパティも含みます。

Fabric v2.0のチェーンコードライフサイクルを発端として、コレクション定義はチェーンコード定義の一部です。コレクションはチャネルメンバーによって承認され、チェーンコード定義がチャネルにコミットされた際にデプロイされます。コレクションファイルは、全てのチャネルメンバーに必要になります。チェーンコード定義をピアCLIを使用して承認しコミットする場合、コレクション定義ファイルのパスを指定して --collections-config フラグを付与します。Fabric SDK for Node.jsを使用する場合は、 How to install and start your chaincode にアクセスしてください。プライベートコレクションをデプロイするために previous lifecycle process を使用する場合、 instantiating your chaincode する際に --collections-config フラグを使用します。

コレクション定義は以下のプロパティから成り立ちます:

  • name: コレクション名
  • policy: プライベートデータコレクションのデータ配布ポリシーは Signature ポリシー構文を使用して表現され、 OR の署名ポリシーリストに含まれる組織のピアにデータが配布されます。読み書きトランザクションをサポートするために、プライベートデータの配布ポリシーはチェーンコードのエンドースメントポリシーより広く組織セットを定義する必要があります。それにより、提案されたトランザクションをエンドースし、ピアはプライベートデータを保持します。例えば、1チャネルに10の組織が所属し、5の組織がプライベートデータコレクションの配布ポリシーに含まれていた場合、エンドースメントポリシーにいづれかの3の組織を含む必要があります。
  • requiredPeerCount: エンドースメントの署名とプロポーザルレスポンスをクライアントに送信する前に、プライベートデータを配布する組織内のエンドーシングピアの最小の数です。エンドーシングピアが利用出来なくなったとしても、エンドースメントの条件としてプライベートデータの配布を指定することで、ネットワーク内でプライベートデータを利用することが出来ます。 requiredPeerCount0 の場合、プライベートデータは配布 されませんがmaxPeerCount が0より大きい場合は配布されます。エンドーシングピアが利用出来ない場合、プライベートデータが失われる可能性があるため、 requiredPeerCount0 に設定することは推奨されません。また、同一ネットワーク内の複数のピアにおいてプライベートデータの冗長性を確保するために、エンドースメント時にプライベートデータをいくつか配布することが良いでしょう。
  • maxPeerCount: データの冗長性を確保するために、プライベートデータを配布する組織内のエンドーシングピアの最大の数です。エンドースメントとコミットの際にエンドーシングピアが利用出来なくなった場合、エンドースメント時にプライベートデータを受領していないコレクションメンバーの他のピアは、配布されたプライベートデータをプルすることが出来ます。 0 を設定した場合、エンドースメント時にプライベートデータは配布されなくなり、コミット時に認可されたエンドーシングピアからプライベートデータをプルする必要があります。
  • blockToLive: ブロック単位でプライベートデータベースに保存される期間を表します。データは指定したブロック数でプライベートデータベースに保存され、その後パージされ、ネットワークから削除されるため、チェーンコードでクエリ出来なくなり、利用できなくなります。プライベートデータを永久に利用する、すなわちプライベートデータをパージされなくするためには、 blockToLive0 に設定してください。
  • memberOnlyRead: true を設定した場合、ピアは自動的にコレクションメンバーの組織に所属するクライアントのみをプライベートデータの閲覧を出来るようにします。メンバーでない組織に所属するクライアントがプライベートデータを閲覧するチェーンコードを実行した場合、エラーで終了します。より細かいアクセス制御をチェーンコードで実現したい場合、 false を設定してください。
  • memberOnlyWrite: true を設定した場合、ピアは自動的にコレクションメンバーの組織に所属するクライアントのみをプライベートデータの書込みをチェーンコードで出来るようにします。メンバーでない組織に所属するクライアントがプライベートデータを書込むチェーンコードを実行した場合、エラーで終了します。例えば、メンバーでない組織に所属するクライアントが特定のコレクションでプライベートデータを生成出来るようにするなど、より細かいアクセス制御をチェーンコードで実現したい場合、 false を設定してください。
  • endorsementPolicy: チェーンコードレベルのエンドースメントポリシーを上書きしたコレクションを利用するためのオプションのエンドースメントポリシーです。コレクションレベルのエンドースメントポリシーは signaturePolicy で指定、もしくは channelConfigPolicy にチャネルコンフィグレーションの既存のポリシーを指定します。 endorsementPolicy は、コレクション配布の policy と同じ、もしくはいくつかの組織ピアに必要とされます。

以下は、サンプルのコレクション定義のJSONファイルです。2つのコレクション定義を含みます。

[
 {
    "name": "collectionMarbles",
    "policy": "OR('Org1MSP.member', 'Org2MSP.member')",
    "requiredPeerCount": 0,
    "maxPeerCount": 3,
    "blockToLive":1000000,
    "memberOnlyRead": true,
    "memberOnlyWrite": true
 },
 {
    "name": "collectionMarblePrivateDetails",
    "policy": "OR('Org1MSP.member')",
    "requiredPeerCount": 0,
    "maxPeerCount": 3,
    "blockToLive":3,
    "memberOnlyRead": true,
    "memberOnlyWrite":true,
    "endorsementPolicy": {
      "signaturePolicy": "OR('Org1MSP.member')"
    }
 }
]

この例では、Fabricテストネットワークの Org1Org2 の組織を用いています。 collectionMarbles の定義では、ポリシーで両方の組織にプライベートデータを認可しています。これは、チェーンコードデータをオーダリングサービスノードからプライベートにするための典型的な設定です。しかし、 collectionMarblePrivateDetails の定義では、チャネルの組織のサブセットのアクセスを厳しく設定しています。この例では、 Org1 のみに認可しています。また、チェーンコードレベルのエンドースメントポリシーで Org1 もしくは Org2 のエンドースメントを必要と設定していても、 Org1 のピアのエンドースメントを必要とする設定に上書きしています。これは memberOnlyWrite にtrueを設定し、 Org1 に所属するクライアントのみをプライベートデータコレクションに書込むチェーンコードを実行出来るようにしているからです。このように、プライベートデータコレクションに書込む組織を制御することが出来ます。

Implicit private data collections

明示的に定義されたプライベートデータコレクションに加えて、すべてのチェーンコードには、組織固有のプライベートデータのために確保された暗黙のプライベートデータネームスペースがあります。これらの暗黙の組織固有プライベートデータコレクションは、個々の組織のプライベートデータを格納するために使用することができ、明示的に定義する必要はありません。

暗黙的な組織固有のプライベートデータコレクションのためのプライベートデータの配布ポリシーとエンドースメントポリシーは、組織それぞれに用意されています。暗黙のプライベートデータコレクションにデータが存在する場合、個別の組織に承認されます。それゆえ、暗黙のプライベートデータコレクションは、チェーンコードに実装されたマルチパーティのビジネスプロセスでよく使用されるパターンに対して、組織の同意や投票結果を記録するために使用されます。これにより、他組織は、検証のためにオンチェーンに記録されたハッシュデータをチェックすることが出来ます。また、プライベートデータは他組織の暗黙のコレクションに共有または転送することが出来、暗黙のコレクションは、コレクション定義を明示的に管理する必要がなく、チェーンコードアプリケーションで活用するのに有用です。

暗黙のプライベートデータコレクションは明示的に定義されていないため、コレクションプロパティを追加で設定することは出来ません。具体的には、 memberOnlyReadmemberOnlyWrite は使用出来ず、クライアントの暗黙のプライベートデータコレクションからのデータ読み取り、データ書込みのためのアクセスコントロールは、組織のピア上のチェーンコードで実装する必要があります。さらに、 blockToLive は使用出来ないので、プライベートデータが自動的にパージされません。

しかし、 requiredPeerCountmaxPeerCount は、ピアのcore.yamlでも設定出来ます ( peer.gossip.pvtData.implicitCollectionDisseminationPolicy.requiredPeerCountpeer.gossip.pvtData.implicitCollectionDisseminationPolicy.maxPeerCount )。これらの項目は、次のセクションで説明するピア数に応じて設定します。

注釈

暗黙のプライベートデータコレクションは明確に定義していないので、CouchDBのインデックスに関連付けることは出来ません。JSONクエリではなく、キークエリやキー範囲クエリを使用してください。

Private data dissemination

プライベートデータはオーダリングサービスに送信したトランザクションとチャネル内のピアに配布されたブロックを含んでいないため、エンドーシングピアは権限のある組織に所属する他のピアにプライベートデータを配布する役割を担います。これにより、エンドースメント後にエンドーシングピアが利用出来なくなったとしても、チャネルのコレクションのプライベートデータは利用可能です。プライベートデータの配布に関連して、 maxPeerCountrequiredPeerCount はエンドースメント時の配布プロセスを制御します。

エンドーシングピアが requiredPeerCount の数のピアにプライベートデータを配布出来なかった場合、クライアントにエラーが返ります。エンドーシングピアは、異なる組織のピアがプライベートデータを保持することを担保するために、プライベートデータを配布します。チェーンコード実行時にトランザクションはコミットされないため、エンドーシングピアとレシピエントピアはトランザクションがコミットされるまでローカルの transient store にプライベートデータのコピーを保持します。

エンドーシングピアではない且つエンドースメント時にプライベートデータを受領していないピアがコミット時にトランジエントデータストアにプライベートデータのコピーを保持していない場合、 core.yamlpeer.gossip.pvtData.pullRetryThreshold設定した時間 で他のピアからプライベートデータをプルします。

注釈

プライベートデータ配布ポリシーで定義したコレクションのメンバーがプライベートデータをリクエストした場合、リクエストされたピアは、プライベートデータのみを返します。

pullRetryThreshold を使用する際の考慮事項:

  • pullRetryThreshold で設定した時間内にプライベートデータを受領したピアは、プライベートデータハッシュも含めてトランザクションを台帳にコミットします。また、プライベートデータを、他のチャネルのステートデータとは分離した形でステートデータベースに保管します。
  • pullRetryThreshold で設定した時間内にプライベートデータを受領出来なかったピアは、プライベートデータはコミット出来ず、プライベートデータハッシュも含めてトランザクションを台帳にコミットします。
  • ピアが受領すべきだったプライベートデータを失った場合、そのプライベートデータに関連するトランザクションのエンドースメントが出来なくなります。チェーンコードにおいて、ステートデータベースにある失ったデータのハッシュを基に、失ったデータのキーが検出され、チェーンコードのクエリ実行時にエラーが発生します。

したがって、チャネルのプライベートデータの可用性を担保するために、 requiredPeerCount and maxPeerCount を十分に大きな値を設定することは重要です。例えば、トランザクションをコミットする前にエンドーシングピアが利用出来なくなった場合、 requiredPeerCount and maxPeerCount を設定することで、他のピアでのプライベートデータの可用性を担保します。

注釈

コレクションを上手く動作させるためには、組織を横断したゴシップを適切に設定することが重要です。 Gossip data dissemination protocol を参照して、"アンカーピア" と "エクスターナルエンドポイント" を注意して設定してください。

Referencing collections from chaincode

shim APIs を使用して、プライベートデータの設定と受領が可能です。

同一のチェーンコードでチャネルのステートデータとプライベートデータを操作出来ますが、プライベートデータの場合、 PutPrivateData(collection,key,value)GetPrivateData(collection,key) の様な形でチェーンコードAPIの引数にコレクション名を指定する必要があります。

単体のチェーンコードから複数のコレクションを参照出来ます。

Referencing implicit collections from chaincode

v2.0から、チャネルの各組織で暗黙のプライベートデータを使用出来るようになり、組織毎にコレクションを定義する必要がなくなりました。各組織の暗黙のコレクションは、組織に紐づく配布ポリシーとエンドースメントポリシーを含んでいます。したがって、コレクションキーネームスペースに書込む特定の組織を決めたい場合にも暗黙のコレクションを使用することが出来ます。v2.0のチェーンコードライフサイクルでは、組織が承認したチェーンコード定義を追っていくために暗黙のコレクションが使用されています。同様に、チェーンコードアプリケーションにおいても状態の変更に対する組織の承認や投票を追っていくために暗黙のコレクションが使用されています。

暗黙のプライベートデータコレクションキーを書込みと読み込むために、チェーンコードAPIの PutPrivateDataGetPrivateData に、 "_implicit_org_Org1MSP" の様な形で引数として、 "_implicit_org_<MSPID>" を指定する必要があります。

注釈

アプリケーションで定義するコレクション名には、接頭字にアンダースコアを指定出来ません。それにより、暗黙のコレクション名がアプリケーションで定義するコレクション名と被ることはありません。

How to pass private data in a chaincode proposal

ブロックチェーンにチェーンコード提案が保存されるため、チェーンコード提案にプライベートデータを含まないようにすることは重要です。ピアでチェーンコードを実行するために、 transient フィールドと呼ばれるチェーンコード提案の特別なフィールドを利用して、クライアントからのプライベートデータ、もしくはチェーンコードがプライベートデータで利用するデータを渡すことが出来ます。 GetTransient() API を呼び出すことで、チェーンコードが transient フィールドを読み込むことが出来るようになります。 この transient フィールドは、チャネルトランザクションから除外されます。

Protecting private data content

プライベートデータがトランザクションドル量のように比較的に単純で推測可能であれば、プライベートデータコレクションに対する権限を持っていないチャネルメンバーは、ブロックチェーン上のプライベートデータのハッシュをブルートフォースで見つけ、プライベートデータの内容を推測しようとします。推測可能なプライベートデータには、プライベートデータのキーを結合させ、プライベートデータを含めたランダムなソルトを含めることで、一致するハッシュをブルートフォースで見つけることを現実的に出来ないようにします。ランダムなソルトは、セキュアな疑似ランダムなソースのサンプリング等によりクライアント側で生成し、チェーンコード実行時に、トランジエントフィールドにプライベートデータと共に入れて渡します。

Access control for private data

バージョン1.3までは、コレクションメンバーシップを基にしたプライベートデータのアクセス制御がピアのみに適用されていました。チェーンコード提案送信者の組織を基にしたアクセス制御は、チェーンコードに実装する必要があります。バージョン1.4からのコレクション設定オプションである memberOnlyRead と、バージョン2.0からの memberOnlyWrite は、プライベートデータのキーの読み込みと書込みをするために、チェーンコード提案送信者をコレクションメンバーに自動的に適用させます。コレクション設定の定義や設定方法に関するより詳しい情報は、 Private data collection definition セクションを参照してください。

注釈

より細かいアクセス制御をする場合は、 memberOnlyReadmemberOnlyWrite をfalseに設定してください。なお、暗黙のコレクションは常にfalseの形で動作します。これにより、例えばチェーンコードAPIのGetCreator()を呼び出す、またはクライアント認証の chaincode library を使用することで、チェーンコードロジックにアクセス制御が適用されます。

Querying Private Data

shim APIを利用することで、プライベートデータコレクションは通常のチャネルデータの様にクエリすることが出来ます:

  • GetPrivateDataByRange(collection, startKey, endKey string)
  • GetPrivateDataByPartialCompositeKey(collection, objectType string, keys []string)

そして、明示的なプライベートデータコレクションとCoudh DBのステートデータベースを利用した場合、shim APIを利用してJSONコンテンツクエリを渡すことが出来ます:

  • GetPrivateDataQueryResult(collection, query string)

制約事項:

  • Private Data Disseminationセクションで述べた通り、プライベートデータを失ったピアに対して、キー範囲クエリもしくはJSONクエリを実行するチェーンコードを呼び出したクライアントは、結果セットのサブセットに注意しなければなりません。
  • プライベートデータにアクセス出来ないもしくはアクセス権限のあるプライベートデータを失ったピアで検証が出来ないということで、単一のトランザクションで、キー範囲クエリもしくはJSONクエリと、データ更新に関するチェーンコードの実行はサポートされていません。プライベートデータのクエリと更新を一度のチェーンコード実行ですると、トランザクション提案はエラーを返します。もしアプリケーションでチェーンコード実行と、検証及びコミットまでの間に結果セットの変更を許容するのであれば、1つのチェーンコードの関数でクエリを実行し、次に呼び出すチェーンコードの関数で更新を実行することが出来ます。個別のキーを取得するGetPrivateData()は、PutPrivateData()と同じトランザクションで呼び出すことが出来ます。これは、全てのピアがハッシュ化されたキーに基づいてキーの読み取りを検証出来るからです。
  • 暗黙のプライベートデータコレクションは明示的に定義されていないので、Couch DBのインデックスと紐づけることが出来ません。それゆえ、暗黙のプライベートデータコレクションを利用する場合は、JSONクエリを利用することは推奨されません。

Using Indexes with collections

CouchDB as the State Database トピックでは、チェーンコードインストール時に META-INF/statedb/couchdb/indexes ディレクトリにあるパッケージ化されたインデックスを利用して、JSONコンテンツクエリを使用出来るチャネルのステートデータベースに適用したインデックスについて説明しています。同様に、 META-INF/statedb/couchdb/collections/<collection_name>/indexes ディレクトリにあるパッケージ化されたインデックスを利用して、暗黙のプライベートデータコレクションに適用したインデックスを利用できます。インデックスの例は、 here を参照してください。

Considerations when using private data

Private data purging

暗黙のプライベートデータコレクションに含まれるプライベートデータは、ピアから周期的にパージされます。詳細は、上述の blockToLive のコレクション定義プロパティを参照してください。

加えて、コミット前は、ピアは、ローカルのトランジエントデータストアにプライベートデータを保管します。このデータは、トランザクションがコミットされた際に、自動的にパージされます。しかし、トランザクションがチャネルに送信されずコミットされない場合、プライベートデータは各ピアとトランジエントストアに残り続けます。このデータに関しては、ピアの core.yaml ファイルにある peer.gossip.pvtData.transientstoreMaxBlockRetention プロパティに設定した数よりもブロックが貯められるとトランジエントストアからパージされます。

Updating a collection definition

コレクション定義を更新もしくは新しいコレクションを追加するためには、チェーンコード定義を追加し、チェーンコード承認とコミットのトランザクションで新しいコレクション定義を渡さなければなりません。CLIを利用する場合は、 --collections-config フラグを利用します。チェーンコード定義を更新する際、コレクション定義が明示的な場合、既存の各コレクション定義を含めなければなりません。

チェーンコード定義を更新する際に、新しいプライベートデータコレクションの追加と既存のプライベートデータコレクションの更新が出来ます。例えば、既存のコレクションに新しいメンバーを追加したり、コレクション定義のプロパティの一つを変更することが出来ます。ただし、コレクション名やblockToLiveプロパティを更新することは出来ません。これは、ピアのブロックの高さの観点で、一貫したblockToLiveを必要とするからです。

ピアがチェーンコード定義を更新するブロックをコミットした際に、コレクションの更新はより効果的です。ただし、チャネルのブロックチェーン上にある過去のプライベートデータのハッシュを削除出来ないことと同様に、コレクションは削除出来ません。

Private data reconciliation

v1.4から、既存のコレクションに後から追加された組織のピアは、追加前にコレクションにコミットされたプライべートデータを自動的にフェッチします。

このプライベートデータの "調和" は権限を持ち、ネットワークの問題、例えばブロックのコミット時にプライベートデータの追跡を失いデータを受領していないピアにも適用されます。

プライベートデータ調和は、core.yamlの peer.gossip.pvtData.reconciliationEnabledpeer.gossip.pvtData.reconcileSleepInterval のプロパティを基に周期的に発生します。ピアはプライベートデータを持っている他のコレクションメンバーのピアからデータを周期的にフェッチします。

この様なプライベートデータ調和の機能は、v1.4以降のピアで動作しています。