本文较全面介绍Fabric 2.X开发中链码的生命周期全过程,并辅以图解。然后,总结了链码部署的典型场景。本文结论适合于从Fabric区块链从2.0到截止目前最新的2.5的各个版本。
链码(Chaincode)是什么?
链码(Chaincode),也称智能合约(是Ethereum区块链中的典型称呼),是一个用Go、Node.js或Java编写的程序,用于实现指定的接口。Chaincode运行在一个与背书节点进程隔离的安全Docker容器中。Chaincode通过应用程序提交的交易初始化和管理分类帐状态。
按照1996年发明智能合约概念的法律学者尼克.绍博给出的定义,智能合约是指嵌入软件或者硬件中的合同条款。
链码通常处理网络成员同意的业务逻辑,因此它可以被视为“智能合约”。由链码创建的分类帐更新仅限于该链代码,不能由另一个链代码直接访问。然而,在同一网络内,给定适当的许可,链码可以调用另一个链码来访问其状态。
在本文中,我们将通过区块链网络运营商而不是应用程序开发人员的视角来探索链码。Chaincode运营商可以将本文作为如何使用Fabric Chaincode生命周期在其网络上部署和管理链代码的指南。
部署链码
Fabric链码生命周期是一个过程,允许多个组织就链码在通道上使用之前的操作方式达成一致。网络运营商将使用Fabric生命周期来执行以下任务:
- 安装并定义链码
- 升级chaincode
- 部署场景
- 迁移到新的Fabric生命周期
您可以通过创建一个新通道并将通道功能设置为V2_0来使用Fabric链码生命周期。您将无法使用旧的生命周期在启用V2_0功能的通道上安装、实例化或更新链码。但是,在启用V2_0功能后,仍然可以调用使用上一个生命周期模型安装的链码。如果您正在从v1.4.x网络升级,并且需要编辑频道配置以启用新的生命周期,请查看博文启用新链码生命周期。
安装并定义链码
Fabric链码生命周期要求组织同意定义链码的参数,如名称、版本和链代码背书策略。通道成员通过以下四个步骤达成一致。并不是每个通道上的组织都需要完成每一步。
- 打包链码:此步骤可以由一个组织完成,也可以由每个组织完成。
- 在Peer上安装链码:每个将使用链码背书交易或查询总账的组织都需要完成这一步骤。
- 批准组织的链码定义:每个将使用链码的组织都需要完成此步骤。链码定义需要得到足够数量的组织的批准,以满足通道的生命周期结束策略(默认情况下为多数),然后才能在通道上启动链码。
- 将链码定义提交到通道:一旦通道上所需数量的组织获得批准,提交事务就需要由一个组织提交。提交者首先从已经批准的组织的足够多的Peer那里收集背书,然后提交事务以提交链码定义。
本文将详细概述Fabric链码生命周期的操作,而不是特定命令。要了解有关如何使用Peer CLI使用Fabric生命周期的更多信息,请参阅将智能合约部署到通道教程或Peer生命周期命令参考。
第一步:打包智能合约
Chaincode需要打包在tar文件中,然后才能安装在您的对等设备上。您可以使用Fabric Peer二进制文件、Node Fabric SDK或GNU tar等第三方工具来打包链码。创建链码包时,需要提供链码包标签,以创建简洁易懂的包描述。
如果使用第三方工具对链码进行打包,则生成的文件需要采用以下格式。结构对等二进制文件和结构SDK将自动创建此格式的文件。
链码需要打包在一个tar文件中,以.tar.gz文件扩展名结尾。
tar文件需要包含两个文件(没有目录):一个元数据文件“Chaincode Package metadata.json”和另一个包含链代码文件的tar。
“Chaincode Package Metadata.json”包含指定链码语言、代码路径和包标签的json。您可以在下面看到元数据文件的示例:
{"Path":"fabric-samples/chaincode/fabcar/go","Type":"golang","Label":"fabcarv1"}
上图中,链码由Org1和Org2分别打包。两个组织都使用MYCC_1作为包标签,以便使用名称和版本来识别包。组织没有必要使用相同的包装标签。
第二步:在对等设备上安装链码
您需要在每个将执行和认可事务的对等体上安装chaincode包。无论使用CLI还是SDK,都需要使用对等管理员完成此步骤。您的对等方将在安装链代码后生成链代码,如果链代码出现问题,则返回生成错误。建议组织只打包一次链码,然后在属于其组织的每个对等体上安装相同的包。如果渠道希望确保每个组织运行相同的链码,一个组织可以打包链码并将其发送给带外的其他渠道成员。
成功的安装命令将返回一个链码包标识符,该标识符是包标签和包的哈希值的组合。此程序包标识符用于将对等设备上安装的链代码程序包与组织批准的链代码定义相关联。保存标识符以备下一步使用。您还可以通过使用peer CLI查询对等设备上安装的软件包来查找软件包标识符。
此图中,Org1和Org2的对等管理员在加入通道的对等上安装链码包MYCC_1。安装chaincode包将构建chaincode并创建包标识符MYCC_1:hash。
第三步:批准组织的链码定义
链代码由链码定义管理。当通道成员批准链码定义时,该批准将充当组织对其接受的链码参数的投票。这些经批准的组织定义允许渠道成员在将链码用于渠道之前就链码达成一致。链码定义包括以下参数,这些参数需要在各个组织之间保持一致:
- 名称:应用程序在调用链代码时将使用的名称。
- 版本:与给定链代码包关联的版本号或值。如果升级链代码二进制文件,还需要更改链代码版本。
- 序列:定义链代码的次数。此值是一个整数,用于跟踪链代码升级。例如,当您第一次安装并批准链代码定义时,序列号将为1。下次升级链代码时,序列号将增加到2。
- 背书策略:哪些组织需要执行和验证事务输出。背书策略可以表示为传递给CLI的字符串,也可以引用通道配置中的策略。默认情况下,背书策略设置为“渠道/应用程序/背书”,默认情况下要求渠道中的大多数组织对交易进行背书。
- 集合配置:指向与链代码关联的专用数据集合定义文件的路径。有关私有数据集合的更多信息,请参阅私有数据体系结构参考。
- 初始化:所有链代码都需要包含用于初始化链代码的Init函数。默认情况下,此函数从不执行。但是,您可以使用链代码定义来请求Init函数是可调用的。如果请求执行Init,结构将确保Init在任何其他函数之前被调用,并且只被调用一次。
- ESCC/VSCC插件:此链代码要使用的自定义背书或验证插件的名称。
链代码定义还包括包标识符。这是每个想要使用链代码的组织所必需的参数。不需要所有组织的程序包ID都相同。组织可以批准链码定义,而无需安装链代码包或在定义中包含标识符。
每个想要使用链码的渠道成员都需要批准其组织的链码定义。此批准需要提交给订购服务,然后分发给所有对等方。此批准需要由您的组织管理员提交。成功提交审批事务后,审批的定义将存储在一个集合中,该集合可供组织的所有对等方使用。因此,即使您有多个同行,您也只需要为组织批准一次链代码。
在此,Org1和Org2的组织管理员批准其组织的MYCC链码定义。链代码定义包括链码名称、版本和背书策略等字段。由于两个组织都将使用链码来背书交易,因此两个组织的已批准定义都需要包含packageID。
第四步:将链码定义提交到通道
一旦足够数量的渠道成员批准了链码定义,一个组织就可以将该定义提交给渠道。在使用Peer CLI将定义提交到通道之前,可以使用checkcommitreness命令根据通道成员已批准定义来检查是否应成功提交链代码定义。提交事务建议首先发送给通道成员的对等方,后者查询为其组织批准的链码定义,并在其组织批准后对该定义进行背书。然后将事务提交给订购服务,订购服务随后将链码定义提交给通道。提交定义事务需要以组织管理员的身份提交。
在定义成功提交到渠道之前,需要批准该定义的“Channel/Application/LifecycleEndorsement”策略控制。默认情况下,此策略要求通道中的大多数组织认可该事务。生命周期背书策略与链码背书策略是分开的。例如,即使链码背书策略只需要一个或两个组织的签名,大多数渠道成员仍然需要根据默认策略批准链码定义。提交渠道定义时,您需要针对渠道中足够多的对等组织,以满足您的生命周期认可策略。您可以在策略概念主题中了解有关结构链代码生命周期策略的更多信息。
您还可以将“Channel/Application/LifecycleEndorsement”策略设置为签名策略,并明确指定通道上可以批准链码定义的组织集。这允许您创建一个通道,其中选定数量的组织充当链代码管理员,并管理通道使用的业务逻辑。如果您的渠道有大量的Idemix组织,这些组织无法批准链码定义或认可链码,并且可能因此阻止渠道获得多数,则您也可以使用签名策略。
Org1或Org2的一名组织管理员将链码定义提交给通道。通道上的定义不包括packageID。
组织可以在不安装链码包的情况下批准链码定义。如果组织不需要使用链码,他们可以批准不带包标识符的链码定义,以确保满足生命周期背书策略。
在将链码定义提交到通道后,链码容器将在安装了链码的所有对等体上启动,允许通道成员开始使用链码。链码容器可能需要几分钟才能启动。您可以使用链码定义来要求调用Init函数来初始化链代码。如果请求调用Init函数,则链码的第一次调用必须是对Init函数的调用。Init函数的调用受链码认可策略的约束。
一旦在通道上定义了MYCC,Org1和Org2就可以开始使用链码。在每个对等体上第一次调用链码会启动该对等体上的链码容器。
升级链码
您可以使用与安装和启动chainocode相同的Fabric生命周期过程升级链码。您可以升级链码二进制文件,也可以只更新链码策略。按照以下步骤升级链码:
[第一步]重新打包链码:如果您正在升级链码二进制文件,则只需要完成此步骤。
Org1和Org2升级链代码二进制文件并重新打包链代码。两个组织都使用不同的包装标签。
[第二步]在对等设备上安装新的链代码包:同样,如果您正在升级链代码二进制文件,则只需要完成此步骤。安装新的链代码包将生成一个包ID,您需要将其传递给新的链码定义。您还需要更改链代码版本,生命周期过程使用该版本来跟踪链代码二进制文件是否已升级。
Org1和Org2在其对等设备上安装新程序包。安装将创建一个新的packageID。
[第三步]批准新的链代码定义:如果要升级链代码二进制文件,则需要更新链代码定义中的链代码版本和包ID。您还可以更新链代码背书策略,而无需重新打包链代码二进制文件。渠道成员只需批准具有新策略的定义。新定义需要将定义中的序列变量增加一。
组织1和组织2的组织管理员批准各自组织的新链代码定义。新定义引用新的packageID并更改链代码版本。由于这是链代码的第一次更新,因此序列从1增加到2。
[第四步]将定义提交给渠道:当足够数量的渠道成员批准了新的链码定义时,一个组织可以提交新的定义,以将链码定义升级到渠道。作为生命周期过程的一部分,没有单独的升级命令。
Org1或Org2的组织管理员将新链码定义提交给通道。
提交链码定义后,将启动一个新的链码容器,其中包含升级后的链码二进制文件中的代码。如果您请求执行链码定义中的Init函数,则需要在成功提交新定义后再次调用Init函数来初始化升级后的链代码。如果在不更改链码版本的情况下更新了链码定义,则链码容器将保持不变,并且不需要调用Init函数。
一旦新定义被提交到通道,每个对等方将自动启动新的链码容器。
Fabric链码生命周期使用链码定义中的序列来跟踪升级。所有通道成员都需要将序列号增加一,并批准一个新的定义来升级链码。version参数用于跟踪链码二进制文件,只有在升级链码二进制时才需要更改。
部署场景
接下来的示例将说明如何使用Fabric链码生命周期来管理通道和链码。
加入通道
新组织可以加入已定义链码的通道,并在安装链码包并批准已提交给通道的链码定义后开始使用链码。
Org3加入通道并批准先前由Org1和Org2提交到通道的相同链码定义。
在批准链码定义后,新组织可以在Peers上安装包后开始使用链码,不需要再次提交该定义。如果背书策略设置为需要大多数通道成员背书的默认策略,则背书策略将自动更新以包括新组织。
启动链码
在此,链码容器将在Org3 Peer上第一次调用链码之后启动。
更新背书策略
开发者可以使用链码定义来更新背书策略,而无需重新打包或重新安装链码。通道成员可以使用新的认可策略批准链码定义,并将其提交给通道。
批准新链码定义
此图中,Org1、Org2和Org3批准一个新的背书策略,要求所有三个组织都背书一个交易。它们将定义序列从1递增到2,但不需要更新链码版本。
新的背书策略将在新定义提交给通道后生效。通道成员不必通过调用链码或执行Init函数来重新启动链码容器,即可更新背书策略。
提交新的链码定义
此图展示了一个组织将新的链码定义提交给通道以更新背书策略。
在不安装链码的情况下批准定义
您可以在不安装链码包的情况下批准链码定义。这允许您在链码定义提交到渠道之前对其进行背书,即使您不想使用链码来背书交易或查询分类账。您需要批准与通道的其他成员相同的参数,但不需要将packageID作为链码定义的一部分。
此图中,Org3未安装链码包。因此,他们不需要提供packageID作为链码定义的一部分。然而,Org3仍然可以认可已经承诺给该频道的MYCC的定义。
一个组织不同意链代码的定义
未批准已提交到通道的链码定义的组织不能使用链码。未批准链码定义或批准其他链码定义的组织将无法在其同行上执行链码。
上图中展示了Org3批准具有与Org1和Org2不同的背书策略的链码定义。因此,Org3无法在通道上使用MYCC链码。然而,Org1或Org2仍然可以获得足够的背书,以便将定义提交给通道并使用链码。链代码中的交易仍将添加到分类账中,并存储在Org3对等方上。但是,Org3将无法为交易背书。
组织可以批准具有任何序列号或版本的新链码定义。这允许您批准已提交到通道的定义,并开始使用链代码。您还可以批准新的链码定义,以更正在批准或打包链码过程中出现的任何错误。
通道不同意链码定义
如果通道上的组织不同意链码定义,则无法将该定义提交给通道。任何通道成员都不能使用链码。
上图中,组织1、组织2和组织3都批准不同的链码定义。因此,通道的任何成员都无法获得足够的认可来向通道提交链码定义。任何通道成员都不能使用链码。
组织安装不同的链码包
每个组织在批准链码定义时都可以使用不同的packageID。这允许通道成员安装使用相同背书策略的不同链码二进制文件,并读取和写入同一链码命名空间中的数据。
组织可以使用此功能安装包含特定于其组织的业务逻辑的智能合约。每个组织的智能合约都可能包含组织在同行认可交易之前需要的额外验证。每个组织还可以编写代码,帮助将智能合约与现有系统中的数据集成。
Org1和Org2分别安装MYCC链码的版本,其中包含特定于其组织的业务逻辑。
使用一个包创建多个链码
通过批准和提交多个链码定义,可以使用一个链码包在通道上创建多个链码实例。每个定义都需要指定不同的链码名称。这允许您在一个通道上运行智能合约的多个实例,但合约受到不同的背书策略的约束。
上图中,Org1和Org2使用MYCC_1链码包来批准和提交两个不同的链码定义。因此,两个Peer都有两个链码容器在它们的Peer上运行。MYCC1的背书政策为2选1,而MYCC2的背书政策则为2选2。
总结
链码的开发是HyperLedger Fabric区块链网络开发的核心技术之一。因此,弄清链码的生命周期的来笼去脉,对于开发出高质量安装可靠的链码并进行顺利部署具有重要意义。本文主要结合最新的Ver 2.5版本的Fabric官方资料整理而成,希望对于Fabric开发朋友有所帮助。