[toc]
在 fabric 上执行 chaincode 的梳理
流程说明
以 commercial-paper 为例,梳理运行 chaincode 程序的流程。 在区块链上有两个组织——org1,org2。对应 digibank 与 magentocorp 这两家公司。magentocorp 为 paper 发行商,digibank 购买 paper,并在到期后赎回。 两家拥有一模一样的 chaincode 程序,在他们的网络环境中分别打包、验证并发布 chaincode 程序。最后各自使用不同的客户端程序分别完成发行、购买、赎回等动作。 这里要注意:两家公司使用相同的 chaincode 程序,但他们的客户端程序不相同。
准备环境变量
准备一个环境变量脚本 ~/.fabric.sh,用于切换环境变量以对应不同的 peer。
#! /bin/bash
mySetGlobals() {
export CORE_PEER_TLS_ENABLED="true"
export ORDERER_CA=${TEST_NETWORK}/organizations/ordererOrganizations/nd.com.cn/orderers/orderer.nd.com.cn/msp/tlscacerts/tlsca.nd.com.cn-cert.pem
export ORDERER_TLS_ROOTCERT_FILE=${TEST_NETWORK}/organizations/ordererOrganizations/nd.com.cn/msp/tlscacerts/tlsca.nd.com.cn-cert.pem
export PEER0_ORG1_CA=${TEST_NETWORK}/organizations/peerOrganizations/org1.nd.com.cn/peers/peer0.org1.nd.com.cn/tls/ca.crt
export PEER1_ORG1_CA=${TEST_NETWORK}/organizations/peerOrganizations/org1.nd.com.cn/peers/peer1.org1.nd.com.cn/tls/ca.crt
export PEER2_ORG1_CA=${TEST_NETWORK}/organizations/peerOrganizations/org1.nd.com.cn/peers/peer2.org1.nd.com.cn/tls/ca.crt
export PEER0_ORG2_CA=${TEST_NETWORK}/organizations/peerOrganizations/org2.nd.com.cn/peers/peer0.org2.nd.com.cn/tls/ca.crt
export PEER1_ORG2_CA=${TEST_NETWORK}/organizations/peerOrganizations/org2.nd.com.cn/peers/peer1.org2.nd.com.cn/tls/ca.crt
export PEER0_ORG3_CA=${TEST_NETWORK}/organizations/peerOrganizations/org3.nd.com.cn/peers/peer0.org3.nd.com.cn/tls/ca.crt
export PEER1_ORG3_CA=${TEST_NETWORK}/organizations/peerOrganizations/org3.nd.com.cn/peers/peer1.org3.nd.com.cn/tls/ca.crt
export PEER0_ORG4_CA=${TEST_NETWORK}/organizations/peerOrganizations/org4.nd.com.cn/peers/peer0.org4.nd.com.cn/tls/ca.crt
export PEER1_ORG4_CA=${TEST_NETWORK}/organizations/peerOrganizations/org4.nd.com.cn/peers/peer1.org4.nd.com.cn/tls/ca.crt
USING_ORG=$1
USING_PEER=$2
PORT=$((7051+2000*$USING_PEER))
export CORE_PEER_ADDRESS=peer${USING_PEER}.org${USING_ORG}.nd.com.cn:$PORT
export CORE_PEER_LOCALMSPID="Org${USING_ORG}MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${TEST_NETWORK}/organizations/peerOrganizations/org${USING_ORG}.nd.com.cn/peers/peer${USING_PEER}.org${USING_ORG}.nd.com.cn/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${TEST_NETWORK}/organizations/peerOrganizations/org${USING_ORG}.nd.com.cn/users/Admin@org${USING_ORG}.nd.com.cn/msp
}
. ~/.fabric.sh
打包 chaincode 程序
for node.js
在第一个 terminal 中运行:
# 设置环境变量,指向 peer0.org2.nd.com.cn
setGlobals 2 0
peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
注意:在执行前要先设置 peer2 的环境变量
在第二个 terminal 中运行:
# 设置环境变量,指向 peer0.org1.nd.com.cn
setGlobals 1 0
peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
for java
在打包前,先 build(注:实际操作中发现不用先 build,因为上传的是源码,在服务端 install 的时候会 build 一次):
cd ./organizations/magentocorp/contract-java
./gradlew build
再打包:
cd ..
peer lifecycle chaincode package cp.tar.gz --lang java --path ./contract-java --label cp_0
其余步骤与 node.js 一样。
安装 chaincode 程序
在第一个 terminal 中运行:
setGlobals 2 0
peer lifecycle chaincode install cp.tar.gz
在第二个 terminal 中运行:
setGlobals 1 0
peer lifecycle chaincode install cp.tar.gz
报错 执行过程中会有好几次报错:peer0.org1.example.com|2020-03-26 14:56:05.514 UTC [endorser] SimulateProposal -> ERRO 05a failed to invoke chaincode _lifecycle, error: timeout expired while executing transaction 这是客户端在得到服务端的回复之前就断开了连接的缘故。这里可以修改 core.yaml 中的 peer.keepalive.client.timeout 来修改超时时间。 多个 peer 节点的情况
- 在遇到每个组织有多个节点时,需要在每个 peer 节点上都 install 一次,否则在程序运行后会提示找不到 chaincode 程序
- 这里的每个节点,指的是 endorsement policy 里规定的需要的节点。
分别在两个 terminal 中执行:
> peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:07fd097779797941c75b559b0c552b5335cc7fca95a098cb566cfb49673a6e76, Label: cp_0
说明已经安装成功。
approve the chaincode definition for my organizations
分别在两个 terminal 中运行:
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq -r '.installed_chaincodes[0].package_id')
echo $PACKAGE_ID
peer lifecycle chaincode approveformyorg --orderer orderer.nd.com.cn:7050 --ordererTLSHostnameOverride orderer.nd.com.cn \
--channelID mychannel \
--name papercontract \
-v 0 \
--package-id $PACKAGE_ID \
--sequence 1 \
--tls \
--cafile $ORDERER_TLS_ROOTCERT_FILE
检查 chaincode 状态
在第一个 terminal 中运行:
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name papercontract -v 0 --sequence 1
Chaincode definition for chaincode 'papercontract', version '0', sequence '1' on channel 'mychannel' approval status by org:
Org1MSP: false
Org2MSP: true
显示 chaincode 已部署在 Org2MSP 中。
在第二个 terminal 中运行:
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name papercontract -v 0 --sequence 1
Chaincode definition for chaincode 'papercontract', version '0', sequence '1' on channel 'mychannel' approval status by org:
Org1MSP: true
Org2MSP: true
提交 chaincode
当两个组织都已安装了chaincode,并通过了认证后,可以提交 chaincode。
# 第一个 terminal 中
peer lifecycle chaincode commit -o orderer.nd.com.cn:7050 \
--peerAddresses peer0.org1.nd.com.cn:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} \
--peerAddresses peer1.org1.nd.com.cn:9051 --tlsRootCertFiles ${PEER1_ORG1_CA} \
--peerAddresses peer2.org1.nd.com.cn:11051 --tlsRootCertFiles ${PEER2_ORG1_CA} \
--peerAddresses peer0.org2.nd.com.cn:7051 --tlsRootCertFiles ${PEER0_ORG2_CA} \
--peerAddresses peer1.org2.nd.com.cn:9051 --tlsRootCertFiles ${PEER1_ORG2_CA} \
--peerAddresses peer2.org2.nd.com.cn:11051 --tlsRootCertFiles ${PEER2_ORG2_CA} \
--ordererTLSHostnameOverride orderer.nd.com.cn \
--channelID mychannel --name papercontract -v 0 \
--sequence 1 \
--tls --cafile $ORDERER_CA --waitForEvent
返回结果:
2020-06-08 15:32:00.871 CST [chaincodeCmd] ClientWait -> INFO 001 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer0.org2.nd.com.cn:7051
2020-06-08 15:32:00.959 CST [chaincodeCmd] ClientWait -> INFO 002 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer2.org2.nd.com.cn:11051
2020-06-08 15:32:00.974 CST [chaincodeCmd] ClientWait -> INFO 003 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer1.org2.nd.com.cn:9051
2020-06-08 15:32:01.165 CST [chaincodeCmd] ClientWait -> INFO 004 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer1.org1.nd.com.cn:9051
2020-06-08 15:32:01.192 CST [chaincodeCmd] ClientWait -> INFO 005 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer0.org1.nd.com.cn:7051
2020-06-08 15:32:01.256 CST [chaincodeCmd] ClientWait -> INFO 006 txid [436c5e991841ea596913ba2650a5d98cb07d119246768aa4ec9c121bc9c38bc5] committed with status (VALID) at peer2.org1.nd.com.cn:11051
测试 chaincode
测试一:
peer chaincode invoke -o orderer.nd.com.cn:7050 --ordererTLSHostnameOverride orderer.nd.com.cn \
--peerAddresses peer0.org1.nd.com.cn:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} \
--peerAddresses peer1.org1.nd.com.cn:9051 --tlsRootCertFiles ${PEER1_ORG1_CA} \
--peerAddresses peer2.org1.nd.com.cn:11051 --tlsRootCertFiles ${PEER2_ORG1_CA} \
--peerAddresses peer0.org2.nd.com.cn:7051 --tlsRootCertFiles ${PEER0_ORG2_CA} \
--peerAddresses peer1.org2.nd.com.cn:9051 --tlsRootCertFiles ${PEER1_ORG2_CA} \
--peerAddresses peer2.org2.nd.com.cn:11051 --tlsRootCertFiles ${PEER2_ORG2_CA} \
--channelID mychannel --name papercontract \
-c '{"Args":["org.papernet.commercialpaper:instantiate"]}' ${PEER_ADDRESS_ORG1} ${PEER_ADDRESS_ORG2} \
--tls --cafile $ORDERER_CA --waitForEvent
返回结果:
2020-03-26 23:34:11.965 CST [chaincodeCmd] ClientWait -> INFO 001 txid [327cd7698d849f5cd7aba5a7b39793c1f303cc21fbd4686270ed52a074fcbd2c] committed with status (VALID) at localhost:9051
2020-03-26 23:34:12.007 CST [chaincodeCmd] ClientWait -> INFO 002 txid [327cd7698d849f5cd7aba5a7b39793c1f303cc21fbd4686270ed52a074fcbd2c] committed with status (VALID) at localhost:7051
2020-03-26 23:34:12.007 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:20
测试二:
peer chaincode query -o orderer.nd.com.cn:7050 --ordererTLSHostnameOverride orderer.nd.com.cn \
--channelID mychannel \
--name papercontract \
-c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' \
--peerAddresses peer0.org2.nd.com.cn:9051 --tlsRootCertFiles ${PEER0_ORG2_CA} \
--tls --cafile $ORDERER_CA | jq -C
返回结果:
{
"$schema": "https://fabric-shim.github.io/master/contract-schema.json",
"contracts": {
"org.papernet.commercialpaper": {
"name": "org.papernet.commercialpaper",
"contractInstance": {
"name": "org.papernet.commercialpaper",
"default": true
},
"transactions": [
{
"name": "instantiate",
"tags": [
"submitTx"
]
},
{
"name": "issue",
"tags": [
"submitTx"
],
"parameters": [
{
"name": "arg0",
"description": "Argument 0",
"schema": {
"type": "string"
}
},
{
"name": "arg1",
"description": "Argument 1",
"schema": {
"type": "string"
}
},
{
"name": "arg2",
"description": "Argument 2",
"schema": {
"type": "string"
}
},
{
"name": "arg3",
"description": "Argument 3",
"schema": {
"type": "string"
}
},
{
"name": "arg4",
"description": "Argument 4",
"schema": {
"type": "string"
}
}
]
},
{
"name": "buy",
"tags": [
"submitTx"
],
"parameters": [
{
"name": "arg0",
"description": "Argument 0",
"schema": {
"type": "string"
}
},
{
"name": "arg1",
"description": "Argument 1",
"schema": {
"type": "string"
}
},
{
"name": "arg2",
"description": "Argument 2",
"schema": {
"type": "string"
}
},
{
"name": "arg3",
"description": "Argument 3",
"schema": {
"type": "string"
}
},
{
"name": "arg4",
"description": "Argument 4",
"schema": {
"type": "string"
}
},
{
"name": "arg5",
"description": "Argument 5",
"schema": {
"type": "string"
}
}
]
},
{
"name": "redeem",
"tags": [
"submitTx"
],
"parameters": [
{
"name": "arg0",
"description": "Argument 0",
"schema": {
"type": "string"
}
},
{
"name": "arg1",
"description": "Argument 1",
"schema": {
"type": "string"
}
},
{
"name": "arg2",
"description": "Argument 2",
"schema": {
"type": "string"
}
},
{
"name": "arg3",
"description": "Argument 3",
"schema": {
"type": "string"
}
}
]
}
],
"info": {
"title": "",
"version": ""
}
},
"org.hyperledger.fabric": {
"name": "org.hyperledger.fabric",
"contractInstance": {
"name": "org.hyperledger.fabric"
},
"transactions": [
{
"name": "GetMetadata"
}
],
"info": {
"title": "",
"version": ""
}
}
},
"info": {
"version": "0.0.1",
"title": "papernet-js"
},
"components": {
"schemas": {}
}
}
其他操作
查找已提交的 chaincode:
> peer lifecycle chaincode querycommitted -C mychannel
Committed chaincode definitions on channel 'mychannel':
Name: papercontract, Version: 0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc
查找已安装的 chaincode: (可以发现,在两个 peer 上分别执行,返回的 package id 不同)
# setGlobals 2
> peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:3d3227b96d0c8be52c6982cc103761d17235a4d74385f1f789ce5eed8811e2d6, Label: cp_0
# setGlobals 1
> peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:f004476a6d6d3fde2a356fea83c8885b385dd7948cd72b2a7a86b74586dac9eb, Label: cp_0
commercial-paper 客户端
magnetocorp 发行
> cd fabric-samples/commercial-paper/organization/magnetocorp/application
> npm install
> node issue.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper issue transaction.
Process issue transaction response.{"class":"org.papernet.commercialpaper","key":"\"MagnetoCorp\":\"00001\"","currentState":1,"issuer":"MagnetoCorp","paperNumber":"00001","issueDateTime":"2020-05-31","maturityDateTime":"2020-11-30","faceValue":"5000000","owner":"MagnetoCorp"}
MagnetoCorp commercial paper : 00001 successfully issued for value 5000000
Transaction complete.
Disconnect from Fabric gateway.
Issue program complete.
> node issue.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper issue transaction.
Process issue transaction response.{"class":"org.papernet.commercialpaper","key":"\"MagnetoCorp\":\"00001\"","currentState":1,"issuer":"MagnetoCorp","paperNumber":"00001","issueDateTime":"2020-05-31","maturityDateTime":"2020-11-30","faceValue":"5000000","owner":"MagnetoCorp"}
MagnetoCorp commercial paper : 00001 successfully issued for value 5000000
Transaction complete.
Disconnect from Fabric gateway.
Issue program complete.
node add
digibank 购买与兑换
> cd fabric-samples/commercial-paper/organization/digibank/application
> npm install
> node addToWallet.js
done
> node buy.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper buy transaction.
Process buy transaction response.
MagnetoCorp commercial paper : 00001 successfully purchased by DigiBank
Transaction complete.
Disconnect from Fabric gateway.
Buy program complete.
> node redeem.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper redeem transaction.
Process redeem transaction response.
MagnetoCorp commercial paper : 00001 successfully redeemed with MagnetoCorp
Transaction complete.
Disconnect from Fabric gateway.
Redeem program complete.
更新 chaincode 程序
当 chaincode 程序提交运行后,可以对其进行更新。更新的 chaincode 程序需要与原来的程序具有相同的 chaincode 名字,并对 version 进行升级。
打包 chaincode 程序
peer lifecycle chaincode package cp.tar.gz --lang java --path ./contract-java --label cp_1
注意这里的 label 相比之前发生了变化。
安装 chaincode 程序
peer lifecycle chaincode install cp.tar.gz
这一步骤没有区别。
approve the chaincode definition for my organizations
> peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:07fd097779797941c75b559b0c552b5335cc7fca95a098cb566cfb49673a6e76, Label: cp_0
Package ID: cp_1:2da28088c9f13c6b64e877fc29ef811b506207ef1d344cf4ab343b4becb0d2a1, Label: cp_1
可以看到这里的多了一个 cp_1开头的 package,记下 Package ID
peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel \
--name papercontract \
-v 1 \
--package-id $PACKAGE_ID \
--sequence 2 \
--tls \
--cafile $ORDERER_TLS_ROOTCERT_FILE
注意这里 -v
和 --sequence
都发生了变化,但 --name
必须保持一致。不然 fabric 会认为这是一个全新的程序。
检查 chaincode 状态
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name papercontract -v 1 --sequence 2
检查 version=1 sequence=2 的新版本程序的状态
提交更新后的程序
peer lifecycle chaincode commit -o localhost:7050 \
--peerAddresses localhost:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} \
--peerAddresses localhost:9051 --tlsRootCertFiles ${PEER0_ORG2_CA} \
--ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel --name papercontract -v 1 \
--sequence 2 \
--tls --cafile $ORDERER_CA --waitForEven
同样注意 version 与 sequence。 提交后,mychannel 上的 chaincode——papercontract 就更新完毕了。