Hyperledger Fabric链码之三

时间:2021-10-25 03:54:34

在《Hyperledger Fabric链码之一》和《Hyperledger Fabric链码之二》中我们介绍了链码的定义,并通过dev网络测试了测试了自己编写的链码程序。

本文中我们站在区块链网络管理员的角度来阐述链码,我们集中在链码的声明周期管理,如链码的打包,安装,初始话以及升级。

链码声明周期


超级帐本Fabric提供的接口使得多种类型的节点能够进行交互 — 节点,排序节点以及成员管理服务 — 同时使得在背书节点上可以进行打包、安装、初始化和升级链码。

Hyperledger Fabric的SDKs对API接口进行了抽象以便于应用开发,用来管理链码的生命周期。此外Hyperledger Fabric的API可以通过CLI的方式直接访问,本文中我们使用了这种方式。

我们为链码的生命周期管理提供了4个命令 package, install, instantiate, 以及 upgrade。 以后版本中,我们计划添加stopstart交易来关闭和启动链码而不需要真正的卸载它。链码被成功安装和初始化后,链码会处于激活状态(running)并通过invoke来处理交易。之后链码也可以被升级。

打包


链码的打包包含3个部分:

  • 链码,被定义为ChaincodeDeploymentSpec或者CDS。 CDS根据代码以及名字和版本来定义链码包。
  • 一个可选的初始化策略,语法构成上与背书endorsement-policies相同
  • 一组签名,来自拥有该链码的实体

    签名具有下面的目的:
  • 建立链码归属权
  • 验证链码包的内容
  • 防止链码包篡改

    在一个channel中链码初始化交易的创建者会经过链码的初始化策略的验证。

创建链码包


有两种方式来打包链码。一种方式是:当一个链码有多个拥有者,因此需要链码包被多个身份进行签名。首先需要创建一个签名的链码包SignedCDS,然后顺序传送给其他拥有者进行签名。

更简单的方式是: 当部署一个仅仅由一个节点签名的SignedCDS时执行install交易

我们首先解决最复杂的情况。但是,如果你不需要担心多个拥有者的情况,你可以直接跳到:ref:安装章节。

使用下面的命令创建链码包

peer chaincode package -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -v 0 -s -S -i "AND('OrgA.admin')" ccpack.out

其中, -s选项创建了一个可以被多个拥有者签名的链码包,而不是简单的一个CDS。 当指定了-s, 如果需要其他拥有者签名的话也必须指定-S选项。否则,除了CDS以外,上述命令会创建一个仅包含初始化策略的SignedCDS

-S选项用来指导链码包的签名过程,使用core.yaml文件中localMspid指定的MSP的值。 该选项是可选的。然而如果链码包创建没有使用签名,也就不能被别的拥有者使用signpackage命令来进行签名。

选项-i允许指定链码的初始化策略。初始化策略与背书策略具有相同的格式,用来指定什么身份可以来初始化链码。 在上面的例子中,仅仅OrgA的管理员能够初始化该链码。如果未提供初始化策略,会使用默认值,仅允许节点MSP的管理员身份来初始化链码。

链码包签名


被签名的链码包被创建后可以交给其他拥有者进行检查和签名。 工作流支持线下的链码包签名。

ChaincodeDeploymentSpec 被一组拥有者进行签名得到 SignedChaincodeDeploymentSpec或者SignedCDS. SignedCDS包含3个元素:

  1. CDS包含源码,名字以及链码的版本。
  2. 链码的初始化策略,描述为背书策略
  3. 链码拥有者列表,通过Endorsement来定义。

注意::背书策略是线下确定的,用来提供合适的MSP规则当链码在一些通道初始话的时候。如果未指定初始化策略,那么缺省策略是通道的任何MSP管理员。

每个拥有者背书ChaincodeDeploymentSpec, 然后结合自己的身份(比如证书)后进行签名。

链码拥有者可以使用如下的命令对之前签名的链码包进行签名

 peer chaincode signpackage ccpack.out signedccpack.out

其中, ccpack.out和`signedccpack.out``分别是命令的输入和输出。 后者包含一个额外的本地MSP签名。

安装


install交易将链码源码打包为一个指定的格式ChaincodeDeploymentSpec (或者CDS),并安装到运行链码的节点上。

注意:链码必须安装在同一个通道的所有背书节点上。

install API输入参数仅是ChaincodeDeploymentSpec时,会使用默认的初始化策略并包含一个空的拥有者列表。

注意: 链码应该仅安装在拥有者的背书节点上以保护链码逻辑的机密性,防止网络中其他成员的访问。那些没有链码的成员,不能作为链码交易的背书人;也就是说,他们不能执行链码。然而,他们仍然可以验证和提交交易。

为了安装链码,需要向lifecycle system chaincode (LSCC), 在System Chaincode章节描述,发送一个SignedProposal。例如,安装sacc链码。

使用CLI的方式,安装命令如下:

 peer chaincode install -n asset_mgmt -v 1.0 -p sacc

CLI内部会为sacc创建SignedChaincodeDeploymentSpec 并且发送给本地的peer,节点调用LSCC的install方法。-p参数指定了链码的路径,必须在用户GOPATH下,例如$GOPATH/src/sacc。 CLI命令的完整描述参考CLI章节。

值得注意的是为了在节点上安装链码,SignedProposal的签名必须来自peer本地MSP管理员。

初始化


instantiate交易调用lifecycle System Chaincode (LSCC)`创建并初始化通道中的链码。这是一个链码-通道绑定的过程:链码可以绑定到多个通道中,并独立运行在每一个通道中。也就是说,不管链码被安装并初始化到多少个通道中,通道状态都是隔离的。

instantiate交易的创建者必须在SignedCDS中指定初始化策略,同时必须在通道中具有可写权限,在通道创建时配置。这些对于防止恶意实体部署链码并欺骗成员执行链码具有重要作用。

例如, 默认的初始化策略是通道MSP的任意管理员,因此链码初始化交易的创建者必须是一个通道管理员。当交易提议发送到背书节点,会使用背书策略验证创建者的签名。在交易提交到账本前的验证阶段会再一次进行验证。

初始化交易也会为通道中链码设置背书策略。背书策略描述的是需要多少个对交易结果的背书,交易才能被通道成员承认。

比如,使用CLI的方式来初始化sacc链码,并用状态john0来进行初始化,命令描述如下:

 peer chaincode instantiate -n sacc -v 1.0 -c '{"Args":["john","0"]}' -P "OR ('Org1.member','Org2.member')"

注意:上面命令中背书策略(使用波兰表示法)表示需要Org1或者Org2中的任意成员对所有sacc的所有交易进行背书。即,Org1或Org2必须对执行Invoke的结果进行签名,交易才是有效交易。

交易成功初始化后,链码进入了激活状态,准备处理接收到的类型为ENDORSER_TRANSACTION的交易提议。 交易在背书节点上进行并行处理。

升级


链码可以通过改变版本号的方式来进行升级,版本号是SignedCDS的一部分。其他组成有拥有者、背书策略是可选的。然而,链码名必须是相同的,否则会被认为是完全不同的链码。

升级前,新版本的链码必须首先安装到背书节点上。升级交易与初始化交易类似,会将新版本的交易绑定到通道中。其他绑定旧版本的通道仍然运行旧版本。也就是说upgrade交易一次只影响一个通道,即交易提交到的通道。

注意:既然链码多个版本可以同时运行,那么升级过程不会自动移除旧版本,因此用户需要自己进行处理。

instantiate细微的不同是:upgrade交易会用当前链码的初始化策略进行检查,而不是新的策略。这样用来保证只有当前初始化策略指定的成员能够来升级链码。

注意:在升级阶段,链码Init函数会被调用来升级数据或者重新初始化,因此当升级链码的时候需要格外小心防止重新设置状态。

停止和启动


stopstart交易现在还没有实现。然而,你可以通过手动删除每个背书节点上的链码容器和SignedCDS包来停止一个链码。注:你需要登入peer节点容器来删除CDS。我们提供一个工具脚本来执行这个操作。

 docker rm -f <container id>
rm /var/hyperledger/production/chaincodes/<ccname>:<ccversion>

链码的停止将有助于在可控方式下进行升级,在链码升级前,将通道中所有节点上的链码进行停止。

CLI


注:我们需要平台相关的二进制可执行程序peer. 现在,你可以简单的在运行的docker容器中使用此命令。

fabric-peer Docker容器中执行命令,如下

 docker run -it hyperledger/fabric-peer bash
# peer chaincode --help

执行上面的命令会显示:

Usage:
peer chaincode [command] Available Commands:
install Package the specified chaincode into a deployment spec and save it on the peer's path.
instantiate Deploy the specified chaincode to the network.
invoke Invoke the specified chaincode.
package Package the specified chaincode into a deployment spec.
query Query using the specified chaincode.
signpackage Sign the specified chaincode package
upgrade Upgrade chaincode. Flags:
--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint
-C, --chainID string The chain on which this command should be executed (default "testchainid")
-c, --ctor string Constructor message for the chaincode in JSON format (default "{}")
-E, --escc string The name of the endorsement system chaincode to be used for this chaincode
-l, --lang string Language the chaincode is written in (default "golang")
-n, --name string Name of the chaincode
-o, --orderer string Ordering service endpoint
-p, --path string Path to chaincode
-P, --policy string The endorsement policy associated to this chaincode
-t, --tid string Name of a custom ID generation algorithm (hashing and decoding) e.g. sha256base64
--tls Use TLS when communicating with the orderer endpoint
-u, --username string Username for chaincode operations when security is enabled
-v, --version string Version of the chaincode specified in install/instantiate/upgrade commands
-V, --vscc string The name of the verification system chaincode to be used for this chaincode Global Flags:
--logging-level string Default logging level and overrides, see core.yaml for full syntax
--test.coverprofile string Done (default "coverage.cov") Use "peer chaincode [command] --help" for more information about a command.

在脚本中运行,peer命令在执行失败的时候会返回一个非零的错误码。

链码命令使用示例:

    peer chaincode install -n mycc -v 0 -p path/to/my/chaincode/v0
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a", "b", "c"]} -C mychannel
peer chaincode install -n mycc -v 1 -p path/to/my/chaincode/v1
peer chaincode upgrade -n mycc -v 1 -c '{"Args":["d", "e", "f"]} -C mychannel
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","e"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'

系统链码


系统链码与链码具有相同的编程模型,不同的是,系统链码运行在peer进程中,而不是隔离的docker容器中。因此,系统链码被编译进了peer可执行程序中,生命周期与前面的不同。比如,系统链码没有install,instantiateupgrade

系统链码的作用是降低节点和链码之间的gRPC通信开销,折中了管理的灵活性。例如,系统链码只能使用peer二进制程序来升级。也必须使用固定的参数来注册,不具有背书策略或者背书策略函数。

系统链码在Fabric中用来实现一些系统行为,可以进行合理的替换和修改。

当前提供的系统链码列表:

  1. LSCC生命周期系统链码用来处理声明周期请求
  2. CSCC配置系统链码在节点端用来处理通道配置
  3. QSCC请求系统链码 提供了账本请求的APIs,例如获取区块和交易。
  4. ESCC背书系统链码通过对交易提议响应进行签名来处理背书
  5. VSCC验证系统链码处理交易验证,包括检查背书策略和多版本并发控制。

在对系统链码进行修改和替换时需要格外的小心,尤其是LSCC,ESCC和VSCC,因为他们管理了整个交易的执行。值得注意的是在将交易提交到账本前VSCC来验证一个区块的有效性,通道中所有节点执行相同的验证以防止账本分叉(不确定)是至关重要的。因此需要格外关注VSCC的修改和替换。

------------------------------------------------------------------------------------完美的终结线--------------------------------------------------------------------------------------