在《Hyperledger Fabric链码之一》和《Hyperledger Fabric链码之二》中我们介绍了链码的定义,并通过dev网络测试了测试了自己编写的链码程序。
本文中我们站在区块链网络管理员的角度来阐述链码,我们集中在链码的声明周期管理,如链码的打包,安装,初始话以及升级。
链码声明周期
超级帐本Fabric提供的接口使得多种类型的节点能够进行交互 — 节点,排序节点以及成员管理服务 — 同时使得在背书节点上可以进行打包、安装、初始化和升级链码。
Hyperledger Fabric的SDKs对API接口进行了抽象以便于应用开发,用来管理链码的生命周期。此外Hyperledger Fabric的API可以通过CLI的方式直接访问,本文中我们使用了这种方式。
我们为链码的生命周期管理提供了4个命令 package
, install
, instantiate
, 以及 upgrade
。 以后版本中,我们计划添加stop
和start
交易来关闭和启动链码而不需要真正的卸载它。链码被成功安装和初始化后,链码会处于激活状态(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个元素:
- CDS包含源码,名字以及链码的版本。
- 链码的初始化策略,描述为背书策略
- 链码拥有者列表,通过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
链码,并用状态john
和0
来进行初始化,命令描述如下:
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
函数会被调用来升级数据或者重新初始化,因此当升级链码的时候需要格外小心防止重新设置状态。
停止和启动
stop
和start
交易现在还没有实现。然而,你可以通过手动删除每个背书节点上的链码容器和SignedCDS包来停止一个链码。注:你需要登入peer节点容器来删除CDS。我们提供一个工具脚本来执行这个操作。
docker rm -f
rm /var/hyperledger/production/chaincodes/:
链码的停止将有助于在可控方式下进行升级,在链码升级前,将通道中所有节点上的链码进行停止。
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
,instantiate
和upgrade
。
系统链码的作用是降低节点和链码之间的gRPC通信开销,折中了管理的灵活性。例如,系统链码只能使用peer二进制程序来升级。也必须使用固定的参数来注册,不具有背书策略或者背书策略函数。
系统链码在Fabric中用来实现一些系统行为,可以进行合理的替换和修改。
当前提供的系统链码列表:
- LSCC生命周期系统链码用来处理声明周期请求
- CSCC配置系统链码在节点端用来处理通道配置
- QSCC请求系统链码 提供了账本请求的APIs,例如获取区块和交易。
- ESCC背书系统链码通过对交易提议响应进行签名来处理背书
- VSCC验证系统链码处理交易验证,包括检查背书策略和多版本并发控制。
在对系统链码进行修改和替换时需要格外的小心,尤其是LSCC,ESCC和VSCC,因为他们管理了整个交易的执行。值得注意的是在将交易提交到账本前VSCC来验证一个区块的有效性,通道中所有节点执行相同的验证以防止账本分叉(不确定)是至关重要的。因此需要格外关注VSCC的修改和替换。
------------------------------------------------------------------------------------完美的终结线--------------------------------------------------------------------------------------