Hyperledger Fabric 2.0最近已经发布,其中最引人关注的一点是 链码操作。官方文档虽然对此提供了详细的说明,但本文将通过与 Hyperledger Fabric前一个版本中链码操作的对比,来帮助你更好的 理解新版本中链码操作的不同之处以及幕后的一些技术细节。
Hyperledger Fabric区块链开发教程: [Node.js] [Golang]
1、链码操作:Fabric 1.4 vs Fabric 2.0
我们将首先快速介绍在HF 1.4和HF 2.0中的整个链码操作过程。
链码操作指的是在Hyperledger fabric网络通道上部署链码的操作,这样区块链 之外的应用可以调用或查询链码方法。在链码开发完成并测试后,首先需要 将Fabric链码安装到指定的peer节点。在这个阶段链码还不能使用,直到 链码被提交(Fabric 2.0中的术语)到通道中或在通道上实例化(Fabric 1.4中的 术语),这样链码就可以被授权用户访问了。
下面是两个版本的Hyperledger Fabric中链码操作流程的对比图:
在Hyperledger Fabric 1.4中,链码操作过程包含以下步骤:打包、安装、实例化。 如果链码属于多个参与方,那么就需要打包这一环节。如果不存在多方属主的问题, 那么直接安装链码就可以(其中隐含了打包环节)。在Fabric链码安装时需要指定 要安装链码的目标节点。
在这个阶段,安装好的Fabric链码还不能使用,因为它还没有在通道上实例化。 当Fabric链码包被安装在指定的节点上之后,我们就可以执行链码实例化操作, 从而让链码在通道上可用。技术上来说,链码实例化实际上就是调用LSCC系统链码 的方法来初始化通道上的一个链码。
Fabric链码实例化之后就可以使用了,可以接受通道上的调用或查询请求。
下面我们看在Hyperledger Fabric 2.0中的链码操作步骤有何区别。
宽泛地来讲,在Fabric 2.0中链码操作基本遵循同样的流程,但是在命令和某些 后台处理中做了一些调整。整体的流程可以分为四个步骤:打包、安装、机构审批、 链码提交。大致可以认为前两个环节对应于Fabric 1.4中的链码安装,后面两个 环节对应于Fabric 1.4中的链码实例化,但是实例化(instantiation)这个词不再 用了。
链码打包这一步是创建一个打包文件(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方法。
在批准机构达到指定数量后,链码就可以提交了。我们现在就进入了最后一个步骤: 链码提交。
链码提交可以由任何机构发起。该流程首先需要批准机构的背书,然后交易提交到 排序服务并生成新的区块,最后所有的对等节点在账本中提交该区块。
现在链码就可以使用了。
2、First Network和SACC链码简介
出于完整性考虑,下面给出关于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中链码操作的不同了。
3、Fabric 1.4.4链码操作演示
我们首先以无链码方式(使用-n选项)启动First Network,然后我们再加载 SACC链码以便聚焦链码的生命周期。
下面是演示步骤:
- 无链码方式启动First Network
- 在指定的peer节点上安装SACC链码
- 在mychannel通道上实例化SACC链码并查询结果
- 调用set()设置新值并从另一个peer节点查询结果
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"]}'
4、Fabric 2.0链码操作演示
类似的,在Fairc 2.0.0中,我们也先以无链码方式启动First Network, 然后再启动SACC链码以便聚焦链码的生命周期。
下面是演示步骤:
- 无链码方式启动First Network
- 打包SACC链码
- 在指定peer节点上安装SACC链码包
- 机构审批链码
- 在mychannel通道上提交链码
- 调用SACC链码的Init方法
- 调用SACC链码的set方法并从另一个peer节点查询结果
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"]}'
一切正常。
有疑问加站长微信联系(非本文作者)