节点

区块链网络主要由一组 Peer 节点(或者简称节点)组成。节点托管着账本和智能合约,因此节点是网络的基本成分。回想一下,账本记录着由智能合约( Hyperledger Fabric 的智能合约储存在链码,稍后将详细介绍)生成的所有交易,并且不可篡改。智能合约和账本分别用于封装网络中的共享进程和共享信息*。因此节点是了解 Fabric 网络的良好开端。

区块链网络的其他元素也很重要:账本和智能合约、排序节点、策略、通道、应用程序、组织、身份和成员,您可以在各元素的专属章节中阅读更多相关信息。本节主要讨论节点及其与 Fabric 网络中其他元素的关系。

Peer1

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

节点可以被创建、启动、停止、重新配置甚至被删除。节点公开了一组 API(Application Programming Interface 应用程序编码端口),以供管理员和应用程序与 API 提供的服务进行交互。下文中将详细谈到这些服务。

术语

Fabric 通过一种叫做链码的技术概念来实现智能合约,简单来说,链码就是一段访问账本的代码,它是用网络支持的编程语言编写的。在本主题中,我们将使用链码这个术语,但是如果您更习惯智能合约这个名字也可以把它看成智能合约。它们其实是一回事!如果您想了解更多关于链码和智能合约的信息,请查看我们关于智能合约和链码的文档

账本和链码

让我们来更仔细地研究一下节点。我们可以看到,节点托管账本和链码。更准确地说,节点实际上托管着账本和链码的副本。注意,这是故意在 Fabric 网络中造成副本冗余,它避免了单点故障。下文中我们将了解更多关于区块链网络分布式和去中心的特性。

Peer2

节点托管账本和链码的副本。在本例中,P1 托管了账本 L1 的副本和链码 S1 的副本。单个节点上可以托管许多账本和链码。

因为节点是账本和链码的宿主,所以应用程序和管理员必须与节点进行交互才能访问账本和链码。这就是为什么节点被视为构成 Fabric 网络最基本的构件。首次创建节点时,节点上既没有账本也没有链码。稍后我们将看到如何在节点上创建账本和安装链码。

多账本

一个节点能够保存多个账本,这使得灵活的系统设计成为可能,因此非常有帮助。最简单的节点配置是一个节点只管理一个账本,但是在有需要时,一个节点保存两个或多个账本是绝对合适的。

Peer3

一个节点保存多个账本。节点保存一个或多个账本,并且每个账本都具有零个或多个适用于它们的链码。在这个例子中,我们可以看到节点 P1 保存着账本 L1 和 L2。要访问账本 L1需使用链码 S1 。而要访问账本 L2 可使用链码 S1 和 S2 。

虽然节点只保存账本副本而不保存访问账本的链码副本的情况也存在,但是很少有节点是以这种方式配置的。绝大多数节点都会安装至少一个链码,以用来查询或更新该节点上的账本副本。值得一提的是,无论用户是否安装了供外部应用程序使用的链码,节点始终都有特殊的系统链码。本主题不详细讨论这些。

多链码

一个节点所拥有的账本数量和能够访问这些账本的链码数量之间没有固定的关系。一个节点可能拥有许多链码以及许多可供这些链码访问的账本。

Peer4

上面这个例子显示的是一个节点保存了多个链码。每个账本可被多个链码访问。在这个示例中,我们可以看到节点 P1 保存着账本 L1 和 L2,其中 L1 由链码 S1 和 S2 访问,而 L2 由 S1 和 S3 访问。我们可以看到 S1 既可以访问 L1 也可以访问 L2。

稍后我们将简单谈到为什么 Fabric 中的通道概念对于在节点上保存多个账本或多个链码来说非常重要。

应用程序和节点

现在我们将展示的是应用程序如何与节点交互来访问账本。账本查询交互涉及了应用程序和节点之间简单的三步对话;账本更新交互稍微复杂一些,需要两个额外的步骤。为了帮助您开始使用 Fabric,我们稍微简化了这些步骤,但是不要担心——需要你理解的最关键点在于应用程序和节点之间进行账本查询和账本更新的交易类型之间的区别。

当应用程序需要访问账本和链码时,它们总是连接到节点上。Fabric 软件开发工具包(SDK)让程序员的上述工作变得简单,首先,SDK 的应用程序编程接口(API) 让应用程序连接到节点上,随后调用链码来生成交易,接着向网络提交交易,网络将对这些交易进行排序并将其提交到分布式账本上,最后当这一过程完成时,应用程序将接收到对应的事件。

通过与一个节点连接,应用程序可以执行链码来查询或更新账本。账本查询交易的结果会立即返回,而账本更新交易涉及了应用程序、节点和排序服务之间更复杂的交互。让我们更详细地研究一下。

Peer6

节点与排序服务一起发挥作用,保证每个节点上的账本都是最新的。在本例中,应用程序 A 连接到账本 P1 上并调用链码 S1 来查询或更新 L1。 P1 调用 S1 来生成一个包含查询结果或者账本拟更新的提案响应。应用程序 A 接收到提案响应,对于查询来说,流程到这里就已经完成了。而对于更新来说,A 会基于所有响应生成一个交易,并将其发送到 排序服务 O1 进行排序。O1 将网络上的所有交易收集到区块中并分发给包括 P1 在内的所有节点。P1 对交易进行验证,随后将其提交到账本 L1 上。一旦 L1 更新完毕,P1 会生成一个事件,随后 A 收到这一事件,标志着整个过程结束。

因为节点的本地账本副本中包含了账本查询所需的全部信息,所以节点可以立即将查询结果返回给应用程序。节点从不通过与其他节点协商来响应应用程序发出的查询。但是,应用程序可以连接到一个或多个节点上来执行查询;例如,在多个节点之间验证结果,或者如果怀疑信息不是最新的,可以从另一个节点上检索最新的结果。在图中,您可以看到账本查询是只需要三个步骤,非常简单。

更新交易的开始方式和查询交易的一样,但是多了两个额外的步骤。虽然账本更新应用程序和账本查询应用程序一样,也是连接到节点上来调用链码的,但不同的是,单个节点无法执行账本更新,这是由于其他节点必须首先同意这一改变,我们把这个过程称为共识。因此,节点向应用程序返回一个更新——该节点将在其他节点事先同意的情况下应用该更新。第一个额外步骤(步骤4)要求应用程序向全网络中的所有节点发送一组适当的拟更新,以作为向各自账本提交的交易。该步骤是由应用程序实现的,排序服务将交易打包成区块,并将这些交易区块分发到网络中所有的节点上,节点在将这些交易应用到各自本地账本副本之前会对其进行验证。如步骤5所示,由于整个排序服务需要一些时间(几秒钟)才能完成,因此应用程序不会同时收到通知。

下文中将继续讨论排序服务的详细特性,想要深入了解此流程,请参阅交易流程主题。

节点和通道

虽然本节讨论的是节点而不是通道,但还有必要花点时间来了解一下节点是如何通过通道来彼此交互以及与应用程序交互的,通道是区块链网络的一种机制,有了它区块链网络中的一组组件就能够私下通信和交易。

这些组件通常是节点、排序节点和应用程序,通过加入一个通道,这些组件同意协作共享和管理与该通道关联的相同的账本副本。从概念上讲,您可以将通道看作类似于朋友组(尽管通道的成员并不需要是朋友!)一个人可能有几组朋友,每组朋友都有他们一起做的活动。这些群体可能是完全独立的(一群工作上的朋友对比于一群爱好上的朋友),或者他们之间可能有交叉。但不管怎样,每个组都是自己的实体,具有某种“规则”。

Peer5

通道允许一组特定的节点和应用程序在区块链网络中彼此通信。在本例中,应用程序 A 可以使用通道 C 直接与节点 P1和 P2通信。你可以把通道看成特定应用程序和节点之间通信的通道。(为了简单起见,此图中没有显示排序节点,但是必须在一个正常运行的网络中显示排序节点。)

我们看到通道的存在方式与节点不同——将通道看作由物理节点集合形成的逻辑结构更合适。节点为通道的访问和管理提供控制点,理解这一点非常重要。

节点和组织

既然您已经清楚了节点及其与账本、链码和通道的各自关系,那您将能够看到多个组织是如何组合在一起形成区块链网络的。

区块链网络的管理者是一系列组织,而不是单个组织。因为节点属于这些组织,并且是这些组织与网络的连接点,所以它对于这种分布式网络的构建至关重要。

Peer8

区块链网络中的节点和多个组织。区块链网络是由不同组织所拥有和提供的节点构建而成的。在这个例子中,我们看到四个组织贡献了八个节点来组成一个网络。通道 C 连接了网络 N 中的五个节点—— P1、P3、P5、P7 和 P8。这些组织拥有的其他节点尚未连接到此通道,但它们通常至少连接到一个其他通道上。由特定组织开发的应用程序将连接到他们自己组织的节点以及不同组织的节点上。同样,为了简单起见,此图中没有显示排序节点。

务必了解区块链网络的形成过程,这一点十分重要。区块链网络是由多个向其提供资源的组织形成和管理的。节点是我们在本主题中讨论的资源,但是组织提供的资源不仅仅是节点。这里有一个原则——如果组织不向网络贡献自己的资源,那么网络根本就不会存在。此外,区块链网络随着协作组织所提供资源的增减而增长和收缩。

您可以看到(除了排序服务之外)没有集中的资源——在上面的示例中,如果组织没有将自己的节点贡献给网络 N ,那么N将不存在。这反映了以下事实:除非各组织把构成网络的资源贡献出来,否则网络在任何意义上都不存在。此外,网络并不依赖于任何一个单独的组织——不管其他组织加入或离开,只要还有一个组织,网络就还会继续存在。这就是网络去中心化的核心。

就像上边的例子,不同的组织中的应用程序可能相同也可能不同。这是因为一个组织完全取决于它的应用程序如何处理其节点的账本副本。这意味着虽然各组织的节点保存着完全相同的账本数据,但是应用程序和呈现逻辑都可能会因组织而异。

应用程序可以连接到其所在组织上的节点,也可以连接到另一个组织上的节点,这取决于所需账本交互的性质。对于账本查询交互来说,应用程序通常连接到它们自己组织的节点上。对于账本更新交互来说,下文中我们将谈到为什么应用程序需要连接到代表每个必须对账本更新背书的组织的节点上。

节点和身份

既然您已经清楚了来自不同组织的节点是如何聚集在一起形成区块链网络的,那么有必要花一些时间来了解组织管理员是如何将节点分配到组织中去的。

节点会被分配一个身份,这一身份是由特定证书授权中心颁发给它们的数字证书赋予的。本指南的其他部分讲解了更多关于 X.509 数字证书工作原理的信息,但是就目前而言,可以将数字证书看作是一个 ID 卡,它提供了大量关于节点的可验证信息。网络中的每个节点都由所属组织的管理员分配一个数字证书。

Peer9

当节点连接到通道时,节点的数字证书通过该通道的 MSP 识别其所属组织。在这个例子中,P1 和 P2 的身份由证书授权中心 CA1 颁布。通道 C 在其通道配置的策略中规定由 CA1 颁发的身份应该使用组织1的 MSP (ORG1.MSP) 来与 Org1 关联。类似的,P3 和 P4 由 ORG2.MSP 识别为 Org2 的一部分。

当一个节点使用通道连接到区块链网络时,通道配置中的策略使用节点的身份来确定其权限。身份与组织之间的映射是由一个名为成员服务提供者(MSP)的组件建立的——它规定了如何在特定组织中将一个特定角色分配给一个节点,并让节点相应地获得对区块链资源的适当访问权。此外,因为节点只能由单个组织拥有,所以它与单个 MSP 关联。稍后我们将谈到更多关于节点访问控制的内容,本指南的其他部分有一整节是关于 MSP 和访问控制策略的。但是现在,可以将 MSP 看作是在区块链网络中提供个人身份和特定组织角色之间的链接。

稍微讨论一个额外的话题,节点以及所有与区块链网络交互的东西都从它们的数字证书和 MSP 中获得它们的组织身份。如果节点、应用程序、最终用户、管理员和排序服务想要与区块链网络进行交互,那么它们必须具有身份和关联的 MSP。我们为使用身份与区块链网络交互的每个实体提供了一个名称——主体(principal)。在其他章节中,您可以了解更多关于主体和组织的信息,但是现在你已经有足够的知识来继续学习节点了!

最后,要注意的是节点位于哪里并不重要——它可以位于云端,或者位于一个组织的数据中心中,又或者位于一个本地机器上-——决定节点所述组织的是与该节点相关的数字证书。在我们上面的例子中,P3 可以位于 Org1 的数据中心,但是只要与 P3 相关联的数字证书是由 CA2 颁发,那么 P3 就属于 Org2。

节点和排序节点

我们已经看到,节点构成了区块链网络的基础,它承载着账本和智能合约,与节点相连接的应用程序可以对账本和智能合约进行查询和更新。然而,应用程序和节点使用一种机制进行彼此交互以确保每个节点上的账本始终都彼此一致,这一机制是由由名为排序节点的特殊节点来协调的,现在我们就来讨论这些节点。

更新交易与查询交易有很大的不同,这是因为光靠单个节点无法完成账本更新(更新需要网络中其他节点的同意)。一个节点需要等到其他节点对一项账本更新交易表示同意之后才能将该交易实行到自己的本地账本上。这个过程称叫做共识,比起简单的查询,共识需要的时间更长。但是,当所有需要批准某交易的节点都已批准该交易,并且已将该交易提交到账本上时,那么各节点会把账本已经更新的消息通知给与其连接的应用程序。下文将继续详细谈论节点和排序节点是如何管理共识过程的。

具体来说,想要更新账本的应用程序会涉及到三个步骤,这些步骤确保了区块链网络中的所有节点能保持彼此账本始终一致。

  • 第一步,应用程序与一组背书节点合作,每个背书节点都向该应用程序提供对拟账本更新的背书,但是并不会把该拟更新应用到自己的账本副本上。
  • 第二步,把各背书节点做出的背书收集起来作为交易打包成区块。
  • 最后一步,将这些区块分发给每个节点,节点会对每项交易进行验证,随后将交易提交到各自账本副本上。

正如下文中你将看到的,排序节点是上述过程的核心,所以让我们来深入研究一下应用程序和节点如何使用排序节点生成账本更新,而这些更新可被持续应用到一个分布式、可复制的账本上。

第一阶段:提案

交易流程的第一阶段涉及的是一个应用程序和一组节点之间的交互,并不涉及排序节点。阶段一发生的只是:应用程序请求不同组织的背书节点对拟链码调用的结果做出同意。

要开始第一阶段,应用程序必须先生成一个交易提案,并将该提案发送给每个需要对交易做出背书的节点进行背书。随后,每个背书节点都使用该交易提案独立地执行一个链码,以生成交易提案响应。背书节点不会将此更新应用到账本上,它只是简单地对交易进行签名并将其返回给应用程序。一旦应用程序收到足够数量的签名提案响应,那么交易流程的第一阶段就完成了。让我们来更详细地研究一下这个阶段。

Peer10

返回已背书提案响应的各个节点会独立执行交易提案。在本例中,应用程序 A1 生成交易 T1 提案 P,并将其发送给通道 C 上的节点 P1 和 P2。P1 使用交易 T1 提案 P 调用链码 S1,以生成 交易 T1 响应 R1,并且 P1 通过 E1 对该响应进行背书。P2 独立使用交易 T1 提案 P 来执行 S1,以生成交易 T1 响应 R2,该响应是由 E2 背书的。应用程序 A1 收到交易 T1 发来的两个已背书的响应,即 E1 和 E2。

最初,应用程序选择一组节点来生成一些拟账本更新。应用程序会选择哪些节点呢?这取决于背书策略(为链码定义的),背书策略定义了一群需要在网络接受某项拟账本更新之前对其作出背书的组织。这就是达成共识的真正含义——在任何节点的账本接受拟账本更新之前,所有相关组织必须对该拟账本更新进行背书。

节点通过添加自己的数字签名来对提案响应进行背书,并使用自己的私钥为整体进行签名。该背书随后可被用于证明此组织的节点生成了一个特定响应。在我们的示例中,如果节点 P1 属于组织 Org1,则背书 E1 对应了一个数字证明——“账本 L1 上的交易 T1 响应 R1 是由 Org1 的 节点 P1 提供的!”。

节点通过添加其数字签名,并使用其私钥对整个有效负载签名,来背书提案响应。此背书随后可用于证明该组织的节点生成了特定的响应。在我们的示例中,如果节点 P1 属于组织 Org1,则背书 E1 对应一个数字证明——“在账本 L1 上的交易 T1 的反馈 R1 已经被 Org1 的 peer P1 提供了!”。

当应用程序收到足够数量节点发来的签名提案响应时,第一阶段就结束了。我们注意到,对于相同的交易提案,不同的节点可能会向应用程序返回不同的,因此也就不一致的交易响应。这获许只是因为各节点生成交易响应的时间不同,账本的世界状态也不同,在这种情况下,应用程序只需请求一个更新版本的提案响应即可;又或许是因为链码是不确定的,这种情况发生的可能性不太大,但是一旦发生,后果极其严重。不确定性是链码和账本的敌人,如果发生这种情况,则表明提案的交易存在严重问题,因为不一致的结果显然不能适用于账本。单个节点无法知道自己的交易结果是非确定性的——只有将所有交易响应收集在一起进行比较才能发现不确定性。(严格来说,这些依然不够,不过我们暂且不继续往下谈,后续在交易模块会深入探讨非确定性的问题。)

在第一阶段的最后,应用程序可以按照自己的医院丢弃不一致的交易响应,从而有效地提前终止交易流程。稍后我们将看到,如果应用程序试图使用一组不一致的交易响应来更新账本,它将被拒绝。

第二阶段:排序和把交易打包成区块

交易流程的第二阶段是打包阶段。排序节点是该流程的关键——多个应用程序向排序节点发送交易,其中包含了已背书的交易提案响应,随后排序节点将这些交易排序进区块。有关排序和打包阶段的更多细节,请查看排序阶段的概念信息

第三阶段:验证和提交

在阶段二的末尾,我们看到排序节点负责的是对提案的交易更新进行收集、排序、打包进区块,以便分发给各节点,这些任务虽简单但却十分关键。

交易流程的最后一个阶段涉及到从排序节点到 Peer 节点的区块的分发和随后的验证,节点可将这些交易应用到账本上。具体来说,所有节点都会对一个区块内的每一笔交易进行验证,以确保这些交易在应用到账本上之前已经得到所有相关组织的背书。未成功的交易会被留下来进行审计,但不会提交到账本上。

Peer12

排序节点的第二个角色是将区块分发给 peer 节点。在本例中,排序节点 O1 将区块 B2 分配给节点 P1 和 P2。节点 P1 处理区块 B2,最终将一个新的区块添加到节点 P1 的账本 L1 上。同时,节点 P2 处理区块 B2,最终将一个新的区块添加到节点 P2 的账本 L1 上。一旦这个过程结束,节点 P1和 P2 各自的账本 L1 就已经一致更新了,并且 P1 和 P2 都会把交易已处理完毕的消息通知给与它们连接的应用程序。

阶段三从排序节点将区块分发给与其连接的所有 peer 节点开始。peer 节点和通道上的排序节点相连接,这样一来,当生成一个新区块时,连接到排序节点的所有 Peer 节点都将收到这个新区块的副本。随后每个 Peer 节点独立地处理该新区块,不过通道上各节点的处理方式完全相同。因此,我们将看到各节点的账本依然保持一致。同样值得注意的是,并不是每个 peer 节点都需要连接到一个排序节点上——peer 节点可以使用 gossip 协议将区块信息发送给其他(未连接到排序节点的) Peer 节点,这些 Peer 节点在收到信息后也可以独立地处理新区块。不过我们下次再讨论这个问题!

当接收到一个区块时,节点将按照各交易在区块中出现的顺序依次进行处理。各节点将根据生成交易的链码中的背书策略对每项交易进行验证,以确保所有交易都已被相关组织背书。例如,某些交易可能只需要一个组织的背书,而另一些交易可能需要多个组织的背书才能被视为有效。该验证过程将验证所有相关组织是否都已经产生了相同的结果。还要注意的是,此验证与阶段一中的背书检查不同,在背书检查中,是应用程序接收了背书节点发送的响应,并作出发送提案交易的决定。如果应用程序发送错误的交易,违反了背书策略,那么节点在阶段三的验证环节依然能够拒绝该交易。

如果一笔交易被正确地背书,节点将试图把它应用于账本。为此,节点必须执行账本一致性检查,以验证账本的当前状态与生成提案更新时的账本状态是否兼容。两个状态可能不总是兼容的,即便交易已经被所有相关组织背书了。例如,另一个交易可能更新了账本中的相同资产,这就导致前一个交易更新不再有效,因此无法将其应用到账本上。通过这种方式,每个节点的账本副本在整个网络中保持一致,这是因为它们都遵循相同的验证规则。

在节点成功地验证每一笔交易之后,它将更新账本。节点不会把失败的交易应用到账本上,但为了审计会保留这些交易,就像成功的交易一样。这意味着节点中的区块与从排序节点接收到的区块几乎完全相同,唯一不同的是节点区块中的每个交易上都存在有效或无效指示符。

我们还注意到,阶段三不需要运行链码,链码运行只发生在阶段一,这一点很重要。它意味着链码只需存在于背书节点上,并不要求在整个区块链网络上都能使用链码。这样一来,只有参与背书的组织才能看到链码的逻辑,因此这一点通常很有帮助。而链码(交易提案响应)的输出则与之相反,链码输出会在通道上的各节点间共享,无论这些节点是否参与了该交易的背书。这种背书节点的特殊设计旨在提升区块链网络的可扩展性和机密性。

最后,每次将一个区块提交到节点的账本上时,该节点都会生成一个适当的事件区块事件包括完整的区块内容,而区块交易事件只包含总结信息,例如区块中的每个交易经验证显示有效还是无效。链码执行产生的链码事件也可以在这个时候发布出去。应用程序可以注册这些事件的类型,以便在这些事件发生时,它可以得到通知。这些通知标志着交易流程最后一步结束了。

总之,第三阶段中,排序节点生成的区块都被一致地应用于账本。将交易严格排序到区块中,这使得每个节点都可以验证交易更新是否在整个区块链网络中得到一致应用。

排序节点和共识

上述的整个交易流程叫做共识,这是因为所有节点都已就交易的顺序和内容达成一致,排序节点在这个流程中扮演调节者的角色。共识是一个多步骤的过程,只有当流程完成时,应用程序才会收到账本更新的通知——在不同的节点上,更新完成的时间可能略有不同。

我们将在以后的排序节点主题中更详细地讨论它,但是现在我们可以先这样理解排序节点:它从应用程序那里收集和分发提案的账本更新,以供节点进行验证并最终应用到账本上。

就是这样!现在我们已经完成了节点以及与 Fabric 相关的其他组件的学习。我们已经看到,节点在很多方面都是最基本的元素——它们组成网络、托管链码和账本、处理交易提案和响应,并且与其他节点一致地把交易更新应用到账本上,从而使账本的状态保持最新。