目录
一、什么是链码
二、部署链码
2.1 安装和定义链码
2.1.1 打包智能合约
2.1.2 peer节点安装链码
2.1.3 组织批准链码
2.1.4 将链码提交到通道
2.2 升级链码
总结
ChainCode(链码)是一个程序,用Go、Node.js或Java编写,实现了规定的接口。ChainCode运行在一个安全的Docker容器中与背书节点相隔离,ChainCode通过应用程序提交的交易来初始化和管理账本状态。
链码通常处理由网络成员同意的业务逻辑,因此可以被视为“智能合约”。由链码创建的分类账本更新仅限于该链码,别的链码无法直接访问,但是,在同一个网络中,如果获得适当的权限,链码就可以调用另一个链码来访问其状态。
Fabric 链码生命周期是一个过程,它允许多个组织对于在通道上的链码在使用之前就如何操作链码达成一致,我们使用Fabric生命周期来操作部署和操作链码:
Fabric 链码生命周期要求组织同意定义链码的参数,例如名称、版本和链码背书策略,通道成员通过以下四个步骤达成一致,但是并非频道上的每个组织都需要完成每个步骤。
chaincode 需要打包在一个 tar 文件中,然后才能安装到peer节点上,可以使用 Fabric peer 二进制文件、Node Fabric SDK 或第三方工具(例如 GNU tar)打包链码。当你创建一个链码包时,你需要提供一个链码包标签来创建一个简洁易读的包描述。
如果使用第三方工具打包链码,则生成的文件需要采用以下格式。Fabric peer 二进制文件和 Fabric SDK 将自动以这种格式创建文件。
链码需要打包在一个 tar 文件中,以.tar.gz文件扩展名结尾。
tar 文件需要包含两个文件(无目录):一个元数据文件“metadata.json”和另一个包含链代码文件的 tar“code.tar.gz”。
“metadata.json”包含指定链码语言、代码路径和包标签的 JSON。可以在下面看到元数据文件的示例:
{"Path":"fabric-samples/asset-transfer-basic/chaincode-go","Type":"golang","Label":"basicv1"}
链码由 Org1 和 Org2 分别打包。这两个组织都使用 MYCC_1 作为他们的包标签,以便使用名称和版本来识别包。组织没有必要使用相同的包标签。
只有安装了链码的peer节点才可以执行交易和背书交易,无论是CLI还是SDK,都需要用Peer Administrator来完成此步骤。在安装链码后将构建链码,如果链码有问题,就会返回构建错误。建议组织只需要打包一次链码,然后再属于组织的需要安装的peer节点上安装相同的链码包,如果通道想要确保每个组织运行相同的链码,一个组织就完成打包工作然后发送给通道内的其他成员。
成功的安装命令将返回一个链码包标识符,它是包标签与包的哈希组合。此包标识符用于将安装在peer节点上的链码包与组织批准的链码定义相关联, 为下一步保存标识符,还可以通过使用 Peer CLI 查询安装在对等方上的包来查找包标识符。
Org1 和 Org2 的 peer 管理员在加入频道的 peer 上安装链码包 MYCC_1。安装链码包会构建链码并创建一个包标识符 MYCC_1:hash。
当通道成员批准链码定义时,批准是由其接受的链码参数的组织的投票。这些经批准的组织定义允许通道成员在链码用于通道之前就其达成一致,链码定义包括以下参数,这些参数需要在组织之间保持一致:
名称:应用程序在调用链码时将使用的名称。
版本:与给定链码包关联的版本号或值。如果你升级链码二进制文件,你还需要更改链码版本,版本可以包含任何字符,但通常使用诸如v1.v2.v3的格式,peer节点不会检查版本,它只是一个指标,旨在帮助组织在更新其链码逻辑时进行协调。
序列:在通道上定义链码的次数。该值是一个整数,用于跟踪链码升级。例如,第一次在通道上批准并提交链码定义时,必须将序列号设置为 1。当下次升级链码或更新链码定义时,将序列号增加为 2,序列号由peer节点使用,以确保所有组织都与其批准和提交的链码定义保持同步。
背书政策:哪些组织需要执行和验证交易输出。背书策略可以表示为传递给 CLI 的字符串,也可以引用通道配置中的策略。默认情况下,背书策略设置channel/Application/Endorsement,默认要求通道中的大多数组织对交易进行背书。
集合配置:与链码关联的私有数据集合定义文件的路径。有关私有数据集合的更多信息,请参阅私有数据架构参考。
ESCC/VSCC 插件:链码要使用的自定义背书或验证插件的名称。
初始化:如果使用Fabric ChainCode Shim API提供的低级API,则链码需要包含用于初始化链码的Init函数。chaincode接口需要此函数,但不一定需要由你的应用程序调用,当你批准链码定义时,你可以指定是否Init必须在调用之前调用。如果你指定这Init是必需的,Fabric 将确保Init在链码中的任何其他函数之前调用该函数并且只调用一次,请求执行Init函数允许你实现在初始化链码时运行的逻辑,例如设置一些初始状态。每次增加链码的版本时,都需要调用init才能初始化链码,假设链码定义递增版本指示所需的Init。
链码定义还包括包标识符。这是每个想要使用链码的组织的必需参数,所有组织的包 ID 不必相同,组织可以在不安装链码或在定义中包含标识符的情况下批准链码定义。
每个想要使用链码的通道成员都需要为其组织批准链码定义,此批准需要提交给排序服务,然后分发给所有peer。此批准需要由你的组织管理员提交,成功提交批准事务后,批准的定义将存储在可供组织的所有peer使用的集合中。因此,即使你有多个peer节点,你的组织也只需批准一次链码。
Org1 和 Org2 的组织管理员为其组织批准 MYCC 的链码定义。链码定义包括链码名称、版本和背书策略等字段。由于两个组织都将使用链码来背书交易,因此两个组织的批准定义都需要包含 packageID。
一旦足够数量的通道成员批准了链码定义,一个组织就可以将该定义提交给通道。在使用 peer CLI 将定义提交到通道之前,你可以使用该 checkcommitreadiness命令根据哪些通道成员已批准定义来检查提交链代码定义是否应该成功。提交交易提案首先发送给通道成员的peer,他们查询为其组织批准的链码定义,如果他们的组织批准,则认可该定义。然后将事务提交给orderer,然后将链码定义提交给通道,提交定义事务需要以组织的管理员的身份提交。
需要批准定义才能成功提交到通道的组织数量由 Channel/Application/LifecycleEndorsement策略控制。默认情况下,此策略要求通道中的大多数组织认可交易,LifecycleEndorsement 策略与链码背书策略是分开的。例如,即使链码背书策略只需要一个或两个组织的签名,大多数通道成员仍然需要根据默认策略批准链码定义,提交通道定义时,你需要针对通道中足够多的peer组织来满足你的 LifecycleEndorsement 策略。
你还可以将Channel / Application / LifeCycleEndoseMent策略设置为签名策略,并明确指定通道上可以批准链码定义的组织集。这允许你创建一个通道,其中选定数量的组织充当链码管理员并管理通道使用的业务逻辑。如果你的频道拥有大量 Idemix组织,你也可以使用签名策略,这些组织无法批准链码定义或背书链码,并可能因此阻止频道达到多数。
来自 Org1 或 Org2 的一位组织管理员将链码定义提交到通道。频道上的定义不包括 packageID。
在将链码定义提交到通道后,链码容器将在已安装链码的所有peer节点上启动,从而允许通道成员开始使用链码,链码容器可能需要几分钟才能启动,你可以使用链码定义来要求调用Init函数来初始化链码。如果Init请求调用函数,则链码的第一次调用必须是对该Init函数的调用,函数的调用Init受链码背书策略的约束。
你可以使用与安装和启动链码相同的 Fabric 生命周期过程来升级链码,你可以升级链码二进制文件,或仅更新链码策略,按照以下步骤升级链码:
重新打包链码:如果你正在升级链码二进制文件,则只需完成此步骤。
Org1 和 Org2 升级链码二进制文件并重新打包链码,两个组织都使用不同与之前的包装标签。
在你的对等节点上安装新的链码包:同样,如果你要升级链码二进制文件,则只需完成此步骤。安装新的链码包将生成一个包 ID,需要将其传递给新的链码定义,你还需要更改链码版本,生命周期过程使用该版本来跟踪链码二进制文件是否已升级。
Org1 和 Org2 将新软件包安装到它们的对等节点上。安装会创建一个新的 packageID。
批准新的链码定义:如果要升级链码二进制文件,则需要更新链码定义中的链码版本和包 ID。你还可以更新你的链码背书策略,而无需重新打包你的链码二进制文件,通道成员只需批准新策略的定义,新定义需要将定义中的序列变量加一。
Org1 和 Org2 的组织管理员为其各自的组织批准新的链码定义,新定义引用新的 packageID 并更改链码版本,由于这是链码的第一次更新,因此序列从一增加到二。
将定义提交到通道:当足够数量的通道成员批准新的链码定义时,一个组织可以提交新定义以将链码定义升级到通道,作为生命周期过程的一部分,没有单独的升级命令。
Org1 或 Org2 的组织管理员将新的链码定义提交到通道。
提交链码定义后,将使用升级后的链码二进制文件中的代码启动一个新的链码容器。如果你在链码定义中请求执行该函数,则需要在新定义成功提交后再次Init调用该函数来初始化升级后的链码。如果在不更改链码版本的情况下更新了链码定义,则链码容器将保持不变,并且您无需调用Init函数。
将新定义提交到通道后,每个对等点将自动启动新的链码容器。
Fabric 链码生命周期使用链码定义中的序列来跟踪升级。所有通道成员都需要将序列号加一并批准新定义以升级链码。version 参数用于跟踪链码二进制文件,只有在升级链码二进制文件时才需要更改。
参考:Fabric chaincode lifecycle — hyperledger-fabricdocs main documentation