引言

如今,网络上流传着“链码”即“智能合约”的不少网文,这可能与Fabric联盟链出现之前Bitcoin与Ethereum两种公有链中存在类似概念所致。

其实,在Hyperledger Fabric联盟链中,“链码”与“智能合约”根本不是同一个概念,但是存在联系。

本文正是想澄清上述模糊所带来的纠纷。

从应用程序开发人员的角度来看:

智能合约与账本一起构成了 Hyperledger Fabric 区块链系统的核心。

账本包含了与一组业务对象的当前和历史状态有关的事实,而智能合约定义了生成这些被添加到账本中的新事实的可执行逻辑。Fabric联盟链网络的系统管理员通常使用链码将相关的智能合约组织起来进行部署。此外,链码也可以用于 Fabric 的底层系统编程。

在下文中,我们将重点讨论为什么存在智能合约链码,以及如何和何时使用它们。

智能合约

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

Hyperledger Fabric 2.5.4开发之智能合约和链码_区块链

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

在一个区块链网络中,我们可以将这些合约转换为可执行程序(业内称为“智能合约”),从而实现了各种各样的新可能性。之所以这样说,原因在于:

智能合约可以为任何类型的业务对象实现治理规则,以便在执行智能合约时自动执行这些规则。

例如,一个智能合约可能会确保新车在指定的时间内交付,或者根据预先安排的条款释放资金,前者可改善货物流通,而后者可优化资本流动。然而最重要的是,智能合约的执行要比人工业务流程高效得多。

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

术语:智能合约与链码

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

Hyperledger Fabric 2.5.4开发之智能合约和链码_智能合约_02


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

从上图中我们可以看到,vehicle 链码包含了以下三个智能合约:carsboats 和 trucks;而 insurance 链码包含了以下四个智能合约:policyliabilitysyndication 和 securitization。以上每种智能合约都涵盖了与车辆和保险有关的业务流程的一些关键点。在本文中,我们将以 car 智能合约为例展开讨论。我们可以看到:


智能合约是一个特定领域的程序,它与特定的业务流程相关,

链码则是一个一组相关智能合约安装和实例化的技术容器


[参考资料]4中对于二概念的介绍如下。

链码:是一种用于部署代码到 Hyperledger Fabric 区块链网络中的通用容器。链码中定义一个或多个相关联的智能合约。每个智能合约在链码中有一个唯一的标识名。应用程序通过合约名称去访问链码容器内的指定的智能合约。

智能合约(Smart Contract)是一种高级编程抽象的例子,可以在链码容器中定义智能合约。当一个链码被安装和实例化时,则链码内所有的智能合约对于相关联的通道(Channel)来说都是可用的。

多个智能合约能够被定义在同一个链码内。每一个智能合约都通过链码内的名字而被唯一标识。

注:通常在构造类时分配名称,如果没有明确指明合约名,则会分配一个默认的名字--类名。建议使用显式的 DNS 样式命名方法,对组织清晰、有意义的名称有帮助;例如:peer0.org1.example.com


合约名称在链码文件内必须是唯一的。在部署前,一些代码编辑器将会检测是否存在具有相同类名的多个定义的情况。如果存在多个类使用了相同的合约名,无论是显式还是隐式指定,链码都将会返回错误。


账本

以最简单的方式来说:区块链记录着更新账本状态的交易,且记录不可篡改

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

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

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

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

智能合约编程

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

归纳来看,智能合约的核心是一组 交易 定义。例如,在官方案例文件fabcar.js 中,你可以看到一个创建了一辆新车的智能合约交易:

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)));
}

智能合约几乎可以描述所有与多组织决策中数据不可变性相关的业务案例。智能合约开发人员的主要工作是:

将一个现有的业务流程(可能是管理金融价格或交付条件)用 JavaScript、GO或 Java 等编程语言来表示成一个智能合约。

背书(Endorsement)

“背书”是我所讨厌的网络术语之一,英语即“Endorsement”,其朴素的汉语意思就是:经过权威人士(或者机构)开具证明(或者说“签字”),支票应用中的XXX领导签字就用这个词。另外,在网络营销环境中,名人(代言人)作产品宣传等,即是“背书”(endorse)。在Fabric区域链中也是类似意思。

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

Hyperledger Fabric 2.5.4开发之智能合约和链码_Fabric_03

 上图中(右下方)强调指出,每个智能合约都有一个与之关联的背书策略。这个背书策略定义了在智能合约生成的交易被认证为有效之前,哪些组织必须同意该交易。

一个示例背书策略可能是这样定义的:


参与区块链网络的四个组织中有三个必须在交易被认为有效之前签署该交易。所有的交易,无论是有效的还是无效的,都会被添加到分布式账本中,但只有有效交易会更新世界状态。


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

背书策略是 Hyperledger Fabric 与Ethereum或Bitcoin等其他区块链的区别所在。在这些区块链系统中,网络上的任何节点都可以生成有效的交易。而 Hyperledger Fabric 更真实地模拟了现实世界:

交易必须由 Fabric 网络中受信任的组织验证!

例如,一个政府组织必须签署一个有效的 issueIdentity 交易,或者一辆车的 买家 和 卖家 都必须签署一个 车辆 转移交易。背书策略的设计旨在让 Hyperledger Fabric 更好地模拟这些真实发生的交互。

最后,背书策略只是 Hyperledger Fabric 中策略的一个例子。还可以定义其他策略来确定谁可以查询或更新账本,或者谁可以在网络中添加或删除参与者。

总体来说,虽然区块链网络中的组织联盟并非一成不变,但是它们需要事先商定好策略。

实际上,策略本身可以定义对自己进行更改的规则。

有效交易

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

在执行智能合约时世界状态没有更新!

Hyperledger Fabric 2.5.4开发之智能合约和链码_智能合约_04

 注意到,上图下部中央位置的方框内指明:所有的交易都有一个识别符、一个提案和一个被一群组织签名的响应。

而且:所有交易,无论是否有效,都会被记录在区块链上,但仅是有效的交易才会更新世界状态。

观察上图的下部中央位置的方框内 车辆转移 交易。您可以看到 ORG1 和 ORG2 之间为转移一辆车而进行的交易 t3。看一下交易是如何通过输入 {CAR1,ORG1,ORG2} 和输出 {CAR1.owner=ORG1,CAR1.owner=ORG2} 来表示汽车的所有者从 ORG1 变为了 ORG2。注意输入是如何由应用程序的组织 ORG1 签名的,输出是如何由背书策略标识的两个组织( ORG1 和 ORG2 )签名的。

另外,上述这些签名是使用每个参与者的私钥生成的,这意味着网络中的任何人都可以验证网络中的所有参与者是否在交易细节上达成了一致。

一项交易被分发给网络中的所有节点,各节点通过两个阶段对其进行验证

第一步:根据背书策略检查交易,确保该交易已被足够的组织签署。

第二步:继续检查交易,以确保当该交易在受到背书节点签名时它的交易读集与世界状态的当前值匹配,并且中间过程中没有被更新。

如果一个交易通过了这两个测试,它就被标记为有效。所有交易,不管是有效的还是无效的,都会被添加到区块链历史中,但是仅有效的交易才会更新世界状态。

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


通道

Hyperledger Fabric 允许一个组织利用通道同时参与多个、彼此独立的区块链网络。通过加入多个通道,一个组织可以参与一个所谓的网络的网络

通道在维持数据和通信隐私的同时还提供了高效的基础设施共享。通道是足够独立的,可以帮助组织将自己的工作与其他组织的分开,同时它还具有足够的协调性,在必要时能够协调各个独立的活动。

Hyperledger Fabric 2.5.4开发之智能合约和链码_Fabric_05

 从上图中易见,通道在一群组织之间提供了一种完全独立的通信机制

当链码定义被提交到通道上时,该通道上所有的应用程序都可以使用此链码中的智能合约。虽然智能合约代码被安装在组织节点的链码包内,但是只有等到链码被定义在通道上之后,该通道上的成员才能够执行其中的智能合约。

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

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

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

跨通道通信

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

这些都是智能合约彼此通信的限制,有兴趣的读者可以进一步结合官网链码生命周期主题作进一步探讨。

系统级链码简介

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

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

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

底层的 Fabric 开发人员和管理员可以根据自己的需要修改这些系统链码!

但是,系统链码的开发和管理是一项专门的活动,完全独立于智能合约的开发,一般来说,没有必要进行系统链码的开发和管理。

系统链码对于一个 Hyperledger Fabric 网络的正常运行至关重要,因此必须非常小心地处理系统链码的更改。例如,如果没有正确地开发系统链码,那么有可能某个 Peer 节点更新的世界状态或区块链备份与其他 Peer 节点的不同。这种缺乏共识的现象是账本分叉的一种形式,是极不理想的情况。


参考资料