返回

Hyperledger Fabric文档v2.2(三)

关键概念

关键概念⭐

介绍

Hyperledger Fabric 是分布式账本解决方案的平台,采用模块化架构,提供高安全性弹性灵活性可扩展性。它被设计为支持以可插拔方式实现不同组件,并适应复杂的经济生态系统。

什么是区块链

一个分布式账本

区块链网络的核心是一个分布式账本,记录网络上发生的所有交易。

区块链账本通常被描述为 去中心化的 ,因为它会被复制到许多网络参与者中,每个参与者都在 协作 维护账本。

除了”去中心化”和”协作”之外,信息仅能以追加的方式记录到区块链上,并使用加密技术保证一旦将交易添加到账本就无法修改。这种“不可修改”的属性简化了信息的溯源,因为参与者可以确定信息在记录后没有改变过。这就是为什么区块链有时被描述为 证明系统

智能合约

为了支持以同样的方式更新信息,并实现一整套账本功能(交易,查询等),区块链使用 智能合约 来提供对账本的受控访问。

智能合约还可以被编写成自动执行参与者的特定交易的合约。例如,可以编写智能合约以规定物品的运费,运费根据物品送达的速度变化而变化。交易双方同意并把该条款写入账本后,当物品送达时,相应的资金就会自动转账。

共识

保持账本在整个网络中同步的过程称为 共识 。该过程确保所有账本仅在交易被相应参与者批准时更新,并且当账本更新时,所有账本都以相同的顺序更新相同的交易。

目前,将区块链视为共享的并具有多份副本的交易系统就足够了,该系统通过智能合约进行更新,并通过称为共识的协作流程来保持一致。

什么是Hyperledger Fabric

Linux 基金会于2015年创建了 Hyperledger(超级账本)项目,以推进跨行业的区块链技术。它不是用来宣布一个区块链标准的,而是鼓励通过社区流程开发区块链技术的协作方法,其中包括鼓励开放式开发、和随着时间的推移采用关键标准的知识产权。

Hyperledger Fabric 是 Hyperledger 中的区块链项目之一。与其他区块链技术一样,它有一个账本,使用智能合约,是一个参与者管理交易的系统。

Hyperledger Fabric 与其他区块链系统不同的地方是 私有许可 。与允许未知身份参与网络的开放式非许可系统(需要诸如“工作量证明”之类的协议来验证交易并保护网络)不同,Hyperledger Fabric 网络的成员需要从可信赖的 成员服务提供者(MSP) 注册。

Hyperledger Fabric 还提供多种可插拔选项。账本数据可以以多种格式存储,共识机制可以交换替换,并且支持不同的MSP。

Hyperledger Fabric 还提供创建 通道 的功能,允许一组参与者创建各自的交易账本。对于某些网络而言,这是一个特别重要的选择。这些网络中,一些参与者可能是竞争对手,并且不希望他们做出的每笔交易都被每个参与者知晓,例如,他们只向某些参与者提供的特殊价格,而其他人不是。如果两个参与者组成一个通道,那么只有这两个参与者拥有该通道的账本副本,而其他参与者没有。

共享账本

Hyperledger Fabric 有一个账本子系统,包括两个组件: 世界状态交易日志 。每个参与者都拥有他们所属的每个 Hyperledger Fabric 网络的账本副本。

世界状态组件描述了在给定时间点的账本的状态。它是账本的数据库。交易日志组件记录产生世界状态中当前值的所有交易;这是世界状态的更新历史。然后,账本包括世界状态数据库和交易日志历史记录。

账本中世界状态的数据存储是可替换的。默认情况下,这是 LevelDB 键值存储数据库。交易日志不需要是可插拔的。它只记录区块链网络使用账本数据库前后的值。

智能合约

Hyperledger Fabric 智能合约用 链码 编写,当该应用程序需要与账本交互时,由区块链外部的应用程序调用。在大多数情况下,链码只与账本的数据库、世界状态(例如,查询)交互,而不与交易日志交互。

链码可以用几种编程语言实现。目前支持 Go、Node.js 和 Java 链码。

隐私

根据网络的需求,企业对企业(B2B)网络中的参与者可能对他们共享的信息量非常敏感。对于其他网络,隐私不是最受关注的问题。

Hyperledger Fabric 支持私有网络(使用通道)是很重要的,因为网络是相对开放的

共识

共识意思是:交易必须按照发生的顺序写入账本,即使它们可能位于网络中不同的参与者集合之中。为此,必须建立交易的顺序,且必须采用一种方法来拒绝错误(或恶意)插入到账本中的非法交易。

这是一个彻底的计算机科学研究领域,且有很多方法可以实现它,每个方法都有不同的权衡。例如,PBFT(实用拜占庭容错算法)可以为文件副本提供一种机制,使其能够保持各个副本的一致性,即使在发生损坏的情况下也是如此。或者,在比特币中,通过称为挖矿的过程进行排序,其中竞争计算机竞相解决加密难题,该难题定义所有过程随后构建的顺序。

Hyperledger Fabric 被设计为允许网络启动者选择最能代表参与者间存在的关系的共识机制。与隐私一样,有一系列需求;从那些他们关系中的高度结构化的网络,到更加点对点的网络。

Hyperledger Fabric模型

  • 资产 — 资产是可以通过网络交换的具有价值的东西,从食品到古董车到货币期货。
  • 链码 — 链码执行与交易排序分离,限制了跨节点类型所需的信任和验证级别,并优化了网络可扩展性和性能。
  • 账本特性 — 不可变的共享账本为每个通道编码整个交易历史记录,并包括类似 SQL 的查询功能,以便高效审计和解决争议。
  • 隐私 — 通道和私有数据集合实现了隐私且机密的多边交易,这些交易通常是在共同网络上交换资产的竞争企业和受监管行业所要求的。
  • 安全和成员服务 — 许可成员资格提供可信的区块链网络,参与者知道所有交易都可以由授权的监管机构和审计员检测和跟踪。
  • 共识 — 达成共识的独特方法可实现企业所需的灵活性和可扩展性。

资产

资产的范围可以从有形(房地产和硬件)到无形资产(合同和知识产权)。Hyperledger Fabric 提供使用链码交易来修改资产的功能。

资产在 Hyperledger Fabric 中表示为键值对的集合,状态更改记录为 Channel 账本上的交易。资产可以用二进制或 JSON 格式表示。

链码

链码是定义单项或多项资产的软件,和能修改资产的交易指令;换句话说,它是业务逻辑。链码强制执行读取或更改键值对其他状态数据库信息的规则。链码函数针对账本的当前状态数据库执行,并通过交易提案启动。链码执行会产生一组用于写入的键值对(写集),可以被提交到网络并应用于所有节点的账本。

账本特性

账本是 Fabirc 中所有状态转换的有序的防篡改的记录。状态转换是参与方提交的链码调用(“交易”)的结果。每个交易都会生成一组资产键值对,这些键值对以创建、更新或删除形式提交到账本。

账本由区块链(“链”)组成,用于以区块的形式存储不可变的顺序记录,以及用于维护当前 Fabirc 状态的状态数据库。每个通道有一个账本,每个节点为其所属的每个通道维护一个账本的副本

Fabric 账本的一些特点:

  • 使用基于键的查找、范围查询和组合键查询来查询和更新账本
  • 使用富查询语言进行只读查询(如果使用 CouchDB 作为状态数据库)
  • 只读历史记录查询(查询一个键的账本历史记录)用于支持数据溯源场景
  • 交易包括链码读取键/值(读集)的版本以及链码写入键/值(写集)的版本
  • 交易包含每个背书节点的签名,并被提交给排序服务
  • 交易按顺序打包到区块,并被排序服务“分发”到通道上的节点
  • 节点根据背书策略验证交易并执行策略
  • 在附加一个区块之前,会执行一次版本检查,以确保被读取的资产的状态自链码执行以来未发生更改
  • 一旦交易被验证并提交,就具有不变性
  • 一个通道的账本包含一个配置区块,用于定义策略、访问控制列表和其他相关信息
  • 通道包含 Membership Service Provider 的实例,允许从不同的证书颁发机构(CA)生成加密材料

查看 账本 主题来更深地了解数据库、存储结构和 “查询能力”。

隐私

Hyperledger Fabric 在每个通道上使用不可变的账本,以及可操纵和修改资产当前状态(即更新键值对)的链码。账本存在于通道范围内,它可以在整个网络中共享(假设每个参与者都在同一个公共通道上),也可以被私有化,仅包括一组特定的参与者。

在后一种情况下,这些参与者将创建一个单独的通道,从而隔离他们的交易和账本。为了想在完全透明和隐私之间获得平衡的场景,可以仅在需要访问资产状态以执行读取和写入的节点上安装链码(换句话说,如果未在节点上安装链码,它将无法与账本正确连接)。

当该通道上的组织子集需要对其交易数据保密时,私有数据集合用于将此数据隔离在私有数据库中,在逻辑上与通道账本分开,只有经授权的组织子集才能访问。

因此,通道在更广泛的网络上保持交易的私密性,而集合则在通道上的组织子集之间保持数据的私密性

为了进一步模糊数据,在将交易发送到排序服务并将区块附加到账本之前,可以使用诸如 AES 之类的通用加密算法对链码内的值进行加密(部分或全部)。一旦加密数据被写入账本,它就只能由拥有用于生成密文的相应密钥的用户解密。

有关如何在区块链网络上实现隐私的更多详细信息,请参阅 私有数据 主题。

安全和成员服务

Hyperledger Fabric 支持一个交易网络,在这个网络中,所有参与者都拥有已知的身份。公钥基础设施用于生成与组织、网络组件以及终端用户或客户端应用程序相关联的加密证书。因此,可以在更广泛的网络和通道级别上操纵和管理数据访问控制。Hyperledger Fabric 的这种“许可”概念,加上通道的存在和功能,有助于解决隐私和机密性要求较高的场景。

请参阅 成员服务提供者 (MSP) 主题,以更好地了解加密实现,以及 Hyperledger Fabric 中使用的签名、验证、身份认证方法。

共识

最近,在分布式账本技术中,共识已成为单个函数内特定算法的同义词。然而,共识不仅包括简单地就交易顺序达成一致,Hyperledger Fabric 通过其在整个交易流程中的基本角色,从提案和背书到排序、验证和提交,突出了这种区别。简而言之,共识被定义为组成区块的一组交易的正确性的闭环验证

当区块中交易的顺序和结果满足明确的策略标准检查时,最终会达成共识。这些制衡措施是在交易的生命周期内进行的,包括使用背书策略来规定哪些特定成员必须背书某个交易类别,以及使用系统链码来确保这些策略得到执行和维护。在提交之前,节点将使用这些系统链码来确保存在足够的背书,并且它们来自适当的实体。此外,在将包含交易的任何区块附加到账本之前,将进行版本检查,以确保在此期间,账本的当前状态是能与交易中的信息达成共识的。该最终检查可防止双重花费操作和可能危及数据完整性的其他威胁,并允许针对非静态变量执行功能。

除了众多的背书、验证和版本检查外,交易流的各个方向上还会发生持续的身份验证。访问控制列表是在网络的分层上实现的(排序服务到通道),并且当一个交易提议通过不同的架构组件时,有效负载会被反复签名、验证和认证。总而言之,共识并不仅仅局限于一批交易的商定顺序;相反,它的首要特征是交易从提案到提交的过程中不断进行核查而附带实现的

查看 交易流程 以获得共识的直观表示。

区块链网络⭐⭐

这个话题会在概念层面上描述 Hyperledger Fabric 是如何让组织间以区块链网络的形式进行合作的。可以通过这个话题来理解在 Hyperledger Fabric 区块链网络中的主要结构和处理组件。这个话题会使用一个可管理的工作的例子来介绍在一个区块链网络中的主要组件。

什么是区块链网络

区块链网络是一个为应用程序提供账本及智能合约(chaincode)服务技术的基础设施。首先,智能合约被用来生成交易,接下来这些交易会被分发给网络中的每个节点,这些交易会被记录在他们的账本副本上并且是不可篡改的。这个应用程序的使用者可能是使用客户端应用的终端用户,也可能是一个区块链网络的管理员。

在大多数情况下,多个 组织 会聚集到一起作为一个 联盟 来形成一个网络,并且他们的权限是由一套在网络最初配置的时候联盟成员都同意的规则来决定的。并且,网络的规则可以在联盟中的组织同意的情况下随时地被改变。

示例网络

在我们开始前,先展示一下我们最终要做的东西吧!这是我们示例网络的 最终状态

四个组织 R1、R2、R3 和 R4,他们共同决定,并且达成了一个协议,他们将会设置并开发一个 Hyperledger Fabric 网络。R4 被分配作为网络的初始者,它有权设置网络的初始版本。R4 不会在网络中去进行任何的业务交易。R1 和 R2 在整个网络中有进行私有通信的需求,R2 和 R3 也是。组织 R1 有一个客户端的应用能够在通道 C1 中进行业务的交易。组织 R2 有一个客户端应用可以在通道 C1 和 C2 中进行类似的工作。组织 R3 可以在通道 C2 中做这样的工作。节点 P1 维护了 C1 的账本 L1 的副本。节点 P2 维护了 C1 的账本 L1 和 C2 的账本 L2 的副本。节点 P3 维护了 C2 的账本 L2 的副本。这个网络是根据在网络配置 NC4 中指定的规则来进行管理的,整个网络由组织 R1 和 R4 管理。通道 C1 是根据在通道配置 CC1 中指定的规则来管理的,这个通道由组织 R1 和 R2 管理。通道 C2 是根据在 通道配置 CC2 中指定的规则来管理的,这个通道由组织 R2 和 R3 管理。这有一个排序服务 O4 作为这个网络 N 的一个网络管理员节点,并且使用系统通道。排序服务同时也支持应用通道 C1 和 C2,来对交易进行排序、加入区块然后分发。每个组织都有一个首选的 CA。

创建网络

让我们从头开始来创建网络的基础:

当一个排序服务启动后就形成了这样的一个网络。在我们的示例网络 N 中,排序服务 O4 由一个单独的节点组成,是根据一个网络配置 NC4 来进行配置的。在网络层面上,证书颁发机构 CA4 被用来向管理员和组织 R4 的网络节点分配身份信息。

我们能够看到,在定义 网络 N 的时候,第一件事情就是定义一个 排序服务, O4。对于一个网络在最初就考虑以管理员节点的形式定义这个排序服务是非常有帮助的。就像在之前同意的,O4 最初被配置且由组织 R4 的一个管理员来启动,并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初在网络中集合仅赋予了 R4 这个权利。这个在将来会变化,我们稍后会看到,但是目前 R4 是这个网络中唯一的一个成员。

证书颁发机构(Certificate Authorities,CA)

你也能够看到一个证书颁发机构,CA4,它会被用来给管理者和网络节点颁发证书。CA4 在我们的网络中扮演着重要的角色,因为它会分配 X.509 证书,这个证书能够用来识别属于组织 R4 的组件。由 CA 颁发的证书也可以用来为交易提供签名,来表明一个组织对交易的结果进行背书,背书是一笔交易可以被接受并记录到账本上的前提条件。让我们对有关 CA 的两个方面更详细的介绍一下。

首先,在区块链网络中的不同组件之间,彼此是使用证书来标识自己是来自于特定组织的。这就是为什么通常会有多个 CA 来支持一个区块链网络,因为不同的组织通常会使用不同的 CA。在我们的网络中,我们会使用 4 个 CA,每个组织会有一个 CA。事实上,CA 是非常重要的,所以 Hyperledger Fabric 提供给你一个内置的 CA(被称为 Fabric-CA)以方便使用,尽管在实际当中,组织会选择使用它们自己的 CA。

将证书同成员组织进行匹配是通过一个称为成员服务提供者Membership Service Provider, MSP)的结构来实现的。网络配置 NC4 使用一个已命名的 MSP 来识别由 CA4 颁发的证书的属性,这些证书会关联到组织 R4 下的证书持有者。NC4 接下来会使用在策略中的这个 MSP 名字来分配在网络资源上的特殊权利。这个策略的一个例子就是,在 R4 中识别管理员,这个管理员可以向网络中添加新的成员组织。我们没有在图中显示 MSP,因为他们会很杂乱,但是他们是非常重要的。

第二点,接下来我们会看到由 CA 签发的证书是如何在交易的生成和验证的流程中处于核心位置的。特别的,X.509 证书被用于客户端应用的交易提案和智能合约的交易响应,来对交易进行数字签名。接下来持有账本副本的网络节点在接受将交易更新到账本之前会验证交易签名是否有效。

让我们重新整理一下我们的区块链网络示例的基本结构:有一个网络 N,有一些用户能够访问这个网络,这些用户是由一个证书颁发机构 CA4 定义的,他们具有网络配置 NC4 中包含的规则中所描述的在网络 N 中的权利。当我们配置和启动排序服务节点 O4 的时候上边讲的事情都会发生。

添加网络管理员

NC4 最初被配置为仅仅允许 R4 用户在网络中具有管理的权限。在接下来的阶段,我们会允许组织 R1 用户也具有管理的权限。让我们来看看网络是如何演变的:

组织 R4 更新了网络配置来使组织 R1 也成为了管理员。现在 R1 和 R4 在网络配置中便具有了相同的权限。

我们看到了新的组织 R1 变成了管理员,R1 和 R4 现在在网络中具有了相同的权限。我们看到证书颁发机构 CA1 也被添加进来了,他用来标识 R1 组织的用户。现在从 R1 和 R4 来的用户就已经是网络的管理员了。

尽管排序节点 O4 是运行在 R4 的基础设施上的,如果 R1 能够访问到的话就可以共享管理的权限。也就是说 R1 或者 R4 可以更新这个网络配置 NC4 来允许组织 R2 进行网络维护中的部分功能。通过这种方式,尽管 R4 运行着排序服务,但是 R1 在其中也具有着全部的管理员权限,R2 具有有限的创建新联盟的权限

在这个最简单的模式中,排序服务在网络中是一个独立的节点,就像你在例子中看到的。排序服务通常是多节点的,也可以被配置为在不同组织中的不同节点上。比如,我们可能会在 R4 中运行 O4 并连接到 O2,O2 是在组织 R1 中的另一个排序节点。通过这种方式,我们就有了一个多节点、多组织的管理结构。

我们会在后边讨论更多关于排序服务的话题,但是目前只需要把排序服务当成是一个管理者,它给不同的组织提供了对于网络的管理的权限。

定义联盟

尽管这个网络当前可以被 R1 和 R4 管理,但是只有这些还是太少了。我们需要做的第一件事就是定义一个联盟。这个词表示“具有着共同命运的一个群组”,也就是在一个区块链网络中合理地选择出来的一些组织

让我们来看看如何定义一个联盟:

网络管理员定义了一个包含两个成员的联盟 X1,包含组织 R1 和 R2。这个联盟的定义被存储在了网络配置 NC4 中,会在接下来的网络开发中被使用。CA1 和 CA2 是这两个组织对应的证书颁发机构。

由于 NC4 的配置方式,只有 R1 和 R4 能够创建新的联盟。这个图显示了一个新的联盟 X1,它定义了 R1 和 R2 是它的联盟组织。我们也看到了 CA2 也被添加进来标识来自 R2 的用户。注意一个联盟可以包含任意数量的组织,这里我们仅包含了两个组织作为一个最简单的配置。

为什么联盟这么重要?我们能够看到联盟定义了网络中的一部分组织,他们共享了彼此能够交易的需求,在这个示例中就是 R1 和 R2 能够进行交易。这对于一组有着共同的目标的组织来说是有意义的。

这个网络虽然最初仅包含一个组织,现在已经由多个组织来管理了。我们将从 R1、R2 和 R4 共享管控权的方式开始,这样的构成更容易被理解。

现在我们要使用联盟 X1 创建一个对于 Hyperledger Fabric 区块链非常重要的部分——通道

为联盟创建通道

现在让我们来创建 Fabric 区块链网络的关键部分——通道。通道是一个联盟中的成员彼此进行通信的主要机制。在一个网络中可能会有多个通道,但是现在让我们从一个通道开始。

让我们来看第一个通道是如何被添加到这个网络中的:

使用联盟 X1 为 R1 和 R2 创建的的通道 C1。这个通道通过通道配置 CC1 来进行管理,完全独立于网络配置NC4。CC1 是由 R1 和 R2 管理的,他们在 C1 上具有同等的权利。R4 在 CC1 中是没有任何权利的

通道 C1 为联盟 X1 提供了一个私有的通信机制。我们能够看到通道 C1 已经关联到了排序服务 O4 但是这并没有附带任何功能。在网络开发的下一个阶段,我们将会连接不同的组件,比如客户端应用Peer 节点。但是到目前为止,一个通道就代表了将来要进行连接的可能性

尽管 C1 是网络 N 中的一部分,它还是跟这个网络非常不同的。同时也要注意到组织 R3 和 R4 并没有在这个通道中,因为这个通道仅仅是为了处理在 R1 和 R2 之间进行的交易的。在上一步中,我们看到了 R4 是如何能够为 R1 分配权限来创建新的联盟。R4 同样允许 R1 来创建通道。在这个图中,组织 R1 和 R4 创建了通道 C1。再次强调,一个通道可以包含任意数量的组织,但是我们目前只包含了两个组织,这是一个最简单的配置。

需要注意的是通道 C1 如何具有一个同网络配置 NC4 完全分开的配置 CC1。CC1 包含了赋予 R1 和 R2 在通道 C1 上的权利的规则,就像我们看到的那样,R3 和 R4 在这个通道中没有权限。R3 和 R4 只有被 R1 或 R2 添加到通道配置 CC1 中的规则后才能够跟 C1 进行交互。这样做的一个例子是定义谁能够向通道中添加新的组织。特别要注意的是 R4 是不能够将它自己添加到通道 C1 中的,这个只能由 R1 或者 R2 来授权添加。

为什么通道会如此重要?通道非常有用,因为提供了一个联盟成员之间进行私有通信和私有数据的机制。通道提供了与其他通道以及整个网络的隐私性。Hyperledger Fabric 在这一点上是很强悍的,因为它允许组织间共享基础设施的同时又保持了私有性。这里并不矛盾,网络中不同的联盟之间会需要将不同的信息和流程进行适合的共享,通道为之提供了有效的机制。通道提供了一个有效的基础设施共享,同时保持了数据和通信的隐私性

我们也能够看到一旦通道被创建之后,它会真正地代表了“从网络中解放出来”。从现在开始和未来,只有在通道配置中指定的组织才能够控制它。同样的,从现在开始,之后的对于网络配置 NC4 的任何改动都不会对通道配置 CC1 造成任何直接的影响。比如如果联盟定义 X1 被改动了,它不会影响通道 C1 的成员。所以通道是有用的,因为他们允许构成通道的组织间进行私有的沟通。并且在通道中的数据跟网络中的其他部分是完全隔离的,包括其他的通道

同时,这里还有一个被排序服务使用的特殊的系统通道。它跟常规的通道是完全一样的方式运行的,因此常规的通道有时候又被称为应用通道。我们通常不会关心这个通道,但是以后我们会更详细的讨论它。

节点和账本

现在,让我们开始使用通道来将这个区块链网络以及组织的组件关联到一起吧。在网络开发的下一个阶段,我们能够看到我们的网络 N 又新增了两个组件,称作 Peer 节点 P1 和账本实例 L1。

一个 Peer 节点 P1 加入了通道 C1。物理上 P1 会存储账本 L1 的副本。P1 和 O4 可以使用通道 C1 来进行通信。

Peer 节点是存储区块链账本副本的网络组件。至少,我们已经开始看到了一些区块链标志性的组件了!P1 在这个网络中的目的是单纯地放置被其他人访问的账本 L1 的副本。我们可以想象 L1 会被物理地存储在 P1 上,但是 逻辑上 是存储在通道 C1 上。当我们向通道中添加更多的节点之后,我们对这些就会更加清楚。

P1 的配置中一个关键部分就是一个由 CA1 颁发的 X.509 身份信息,它将 P1 和组织 R1 关联了起来。当 P1 启动之后,它就可以使用排序 O4 加入通道C1。当 O4 收到这个加入请求,它会使用通道配置 CC1 来决定 P1 在这个通道中的权限。比如,CC1 决定 P1 是否能够向账本 L1 中读取或写入信息。

注意节点是如何通过所在组织加入到通道的,尽管我们仅仅加了一个节点,我们将会看到如何在网络中将多个节点加入通道。我们也会在后边的部分看到节点能够扮演的不同的角色。

应用程序和智能合约链码

现在通道 C1 拥有了一个账本,我们可以连接客户端应用来使用由 Peer 节点提供的服务了。

注意网络是如何变化的:

智能合约 S5 被安装在了 P1 上。在组织 R1 中的客户端应用 A1 可以通过 Peer 节点 P1 使用 S5 来访问账本L1。A1、P1 和 O4 都加入了通道 C1,他们都可以使用由这个通道提供的通信设施。

在网络开发的下一个阶段,我们可以看到客户端应用 A1 能够使用通道 C1 来连接指定的网络资源,在这个示例中,A1 能够连接 Peer 节点 P1 和排序节点 O4。再次注意,看看通道是如何处在网络和组织的组件的通信中心的。就像 Peer 节点和排序节点一样,客户端应用也会有一个使它和组织相关联的身份信息。在我们的例子中,客户端应用 A1 是跟组织 R1 相关联的,尽管它处在 Fabric 区块链网络的外边,但它是可以通过通道 C1 跟网络相连的。

现在我们能够清楚地看到 A1 能够通过 P1 直接访问账本 L1,但是事实上,所有的访问都是由一个称为智能合约链码 S5 的特殊程序来管理的。将 S5 理解为定义访问账本的常规模式,S5 提供了一套完整的定义来对账本 L1 进行查询及更新。简言之,客户端应用 A1 需要通过智能合约 S5 来获得账本 L1

智能合约可以被每个组织的应用开发者创建来实现一个在联盟成员间共享的业务流程。智能合约被用来帮助生成被分发到网络中每个节点的交易。我们接下来会详细讨论。当网络变得更大了之后,这个会更容易理解。现在,需要理解的重要的事情是,为了达到这一点,需要对智能合约执行两项操作,它必须被安装,然后在通道中被定义

Hyperledger Fabric 用户经常会在内部使用名词智能合约链码。大体上来说,一个智能合约定义了交易逻辑,它控制了在世界状态中包含的一个业务对象的生命周期。然后它会被打包进一个链码中,这个链码会被部署到一个区块链网络中。可以把智能合约想象为管理交易,链码则管理着智能合约应该如何被打包部署

安装链码包

在智能合约 S5 被开发完之后,组织 R1 中的管理员必须要把它安装到节点 P1 上。这是一个很简单的操作。当完成之后,P1 就完全了解了 S5。特别地,P1 能够看到 S5 的实现逻辑(用来访问账本 L1 的程序代码)。我们将这个同 S5 的接口进行对比,接口只是描述了 S5 的输入和输出,但是没有它的实现。

当一个组织在一个通道中有多个 Peer 节点时,可以选择在哪个节点安装智能合约,而不需要每个 Peer 节点上都安装智能合约

定义链码

尽管链码会被安装在组织的 Peer 节点上,但是它是在一个通道范围内被管理和维护的。每个组织需要批准一个链码定义,和一系列参数来定义在一个通道中链码应该被如何使用。一个组织必须要批准一个链码定义,才能使用已经安装的智能合约来查询账本和为交易背书。在我们的例子中,只有一个单独的 Peer 节点 P1,一个组织中的管理员 R1 必须要批准 S5 的链码定义。

在链码定义能够被提交到通道并且用来同通道账本进行互动之前,需要有效数量的组织来批准一个链码的定义(默认为大多数)。因为通道中只有一个成员,R1 的管理员可以提交 S5 的链码定义到通道 C1。当这个定义提交后,S5 就可以被客户端应用 A1 调用了!

注意,虽然在这个通道上的每个组件现在都可以访问 S5,但是他们是不能够看到它的程序逻辑的。这对于安装了这个智能合约的节点还是保持隐私性的,在我们的示例中指的是 P1。从概念上讲,这意味着实际上是定义并提交了智能合约的接口到通道,而不是安装了智能合约的实现。为了强调这个想法,安装智能合约展示了我们是如何将它物理地存储在 Peer 节点上,而实例化智能合约展示了我们是如何将它逻辑地存储在通道中。

背书策略

在链码定义提供的信息中最重要的部分就是背书策略。它描述了在交易被其他的组织接受并存储在他们的账本副本上之前,哪些组织必须要同意此交易。在我们的示例网络中,只有当 R1 和 R2 对交易进行背书之后,交易才能够被接受并存储到账本 L1 中。

将链码定义提交到通道的同时背书策略也会被放置在通道账本上,通道中的每个成员都可以访问该策略。你可以在交易流程话题中阅读更多关于背书策略的内容。

调用智能合约

当智能合约被安装在 Peer 节点并且在通道上定义之后,它就可以被客户端应用调用了。客户端应用是通过发送交易提案给智能合约背书策略所指定的 Peer 节点的方式来调用智能合约的。这个交易的提案会作为智能合约的输入,智能合约会使用它来生成一个背书交易响应,这会由 Peer 节点返回给客户端应用。

这些交易的响应会和交易的提案打包到一起形成一个完整的经过背书的交易,他们会被分发到整个网络。我们会在之后更详细的了解,现在理解应用是如何调用智能合约来生成经过背书的交易就已经足够了。

在网络开发的这个阶段,我们能够看到组织 R1 完整参与了这个网络。它的应用,从 A1 开始,通过智能合约 S5 访问账本 L1,并生成将要被 R1 背书的交易,最后会被接受并添加到账本中,因为这满足了背书策略。

完成网络

我们的目标是为联盟 X1(由组织 R1 和 R2 构成)创建一个通道。网络开发的下一个阶段是将组织 R2 的基础设施添加到网络中。

让我们看一下网络是如何演进的:

这个网络通过增加新组织 R2 的基础设施变得更大了。具体来说,R2 添加了 Peer 节点 P2,它会存有账本 L1 的一个副本,和链码 S5。R2 像 R1 一样批准了相同的链码定义。P2 也加入了通道 C1,也有一个客户端应用 A2。A2 和 P2 使用由 CA2 颁发的证书来标识 A2 和 P2。所有这些都说明了 A1 和 A2 能够使用 Peer 节点 P1 或者 P2 来调用在 C1 上的 S5。

我们能够看到组织 R2 在通道 C1 上添加了 Peer 节点 P2。P2 也存储了账本 L1 和智能合约 S5 的副本。R2 也添加了客户端应用 A2,它能够通过通道 C1 连接到网络。为了达到这个目的,组织 R2 的管理员添加了 Peer 节点 P2 并且将它加入到通道 C1,就像 R1 的管理员一样。管理员也必须要像 R1 那样批准相同的链码定义。

我们创建了第一个可运行的网络!目前,我们定义了一个通道,在这个通道中组织 R1 和 R2 能够彼此进行交易。特别地,这意味着 A1 和 A2 能够使用在通道 C1 上的智能合约 S5 和账本 L1 来生成交易。

生成并接受交易

相较于经常会存有账本副本的 Peer 节点,我们能够看到两种类型的 Peer 节点,一类是存储智能合约而另一类则不存。在我们的网络中,每个 Peer 节点都会存储智能合约的副本,但是在一个更大的网络中,会存在更多的 Peer 节点并且没有存储智能合约的副本。节点只有在安装了智能合约之后才能够运行它,但是这个 Peer 节点可以通过连接到通道来获取一个智能合约的接口信息。

对于没有安装智能合约的 Peer 节点,我们不应该认为他们在某种程度上是较差的。更多情况下,带有智能合约的 Peer 节点通常会拥有一个特殊的能力——帮助生成交易。需要注意的是所有的 Peer 节点都可以验证接受或者拒绝交易存入他们的账本 L1 的副本中。然而,只有安装了智能合约的 Peer 节点才能够参与交易背书的流程,这是生成一笔有效交易的核心。

我们不需要关心交易生成的详细信息、分发和被接受的,只需知道我们有一个区块链网络,在这个网络中组织 R1 和 R2 能够共享由账本记录的交易信息和流程就够了。我们会在其他的部分学习更多关于交易、账本以及智能合约。

Peer 节点的类型

在 Hyperledger Fabric 中,所有的 Peer 节点都是一样的,基于这个网络的配置,Peer 节点能够担当多个角色。我们现在对于描述这些角色的典型网络拓扑已经有足够的理解了。

  • 提交节点。通道中的每个 Peer 节点都是一个提交节点。他们会接收生成的区块,在这些区块被验证之后会以附加的方式提交到 Peer 节点的账本副本中。

  • 背书节点。每个安装了智能合约的 Peer 节点都可以作为一个背书节点。然而,想要成为一个真正的背书节点,节点上的智能合约必须要被客户端应用使用,来生成一个被签名的交易响应。背书节点的术语就是这样来的。

    智能合约的背书策略明确了在交易被接受并且记录到提交节点的账本之前,需要哪些组织的 Peer 节点为交易签名

这是 Peer 节点的两个主要类型,一个 Peer 节点还可以担任的两种其他的角色:

  • 主节点。当组织在通道中具有多个 Peer 节点的时候,会有一个主节点,它负责将交易从排序节点分发到该组织中其他的提交节点。一个节点可以选择参与静态或者动态的领导选举。

    这是很有用的,从管理者的角度来考虑的话会有两套节点,一套是静态选择的主节点,另一套是动态选举的主节点。对于静态选择,0个或者多个节点可以被配置为主节点。对于动态选举,一个节点会被选举成为主节点。另外,在动态选举主节点中,如果一个主节点出错了,那么剩下的节点将会重新选举一个主节点。

    这意味着一个组织的节点可以有一个或者多个主节点连接到排序服务。这有助于改进需要处理大量交易的大型网络的弹性以及可扩展性。

  • 锚节点。如果一个 Peer 节点需要同另一个组织的 Peer 节点通信的话,它可以使用对方组织通道配置中定义的锚节点。一个组织可以拥有0个或者多个锚节点,并且一个锚节点能够帮助跨组织间的通信

需要注意的是,一个 Peer 节点可以同时是一个提交节点、背书节点、主节点和锚节点。在实际情况中只有锚节点是可选的,一般都会有一个主节点,至少一个背书节点和一个提交节点

向通道中添加组织和节点

当 R2 加入到通道的时候,组织必须要向它的 Peer 节点 P2 上安装智能合约 S5。这很明显,如果应用 A1 或者 A2 想要使用 Peer 节点 P2 上的 S5 来生成交易,节点 P2 就必须安装了智能合约 S5。现在,Peer 节点 P2 有了智能合约和账本的物理的副本,像 P1 一样,它可以生成并接受交易到它的账本 L1 的副本上了。

R2 必须要像 R1 那样批准相同的链码定义才能够使用智能合约 S5。因为链码定义已经被组织 R1 提交到了通道,当 R2 的组织批准了链码定义并且安装了链码包之后,R2 就可以使用链码了。提交的交易只需要发生一次。通道中新的组织批准了通道中其他成员已经同意的链码参数之后就可以使用链码了。因为链码定义的批准是发生在组织级别的,所以 R2 只需要批准链码定义一次,然后就可以将多个节点加入到安装了链码包的通道。然而,如果 R2 想改变链码的定义,那么 R1 和 R2 需要为他们的组织批准一个新的定义,然后其中的一个组织需要将定义提交到通道。

在我们的网路中,我们能够看到通道 C1 连接了两个客户端应用、两个 Peer 节点和一个排序服务。因为这里只有一个通道,也就只有一个跟这个通道组件交互的逻辑账本。Peer 节点 P1 和 P2 具有相同的账本 L1 的副本。智能合约 S5 的副本通常会使用相同的编程语言来进行相同的实现,如果语言不同,他们也必须有相同的语义。

我们能够看到,在网络精心的增加节点有助于提升吞吐量、稳定性以及弹性。比如,网络中有更多的节点将允许更多的应用来连接这个网络,并且当组织中有多个节点发生计划内和计划外停机的时候可以提供额外的弹性。

这意味着可以通过配置网络拓扑来支持不同的目的,网络的大小是没有理论上限的。并且,一个组织内节点的发现和通信的技术机制,gossip 协议,可以容纳大量的 Peer 节点来支持这样的拓扑。

网络和通道策略的精心使用可以很好的管理庞大的网络。组织可以随意地向网络中添加 Peer 节点,只要他们满足了网络的策略。网络及通道的策略在描绘去中心化网络中的自主和管控之间创建了平衡。

简化视觉词汇表

我们接下来要为网络中添加更多内容,在我们做这个之前,让我们来一起简化一下视觉词汇表吧。下边是我们目前开发的网络的简图:

这个图表展示了在网络 N 中和通道 C1 的相关内容:客户端应用 A1 和 A2 能够通过节点 P1 和 P2 以及排序节点 O4 使用通道 C1 来进行通信。Peer 节点 P1 和 P2 可以使用通道 C1 的通信服务。排序服务 O4 可以使用通道 C1 的通信服务。通道配置 CC1 应用于通道 C1。

注意,这个网络的图表通过将通道连线替换成了连接点的方式进行了简化,连接点显示为一个蓝色的圆圈,里边包含了通道数字。没有任何的信息丢失。这种展现方式更加的可扩展,因为它去除了交叉的连接线。这个让我们能够更清晰地展现更大的网络。我们通过更加关注组件和通道之间的连接点,而不是通道本身的方式实现了这样的简化。

添加另外一个联盟定义

在网络开发的下一个阶段,我们引入了组织 R3。我们将会给 R2 和 R3 一个新的独立的应用通道,以便他们互相进行交易。这个应用通道会同之前定义的通道完全分离开来,所以 R2 和 R3 的交易信息会对他们保持良好的隐私性。

让我们回到网络级别并且为 R2 和 R3 定义一个新的联盟 X2:

来自 R1 或者 R4 的网络管理员添加了一个新的联盟定义 X2,其中包含了 R2 和 R3。这将会被用来为 X2 定义一个新的通道。

注意到现在网络中已经有两个联盟被定义了:组织 R1 和 R2 的联盟 X1,以及组织 R2 和 R3 的联盟 X2。引入联盟 X2 是为了给 R2 和 R3 创建一个新的通道。

新通道只能够由网络配置策略 NC4 中指定的组织比如 R1 或者 R4 来创建,因为只有他们才有相关的权限。这是一个区分在网络级别通道级别谁能管理资源的策略的例子。在工作中观察这些策略能够帮助我们理解为什么 Hyperledger Fabric 具有一个复杂的层级的策略结构。

实际上,联盟定义 X2 已经被添加进了网络配置 NC4。我们会在文档的其他部分讨论具体的技术细节。

添加一个新的通道

让我们使用这个新的联盟定义 X2 来创建一个新的通道 C2。为了帮助加强你对于简单通道符号的理解,我们会使用两种视觉样式:通道 C1,使用蓝色的圆圈来表示;通道C2,使用红色的连接线表示:

一个使用联盟定义 X2 为 R2 和 R3 的创建的新通道 C2。这个通道具有通道配置 CC2,完全同网络配置 NC4 以及通道配置 CC1 分离。通道 C2 由 R2 和 R3 来管理,他们两个就像 CC2 中的一个策略定义的那样具有相同的权利。R1 和 R4 在 CC2 中是没有任何权利的。

通道 C2 为联盟 X2 提供了一个私有的通信机制。这里,需要注意的是联盟将组织统一到一起的方式就是通道。通道配置 CC2 现在包含了管理通道资源的策略,通过通道C2 来向组织分配管理权限。这由 R2 和 R3 唯一管理,R1 和 R4 在通道 C2 中是没有权力的。比如可以更新通道配置 CC2 来添加新的组织以支持网络的增长,但是这个只能由 R2 或者 R3 来完成。

注意,通道配置 CC1 和 CC2 以及网络配置 NC4 是彼此完全分离的。我们也看到了一个 Hyperledger Fabric 网络的去中心化的特质,一旦通道 C2 被创建后,它是由组织 R2 和 R3 来管理的,独立于网络中的其他元素。通道的策略通常是保持彼此分离的,并且只能由通道中授权的组织来进行改动

随着网络和通道的发展,网络和通道的配置也会升级。这里有一个以可控形式实现的流程——引入包含配置变更的配置交易。每次配置的改变会生成一个新的配置区块,在后边的话题中,我们会看到这些区块是如何被验证和接受,并更新相关网络及通道的配置。

网络和通道配置

在我们的示例网络中,我们看到了网络和通道配置的重要性。这些配置很重要,是因为他们封装了网络成员同意的策略,这提供了对网络资源访问控制的共享参考。网络和通道配置也包含了有关网络和通道组成的一些情况,比如联盟的名字以及它所包含的组织。

比如,当使用排序服务节点 O4 首次组建网络的时候,它的行为是由网络配置 NC4 来管理的。NC4 的初始配置中只包含了允许组织 R4 来管理网络资源的策略。NC4 接下来被变更为也允许 R1 来管理网络资源。一旦这个改动生效后,任何来自于组织 R1 或者 R4 的管理员连接到 O4 都将具有网络管理的权限,因为这是网络配置 NC4 中的策略所允许的。在内部来说,在排序服务中的每个节点都记录着网络配置中的每个通道,所以在网络级别中每个通道被创建时都会有一条记录

这就意味着,尽管排序服务节点 O4 创建了联盟 X1 和 X2 以及通道 C1 和 C2,网络配置 NC4 中包含了 O4 遵守的这个网络的智慧。只要 O4 是一个好的参与者,并且在它处理网络资源的任何时候都能够正确的实现在 NC4 中定义的策略的话,那么我们的网络就会按照所有的组织一致同意的方式工作。在很多方面 NC4 被认为要比 O4 更重要,因为最终是它来管控网络的访问。

与 Peer 节点同样的概念也可以应用到通道配置。在我们的网络中,P1 和 P2 是很类似的角色。当 Peer 节点 P1 和 P2 同客户端应用程序 A1 或者 A2 进行交互的时候,他们使用了在通道配置中定义的策略来管理对通道 C1 资源的访问。

比如,如果 A1 想要访问在 Peer 节点 P1 或者 P2 上的智能合约链码 S5 的话,每个 Peer 节点会使用它的 CC1 的副本来决定 A1 能够进行哪些操作。比如根据在 CC1 中定义的策略,A1 可能被允许从账本 L1 上读取或者写入数据。后边我们会看到在通道和通道配置 CC2 中对操作者相同的模式。我们能够看到尽管 Peer 节点和应用程序在网络中是关键的操作者,他们在一个通道中的行为更多的是由通道配置的策略来决定的。

最后,理解网络和通道配置是如何在物理上来实现的是非常重要的。我们能够看到网络和通道的配置在逻辑上是独立的,网络会有一个配置,每个通道也会有一个配置。这一点非常重要,任何访问网络或者通道的组件必须对不同组织的授权有共同的理解。

尽管在逻辑上是独立的配置,实际上它会被复制到组成网络或者通道的每个节点,并保持一致。比如,在我们的网络中,节点 P1 和 P2 都有通道配置 CC1 的副本,在这个网络完成的时候,节点 P2 和 P3 也会有通道配置 CC2 的副本。类似的,排序服务节点 O4 有网络配置的副本,但是在多节点配置中,每个排序服务节点都会有他们自己的关于网络配置的副本。

网络和通道的配置使用了和用户交易所使用的相同的区块链技术来保持一致,只是被叫做配置的交易。想要改变网络或者通道的配置,管理员必须要提交一个配置交易来改变网络或者通道的配置。该交易必须被对应策略中指定的组织签名,这些组织负责配置的改变。这个策略被称为mod_policy 我们稍后讨论

实际上,排序服务节点运行着一个小型的区块链,通过我们前边提到过的系统通道连接。使用系统通道排序服务节点分发网络配置交易。这些交易被用来维护每个排序服务节点间网络配置副本的一致性。类似的,应用程序通道中的 Peer 节点分发通道配置交易。同样,这些交易被用来维护每个 Peer 节点通道配置的一致性

这种对象在逻辑上独立,却在物理分发上平衡,这在 Hyperledger Fabric 中是一种常见的模式。像网络配置这样的对象,逻辑上是独立的,但在一些排序服务节点间被物理复制。对于通道配置、账本及智能合约,我们也看到了这样的情况,他们被安装在了多个地方,但是在逻辑上他们的接口是在通道级别上的。这种模式你会在 Hyperledger Fabric 中重复地看到多次,这使 Hyperledger Fabric 变得既去中心化,又能够在同一时间进行管理。

添加另外一个Peer节点

现在组织 R3 能够完全地参与到通道 C2 中了,让我们来把它的基础设施组件添加到通道中。我们不会每次只加一个组件,我们将会一次性地将 Peer 节点、它的账本本地副本、智能合约以及客户端应用程序都加进来。

让我们看一下添加了组织 R3 的组件的网络是什么样:

这个图展示了在网络 N 中关于通道 C1 和 C2 的以下内容:客户端应用程序 A1 和 A2 可以使用通道 C1 来同节点 P1 和 P2,以及排序服务 O4 进行通信。客户端应用程序 A3 能够使用 C2 同节点 P3 和排序服务 O4 进行通信。排序服务 O4 可以使用通道 C1 和 C2 的通信服务。通道配置 CC1 应用到了通道 C1 上,CC2 应用到了通道 C2 上。

首先,要注意的是因为 Peer 节点 P3 连接到了通道 C2,所以它有一个和使用通道 C1 的节点不同的账本 L2。账本 L2 被有效地控制在了通道 C2 中。账本 L1 是完全独立的,它被限制在了通道 C1。这么做是有意义的,通道 C2 的目的是为联盟 X2 的成员提供私有通信,并且账本 L2 是他们的交易的私有存储

同样的方式,智能合约 S6 安装在 Peer 节点 P3,定义在通道 C2 上,用来为账本 L2 提供可控的访问。应用程序 A3 现在能够使用通道 C2 来调用智能合约 S6 提供的服务来生成交易,这些交易会在网络中被每个账本的副本所接受。

到目前为止,我们有一个独立的网络,其中定义了两个完全独立的通道。这些通道为组织提供了独立的管理设施来彼此交易。这是在工作中的去中心化,我们在管控和自制之间具有着一个平衡。这是通过应用到通道的策略来实现的,这些通道由不同的组织控制,而通道又会影响这些组织。

把一个Peer节点添加到多个通道

在网络开发的最后一个阶段,让我们把焦点再转回组织 R2。我们可以通过把 R2 加入到多个通道中的方式来让它成为两个联盟 X1 和 X2 的成员。

这个图展示了在网络 N 中关于通道 C1 和 C2 的以下内容:客户端应用程序 A1 能够使用通道 C1 与节点 P1 和 P2 以及排序服务 O4 进行通信。客户端应用程序 A2 可以使用通道 C1 与节点 P1 和 P2 进行通信,以及使用通道 C2 与节点 P2 和 P3 以及排序服务 O4 进行通信。客户端应用程序 A3 能够使用通道 C2 与节点 P3 和 P2 和排序服务 O4 进行通信。排序服务 O4 能够使用通道 C1 和 C2 的通信服务。通道配置 CC1 应用在了通道 C1 中,CC2 应用在了通道 C2 中。

我们能够看到,R2 在网络中是一个特别的组织,因为它是唯一一个同时属于两个通道成员的组织!它能够在通道 C1 上跟组织 R1 进行交易,也能够同时使用另外一个通道 C2 来跟组织 R3 进行交易。

注意,节点 P2 将智能合约 S5 安装在通道 C1 中,将智能合约 S6 安装在通道 C2 中。节点 P2 同时是两个通道的成员,并且通过不同的智能合约来处理不同的账本

通道是一个非常强大的概念,既提供了组织间的分离,又提供了组织间进行合作的机制。总的来说,这个基础设施是由一系列独立的组织来提供的,并且在这些组织间进行共享。

重点需要注意的是,在不同通道上交易时 Peer 节点 P2 的行为受到不同的约束。特别地,在通道配置 CC1 中包含的策略决定了 P2 在通道 C1 中进行交易的时候的操作,这也是通道配置 CC2 中的策略对 P2 在通道 C2 中的控制。

这是值得的,R2 和 R1 同意了通道 C1 的规则,R2 和 R3 同意了通道 C2 的规则。这些规则包含在对应的通道策略中,它们能够且必须要在通道里被用来强制执行正确的操作,就像当初同意的一样。

类似的,我们能够看到客户端应用程序 A2 现在能够在通道 C1 和 C2 上进行交易。同样,它也会按照在相关通道配置中的策略来进行管理。另外,注意客户端应用程序 A2 和 Peer 节点 P2 在使用一个混合的视觉词汇表,既包括线也包括连接点。你能够看到他们是等价的,他们在视觉上是同义词。

排序服务

善于观察的读者可能已经注意到排序服务看起来像是一个中心化的组件,它最初被用来创建这个网络,然后连接到了网络中的每个通道。即使我们添加 R1 和 R4 到了管理排序服务的网络配置策略 NC4,这个排序节点依旧是运行在 R4 的基础设施上。在一个去中心化的世界中,这个看起来是错误的!

不必担心!我们的示例网络显示的是一个最简单的排序服务配置,为了帮助你从网络管理员的角度来理解。事实上,排序服务本身可以是完全去中心化的!我们之前提到过一个排序服务可以包含很多单独的不同组织的节点,让我们看一下在我们的网络中应该怎么做。

让我们看一个更加真实的排序服务节点配置:

一个多组织的排序服务。排序服务包括排序服务节点 O1 和 O4。O1 是由组织 R1 提供的,O4 是由组织 R4 提供的。网络配置 NC4 中定义了来自 R1 和 R4 的操作者的网络资源权限。

我们能够看到这个排序服务是完全去中心化的,它在组织 R1 和 R4 中运行。网络配置策略 NC4 赋予了 R1 和 R4 对于网络资源相同的权限。R1 和 R4 的客户端应用程序和 Peer 节点可以通过连接 O1 或者 O4 来管理网络资源,就像在网络配置 NC4 中定义的策略一样,两个节点是用相同的方式来操作的。在实际中,组织的操作者愿意使用自己组织提供的基础设施,但是显然并不总是这样的。

去中心化的交易分发

跟作为网络的管理点一样,排序服务同样提供了另外一个关键的设施——交易的分发点。排序服务是一个从应用程序搜集背书过的交易的组件,然后它会把这些交易进行排序并放进区块中,这些区块会被分发到通道中的每个 Peer 节点。在每个这样的提交节点中,交易不管是有效的还是无效的都会被记录下来,并且他们本地账本副本也会更新。

注意这里,排序服务节点 O4 在通道 C1 扮演着和网络 N 不同的角色。当在通道级别操作时,O4 的角色是搜集交易并在通道中分发区块。它依据通道配置 CC1 中定义的策略来操作。当在网络级别操作时,O4 的角色是提供对网络资源的管理,这是根据网络配置 NC4 中定义的策略来操作的。我们应该注意这些不同的角色是如何在通道和网络的配置中定义的。这个会加强你对 Hyperledger Fabric 中基于配置的可声明策略的重要性的印象。两种策略都被定义并且用来管控联盟中的每个成员都同意的行为。

我们能够看到排序服务和 Hyperledger Fabric 中的其他组件一样,是一个完全去中心化的组件。不管是作为一个网络的管理点,还是作为一个通道中的分发节点,它的节点都可以依据在一个网络中的多个组织的要求被分散地运行。

修改策略

经过我们对于这个示例网络的解析,我们看到了在这个系统中使用策略对不同操作者行为控制的重要性。我们仅仅讨论了一些可用的策略,还有很多不同方面管控行为的定义。这些单独的策略会在文档的其他部分讨论。

最重要的一点,Hyperledger Fabric 提供了一个独特的强大的策略来允许网络和通道管理员自己来管理策略的变更!底层的理论是:策略的变更是一个常量,无论它是发生在不同的组织间,还是由外部的监管者加进来的。比如一个新的组织想要加入一个通道或者一些已经存在的组织想要增加或减少他们的权限。让我们来详细的看一下在 Hyperledger Fabric 中修改策略是如何实现的。

理解这个的关键点是一个策略的变化是由策略中的策略来管理的。那就是修改策略,或者简称mod_poicy,它是在管理变化的网络或者通道配置中的头等策略。关于我们是如何已经使用了 mod_policy 来管理网络中的变化,我们提供了两个简单的示例。

第一个例子是初始创建网络的时候。这时,只有组织 R4 被允许管理网络。在实际当中,这个是通过在网络配置 NC4 中把 R4 定义为唯一一个有权限来管理网络资源的组织来实现的。并且对于 NC4 的 mod_policy 也仅仅提到了组织 R4,因此只有 R4 被允许改变这个配置。

我们接下来将网络 N 进行了演进,同时允许组织 R1 来管理网络。R4 通过将 R1 添加到通道创建和联盟创建的策略中来实现。因为这个改动,R1 就可以定义联盟 X1 和 X2 了,并且可以创建通道 C1 和 C2。R1 在网络配置中对于通道和联盟策略具有了同样的管理权限。

R4 甚至可以通过网络配置来给 R1 赋予更大的权限!R4 可以将 R1 添加到 mod_poicy,这样 R1 就同样可以管理这个网络中的变更了。

第二个权利要比第一个权利大的多,因为现在 R1 具有了在网络配置 NC4 上的所有权限!这意味着,R1 能够移除 R4 在这个网络的管理权限。在实际当中,R4 会将 mod_policy 配置成对这样的改动需要 R4 批准,或者需要所有在 mod_policy 中定义的组织批准。这里有很大的灵活性来使 mod_policy 根据需要来定义任何更改流程。

这就是在实际工作中的 mod_policy,它允许一个基本的配置被优雅地演进为一个成熟的配置。这些演进都需要所有被引入的组织的同意。mod_policy 像在一个网络或者通道配置中的每一个其他的策略一样,它定义了一系列的组织,这些组织被允许自己来修改这个 mod_policy。

我们仅仅在这个部分了解了策略以及 mod_policy 的表面的内容。这会在策略的话题中有更详细的讨论,现在让我们回到这个已经完成的网络!

网络已经完成形成了

让我们使用一个统一的视觉来回顾一下我们的网络应该是什么样。我们使用更加紧凑的视觉语法来稍微重新组织一下这个网络,因为它能够更好地适应更大的一个拓扑结构:

在这个图中,我们看到了这个 Fabric 区块链网络包括了两个应用程序通道C1、C2以及一个排序通道C0。组织 R1 和 R4 负责排序通道,R1 和 R2 负责蓝色的应用程序通道,R2 和 R3 负责红色的应用程序通道。客户端应用程序 A1 是组织 R1 的元素,CA1 是它的证书颁发机构。注意到组织 R2 的节点 P2 可以使用蓝色的通信设施,也可以使用红色的应用程序通道。每个应用程序通道具有它自己的通道配置,这里是 CC1 和 CC2。系统通道的通道配置是网络配置 NC4 的一部分。

我们已经在概念上构建了一个 Hyperledger Fabric 区块链网络实例的最后一部分了。我们创建了一个有四个组织的网络,带有两个通道和三个 Peer 节点,两个智能合约和一个排序服务。并由四个证书颁发机构来支撑。它为三个客户端应用程序提供了账本及智能合约服务,这些应用程序可以通过两个通道与账本和智能合约进行交互。花些时间来仔细看看这个图中网络的详细内容,并且随时回来阅读这个部分来加强你的理解,或者查看其它更详细的话题。

网络组件的总结

下边是我们讨论过的网络组件的一个快速总结:

总结

我们了解了不同的组织如何共享它们的基础设施来提供一个集成的 Hyperledger Fabric 区块链网络。我们看到了如何将集体基础设施组织成提供独立管理的私有通信机制的通道。我们也已经看到了如何通过使用来自各自证书认证机构的证书来识别来自不同组织的参与者,比如客户端应用程序、管理员、节点和排序服务。反过来,我们也看到了策略的重要性,它定义了这些组织参与者在网络和通道资源上拥有的一致同意的权限。

身份

什么是身份

区块链网络中的不同参与者包括 Peer 节点、排序节点、客户端应用程序、管理员等。每一个参与者(网络内部或外部能够使用服务的活动元素)都具有封装在 X.509 数字证书中的数字身份。这些身份很重要,因为它们确定了对资源的确切权限以及对参与者在区块链网络中拥有的信息的访问权限

此外,数字身份还具有 Fabric 用于确定权限的一些其他属性,并且它为身份和关联属性的并集提供了特殊名称——主体 。主体就像 userID 或 groupID,但更灵活一点,因为它们可以包含参与者的身份的各种属性,例如参与者的组织,组织单位,角色甚至是参与者的特定身份。当我们谈论主体时,它们是决定其权限的属性。

要使身份可以被验证,它必须来自可信任的权威机构。成员服务提供者(Membership Service Provider,MSP)是 Fabirc 中可以信任的权威机构。具体地说,一个 MSP 是定义管理该组织有效身份规则的组件。Fabric 中默认的 MSP 实现使用 X.509 证书作为身份,采用传统的公钥基础结构(Public Key Infrastructure,PKI)分层模型(稍后将详细介绍PKI)。

身份的使用场景

想象你去超市购买一些杂货。在结账时,你会看到一个标志,表明只接受 Visa,Mastercard 和 AMEX 卡。如果你尝试使用其他卡付款(我们称之为“想象卡”)无论该卡是否真实、或你的帐户中是否有足够的资金,都无关紧要。它不会被接受。

拥有有效的信用卡是不够的,它也必须被商店接受!PKI 和 MSP 以相同的方式协同工作,PKI提供身份列表,MSP说明哪些是参与网络的给定组织的成员

PKI 证书和 MSP 提供了类似的功能组合。PKI 就像一个卡片提供商,它分配了许多不同类型的可验证身份。另一方面,MSP 类似于商店接受的卡提供商列表,确定哪些身份是商店支付网络的可信成员(参与者)。MSP 将可验证的身份转变为区块链网络的成员

让我们更详细地深入研究这些概念。

什么是PKI

**公钥基础结构(PKI)是一组互联网技术,可在网络中提供安全通信。**是 PKI 将 S 放在 HTTPS 中,如果你在网页浏览器上阅读这个文档,你可能正使用 PKI 来确保它来自一个验证过的来源。

上图是公钥基础结构(PKI)的要素。PKI 由向各方(例如,服务的用户,服务提供者)发布数字证书的证书授权中心组成,然后使用它们在与其环境交换的消息中对自己进行身份验证。CA 的证书撤销列表(CRL)构成不再有效的证书的参考。证书的撤销可能由于多种原因而发生。例如,由于与证书相关联的加密私有材料已被公开,所以证书被撤销。

虽然区块链网络不仅仅是一个通信网络,但它依赖于 PKI 标准来确保各个网络参与者之间的安全通信,并确保在区块链上发布的消息得到适当的认证。因此,了解 PKI 的基础知识以及 MSP 是非常重要的。

PKI 有四个关键要素:

  • 数字证书
  • 公钥和私钥
  • 证书授权中心
  • 证书撤销列表

让我们快速描述这些 PKI 基础知识,如果你想了解更多细节,维基百科是一个很好的起点。

下面这四部分介绍可以看上一篇笔记——密码学基础

数字证书

数字证书是包含与证书持有者相关的属性的文档。最常见的证书类型是符合 X.509标准 的证书,它允许在其结构中编码一些用于身份识别的信息。

例如,密歇根州底特律的 Mitchell 汽车的制造部门的 Mary Morris 可能有一个带有 SUBJECT 属性为 C=US, ST=Michigan, L=Detroit, O=Mitchell Cars, OU=Manufacturing, CN=Mary Morris /UID=123456 的数字证书。Mary 的证书类似于她的身份证(提供了 Mary 的信息),她可以用来证明关于她的重要事实。X.509 证书中还有许多其他属性,但现在让我们专注于这些。

描述一个名为 Mary Morris 的组织的数字证书。Mary 是证书的 SUBJECT,突出显示的 SUBJECT 文本显示了关于 Mary 的重要事实。如你所见,证书还包含更多信息。最重要的是,Mary 的公钥是在她的证书中分发的,而她的私人签名密钥则不是。此签名密钥必须保密。

重要的是,Mary 的所有属性都可以使用称为密码学(字面意思,“ 秘密书写 ”)的数学技术进行记录,这样篡改将使证书无效。只要对方信任证书颁发者,即证书授权中心(CA),密码学就允许 Mary 将证书提交给其他人以证明其身份。只要 CA 安全地保存某些加密信息(CA 的私钥),任何阅读证书的人都可以确定有关 Mary 的信息没有被篡改,它将始终具有 Mary Morris 的特定属性。将 Mary 的 X.509 证书视为无法改变的数字身份证

授权, 公钥和私钥

身份验证和消息完整性是安全通信中的重要概念。身份验证要求确保交换消息的各方创建特定消息的身份。对于具有“完整性”的消息意味着在其传输期间不能被修改。例如,你可能希望确保与真正的 Mary Morris 而不是模仿者进行沟通。或者,如果 Mary 向你发送了一条消息,你可能希望确保其在传输过程中没有被其他任何人篡改过。

传统的身份验证机制依赖于数字签名,顾名思义,它允许一方对其消息进行数字签名。数字签名还可以保证签名消息的完整性。

从技术上讲,数字签名机制要求每一方保存两个加密连接的密钥:广泛可用的公钥和充当授权锚的私钥,以及用于在消息上产生数字签名的私钥 。数字签名消息的接收者可以通过检查附加签名在预期发送者的公钥下是否有效来验证接收消息的来源和完整性。

私钥和公钥的唯一关系是保证安全通信的加密魔法。密钥之间唯一的数学关系使得私钥在消息上的签名,只有对应公钥在相同的消息上才可以与之匹配。

在上面的示例中,Mary 使用她的私钥对邮件进行签名。任何使用她的公钥查看签名消息的人都可以验证签名。

证书授权中心

如你所见,人员或节点能够通过由系统信任的机构为其发布的数字身份参与区块链网络。在最常见的情况下,数字身份(或简称身份)的形式为,符合 X.509 标准并由证书授权中心(CA)颁发的经加密验证的数字证书。

CA 是互联网安全协议的常见部分,你可能已经听说过一些比较流行的协议:Symantec(最初是 Verisign),GeoTrust,DigiCert,GoDaddy 和 Comodo 等。

证书授权中心向不同的参与者颁发证书。这些证书由 CA 进行签名,并将参与者的公钥绑定在一起(并且可选是否具有全部属性列表)。因此,如果一个成员信任 CA(并且知道其公钥),则可以信任与参与者绑定的证书中包含的公钥,并通过验证参与者证书上的 CA 签名来获取所包含的属性。

证书可以广泛传播,因为它们既不包括参与者也不包括 CA 的私钥。因此,它们可以用作信任的锚,用于验证来自不同参与者的消息。

CA 也有一个证书,它们可以广泛使用。这就可以让从给定 CA 获取身份证书的消费者验证自己的身份,因为只有对应的私钥才可以生成该证书。

在区块链设置中,希望与网络交互的每个参与者都需要一个身份。在此设置中,你可能会说使用一个或多个 CA 从数字角度定义了组织的成员 。CA 是为组织的参与者提供可验证的数字身份的基础。

根CA, 中间CA和信任链

CA 有两种形式:根 CA中间 CA 。因为根 CA(Symantec,Geotrust等)必须安全地向互联网用户颁发数亿个证书,所以将这个过程分散到所谓的中间 CA 中是很有用的。这些中间 CA 具有由根 CA 或其他中间 CA 颁发的证书,允许为链中的任何 CA 颁发的任何证书建立“信任链”。追溯到根 CA 的能力不仅让 CA 的功能在仍然提供安全性的同时进行扩展(允许使用证书的组织充满信心地使用中间 CA),还限制了根 CA 的暴露,如果根 CA 受到损害,将会危及整个信任链。另一方面,如果中间 CA 受到损害,则曝光量会小得多。

只要中间 CA 证书的颁发具有对根 CA 的信任链,就在根 CA 和中间 CA 之间建立信任链。

中间 CA 在跨多个组织颁发证书时提供了巨大的灵活性,这在许可的区块链系统(如Fabric)中非常有用。例如,你将看到不同的组织可能使用不同的根 CA,或者使用具有不同中间 CA 的相同根 CA,这取决于网络的需求。

Fabric CA

因为 CA 非常重要,所以Fabric 提供了一个内置的 CA 组件,允许在自己的区块链网络中创建 CA。此组件称为 Fabric CA ,是一个私有根 CA 提供者,能够管理具有 X.509 证书形式的 Fabric 参与者的数字身份。由于 Fabric CA 是针对 Fabric 的根 CA 需求的自定义 CA,因此它本身无法为浏览器中的常规或自动使用提供 SSL 证书。但是,由于一些 CA 必须用于管理身份(即使在测试环境中),因此可以使用 Fabric CA 来提供和管理证书。使用公共或商业的根或中间 CA 来提供识别也是可以的,并且完全合适。

如果你有兴趣,你可以在 CA 文档部分阅读有关 Fabric CA 的更多信息。

证书撤销列表

证书撤销列表(Certificate Revocation List,CRL)很容易理解,它是 CA 知道由于某些原因而被撤销的证书的引用列表。回想上面的信用卡场景,CRL 就像被盗信用卡列表一样。

当第三方想要验证另一方的身份时,它首先检查颁发 CA 的 CRL 以确保证书尚未被撤销。验证者不是必须要检查 CRL,但如果不检查,则他们冒着接受无效身份的风险。

使用 CRL 检查证书是否仍然有效。如果模仿者试图将无效的数字证书传递给验证者,则可以首先检查颁发证书的 CA 的 CRL,以确保其未被列为无效。

请注意,被撤销的证书与证书过期非常不同。撤销的证书尚未过期,按其他方式来说,它们是完全有效的证书。有关 CRL 的更多深入信息,请单击 此处

现在你已经了解了 PKI 如何通过信任链提供可验证的身份,下一步是了解如何使用这些身份来代表区块链网络的可信成员。这就是 MSP 发挥作用的地方——它确定了区块链网络特定组织的成员

要了解有关成员的更多信息,请查看有关 MSP 的概念文档。

成员服务提供者(MSP)

为什么需要MSP

因为Fabric是一个认证性的网络, 所以区块链参与者需要一种向网络中的其他参与者证实自己身份的机制从而在网络中进行交易。如果你已经阅读文档身份,你会看到公钥基础结构(PKI)如何通过信任链提供可认证的身份信息。那么区块链网络是怎么应用信任链的?

证书机构通过生成可以用来证实身份的由公钥和私钥形成的键值对来发放认证信息。因为一个私钥永远不会被公开,所以引入了一种可以证实身份的机制即MSP。例如,一个peer节点用它的私钥进行数字签名或背书交易。接着排序节点包含的该peer节点的公钥会被用来验证交易携带的签名是否合法。私钥被用作生成交易信息上的,只有与私钥相对应的且作为MSP一部分的公钥可以匹配的签名。因此,MSP是一个可让身份被信任和被网络中其他参与者公认的,而不需要暴露成员的私钥的机制。

回想一下同样是身份认证相关的信用卡场景,证书颁发机构CA就像一个信用卡提供商,它分发许多不同类型的可验证的身份。另一方面,MSP确定商店接受哪些信用卡提供商。通过这种方式,MSP将一个身份(信用卡)转换为一个角色(在商店购买东西的能力)

这种将可验证身份转换为角色的能力是Fabric网络功能的基础,因为它给予组织、节点和通道建立MSPs的能力,使其确定谁可以在组织、节点和通道层次上运作。

Identities类似于你的信用卡,用来证明你可以支付。MSP类似于被商店接受的信用卡清单。

以运用区块链网络的银行联盟为例。各个银行操作peer节点和排序节点,并且这些peer节点对提交到网络的交易进行背书。然而,每个银行也会有部门和账户持有人。账户持有人将属于各个组织,但不会运行网络上的节点。他们只会通过移动电话或web应用程序与系统交互。那么网络如何识别和区分这些身份呢?于是一个CA用于创建身份,但就跟信用卡的例子一样,这些身份不能就这样被颁发,它们需要被网络识别。MSPs被用于定义哪些是受网络成员信任的组织,也在网络中为成员提供一系列角色和权限的机制。因为定义这些组织的MSPs是网络成员所知道的,所以可以使用这些MSP来验证是否允许网络对象试图执行的操作。

最后,考虑一下如果您想要加入一个 现有的 网络,您需要一种方法来将您的身份转换为可以被网络识别的东西MSP是一种机制,使您能够加入一个需要许可的区块链网络。要在Fabric网络上进行交易,成员需要这样做:

  1. 拥有一个由网络信任的CA颁发的身份
  2. 成为一个被网络成员认可和认可的 组织成员。MSP将身份组织的成员资格联系在一起。成员资格是通过将成员的公钥(也称为证书、签名证书或签证)添加到组织的MSP来实现的。
  3. 将MSP添加到网络上的一个 联盟 或者通道
  4. 确保MSP包括在网络中的 策略 定义。

MSP是什么

尽管取着这样的名字,但是实际上成员服务提供者并不提供任何东西。相反,MSP要求的实现是一组文件夹添加到网络的配置,和用于内部地(组织决定它的管理员是谁)和外部地(通过允许其他组织验证对象是否有权做他们正在试图做的事情)定义一个组织。尽管证书颁发机构生成代表身份的证书,但MSP仍包含一个被允许的身份的列表。

MSP通过列出其成员的身份,或通过确定哪些是为其成员授权颁发有效身份的ca,来识别和确定接受来自这些根ca和中间ca所定义的信任域的成员。

但是MSP的能力不仅仅是简单地列出谁是一个网络参与者或一个通道的成员。MSP通过标识参与者在节点或通道上拥有的特定特权,将身份转换为角色。请注意,当用户使用Fabric CA注册时,该用户必须关联到管理员、peer节点、客户端、排序节点或成员其中之一的角色。例如,注册为“peer”角色的身份应该自然而然地给到peer节点。同样,注册为“admin”角色的身份也应该被授予给组织管理员。我们将在本章节后面深入探讨这些角色的重要性。

此外,MSP可以识别被撤销的身份列表——就像身份文档中所讨论的——而我们将讨论该过程如何扩展到MSP。

MSP域

在区块链网络中,MSP 出现在两个位置:

  • 在参与者节点本地(本地 MSP
  • 在通道配置中(通道 MSP

本地MSPs和通道MSPs之间的关键区别不在于它们如何运作——它们都将身份转化为角色——而是它们的范围。每个MSP列出特定管理级别上的角色和权限。

本地MSP

本地MSP是为客户端和节点(peer节点和排序节点)定义的。 本地MSPs定义节点的权限(例如,谁是可以操作节点的peer节点管理员)。客户端(以上银行场景的账户持有人)的本地MSP,允许用户作为一个通道成员或作为一个特定角色的所有者如组织管理者,在其交易(如链码交易)进行身份验证从而进入系统,例如,进行配置交易。

每个节点都必须定义一个本地MSP,因为它定义了在该级别上谁拥有管理权或参与权(peer节点管理员不一定是通道管理员,反之亦然)。这允许在通道上下文之外对成员消息进行身份验证,并定义特定节点(例如,能够在peer节点上安装链码的节点)的权限。请注意,一个组织可以拥有一个或多个节点。MSP定义了组织管理员。组织、组织的管理员、节点的管理员以及节点本身都应该具有相同的信任根。

排序节点的本地MSP也在节点的文件系统上定义,并且只应用于该节点。与peer节点一样,排序节点也由单个组织拥有,因此有一个MSP来列出它信任的参与者角色或节点。

通道MSP

相比之下,通道MSP在通道层面上定义了管理权和参与权。应用程序通道上的peer节点和排序节点共用通道MSP的相同视图,因此能够正确地对通道参与者进行身份验证。这意味着,如果组织希望加入通道,则需要在通道配置中添加包含组织成员信任链的MSP。否则,来自该组织身份的交易将被拒绝。本地MSP表现为文件系统上的文件夹结构,而通道MSP则在通道配置中被描述

从通道配置config.json文件中截取片段,其中包括两个组织MSP

通道MSP识别谁在通道层次拥有权限。 通道MSP定义通道成员(本身是MSP)的身份和通道级策略的执行之间的 关系 。通道MSP包含通道成员组织的MSP。

每个参与通道的组织都必须为其定义一个MSP。事实上,建议在组织和MSP之间建立一对一的映射。MSP定义了哪些成员被授权代表组织行事。这包括MSP本身的配置以及批准组织进行具有管理角色权限的任务,例如向通道添加新成员。如果所有网络成员都是单个组织或MSP的一部分,那将没有数据隐私。多个组织通过将账本数据仅隔离给通道成员来促成隐私保护。如果组织内部需要更细的隔离粒度,则可以将组织进一步划分为组织单元(ou),我们将在本章节后面详细描述这些单元。

系统通道MSP包括参与排序服务的所有组织的MSP。排序服务可能包括来自多个组织的排序节点,这些组织共同运行排序服务,最重要的是管理组织联盟和应用程序通道所继承的默认策略。

本地MSP仅在其应用的节点或用户的文件系统上定义。因此,在物理上和逻辑上,每个节点只有一个本地MSP。然而,由于通道MSP对通道内的所有节点都可用,它们在通道配置中逻辑上仅定义一次。然而,通道MSP也在通道中的每个节点的文件系统上实例化,并通过共识保持同步。因此,尽管每个节点的本地文件系统上都有每个通道MSP的副本,但从逻辑上讲,通道MSP存在并被维护于通道或网络上。

下图说明了本地MSP和通道MSP在网络中是如何共存的:

peer节点和排序节点的MSP是本地化的,而一个通道(包括网络配置通道,也称为系统通道)的MSP是全局化的,被该通道的所有参与者共用。在该图中,网络系统通道由ORG1管理,而另一个应用程序通道可以由ORG1和ORG2管理。peer节点是ORG2的成员并由ORG2管理,而ORG1则管理图中的排序节点。ORG1信任来自RCA1颁布的身份,而ORG2信任来自RCA2颁布的身份。需要注意的是,这些是管理身份标识,反映了谁可以管理这些组件。所以当ORG1管理网络时,网络定义中确实存在ORG2的MSP

组织在MSP中的角色

组织是一个逻辑上成员们的管理组。它可以大到跨国公司,也可以小到花店。关于组织(或orgs)最重要的是他们在单个MSP下管理其成员。MSP允许将标识链接到组织。注意,这与我们前面提到的组织概念中定义的X.509证书不同。

组织和它的MSP之间的专属关系使得以组织的名字为前缀命名MSP是合乎情理的,大多数策略配置都会采用这种约定。例如,组织ORG1可能有一个类似于ORG1-MSP的MSP。在某些情况下,一个组织可能需要多个成员组——例如,在组织之间使用通道执行完全不同的业务功能。在这些情况下,有多个msp并据此约定命名它们是有意义的,例如,ORG2-MSP-NATIONALORG2-MSP-GOVERNMENT,反映了GOVERNMENT控制的通道与NATIONAL交易通道在ORG2中不同的成员资格信任根。

组织单元(ou)和MSP

一个组织也可以被划分为多个组织单元,每个单元都有一定的职责,也称为affiliations。可以将组织单元看作组织内部的一个部门。例如,ORG1组织可能同时拥有ORG1.MANUFACTURINGORG1.DISTRIBUTION组织单元,这反映了相隔离的业务流水线。当CA颁发X.509证书时,证书中的OU字段指定该身份所属的业务流水线。这样使用组织单元的一个好处是,这些值可以用于定义策略,以限制访问,或者用于基于属性的访问控制的智能合约。否则,就需要为每个组织创建单独的MSP。

OU字段是否指定是可选的。如果不使用ou, MSP中的所有身份(由根CA和中间CA文件夹认定的)都将被视为组织的成员。

节点组织单元和MSP

此外,还有一种特殊类型的组织单元,有时称为节点组织单元,可用于授予角色以身份标识。这些节点组织单元角色定义在$FABRIC_CFG_PATH/msp/config.yaml配置文件中,并包含一个组织单元列表,这些单元成员被认为是MSP所代表的组织的一部分。当您希望将组织成员限制为只具有特定节点组织单元角色的身份标识时(由MSP指定的其中一个CA进行签名),这一点特别有用。例如,通过节点组织单元,您可以实现更细粒度的背书策略,该策略要求Org1的peer节点(而不是Org1的任何成员)为交易背书。

为了使用节点组织单元角色,您必须为网络启用“身份分类”特性。使用文件夹形式的MSP时,这可以通过在MSP目录下的配置文件config.yaml中启用“Node OUs”字段来实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
NodeOUs:
  Enable: true
  ClientOUIdentifier:
    Certificate: cacerts/ca.sampleorg-cert.pem
    OrganizationalUnitIdentifier: client
  PeerOUIdentifier:
    Certificate: cacerts/ca.sampleorg-cert.pem
    OrganizationalUnitIdentifier: peer
  AdminOUIdentifier:
    Certificate: cacerts/ca.sampleorg-cert.pem
    OrganizationalUnitIdentifier: admin
  OrdererOUIdentifier:
    Certificate: cacerts/ca.sampleorg-cert.pem
    OrganizationalUnitIdentifier: orderer

在上述例子中, MSP有4种节点组织单元角色:

  • client
  • peer
  • admin
  • orderer

这个约定允许您根据X509证书的CommonName属性中显示的OU来区分MSP角色。上面的示例说明由cacerts/ca.sampleorg-cert.pem颁发的任何证书,字段OU=client的将被认定为客户端,字段OU=peer的将被认定为peer,以此类推。从Fabric的1.4.3版本开始,还有一个用于排序节点和管理员的OU。新的admins角色意味着您不再需要显式地将证书放置在MSP目录下的admincerts文件夹中。相反,用户的signcert文件夹结构中呈现的admin角色使其具有管理员用户的身份标识。

当使用Fabric CA或SDK注册带有CA的用户时,这些角色和OU属性会被分配给一个身份标识。随后enroll用户命令会在用户的/msp文件夹中生成证书。

生成的角色和OU属性在位于/signcerts文件夹中的X.509签名证书中可见。ROLE属性被标识为hf.Type,其指的是参与者在其组织中的角色(例如,指定参与者是一个peer节点)。请参阅以下来自签名证书的代码片段,它显示了角色和ou在证书中是如何表示的。

注意: 对于通道MSP,仅仅只是某个参与者具有管理员的角色的话,是不能意味着他们就可以管理特定的资源的。给定的身份标识在管理系统方面的实际权力由管理系统资源的 策略 决定。例如,通道策略可能指定ORG1-MANUFACTURING管理员,即具有admin角色和ORG1-MANUFACTURING节点组织单元的身份,使其有权向通道添加新组织,而ORG1-DISTRIBUTION管理员则没有这样的权限。

最后,联盟中的不同组织可以使用组织单元来区分彼此。但在这种情况下,不同的组织必须为其信任链使用相同的根CA和中间CA,并分配OU字段来标识每个组织的成员们。当每个组织都拥有相同的CA或信任链时,这使得系统比预期中的更加中心化,因此这在区块链网络上应该仔细考虑。

MSP结构

让我们来探究提供我们迄今为止描述的这些功能的MSP元素。

本地MSP文件夹包含以下子文件夹:

上图显示了本地MSP在文件系统中的子文件夹

  • config.yaml: 通过启用“Node OUs”和定义可接受的角色来配置Fabric中的身份分类特性。

  • cacerts: 此文件夹包含此MSP代表的组织所信任的根CA的自签名X.509证书列表。此MSP文件夹中必须至少有一个根CA证书。

    这是最重要的文件夹,因为它确定了派生所有其他证书的必要CA,拥有这些证书才能被视为对应组织的成员,从而形成信任链。

  • intermediatecerts: 此文件夹包含该组织所信任的中间CA的X.509证书列表。每个证书必须由MSP中的一个根CA,或者其本身颁发的CA链最终会指向一个受信任的根CA的任何中间CA,进行签名。

    一个中间CA可能代表组织的不同细分(如ORG1-MANUFACTURINGORG1-DISTRIBUTION对应于ORG1),或者组织本身(如果商业CA被用于组织的身份管理,则可能是这种情况)。在后一种情况下,中间CA可以用来表示组织的细分这里你可以找到关于MSP配置的最佳实践的更多信息。请注意,一个正常工作的网络可能没有中间CA,在这种情况下,这个文件夹将是空的。

    与根CA文件夹一样,该文件夹也定义了CA,且证书必须从该CA颁发,才能被视为组织的成员。

  • admincerts (在Fabric的1.4.3及以上版本被弃用): 此文件夹包含一个身份列表,这些身份定义了具有此组织管理员角色的参与者。通常,这个列表中应该有一个或多个X.509证书。

    注意: 在Fabric v1.4.3之前,管理员是通过显式地将证书放在peer节点本地MSP目录的admincerts文件夹中来被定义的。Fabric的1.4.3及以上版本不再需要此文件夹中的证书。 相反,建议在用户注册到CA时,使用admin角色来指定节点管理员。然后,该标识被节点OU角色在它们的signcert中识别为admin。提醒一下,为了使用管理员角色,必须在以上的config.yaml配置文件中,通过将“Node OUs”设置为Enable: true来启用“identity classification”特性。我们稍后将进一步探讨这个问题。

    提醒一下,对于通道MSP,仅有参与者具有管理员角色这个条件,并不能说明他们可以管理特定的资源。给定身份在管理系统中拥有的实际权限是由管理系统资源的 策略 决定的。例如,通道策略可能指定ORG1-MANUFACTURING管理员拥有向通道添加新组织的权限,而ORG1-DISTRIBUTION管理员没有这样的权限。

  • keystore: (私钥) 这个文件夹是为peer节点或排序节点的本地MSP(或客户端的本地MSP)定义的,其包含节点的私钥。此私钥用于签名数据——例如,作为背书阶段的一部分,用其签名交易提案响应。

    此文件夹对于本地MSP是强制性的,并且必须准确地包含一个私钥。显然,对该文件夹的访问必须仅限于对peer节点负有管理责任的用户。

    通道MSP配置不包含此文件夹,因为通道MSP仅提供身份验证功能,而不提供签名功能。

    注意: 如果您使用硬件安全模块(HSM)进行私钥管理,此文件夹将为空,因为私钥由HSM生成并存储在HSM中。

  • signcert: 对于 Peer 节点或排序节点(或在客户端的本地 MSP 中),此文件夹包含 CA 发行的节点签名密钥。该证书表明节点的身份,与这个证书相对应的私钥可以用于生成签名,并且该签名可以被任何拥有这个证书的人验证。

    此文件夹对于本地 MSP是强制性的,并且必须包含一个准确的公钥。显然,对该文件夹的访问必须仅限于对 Peer 节点负有管理责任的用户。

    通道 MSP的配置不包含此文件夹,因为通道MSP仅提供身份验证功能,而不提供签名功能。

  • tlscacerts: 此文件夹包含受此组织信任的根CA的自签名X.509证书列表,用于进行节点之间基于TLS的安全通信。TLS通信的一个例子是peer节点需要连接到排序节点,以便它能接收到账本更新数据。

    MSP和TLS信息与网络内的节点相关——peer节点和排序节点,换句话说,而不是与使用网络的应用程序和管理程序相关。

    此文件夹中必须至少有一个TLS根CA证书。有关TLS的更多信息,请参见使用传输层安全协议(TLS)保护通信

  • tlsintermediatecacerts: 此文件夹包含一个受该MSP所代表的组织信任的中间CA证书列表,用于进行节点之间基于TLS的安全通信。当商业CA被用作一个组织的TLS证书时,此文件夹特别有用。与成员资格中间CA类似,TLS中间CA的指定是可选的。

  • operationscerts: 此文件夹包含与Fabric运维服务API通信所需的证书。

通道MSP包含以下附加文件夹:

  • Revoked Certificates: 如果参与者的身份被撤销,关于该身份的识别信息——而不是身份本身——会被保存在这个文件夹中。对于基于x.509的身份,这些标识符是被称为Subject Key Identifier(SKI)和Authority Access Identifier(AKI)的字符串对,并且在使用证书时被检查,以确保证书没有被撤销。

    尽管这个列表在概念上与CA的证书撤销列表(CRL)相同而已,但它也与组织成员的撤销有关。因此,通道MSP的管理员可以通过发布CA的更新过的CRL,快速从组织中撤销参与者或节点。这个“撤销列表中的列表”具有可选择性。只有当证书被撤销时,它才会被填充。

如果你读过这个文档以及我们关于身份的文档,你应该对身份和成员在 Hyperledger Fabric 中的作用有了很好的理解。您了解了如何使用 PKI 和 MSP 来识别在区块链网络中协作的参与者。您学习了证书、公钥、私钥和信任根的工作原理,以及 MSP 的物理和逻辑结构。

策略

什么是策略

从根本上来说,策略是一组规则,用来定义如何做出决策和实现特定结果。为此,策略一般描述了什么,比如一个人对资产访问或者权限。我们可以看到,在我们的日常生活中策略也在保护我们的资产数据,比如汽车租金、健康、我们的房子等。

例如,购买保险时,保险策略定义了条件、项目、限制和期限。该策略经过了策略持有者和保险公司的一致同意,定义了各方的权利和责任。

保险策略用于风险管理,在 Hyperledger Fabric 中,策略是基础设施的管理机制。Fabric 策略表示成员如何同意或者拒绝网络、通道或者智能合约的变更。策略在网络最初配置的时候由联盟成员一致同意,但是在网络演化的过程中可以进行修改。例如,他们定义了从通道中添加或者删除成员的标准改变区块格式或者指定需要给智能合约背书的组织数量。所有这些定义谁可以干什么的行为都在策略中描述。简单来说,你在 Fabric 网络中的所有想做的事情,都要受到策略的控制

为什么需要策略

策略是使 Hyperledger Fabric 不同于其他区块链系统(比如 Ethereum 或者 Bitcoin)的内容之一。在其他系统中,交易可以在网络中的任意节点生成和验证。治理网络的策略可以在任何时间及时修复,并且只可以使用和治理代码相同的方式进行变更。因为 Fabric 是授权区块链,用户由底层基础设施识别,所以用户可以在启动前决定网络的治理方式,以及改变正在运行的网络的治理方式。

策略决定了哪些组织可以访问或者更新 Fabric 网络,并且提供了强制执行这些决策的机制。策略包含了有权访问给定资源的组织列表,比如一个用户或者系统链码。他们同样指定了需要多少组织同意更新资源的提案,比如通道或者智能合约。一旦策略被写入,他们就会评估交易和提案中的签名,并验证签名是否满足网络治理规则。

Fabric是如何实现策略的

策略实现在 Fabric 网络的不同层次。每个策略域都管理着网络操作的不同方面。

Fabric 策略层级图。

系统通道配置

每个网络都从排序服务系统通道开始。网络中必须有至少一个排序服务的排序系统通道,它是第一个被创建的通道。该通道也包含着谁是排序服务(排序服务组织)以及在网络中交易(联盟组织)的成员。

排序系统通道配置区块中的策略治理着排序服务使用的共识,并定义了新区块如何被创建。系统通道也治理着联盟中的哪些成员可以创建新通道

应用通道配置

应用 通道 用于向联盟中的组织间提供私有通信机制。

应用通道中的策略治理着从通道中添加和删除成员的能力。应用通道也治理着使用 Fabric 链码生命周期在链码定义和提交到通道前需要哪些组织同意。当系统通道初始创建时,它默认继承了排序系统通道的所有排序服务参数。同时,这些参数(包括治理它们的策略)可以被每个通道自定义。

权限控制列表(ACL)

网络管理员可能对 Fabric 中 ACL 的使用更感兴趣,ACL 通过将资源和已有策略相关联的方式提供了资源访问配置的能力。“资源”可以是系统链码中的方法(例如,“qscc”中的“GetBlockByNumber”)或者其他资源(例如,谁可以获取区块事件)。ACL 参考应用通道配置中定义的策略并将它们扩展到了其他资源的控制。Fabric ACL 的默认集合在 configtx.yaml 文件的 Application: &ApplicationDefaults 部分,但是它们可以也应该在生产环境中被重写configtx.yaml 中定义的资源列表是 Fabric 当前定义的所有内部资源的完整集合。

该文件中,ACL 以如下格式表示:

1
2
# ACL policy for chaincode to chaincode invocation
peer/ChaincodeToChaincode: /Channel/Application/Writers

peer/ChaincodeToChaincode 表示该资源是被保护的,相关的交易必须符合 /Channel/Application/Writers 引用侧策略才能被认为是有效的。

关于 ACL 更深入的信息,请参考操作指南中的 ACL 主题。

智能合约背书策略

链码包中的每一个智能合约都有一个背书策略,该策略指明了需要通道中多少不同组织的成员根据指定智能合约执行和验证交易才能使一笔交易有效。因此,背书策略定义了必须“背书”(批准)提案执行的组织(的 Peer 节点)

修改策略

还有一个对 Fabric 的策略工作有重要作用的策略类型,修改(Modification)策略。修改策略指明了需要签名所有配置 更新 的一组身份。它是定义如何更新策略的策略。因此,每个通道配置元素都包含这一个治理它的变更的策略的引用。

Fabric策略作用域

虽然 Fabric 的策略很灵活地配置以适应网络需要,但是策略的结构天然地隔离了由不同排序服务组织或者不同联盟成员治理的域。下边的图中,你可以看到默认策略是如何实现对 Fabric 策略域的控制的。

排序组织和联名组织治理的策略域的详细视图。

一个完整的 Fabric 网络可以由许多不同职能的组织组成。通过支持排序服务创建者建立初始规则和联盟成员的方式,域提供了向不同组织扩展不同的优先级和角色的能力。还支持联盟中的组织创建私有应用通道、治理他们自己的商业逻辑以及限制网络中数据的访问权限。

系统通道配置和每个应用通道配置部分提供了排序组织对哪些组织是联盟成员、区块如何分发到通道以及排序服务节点使用的共识机制的控制。

系统通道配置为联盟成员提供了创建通道的能力。应用通道和 ACL 是联盟组织用来从通道中添加或删除成员以及限制通道中智能合约和数据访问的机制。

在Fabric中如何写策略

如果你想修改 Fabric 的任何东西,和资源相关的策略都描述了需要批准它,可以是来自个人的一个显式签名,也可以是组的一个隐式签名。在保险领域,一个明确的签名可以是业主保险代理集团中的一员。而一个隐含的签名类似于需要业主保险代理集团中的大多数管理成员批准。这很重要,因为集团中的成员可以在不更新策略的情况下变动。在 Hyperledger Fabric 中,策略中明确的签名使用 Signature 语法,隐含的签名使用 ImplicitMeta 语法。

签名策略

Signature 策略定义了要满足策略就必须签名的特定用户类型,比如 Org1.Peer OR Org2.Peer。策略是很强大的,应为它可以构造复杂的规则,比如“组织 A 和 2 个其他管理员,或者 6 个组织的管理员中的 5 个”。语法支持 ANDORNOutOf 的任意组合。例如,一个策略可以简单表达为使用 AND (Org1, Org2) ,表示满足该策略就同时需要 Org1 中的一个成员和 Org2 中的一个成员的签名。

隐元(ImplicitMeta)策略

隐元策略只在通道配置上下文中有效,通道配置在配置树策略中是基于分层的层次结构。隐元策略聚合了由签名策略最终定义的配置树深层的结果。它们是隐藏的,因为它们基于通道配置中的当前组织隐式构建,它们是元信息,因为它们的评测不依赖于特定 MSP 规范,而是依赖于配置树中它们的其他子策略。

下边的图例说明了应用通道分层的策略结构,并演示了隐元通道配置管理策略(称为 /Channel/Admins)是如何处理的,也就是说,当满足配置层级中它的 Admins 子策略时,就代表也满足了其子策略的子策略条件。

正如你在上图看到的,隐元策略,Type = 3,使用了一种不同的语法 "<ANY|ALL|MAJORITY> <SubPolicyName>",例如:

1
`MAJORITY sub policy: Admins`

上边的图表展示了一个在配置树中所有 Admins 策略都引用了的 Admin 子策略。你可以创建你自己的子策略并随意命名,并且可以定义在你的每一个组织中。

正如上边提到的,隐元策略比如 MAJORITY Admins 的主要优势在于当你向通道添加新组织的时候,你不必更新通道策略。因此隐元策略就像联盟成员变更一样灵活。联盟中成员的新增或者退出只要联盟成员一致同意即可,不需要更新策略。重申一下,隐元策略最终处理的是如图所示的配置树中它们之下的签名子策略

你也可以定义一个应用级别的隐策略来进行跨组织操作,例如在通道中,需要 ANY (任意)、 ALL (全部)或者 MAJORITY (大多数)组织来满足。这个格式有更好、更自然的默认值,因此组织可以决定有效背书的含义。

你可以通过在组织定义中引入 NodeOUs 来实现进一步的粒度和控制。OU (Organization Units,组织单元)定义在 Fabric CA 客户端配置文件中,当创建身份的时候就会与之关联。在 Fabric 中, NodeOUs 提供为数字证书层级分类的功能。例如,一个指定了 NodeOUs 的组织可以让一个 ‘Peer’ 签名合法背书,或者组织也可以简单设置为任何成员都可以签名。

示例:通道配置策略⭐

背书策略的理解要从 configtx.yaml 开始, configtx.yaml 里边定义了通道策略。我们可以查看 BYFN(first-network) 教程中的 configtx.yaml 来查看这两种策略语法类型的示例。请导航至 fabric-samples/first-network 目录查看 BYFN 中的 configtx.yaml 文件。

文件的第一部分(Organizations)定义了网络中的组织。在每个组织的定义中设置了默认策略Readers, Writers, Admins, and Endorsement,但是你可以任意定义策略命名。每个策略都有一个 TypeRuleType 描述了策略的表达式类型(SignatureImplicitMeta)。

下边的 BYFN 示例展示了组织 Org1 在系统通道中的定义,其中策略的 TypeSignature 背书策略规则定义为 "OR('Org1MSP.peer')",表示需要 Org1MSP 成员中的 peer 来签名。正是这些签名策略形成了隐元策略指向的子策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 - &Org1
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org1MSP

        # ID to load the MSP definition as
        ID: Org1MSP

        MSPDir: crypto-config/peerOrganizations/org1.example.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org1MSP.peer')"

下一个示例显示了在 configtx.yaml 的应用程序部分中使用的 ImplicitMeta 策略类型。 这些策略集位于 /Channel/Application/ 路径上。 如果您使用默认的 Fabric ACL 集,这些策略定义了应用程序通道的许多重要特性的行为,例如谁可以查询通道分类帐、调用链代码或更新通道配置。 这些策略指向为每个组织定义的子策略。 上一节中定义的 Org1 包含由 Application 部分中的 Reader、Writer 和 Admin ImplicitMeta 策略评估的 Reader、Writer 和 Admin 子策略。 由于测试网络是使用默认策略构建的,因此您可以使用示例 Org1 来查询通道分类帐、调用链代码并批准您创建的任何测试网络通道的通道更新。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/<PolicyName>
    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"

Fabric链码生命周期

Fabric 2.0 发布版本中,介绍了一个新的链码生命周期过程,这是一个在网络中更民主的治理链码的过程。新的过程允许多个组织在链码应用到通道之前如何操作进行投票。这个很重要,因为这是新生命周期过程和策略的融合,策略是在过程中指定的决定着网络的安全性。关于该流程的更多细节在 操作者的链码 教程中,但是为了本主题的目的,你应该理解策略在流程中的使用。新的流程指定策略包含两步,

  1. 当链码被组织成员批准的时候
  2. 当它被提交到通道后。

configtx.yaml 文件中 Application 部分包含了默认的链码生命周期背书策略。在生产环境中你应该为你的用例自定义这个。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/<PolicyName>
    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"
  • LifecycleEndorsement 策略控制需要谁 批准链码定义
  • Endorsement 策略是 链码的默认背书策略 。更多细节请继续向下阅读。

链码背书策略

当使用 Fabric 链码生命周期链码被批准并提交到通道时会指定一个背书策略(这个背书策略会覆盖与该链码相关的所有状态)。背书策略可以引用通道配置中的背书策略或者明确指定签名策略

如果在批准阶段没有明确指明背书策略,就默认使用 Endorsement 策略 "MAJORITY Endorsement",意味着要想使交易生效就需要大多数不同通道成员(组织)的执行并验证交易。默认策略允许加入通道的组织自动加入链码背书策略。如果你不想使用默认背书策略,你可以使用签名策略格式来指定更复杂的背书策略(这样就需要链码先被通道中的一个组织签名,然后让其他组织签名)。

签名策略也允许你包含主角(principals),这是匹配角色和身份的一种简单方式。主角类似用户 ID 或者 组 ID,但是更广泛,因为它们可以包含更大范围演员身份的属性,比如演员的组织、组织单元、角色,甚至演员指定的身份。我们讨论的主角是决定他们权限的属性。主角被描述为 ‘MSP.ROLE’,MSP 表示需要的 MSP ID(组织),ROLE 表示一下四种可接受的角色之一:Member、 Admin、 Client 和 Peer。角色在用户使用 CA 登记(enroll)的时候与之关联。你可以在 Fabric CA 中自定义可用的角色列表。

一些有效的主角:

  • ‘Org0.Admin’: Org0 MSP 的一个管理员
  • ‘Org1.Member’: Org1 MSP 的一个成员
  • ‘Org1.Client’: Org1 MSP 的一个客户端
  • ‘Org1.Peer’: Org1 MSP 的一个 Peer 节点
  • ‘OrdererOrg.Orderer’: OrdererOrg MSP 的一个排序节点

有一些场景可能需要一些特殊的状态(特殊的键-值对,或这其他的)有不同的背书策略。基于状态的背书可以指定与默认链码级别背书策略不同的键的背书策略。

如何写一个背书策略的更多信息请参考操作指南中的 背书策略 主题。

注意: 不同版本 Fabric 的策略有所不同:

  • 在 Fabric 2.0 之前,链码的背书策略可以在链码实例化或者使用链码生命周期命令时更新。如果没有在实例化时指明,默认背书策略是“通道中组织的任意成员”。例如。在有 “Org1” 和 “Org2” 的通道中,将有一个 “OR(‘Org1.member’, ‘Org2.member’)” 的默认策略。
  • 从 Fabric 2.0 开始,Fabric 提出了一个新的链码生命周期过程,允许多组织同意在链码应用到通道之前如何操作。新的过程需要组织同意链码定义的参数,比如名字版本以及链码背书策略

覆盖策略定义

Hyperledger Fabric 包含了用于快速入门、开发、测试的默认策略,但是在生产环境中需要自定义。你应该留意 configtx.yaml 文件中的默认策略。通道配置策略可以使用任意单词扩展,不仅仅是 configtx.yaml 中的 Readers、 Writers、 Admins。当你编辑 configtx.yaml 文件重写了排序系统通道或指定通道的默认策略并提交了配置更新,就会覆盖排序系统和应用通道的默认策略。

Fabric中的策略

Hyperledger Fabric 区块链网络的配置由策略管理。这些策略通常驻留在通道配置中。本文档的主要目的是解释如何在通道配置中定义策略并与之交互。但是,策略也可能在其他一些地方指定,例如链代码,因此此信息可能会在通道配置范围之外引起人们的兴趣。

什么是策略

在最基本的层面上,策略是一个函数,它接受一组签名数据作为输入并成功评估,或者因为签名数据的某些方面不满足策略而返回错误。

更具体地说,策略测试某些数据的签名者或签名者是否满足将这些签名视为“有效”所需的某些条件。这对于确定正确的各方已同意交易或更改很有用。

例如,一项策略可以定义以下任何一项:

  • 5 个可能的不同组织中的 2 个管理员必须签名。
  • 任何组织的任何成员都必须签名。
  • 两个特定的证书必须同时签名。

当然这些只是示例,还可以构建其他更强大的规则。

策略类型

目前实施了两种不同类型的政策:

  1. SignaturePolicy:此策略类型是最强大的,并将策略指定为 MSP Principals 评估规则的组合。它支持ANDORNOutOf的任意组合,允许构建极其强大的规则,例如:“组织 A 的管理员和 2 个其他管理员,或 20 个组织管理员中的 11 个”。
  2. ImplicitMetaPolicy:此策略类型不如 SignaturePolicy 灵活,并且仅在配置上下文中有效。它聚合了配置层次结构中更深层次的评估策略的结果,这些策略最终由 SignaturePolicies 定义。它支持良好的默认规则,例如“大多数组织管理策略”。

策略被编码为common.Policy消息,定义在fabric-protos/common/policies.proto中。它们由以下消息定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
message Policy {
    enum PolicyType {
        UNKNOWN = 0; // Reserved to check for proper initialization
        SIGNATURE = 1;
        MSP = 2;
        IMPLICIT_META = 3;
    }
    int32 type = 1; // For outside implementors, consider the first 1000 types reserved, otherwise one of PolicyType
    bytes policy = 2;
}

要对策略进行编码,只需选择策略类型IMPLICIT_METASIGNATURE,将其设置为type字段,并将相应的策略实现原型编组为policy

配置和策略

通道配置表示为配置组的层次结构,每个配置组都有一组值和与之关联的策略。对于具有两个应用程序组织和一个排序组织的有效配置的应用程序通道,配置至少如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Channel:
    Policies:
        Readers
        Writers
        Admins
    Groups:
        Orderer:
            Policies:
                Readers
                Writers
                Admins
            Groups:
                OrderingOrganization1:
                    Policies:
                        Readers
                        Writers
                        Admins
        Application:
            Policies:
                Readers
----------->    Writers
                Admins
            Groups:
                ApplicationOrganization1:
                    Policies:
                        Readers
                        Writers
                        Admins
                ApplicationOrganization2:
                    Policies:
                        Readers
                        Writers
                        Admins

……未完待续

策略默认值

请注意,层次结构中较高的策略都定义为ImplicitMetaPolicys,而叶节点必须定义为SignaturePolicys。这组默认值工作得很好,因为ImplicitMetaPolicies不需要随着组织数量的变化而重新定义,并且各个组织可以选择自己的规则和阈值来确定读者、作者和管理员的含义。

configtxgen工具使用必须在 configtx.yaml 中明确指定的策略。

Peer节点

区块链网络主要由 Peer 节点(或者简单称之为 Peer)组成。Peer 是网络的基本元素,因为他们存储了账本和智能合约。之前我们说过账本不可篡改地保存着智能合约生成的所有交易(在 Hyperledger Fabric 中智能合约包含在链码中,稍后会详细介绍)。智能合约和账本将网络中共享的流程信息对应地封装起来。Peer 节点的这些功能使它成为了理解 Fabric 网络很好的起点。

区块链网络中的其他部分当然也非常重要:账本和智能合约、排序节点、策略、通道、应用程序、组织、身份和成员关系等,你可以在其他的文档中了解更多。这个部分会集中在 Peer 节点上,以及他们和 Hyplerledger Fabric 网络中的其他要素的关系。

区块链网络是由 Peer 节点组成的,每个节点都保存着账本和智能合约的副本。在这个例子中,网络 N 是由节点 P1、P2 和 P3 组成的,每个节点都维护这他们自己的分布式账本 L1。P1、P2 和 P3 使用相同的链码 S1 来访问他们的分布式账本的副本。

Peer 节点可以被创建、启动、停止、重新配置甚至删除。他们暴露了一系列的 API,这就可以让管理者和应用程序同这些 API 提供的服务互动。我们会在这里学习更多关于这些服务的知识。

一个术语

Fabric 是使用一个被称为链码的技术概念来实现 智能合约 的,就是使用已支持的编程语言编写的一段简单的代码来访问账本。在这个话题中,我们会经常使用名词链码,但是如果你更习惯于使用智能合约的话,你也可以将它读成智能合约。他们是相同的概念!如果你想了解更多关于链码和智能合约的话,查看我们的智能合约和链码文档

账本和链码

让我们更详细地了解一下 Peer 节点。我们能够看到其实是 Peer 节点在维护账本和链码。确切地说,Peer 节点维护的是账本及链码的实例。请注意这其实是在 Fabric 网络中故意提供了冗余,因为这样可以避免单点失效。我们会在接下来的章节中了解更多有关区块链网络的分布式和去中心化的特点。

Peer 节点维护着账本及链码的实例。在这个例子中,P1 维护着账本 L1 和链码 S1 的实例。也可以多个账本及链码维护在一个独立的 Peer 节点上。

Peer 节点是账本及链码的宿主,应用程序及管理员如果想要访问这些资源,他们必须要和 Peer 节点进行交互。这就是为什么 Peer 节点被认为是 Hyperledger Fabric 网络最基本的组成模块。当 Peer 节点被第一次创建的时候,它并没有账本也没有链码。我们接下来会看到 Peer 节点的上账本是如何被创建的,以及链码是如何被安装的。

多账本

一个 Peer 节点可以维护多个账本,这是很有用的,因为它能够进行很灵活的系统设计。最简单的配置就是一个 Peer 节点管理一个账本,但是当需要的时候,一个 Peer 节点维护两个或者更多的账本也是非常适合的。

一个 Peer 节点维护多个账本。Peer 节点维护着一个或者多个账本,并且每个账本具有零个或者多个链码使用账本。在这个例子中,我们能够看到 Peer 节点 P1 维护着账本 L1 和 L2。账本 L1 通过链码 S1 来访问。账本 2 通过链码 S1 和 S2 访问。

尽管一个 Peer 节点只维护一个账本的实例而不运行任何访问账本的链码是完全可能的,但是很少有 Peer 节点会像这样来进行配置。大多数的 Peer 节点将会至少安装一个链码,用来查询或更新 Peer 节点的账本实例。有必要说明一下,无论用户是否安装了外部应用使用的链码,Peer 节点总是会有一个特殊的系统链码。这个不会在这个章节中进行讨论。

多链码

账本数量和访问账本的链码的数量之间没有固定的关系。一个 Peer 节点可能会有很多链码和账本。

这是一个运行着多个链码的 Peer 节点。每个账本可以拥有多个访问它的链码。在这个例子中,我们能够看到 Peer 节点 P1 维护着账本 L1 和 L2,L1 可以通过链码S1 和 S2 来访问,账本 L2 可以由 S1 和 S3 来访问。我们能够看到链码 S1 既能访问 L1 也能访问 L2。

稍后我们会看到在 Hyperledger Fabric 中,为什么当 Peer 节点维护多个账本或多个链码的时候,通道的概念就会很重要。

应用程序和Peer节点

现在我们要展示应用程序是如何通过跟 Peer 节点交互来访问账本的。查询账本的操作涉及到应用程序和 Peer 节点之间的一个简单的三步对话;更新账本的操作会涉及到更多的步骤,需要额外的两步。我们将简化这些步骤来帮助你了解 Hyperledger Fabric,不要担心,你需要理解的最重要的部分是应用程序和 Peer 节点之间进行查询账本和更新账本交易的不同。

当应用程序需要访问账本和链码的时候,他们总是需要连接到 Peer 节点。Hyperledger Fabric SDK 将这个操作变得非常简单,它的 API 使应用程序能够连接到 Peer 节点,调用链码生成交易,提交交易到网络,在网络中交易会被排序并且提交到分布式账本中,并且在这个流程结束的时候接收到事件。

通过连接 Peer 节点,应用程序能够执行链码来查询或者更新账本。对账本的查询结果马上会返回,但是对账本的更新会在应用程序、Peer 节点以及排序节点之间有更复杂的交互。让我们更详细地研究一下。

Peer 节点和排序节点,确保了账本在每个 Peer 节点上都具有最新的账本。在这个例子中,应用程序 A 连接到了 P1 并且调用了链码 S1 来查询或者更新账本 L1。P1 调用了链码 S1 来生成提案响应,这个响应包含了查询结果或者账本更新的提案。应用程序 A 接收到了提案的响应,对于查询来说,流程到这里就结束了。对于更新来说,应用程序 A 会从所有的响应中创建一笔交易,它会把这笔交易发送给排序节点 O1 进行排序。O1 会搜集网络中的交易并打包到区块中,然后将这些区块分发到所有 Peer 节点上,包括 P1。P1 在把交易提交到账本 L1 之前对交易进行验证。当 L1 被更新之后,P1 会生成一个事件,该事件会被 A 接收到,来标识这个过程结束了。

Peer 节点可以马上将查询的结果返回给应用程序,因为满足这个查询的所有信息都保存在 Peer 节点本地的账本副本中。Peer 节点从来不会为了应用程序的查询返回结果而去询问其他 Peer 节点的。但是应用程序还是能够连接到一个或者多个 Peer 节点来执行一个查询;比如,为了协调在多个 Peer 节点间的一个结果,或者当怀疑数据不是最新的时候,需要从不同的 Peer 节点获得更新的结果。在上图中,你能够看到账本查询是一个简单的三步流程。

更新交易和查询交易起点相同,但是有两个额外的步骤。尽管更新账本的应用程序也会连接到 Peer 节点来调用链码,但是不像查询账本的应用程序,一个独立的 Peer 节点目前是不能进行账本更新的,因为其他的 Peer 节点必须首先要同意这个变动(即达成共识)。因此,Peer 节点会返回给应用程序一个被提案过的更新,这个 Peer 节点会依据其他节点之前的协议来应用这个更新。第一个额外的步骤,也就是第四步,要求应用程序将响应的提案过的更新发送到网络中,网络中的 Peer 节点会将交易提交到它们相应的账本中。应用程序会收到排序节点打包了交易的区块,然后将他们分发到网络中所有的 Peer 节点,在区块被更新到每个 Peer 节点本地账本的副本中之前,这些区块都需要被验证。排序流程需要一定时间来完成 (数秒钟),因此应用程序会被异步通知,像步骤五中展示的那样。

在这个部分的后边,你将会了解到更多关于排序流程的信息。如果你想更详细地了解一下这个流程,你可以阅读Transaction Flow话题。

Peer节点和通道

尽管该部分更关注 Peer 节点而不是通道,但是花一些时间来理解 Peer 节点是如何通过应用程序,使用通道彼此进行交互还是值得的,这是区块链网络中组件能够进行交流和私密交易的机制。

这些组件通常是 Peer 节点、排序节点和应用程序,并且通过加入通道的方式,表明他们同意在那个通道中通过互相合作来共享以及管理完全一致的账本副本。概念上来说,你可以把通道想象为类似于一个由朋友组成的群组一样(尽管一个通道中的成员不需要是朋友!)。一个人可能会有很多个群组,在每个群组中他们会共同地进行一些活动。这些群组可能是完全独立的(一个工作伙伴的群组和一个兴趣爱好伙伴的群组),或者群组间可能会有交叉的部分。然而,每个群组都是它自己的实体,具备某种”规则”。

通道允许区块链网络中特定的一些 Peer 节点以及应用程序来彼此交互。在这个例子中,应用程序 A 能够直接同 Peer 节点 P1 和 P2 使用通道 C 进行沟通。你可以把通道想象为在某些应用程序和 Peer 节点之间进行通信的小路。(排序节点没有显示在这个图中,但是在工作网络中它必须存在。)

我们可以看到通道和 Peer 节点是以不同的方式存在的,将通道理解为由物理的 Peer 节点的组成的逻辑结构更合适一些理解这一点很重要,因为 Peer 节点提供了对通道访问和管理的控制

Peer节点和组织

现在你已经理解了 Peer 节点以及它们同账本、链码和通道间的关系,你将会看到多个组织是如何走到一起来构成一个区块链网络的。

区块链网络是由多个组织来管理的,而不是单个组织。对于如何构建这种类型的分布式网络,Peer 节点是核心,因为他们是由这些组织所有,也是这些组织同这个网络的连接点。

区块链网络中的 Peer 节点和多个组织。区块链网络是由不同的组织所拥有并贡献的 Peer 节点构成的。在这个例子中,我们看到由四个组织贡献了八个 Peer 节点组成一个网络。在网络 N 中,通道 C 连接了这些 Peer 节点中的五个:P1、P3、P5、P7 和 P8。这些组织拥有的其他节点并没有加入该通道,但是通常会加入至少一个其他通道。某个组织开发的应用程序将会连接到他们自己组织的 Peer 节点,其他组织也一样。为了简化,排序节点没有在这个图中表示出来。

真正重要的是,你能够看到在形成一个区块链网络的时候都发生了什么。*这个网络是由多个组织来组成并维护的,这些组织向这个网络贡献资源。*Peer 节点是我们在这个话题中正在讨论的资源,但是一个组织提供的资源不仅仅是 Peer 节点。这里有一个工作原则:如果组织不为这个网络贡献他们的资源,这个网络是不会存在的。更关键的是,这个网络会随着这些互相合作的组织提供的资源而增长或者萎缩。

上边的例子 中,你能够看到(除了排序服务),这里没有中心化的资源,如果这些组织不贡献他们的节点的话,网络 N 是不会存在的。这反映了一个事实,除非并且直到组织贡献了他们的资源才会形成这样一个网络,否则这个网络没有存在的意义。另外,这个网络不依赖于任何一个单独的组织,只要还存在一个组织,网络就会继续存在,不管其他的组织加入或者离开。这就是去中心化网络的核心

就像上边的例子,在不同的组织中的应用程序可能相同也可能不同。这完全取决于组织想要他们的应用程序如何处理他们的 Peer 节点的账本副本。这意味着应用程序和展示逻辑可能在不同组织间有很大的不同,尽管他们的 Peer 节点维护着完全相同的账本数据。

应用程序会连接到他们组织的 Peer 节点或者其他组织的 Peer 节点,取决于账本交互的需求。对于查询账本的交互,应用程序通常会连接到他们自己组织的 Peer 节点。对于更新账本的交互,之后我们会看到为什么应用程序需要连接到多个 Peer 节点,这些节点是每一个要为账本更新进行背书的组织的代表

Peer节点和身份

现在你已经看到了来自于不同组织的 Peer 节点是如何组合到一起形成区块链网络的,花费一些时间来理解 Peer 节点是如何被他们的管理者分配到相关的组织是非常值得的。

Peer 节点会有一个身份信息被分给他们,这是通过一个特定的证书认证机构颁发的数字证书来实现的。你可以在本指南的其他地方阅读更多的关于 X.509 数字证书是如何工作的,但是,现在,就把数字证书看成是能够为 Peer 节点提供可验证信息的身份证。在网络中的每个 Peer 节点都会被所属组织的管理员分配一个数字证书

当 Peer 节点连接到一个通道的时候,它的数字证书会通过通道 MSP 来识别它的所属组织。在这个例子中,P1 和 P2 具有由 CA1 颁发的身份信息。通道 C 通过在它的通道配置中的策略来决定来自 CA1 的身份信息应该使用 ORG1.MSP 被关联到 Org1。类似的,P3 和 P4 由 ORG2.MSP 识别为 Org2 的一部分。

当 Peer 节点使用通道连接到一个区块链网络的时候,在通道配置中的策略会使用 Peer 节点的身份信息来确定它的权利。关于身份信息和组织的映射是由成员服务提供者(MSP)来提供的,它决定了一个 Peer 节点如何在指定的组织中分配到特定的角色以及得到访问区块链资源的相关权限。更多的是,一个 Peer 节点只能被一个组织所有,因此也就只能被关联到一个单独的 MSP。我们会在本部分的后边学习更过关于 Peer 节点的访问控制,并且在本指南中还有关于 MSP 和访问控制策略的部分。目前,可以把 MSP 看作在区块链网络中,为一个独立的身份信息和一个特定的组织角色之间提供了关联

稍微讨论一个额外的话题,Peer 节点以及同一个区块链网络进行交互的每件事情都会从他们的数字证书和 MSP 来得到他们的组织的身份信息**。Peer 节点、应用程序、终端用户、管理员以及排序节点如果想同一个区块链网络进行交互的话,必须要有一个身份信息和一个相关联的 MSP**。我们使用身份信息来为每个跟区块链网络进行交互的实体提供一个名字——一个主角(principal)。 你可以在本指南中其他部分学习到更多的关于主角和组织的知识,但是现在你已经有足够的知识来继续你对 Peer 节点的理解了!

最后,请注意 Peer 节点物理上在哪真的不重要——它可以放在云中,或者是由一个组织所有的数据中心中,或者在一个本地机器中——是与它相关联的数字证书信息来识别出它是由哪个组织所有的。在我们上边的例子中,P3 可以运行在 Org1 的数据中心中,只要与它相关联的数字证书是由 CA2 颁发的,那么它就是 Org2 所拥有的。

Peer节点和排序节点

我们已经看到了 Peer 节点构成了一个基本的区块链网络,维护着账本和智能合约,连接到 Peer 节点的应用程序进行查询及更新。但是,应用程序和 Peer 节点彼此互相交互来确保每个 Peer 节点的账本永远保持一致是通过以排序节点作为中心媒介的一种特殊机制,我们现在会关注这些节点。

一个更新的交易和一个查询的交易区别很大,因为一个单独的 Peer 节点不能够由它自己来更新账本——更新需要网络中其他节点的同意。在一个账本的更新被应用到 Peer 节点的本地账本之前, Peer 节点会请求网络中的其他 Peer 节点来批准这次更新。这个过程被称为共识,这会比一个简单的查询花费更长的时间来完成。但是当所有被要求提供批准的节点都提供了批准,并且这笔交易被提交到账本的时候,Peer 节点会通知它连接的应用程序账本已经更新了。在这个章节中你将会看到 Peer 节点和排序节点是如何管理这个共识流程的详细内容。

特别的是,想要更新账本的应用程序会被引入到一个三阶段的流程,这确保了在一个区块链网络中所有的 Peer 节点都彼此保持着一致的账本

  • 在第一个阶段,应用程序会跟背书节点的子集一起工作,其中的每个节点都会向应用程序为提案的账本更新提供背书,但是不会将提案的更新应用到他们的账本副本上。
  • 在第二个阶段,这些分散的背书会被搜集到一起当做交易被打包进区块中。
  • 在最后一个阶段,这些区块会被分发回每个 Peer 节点,在这些 Peer 节点上每笔交易在被应用到 Peer 节点的账本副本之前会被验证。

就像你将会看到的,排序节点在这个流程中处于中心地位,所以让我们稍微详细一点地研究一下应用程序和 Peer 节点对于一个分布式的和重复的账本是如何使用排序节点来生成账本更新的。

阶段1:提案

交易流程的第一阶段会引入在应用程序和一系列的 Peer 节点之间的交互——它并没有涉及到排序节点。第一阶段只在乎应用程序询问不同组织的背书节点同意链码调用的提案结果。

为了开始第一阶段**,应用程序会生成一笔交易的提案,它会把这个提案发送给一系列的被要求的节点来获得背书。其中的每一个背书节点接下来都会独立地使用交易提案来执行链码,以此来生成这个交易提案的响应。这并没有将这次更新应用到账本上,只是简单地为它提供签名然后将它返回给应用程序**。当应用程序接收到有效数量的被签过名的提案响应之后,交易流程中的第一个阶段就结束了。让我们对这个阶段做更详细地研究。

交易提案会被 Peer 节点独立地执行,Peer 节点会返回经过背书的提案响应。在这个例子中,应用程序 A1 生成了交易 T1 和提案 P,应用程序会将交易及提案发送给通道 C 上的 Peer 节点 P1 和 Peer 节点 P2。P1 使用交易 T1 和 提案 P 来执行链码 S1,这会生成对交易 T1 的响应 R1,它会提供背书 E1。P2 使用交易 T1 提案 P 执行了链码 S1,这会生成对于交易 T1 的响应 R2,它会提供背书 E2。应用程序 A1 对于交易 T1 接收到了两个背书响应,称为 E1 和 E2。

最初,应用程序会选择一些 Peer 节点来生成一套关于账本更新的提案。应用程序会选择哪些 Peer 节点呢?这取决于背书策略(这是为链码定义的),这个策略定义了在一个账本提案能够被网络所接受之前,都需要哪些 Peer 节点需要对这个账本变更提案进行背书。这很明显就是为了实现共识——每一个需要的组织必须对账本更新的提案在被各个 Peer 节点同意更新到他们的账本之前,对这个提案进行背书。

Peer 节点通过向提案的响应添加自己的数字签名的方式提供背书,并且使用它的私钥为整个的负载提供签名。然后这个背书会被用于证明这个组织的 Peer 节点生成了一个特殊的响应。在我们的例子中,如果 Peer 节点 P1 是属于组织 Org1 的话,背书 E1 就相当于一个数字证明——”在账本 L1 上的交易 T1 的响应 R1 已经被 Org1 的 Peer 节点 P1 同意了!”。

第一阶段在当应用程序从足够多的有效的 Peer 节点那里收到了签过名的提案响应的时候就结束了。我们注意到了不同的 Peer 节点能够返回不同的响应,因此对于同一个交易提案应用程序可能会接收到不同的交易响应。这可能简简单单地因为这个结果是在不同的时间,不同的 Peer 节点以及基于不同状态的账本所产生的,在这个情况下,一个应用程序可以请求一个更新的提案响应。不太可能但是却非常严重的是,结果的不同可能会是因为链码是非确定性的。非确定性是链码和账本的敌人,并且如果它真的发生了的话,这代表着这个提案的交易存在一个很严重的问题,因为非一致的结果很明显是不能够被应用到账本上的。一个单独的 Peer 节点是无法知道他们的交易结果是非确定性的——在非确定性问题被发现之前,交易的响应必须要被搜集到一起来进行比较。(严格地说,尽管这个还不够,但是我们会把这个话题放在交易的部分来讨论,在那里非确定性会被讨论。)

在第一阶段的最后,应用程序可以自由地放弃不一致的交易响应,如果他们想这么做的话,就可以在早期有效地终结这个交易流程。我们接下来会看到如果应用程序尝试使用不一致的交易响应来更新账本的时候,这会被拒绝。

阶段2:排序和将交易打包到区块

交易流程的第二个阶段是打包阶段。排序节点是这个过程的关键——它接收交易,这些交易中包含了来自很多个应用的已经背书过的交易提案,并且将交易排序并打包进区块。关于排序和打包阶段的更多详细信息,查看我们的排序阶段的概念信息.

阶段3:验证和提交

在第二阶段末尾,我们看到了排序节点需要负责这个简单但是重要的搜集提案的交易变更,将他们排序,并且打包到区块中,让他们准备好分发给 Peer 节点的整个流程。

这个交易流程的最后一个阶段是分发以及接下来的对于从排序节点发送给 Peer 节点的区块的验证工作,这些区块最终会提交到账本中。具体来说,在每个 Peer 节点上,区块中的每笔交易都会被验证,以确保它在被提交到账本之前,已经被所有相关的组织一致地背书过了。失败的交易会被留下来方便审计,但是不会被提交到账本中。

排序节点的第二个角色是将区块分发给 Peer 节点。在这个例子中,排序节点 O1 将区块 B2 分发给了 Peer 节点 P1 和 Peer 节点 P2。Peer P1 处理了区块 B2,产生了一个会被添加到 P1 的账本 L1 中的新区块。同时,peer P2 处理了区块 B2,产生了一个会被添加到 P2 的账本 L1 中的新区块。当这个过程结束之后,账本 L1 就会被一致地更新到了 Peer 节点 P1 和 P2 上,他们也可能会通知所连接的应用程序关于这笔交易已经被处理过的消息。

阶段三是从排序节点将区块分发到所有与它连接的 Peer 节点开始的。Peer 节点会和通道中的排序节点相连,所有跟这个排序节点相连的 Peer 节点将会收到一个新的区块的副本。每个 Peer 节点会独立处理这个区块,但是会跟这个通道上的每一个其他 Peer 节点使用完全一致的方式处理。通过这种方式,我们会看到账本是会始终保持一致的。不是每个 Peer 节点都需要连接到排序节点——Peer 节点可以使用 gossip 协议将区块的信息发送给其他 Peer 节点,其他 Peer 节点也可以独立地处理这些区块。但是让我们把这个话题放在其他的时间来讨论吧!

当接到区块的时候,Peer 节点会按照区块中的顺序处理每笔交易。对于每一笔交易,每个 Peer 节点都会确认这笔交易已经根据产生这笔交易的链码中定义的背书策略由要求的组织进行过背书了。比如,在一些交易被认为是有效之前,这些交易可能仅仅需要一个组织的背书,但是其他的交易可能会需要多个背书。这个验证的流程确认了所有相关的组织已经生成了相同的产出或者结果。也需要注意到的是,这次的验证跟在阶段 1 中进行的背书检查是不同的,应用程序从背书节点那里接收到了交易的响应,然后做了决定来发送交易提案。如果应用程序违反了背书策略发送了错误的交易,那么 Peer 节点还是能够在阶段 3 中的验证流程里拒绝这笔交易

如果一笔交易被正确的背书,Peer 节点会尝试将它应用到账本中。为了做这个,Peer 节点必须要进行账本一致性检查来验证当前账本中的状态同应用了更新提案后的账本是能够兼容的。这可能不是每次都是有可行的,即使交易已经被完整地背书过了。比如,另外一笔交易可能会更新账本中的同一个资产,这样的话交易的更新就不会是有效的了,因此也就不会被应用。通过这种方式,账本在通道中的每个 Peer 节点都是保持一致的,因为他们中每个都在遵守相同的验证规则。

当 Peer 节点成功地验证每笔单独的交易之后,它就会更新账本了。失败的交易是不会应用到账本中的,但是他们会被保留为之后的审计使用,就像成功的交易那样。这意味着 Peer 节点中的区块几乎会跟从排序节点收到的区块是一样的,除了在区块中每笔交易中会带有有效或者无效的指示符。

我们也注意到了第三阶段并没有要求执行链码——那只会在第一阶段执行,这是很重要的。这意味着链码仅仅需要在背书节点中有效,而不需要在区块链网络的所有部分都要有。这个通常是很有帮助的,因为这保持了链码逻辑的机密性只有背书组织了解。这个同链码的输出(交易提案的响应)恰恰相反,这个输出会被分享给通道中的所有 Peer 节点,不管这些 Peer 节点是否为这交易提供背书。这个关于背书节点的特殊性是被设计用来帮助扩展性和保密性的。

最终,每次当区块被提交到 Peer 节点的账本的时候,那个 Peer 节点会生成一个合适的事件区块事件包括了整个区块的内容,然而区块交易事件仅仅包含了概要信息,比如是否在区块中的每笔交易是有效的还是无效的。链码已经被执行的链码事件也可以在这个时候公布出去。应用程序可以对这些事件类型进行注册,所以在这些事件发生的时候他们能够被通知到。这些通知结束了交易流程的第三以及最后的阶段。

总结来说,在第三阶段中看到了由排序节点生成的区块被一致地应用到了账本中。将交易严格地排序到区块中让每个 Peer 节点都来验证交易更新,并一致地应用到区块链网络中。

排序节点和共识

整个交易处理流程被称为共识,因为所有 Peer 节点在由排序节点提供的流程中对交易的排序及内容都达成了一致。共识是一个多步骤的流程,并且应用程序只会在这个流程结束的时候通知账本更新——这个在不同的 Peer 节点上可能在不同的时间会发生。

我们会在之后的排序节点话题中更详细地讨论排序节点,但是到目前为止,可以把排序节点理解为这样一些节点,它们从应用程序收集和分发账本更新提案以供 Peer 节点验证并写入账本中。

这就是所有内容了!我们完成了 Peer 节点以及在 Hyperledger Fabric 中他们相关联的其他组件的学习。我们看到了 Peer 节点在很多方面都是最基础的元素——他们构成了网络,维护链码和账本,处理交易提案和响应,并且通过一致地将交易更新到账本上来保持一个始终包含最新内容的账本。

智能合约和链码

从应用程序开发人员的角度来看,智能合约账本一起构成了 Hyperledger Fabric 区块链系统的核心。账本包含了与一组业务对象的当前和历史状态有关的事实,而智能合约定义了生成这些被添加到账本中的新事实的可执行逻辑。管理员通常使用链码将相关的智能合约组织起来进行部署,并且链码也可以用于 Fabric 的底层系统编程。在本主题中,我们将重点讨论为什么存在智能合约链码,以及如何和何时使用它们。

什么是智能合约

在各业务彼此进行交互之前,必须先定义一套通用的合约,其中包括通用术语、数据、规则、概念定义和流程。将这些合约放在一起,就构成了管理交易各方之间所有交互的业务模型

智能合约用可执行的代码定义了不同组织之间的规则。应用程序调用智能合约来生成被记录到账本上的交易。

使用区块链网络,我们可以将这些合约转换为可执行程序(业内称为智能合约),从而实现了各种各样的新可能性。这是因为智能合约可以为任何类型的业务对象实现治理规则,以便在执行智能合约时自动执行这些规则。例如,一个智能合约可能会确保新车在指定的时间内交付,或者根据预先安排的条款释放资金,前者可改善货物流通,而后者可优化资本流动。然而最重要的是,智能合约的执行要比人工业务流程高效得多。

在上图中,我们可以看到组织 ORG1ORG2 是如何通过定义一个 car 智能合约来实现 查询转移更新 汽车的。来自这些组织的应用程序调用此智能合约执行业务流程中已商定的步骤,例如将特定汽车的所有权从 ORG1 转移到 ORG2

术语说明

Hyperledger Fabric 用户经常交替使用智能合约链码。通常,智能合约定义的是控制世界状态中业务对象生命周期的交易逻辑,随后该交易逻辑被打包进链码,紧接着链码会被部署到区块链网络中。可以将智能合约看成交易的管理者,而链码则管理着如何将智能合约打包以便用于部署。

一个智能合约定义在一个链码中。而多个智能合约也可以定义在同一个链码中。当一个链码部署完毕,该链码中的所有智能合约都可供应用程序使用。

从上图中我们可以看到,vehicle 链码包含了以下三个智能合约:carsboatstrucks;而 insurance 链码包含了以下四个智能合约:policyliabilitysyndicationsecuritization。以上每种智能合约都涵盖了与车辆和保险有关的业务流程的一些关键点。在本主题中,我们将以 car 智能合约为例。我们可以看到,智能合约是一个特定领域的程序,它与特定的业务流程相关,而链码则是一组相关智能合约安装和实例化的技术容器

智能合约和账本

以最简单的方式来说,区块链记录着更新账本状态的交易,且记录不可篡改。智能合约以编程方式访问账本两个不同的部分:一个是区块链(记录所有交易的历史,且记录不可篡改),另一个是世界状态(保存这些状态当前值的缓存,是经常需要用到的对象的当前值)。

智能合约主要在世界状态中将状态写入(put)、读取(get)和删除(delete),还可以查询不可篡改的区块链交易记录。

  • 读取(get) 操作一般代表的是查询,目的是获取关于交易对象当前状态的信息。
  • 写入(put) 操作通常生成一个新的业务对象或者对账本世界状态中现有的业务对象进行修改。
  • 删除(delete) 操作代表的是将一个业务对象从账本的当前状态中移除,但不从账本的历史中移除

智能合约有许多可用的 API。但重要的是,在任何情况下,无论交易创建、读取、更新还是删除世界状态中的业务对象,区块链都包含了这些操作的记录,且记录不可更改

怎么开发一个智能合约

智能合约是应用程序开发的重点,正如我们所看到的,一个链码中可定义一个或多个智能合约。将链码部署到网络中以后,网络上的组织就都可以使用该链码中的所有智能合约。这意味着只有管理员才需要考虑链码;其他人都只用考虑智能合约。

智能合约的核心是一组 交易 定义。例如,在 fabcar.js 中可以看到一个创建了一辆新车的智能合约交易:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
async createCar(ctx, carNumber, make, model, color, owner) {

    const car = {
        color,
        docType: 'car',
        make,
        model,
        owner,
    };

    await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
}

编写您的第一个应用程序 教程中,可以了解更多关于 Fabcar 智能合约的信息。

智能合约几乎可以描述所有与多组织决策中数据不可变性相关的业务案例。智能合约开发人员的工作是将一个现有的业务流程(可能是管理金融价格或交付条件)用 JavaScript、GOLANG 或 Java 等编程语言来表示成一个智能合约。将数百年的法律语言转换为编程语言需要法律和技术方面的技能,智能合约审核员们不断地实践着这些技能。您可以在开发应用主题中了解如何设计和开发智能合约。

背书策略的重要性

每个链码都有一个背书策略与之相关联,该背书策略适用于此链码中定义的所有智能合约。背书策略非常重要,它指明了区块链网络中哪些组织必须对一个给定的智能合约所生成的交易进行签名,以此来宣布该交易有效

每个智能合约都有一个与之关联的背书策略。这个背书策略定义了在智能合约生成的交易被认证为有效之前,哪些组织必须同意该交易。

一个示例背书策略可能这样定义:参与区块链网络的四个组织中有三个必须在交易被认为有效之前签署该交易。所有的交易,无论是有效的还是无效的,都会被添加到分布式账本中,但只有有效交易会更新世界状态。

如果一项背书策略指定了必须有不止一个组织来签署交易,那么只有当足够数量的组织都执行了智能合约,才能够生成有效交易。在上面的示例中,要使用于车辆 transfer 的智能合约交易有效,需要 ORG1ORG2 都执行并签署该交易。

背书策略是 Hyperledger Fabric 与以太坊(Ethereum)或比特币(Bitcoin)等其他区块链的区别所在。在这些区块链系统中,网络上的任何节点都可以生成有效的交易。而 Hyperledger Fabric 更真实地模拟了现实世界;交易必须由 Fabric 网络中受信任的组织验证。例如,一个政府组织必须签署一个有效的 issueIdentity 交易,或者一辆车的 买家卖家 都必须签署一个 车辆 转移交易。背书策略的设计旨在让 Hyperledger Fabric 更好地模拟这些真实发生的交互。

最后,背书策略只是 Hyperledger Fabric 中策略的一个例子。还可以定义其他策略来确定谁可以查询或更新账本,或者谁可以在网络中添加或删除参与者。总体来说,虽然区块链网络中的组织联盟并非一成不变,但是它们需要事先商定好策略。实际上,策略本身可以定义对自己进行更改的规则。虽然现在谈论这个主题有点早,但是在 Fabric 提供的规则基础上来定义自定义背书策略的规则也是可能实现的。

有效交易

当智能合约执行时,它会在区块链网络中的组织所拥有的节点上运行。智能合约提取一组名为交易提案的输入参数,并将其与程序逻辑结合起来使用以读写账本。对世界状态的更改被捕获为交易提案响应(或简称交易响应),该响应包含一个读写集,其中既含有已读取的状态,也含有还未书写的新状态(如果交易有效的话)。注意,在执行智能合约时世界状态没有更新

所有的交易都有一个识别符、一个提案和一个被一群组织签名的响应。所有交易,无论是否有效,都会被记录在区块链上,但仅有效交易会更新世界状态。

检查 车辆转移 交易。您可以看到 ORG1ORG2 之间为转移一辆车而进行的交易 t3。看一下交易是如何通过输入 {CAR1,ORG1,ORG2} 和输出 {CAR1.owner=ORG1,CAR1.owner=ORG2} 来表示汽车的所有者从 ORG1 变为了 ORG2。注意输入是如何由应用程序的组织 ORG1 签名的,输出是如何由背书策略标识的两个组织( ORG1ORG2 )签名的。这些签名是使用每个参与者的私钥生成的,这意味着网络中的任何人都可以验证网络中的所有参与者是否在交易细节上达成了一致。

一项交易被分发给网络中的所有节点,各节点通过两个阶段对其进行验证。首先,根据背书策略检查交易,确保该交易已被足够的组织签署。其次,继续检查交易,以确保当该交易在受到背书节点签名时它的交易读集与世界状态的当前值匹配,并且中间过程中没有被更新。如果一个交易通过了这两个测试,它就被标记为有效。所有交易,不管是有效的还是无效的,都会被添加到区块链历史中,但是仅有效的交易才会更新世界状态。

在我们的示例中,t3 是一个有效的交易,因此 CAR1 的所有者已更新为 ORG2。但是 t4 (未显示)是无效的交易,所以当把它记录在账本上时,世界状态没有更新,CAR2 仍然属于 ORG2 所有。

最后,要了解如何通过世界状态来使用智能合约或链码,请阅读链码命名空间主题

通道和链码的定义

Hyperledger Fabric 允许一个组织利用通道同时参与多个、彼此独立的区块链网络。通过加入多个通道,一个组织可以参与一个所谓的网络的网络。通道在维持数据和通信隐私的同时还提供了高效的基础设施共享。通道是足够独立的,可以帮助组织将自己的工作与其他组织的分开,同时它还具有足够的协调性,在必要时能够协调各个独立的活动。

通道在一群组织之间提供了一种完全独立的通信机制。当链码定义被提交到通道上时,该通道上所有的应用程序都可以使用此链码中的智能合约。

虽然智能合约代码被安装在组织节点的链码包内,但是只有等到链码被定义在通道上之后,该通道上的成员才能够执行其中的智能合约。链码定义是一种包含了许多参数的结构,这些参数管理着链码的运行方式,包含着链码名、版本以及背书策略。各通道成员批准各自组织的一个链码定义,以表示其对该链码的参数表示同意。当足够数量(默认是大多数)的组织都已批准同一个链码定义,该定义可被提交至这些组织所在的通道。随后,通道成员可依据该链码定义中指明的背书策略来执行其中的智能合约。这个背书策略可同等使用于在相同链码中定义的所有智能合约。

在上面的示例中,car 智能合约被定义在 VEHICLE 通道上,insurance 智能合约被定义在 INSURANCE 通道上。car 的链码定义明确了以下背书策略:任何交易在被认定为有效之前必须由 ORG1ORG2 共同签名。insurance 智能合约的链码定义明确了只需要 ORG3 对交易进行背书即可。ORG1 参与了 VEHICLE 通道和 INSURANCE 通道这两个网络,并且能够跨网络协调与 ORG2ORG3 的活动。

链码的定义为通道成员提供了一种他们在通道上使用智能合约来交易之前,同意对于一个链码的管理的方式。在上边的例子中,ORG1ORG2 想要为调用 car 智能合约的交易背书。因为默认的背书策略要求大多数组织需要批准一个链码的定义,双方的组织需要批准一个 AND{ORG1,ORG2} 的背书策略。否则的话,ORG1ORG2 将会批准不同的链码定义,并且最终不能够将链码定义提交到通道。这个流程确保了一个来自于 car 智能合约的交易需要被两个组织批准。

智能合约之间的通信

一个智能合约既可以调用同通道上的其他智能合约,也可以调用其他通道上的智能合约。这样一来,智能合约就可以读写原本因为智能合约命名空间而无法访问的世界状态数据。

这些都是智能合约彼此通信的限制,我们将在链码命名空间主题中详细描述。

什么是系统链码

链码中定义的智能合约为一群区块链组织共同认可的业务流程编码了领域相关规则。然而,链码还可以定义低级别程序代码,这些代码是无关于领域的系统交互,但与业务流程的智能合约无关。

以下是不同类型的系统链码及其相关缩写:

  • 生命周期 在所有 Peer 节点上运行,它负责管理节点上的链码安装、批准组织的链码定义、将链码定义提交到通道上。 你可以了解更多生命周期是如何实现 Fabric 链码声明周期过程的。
  • 生命周期系统链码(LSCC) 负责为 1.x 版本的 Fabric 管理链码生命周期。该版本的生命周期要求在通道上实例化或升级链码。你可以阅读更多关于 LSCC 如何实现这一过程。如果你的 V1_4_x 或更低版本设有通道应用程序的功能,那么你也可以使用 LSCC 来管理链码。
  • 配置系统链码(CSCC) 在所有 Peer 节点上运行,以处理通道配置的变化,比如策略更新。你可以在这里阅读更多 CSCC 实现的内容。
  • 查询系统链码(QSCC) 在所有 Peer 节点上运行,以提供账本 API(应用程序编码接口),其中包括区块查询、交易查询等。你可以在交易场景主题中查阅更多这些账本 API 的信息。
  • 背书系统链码(ESCC) 在背书节点上运行,对一个交易响应进行密码签名。你可以在这里阅读更多 ESCC 实现的内容。
  • 验证系统链码(VSCC) 验证一个交易,包括检查背书策略和读写集版本。你可以在这里阅读更多 VSCC 实现的内容。

底层的 Fabric 开发人员和管理员可以根据自己的需要修改这些系统链码。然而,系统链码的开发和管理是一项专门的活动,完全独立于智能合约的开发,通常没有必要进行系统链码的开发和管理。系统链码对于一个 Hyperledger Fabric 网络的正常运行至关重要,因此必须非常小心地处理系统链码的更改。例如,如果没有正确地开发系统链码,那么有可能某个 Peer 节点更新的世界状态或区块链备份与其他 Peer 节点的不同。这种缺乏共识的现象是账本分叉的一种形式,是极不理想的情况。

账本

账本是 Hyperledger Fabric 中的一个重要概念,它存储了有关业务对象的重要事实信息,其中既包括对象属性的当前值,也包括产生这些当前值的交易的历史。

什么是账本

账本记录着业务的当前状态,它就像一个交易日记。欧洲和中国最早的账本可以追溯到近 1000 年前,苏美尔人在 4000 年前就已经有石制账本了,不过我们还是从离我们最近的例子开始讲吧!

你可能已经习惯查看你的银行账户了。对你来说,最重要的是账户余额,它是你当时就能花的钱。如果你想看看你的余额是如何产生的,可以浏览一下相关的交易收入和支出。这是现实生活中的一个账本的示例——一个状态(您的银行余额)和一组促成该状态的有序交易(收入和支出)。Hyperledger Fabric 也致力于这两个方面,它旨在呈现一组账本状态的当前值,同时记录下促成了以上账本状态的交易的历史。

存储业务对象的事实

账本储存的其实并不是业务对象本身,而是与业务对象相关的事实信息。当我们说“我们在账本中存储一个业务对象”时,其实是说我们正在记录与一个业务对象当前状态有关的事实,以及与促成这一当前状态的交易历史相关的事实。在一个日益数字化的世界里,我们感觉自己正在看的是一个物体本身,而不是关于这个物体的一些事实。对于数字对象来说,它可能位于一个外部数据库,但通过我们储存在账本中有关该对象的事实就能够识别出该数字对象的所在位置以及其他与之相关的关键信息。

虽然与业务对象当前状态相关的事实可能会发生改变,但是与之相关的事实历史是不可变的,我们可以在事实历史上增加新的事实,但无法更改历史中已经存在的事实。我们将看到,如果把区块链看作是与业务对象有关的事实历史,且该历史是不可更改的,那么我们就能够很轻松、高效地理解区块链。

现在我们来深入探讨一下 Hyperledger Fabric 的账本结构!

区块链账本

Hyperledger Fabric 中的账本由“世界状态“和”区块链“这两部分组成,它们彼此不同但却相互关联。二者都代表了与业务对象有关的一些事实。

首先,世界状态是一个数据库,它存储了一组账本状态的当前值。通过世界状态,程序可以直接访问一个账本状态的当前值,不需要遍历整个交易日志来计算当前值。默认情况下,账本状态是以键值对的方式来表示的,稍后我们将看到 Hyperledger Fabric 如何提供这一方面的灵活性。因为我们可以创建、更新和删除状态,所以世界状态能够频繁更改。

其次,区块链是交易日志,它记录了促成当前世界状态的所有改变。交易被收集在附加到区块链的区块中,能帮助我们理解所有促成当前世界状态的改变的历史。区块链数据结构与世界状态相差甚远,因为一旦把数据写入区块链,就无法修改,它是不可篡改的

账本 L 由区块链 B 和世界状态 W 组成,其中世界状态 W 由区块链 B 决定。我们也可以说世界状态 W 是源自区块链 B。

为帮助理解,可以这样认为:Hyperledger Fabric 网络中存在一个逻辑账本。实际上,Fabric 网络维护着一个账本的多个副本,这些副本通过名为共识的过程来与其他副本保持一致。分布式账本技术(DLT)这个术语经常与这种账本联系在一起,这种账本在逻辑上是单个的,但是在整个网络中却分布着许多彼此一致的副本。

现在让我们更细致地研究一下世界状态和区块链数据结构。

世界状态

世界状态将业务对象属性的当前值保存为唯一的账本状态。这很有用,因为程序通常需要对象的当前值,如果遍历整个区块链来计算对象的当前值会很麻烦——从世界状态中可以直接获取当前值。

一个账本世界状态包含两个状态。第一个状态是: key=CAR1 和 value=Audi。第二个状态中有一个更复杂的值:key=CAR2 和 value={model:BMW, color=red, owner=Jane} 。两个状态的版本都是0。

账本状态记录了一组与特定业务对象有关的事实。我们的示例展示的是 CAR1 和 CAR2 这两辆车的账本状态,二者都各有一个值和一个键。应用程序可以调用智能合约,该合约使用简单的账本 API 来获取写入删除状态。注意状态值可以是简单值(Audi…),也可以是复合值(type:BMW…)。经常会通过查询世界状态来检索具有某些特定属性的对象,例如查找所有红色宝马汽车。

世界状态被作为数据库来实现。这一点很有意义,因为数据库为有效存储和状态检索提供了充分的算子。稍后我们将看到,我们可以将 Hyperledger Fabric 配置为使用不同的世界状态数据库来满足以下需求:不同类型的状态值,应用程序所需的访问模式,例如,当遇到复杂查询的情况时。

应用程序提交那些会更改世界状态的交易,这些交易最终被提交到账本区块链上。应用程序无法看到 Hyperledger Fabric SDK(软件开发工具包)设定的共识机制的细节内容,它们能做的只是调用智能合约以及在交易被收进区块链时收到通知(所有被提交的交易,无论有效与否,都会被收进区块链)。Hyperledger Fabric 的关键设计在于,只有那些受到相关背书组织签名的交易才会更新世界状态。如果一个交易没有得到足够背书节点的签名,那么它不会更新世界状态。您可以阅读更多关于应用程序如何使用智能合约以及如何开发应用程序的信息。

您还会注意到,每个状态都有一个版本号,在上面的图表中,状态 CAR1 和 CAR2 都处于它们的初始版本 0。版本号是供 Hyperledger Fabric 内部使用的,并且每次状态更改时版本号会发生递增。每当更新状态时,都会检查该状态的版本,以确保当前状态与背书时的版本相匹配。这就确保了世界状态是按照预期进行更新的,没有发生并发更新。

最后,首次创建账本时,世界状态是空的。因为区块链上记录了所有代表有效世界状态更新的交易,所以任何时候都可以从区块链中重新生成世界状态。这样一来就变得非常方便,例如,创建节点时会自动生成世界状态。此外,如果某个节点发生异常,重启该节点时能够在接受交易之前重新生成世界状态。

区块链数据结构

现在让我们把注意力从世界状态转移到区块链上。世界状态存储了与业务对象当前状态相关的事实信息,而区块链是一种历史记录,它记录了这些业务对象是如何到达各自当前状态的相关事实。区块链记录了每个账本状态之前的所有版本以及状态是如何被更改的。

区块链的结构是一群相互链接的区块的序列化日志,其中每个区块都包含一系列交易各项交易代表了一个对世界状态进行的查询或更新操作。我们在其他地方讨论了排序交易的确切机制;其中重要的是区块排序以及区块内的交易排序,这一机制是在 Hyperledger Fabric 的排序服务组件首次创建区块时被建立起来的。

每个区块的头部都包含区块交易的一个哈希,以及前一个区块头的哈希。这样一来,账本上的所有交易都被按序排列,并以密码方式连接在一起。这种哈希和链接使账本数据变得非常安全。即使某个保存账本的节点被篡改了,该节点也无法让其他节点相信自己拥有“正确的”区块链,这是因为账本被分布在一个由独立节点组成的网络中。

区块链总是以文件实现,而与之相反的是,世界状态以数据库实现。这是一个明智的设计,因为区块链数据结构高度偏向于非常小的一组简单操作。第一项操作被放在区块链的末尾,就目前来说,查询操作相对少见。

让我们更详细地看看区块链的结构。

区块链 B 包含了 B0、B1、B2、B3这四个区块。B0 是该区块链的第一个区块,也叫创世区块。

在上面的图中我们可以看到,区块 B2 有一个区块数据 D2,该数据包含了 B2 的所有交易:T5、T6、T7。

最重要的是,B2 有一个区块头 H2,H2 包含了 D2 中所有交易的加密哈希以及前一个区块中 H1 的一个哈希。这样一来,所有区块彼此紧密相连,不可篡改,术语区块链很好地描述了这一点!

最后,如图所示,区块链中的第一个区块被称为创世区块。虽然它并不包含任何用户交易,但却是账本的起始点。相反的,创世区块包含了一个配置交易,该交易含有网络配置(未显示)的初始状态。我们将会在讨论区块链网络和 通道 时更详细地探讨初始区块

区块

让我们仔细看看区块的结构。它由三个部分组成

  • 区块头

    这个部分包含三个字段,这些字段是在创建一个区块时候被写入的。

    • 区块编号:编号从0(初始区块)开始,每在区块链上增加一个新区块,编号的数字都会加1。
    • 当前区块的哈希值:当前区块中包含的所有交易的哈希值。
    • 前一个区块头的哈希值:区块链中前一个区块头的哈希值。

    这些字段是通过在内部对区块数据进行加密哈希而生成的。它们确保了每一个区块和与之相邻的其他区块紧密相连,从而组成一个不可更改的账本。

  • 区块头详情:区块 B2 的区块头 H2 包含了区块编号 2,当前区块数据 D2 的哈希值 CH2,以及前一个区块头 H1 的哈希值。

  • 区块数据

    这部分包含了一个有序的交易列表。区块数据是在排序服务创建区块时被写入的。这些交易的结构很复杂但也很直接,我们会在后边进行讲解。

  • 区块元数据

    这个部分包含了区块被写入的时间,还有区块写入者的证书、公钥以及签名。随后,区块的提交者也会为每一笔交易添加一个有效或无效的标记,但由于这一信息与区块同时产生,所以它不会被包含在哈希中。

交易

正如我们所看到的,交易记录了世界状态发生的更新。让我们来详细了解一下这种把交易包含在区块中的区块数据结构。

交易详情:交易 T4 位于区块 B1 的区块数据 D1 中,T4包括的内容如下:交易头 H4,一个交易签名 S4,一个交易提案 P4,一个交易响应 R4 和一系列背书 E4。

在上面的例子中,我们可以看到以下字段:

  • 这部分用 H4 表示,它记录了关于交易的一些重要元数据,比如,相关链码的名字以及版本。

  • 签名

    这部分用 S4 表示,它包含了一个由客户端应用程序创建的加密签名。该字段是用来检查交易细节是否未经篡改,因为交易签名的生成需要用到应用程序的私钥。

  • 提案

    这部分用 P4 表示,它负责对应用程序供给智能合约的输入参数进行编码,随后该智能合约生成提案账本更新。在智能合约运行时,这个提案提供了一套输入参数,这些参数同当前的世界状态一起决定了新的账本世界状态。

  • 响应

    这部分用 R4 表示,它是以读写集 (RW-set)的形式记录下世界状态之前和之后的值。交易响应是智能合约的输出,如果交易验证成功,那么该交易会被应用到账本上,从而更新世界状态。

  • 背书

    就像 E4 显示的那样,它指的是一组签名交易响应,这些签名都来自背书策略规定的相关组织,并且这些组织的数量必须满足背书策略的要求。你会注意到,虽然交易中包含了多个背书,但它却只有一个交易响应。这是因为每个背书都对组织特定的交易响应进行了有效编码,那些不完全满足背书的交易响应肯定会遭到拒绝、被视为无效,而且它们也不会更新世界状态,所以没必要放进交易中。

    在交易中只包含一个交易响应,但是会有多个背书。这是因为每个背书包含了它的组织特定的交易响应,这意味着不需要包含任何没有有效的背书的交易响应,因为它会被作为无效的交易被拒绝,并且不会更新世界状态。

以上总结了交易的一些主要字段,其实还有其他字段,但是上述几种是您需要了解的基本字段,便于您对账本数据结构有一个很好的了解。

世界状态数据库选项

世界状态是以数据库的形式实现的,旨在提供简单有效的账本状态存储和检索。正如我们所看到的,账本状态可包含简单值或复合值,为了适应这一点,世界状态数据库可以多种形式实现,从而对这些值进行有效实现。目前,世界状态数据库的选项包括 LevelDB 和 CouchDB 。

LevelDB 是世界状态数据库的默认选项,当账本状态是简单的键值对时,使用 LevelDB 非常合适。LevelDB 数据库与 peer 节点位于相同位置,它被嵌入与 peer 节点相同的操作系统进程中。

当账本状态结构为 JSON 文档时,以 CouchDB 来实现世界状态非常合适,这是因为业务交易涉及的数据类型通常十分丰富,而 CouchDB 可支持对这些数据类型进行各种形式的查询和更新。在实现方面,CouchDB 是在单独的操作系统进程中运行的,但是节点和 CouchDB 实例之间仍然存在1:1的关系。智能合约无法看到上述任何内容。有关 CouchDB 的更多信息,请参见 CouchDB 作为状态数据库

在 LevelDB 和 CouchDB 中,我们看到了 Hyperledger Fabric 的一个重要方面——它是可插拔的。世界状态数据库可以是关系数据存储、图形存储或时态数据库。这极大提升了可被有效访问的账本状态类型的灵活性,使得 Hyperledger Fabric 能够处理多种不同类型的问题。

Fabcar示例账本

关于账本的讨论即将结束,让我们来看一个示例账本。如果您已经运行了 fabcar 示例应用程序,那么您就已经创建了这个账本。

fabcar 示例应用程序创建了 10 辆车,每辆车都有独一无二的身份;它们有不同的颜色,制造商,型号和拥有者。以下是前四辆车创建后的账本。

账本 L包含了一个世界状态 W 和一个区块链 B。其中 W 包含了四个状态,各状态的键分别是:CAR0,CAR1,CAR2 和 CAR3 。而 B 包含了两个区块 0和 1。区块1包含了四笔交易:T1,T2,T3,T4。

我们可以看到世界状态包含了对应于 CAR0、CAR1、CAR2 和 CAR3 的状态。CAR0 中包含的值表明了这是一辆蓝色的丰田普锐斯(Toyota Prius),目前车主是 Tomoko,其他车辆的的状态和值也与此类似。此外,我们还可以看到所有车辆状态的版本号都是0,这是它们的初始版本号,也就是说这些车辆状态自创建以来一直没有被更新过。

我们还可以看到区块链包含两个区块。其中区块0是创世区块,但它并不包含任何与汽车相关的交易。而区块1包含交易 T1、T2、T3、T4,这些交易与生成世界状态中 CAR0 到 CAR3 这四辆车初始状态的交易相符。同时区块1与区块0是相连的。

我们没有介绍区块或交易中的其他字段,特别是(区块/交易)头和哈希,如果你对这部分内容感兴趣的话,可以阅读文件中的其他部分。读完后你会对整个区块和交易有更加透彻的认识,但现在,你对 Hyperledger Fabric 账本的概念已经足够了解了。很好!

账本和命名空间

上文中我们讨论账本时,似乎它只包括一个世界状态和一条区块链,但这显然过于简单化了。实际上,每个链码都有自己的世界状态,并且与所有其他链码的世界状态分离。世界状态位于一个命名空间中,因此只有位于同一链码中的智能合约才能访问一个给定的命名空间。

区块链没有命名空间。它包含来自许多不同智能合约命名空间的交易。您可以在此主题中阅读更多关于链码命名空间的信息。

现在让我们看看命名空间的概念是如何被应用到 Hyperledger Fabric 通道中的。

账本和通道

在 Hyperledger Fabric 中,每个通道都有一个完全独立的账本。这意味着完全独立的区块链和完全独立的世界状态,包括命名空间。应用程序和智能合约可以在通道之间通信,以便在通道间访问账本信息。

在本主题中,您可以阅读更多关于账本如何与通道一起工作的信息。

排序服务

本主题将概念性的介绍排序的概念排序节点是如何与 Peer 节点交互的、它们在交易流程中如何所发挥作用以及当前可用的排序服务的实现方式,尤其关注建议的 Raft 排序服务实现。

什么是排序

许多分布式区块链,如以太坊(Ethereum)和比特币(Bitcoin),都是非许可的,这意味着任何节点都可以参与共识过程,在共识过程中,交易被排序并打包成区块。因此,这些系统依靠概率共识算法最终保证账本一致性高的概率,但仍容易受到不同的账本(有时也称为一个账本“分叉”),在网络中不同的参与者对于交易顺序有不同的观点。

Hyperledger Fabric 的工作方式不同。它有一种称为排序节点的节点使交易有序,并与其他排序节点一起形成一个排序服务。因为 Fabric 的设计依赖于确定性的共识算法,所以 Peer 节点所验证的区块都是最终的和正确的。账本不会像其他分布式的以及无需许可的区块链中那样产生分叉

除了促进确定性之外,排序节点还将链码执行的背书(发生在节点)与排序分离,这在性能和可伸缩性方面给 Fabric 提供了优势,消除了由同一个节点执行和排序时可能出现的瓶颈。

排序节点和通道配置

除了排序角色之外,排序节点还维护着允许创建通道的组织列表。此组织列表称为**“联盟”**,列表本身保存在“排序节点系统通道”(也称为“排序系统通道”)的配置中。默认情况下,此列表及其所在的通道只能由排序节点管理员编辑。请注意,排序服务可以保存这些列表中的几个,这使得联盟成为 Fabric 多租户的载体。

排序节点还对通道执行基本访问控制,限制谁可以读写数据,以及谁可以配置数据。请记住,谁有权修改通道中的配置元素取决于相关管理员在创建联盟或通道时设置的策略。配置交易由排序节点处理,因为它需要知道当前的策略集合,并根据策略来执行其基本的访问控制。在这种情况下,排序节点处理配置更新,以确保请求者拥有正确的管理权限。如果有权限,排序节点将根据现有配置验证更新请求,生成一个新的配置交易,并将其打包到一个区块中,该区块将转发给通道上的所有节点。然后节点处理配置交易,以验证排序节点批准的修改确实满足通道中定义的策略。

排序节点和身份

与区块链网络交互的所有东西,包括节点、应用程序、管理员和排序节点,都从它们的数字证书和成员服务提供者(MSP)定义中获取它们的组织身份。

有关身份和 MSP 的更多信息,请查看我们关于身份成员的文档。

与 Peer 节点一样,排序节点属于组织。也应该像 Peer 节点一样为每个组织使用单独的证书授权中心(CA)。这个 CA 是否将作为根 CA 发挥作用,或者您是否选择部署根 CA,然后部署与该根 CA 关联的中间 CA,这取决于您。

排序节点和交易流程

阶段一:提案

从我们对 Peer 节点 的讨论中,我们已经看到它们构成了区块链网络的基础,托管账本,应用程序可以通过智能合约查询和更新这些账本。

具体来说,更新账本的应用程序涉及到三个阶段,该过程确保区块链网络中的所有节点保持它们的账本彼此一致。

在第一阶段,客户端应用程序将交易提案发送给一组节点,这些节点将调用智能合约来生成一个账本更新提案,然后背书该结果。背书节点此时不将提案中的更新应用于其账本副本。相反,背书节点将向客户端应用程序返回一个提案响应。已背书的交易提案最终将在第二阶段经过排序生成区块,然后在第三阶段分发给所有节点进行最终验证和提交。

要深入了解第一个阶段,请参阅Peer 节点主题。

阶段二:将交易排序并打包到区块中

在完成交易的第一阶段之后,客户端应用程序已经从一组节点接收到一个经过背书的交易提案响应。现在是交易的第二阶段。

在此阶段,应用程序客户端把包含已背书交易提案响应的交易提交到排序服务节点。排序服务创建交易区块,这些交易区块最终将分发给通道上的所有 Peer 节点,以便在第三阶段进行最终验证和提交。

排序服务节点同时接收来自许多不同应用程序客户端的交易。这些排序服务节点一起工作,共同组成排序服务。它的工作是将提交的交易按定义好的顺序安排成批次,并将它们打包成区块。这些区块将成为区块链的区块

区块中的交易数量取决于区块的期望大小最大间隔时间相关的通道配置参数(确切地说,是 BatchSizeBatchTimeout 参数)。然后将这些区块保存到排序节点的账本中,并分发给已经加入通道的所有节点。如果此时恰好有一个 Peer 节点关闭,或者稍后加入通道,它将在重新连接到排序服务节点或与另一个 Peer 节点通信之后接收到这些区块。我们将在第三阶段看到节点如何处理这个区块。

排序节点的第一个角色是打包提案的账本更新。在本例中,应用程序 A1 向排序节点 O1 发送由 E1 和 E2 背书的交易 T1。同时,应用程序 A2 将 E1 背书的交易 T2 发送给排序节点 O1。O1 将来自应用程序 A1 的交易 T1 和来自应用程序 A2 的交易 T2 以及来自网络中其他应用程序的交易打包到区块 B2 中。我们可以看到,在 B2 中,交易顺序是 T1、T2、T3、T4、T6、T5,但这可能不是这些交易到达排序节点的顺序!(这个例子显示了一个非常简单的排序服务配置,只有一个排序节点。)

值得注意的是,一个区块中交易的顺序不一定与排序服务接收的顺序相同,因为可能有多个排序服务节点几乎同时接收交易。重要的是,排序服务将交易放入严格的顺序中,并且 Peer 节点在验证和提交交易时将使用这个顺序。

区块内交易的严格排序使得 Hyperledger Fabric 与其他区块链稍有不同,在其他区块链中,相同的交易可以被打包成多个不同的区块,从而形成一个链。在 Hyperledger Fabric 中,由排序服务生成的区块是最终的。一旦一笔交易被写进一个区块,它在账本中的地位就得到了保证。正如我们前面所说,Hyperledger Fabric 的最终性意味着没有账本分叉,也就是说,经过验证的交易永远不会被重写或删除

我们还可以看到,虽然Peer节点执行智能合约并处理交易,而排序节点不会这样做。到达排序节点的每个授权交易都被机械地打包在一个区块中,排序节点不判断交易的内容(前面提到的通道配置交易除外)

在第二阶段的最后,我们看到排序节点负责一些简单但重要的过程,包括收集已提案的交易更新、排序并将它们打包成区块、准备分发

阶段三:验证和提交

交易工作流的第三个阶段涉及到从排序节点到 Peer 节点的区块的分发和随后的验证,这些区块可能会被提交到账本中。

第三阶段排序节点将区块分发给连接到它的所有 Peer 节点开始。同样值得注意的是,并不是每个 Peer 节点都需要连接到一个排序节点,Peer 节点可以使用 gossip 协议 将区块关联到其他节点。

每个节点将独立地以确定的方式验证区块,以确保账本保持一致。具体来说,通道中每个 节点都将验证区块中的每个交易,以确保得到了所需组织的节点背书,也就是节点的背书和背书策略相匹配,并且不会因最初认可该事务时可能正在运行的其他最近提交的事务而失效。无效的交易仍然保留在排序节点创建的区块中,但是节点将它们标记为无效,并且不更新账本的状态

排序节点的第二个角色是将区块分发给 Peer 节点。在本例中,排序节点 O1 将区块 B2 分配给节点 P1 和 P2。节点 P1 处理区块 B2,在 P1 上的账本 L1 中添加一个新区块。同时,节点 P2 处理区块 B2,从而将一个新区块添加到 P2 上的账本 L1中。一旦这个过程完成,节点 P1 和 P2 上的账本 L1 就会保持一致的更新,并且每个节点都可以通知与之连接的应用程序交易已经被处理。

总之,第三阶段看到的是由排序服务生成的区块一致地应用于账本。将交易严格地按区块排序,允许每个节点验证交易更新是否在整个区块链网络上一致地应用。

要更深入地了解阶段三,请参阅节点主题。

排序服务实现

虽然当前可用的每个排序服务都以相同的方式处理交易和配置更新,但是仍然有几种不同的实现可以在排序服务节点之间就严格的交易排序达成共识。

有关如何建立排序节点(无论该节点将在什么实现中使用)的信息,请参阅关于建立排序节点的文档。

  • Raft (推荐)

    作为 v1.4.1 的新特性,Raft 是一种基于 etcdRaft 协议实现的崩溃容错(Crash Fault Tolerant,CFT)排序服务。Raft 遵循“领导者跟随者”模型,这个模型中,在每个通道上选举领导者节点,其决策被跟随者复制。Raft 排序服务会比基于 Kafka 的排序服务更容易设置和管理,它的设计允许不同的组织为分布式排序服务贡献节点。

  • Kafka (在 v2.0 中被弃用)

    和基于 Raft 的排序类似,Apache Kafka 是一个 CFT 的实现,它使用“领导者和跟随者”节点配置。Kafka 利用一个 ZooKeeper 进行管理。基于 Kafka 的排序服务从 Fabric v1.0 开始就可以使用,但许多用户可能会发现管理 Kafka 集群的额外管理开销令人生畏或不受欢迎

  • Solo (在 v2.0 中被弃用)

    排序服务的 Solo 实现仅仅是为了测试,并且只包含了一个单一的排序节点。它已经被弃用了,可能会在将来的版本中被完全移除。既存的 Solo 用户应该迁移到一个单一节点的 Raft 网络获得同样的功能。

Raft

有关如何配置 Raft 排序服务的信息,请参阅有关配置 Raft 排序服务的文档。

对于将用于生产网络的排序服务,Fabric 实现了使用“领导者跟随者”模型的 Raft 协议,领导者是在一个通道的排序节点中动态选择的(这个集合的节点称为“共识者集合(consenter set)”),领导者将信息复制到跟随者节点。Raft 被称为“崩溃容错”是因为系统可以承受节点的损失,包括领导者节点,前提是要剩余大量的排序节点(称为“法定人数(quorum)”)。换句话说,如果一个通道中有三个节点,它可以承受一个节点的丢失(剩下两个节点)。如果一个通道中有五个节点,则可以丢失两个节点(剩下三个节点)。

从它们提供给网络或通道的服务的角度来看,Raft 和现有的基于 Kafka 的排序服务(我们将在稍后讨论)是相似的。它们都是使用领导者跟随者模型设计的 CFT 排序服务。如果您是应用程序开发人员、智能合约开发人员或节点管理员,您不会注意到基于 Raft 和 Kafka 的排序服务之间的功能差异。然而,有几个主要的差异值得考虑,特别是如果你打算管理一个排序服务:

  • Raft 更容易设置。虽然 Kafka 有很多崇拜者,但即使是那些崇拜者也(通常)会承认部署 Kafka 集群及其 ZooKeeper 集群会很棘手,需要在 Kafka 基础设施和设置方面拥有高水平的专业知识。此外,使用 Kafka 管理的组件比使用 Raft 管理的组件多,这意味着有更多的地方会出现问题。Kafka 有自己的版本,必须与排序节点协调。使用 Raft,所有内容都会嵌入到您的排序节点中
  • Kafka 和 Zookeeper 并不是为了在大型网络上运行。Kafka 是 CFT,它应该在一组紧密的主机中运行。这意味着实际上,您需要有一个组织运行 Kafka 集群。考虑到这一点,在使用 Kafka 时,让不同组织运行排序节点不会给您带来太多的分散性,因为这些节点都将进入同一个由单个组织控制的 Kafka 集群。使用 Raft,每个组织都可以有自己的排序节点参与排序服务,从而形成一个更加分散的系统
  • Raft 是原生支持的,这就意味着用户需要自己去获得所需的镜像并且学习应该如何使用 Kafka 和 Zookeeper。同样,对 Kafka 相关问题的支持是通过 Apache 来处理的,Apache 是 Kafka 的开源开发者,而不是 Hyperledge Fabric。另一方面,Fabric Raft 的实现已经开发出来了,并将在 Fabric 开发人员社区及其支持设备中得到支持。
  • Kafka 使用一个服务器池(称为“Kafka 代理”),而且排序组织的管理员要指定在特定通道上使用多少个节点,但是 Raft 允许用户指定哪个排序节点要部署到哪个通道。通过这种方式,节点组织可以确保如果他们也拥有一个排序节点,那么这个节点将成为该通道的排序服务的一部分,而不是信任并依赖一个中心来管理 Kafka 节点。
  • Raft 是向开发拜占庭容错(BFT)排序服务迈出的第一步。正如我们将看到的,Fabric 开发中的一些决策是由这个驱动的。如果你对 BFT 感兴趣,学习如何使用 Raft 应该可以慢慢过渡。

由于所有这些原因,在 Fabric v2.0 中,对于基于 Kafka 的排序服务正在被弃用。

注意:与 Solo 和 Kafka 类似,在向客户发送回执后 Raft 排序服务也可能会丢失交易。例如,如果领导者和跟随者提供回执时同时崩溃。因此,应用程序客户端应该监听节点上的交易提交事件,而不是检查交易的有效性。但是应该格外小心,要确保客户机也能优雅地容忍在配置的时间内没有交易提交超时。根据应用程序的不同,在这种超时情况下可能需要重新提交交易或收集一组新的背书。

Raft概念

虽然 Raft 提供了许多与 Kafka 相同的功能(尽管它是一个简单易用的软件包)但它与 Kafka 的功能却大不相同,它向 Fabric 引入了许多新的概念,或改变了现有的概念。

日志条目(Log entry)。 Raft 排序服务中的主要工作单元是一个“日志条目”,该项的完整序列称为“日志”。如果大多数成员(换句话说是一个法定人数)同意条目及其顺序,则我们认为条目是一致的,然后将日志复制到不同排序节点上。

共识者集合(Consenter set)。主动参与给定通道的共识机制并接收该通道的日志副本的排序节点。这可以是所有可用的节点(在单个集群中或在多个集群中为系统通道提供服务),也可以是这些节点的一个子集。

有限状态机(Finite-State Machine,FSM)。Raft 中的每个排序节点都有一个 FSM,它们共同用于确保各个排序节点中的日志序列是确定(以相同的顺序编写)。

法定人数(Quorum)。描述需要确认提案的最小同意人数。对于每个共识者集合,这是大多数节点。在具有五个节点的集群中,必须有三个节点可用,才能有一个法定人数。如果节点的法定人数因任何原因不可用,则排序服务集群对于通道上的读和写操作都不可用,并且不能提交任何新日志。

领导者(Leader)。这并不是一个新概念,正如我们所说,Kafka 也使用了领导者,但是在任何给定的时间,通道的共识者集合都选择一个节点作为领导者,这一点非常重要(我们稍后将在 Raft 中描述这是如何发生的)。领导者负责接收新的日志条目,将它们复制到跟随者的排序节点,并在认为提交了某个条目时进行管理。这不是一种特殊类型的排序节点。它只是排序节点在某些时候可能扮演的角色,而不是由客观环境决定的其他角色。

跟随者(Follower)。再次强调,这不是一个新概念,但是理解跟随者的关键是跟随者从领导者那里接收日志并复制它们,确保日志保持一致。我们将在关于领导者选举的部分中看到,跟随者也会收到来自领导者的**“心跳”消息**。如果领导者在一段可配置的时间内停止发送这些消息,跟随者将发起一次领导者选举,它们中的一个将当选为新的领导者。

交易流程中的Raft

每个通道都在 Raft 协议的单独实例上运行,该协议允许每个实例选择不同的领导者。这种配置还允许在集群由不同组织控制的排序节点组成的用例中进一步分散服务。虽然所有 Raft 节点都必须是系统通道的一部分,但它们不一定必须是所有应用程序通道的一部分。通道创建者(和通道管理员)能够选择可用排序节点的子集,并根据需要添加或删除排序节点(只要一次只添加或删除一个节点)。

虽然这种配置以冗余心跳消息和线程的形式产生了更多的开销,但它为 BFT 奠定了必要的基础。

在 Raft 中,交易(以提案或配置更新的形式)由接收交易的排序节点自动路由到该通道的当前领导者。这意味着 Peer 节点和应用程序在任何特定时间都不需要知道谁是领导者节点。只有排序节点需要知道。

当排序节点检查完成后,将按照我们交易流程的第二阶段的描述,对交易进行排序、打包成区块、协商并分发。

架构说明

Raft 是如何选举领导者的

尽管选举领导者的过程发生在排序节点的内部过程中,但是值得注意一下这个过程是如何工作的。

节点总是处于以下三种状态之一:跟随者候选人领导者。所有节点最初都是作为跟随者开始的。在这种状态下,他们可以接受来自领导者的日志条目(如果其中一个已经当选),或者为领导者投票。如果在一段时间内没有接收到日志条目或心跳(例如,5秒),节点将自己提升到候选状态。在候选状态中,节点从其他节点请求选票。如果候选人获得法定人数的选票,那么他就被提升为领导者。领导者必须接受新的日志条目并将其复制到跟随者。

要了解领导者选举过程的可视化表示,请查看数据的秘密生活

快照

如果一个排序节点宕机,它如何在重新启动时获得它丢失的日志?

虽然可以无限期地保留所有日志,但是为了节省磁盘空间,Raft 使用了一个称为“快照”的过程,在这个过程中,用户可以定义日志中要保留多少字节的数据。这个数据量将决定区块的数量(这取决于区块中的数据量。注意,快照中只存储完整的区块)。

例如,假设滞后副本 R1 刚刚重新连接到网络。它最新的区块是100。领导者 L 位于第 196 块,并被配置为快照20个区块。R1 因此将从 L 接收区块 180,然后为区块 101180 区块 分发 请求。然后180196 的区块将通过正常 Raft 协议复制到 R1

Kafka(V2.0弃用)

Fabric 支持的另一个容错崩溃排序服务是对 Kafka 分布式流平台的改写,将其用作排序节点集群。您可以在 Apache Kafka 网站上阅读更多关于 Kafka 的信息,但是在更高的层次上,Kafka 使用与 Raft 相同概念上的“领导者跟随者”配置,其中交易(Kafka 称之为“消息”)从领导者节点复制到跟随者节点。就像 Raft 一样,在领导者节点宕机的情况下,一个跟随者成为领导者,排序可以继续,以此来确保容错。

Kafka 集群的管理,包括任务协调、集群成员、访问控制和控制器选择等,由 ZooKeeper 集合及其相关 API 来处理。

Kafka 集群和 ZooKeeper 集合的设置是出了名的棘手,所以我们的文档假设您对 Kafka 和 ZooKeeper 有一定的了解。如果您决定在不具备此专业知识的情况下使用 Kafka,那么在试验基于 Kafka 的排序服务之前,至少应该完成 Kafka 快速入门指南的前六个步骤。您还可以参考 这个示例配置文件 来简要解释 Kafka 和 ZooKeeper 的合理默认值。

要了解如何启动基于 Kafka 的排序服务,请查看我们关于 Kafka 的文档

私有数据

什么是私有数据

如果一个通道上的一组组织需要对该通道上的其他组织保持数据私有,则可以选择创建一个新通道,其中只包含需要访问数据的组织。但是,在每种情况下创建单独的通道会产生额外的管理开销(维护链码版本、策略、MSP等),并且不能在保留一部分数据私有的同时,可以让所有通道参与者看到该事务。

这就是为什么从v1.2开始,Fabric 提供了创建私有数据集合的功能,它允许在通道上定义的组织子集能够背书、提交或查询私有数据,而无需创建单独的通道

什么是私有数据集合

集合是两个元素的组合:

  1. 实际的私有数据,通过 Gossip 协议 点对点地发送给授权可以看到它的组织。私有数据保存在被授权的组织的节点上的私有数据库上,它们可以被授权节点的链码访问。排序节点不能影响这里也不能看到私有数据。注意,由于 gossip 以点对点的方式向授权组织分发私有数据,所以必须设置通道上的锚节点,也就是每个节点上的 CORE_PEER_GOSSIP_EXTERNALENDPOINT 配置,以此来引导跨组织的通信
  2. 该数据的 hash 值,该 hash 值被背书、排序之后写入通道上每个节点的账本。Hash 值作为交易的证明用于状态验证,并可用于审计。

下面的图表分别说明了被授权和未被授权拥有私有数据的节点的账本内容。

如果集合成员陷入争端,或者他们想把资产转让给第三方,他们可能决定与其他参与方共享私有数据。然后,第三方可以计算私有数据的 hash,并查看它是否与通道账本上的状态匹配,从而证明在某个时间点,集合成员之间存在该状态。

有些情况,你可能选择每个组织会有一套集合。比如一个组织可能会将私有数据记录到他们自己的集合中,之后可以共享给其他的通道成员并且在链码中引用。我们会在下边的共享私有数据部分看到一些例子。

什么时候使用一个通道内的组织集合,什么时候使用单独的通道

  • 当必须将整个账本在属于通道成员的组织中保密时,使用通道比较合适。
  • 当账本必须共享给一些组织,但是只有其中的部分组织可以在交易中使用这些数据的一部分或者全部时,使用集合比较合适。此外,由于私有数据是点对点传播的,而不是通过块传播的,所以在交易数据必须对排序服务节点保密时,应该使用私有数据集合。

解释集合的用例

设想一个通道上的五个组织,他们从事农产品贸易:

  • 农民在国外售卖他的货物
  • 分销商将货物运往国外
  • 托运商负责参与方之间的货物运输
  • 批发商向分销商采购商品
  • 零售商向托运人和批发商采购商品

分销商可能希望与农民托运商进行私下交易,以对批发商零售商保密交易条款(以免暴露他们收取的加价)。

分销商还可能希望与批发商建立单独的私人数据关系,因为它收取的价格低于零售商

批发商可能还想与零售商托运商建立私有数据关系。

相比于为每一个特殊关系建立各种小的通道来说,更好的做法是,可以定义多个私有数据集合 (PDC),在以下情况下共享私有数据:

  1. PDC1:分销商, 农民托运商
  2. PDC2:分销商批发商
  3. PDC3:批发商, 零售商托运商

使用此示例,属于分销商的节点将在其账本中包含多个私有的私有数据库,其中包括来自分销商农民托运商子集合关系和分销商批发商子集合关系的私有数据。

使用私有数据的交易流

当在链码中引用私有数据集合时,交易流程略有不同,以便在交易被提案、背书并提交到账本时保持私有数据的机密性。

关于不使用私有数据的交易流程的详细信息,请参阅我们的交易流程的文档。

  1. 客户端应用程序提交一个提案请求,让属于授权集合的背书节点执行链码函数(读取或写入私有数据)。 私有数据,或用于在链码中生成私有数据的数据,被发送到提案的 transient(瞬态)字段中。
  2. 背书节点模拟交易,并将私有数据存储在 瞬态数据存储( transient data store ,节点的本地临时存储)中。它们根据组织集合的策略将私有数据通过gossip分发给授权的 Peer 节点。
  3. 背书节点将提案响应发送回客户端。提案响应中包含经过背书的读写集,这其中包含了公共数据,还包含任何私有数据键和值的 hash。私有数据不会被发送回客户端。更多关于带有私有数据的背书的信息,请查看这里
  4. 客户端应用程序将交易(包含带有私有数据 hash 的提案响应)提交给排序服务。带有私有数据 hash 的交易同样被包含在区块中。带有私有数据 hash 的区块被分发给所有节点。这样,通道中的所有节点就可以在不知道真实私有数据的情况下,用同样的方式来验证带有私有数据 hash 值的交易
  5. 在区块提交的时候,授权节点会根据集合策略来决定它们是否有权访问私有数据。如果节点有访问权,它们会先检查自己的本地 瞬态数据存储 ,以确定它们是否在链码背书的时候已经接收到了私有数据。如果没有的话,它们会尝试从其他已授权节点那里拉取私有数据,然后对照公共区块上的 hash 来验证私有数据并提交交易和区块。当验证或提交结束后,私有数据会被移动到这些节点私有数据库和私有读写存储的副本中。随后 瞬态数据存储 中存储的这些私有数据会被删除。

共享私有数据

在多数情况下,一个私有数据集合中的私有数据键或值可能需要与其他通道成员或者私有数据集合共享,例如,当你需要和一个通道成员或者一组通道成员交易私有数据,而初始私有数据集合中并没有这些成员时。私有数据的接收方一般都会在交易过程中对照链上的 hash 来验证私有数据

私有数据集合的以下几个方面促成了私有数据的共享和验证:

  • 首先,只要符合背书策略,尽管你不是私有数据集的成员也可以为集合写入键。可以在链码层面,键层面(用基于状态的背书)或者集合层面(始于 Fabric v2.0)上定义背书策略。
  • 其次,从 v1.4.2 开始出现了链码 API GetPrivateDataHash() ,它支持非集合成员节点上的链码读取一个私有键的 hash。下文中你将发现这是一个十分重要的功能,因为它允许链码对照之前交易中私有数据生成的链上 hash 来验证私有数据。

当设计应用程序和相关私有数据集合时需要考虑这种共享和验证私有数据的能力。您当然可以创建出几组多边私有数据集合以供多个通道成员组合之间共享数据,但是这样做的话你就需要定义大量私有数据集合。或者你也可以考虑使用少量私有数据集合(例如,每个组织用一个集合,或者每对组织用一个集合),然后和其他通道成员共享私有数据,有需要时还可以和其他集合共享私有数据。从 Fabric v2.0 开始,隐含的组织特定集合可供所有链码使用,这样一来部署链码的时候你就不用定义每个组织中的私有数据集合。

私有数据共享模式

为各组织的私有数据集合构建模型时,有多种模式可被用来共享或传输私有数据,且无需费力定义多个多边集合。以下是链码应用程序中可以使用的一些共享模式:

  • 使用相应的公钥来追踪公共状态:您可以选择使用一个相应的公钥来追踪特定的公共状态(例如:资产性质,当前所有权等公共状态),对于每个需要拥有资产相应私有数据访问权的组织,您可以在它们的私有数据集合中创建一个私有秘钥或值。
  • 链码访问控制:您可以在您的链码中执行访问控制,指明什么客户端应用程序能够查询私有数据集合中的私有数据。例如,为一个或多个私有数据集合键存储一个访问控制列表,然后在链码中获取客户端应用程序提交者的证书(使用 GetCreator() 链码 API 或 CID 库 API GetID() or GetMSPID() 来获取),并在返回私有数据之前验证这些证书。同样,为了访问私有数据,您可以要求客户端将密码短语传送到链码中,且该短语必须与存储在秘钥级别的密码短语相匹配。注意,这种模式也可用于限制客户端对公共状态数据的访问权。
  • 使用带外数据来共享私有数据:这是一种链下选项,您可以同其他组织以带外数据的形式共享私有数据,这些组织可使用 GetPrivateDataHash() 链码 API 将键或值转换成 hash 以验证其是否与链上 hash 匹配。例如,如果一个组织想要购买一份你的资产,那么在同意购买之前它会检查链上 hash,以验证如下事项:该资产的属性;你是否为该资产的合法所有人。
  • 与其他集合共享私有数据:您可以同链码在链上共享私有数据,该链码在其他组织的私有数据集合中生成一个相应的键或值。你将通过临时字段把私有数据键或值传送给链码,收到私有数据后该链码使用 GetPrivateDataHash() 验证此私有数据的 hash 是否与您集合中的链上 hash 一致,随后将该私有数据写入其他组织的私有数据集合中。
  • 将私有数据传送给其他集合:您可以使用链码来”分发“私有数据,该链码把您集合中的私有数据键删除,然后在其他组织的集合中生成。与上述方法相同,这里在调用链码时使用临时字段传输私有数据,并且在链码中用 GetPrivateDataHash() 来验证你的私有数据集合中是否存在该数据,验证成功之后再把你的集合中该数据删除,并在其他组织的集合中生成该键。为确保每次操作都会从一个集合中删除一项交易并在另一个集合中添加该交易,你可能需要获得一些额外组织的背书,如监管者或审计者。
  • 使用私有数据进行交易确认:如果您想在交易完成之前获得竞争对手的批准(即竞争对手同意以某价钱购买一项资产这一链上记录),链码会在竞争对手或您自己的私有数据集合中写入一个私有数据(链码随后将使用 GetPrivateDataHash() 来验证该数据),从而要求竞争对手”率先批准“这项交易。事实上,嵌入式生命周期系统链码就是使用这种机制来确保链码定义在被提交到通道之前已经获得通道上各组织的同意。这种私有数据共享模式从从 Fabric v2.0 开始凭借集合层面的背书策略变得越来越强大,确保在集合拥有者自己的信任节点上执行、背书链码。或者,您也可以使用具有秘钥层面背书策略、共同商定的秘钥,随后该秘钥被预先批准的条款更新,并且在指定组织的节点上获得背书。
  • 使交易者保密:对上一种共享模式进行些许变化还可以实现指定交易的交易者不被暴露。例如,买方表示同意在自己的私有数据集合上进行购买,随后在接下来的交易中卖方会在自己的私有数据集合中引用该买方的私有数据。带有 hash 过的引用的交易证据被记录在链上,只有出售者和购买者知道这些是交易,但是如果需要需要知道的原则的话,他们可以暴漏原像,比如在一个接下来的跟其他的伙伴进行交易时,对方就能够验证这个 hash 了。

结合以上几种模式,我们可以发现,私有数据的交易和普通的通道状态数据交易情况类似,特别是以下几点:

  • 重要级别交易访问控制 - 您可以在私有数据值中加入 所有权证书,这样一来,后续发生的交易就能够验证数据提交者是否具有共享和传输数据的所有权。在这种情况下,链码会获取数据提交者的证书(例如:使用 GetCreator() 链码 API or CID library API GetID() or GetMSPID() ),将此证书与链码收到的其他私有数据合并,
  • 重要级别背书策略 - 和正常的通道状态数据一样,您可以使用基于状态的背书策略来指明哪些组织必须对共享或转移私有数据的交易做出背书,使用 SetPrivateDataValidationParameter() 链码 API 来进行一些操作,例如,指明必须对上述交易作出背书的仅包括一个拥有者的组织节点,托管组织的节点或者第三方组织。

样例场景:使用私有数据集合的资产交易

将上述私有数据共享模式结合起来能够赋能基于链码的应用程序。例如,思考一下如何使用各组织私有数据集合来实现资产转移场景:

  • 在公共链码状态使用 UUID 键可以追踪一项资产。所记录信息只包括资产的所属权,没有其他信息。
  • 链码要求:所有资产转移请求必须源自拥有者客户端,并且关键在于需要有基于状态的背书,要求从所有者的组织和一个监管者的组织的一个 Peer 必须要为所有的交易请求背书。
  • 资产拥有者的私有数据集合包含了有关该资产的私有信息,用一个 UUID 的 hash 作为键值。其他的组织和排序服务将会只能看到资产详细的 hash 。
  • 假定监管者是各私有数据集合的一员,因此它一直维护着私有数据,即使他并没必要这么做。

一项资产交易的进行情况如下:

  1. 链下,资产所有者和意向买家同意以某一特定价格交易该资产。
  2. 卖家通过以下方式提供资产所有权证明:利用带外数据传输私有信息;或者出示证书以供买家在其自身节点或管理员节点上查询私有数据。
  3. 买家验证私有信息的 hash 是否匹配链上公共 hash。
  4. 买家通过调取链码来在其自身私有数据集合中记录投标细节信息。一般在买家自己的节点上调取链码,但如果集合背书策略有相关规定,则也可能会在管理员节点上调取链码。
  5. 当前的资产所有者(卖家)调取链码来卖出、转移资产,传递私有信息和投标信息。在卖家、买家和管理员的节点上调用链码,以满足公钥的背书策略以及买家和买家私有数据集合的背书策略。
  6. 链码验证交易发送方是否为资产拥有者,根据卖家私有数据集合中的 hash 来验证私有细节信息,同时还会根据买家私有数据集合中的 hash 来验证投标细节信息。随后链码为公钥书写提案更新(将资产拥有者设定为买家,将背书策略设定为买家和管理员),把私有细节信息写入买家的私有数据集合中,以上步骤成功完成后链码会把卖家私有数据集合中的相关私有细节信息删除。在最终背书之前,背书节点会确保已将私有数据分布给卖家和管理员的所有授权节点。
  7. 卖家提交交易等待排序,其中包括了公钥和私钥 hash,随后该交易被分布到区块中的所有通道节点上。
  8. 每个节点的区块验证逻辑都将一致性地验证背书策略是否得到满足(买家、卖家和管理员都作出背书),同时还验证链码中已读取的公钥和私钥自链码执行以来未被任何其他交易更改。
  9. 所有节点提交的交易都是有效的,因为交易已经通过验证。如果买家和管理员节点在背书时未收到私有数据的话,它们将会从其他授权节点那里获取这些私有数据,并将这些数据保存在自己的私有数据状态数据库中(假定私有数据与交易的 hash 匹配)。
  10. 交易完成后,资产被成功转移,其他对该资产感兴趣的通道成员可能会查询公钥的历史以了解该资产的来历,但是它们无法访问任何私有细节信息,除非资产拥有者在须知的基础上共享这些信息。

以上是最基本的资产转移场景,我么可以对其进行扩展,例如,资产转移链码可能会验证一项付款记录是否可用于满足付款和交付要求,或者可能会验证一个银行是否在执行资产转移链码之前已经提交了信用证。交易各方并不直接维护节点,而是通过那些运行节点的托管组织来进行交易。

清除私有数据

对于非常敏感的数据,即使是共享私有数据的各方可能也希望(或者应政府相关法规要求必须)定期“清除”节点上的数据,仅把这些敏感数据的 hash 留在区块链上,作为私有数据不可篡改的证据。

在某些情况下,私有数据只需要在其被复制到节点区块链外部的数据库之前存在于该节点的私有数据库中。而数据或许也只需要在链码业务流程结束之前存在于节点上(交易结算、合约履行等)。

为了支持这些用户案例,如果私有数据已经持续 N 个块都没有被修改,则可以清除该私有数据,N 是可配置的。链码中无法查询已被清除的私有数据,并且其他节点也请求不到。

私有数据集合怎么定义

有关集合定义的更多详细信息,以及关于私有数据和集合的其他更底层的信息,请参阅私有数据主题

通道capabilities

注意:这是一个进阶的Fabric概念, 新用户或应用程序开发人员不一定要理解它。 然而,随着通道和网络的成熟,理解和管理capabilities变得至关重要。 此外,要认识到,尽管更新capabilities升级节点通常是相关的, 但这两者是不同的过程,这是相当重要的。 我们将在本章节中对此进行详细描述。

因为Fabric是一个通常涉及多个组织的分布式系统, 所以不同版本的Fabric代码可能(而且通常) 存在于网络中的不同节点以及该网络中的通道上。 Fabric允许这种情况—— 即不需要每个peer节点和排序节点都处于相同的版本。 实际上,正因为其支持不同的版本才使得Fabric节点能够滚动升级。

重要的是,网络和通道以相同的方式来处理事情, 例如为通道配置更新和链代码调用等事情创建确定性结果。 如果没有确定性的结果, 通道上的一个peer节点可能使一笔交易失效, 而另一个peer节点可能确认该交易。

为此,Fabric定义了所谓的“capabilities”。 这些capabilities在每个通道的配置中定义, 通过定义行为会产生一致结果的版本,确保了确定性。 正如您将看到的,这些capabilities的版本与节点二进制版本密切相关。 capabilities使运行在不同版本的节点能够以兼容和一致的方式在给定特定区块高度的通道配置下运行。 您还将看到,配置树的许多部分都存在capabilities, 这些capabilities是根据特定任务的实施而定义的。

正如您将看到的, 有时需要将您的通道更新到新的capabilities版本以启用新特性。

节点版本和capabilities版本

如果您熟悉Hyperledger Fabric,就会意识到它遵循典型的语义版本模式:v1.1、v1.2.1和v2.0等等。这些版本指的是发行版及其相关的二进制版本。

capabilities遵循相同的语义版本约定。 虽然它也有v1.1 capabilities、v1.2 capabilities和2.0 capabilities等等。 但重要的是注意一些区别。

  • 每次发布版本不一定都有一个新的capability level。 建立新 capabilities的需求取决于具体情况本身, 主要依赖于新特性和旧二进制版本的向后兼容性。 例如,在v1.4.1中添加Raft排序服务并没有改变交易或排序服务 capabilities的处理方式, 因此不需要设定任何新 capabilities。另一方面, 私有数据 在v1.2之前无法被peer节点处理,因此需要设定v1.2 capability level。 因为不是每次版本发布都包含改变交易处理方式的新特性(或bug修复), 所以某些发布的版本不需要任何新 capabilities(例如,v1.4), 而其他版本只需要特定的新capabilities(例如v1.2和v1.3)。 稍后我们将讨论capabilities的“level”以及它们位于配置树中的位置。
  • 在通道中,节点版本必须不能低于特定的capability版本。 当一个peer节点加入一个通道时,它将顺序读取账本中的所有区块,从通道的创世块开始,持续经过交易区块和所有后续配置区块。如果节点(例如peer节点)试图读取一个包含其不理解的capabilities的更新的区块(例如,v1.4.x中peer节点试图读取包含v2.0应用程序capabilities的区块),那么peer节点将崩溃。这种崩溃行为是故意如此设计的,因为v1.4.x的peer节点不应该试图验证或提交任何超前于该版本的交易。在加入通道之前,请确保该节点不低于与该节点相关的通道配置中指定的capabilities的Fabric版本(二进制)。稍后我们将讨论哪些capabilities与哪些节点相关。然而,由于没有用户希望他们的节点崩溃,所以强烈建议在尝试更新capabilities之前将所有节点更新到所需的版本(最好是更新到最新版本)。这符合Fabric的默认建议,即始终使用最新的二进制和capabilities版本。

如果用户不能升级他们的二进制文件,那么capabilities必须保留在较低的版本。 较低版本的二进制文件和capabilities仍然会像它们所期望的那样一起工作。 然而,请记住,即使用户选择不更新它们的capabilities, 始终更新到新的二进制文件也仍是一个最佳做法。 因为capabilities本身也包括一些缺陷修复, 所以总是建议一旦网络中的二进制文件支持capabilities后就更新它们。

capabilities配置分类

正如我们前面讨论的,不存在包含整个通道的单一capability level。相反,有三种capabilities,每一种都代表一个管理区域。

  • 排序节点: 这些capabilities管理排序服务独有的任务和处理。 由于这些capabilities不涉及影响交易或peer节点的操作, 因此更新它们仅能由排序服务管理员完成(peer节点不需要了解排序节点capabilities, 因此无论排序节点capabilities更新了什么,都不会发生崩溃)。 注意,这些capabilities在v1.1和v1.4.2之间没有改变。 然而,正如我们将在通道一节中看到的, 这并不意味着v1.1排序节点能在capability level低于v1.4.2的所有通道上运作。
  • 应用程序: 这些capabilities管理peer节点独占的任务和处理。 因为排序服务管理员在决定peer节点组织之间的交易性质方面没有任何作用, 因此更改此capability level只能由peer节点组织来完成。例如, 只能在启用了v1.2(或更高版本)应用程序组capabilities的通道上启用私有数据。 在有私有数据的情况下,这是必须被启用的唯一capabilities, 因为私有数据的工作方式不需要更改通道管理或排序服务处理交易的方式。
  • 通道: 此分类包含由peer节点组织和排序服务共同管理的任务。 例如,这个capabilities定义了进行通道配置更新的level, 这些更新由peer节点组织发起并由排序服务排序。 在实际层面上,这个分类定义了通道中所有二进制文件的最小level,因为排序节点和peer节点都必须不能低于与此capabilities相对应的二进制版本,才能运行该capabilities

通道的排序节点通道 capabilities默认情况下是从排序系统通道继承的, 其中修改它们是排序服务管理员的专属权限。因此, peer节点组织应该在将其peer节点加入该通道之前检查通道的创世块。 虽然通道capabilities是由排序系统通道的排序节点(正如联盟成员那样)管理的, 但是排序管理员将与联盟管理员协同确保仅在联盟准备好后才升级通道capabilities, 这是典型的和符合预期的。

因为排序系统通道没有定义一个应用程序capabilities, 所以在为通道创建创世块时,必须在通道配置文件中指定此capabilities。

当指定或修改应用程序capabilities时,请谨慎。因为排序服务不验证capability level是否存在,所以它将允许创建(或修改)通道来包含例如v1.8这样的应用程序capabilities,即使不存在这种capabilities。任何peer节点在试图读取一个含此capabilities的配置块将会崩溃,即使可以再次修改该通道为合法的capability level也没有意义,因为没有peer节点能够通过含无效的v1.8 capabilities的区块。

要全面了解当前有效的排序节点、应用程序和通道capabilities,请查看示例configtx.yaml文件,这些在“通道capabilities”一节中列出。

有关capabilities的更多具体信息以及它们处于通道配置中的位置, 请查看定义capabilities要求

Fabric链码生命周期

什么是链码?

链码是一段用 GoNode.js 或者 Java 写的实现了规定接口的程序。链码运行在一个隔离于背书 peer 节点进程的安全的 Docker 容器中。链码通过应用提交的交易来初始化以及管理账本状态。

链码通常用来处理网络中成员共同接受的业务逻辑,所以它可以被认为是“智能合约”。通过链码创建的账本更新只适用于该链码,并且不能直接被另一个链码访问到。然而在同一个网络中,在被授予适当权限的情况下,链码可以调用另一个链码来访问它的状态。

在这个概念主题下,我们将会以一个区块链网络操作者而不是应用开发者的视角来探索链码。链码操作者可以用本文作为在网络上使用 Fabric 链码生命周期来部署和管理链码的指南。

部署一个链码

Fabric 链码生命周期是一个过程,它允许多个组织在使用一个链码之前就如何操作达成一致。网络操作者可以使用 Fabric 生命周期来展开以下的任务:

你可以通过创建一个通道并设置其 capabilities 为 V2_0 来使用 Fabric 链码生命周期。在 capabilities 为 V2_0 的通道上,你将不能使用旧的生命周期来安装、初始化或升级链码。然而,在启动 V2_0 后,你仍然可以调用用之前生命周期模式安装的链码。如果你从 v1.4.x 网络基础上升级并且需要启动新的生命周期,查看 启用新的链码生命周期

安装以及定义链码

Fabric 链码生命周期需要组织同意定义一个链码的参数,比如说名称、版本以及链码背书策略。通道成员通过以下四步达成共识。不是通道上的每一个组织都需要完成每一步。

1、打包链码: 这一步可以被一个或者每一个组织完成。

2、安装链码在你的 peer 节点上: 每一个用链码的组织需要完成这一步。

3、为你的组织批准链码定义: 使用链码的每一个组织需要完成这一步。链码能够在通道上运行之前,链码定义需要被足够多的组织批准来满足通道的生命周期背书(LifecycleEndorsement)策略(默认为大多数组织)。

4、提交链码定义到链上: 一旦通道上所需数量的组织已经同意,提交交易需要被提交。提交者首先从已同意组织中的足够的 peer 节点中收集背书,然后通过提交交易来提交链码声明。

本文提供了操作 Fabric 链码生命周期的细节概述而不是特定的指令。学习更多关于如何通过 Peer CLI 工具来使用 Fabric 生命周期,查看 部署智能合约到通道上的教程 或者 peer 生命周期指令参考.

步骤一:打包智能合约

在被安装到 peer 节点之前,链码需要被打包进一个 tar 文件。你可以使用 Fabric Peer 二进制可执行文件、Node Fabric SDK、或者第三方工具例如 GNU tar 来打包链码。当你创建一个链码包的时候,你需要提交一个用来创建简明易读的包描述的链码包标签

如果你使用第三方工具来打包链码,结果文件(译者注:打包生成的文件)需要为以下格式。Fabric peer 的二进制可执行文件和 Fabric SDKs 将会自动以这个格式来创建文件。

  • 链码需要被打包进一个以 .tar.gz 文件扩展名结尾的 tar 文件。

  • tar 文件需要包含两个文件(没有目录):“metadata.json”和另一个包含了链码文件的 tar 文件“code.tar.gz”。

  • “metadata.json”包含了指定链码语言、代码路径、以及包标签的 JSON 文件。以下,你可以看到一个元数据文件:

    1
    
    {"Path":"fabric-samples/chaincode/fabcar/go","Type":"golang","Label":"fabcarv1"}
    

打包链码

链码分别被 Org1 和 Org2 打包。为了使用名字和版本来识别包,两个组织都使用 MYCC_1 作为包标签。对于多个组织来说使用相同的包标签没有必要。

步骤二:在你的 peers 节点上安装链码

你需要在每个要执行和背书交易的peer节点上安装链码包。无论使用 CLI 或者是 SDK,你需要以 Peer Administrator (译者注:peer 所在组织的管理员) 的身份来完成这步。链码安装后,你的 peer 节点会构建链码,并且如果你的链码有问题,会返回一个构建错误。建议每个组织只打包链码一次,然后安装相同的包在属于他们组织的每一个 peer 节点上。如果某个通道希望确保每个组织都运行同样的链码,某一个组织可以打包链码并通过带外数据(译者注:不通过链上)把它发送给其他通道成员.

通过指令成功安装链码后会返回链码包标识符,它是包标签和包哈希值的结合。这个包标识符用来关联安装在你的 peer 节点上的链码包已被批准的链码。为下一步的操作保存这个标识符。你也可以通过使用 Peer CLI 工具查询安装在 peer节点上的包来查看包标识符。

安装链码

Org1 和 Org2 的管理员安装链码 MYCC_1 到加入通道的 peer 节点上。安装链码包构建了链码并且创建了包标识符 MYCC_1:hash。

步骤三:为你的组织批准链码定义

通过 链码定义 来管理链码。当通道成员批准一个链码定义,这个批准便作为一个组织在接受链码参数方面的投票。这些同意的组织定义允许通道成员在链码可以在通道上使用之前达成一致意见(译者注:同意链码运行在此通道上)。链码定义包含了以下需要持续在组织之间保持一致的参数:

  • 名称: 应用调用链码时使用的名称。

  • 版本: 一个版本号或者和给定链码包关联的值。如果你升级链码二进制文件(译者注:打包后的链码文件),你也需要改变你的链码版本。

  • 序列号: 链码被定义的次数。这个值是一个整数,并且被用来追踪链码的更新次数。例如当你第一次安装并且同意一个链码定义,这个序列号会是1。当你下一次更新链码,序列号会是2。

  • 背书策略: 哪些组织需要执行并且验证交易输出。背书策略可以表达为传递给 CLI 工具的字符串或者它能参考通道配置中的一个策略。默认情况下,背书策略设置为 Channel/Application/Endorsement,默认通道中大多数组织为一笔交易背书。

  • 集合配置(译者注:私有数据集合配置): 和你链码相关的私有数据集合定义文件的路径。了解更多关于私有数据集合的信息,查看 私有数据架构参考

  • ESCC/VSCC 插件: 这个链码使用的定制的背书或者验证插件名称。

  • 初始化: 如果你使用 Fabric Chaincode Shim API 提供的低级别的 API,你的链码需要包含用来初始化链码的 Init 方法。链码接口需要这个方法,但不必要被你的应用调用。 当你批准一个链码定义时,你可以指定是否 Init 方法必须在调用(译者注:调用非 init 方法)之前被执行。如果你指定需要 Init,Fabric 会确保Init 方法在链码中的其他方法之前被调用,并且只会被调用一次。 请求执行 Init 方法允许你实现链码初始化时运行的逻辑,例如设置一些初始状态。每次你的链码版本更新,你都需要调用 Init 来初始化链码,假定链码定义增加了版本号意味着 Init 是需要的。

    如果你正在使用 Fabric peer CLI 工具,当你同意提交链码定义时候,你可以使用 --init-required 变量来表示 Init 方法必须被调用来初始化新的链码版本。用 Fabric peer CLI 工具调用 Init 方法时,需要使用 peer chaincode invoke 指令来传 --isInit 变量。

    如果你使用 Fabric 合约 API,你不需要把 Init 方法包含进你的链码。然而,你仍然可以使用 --init-required 变量发起从应用调用来初始化链码的请求。如果你使用 --init-required 变量,为了每次初始化链码时增加链码的版本号,你需要传 --isInit 变量或者参数给链码调用。你可以用链码中的任何方法结合传 --isInit 变量来初始化链码。

链码定义也包括 Package Identifier。对每个希望使用链码的组织来说,这是个必须的参数。包 ID 不需要所有组织都一致。一个组织可以在不安装链码包或者定义中不包含 identifier 的情况下,批准链码定义。

每个希望使用链码通道成员需要为他们的组织批准链码定义。这个批准操作需要提交给排序服务,在此之后会分发给所有的 peer 节点。这个批准操作需要被你的 Organization Administrator 提交。在批准交易被成功提交后,同意的定义存储在你的组织中所有 peer 节点都可访问到的集合中。结果是,尽管你有多个 peer 节点,你只需要为你的组织同意一个链码一次

批准链码定义

Org1 和 Org2 的组织管理员为他们的组织批准 MYCC 链码定义。链码定义的其他字段包括链码名称、版本号和背书策略。因为两个组织都会用该链码来背书交易,所以两个组织同意的定义都需要 packageID(相同)

步骤四:提交链码定义到通道

一旦足够多的通道成员同意一个链码定义,某个组织能够提交定义到通道。你可以用 checkcommitreadiness 命令在使用 Peer CLI 工具将链码定义提交到通道之前,基于哪个通道成员已经批准了该定义,来检查提交链码定义是否应该成功。(译者注:根据通道成员同意的状况,来判断提交是否可能成功)。提交交易请求首先发送给通道成员的 peer 节点,peer 节点会查询链码定义被他们组织同意的状况,并且为定义背书如果所在组织已经同意了。交易然后提交给排序服务,排序服务会把链码定义提交给通道。提交定义交易需要以 Organization Administrator 身份来提交。

链码在被成功提交到通道之前,需要被同意的组织的数量是通过 Channel/Application/LifecycleEndorsement 策略来管理的。默认情况下,这个策略需要通道中大多数的组织来给交易背书。生命周期背书策略不同于链码背书策略。例如,尽管一个链码背书策略只需要一个或两个组织的签名,根据默认策略大多数的通道成员仍然需要批准链码定义。当提交一个通道定义,你需要面向足够多的 peer 组织,以确保你的生命周期背书策略被满足。你可以在 策略概念主题 中了解到更多关于 Fabric 链码生命周期策略。

你也可以设置 Channel/Application/LifecycleEndorsement 策略为一个签名策略并且明确指明通道上可以批准链码定义的组织集合。这允许你创建一个其中大多数组织作为链码管理者并且治理通道业务逻辑的通道。如果你的通道有大量的 Idemix(译者注:身份混合,实现零知识证明)组织,你也可以用一个签名策略(译者注:策略只需要一个签名),因为这些组织不能批准链码定义或者为链码背书并且可能阻碍通道达成大多数成员同意的结果。

提交链码定义到通道

Org1 或 Org2 的一个组织管理员提交链码定义到通道通道上的定义不包含 packageID

一个组织在不安装链码包的条件下能够批准链码定义。如果一个组织不需要使用链码,他们可以在没有包身份的情况下批准一个链码定义来确保生命周期背书策略被满足。

链码定义已经提交到通道上后,链码容器会在所有安装了链码的 peer 节点上启动,来允许通道成员开始使用链码。可能会花费几分钟的时间来启动链码容器。你可以用链码定义来要求调用 Init 方法初始化链码。如果 Init 方法调用是需要的,链码的第一个调用必须是调用 Init 方法。Init 方法的调用服从于链码的背书策略。

在通道上启动链码

一旦 MYCC 链码在通道上定义,Org1 和 Org2 能开始使用链码。每个 peer 节点上的链码的第一个调用会启动该 peer 上的链码容器

升级链码

你可以用相同的 Fabric 生命周期流程(译者注:和部署链码的生命周期相同)来升级一个链码。你可以升级链码二进制文件或者只升级链码策略。根据以下步骤来升级一个合约:

1、重新打包链码: 如果你升级二进制文件,你只需要完成这一步。

重新打包链码包

Org1 和 Org2 升级链码二进制并且重新打包链码。两个组织都用不同的包标签

2、在你的 peer 节点上安装新的链码包: 再次复述,如果你正在升级链码二进制文件你只需要完成这一步。安装新的链码包会生成一个包 ID,你需要把它传给新的链码定义。如果链码二进制文件升级了,你也需要修改链码版本,版本会被生命周期流程追踪。

重新安装链码包

Org1和Org2在他们的 peer 节点上安装新链码包。安装会生成一个新的 packageID。

3、 批准一个新的链码定义: 如果你正在升级链码二进制文件,你需要在链码定义中升级链码版本和包 ID。你也可以在不打包你的链码二进制文件情况下升级链码背书策略。通道成员只需要在新的策略中批准一个定义。新的定义需要在定义中把 sequence(译者注:序列号) 变量的值加一。

批准一个新的链码定义

Org1 或者 Org2 的组织管理员为他们相关的组织批准新的链码定义。新的定义引用新的 packageID 并且改变链码版本。因为这是第一次升级链码,序列号从1增加到2。

4、 提交定义到通道: 当足够多的通道成员批准新的链码定义,某个组织可以提交新的定义来升级通道上的链码定义。没有单独的升级指令作为生命周期流程的某部分。

提交新的定义到通道

Org1 或者 Org2 的一个组织的管理员提交新的链码定义到通道上。

你提交链码定义后,一个新的包含升级后的链码二进制文件的链码容器会启动。如果你在链码定义中请求执行 Init 方法,你需要在成功提交新的定义后再次调用 Init 方法来初始化升级过的链码。如果你升级没有改变链码的版本号,链码容器会保持一致并且你不需要调用Init 方法。

升级链码

一旦新的定义提交到链上,每个 peer 节点会自动启动新的链码容器。

Fabric 链码生命周期在链码定义中使用 sequence (译者注:序列号)来跟踪升级。所有的通道成员需要把序列号加一并且同意新的定义来升级链码。版本参数用来追踪链码二进制文件,并且只需要当你升级链码二进制时改变。

部署场景

以下的例子描述了你如何才能使用 Fabric 链码生命周期来管理通道和链码。

加入通道

一个新的组织可以在链码已经定义的情况下加入通道,并且在安装完链码包和批准已经提交到通道的链码定义后,开始使用链码。

批准一个链码定义

Org3 加入通道并且批准之前已经被 Org1 和 Org2 提交到通道的相同链码定义。

在批准链码定义后,新的组织会在包安装到它们的 peer 节点上之后,开始使用链码包。定义不需要再次被提交。如果背书策略设置为默认需要大多数通道成员背书的策略,然后背书策略会自动更新为把新的组织也包括进去。

启动链码

链码容器会在 Org3 的 peer 节点上调用后启动。

升级背书策略

你可以在不重新打包或者重新安装链码的情况下使用链码定义来更新背书策略。通道成员可以用新的背书策略批准一个链码定义并且提交到链上。

批准链码定义

Org1、Org2 和 Org3 同意一个新的需要三个组织背书交易的背书策略。它们把定义序列号从1增加到2,但是不需要更新链码版本。

新的背书策略会在新的定义提交到通道上后奏效。通道成员不需要为了更新背书策略而通过调用链码或者执行 Init 方法来重新启动链码容器。

提交新的链码定义

组织提交新的链码定义到通道上来更新背书策略。

不安装链码的情况下批准定义

你可以在不安装链码包的情况下批准一个链码定义。甚至尽管你不希望使用链码来背书交易或者查询账本,你还是被允许在链码提交到通道上之前为链码定义背书。你需要批准其他通道成员相同的参数,但不需要把 packageID 包含为链码定义的一部分。

Org3 不安装链码

Org3 不需要安装链码包。结果是,他们不需要提供 packageID 来作为链码定义的一部分。然而,Org3 仍然可以背书已经提交到通道上的 MYCC 链码的定义。

一个组织不同意链码定义

不批准已经提交到通道上的链码定义的组织不能使用链码。没有批准链码定义或者批准了不同的链码定义的组织不能在他们的 peer 节点上执行合约。

Org3 不同意链码

Org3 批准了一个和 Org1、Org2 不同的背书策略。结果是,Org3 不能在通道上使用 MYCC 链码。然而,Org1 或者 Org2 仍然能得到足够的背书来提交定义到通道上并且使用链码。链码的交易仍然能被添加到账本上并且保存到 Org3 的 peer 节点上。然而,Org3 不能背书交易。

一个组织可以用任何序列号或者版本号批准一个新的链码定义。这允许你批准已经提交到通道上的定义并且开始使用链码。你也可以为了纠正在批准和打包链码过程中犯得错误,而批准一个新的链码定义。

通道不同意链码定义

如果通道上的组织不同意一个链码定义,定义不能被提交到通道上。没有通道成员能用链码。

大多数组织不同意链码

Org1、Org2 和 Org3 都批准不同的链码定义。结果是,没有通道成员能得到足够的背书来提交链码定义到通道上。没有通道成员能使用链码。

组织安装不同的链码包

当它们批准一个链码定义时,每个组织能用不同的 packageID。这允许通道成员能安装不同的具备相同背书策略并且在相同的链码域名中读写数据的链码二进制文件。

组织可以使用这个功能来安装包含特定组织业务逻辑的智能合约。每个组织的智能合约可能包含额外的在它们的 peer 节点背书交易之前的验证。每个组织也能写用它们已有系统中的数据来帮助整合智能合约的代码。

使用不同的链码二进制文件

Org1 和 Org2 分别安装的 MYCC 链码版本包含了它们组织特定的业务逻辑。

用一个包安装多套链码

通过批准和提交多套链码定义的方式,你可以用一个链码包创建在一个通道上的多套链码实例。每个定义需要指定一个不同的链码名称。允许你在一个通道上运行多套智能合约实例,但让合约服从于不同的背书策略。

启动多个链码

Org1 和 Org2 用 MYCC_1 链码包来批准和提交两个不同的链码定义。结果是,两个 peer 节点都有两个链码容器运行在他们的 peer 节点上。 MYCC1 具备1/2的背书策略(译者注:2个组织中需要有1个背书),而 MYCC2 有一个2/2的背书策略(译者注:2个组织都必须背书)。

迁移到新的 Fabric 生命周期

关于迁移到新的生命周期的信息,查看 升级到2.0版本的注意事项

如果你需要升级你的通道配置来启动新的生命周期,查看 启动新的链码生命周期.

更多信息

你可以观看以下视频来学习更多关于 Fabric 链码生命周期的动机以及它是如何实现的。

Built with Hugo
Theme Stack designed by Jimmy