Fabric━━部署智能合约
根据官网教程v2.3.3版本,实践在通道中部署智能合约
启动测试网络
根据之前的操作,重新启动测试网络,这里使用-ca
选项来生成证书
./network.sh up createChannel -ca
设置 Logspout
使用该logspout
工具查看来自一组 Docker 容器的聚合输出,用于在安装智能合约或调用智能合约时调试问题。
直接安装和配置(脚本位于fabric-samples):
cp ~/fabric-samples/commercial-paper/organization/digibank/configuration/cli/monitordocker.sh .
./monitordocker.sh fabric_test # 网络名称改为实际名称
部署链码到通道
将 Fabcar 链代码
部署到通道
打包智能合约
Go
打包链码之前,需要安装链码依赖。注意GO111MODULE=on
下安装依赖:
go mod vendor # 在链码目录chaincode/fabcar/go
配置环境变量
export PATH=${PWD}/../bin:$PATH # 在test-network目录
export FABRIC_CFG_PATH=$PWD/../config/ # for core.yaml
创建链码包
回到test_network
目录,生成链码包:
peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
- 在当前目录创建一个压缩包
fabcar.tar.gz
--label
指定链码标签,唯一识别,使用链码名称_版本号
Java
先进入链码目录:
cd fabric-samples/chaincode/fabcar/java
如果使用Gradle, build.gradle
中列举了使用的依赖包,安装:
./gradlew installDist
构建的智能合约位于 build
目录,回到test_network
目录,生成链码包:
peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/java/build/install/fabcar --lang java --label fabcar_1
安装链码包
链码需要安装在需要为交易背书的所有节点上(实际执行的节点),也是有背书策略决定的。这里使用的背书策略是Org1 and Org2
,需要在两个组织的节点上安装:
- peer0.org1.example.com
- peer0.org2.example.com
设置环境变量
以 Org1 admin操作:
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
安装链码
设置完环境变量后,直接在peer0.org1.example.com上安装链码:
peer lifecycle chaincode install fabcar.tar.gz
输出,返回链码的标志符:
2021-11-21 18:04:24.760 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276\022\010fabcar_1" >
2021-11-21 18:04:24.765 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276
同样步骤在peer0.org2.example.com
上安装链码:
export CORE_PEER_LOCALMSPID="Org2MSP" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=localhost:9051 # peer0.org2.example.com ---------------------------------------------- peer lifecycle chaincode install fabcar.tar.gz
链码是在安装链码时由节点构建的,如果智能合约代码有问题,安装命令将返回任何构建错误。
批准链码定义
安装链码包后,需要组织批准链码的定义,包括:链码名称、版本以及背书策略。链码包 ID 用于将安装在同级上的链码与已批准的链码定义相关联,并允许组织使用链码来背书交易。
链码部署前必须由即configtx.yaml
中的Application/Channel/lifeycleEndorsement
:指定策略,其默认策略是通道上大多数成员批准,才能在通道中使用该链码/部署链码。
查询安装的链码包ID
包 ID 是链码标签和链码二进制文件的哈希值的组合,每个peer将生成相同的包 ID:
peer lifecycle chaincode queryinstalled # peer0.org2.example.com
# output
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1
使用环境变量保存:
export CC_PACKAGE_ID=fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276
批准定义是在组织级别,必须是admin管理员角色批准定义
批准定义
接着上述过程,是在peer0.org2.example.com上操作
peer lifecycle chaincode approveformyorg -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID \
--sequence 1 --tls --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
--package-id
指定链码的ID--sequence
记录链码定义或更新的次数- 可以提供
--signature-policy
指定背书策略
改变环境变量(以 Org1 admin操作),组织1批准:
peer lifecycle chaincode approveformyorg -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID \
--sequence 1 --tls --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
说明:批准链码的定义是由组织的管理员角色完成的,然后批准会提交到排序服务,验证管理员的签名后分发到组织中的其他节点。尽管链码定义只是需要通道上的大多数(默认策略)成员批准即可,但是组织必须批准链码的定义后才能启动其节点上的链码—即不能执行链码/不能为交易进行背书(需要模拟执行)(对于安装的节点)。所有推荐通道成员在提交定义前都批准链码的定义。
提交链码定义到通道
只有足够的组织批准了链码的定义,一个组织才能将链码的定义提交到通道。
查询对链码定义的批准:只需要提供名称等,不需要--package-id
peer lifecycle chaincode checkcommitreadiness \
--channelID mychannel --name fabcar --version 1.0 --sequence 1 \
--tls --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
output:
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
提交链码
以组织管理员角色提交链码到通道:
peer lifecycle chaincode commit \
-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel --name fabcar --version 1.0 --sequence 1 \
--tls --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
--peerAddresses localhost:7051 --tlsRootCertFiles \
${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 --tlsRootCertFiles \
${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
- 使用--peerAddresses来指定
commit tx
分发的节点
通过指定节点,以此查询对应链码的定义,由于组织的批准已经分发到组织中的各个节点,这里只需要随意指定组织中的peer节点,有足够多的组织批准定义后,交易就会提交到通道。
查看提交的链码定义
peer lifecycle chaincode querycommitted \
--channelID mychannel --name fabcar --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
返回对应链码定义的序号和版本:
Committed chaincode definition for chaincode 'fabcar' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
调用链码
将链码定义提交到通道后,链代码现在已准备好由客户端应用程序调用。注意:invoke 命令需要针对足够数量的对等节点来满足链码背书策略。
初始化
调用initLedger
函数
peer chaincode invoke -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com --tls --cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel -n fabcar \
--peerAddresses localhost:7051 --tlsRootCertFiles \
${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 --tlsRootCertFiles \
${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"initLedger","Args":[]}'
查询
使用query
命令:得到链码函数执行后的背书结果,不会产生一次交易
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
升级智能合约
使用相同的 Fabric 链码生命周期流程来升级已部署到通道的链码,通道成员可以通过安装新的链码包,然后使用新的包 ID、新的链码版本和序列号加 1 来批准链码定义来升级链码。还可以使用升级过程来更改链码背书策略。
例如安装Java版本的链码包,先根据上面说明下载依赖
打包
将../chaincode/fabcar/java/build/install/fabcar
打包为fabcar_2.tar.gz
:
export PATH=${PWD}/../bin:$PATHexport FABRIC_CFG_PATH=$PWD/../config/export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp peer lifecycle chaincode package fabcar_2.tar.gz --path ../chaincode/fabcar/javascript/ --lang java --label fabcar_2
安装链码包
在peer0.org1.example.com
节点安装,配置环境变量:
export CORE_PEER_TLS_ENABLED=trueexport CORE_PEER_LOCALMSPID="Org1MSP"export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crtexport CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/mspexport CORE_PEER_ADDRESS=localhost:7051
安装新的链码包:
peer lifecycle chaincode install fabcar_2.tar.gz
安装后会产生新的Package ID,同样使用queryinstalled
查询节点上安装的所有链码:
peer lifecycle chaincode queryinstalled--------------------------------------------# outputInstalled chaincodes on peer:Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1Package ID: fabcar_2:a268f4cf1971bebbf41204aad5375fdc2a8542f4cb5edb139803b33555901b7a, Label: fabcar_2
保存Package ID:
export NEW_CC_PACKAGE_ID=fabcar_2:a268f4cf1971bebbf41204aad5375fdc2a8542f4cb5edb139803b33555901b7a
批准定义
组织org1批准新链码的定义,注意版本号和序号增加:
peer lifecycle chaincode approveformyorg -o localhost:7050 \--ordererTLSHostnameOverride orderer.example.com \--channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID \--sequence 2 --tls --cafile \${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
在组织2中同样操作:
设置环境变量,安装链码,批准链码
export CORE_PEER_LOCALMSPID="Org2MSP"export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crtexport CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crtexport CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/mspexport CORE_PEER_ADDRESS=localhost:9051----------------------------------------------------peer lifecycle chaincode install fabcar_2.tar.gz # 安装链码----------------------------------------------------peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem # 批准
检查是否能够提交到通道
使用peer lifecycle chaincode checkcommitreadiness
来检查序号为2的链码定义是否可以准备提交到通道(是否得到大多数组织批准):
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
提交定义
peer lifecycle chaincode commit -o localhost:7050 \--ordererTLSHostnameOverride orderer.example.com \--channelID mychannel --name fabcar --version 2.0 --sequence 2 \--tls --cafile \${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \--peerAddresses localhost:7051 --tlsRootCertFiles \${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \--peerAddresses localhost:9051 --tlsRootCertFiles \${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
新链码的定义一提交,通道上的链码就会升级,可以从docker ps
运行的链码容器看到结果。
调用
如果使用 --init-required
flag,在你使用链码前必须调用初始化函数。
调用createCar
:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'
查询:
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
说明:升级后数据仍然存在,Go和Java中定义Car的字段名(colour/color)有的不一样,导致查询可能是null