揭秘 Hyperledger Fabric(2/3):私有数据集合

欢迎阅读揭秘 Hyperledger Fabric 系列的第二篇文章。我们假设读者已经了解 Hyperledger Fabric 架构。如果您遇到这篇文章,我建议您先查看上一篇文章

在上一篇文章中,您已经了解了 Hyperledger Fabric 的基本架构。在本文中,您将了解 Fabric 的另一个关键特性——私有数据集合(Private Data Collection)

在 Fabric 1.2 版之前,当一组组织需要对加入同一通道的其他组织保持数据私有时,该组织子集必须创建一个新的单独通道。这会导致额外的管理开销,例如管理链码(Chaincodes)、背书策略(Endorsement policies)、会员服务提供商配置等。此外,分离新通道无法处理某些组织可能需要将部分数据保密但与其他组织共享其余数据的情况。

私有数据集合是在 Hyperledger Fabric 1.2 版中引入的。使用此功能,可以将被视为私有的数据配置为仅与授权组织共享,而公共数据可以与通道上的所有组织共享,而无需创建单独的通道。此外,此功能还对排序服务保密私人数据,排序服务可能由未经授权查看数据的组织控制。

本文目录:

  • 私有数据集合概述
  • 私有数据集合的底层机制
  • 具有私有数据的交易调用工作流
  • 私人数据清除
  • 总结

私有数据集合概述

图 1. 为私有数据集合使用启用的节点账本

启用私有数据集合使用的 Fabric 节点的底层账本可以在图 1 中描述。 通常,启用私有数据集合的 节点账本包括以下两个基本部分。

第一部分是公共数据部分,用于存储特定通道的所有公共数据和交易。公共数据部分由两个实体组成,包括公共区块存储和公共状态数据库,如图 1 上半部分所示。

具体来说,公共区块存储(Public Block Storage)是一个区块链,它保存在通道上实例化的每个链码的所有公共交易的历史记录。公共状态数据库(Public State Database)是一个世界状态(World State)存储,它维护特定链码的公共变量的当前状态。对于任何特定通道,即公共数据部分仅包含单个公共块存储实例(Public Block Storage instance),但该部分可以包含基于在通道上实例化的多个链码的多个公共状态数据库实例(Public State Database instances)

第二部分是私有数据部分,它存储特定通道的所有私有数据和交易。私有数据部分由三个实体组成,包括私有写入集存储(Private Writeset Storage)、私有状态数据库(Private State Database)和瞬态存储数据库(Transient Store Database),如图 1 下半部分所示。

私有写入集存储(Private Writeset Storage)收集特定私有数据集合的所有私有交易的历史记录。每个节点的账本可以包含多个 私有写入集存储(Private Writeset Storage)实例,具体取决于为该特定节点配置的私有集合的数量。其实这种存储不是区块链,而是一种典型的日志持久化数据库。

私有状态数据库(Private State Database)是一个世界状态(World State)存储,它保存特定私有集合的私有变量的当前状态。与私有写入集存储的情况一样,多个私有状态数据库实例(Private State Database instances)可以由节点的账本维护,依赖于为该特定节点配置的许多私有集合。

私有数据部分中的最后一个实体是瞬态存储数据库(Transient Store Database)。这种存储用作临时数据库,用于在交易调用过程中临时存储私有数据。稍后将解释有关瞬态存储数据库的更多详细信息。

图 2. 维护多个私有数据集合的节点

任何单个链码都可以引用多个私有数据集合。图 2 说明了来自不同组织的三个节点,它们引用了同一通道上的两个私有数据集合。如您所见,所有三个节点都维护了私有集合编号#1的私有状态数据库实例。同时,私有集合编号#2的私有状态数据库实例仅由 Org1 节点 和 Org2 节点私有管理。

有趣的是,公共状态数据库(Public State Database)通常存储特定链码的公共变量的当前状态。无论如何,该数据库还存储与该特定链码关联的修改后的私有数据集的哈希值。换句话说,私有数据的哈希将被背书、排序并提交到通道上每个节点的账本中,与公共数据相同。在将私有数据更新到每个授权节点的账本之前,哈希值用于状态验证。哈希值还可以作为交易的证据用于审计目的。稍后将对此进行更多讨论。

即使私人数据的哈希将公开存储在通道上,经过授权的节点才可以将哈希反转为原始内容。

私有数据集合定义示例:

[
{
name: "PDC-1",
policy: "OR('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')",
requiredPeerCount: 1,
maxPeerCount: 3,
blockToLive: 0,
memberOnlyRead: true
},
{
name: "PDC-2",
policy: "OR('Org1MSP.member', 'Org2MSP.member')",
requiredPeerCount: 1,
maxPeerCount: 3,
blockToLive: 0,
memberOnlyRead: true
}
]

图 2 中的私有数据集合可以转换为配置文件,如上面的代码片段。 本文不会进入配置细节,但是,只是让您了解如何配置私有数据集合。 如果您需要了解更多信息,请参阅此链接

让我们关注名为 policy 的集合属性。 此属性定义允许哪些组织的节点保留收集数据。 换句话说,任何私有数据集合都将根据此策略属性存储在授权节点上。 此外,为了使私有集合彼此保密,每个节点将在单独的私有状态数据库实例以及单独的私有写入集存储实例上存储不同的集合


私有数据收集的底层机制

本节讨论有关私有数据集合的底层机制的更多详细信息。

图 3. 使用私有数据进行交易调用的背书阶段

带有私有数据的交易调用的背书阶段可以根据图 3 进行描述。与普通的交易提议一样,带有私有数据的交易提案将在客户端生成(图 3 中的步骤 1)。然而,交易提议的有效载荷将由两部分组成,包括函数参数(Function Arguments)瞬态数据(Transient Data)

函数参数(Function Arguments)包含公共链码函数参数,就像普通交易提议所做的那样。而瞬态数据(Transient Data)包含私有数据参数,这些参数既不会被交易并存储到公共区块存储(Public Block Storage)公共状态数据库(Public State Database)中。换句话说,只有经过授权的节点才可以访问私有数据。

然后将生成的交易提议提交给选定的背书节点(Endorsing Peers),以模拟背书(图 3 中的步骤 2)。在交易模拟过程之后,包含实际私有模拟数据的称为私有读写集(private read-write set)的模拟结果的某一部分将被临时存储到每个背书节点(Endorsing Peers)账本内的瞬态存储数据库(Transient Store Database)中(图 3 中的步骤 3)。

每个背书节点依次尝试通过八卦数据传播协议(gossip data dissemination protocol)将生成的私有读写集(private read-write set)传播到授权组织中的至少 n 个其他集合成员节点(图 3 中的步骤 4),其中 n 是在背书时要求将私有数据(Private Data)分发给的最小成员节点数(值 n 由私有数据集合定义中指定的属性 requiredPeerCount 控制)。

上述步骤被认为对于数据冗余目的很重要。如果背书节点在交易提交期间变得不可用,则作为集合成员但在背书时尚未收到私有读写集(private read-write set)的其他节点将能够从私有数据(private data)被传播到的节点中提取该私有数据(private data)

当且仅当它可以成功地将私有读写集分发给至少 n 个其他集合成员节点时,背书节点(Endorsing Peer)才会背书提案响应。接下来,背书的提议响应被发送回客户端(图 3 中的步骤 5)。背书的提议响应将包含两部分信息,即公共读写集私有读写集的哈希。

公共读写集(Public read-write set)包含与调用的交易相关的公共变量的更改列表。私有读写集的哈希(Hash of private read-write set )是之前存储在瞬态存储数据库(Transient Store Database)中的私有变量的修改列表的哈希值(图3中的步骤3)。在将私有数据更新到每个授权节点的账本之前,私有读写集的哈希值(hash of private read-write set)将用于状态验证。提议响应的这两部分将被排序、验证并提交给公共块存储(Public Block Storage)公共状态数据库(Public State Database)

图 4. 使用私有数据的交易调用的排序和验证承诺阶段

可以根据图 4 描述使用私有数据的交易调用的排序和验证承诺阶段。 在交易提议被背书节点(Endorsing Peers)背书后,客户端(Client)生成与背书提议响应集捆绑在一起的交易,然后将该交易发送到排序节点(Orderer)(图 4 中的步骤 1)。

接下来,排序节点(Orderer) 对收到的交易(包括其他交易)进行排序,生成一个新的有序交易区块,并将生成的区块分发给通道上的所有节点(图 4 中的步骤 2)。

然后,每个节点将接收到的区块中的每一笔交易一一处理。也就是说,每个节点根据其本地公共状态数据库(Public State Database)验证交易的公共读取集,并将事务的公共写入集提交到其本地公共块存储(Public Block Storage)以及更新公共状态数据库(Public State Database)(图 4 中的步骤 3)。

接下来,每个节点检测正在处理的交易包含私有读写集的哈希(hash of private read-write set)。如果任何节点发现它是有权查看该确切的私有数据集合的成员,则该节点将使用哈希值来验证存储在其瞬态存储数据库(Transient Store Database)中的确切的私有读写集(exact private read-write set)是否存在。

如果瞬态存储数据库(Transient Store Database)中存在确切的私有读写集,则节点将根据其私有状态数据库(Private State Database验证私有读取集(private readset),并将私有写入集(private writeset提交到其私有写入集存储(Private Writeset Storage)以及更新私有状态数据库(Private State Database)。最后,节点从瞬态存储数据库(Transient Store Database) 中删除私有读写集(private read-write set)(图 4 中的步骤 4)。

如果有任何节点是确切私有数据集合的成员,但在背书时缺少确切的私有读写集(exact private read-writeset),则该节点将通过以下方式向其他成员节点发送缺少的私有读写集的拉取请求八卦数据传播协议(gossip data dissemination protocol(图 4 中的步骤 5)。请求的私有读写集将通过八卦协议传输到请求的节点,并临时存储到其瞬态存储数据库中(图 4 中的步骤 6)。

稍后,有问题的节点将使用相应的哈希验证接收到的私有读写集。如果验证成功,节点会根据其私有状态数据库验证接收到的私有读取集,并将私有写入集提交到其私有写入集存储中。 节点还更新私有状态数据库并最终从瞬态存储数据库中删除私有读写集(图 4 中的步骤 7)。


具有私有数据的交易调用工作流

图 5. 带有私有数据的交易的调用工作流

图 5 简要总结了使用私有数据调用 Fabric 交易的工作流程:

  1. 客户端(Client)提出一个包含函数参数和瞬态数据的交易提议,用用户的证书签署提议,并将交易提议发送到特定通道上的一组预先确定的背书节点(Endorsing Peers)。
  2. 每个背书节点从提议的有效负载中验证用户的身份和授权。如果验证检查通过,背书节点将模拟交易。来自模拟结果的私有读写集存储在节点账本内的瞬态存储数据库(Transient Store Database )中。
  3. 每个背书节点通过八卦协议(gossip protocol)将私有读写集传播给其他授权节点以用于数据冗余目的。
  4. 一旦私有数据传播成功的数量达到私有数据集合定义中指定的最小所需计数,背书节点会生成包含私有读写集哈希的提议响应。然后,背书节点使用其证书对生成的响应进行背书,最后将生成的响应发送回客户端。
  5. 客户端积聚并检查来自背书节点的已背书提议响应。然后,客户端将附有背书提议响应的交易提交给 排序节点(Orderer)。
  6. 排序节点(Orderer) 对接收到的交易进行排序,生成一个新的有序交易区块,并用其证书对生成的区块进行签名。
  7. 排序节点(Orderer) 将生成的区块广播给相关通道上的所有节点。每个节点根据调用的链码的背书策略验证收到的区块中每个交易的背书,然后根据其公共状态数据库验证每个交易的公共读取集。如果验证检查成功,则每个交易的公共写集都会更新到每个节点的公共状态数据库中。接收到的区块也会附加到每个节点的公共块存储中。随后,每个授权节点对照私有读写集的哈希验证临时存储在其瞬态存储数据库(如果存在)中的私有读写集。 节点还根据其私有状态数据库验证私有读集。如果所有验证过程都成功,则私有写入集将更新到节点的私有状态数据库中。私有写入集也提交到节点的私有写入集存储中。最后,节点从其瞬态存储数据库中删除私有读写集。
  8. 如果在背书期间有任何授权节点缺少私有读写集(missing private read-write set),该节点将通过八卦协议向其他授权节点(other authorized Peers)发送缺少私有读写集的拉取请求。
  9. 丢失的私有读写集将通过八卦协议从被请求的节点传输到发起请求的节点。因此,接收到的私有读写集将在提交到节点的私有状态数据库和私有写入集存储之前得到验证和校验(类似于步骤 7 中发生的情况)。
  10. 客户端从 EventHub 服务接收任何订阅的事件。

私有数据清除

私有数据可以定期从节点中清除。 在私有数据集合定义中,有一个名为 blockToLive 的集合属性,它指示私有数据应该在私有数据库上存活多长时间。 假设我们将 blockToLive 设置为 50,000。 如果50,000个区块的数据没有被修改,私有数据将自动从私有数据库中清除。 如果 blockToLive 设置为 0,私有数据将无限期地保存在私有数据库中。 也就是说,私有数据永远不会被清除。 有关更多信息,请参阅私有数据的架构参考

即使私有数据可能从私有数据库中永久删除,与删除的私有数据对应的所有哈希也无法删除,因为它们被提交到公共块存储,这是一个区块链。 因此,即使原始私有数据已经消失,哈希值也可以用作审计目的的交易证据。


总结

在本文中,您学习了私有数据集合,这是 Hyperledger Fabric 的关键特性之一。 希望您了解 Hyperledger Fabric 如何更好地工作,如果您愿意,请随时留下您的宝贵意见或建议。 谢谢阅读 。

在下一篇文章(本系列的最后一篇文章)中,您将了解 Hyperledger Fabric 中的网络流量处理、服务发现和运营服务。