[toc]
实操智能合约
什么是Chaincode
chaincode是一个程序,它是使用Go语言编写的,最终在Java等其它编程语言中实现了指定的接口;
chaincode运行一个被 背书peer进程独立出来的安全的Docker容器中;
chaincode通过应用程序提交的事务初始化和管理帐本状态;chaincode通常处理被网络成员认可的业务逻辑;
因此它被认为是一种”智能合约”;
由chaincode创建的状态只作用于该chaincode,而不能通过另一个chaincode直接访问;
但是,在同一个网络中,给定适当的权限;
chaincode可以调用另一个chaincode来访问它的状态;通过区块链通信产品应用方案供应商诺亚的视角来探索chaincode;
主要关注诺亚对chaincode生命周期的操作;
在区块链网络中,打包,安装,实例化和升级chaincode的过程;
是chaincode的操作生命周期的一个功能;
Packaging(包)
chaincode包由3部分组成:
chaincode由chaincode部署规范(ChaincodeDeploymentSpec)或CDS定义码和其他属性(如名称如版本) 定义了chaincode包;
一个可选的实例化策略,他可以在策略上用相同的策略来描述;用于一支持和在背书策略中描述。
由”拥有”chaincode的实体的一组签名;
这些签名有以下目的:
- 为了建立chaincode的所有权;
- 允许对包的内容进行验证;
- 允许检测包是否篡改;
一个channel上的chaincode实例化事务的创建者是通过chaincode的实例化策略来验证的;
创建package(包)
打包chaincode有两种方法。一种是当想要一个chaincode拥有多个所有者时,需要使用多个身份标识为该chaincode签名;
这个工作流程需要我们首先创建一个已签名的chaincode(一个签署的CDS);
然后通过序列的方式将其传递给其他所有者来签署 ;更简单的工作流程是正在发行安装事务的节点的身份签名时部署已部署的CDS;
首先将处理更复杂的情况,但是,如果不需要担心多个所有者; 那么可以跳过下在的安装chaincode部分;要创建一个已签名的chaincode包,使用如下命令:
root@6edc4e6c7b9c:/opt/gopath/src/github.com/hyperledger/fabric/peer# 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
2018-03-20 06:28:29.298 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-03-20 06:28:29.299 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-03-20 06:28:29.299 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2018-03-20 06:28:29.299 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2018-03-20 06:28:29.526 UTC [golang-platform] getCodeFromFS -> DEBU 005 getCodeFromFS github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
2018-03-20 06:28:29.965 UTC [golang-platform] func1 -> DEBU 006 Discarding GOROOT package fmt
2018-03-20 06:28:29.965 UTC [golang-platform] func1 -> DEBU 007 Discarding provided package github.com/hyperledger/fabric/core/chaincode/shim
2018-03-20 06:28:29.965 UTC [golang-platform] func1 -> DEBU 008 Discarding provided package github.com/hyperledger/fabric/protos/peer
2018-03-20 06:28:29.965 UTC [golang-platform] func1 -> DEBU 009 Discarding GOROOT package strconv
2018-03-20 06:28:29.965 UTC [golang-platform] GetDeploymentPayload -> DEBU 00a done
2018-03-20 06:28:29.968 UTC [msp/identity] Sign -> DEBU 00b Sign: plaintext: 0A58080112520A476769746875622E63...0A2D2D2D2D2D454E44202D2D2D2D2D0A
2018-03-20 06:28:29.968 UTC [msp/identity] Sign -> DEBU 00c Sign: digest: 8A854844B0721EB24D348CC38C19A3D5E182CBE46FDFFE8CB9ECA7C44406F720
2018-03-20 06:28:29.969 UTC [chaincodeCmd] chaincodePackage -> DEBU 00d Packaged chaincode into deployment spec of size <3409>, with args = [ccpack.out]
-s 参数是指可以创建一个由多个所有签署的包,而不是简单地创建一个未处理/修饰过的CDS;
当指定了-s时,如果其他所有者需要签名,也必需要指定-s参数; 否则,这个进程会创建一个除了CDS
实例化策略之外的已签署CDS;
-S 参数使用在core.yaml中由localMspid属性值标识的MSP来指示该程序的签名;
-S 参数是可选的。但是,如果一个包是在没有签名的情况下创建的,那么它就不能由任何其他
所有者使用signpackage来签署;
-i 参数是可选的,即指定 chaincode实例化策略。实例化策略与背书策略具有相同的格式;
并指定哪些id可以实例化chaincode。在上面的示例中,只允许使用OrgA的admin实例化链代码;
如果没有提供策略,则使用默认策略,这将只允许peer中MSP的admin身份来实例化chaincode;
包签名(Package signing)
一个已经被签名的chaincode包在被创建时候可以交由其它所有者检查并签名;
这个工作流程支持chaincode包带外签署;
SignedCDS包含了3个元素;
- CDS包含了chaincode的源码,即表示背书策略;
- chaincode的实例化策略,即表示背书策略;
- chaincode的所有者列表,以背书的方式定义;
注: 当chaincode在某些channel上实例化时,此背书策略是由带外决定的,以提供适当的MSP原则。
如果没有指定实例化策略,则默认策略是channel的任何MSP的admin
每个所有都通过将其与所有者的身份(例如证书) 相结合,并签署结合后的结果来为ChaincodeDeploymentSpec背书;
一个caincode所有者可以使用下面的命令来签署一个以前创建的签名包:
root@6edc4e6c7b9c:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode signpackage ccpack.out signedccpack.out
2018-03-20 06:48:52.479 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2018-03-20 06:48:52.479 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2018-03-20 06:48:52.479 UTC [msp/identity] Sign -> DEBU 003 Sign: plaintext: 0A58080112520A476769746875622E63...0A2D2D2D2D2D454E44202D2D2D2D2D0A
2018-03-20 06:48:52.479 UTC [msp/identity] Sign -> DEBU 004 Sign: digest: 8A854844B0721EB24D348CC38C19A3D5E182CBE46FDFFE8CB9ECA7C44406F720
Wrote signed package to signedccpack.out successfully
2018-03-20 06:48:52.480 UTC [main] main -> INFO 005 Exiting.....
ccpack.out 和signedccpack.out分别是输入和输出包。signedccpack.out包含了使用的包附加签名;
安装chaincode
安装事务将chaincode的源代码打包成一种指定的格式,称为ChaincodeDeploymentSpec(chaincode部署规范或CDS);
并将其安装到运行该chaincode的peer节点上;
必须在channel中的每个背书节点上安装chaincode。以运行chaincode;
当安装API被简单地给出一个ChaincodeDeploymentSpec时,它会将默认实例化策略;并包含一个空的所有者列表;
chaincode只应该安装在chaincode拥有的成员的背书pper节点上; 以保护网络中其他成员的chaincode逻辑的机密性
那些没有chaincode的成员,不能成为chaincode交易的背书人; 也就是说,它们不能执行chaincode
但是,它们仍然可以难并将事务提交到账本上;
要安装一个chainocde,请将一个签署的提案发送到system chaincode(系统智能合约) 其中被描述为生命周期系统智能合约(lifecycle system chaincode —LSCC) 的部分;
例如,要安装使用CLI的简单资产chaincode中描述的sacc示例chaincode,使用如下命令:
# peer chaincode install -n asset_mgmt -v 1.0 -p sacc
CLI容器执行创建的SignedChaincodeDeploymentSpec sacc ,并将其发送给本地peer;
本地peer会调用LSCC上的安装方法。对-p选项的参数指定 了chaincode的路径;
它必需们位于用户的GOPATH的源码树中,例如 $GOPATH/src/sacc;为了在peer上安装,签署的提案的签名必需来自peer的地本MSP管理员的一个签名
chaincode实例化
实例化事务调用生命击期系统chaincode(LSCC)来创建和初始化一个channel的chaincode;
这是一个chaincode-chanel绑定过程: chaincode可以绑定到任意数量的channel,并分别在每个channel上独立操作;
不管chaincode安装和实例化了多少个其他channel,状态都被隔离到一个事务提交到channel上;
实例化事务的创建者必需满足在SingedCDS中包含的chincode的实例化策略;
并且该创建者作为创建该channel配置信息的一部分,也必需是channel上的一个写入者;
这对于channel的安全性来说是非常重要的,它可以防止恶意实体部署chaincode或欺骗成员在一个未绑定的channel上执行chaincode;
例如,默认的实例化策略是任何channel的MSP管理员,因此一个chaincode实例化事务的创建者必须是channel管理员的成员;
当事务提案到达背书(节点)的时候,它将验证创建者的签名与实例化策略; 并且在将其提交给账本之前;
在事务验证期间再次执行此操作;
实例化事务还为channel 上的chaincode设置了背书策略。背书策略描述了交易结果的认证需求;
被该channel的所有成员所接受;
例如,使用CLI实例化sacc chaincode,并使用john和0初始化状态,命令如下:
peer chaincode instantiate -n sacc -v 1.0 -c '{"Args":["john","0"]}' -P "OR ('Org1.member','Org2.member')"
签注策略(CLI使用波兰表示法),它需要来自Org1或Org2的任意成员的支持
以支持所有的事务到sacc。也就是说,无论是Org1还是Org2都必须签署在sacc上执行调用的结果,以使用事务是有效的
波兰表示法(Polish notation,或波兰记法),是一种逻辑、算术和代数表示方法;
其特点是操作符置于操作数的前面,因此也称做前缀表示法;
如果操作符的元数(arity)是固定的,则语法上不需要括号仍然能被无歧义的解析;
波兰记法是波兰数学家扬. 武卡谢维奇1920年代引入的。用于简化命题逻辑;
在chaincode成功实例化之后,chaincode在channel上进入活跃状态;
并准备处理任何背书事务类武技的事务协议。。这些事务是并发处理的,因为它们到达了背书peer;
chaincode升级
任何时候,chaincode都可以通过更改其版本来进行升级,这是SignedCDS的一部分;
其他部分,例如所有者和实例化策略是可选的。但是,chaincode的名称必需是相同的;
否则,它将被视为完全不同的chaincode;
在升级之前,必须将chaincode的新版本安装在需要背书peer上,升级是一个类似于实例化事务的事务;
它将chaincode的新版本绑定到channel。其他channel所绑定的旧版本chaincode将会继续运行旧版的chaincode;
换句话说,升级事务只会一次影响 一个channel,即提交事务的channel;
注意:由于chaincode的多个版本可能同时处于活跃状态,所以升级过程不会自动删除旧版本;
因此用户必需暂时管理这个版本;
与实例化事务一个微妙的区别; 升级事务是根据当前的chaincode 实例化策略检查的,而不是新策略;
这是为了确保当前的实例化策略中指定的现有成员可以升级chaincode;
在升级过程中,调用chaincode Init函数来执行任何与数据 相关的更新或重新初始化它;
因此在升级chaincode时必需注意避免重新设置状态;
停止和启动chaincode
停止和启动生命周期事务还没有实现。但是,可以通过每个背书人删除chaincode容器和SignedCDS包来手动停止chaincode
这是通过peer节点运行的每个主机或虚拟机上删除chaincode的容器来完成的,然后从每个背书peer节点 上删除SignedCDS
TODO-为了peer节点删除CDS,首先需要进入peer节点的容器,我们确实需要提供一个能够执行功能的实用程序脚本
#docker rm -f <container id>
rm /var/hyperledger/production/chaincodes/<ccname>:<ccversion>
Stop在工作iytkk是有用的,可以控制方式上进行升级,在进行升级之前,可以在所有peer上停止一个chaincode ;
CLI(客户端)
官方正在评估为Hyperledger Fabric peer二进制文件分发特定平台的二进制文件的需求;
目前,可以简单地运行dodcker 容器中调用命令;
查看当前的可用的CLI命令,运行的fabric-peer Docker容器中执行以下命令:
# docker run -it hyperledger/fabric-peer bash
# peer chaincode --help
注: 可使用docker exec -it cli (容器名) bash命令进入cli
与下面类似的输出
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.
2018-03-20 07:55:59.840 UTC [main] main -> INFO 003 Exiting.....
全局flags: —logging-level string
默认的日志记录level和overrides
- test.coverprofile string Done(default “coverage.cov”)
-v ,—version
使用”peer chaincode [command] -help” 获取更多关于命令的信息;
为了方便在脚本化的应用程序中使用,peer命令总是在发生命令失败时生成非零返回代码;
chaincode命令的例子:
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 --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'
系统智能合约(System chaincode)
系统chaincode具有相同的编程模型,除了它在peer进程中运行,而不是普通的chaincode那样在一个单独的容器中运行; 因此,系统chaincode被构建到peer中可执行文件中,并且不遵循上面描述的相同的生命周期。特别是安装、实例化和升级 并不适用于系统chaincode;
系统chaincode的目的是为了在peer和chaincode之间减少gRPC的通信成本,并权衡管理 的灵活性;
例如,系统chaincode只能用peer二进制进行升级。它还必须注册一个固定的参数集,并且没有背书策略或背书策略的功能;
系统chaincode用于Hyperledger Fabric以实现许多系统行为,使它们可以被系统集成所取代或修改;
系统chaincode列表:
1. LSCC(Lifecycle system chaincode): 生命周期系统chaindoe处理上描述的生命周期请求;
2. CSCC(Configuration system chaincode):配置系统chaincode在peer端处理channel配置;
3. QSCC(Query system chaincode): 查询系统chaincode提供了分类查询api,例如获取块和事务;
4. ESCC(Query system chaincode): 背书系统chaincode通过签署事务提案响应来处理支持;
5. VSCC(Validation system chaincode): 验证系统chaincode处理事务验证,策略和多版本并发控制;
在修改或替换这些系统chaincode时必需注意,特别是LSCC、ESCC和VSCC,因为它们在主事务执行路径 中;
值得注意的是,当VSCC在将其提交到账本之前一个块,重要的是,channel中的所有peer节点都要计算相同的验证,以避免账本差异。因此,如果VSCC被修改或替换,就需要特别的处理和维护;