私有数据
注解
本主题假定你对 私有数据文档 中的概念性材料有所了解。
1. 私有数据集合定义
集合定义包含一个或多个集合,每个集合都有一个策略定义,其中列出了集合中的组织,以及用于在背书时控制私有数据分发的属性以及 (可选) 是否清除数据的属性。
链码实例化 (或升级) 时,集合定义将部署到通道。如果使用对端节点 CLI 实例化链码,则使用 --collections-config
标志将集合定义文件传递到链码实例化。如果使用客户端 SDK,请查看 SDK 文档以获取有关提供集合定义的信息。
集合定义由以下属性组成:
- 名称 (
name
):集合的名称。 - 策略 (
policy
):私有数据集合分发策略定义允许哪些组织的对端节点保留使用签名策略语法 (Signature policy syntax) 表示的集合数据,并且每个成员都包含在OR
签名策略列表中。为了支持读/写交易,私有数据分发策略必须定义比链码背书策略更广泛的组织集,因为对端节点必须具有私有数据才能背书提案的交易。例如,在有十个组织的通道中,私有数据集合分发策略中可能包含五个组织,但是背书策略可能要求其中三个组织都认可。 -
requiredPeerCount
:每个背书对端节点 (在所有授权组织中) 必须成功分发私有数据的最小对端节点数目,然后对端节点签署背书并将提案响应返回给客户。要求传播作为背书的条件,将确保即使背书对端节点变得不可用,私有数据也可以在网络中使用。当requiredPeerCount
为 0 时,表示不需要分配,但是如果maxPeerCount
大于零,则可能会有一些分配。通常不建议将requiredPeerCount
设置为 0,因为如果背书的对端节点变得不可用,则可能导致网络中的私有数据丢失。通常,你需要在背书时至少分配一些私有数据,以确保私有数据在网络中多个对端节点上的冗余。 -
maxPeerCount
:出于数据冗余的目的,每个背书对端节点将尝试向其分发私有数据的其他对端节点 (跨授权组织) 的最大数量。如果在背书时间和提交时间之间没有背书的对端节点可用,则作为集合成员但在背书时尚未收到私有数据的其他对端节点将能够从分发了私有数据的对端节点中获取私有数据。如果将此值设置为 0,则在背书时不会传播私有数据,从而在提交时强制私有数据在所有授权对端节点上对背书对端节点进行拉取。 -
blockToLive
:以区块为单位表示数据在私有数据库上应保留的时间。数据将在指定数量的私有数据库上保留,此后将被清除,从而使该数据已从网络中删除,因此无法从链码中查询它,也无法将其提供给请求对端节点。要无限期保留私有数据,即从不清除私有数据,请将blockToLive
属性设置为 0。 -
memberOnlyRead
:值为 true 表示对端节点自动强制仅允许属于集合成员组织之一的客户端对私有数据进行读取访问。如果来自非成员组织的客户端尝试执行执行读私有数据的链码功能,则链码调用会因错误而终止。如果你想在单个链码函数中对更细粒度的访问控制进行编码,请使用 false 值。
这是一个示例集合定义 JSON 文件,其中包含两个集合定义的数组:
[
{
"name": "collectionMarbles",
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":1000000,
"memberOnlyRead": true
},
{
"name": "collectionMarblePrivateDetails",
"policy": "OR('Org1MSP.member')",
"requiredPeerCount": 0,
"maxPeerCount": 3,
"blockToLive":3,
"memberOnlyRead": true
}
]
本示例使用来自 BYFN 示例网络 Org1 和 Org2 的组织。 collectionMarbles 定义中的策略授权两个组织使用私有数据。当链码数据需要对排序服务节点保持私有时,这是一种典型配置。但是,collectionMarblePrivateDetails 定义中的策略将限制访问通道中的组织子集 (在本例中为 Org1)。在实际情况下,通道中将有许多组织,每个集合中有两个或多个组织在它们之间共享私有数据。
2. 私有数据传播
由于私有数据不包括在提交给排序服务的交易中,因此也不包括在分发给通道中所有对端节点的区块中,因此背书对端节点在将私有数据分发给授权组织的其他对端节点方面起着重要作用。这样,即使背书的对端节点在背书后变得不可用,也可以确保通道集合中私有数据的可用性。为了帮助进行这种分发,集合定义中的 maxPeerCount 和 requiredPeerCount 属性控制了背书时的分发程度。
如果背书对端节点不能成功地将私有数据至少传播到 requiredPeerCount,它将向客户端返回错误。背书对端节点将尝试将私有数据分发给不同组织的对端节点,以确保每个授权组织都具有私有数据的副本。由于交易不是在链码执行时提交的,因此背书对端节点和接收方对端节点将私有数据的副本存储在其区块链旁边的本地临时存储中,直到交易被提交为止。
如果授权对端节点在提交时在其临时数据存储区中没有私有数据的副本 (或者因为他们不是背书对端节点,或者因为他们在背书时未通过分发接收到私有数据),他们将尝试拉取根据对端节点配置 core.yaml 文件中的对端节点属性 peer.gossip.pvtData.pullRetryThreshold,在可配置的时间内配置来自另一个授权对端节点的私有数据。
注解
仅当请求的对端节点是私有数据分发策略所定义的集合的成员时,被要求提供私有数据的对端节点才返回私有数据。
使用 pullRetryThreshold 时的注意事项:
- 如果发出请求的对端节点能够在 pullRetryThreshold 中检索私有数据,它将把交易提交到其帐本 (包括私有数据哈希),并将私有数据存储在其状态数据库中,该数据与其他通道状态数据在逻辑上是分开的。
- 如果发出请求的对端节点无法在 pullRetryThreshold 中检索私有数据,它将把交易提交到其区块链 (包括私有数据哈希),而没有私有数据。
- 如果对端节点有权使用私有数据,但该对端节点丢失了,那么该对端节点将无法背书引用了丢失的私有数据的将来的交易 - 将检测到链码查询丢失的键 (基于存在的键在状态数据库中的哈希值),并且链码将收到错误。
因此,重要的是将 requiredPeerCount 和 maxPeerCount 属性设置为足够大,以确保通道中私有数据的可用性。例如,如果每个背书对端节点在交易提交之前变得不可用,则 requiredPeerCount 和 maxPeerCount 属性将确保私有数据在其他对端节点上可用。
注解
为了使集合正常工作,正确配置跨组织 gossip 很重要。请参阅我们关于 Gossip 数据分发协议 的文档,尤其要注意“锚点”和“外部端点”的配置。
3. 从链码引用集合
一组 [shim API] 可用于设置和检索私有数据。
可以将相同的链码数据操作应用于通道状态数据和私有数据,但是在私有数据的情况下,将在链码 API 中与数据一起指定集合名称,例如 PutPrivateData(collection,key,value)
和 GetPrivateData(collection,key)
。
单个链码可以引用多个集合。
3.1 如何在链码提案中传递私有数据
由于链码提案存储在区块链上,因此在链码提案的主要部分中不要包含私有数据也很重要。链码提案中的一个特殊字段称为瞬态 (transient) 字段,可用于传递来自客户端的私有数据 (或链码将用于生成私有数据的数据),以在对端节点上进行链码调用。链码可以通过调用 GetTransient() API 来检索瞬态字段。此瞬态字段将从通道交易中排除。
3.2 保护私有数据内容
如果私有数据相对简单且可预测 (例如,交易金额),则未经授权访问私有数据集合的通道成员可以尝试通过域空间的强力哈希猜测猜测私有数据的内容,以期找到与链上私有数据哈希的匹配。因此,可预测的私有数据应包括与私有数据键连接并包含在私有数据值中的随机“盐”,以使得无法通过蛮力实际找到匹配的哈希。可以在客户端生成随机的“盐” (例如,通过对安全的伪随机源进行采样),然后在调用链码时将其与私有数据一起传递到瞬态字段中。
3.3 私有数据的访问控制
在 1.3 版之前,仅对对端节点实施基于集合成员资格的对私有数据的访问控制。基于链码提案提交者组织的访问控制需要以链码逻辑进行编码。从 v1.4 开始,集合配置选项 memberOnlyRead 可以根据链码提案提交者的组织自动执行访问控制。有关集合配置定义以及如何设置它们的更多信息,请参考本主题的私有数据集合定义部分。
注解
如果你想要更精细的访问控制,可以将 memberOnlyRead 设置为 false。然后,你可以在链码中应用自己的访问控制逻辑,例如,通过调用 GetCreator() 链码 API 或使用客户端身份 链码库。
3.4 查询私有数据
可以像普通通道数据一样使用 shim API 查询私有数据集合:
- GetPrivateDataByRange(collection, startKey, endKey string)
- GetPrivateDataByPartialCompositeKey(collection, objectType string, keys []string)
对于 CouchDB 状态数据库,可以使用 shim API 传递 JSON 内容查询:
- GetPrivateDataQueryResult(collection, query string)
局限性:
- 根据上面的私有数据分发部分中的说明,调用执行范围或富 JSON 查询的链码的客户端应注意,如果他们查询的对端节点缺少私有数据,则他们可能会收到结果集的子集。客户端可以查询多个对端节点并比较结果,以确定对端节点是否可能缺少某些结果集。
- 不支持在单个交易中执行范围或富 JSON 查询并更新数据的链码,因为无法在无法访问私有数据的对端节点或缺少私有数据的对端节点上验证查询结果他们有权使用。如果链码调用既查询又更新私有数据,则提案请求将返回错误。如果你的应用程序可以容忍链码执行和验证/提交时间之间的结果集更改,那么你可以调用一个链码功能来执行查询,然后调用第二个链码功能来进行更新。请注意,可以调用 GetPrivateData() 以检索单个键,并且可以与 PutPrivateData() 调用在同一交易中进行,因为所有对端节点都可以基于哈希键版本来验证键读取。
3.5 对集合使用索引
CouchDB as the State Database 主题描述了可通过在链码安装时将索引打包在 META-INF/statedb/couchdb/indexes
目录中而将索引应用于通道的状态数据库以启用 JSON 内容查询的索引。同样,通过将索引打包在 META-INF/statedb/couchdb/collections/<collection_name>/indexes
目录中,索引也可以应用于私有数据集合。此处提供示例索引。
4. 使用私有数据时的注意事项
4.1 私有数据清除
可以定期从对端节点清除私有数据。有关更多详细信息,请参见上面的 blockToLive
集合定义属性。
此外,回想一下在提交之前,对端节点将私有数据存储在本地瞬态数据存储中。交易提交时,该数据将自动清除。但是,如果交易从未提交给通道,因此也从未提交,则私有数据将保留在每个对端节点的瞬态存储中。通过使用对端节点 core.yaml 文件中的对端节点的 peer.gossip.pvtData.transientstoreMaxBlockRetention 属性,可配置的区块数量后,将从瞬态存储中清除此数据。
4.2 更新集合定义
要更新集合定义或添加新集合,你可以将链码升级到新版本,并在链码升级交易中传递新的集合配置,例如,如果使用 CLI,则使用 --collections-config
标志。如果在链码升级过程中指定了集合配置,则必须包括每个现有集合的定义。
升级链码时,你可以添加新的私有数据集合,并更新现有的私有数据集合,例如,将新成员添加到现有集合或更改集合定义属性之一。请注意,你不能更新集合名称或 blockToLive 属性,因为无论对端节点的区块高度如何,都需要一致的 blockToLive。
当对端节点提交包含链码升级交易的区块时,集合更新将生效。请注意,无法删除集合,因为该通道的区块链上可能有先前的私有数据哈希无法删除。
4.3 私有数据核对
从 v1.4 开始,添加到现有集合中的组织的对端节点将在加入集合之前自动获取已提交到集合的私有数据。
此私有数据核对还适用于有权接收私有数据但尚未接收到它的对端节 (例如,由于网络故障),通过跟踪在区块提交时丢失的私有数据。
私有数据核对会根据 core.yaml 中的 peer.gossip.pvtData.reconciliationEnabled 和 peer.gossip.pvtData.reconcileSleepInterval 属性定期进行。该对端节点将定期尝试从预期拥有该数据的其他集合成员对端节点获取私有数据。
请注意,此私有数据协调功能仅适用于运行 Fabric v1.4 或更高版本的对端节点。
Reference
- Docs » Architecture Reference » Private Data, https://hyperledger-fabric.readthedocs.io/en/release-1.4/private-data-arch.html
- Docs » Key Concepts » Private data, https://hyperledger-fabric.readthedocs.io/en/release-1.4/private-data/private-data.html
- https://fabric-sdk-node.github.io/
- Docs » Architecture Reference » Gossip data dissemination protocol, https://hyperledger-fabric.readthedocs.io/en/release-1.4/gossip.html
- https://github.com/hyperledger/fabric/blob/8b3cbda97e58d1a4ff664219244ffd1d89d7fba8/core/chaincode/shim/interfaces.go#L315-L321
- https://github.com/hyperledger/fabric/tree/master/core/chaincode/shim/ext/cid
- Docs » Architecture Reference » CouchDB as the State Database, https://hyperledger-fabric.readthedocs.io/en/release-1.4/couchdb_as_state_database.html
项目源代码
项目源代码会逐步上传到 Github,地址为 https://github.com/windstamp。
Contributor
- Windstamp, https://github.com/windstamp