Hyperledger Fabric 2.0最近已经发布,其中最引人关注的一点是链码操做。官方文档虽然对此提供了详细的说明,但本文将经过与Hyperledger Fabric前一个版本中链码操做的对比,来帮助你更好的理解新版本中链码操做的不一样之处以及幕后的一些技术细节。git
咱们将首先快速介绍在HF 1.4和HF 2.0中的整个链码操做过程。docker
链码操做指的是在Hyperledger fabric网络通道上部署链码的操做,这样区块链以外的应用能够调用或查询链码方法。在链码开发完成并测试后,首先须要将Fabric链码安装到指定的peer节点。在这个阶段链码还不能使用,直到链码被提交(Fabric 2.0中的术语)到通道中或在通道上实例化(Fabric 1.4中的术语),这样链码就能够被受权用户访问了。json
下面是两个版本的Hyperledger Fabric中链码操做流程的对比图:网络
在Hyperledger Fabric 1.4中,链码操做过程包含如下步骤:打包、安装、实例化。若是链码属于多个参与方,那么就须要打包这一环节。若是不存在多方属主的问题,那么直接安装链码就能够(其中隐含了打包环节)。在Fabric链码安装时须要指定要安装链码的目标节点。app
在这个阶段,安装好的Fabric链码还不能使用,由于它尚未在通道上实例化。当Fabric链码包被安装在指定的节点上以后,咱们就能够执行链码实例化操做,从而让链码在通道上可用。技术上来讲,链码实例化实际上就是调用LSCC系统链码的方法来初始化通道上的一个链码。区块链
Fabric链码实例化以后就可使用了,能够接受通道上的调用或查询请求。测试
下面咱们看在Hyperledger Fabric 2.0中的链码操做步骤有何区别。ui
宽泛地来说,在Fabric 2.0中链码操做基本遵循一样的流程,可是在命令和某些后台处理中作了一些调整。总体的流程能够分为四个步骤:打包、安装、机构审批、链码提交。大体能够认为前两个环节对应于Fabric 1.4中的链码安装,后面两个环节对应于Fabric 1.4中的链码实例化,可是实例化(instantiation)这个词再也不用了。3d
链码打包这一步是建立一个打包文件(tar格式),其中包含Fabric链码以及一些元数据。虽然不一样的机构能够分别进行打包处理,更常见是由一个机构打包而后分发给其余机构以便确保全部的机构使用相同的链码。
安装步骤是将打包的Fabric链码文件安装在指定的peer节点上。和以前的版本同样,只有须要接受链码调用的节点才须要安装链码。在这个节点,Fabric链码还不可用,由于尚未提交到通道中。链码安装的结果是获得一个包标识符,其格式为<label>.<hash>
。
机构审批是在Hyperledger Fabric 2.0中增长的步骤。在以前的版本中咱们可让一个机构实例化链码。在Fabric 2.0中,须要机构显式地审批链码。须要多少机构审批则是由生命周期背书策略来决定,默认状况下设置为须要大多数机构(超过半数)。若是Fabric网络中包含两个机构,那么就须要这两个机构同时批准。在审批过程当中须要排序节点的参与,由于每次审批都会生成一个新的区块,这意味着全部的peer节点都了解审批的状态。
当审批环节完成后,咱们就须要指定要在哪一个通道上部署链码。这须要提交一些信息,例如背书策略、是否须要执行Init代码等等。在这里也有些与Fabric 1.4不一样的地方:在Fabric 1.4中,当链码实例化时会自动调用链码的Init方法,然而在Fabric 2.0中,须要在提交链码后显式地调用Init方法。
在批准机构达到指定数量后,链码就能够提交了。咱们如今就进入了最后一个步骤:链码提交。
链码提交能够由任何机构发起。该流程首先须要批准机构的背书,而后交易提交到排序服务并生成新的区块,最后全部的对等节点在帐本中提交该区块。
如今链码就可使用了。
出于完整性考虑,下面给出关于First Network和SACC链码的一些信息,这些内容都来自fabric-samples仓库。
First Network是一个双机构设置,每一个机构中包含两个peer节点。通道mychannel建立后加入全部的4个peer节点。在byfn.sh中完整的实现了First Network的部署,并包含一些可选的参数。在下面的演示中,咱们不使用默认的链码(在Fabric 1.4中式chaincode_example02,在Fabric 2.0中式abstore),而是使用SACC链码。
SACC式Simple Asset ChainCode的缩写,表示简单资产链码。它在帐本中模拟一个键/值存储。当初次部署后,须要一个初始的键/值对。SACC链码定义了两个方法:Set()
和Get()
,分别用来设置或读取某个键的值。
好了,如今咱们能够开始演示Fabric 1.4和Fabric 2.0中链码操做的不一样了。
咱们首先以无链码方式(使用-n选项)启动First Network,而后咱们再加载SACC链码以便聚焦链码的生命周期。
下面是演示步骤:
STEP 1:首先启动First Network:
cd fabric-samples/first-network ./byfn.sh up -n
上面的命令会启动First Network、建立通道mychannel并将全部的peer节点加入该通道。注意在Fabric 1.4.4中,First Network使用solo排序服务实现,只有一个排序节点。另外,咱们看到有4个对等节点在运行,以及一个CLI用于链码操做。
如今咱们能够开始链码部署操做。
STEP 2:在指定peer节点上安装链码
这里咱们跳过打包环节,直接在目标节点peer.org1和peer0.org2上安装链码,由于在这个演示中咱们只须要这两个节点进行链码调用和查询。
# peer0.org1 docker exec cli peer chaincode install -n mycc -v 1 \ -p github.com/chaincode/sacc # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode install -n mycc -v 1 -p github.com/chaincode/sacc
STEP 3:在通道mychannel上实例化链码并查询
注意在sacc链码中有Init()代码。当咱们实例化链码时,咱们须要提供Init()所需的参数:
docker exec cli peer chaincode instantiate -o orderer.example.com:7050 --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ -C mychannel -n mycc -v 1 -c '{"Args":["name","kc"]}' \ -P "AND ('Org1MSP.peer','Org2MSP.peer')"
若是如今看看peer节点的日志,咱们能够看到出了新区块#3。
在链码实例化以后,咱们能够查询:
docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
STEP 4:调用set()设置新值并从另外一个节点查询
出于演示目的,咱们在peer0.org1上调用set()
,而后在peer0.org2上调用get()
,以此说明链码是否工做正常。
# peer0.org1 docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc -c '{"Args":["set","name","Peter"]}' # peer0.org2 docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
相似的,在Fairc 2.0.0中,咱们也先以无链码方式启动First Network,而后再启动SACC链码以便聚焦链码的生命周期。
下面是演示步骤:
STEP 1:以无链码方式启动First Network:
cd fabric-samples/first-network ./byfn.sh up -n
如今First Network已经启动,通道mychannel已经建立而且全部peer节点已经加入mychannel通道。注意在Fabric 2.0.0中,First Network使用Raft做为排序服务,全部5个排序节点都在运行。在这个演示中,咱们只使用orderer.example.com,不过使用其余排序节点也是同样的。
STEP 2:打包SACC链码
首先咱们处理依赖问题:
cd fabric-sample/chaincode/sacc GO111MODULE=on go mod vendor cd fabric-sample/first-network
而后打包链码:
docker exec cli peer lifecycle chaincode package sacc.tar.gz \ --path github.com/hyperledger/fabric-samples/chaincode/sacc/ \ --label sacc_1
在CLI容器内能够看到生成了新的文件sacc.tar.gz:
STEP 3:在指定peer节点上安装SACC链码包
如今咱们在peer0.org1和peer0.org2上安装SACC练马报,由于在这个演示中咱们只须要使用这两个节点进行链码调用和查询。
# peer0.org1 docker exec cli peer lifecycle chaincode install sacc.tar.gz # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer lifecycle chaincode install sacc.tar.gz
咱们会收到链码包的标识符,在下面的链码审批阶段会用到。咱们收到的链码标识符为:sacc_1:bf57…6399
。
咱们可使用peer lifecycle chaincode queryinstalled
命令随时检查节点上的链码安装状况,若是咱们须要找出链码包的标识ID,这个命令会颇有用。
# peer0.org1 docker exec cli peer lifecycle chaincode queryinstalled # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer lifecycle chaincode queryinstalled
STEP 4:审批链码
根据默认策略,须要超过半数的机构审批链码后才能向通道提交链码,具体可参考configtx.yaml中的Application/Policies/LifecycleEndorsement
部分。目前的设置中包含两个机构,所以须要两个机构同时批准链码。
首先是Org1批准链码:
docker exec cli peer lifecycle chaincode approveformyorg \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --channelID mychannel --name mycc --version 1 \ --init-required --sequence 1 --waitForEvent --package-id ${PACKAGE_ID}
若是咱们如今看下peer节点的日志,能够看到出了新块#3。
相似的,咱们让Org2批准链码:
docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer lifecycle chaincode approveformyorg \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --channelID mychannel --name mycc --version 1 --init-required \ --sequence 1 --waitForEvent --package-id ${PACKAGE_ID}
不出意外,能够看到出了新块block#4:
注意咱们在approval命令中指定了init相关的参数,以便向SACC链码的Init方法传入所需的参数。
能够随时使用以下命令查看链码的提交状态:
docker exec cli peer lifecycle chaincode checkcommitreadiness \ --channelID mychannel --name mycc --version 1 --sequence 1 --output json
两个机构都已经批准了链码,如今能够提交了。
STEP 5:向通道mychannel提交链码
链码提交能够在一个peer节点上完成:
docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ --channelID mychannel --name mycc --version 1 --sequence 1 --init-required
能够看到出了新块#5:
注意咱们在commit命令中已经包含了init所需的参数。
一样,咱们可使用querycommited命令来查看链码的提交状态:
docker exec cli peer lifecycle chaincode querycommitted --channelID mychannel --name mycc
在链码提交到通道以后,链码的生命周期就完成了,链码已经能够访问。如今咱们回到链码的调用和查询,这和以前的版本是一致的。
STEP 6:调用链码的Init方法
SACC链码的Init方法须要首先调用。
docker exec cli peer chaincode invoke -o orderer.example.com:7050 \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc --isInit -c '{"Args":["name","kc"]}'
如今能够查询 链码:
docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
STEP 7:调用链码的set()方法并从另外一个peer节点查询
和以前同样,咱们在peer0.org1上调用链码的set()
方法,在peer0.org2上进行查询:
# peer0.org1 docker exec cli peer chaincode invoke \ -o orderer.example.com:7050 \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc -c '{"Args":["set","name","Peter"]}' # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
一切正常。