1. 1. 部署新的智能合约到channel
    1. 1.1. 部署V1版本
      1. 1.1.1. 打包
      2. 1.1.2. 安装链码包
      3. 1.1.3. 批准链码定义
        1. 1.1.3.1. 查看已经安装的chaincode
        2. 1.1.3.2. 批准链码定义
      4. 1.1.4. 将链码定义提交到通道
      5. 1.1.5. 调用链码
    2. 1.2. 更新智能合约
      1. 1.2.1. 打包
      2. 1.2.2. 安装链码包
      3. 1.2.3. 批准链码定义
        1. 1.2.3.1. 查看已经安装的chaincode
        2. 1.2.3.2. 批准链码定义
      4. 1.2.4. 将链码定义提交到通道
      5. 1.2.5. 调用链码
        1. 1.2.5.1. 查询调用后的结果
      6. 1.2.6. 调用交易方法
    3. 1.3. 问题记录:
    4. 1.4. 部署v6版本的supply
      1. 1.4.1. v6版本智能合约源码如下:
      2. 1.4.2. 打包
      3. 1.4.3. 安装链码包
      4. 1.4.4. 批准链码定义
        1. 1.4.4.1. 查看已经安装的chaincode
        2. 1.4.4.2. 批准链码定义
      5. 1.4.5. 将链码定义提交到通道
      6. 1.4.6. 调用链码
        1. 1.4.6.1. 查询调用后的结果
      7. 1.4.7. 调用交易方法
    5. 1.5. 部署v7版本的supply
      1. 1.5.1. v7版本智能合约源码如下:
      2. 1.5.2. 打包
      3. 1.5.3. 安装链码包
      4. 1.5.4. 批准链码定义
        1. 1.5.4.1. 查看已经安装的chaincode
        2. 1.5.4.2. 批准链码定义
      5. 1.5.5. 将链码定义提交到通道
      6. 1.5.6. 调用链码
        1. 1.5.6.1. 发行凭证
        2. 1.5.6.2. 查询调用后的结果
    6. 1.6. 创建一级供应商与二级供应商之间的channel
      1. 1.6.1. 创建通道:
    7. 1.7. 把一级供应商和二级供应商的peer加入通道
      1. 1.7.1. 一级供应商的peer加入通道
      2. 1.7.2. 通过获取通道信息确认加入成功
        1. 1.7.2.1. 获取通道信息
      3. 1.7.3. 二级供应商1加入通道
      4. 1.7.4. 二级供应商2加入通道
      5. 1.7.5. 设置锚节点
        1. 1.7.5.1. 为GylFOrg1MSP设置锚节点
          1. 1.7.5.1.1. 拉取最新的channel配置区块
          2. 1.7.5.1.2. 修改通道配置区块
          3. 1.7.5.1.3. 把更新后的交易打包成一个更新通道配置的交易:
          4. 1.7.5.1.4. 提交“更新通道配置的交易”
          5. 1.7.5.1.5. 验证,获取通道信息:peer channel getinfo -c firstandsecondchannel
        2. 1.7.5.2. 为二级供应商1(GylSOrg1MSP)设置锚节点
          1. 1.7.5.2.1. 修改通道配置区块
          2. 1.7.5.2.2. 把更新后的交易打包成一个更新通道配置的交易:
          3. 1.7.5.2.3. 提交“更新通道配置的交易”
          4. 1.7.5.2.4. 验证,获取通道信息
        3. 1.7.5.3. 为二级供应商2(GylSOrg2MSP)设置锚节点
          1. 1.7.5.3.1. 修改通道配置区块
          2. 1.7.5.3.2. 把更新后的交易打包成一个更新通道配置的交易:
          3. 1.7.5.3.3. 提交“更新通道配置的交易”
          4. 1.7.5.3.4. 验证,获取通道信息
    8. 1.8. 部署supply-v7到二级供应商的peer节点
      1. 1.8.1. 打包
      2. 1.8.2. 安装链码包
      3. 1.8.3. 批准链码定义
        1. 1.8.3.1. 查看已经安装的chaincode
        2. 1.8.3.2. 批准链码定义
      4. 1.8.4. 将链码定义提交到通道
      5. 1.8.5. 调用链码
    9. 1.9. 核心企业、一级和二级供应商加入同一个channel
    10. 1.10. 部署supply-v7到alljoinchannel通道
      1. 1.10.1. 打包
      2. 1.10.2. 安装链码包
      3. 1.10.3. 批准链码定义
        1. 1.10.3.1. 查看已经安装的chaincode
        2. 1.10.3.2. 批准链码定义
      4. 1.10.4. 将链码定义提交到通道
      5. 1.10.5. 调用链码
        1. 1.10.5.1. 发行凭证
        2. 1.10.5.2. 查询资产
        3. 1.10.5.3. 一级供应商与二级供应商1交易
        4. 1.10.5.4. 查询资产
        5. 1.10.5.5. 一级供应商与二级供应商2交易
        6. 1.10.5.6. 一级供应商与二级供应商2交易
    11. 1.11. 部署supply-v8到alljoinchannel通道
      1. 1.11.1. 源码
      2. 1.11.2. 打包
      3. 1.11.3. 安装链码包
      4. 1.11.4. 批准链码定义
        1. 1.11.4.1. 查看已经安装的chaincode
        2. 1.11.4.2. 批准链码定义
      5. 1.11.5. 将链码定义提交到通道
      6. 1.11.6. 调用链码
        1. 1.11.6.1. 发行凭证
        2. 1.11.6.2. 查询资产
        3. 1.11.6.3. 一级供应商与二级供应商1交易
        4. 1.11.6.4. 查询资产
        5. 1.11.6.5. 一级供应商与二级供应商2交易
      7. 1.11.7. 转账金额大于凭证资产的金额(期待错误)
      8. 1.11.8. 转账金额等于凭证资产的金额(变更owner,不产生新的凭证资产)
    12. 1.12. 部署supply-v9到alljoinchannel通道
      1. 1.12.1. 源码
      2. 1.12.2. 打包
      3. 1.12.3. 安装链码包
      4. 1.12.4. 批准链码定义
        1. 1.12.4.1. 查看已经安装的chaincode
        2. 1.12.4.2. 批准链码定义
      5. 1.12.5. 将链码定义提交到通道
      6. 1.12.6. 调用链码
        1. 1.12.6.1. 删除资产
    13. 1.13. 部署supply-v9.1到alljoinchannel通道
      1. 1.13.1. 源码
      2. 1.13.2. 打包
      3. 1.13.3. 安装链码包
      4. 1.13.4. 批准链码定义
        1. 1.13.4.1. 查看已经安装的chaincode
        2. 1.13.4.2. 批准链码定义
      5. 1.13.5. 将链码定义提交到通道
      6. 1.13.6. 调用链码
        1. 1.13.6.1. 删除资产
        2. 1.13.6.2. 删除之后查询:

部署新的智能合约到channel

部署新的智能合约到channel

部署V1版本

打包

1
peer lifecycle chaincode package supply.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_1.0

运行完上面的命令,查看当前目录会发现多了supply.tar.gz包,说明打包成功。

安装链码包

一级供应商和核心企业都要安装:
核心企业:

1
peer lifecycle chaincode install supply.tar.gz --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

一级供应商:

1
peer lifecycle chaincode install supply.tar.gz --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

安装成功输出结果如下:

1
2
2020-12-28 17:12:37.540 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nKsupply_1.0:7f51b70454bfcc78087a784c84288a67bbad56786e4007c3a7106491a492ad3a\022\nsupply_1.0" >
2020-12-28 17:12:37.542 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: supply_1.0:7f51b70454bfcc78087a784c84288a67bbad56786e4007c3a7106491a492ad3a

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

成功结果如下:

1
2
3
Installed chaincodes on peer:
Package ID: basic_1.0:4ec191e793b27e953ff2ede5a8bcc63152cecb1e4c3f301a26e22692c61967ad, Label: basic_1.0
Package ID: supply_1.0:7f51b70454bfcc78087a784c84288a67bbad56786e4007c3a7106491a492ad3a, Label: supply_1.0

将链码的信息保存为一个变量

1
export CC_PACKAGE_ID=supply_1.0:7f51b70454bfcc78087a784c84288a67bbad56786e4007c3a7106491a492ad3a

批准链码定义

核心企业和一级供应商都需要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下:

1
2020-12-28 17:14:07.090 CST [chaincodeCmd] ClientWait -> INFO 001 txid [5c192d72135019a4bd6d444231fc95d41b6c7391cbc80a98cb67618f5e7a85c6] committed with status (VALID) at localhost:8053

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID coreandfirstchannel --name supply --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

成功结果如下:

1
2
3
4
5
6
{
"approvals": {
"GylCoreOrg1MSP": true,
"GylFOrg1MSP": true
}
}

在两个组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

成功结果如下:

1
2
2020-12-28 17:14:57.631 CST [chaincodeCmd] ClientWait -> INFO 001 txid [1c5e194c62a24b9fe78d51bd7003fce369f01a0b3051f63ed5e1f9ee4f6cf48b] committed with status (VALID) at localhost:8051
2020-12-28 17:14:57.631 CST [chaincodeCmd] ClientWait -> INFO 002 txid [1c5e194c62a24b9fe78d51bd7003fce369f01a0b3051f63ed5e1f9ee4f6cf48b] committed with status (VALID) at localhost:8053

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID coreandfirstchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下:

1
2
Committed chaincode definition for chaincode 'supply' on channel 'coreandfirstchannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [GylCoreOrg1MSP: true, GylFOrg1MSP: true]

调用链码

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["100", "一级供应商"]}'

成功信息:

1
2020-12-25 17:26:22.583 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

错误信息记录:

1
Error: could not assemble transaction: ProposalResponsePayloads do not match - proposal response: version:1 response:<status:200 > payload:"\n \266\367\033\202\030f\357\010\266zg\350\237\212\313 \342B\2041\316\351>H\037\035\312\274J\021i\220\022\266\002\n\237\002\0227\n\n_lifecycle\022)\n'\n!namespaces/fields/supply/Sequence\022\002\010\t\022\343\001\n\006supply\022\330\001\n\003\n\0011\032\320\001\n\0011\032\312\001{\"ID\":\"1\",\"issuer\":\"\346\240\270\345\277\203\344\274\201\344\270\232\",\"owner\":\"\346\240\270\345\277\203\344\274\201\344\270\232\",\"amount\":100,\"createDate\":\"2020-12-28T09:24:44.871052163Z\",\"endDate\":\"2021-06-28T09:24:44.871052228Z\",\"contractHash\":\"test\",\"invoiceHash\":\"test\"}\032\003\010\310\001\"\r\022\006supply\032\0031.0" endorsement:<endorser:"\n\013GylFOrg1MSP\022\212\006-----BEGIN CERTIFICATE-----\nMIICETCCAbegAwIBAgIRAKxyUt8FsMI4LRaMcjh08ZgwCgYIKoZIzj0EAwIwbTEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xFjAUBgNVBAoTDWYxLnN1cHBseS5jb20xGTAXBgNVBAMTEGNhLmYx\nLnN1cHBseS5jb20wHhcNMjAxMjI1MDkxNzAwWhcNMzAxMjIzMDkxNzAwWjBYMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEcMBoGA1UEAxMTcGVlcjAuZjEuc3VwcGx5LmNvbTBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABIChG5EnW6enlGqH2F9EiWYbilBwfA+KgqqxnN56njS5\ngv368PElfoafV6jCrjA+p2OnbTI3gO2/RAwr2WBLB0+jTTBLMA4GA1UdDwEB/wQE\nAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIHNOBiXoFslrjdFMBMzU7pNe\nI5pmxxrQGrWTdgfI0cetMAoGCCqGSM49BAMCA0gAMEUCIQDEOKc114LvsauKzrMR\n7k6ipg0HPM1+W8JJt06Jeqd1vwIgBre+xg2g/rS7F5oZaJpECUf7ALV0fy9/Dhw0\nYDB3H+g=\n-----END CERTIFICATE-----\n" signature:"0D\002 9\020\212\014\220\302Ao_\226n`o\005\354B\263\316\346\330\347\010\217\205^X\"\267d\320U\365\002 \t<\024e\324\312X\036\346=\025.I*A\311\223\013\301\276\320\232\366\246tZm\341g\223\235|" >

原因应该是代码中使用了Now()来创建当前时间,两个peer的当前时间可能会有一点误差导致了校验不通过。

**解决方案:**使用ctx.GetStub().GetTxTimestamp()来获取时间,这样所有的节点创建的时间都是一致的,详见参考文档

更新智能合约

打包

1
# peer lifecycle chaincode package supply.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/ --lang golang --label supply_1.0

打包本地的代码:

1
peer lifecycle chaincode package supply.5.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_5.0

安装链码包

一级供应商和核心企业都要安装:
核心企业:

1
peer lifecycle chaincode install supply.5.tar.gz --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

一级供应商:

1
peer lifecycle chaincode install supply.5.tar.gz --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_5.0:0006888ea72e1b318238518b719382d440ab72f2d2c45b22e674f4828b7f7f9c

批准链码定义

核心企业和一级供应商都需要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 5.0 --package-id $CC_PACKAGE_ID --sequence 5 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下:

1
2020-12-28 17:58:55.313 CST [chaincodeCmd] ClientWait -> INFO 001 txid [c4974d5c90ae4fb3bd31f179292d9943dd05aac47248f33e365d9f32ccb5ccb6] committed with status (VALID) at localhost:8051

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID coreandfirstchannel --name supply --version 5.0 --sequence 5 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

成功结果如下:

1
2
3
4
5
6
{
"approvals": {
"GylCoreOrg1MSP": true,
"GylFOrg1MSP": true
}
}

在两个组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 5.0 --sequence 5 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

成功结果如下:

1
2
2020-12-28 17:51:08.452 CST [chaincodeCmd] ClientWait -> INFO 001 txid [87bc060e5ccdf4014cd4cf34bbbeb5d2ea10c4ff8ebb6f444d10580e2de2da50] committed with status (VALID) at localhost:8053
2020-12-28 17:51:08.460 CST [chaincodeCmd] ClientWait -> INFO 002 txid [87bc060e5ccdf4014cd4cf34bbbeb5d2ea10c4ff8ebb6f444d10580e2de2da50] committed with status (VALID) at localhost:8051

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID coreandfirstchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下,可以看到已经升级到2.0版本:

1
2
Committed chaincode definition for chaincode 'supply' on channel 'coreandfirstchannel':
Version: 2.0, Sequence: 2, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [GylCoreOrg1MSP: true, GylFOrg1MSP: true]

调用链码

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset001", "100", "一级供应商"]}'

成功信息如下:

1
2020-12-28 18:37:54.285 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

错误信息如下:

1
Error: could not assemble transaction: proposal response was not successful, error code 500, msg Incorrect number of params. Expected 2, received 1 - proposal response: version:1 response:<status:200 > payload:"\n \177\017\350[\344G6\010V\331\332\377\354\216&\035\317&\251[N`\023\036\033\237\237A\005\3670\260\022\266\002\n\237\002\0227\n\n_lifecycle\022)\n'\n!namespaces/fields/supply/Sequence\022\002\010\016\022\343\001\n\006supply\022\330\001\n\003\n\0011\032\320\001\n\0011\032\312\001{\"ID\":\"1\",\"issuer\":\"\346\240\270\345\277\203\344\274\201\344\270\232\",\"owner\":\"\346\240\270\345\277\203\344\274\201\344\270\232\",\"amount\":100,\"createDate\":\"2020-12-28T10:02:30.578872398Z\",\"endDate\":\"2021-06-28T10:02:30.578872527Z\",\"contractHash\":\"test\",\"invoiceHash\":\"test\"}\032\003\010\310\001\"\r\022\006supply\032\0033.0" endorsement:<endorser:"\n\016GylCoreOrg1MSP\022\222\006-----BEGIN CERTIFICATE-----\nMIICFjCCAbygAwIBAgIQU43L5gjtXO+uCpRP2jG2AjAKBggqhkjOPQQDAjBxMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEYMBYGA1UEChMPY29yZS5zdXBwbHkuY29tMRswGQYDVQQDExJjYS5j\nb3JlLnN1cHBseS5jb20wHhcNMjAxMjI1MDkxNzAwWhcNMzAxMjIzMDkxNzAwWjBa\nMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu\nIEZyYW5jaXNjbzEeMBwGA1UEAxMVcGVlcjAuY29yZS5zdXBwbHkuY29tMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAErf3R+7XpNQpmTsMO+iM4WS7IrOoafiPbAS7Q\nbuFFR3Qs4riIczgSmjh9rOA6I1q2q0CstLhfWDbqpf+8fXPUlKNNMEswDgYDVR0P\nAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAguznqsTisa64dNvOR\nvPwP0KGklWohNpbSe7VgIghx4L8wCgYIKoZIzj0EAwIDSAAwRQIhALIw1VMzezCg\n9LONbO4+V+weY42HQLbShkTP/gCFnGRYAiARyLLSDJIC2wwzSvOHNdm+aDRtbqGC\nNJenP9hmEbYsTw==\n-----END CERTIFICATE-----\n" signature:"0E\002!\000\251\370K6S\020\373\242\321\000\211\312\0001\333\365>\314\324\231\020>u;+\243\303dD\023\221\237\002 z \224\236R\355Z\251\202\363\035\304\365\212\277\235\375?\376\030\371\236\220\354iG6\244\334M\315\331" >

原因是因为下图,只有一个组织的链码更新到了最新的版本。

![截屏2020-12-28 18.03.06](/Users/apple/Desktop/截屏2020-12-28 18.03.06.png)

**解决方案:**原因是因为设置环境变量CC_PACKAGE_ID时只设置了一个组织的peer,导致旧的环境变量还在生效,重新操作一遍问题解决。

查询调用后的结果

1
peer chaincode query -C coreandfirstchannel -n supply -c '{"Args":["GetAllAssets"]}'

成功结果如下

1
2
3
4
# 核心企业
[{"ID":"asset001","issuer":"核心企业","owner":"核心企业","amount":100,"createDate":"2020-12-28T10:37:54.271518Z","endDate":"2021-06-28T10:37:54.271518Z","contractHash":"test","invoiceHash":"test"}]
# 一级供应商
[{"ID":"asset001","issuer":"核心企业","owner":"核心企业","amount":100,"createDate":"2020-12-28T10:37:54.271518Z","endDate":"2021-06-28T10:37:54.271518Z","contractHash":"test","invoiceHash":"test"}]

调用交易方法

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset001", "一级供应商"]}'

再次查询:peer chaincode query -C coreandfirstchannel -n supply -c '{"Args":["GetAllAssets"]}'

1
2
3
4
# 核心企业
[{"ID":"asset001","issuer":"核心企业","owner":"一级供应商","amount":100,"createDate":"2020-12-28T10:37:54.271518Z","endDate":"2021-06-28T10:37:54.271518Z","contractHash":"test","invoiceHash":"test"}]
# 一级供应商
[{"ID":"asset001","issuer":"核心企业","owner":"一级供应商","amount":100,"createDate":"2020-12-28T10:37:54.271518Z","endDate":"2021-06-28T10:37:54.271518Z","contractHash":"test","invoiceHash":"test"}]

交易之后owner变成了一级供应商,没有问题。

问题记录:

虽然智能合约的代码编写方式如下,但是第二行的TransferAsset并没有执行,可能是因为第一个创建交易(CreateAsset)还没有成功,所以第二个交易(TransferAsset)没有这个资产所以没有执行?待确认

1
2
3
// 创建资产
s.CreateAsset(ctx, assetID, amount)
s.TransferAsset(ctx, assetID, owner)

部署v6版本的supply

v6版本智能合约源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package chaincode

import (
"encoding/json"
"fmt"
"time"

"github.com/golang/protobuf/ptypes"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// SmartContract provides functions for managing an Asset
type SmartContract struct {
contractapi.Contract
}

// Asset describes basic details of what makes up a simple asset
type Asset struct {
ID string `json:"ID"`
Issuer string `json:"issuer"`
Owner string `json:"owner"`
Amount int64 `json:"amount"`
CreateDate time.Time `json:"createDate"`
EndDate time.Time `json:"endDate"`
ContractHash string `json:"contractHash"`
InvoiceHash string `json:"invoiceHash"`
}

// IssueVoucher 发行凭证
func (s *SmartContract) IssueVoucher(ctx contractapi.TransactionContextInterface, assetID string, amount int64) error {
// 创建资产
asset, err := s.createAsset(ctx, assetID, amount, "核心企业", "核心企业")
if err != nil {
return err
}
return s.PutState(ctx, asset)
}

// createAsset issues a new asset to the world state with given details.
func (s *SmartContract) createAsset(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string) (*Asset, error) {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return nil, err
}
if exists {
return nil, fmt.Errorf("the asset %s already exists", id)
}
now, err := getNow(ctx)
if err != nil {
return nil, err
}
asset := Asset{ID: id, Issuer: issuerName, Amount: amount, Owner: owner, CreateDate: now,
EndDate: now.AddDate(0, 6, 0), ContractHash: "test", InvoiceHash: "test"}
return &asset, nil
}

func getNow(ctx contractapi.TransactionContextInterface) (time.Time, error) {
now, err := ctx.GetStub().GetTxTimestamp()
if err != nil {
return time.Now(), err
}
return ptypes.Timestamp(now)
}

// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}

var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}

return &asset, nil
}

// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}

return assetJSON != nil, nil
}

// TransferAsset updates the owner field of asset with given id in world state.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string, amount int64) error {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return err
}
// 如果金额刚好等于凭证资产的金额,直接更新凭证资产的拥有者
if asset.Amount == amount {
asset.Owner = newOwner
err = s.PutState(ctx, asset)
} else if asset.Amount > amount { // 如果凭证资产的金额大于转账的金额,则创建一个新的资产
// 创建新的资产并保存
newAsset, err := s.createAsset(ctx, asset.ID+"1", amount, asset.Issuer, newOwner)
if err != nil {
return err
}
err = s.PutState(ctx, newAsset)
if err != nil {
return err
}
// 更新旧资产的金额
asset.Amount = asset.Amount - amount
err = s.PutState(ctx, asset)
} else if asset.Amount < amount { // 如果资产的额度小于要转账的金额,则直接报错
err = fmt.Errorf("转账金额=%d,不能超过资产的金额=%d", amount, asset.Amount)
}
return err
}

// PutState 更新资产
func (s *SmartContract) PutState(ctx contractapi.TransactionContextInterface, asset *Asset) error {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(asset.ID, assetJSON)
}

// GetAllAssets returns all assets found in world state
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
// range query with empty string for startKey and endKey does an
// open-ended query of all assets in the chaincode namespace.
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()

var assets []*Asset
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}

var asset Asset
err = json.Unmarshal(queryResponse.Value, &asset)
if err != nil {
return nil, err
}
assets = append(assets, &asset)
}

return assets, nil
}

打包

1
peer lifecycle chaincode package supply.6.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_6.0

安装链码包

一级供应商和核心企业都要安装:
核心企业:

1
peer lifecycle chaincode install supply.6.tar.gz --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

一级供应商:

1
peer lifecycle chaincode install supply.6.tar.gz --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_6.0:18a7379ed3b12a57961a735880a71bea3dd242c741fa0970f779b5a338f848de

批准链码定义

核心企业和一级供应商都需要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 6.0 --package-id $CC_PACKAGE_ID --sequence 6 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下:

1
2020-12-28 17:58:55.313 CST [chaincodeCmd] ClientWait -> INFO 001 txid [c4974d5c90ae4fb3bd31f179292d9943dd05aac47248f33e365d9f32ccb5ccb6] committed with status (VALID) at localhost:8051

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID coreandfirstchannel --name supply --version 6.0 --sequence 6 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

成功结果如下:

1
2
3
4
5
6
{
"approvals": {
"GylCoreOrg1MSP": true,
"GylFOrg1MSP": true
}
}

在两个组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 6.0 --sequence 6 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

成功结果如下:

1
2
2020-12-28 17:51:08.452 CST [chaincodeCmd] ClientWait -> INFO 001 txid [87bc060e5ccdf4014cd4cf34bbbeb5d2ea10c4ff8ebb6f444d10580e2de2da50] committed with status (VALID) at localhost:8053
2020-12-28 17:51:08.460 CST [chaincodeCmd] ClientWait -> INFO 002 txid [87bc060e5ccdf4014cd4cf34bbbeb5d2ea10c4ff8ebb6f444d10580e2de2da50] committed with status (VALID) at localhost:8051

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID coreandfirstchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功结果如下,可以看到已经升级到2.0版本:

1
2
Committed chaincode definition for chaincode 'supply' on channel 'coreandfirstchannel':
Version: 2.0, Sequence: 2, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [GylCoreOrg1MSP: true, GylFOrg1MSP: true]

调用链码

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset002", "1000"]}'

成功信息如下:

1
2020-12-29 10:59:48.513 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

错误信息如下:

1
Error: endorsement failure during invoke. response: status:500 message:"the asset asset001 already exists"

**解决方案:**原因是以内资产ID为asset001的资产已经存在,修改资产ID参数即可。

查询调用后的结果

1
peer chaincode query -C coreandfirstchannel -n supply -c '{"Args":["GetAllAssets"]}'

成功结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 100,
"createDate": "2020-12-28T10:37:54.271518Z",
"endDate": "2021-06-28T10:37:54.271518Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset002",
"issuer": "核心企业",
"owner": "核心企业",
"amount": 1000,
"createDate": "2020-12-29T02:59:48.495257Z",
"endDate": "2021-06-29T02:59:48.495257Z",
"contractHash": "test",
"invoiceHash": "test"
}
]

调用交易方法

把凭证资产拆分一部分(200)给一级供应商:

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset002", "一级供应商", "200"]}'

再次查询:peer chaincode query -C coreandfirstchannel -n supply -c '{"Args":["GetAllAssets"]}'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 100,
"createDate": "2020-12-28T10:37:54.271518Z",
"endDate": "2021-06-28T10:37:54.271518Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset002",
"issuer": "核心企业",
"owner": "核心企业",
"amount": 800,
"createDate": "2020-12-29T02:59:48.495257Z",
"endDate": "2021-06-29T02:59:48.495257Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset0021",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 200,
"createDate": "2020-12-29T03:02:49.495789Z",
"endDate": "2021-06-29T03:02:49.495789Z",
"contractHash": "test",
"invoiceHash": "test"
}
]

交易之后,核心企业剩余800的凭证,一级供应商获得一个新的凭证。验证无误。

部署v7版本的supply

v7版本智能合约源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package chaincode

import (
"encoding/json"
"fmt"
"time"

"github.com/golang/protobuf/ptypes"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// SmartContract provides functions for managing an Asset
type SmartContract struct {
contractapi.Contract
}

// Asset describes basic details of what makes up a simple asset
type Asset struct {
ID string `json:"ID"`
Issuer string `json:"issuer"`
Owner string `json:"owner"`
Amount int64 `json:"amount"`
CreateDate time.Time `json:"createDate"`
EndDate time.Time `json:"endDate"`
ContractHash string `json:"contractHash"`
InvoiceHash string `json:"invoiceHash"`
}

// IssueVoucher 发行凭证
func (s *SmartContract) IssueVoucher(ctx contractapi.TransactionContextInterface, assetID string, amount int64, owner string, contractHash string, invoiceHash string) error {
// 创建资产
return s.CreateAssetAndSave(ctx, assetID, amount, "核心企业", owner, contractHash, invoiceHash)
}

// CreateAssetAndSave 创建资产并保存
func (s *SmartContract) CreateAssetAndSave(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) error {
asset, err := s.createAsset(ctx, id, amount, issuerName, owner, contractHash, invoiceHash)
if err != nil {
return err
}
return s.PutState(ctx, asset)
}

// createAsset issues a new asset to the world state with given details.
func (s *SmartContract) createAsset(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) (*Asset, error) {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return nil, err
}
if exists {
return nil, fmt.Errorf("the asset %s already exists", id)
}
now, err := getNow(ctx)
if err != nil {
return nil, err
}
asset := Asset{ID: id, Issuer: issuerName, Amount: amount, Owner: owner, CreateDate: now,
EndDate: now.AddDate(0, 6, 0), ContractHash: contractHash, InvoiceHash: invoiceHash}
return &asset, nil
}

// 获取当前时间
func getNow(ctx contractapi.TransactionContextInterface) (time.Time, error) {
now, err := ctx.GetStub().GetTxTimestamp()
if err != nil {
return time.Now(), err
}
return ptypes.Timestamp(now)
}

// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}

var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}

return &asset, nil
}

// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}

return assetJSON != nil, nil
}

// TransferAssetByID 根据资产ID转账
func (s *SmartContract) TransferAssetByID(ctx contractapi.TransactionContextInterface, id string, newOwner string, amount int64, contractHash string, invoiceHash string) error {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return err
}
return s.TransferAsset(ctx, asset, newOwner, amount, contractHash, invoiceHash)
}

// TransferAsset updates the owner field of asset with given id in world state.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, asset *Asset, newOwner string, amount int64, contractHash string, invoiceHash string) error {
// 如果金额刚好等于凭证资产的金额,直接更新凭证资产的拥有者
if asset.Amount == amount {
asset.Owner = newOwner
return s.PutState(ctx, asset)
} else if asset.Amount > amount { // 如果凭证资产的金额大于转账的金额,则创建一个新的资产
// 创建新的资产并保存
err := s.CreateAssetAndSave(ctx, asset.ID+"1", amount, asset.Issuer, newOwner, contractHash, invoiceHash)
if err != nil {
return err
}
// 更新旧资产的金额
asset.Amount = asset.Amount - amount
return s.PutState(ctx, asset)
} else if asset.Amount < amount { // 如果资产的额度小于要转账的金额,则直接报错
return fmt.Errorf("转账金额=%d,不能超过资产的金额=%d", amount, asset.Amount)
}
return nil
}

// PutState 更新资产
func (s *SmartContract) PutState(ctx contractapi.TransactionContextInterface, asset *Asset) error {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(asset.ID, assetJSON)
}

// GetAllAssets returns all assets found in world state
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
// range query with empty string for startKey and endKey does an
// open-ended query of all assets in the chaincode namespace.
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()

var assets []*Asset
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}

var asset Asset
err = json.Unmarshal(queryResponse.Value, &asset)
if err != nil {
return nil, err
}
assets = append(assets, &asset)
}

return assets, nil
}

打包

1
peer lifecycle chaincode package supply.7.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_7.0

安装链码包

一级供应商和核心企业都要安装:
核心企业:

1
peer lifecycle chaincode install supply.7.tar.gz --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

一级供应商:

1
peer lifecycle chaincode install supply.7.tar.gz --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_7.0:770f0c8f4fe3a348314f546594d402ccb3eb5f5779f12e7edee48f6ce474227b

批准链码定义

核心企业和一级供应商都需要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 7.0 --package-id $CC_PACKAGE_ID --sequence 7 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID coreandfirstchannel --name supply --version 7.0 --sequence 7 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在两个组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID coreandfirstchannel --name supply --version 7.0 --sequence 7 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID coreandfirstchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

调用链码

调用链码之前先生成测试的合同hash值和发票hash值

1
2
shasum -a 256 CORE_AND_F1_CONTRACT.txt > core_and_f1_contract_hash.txt
shasum -a 256 CORE_AND_F1_INVOICE.txt > CORE_AND_F1_INVOICE_hash.txt

发行凭证

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C coreandfirstchannel -n supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset003", "1000", "一级供应商", "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14", "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"]}'

查询调用后的结果

1
peer chaincode query -C coreandfirstchannel -n supply -c '{"Args":["GetAllAssets"]}'

成功结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 100,
"createDate": "2020-12-28T10:37:54.271518Z",
"endDate": "2021-06-28T10:37:54.271518Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset002",
"issuer": "核心企业",
"owner": "核心企业",
"amount": 800,
"createDate": "2020-12-29T02:59:48.495257Z",
"endDate": "2021-06-29T02:59:48.495257Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset0021",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 200,
"createDate": "2020-12-29T03:02:49.495789Z",
"endDate": "2021-06-29T03:02:49.495789Z",
"contractHash": "test",
"invoiceHash": "test"
},
{
"ID": "asset003",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 1000,
"createDate": "2020-12-29T06:20:30.868298Z",
"endDate": "2021-06-29T06:20:30.868298Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
}
]

ID为asset003的资产归属为一级供应商,金额无误。

创建一级供应商与二级供应商之间的channel

创建通道:

运行下面的程序来为firstandsecondchannel通道创建一个“创建通道的交易”

1
configtxgen -profile FirstAndSecondChannel -outputCreateChannelTx ./channel-artifacts/firstandsecondchannel.tx -channelID firstandsecondchannel

执行结果如下:

1
2
3
4
2020-12-29 14:27:37.416 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2020-12-29 14:27:37.430 CST [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/config/configtx.yaml
2020-12-29 14:27:37.430 CST [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 003 Generating new channel configtx
2020-12-29 14:27:37.436 CST [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 004 Writing new channel tx

设置环境变量,以一级供应商管理员身份操作peerCLI,使用下面的命令把交易发给order服务创建通道:

1
peer channel create -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com -c firstandsecondchannel -f ./channel-artifacts/firstandsecondchannel.tx --outputBlock ./channel-artifacts/firstandsecondchannel.block --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

错误信息记录:

1
Error: got unexpected status: BAD_REQUEST -- error validating channel creation transaction for new channel 'firstandsecondchannel', could not successfully apply update to template configuration: error authorizing update: error validating DeltaSet: policy for [Group]  /Channel/Application not satisfied: implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Admins' sub-policies to be satisfied

错误原因和解决方案:

由于配置文件里面配置的firstandsecondchannel里面包含一级供应商和两个二级供应商,而上面的命令是以核心企业的管理员身份运行的。所以有问题。切换成一级供应商的环境执行即可。

正确执行之后的日志:

1
2
3
4
5
6
7
8
9
10
11
12
2020-12-29 14:34:06.203 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:34:06.231 CST [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
2020-12-29 14:34:06.244 CST [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2020-12-29 14:34:06.450 CST [cli.common] readBlock -> INFO 004 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2020-12-29 14:34:06.458 CST [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2020-12-29 14:34:06.667 CST [cli.common] readBlock -> INFO 006 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2020-12-29 14:34:06.676 CST [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2020-12-29 14:34:06.885 CST [cli.common] readBlock -> INFO 008 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2020-12-29 14:34:06.892 CST [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2020-12-29 14:34:07.099 CST [cli.common] readBlock -> INFO 00a Expect block, but got status: &{SERVICE_UNAVAILABLE}
2020-12-29 14:34:07.108 CST [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2020-12-29 14:34:07.320 CST [cli.common] readBlock -> INFO 00c Received block: 0

把一级供应商和二级供应商的peer加入通道

一级供应商的peer加入通道

使用下面的命令将peer加入通道

1
peer channel join -b ./channel-artifacts/firstandsecondchannel.block

成功信息如下:

1
2
2020-12-29 14:35:00.679 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:35:00.724 CST [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

通过获取通道信息确认加入成功

获取通道信息

1
peer channel getinfo -c firstandsecondchannel

可以看到如下信息:

1
2
2020-12-29 14:35:28.593 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Blockchain info: {"height":1,"currentBlockHash":"270CWtnSyXJmeGCxJx41sX7uTchRZpljYWKJ48dD434="}

二级供应商1加入通道

设置环境变量,然后拉取通道的创世纪区块(因为是测试本次忽略):

1
peer channel fetch 0 ./channel-artifacts/coreandfirstchannel.block -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com -c coreandfirstchannel --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

加入通道:

1
peer channel join -b ./channel-artifacts/firstandsecondchannel.block

成功信息如下:

1
2
2020-12-29 14:47:03.684 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:47:03.722 CST [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

报错信息如下:

1
2
3
supply-finance apple$ peer channel join -b ./channel-artifacts/coreandfirstchannel.block
2020-12-29 14:43:56.186 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Error: proposal failed (err: rpc error: code = Unknown desc = error validating proposal: access denied: channel [] creator org [GylSOrg1M])

**错误原因:**由于环境变量设置的有问题,CORE_PEER_LOCALMSPID设置成了GylSOrg1M,应该设置为GylSOrg1MSP

二级供应商2加入通道

设置环境变量,然后拉取通道的创世纪区块(因为是测试本次忽略):

1
peer channel fetch 0 ./channel-artifacts/coreandfirstchannel.block -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com -c coreandfirstchannel --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

加入通道:

1
peer channel join -b ./channel-artifacts/firstandsecondchannel.block

成功信息如下:

1
2
2020-12-29 14:52:12.969 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:52:13.010 CST [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

设置锚节点

为GylFOrg1MSP设置锚节点

拉取最新的channel配置区块
1
peer channel fetch config channel-artifacts/firstandsecondchannel_config_block.pb -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com -c firstandsecondchannel --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

成功信息如下:

1
2
3
4
2020-12-29 14:55:57.114 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:55:57.120 CST [cli.common] readBlock -> INFO 002 Received block: 0
2020-12-29 14:55:57.120 CST [channelCmd] fetch -> INFO 003 Retrieving last config block: 0
2020-12-29 14:55:57.125 CST [cli.common] readBlock -> INFO 004 Received block: 0
修改通道配置区块

切换到channel-artifacts然后把区块内容转换成json格式:

1
2
3
4
5
cd channel-artifacts
configtxlator proto_decode --input firstandsecondchannel_config_block.pb --type common.Block --output firstandsecondchannel_config_block.json
jq .data.data[0].payload.data.config firstandsecondchannel_config_block.json > firstandsecondchannel_config.json
# copy一份
cp firstandsecondchannel_config.json firstandsecondchannel_config_copy.json

使用jq 工具来添加GylFOrg1MSP组织的锚节点到通道配置。

1
jq '.channel_group.groups.Application.groups.GylFOrg1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.f1.supply.com","port": 8053}]},"version": "0"}}' firstandsecondchannel_config_copy.json > modified_firstandsecondchannel_config.json

将原始的和修改后的通道配置都转换回protobuf格式,并计算它们之间的差异。

1
2
3
configtxlator proto_encode --input firstandsecondchannel_config.json --type common.Config --output firstandsecondchannel_config.pb
configtxlator proto_encode --input modified_firstandsecondchannel_config.json --type common.Config --output modified_firstandsecondchannel_config.pb
configtxlator compute_update --channel_id firstandsecondchannel --original firstandsecondchannel_config.pb --updated modified_firstandsecondchannel_config.pb --output firstandsecondchannel_config_update.pb
把更新后的交易打包成一个更新通道配置的交易:
1
2
3
configtxlator proto_decode --input firstandsecondchannel_config_update.pb --type common.ConfigUpdate --output firstandsecondchannel_config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"firstandsecondchannel", "type":2}},"data":{"config_update":'$(cat firstandsecondchannel_config_update.json)'}}}' | jq . > firstandsecondchannel_config_update_in_envelope.json
configtxlator proto_encode --input firstandsecondchannel_config_update_in_envelope.json --type common.Envelope --output firstandsecondchannel_config_update_in_envelope.pb
提交“更新通道配置的交易”

进到上一级目录cd ..,之后运行命令将交易提交给排序服务进行通道配置的更新:

1
2
cd ..
peer channel update -f channel-artifacts/firstandsecondchannel_config_update_in_envelope.pb -c firstandsecondchannel -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

执行成功的结果:

1
2
2020-12-29 14:57:48.872 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 14:57:48.894 CST [channelCmd] update -> INFO 002 Successfully submitted channel update
验证,获取通道信息:peer channel getinfo -c firstandsecondchannel
1
2
2020-12-29 14:58:15.937 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Blockchain info: {"height":2,"currentBlockHash":"4lhXvhRKDNxBsOIGL0H0A5QDdNkySgv/ehtUkobtW9Y=","previousBlockHash":"270CWtnSyXJmeGCxJx41sX7uTchRZpljYWKJ48dD434="}

为二级供应商1(GylSOrg1MSP)设置锚节点

修改环境变量,拉取最新的channel配置区块

1
peer channel fetch config channel-artifacts/firstandsecondchannel_config_block.pb -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com -c firstandsecondchannel --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem
修改通道配置区块

切换到channel-artifacts然后把区块内容转换成json格式:

1
2
3
4
5
cd channel-artifacts
configtxlator proto_decode --input firstandsecondchannel_config_block.pb --type common.Block --output firstandsecondchannel_config_block.json
jq .data.data[0].payload.data.config firstandsecondchannel_config_block.json > firstandsecondchannel_config.json
# copy一份
cp firstandsecondchannel_config.json firstandsecondchannel_config_copy.json

使用jq 工具来添加GylCoreOrg1MSP组织的锚节点到通道配置。

1
jq '.channel_group.groups.Application.groups.GylSOrg1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.s1.supply.com","port": 8055}]},"version": "0"}}' firstandsecondchannel_config_copy.json > modified_firstandsecondchannel_config.json

将原始的和修改后的通道配置都转换回protobuf格式,并计算它们之间的差异。

1
2
3
configtxlator proto_encode --input firstandsecondchannel_config.json --type common.Config --output firstandsecondchannel_config.pb
configtxlator proto_encode --input modified_firstandsecondchannel_config.json --type common.Config --output modified_firstandsecondchannel_config.pb
configtxlator compute_update --channel_id firstandsecondchannel --original firstandsecondchannel_config.pb --updated modified_firstandsecondchannel_config.pb --output firstandsecondchannel_config_update.pb
把更新后的交易打包成一个更新通道配置的交易:
1
2
3
configtxlator proto_decode --input firstandsecondchannel_config_update.pb --type common.ConfigUpdate --output firstandsecondchannel_config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"firstandsecondchannel", "type":2}},"data":{"config_update":'$(cat firstandsecondchannel_config_update.json)'}}}' | jq . > firstandsecondchannel_config_update_in_envelope.json
configtxlator proto_encode --input firstandsecondchannel_config_update_in_envelope.json --type common.Envelope --output firstandsecondchannel_config_update_in_envelope.pb
提交“更新通道配置的交易”

进到上一级目录cd ..,之后运行命令将交易提交给排序服务进行通道配置的更新:

1
2
cd ..
peer channel update -f channel-artifacts/firstandsecondchannel_config_update_in_envelope.pb -c firstandsecondchannel -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

执行成功的结果:

1
2
2020-12-29 15:01:14.643 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 15:01:14.670 CST [channelCmd] update -> INFO 002 Successfully submitted channel update
验证,获取通道信息
1
2
3
(base) w:supply-finance apple$ peer channel getinfo -c firstandsecondchannel
2020-12-29 15:01:26.952 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Blockchain info: {"height":3,"currentBlockHash":"DPXkm090OpH9ww862WmR4EktxT0NHEM2i3Py0yHAGPE=","previousBlockHash":"4lhXvhRKDNxBsOIGL0H0A5QDdNkySgv/ehtUkobtW9Y="}

为二级供应商2(GylSOrg2MSP)设置锚节点

修改环境变量,拉取最新的channel配置区块

1
peer channel fetch config channel-artifacts/firstandsecondchannel_config_block.pb -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com -c firstandsecondchannel --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem
修改通道配置区块

切换到channel-artifacts然后把区块内容转换成json格式:

1
2
3
4
5
cd channel-artifacts
configtxlator proto_decode --input firstandsecondchannel_config_block.pb --type common.Block --output firstandsecondchannel_config_block.json
jq .data.data[0].payload.data.config firstandsecondchannel_config_block.json > firstandsecondchannel_config.json
# copy一份
cp firstandsecondchannel_config.json firstandsecondchannel_config_copy.json

使用jq 工具来添加GylCoreOrg1MSP组织的锚节点到通道配置。

1
jq '.channel_group.groups.Application.groups.GylSOrg2MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.s2.supply.com","port": 8151}]},"version": "0"}}' firstandsecondchannel_config_copy.json > modified_firstandsecondchannel_config.json

将原始的和修改后的通道配置都转换回protobuf格式,并计算它们之间的差异。

1
2
3
configtxlator proto_encode --input firstandsecondchannel_config.json --type common.Config --output firstandsecondchannel_config.pb
configtxlator proto_encode --input modified_firstandsecondchannel_config.json --type common.Config --output modified_firstandsecondchannel_config.pb
configtxlator compute_update --channel_id firstandsecondchannel --original firstandsecondchannel_config.pb --updated modified_firstandsecondchannel_config.pb --output firstandsecondchannel_config_update.pb
把更新后的交易打包成一个更新通道配置的交易:
1
2
3
configtxlator proto_decode --input firstandsecondchannel_config_update.pb --type common.ConfigUpdate --output firstandsecondchannel_config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"firstandsecondchannel", "type":2}},"data":{"config_update":'$(cat firstandsecondchannel_config_update.json)'}}}' | jq . > firstandsecondchannel_config_update_in_envelope.json
configtxlator proto_encode --input firstandsecondchannel_config_update_in_envelope.json --type common.Envelope --output firstandsecondchannel_config_update_in_envelope.pb
提交“更新通道配置的交易”

进到上一级目录cd ..,之后运行命令将交易提交给排序服务进行通道配置的更新:

1
2
cd ..
peer channel update -f channel-artifacts/firstandsecondchannel_config_update_in_envelope.pb -c firstandsecondchannel -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

执行成功的结果:

1
2
2020-12-29 15:03:39.793 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-12-29 15:03:39.817 CST [channelCmd] update -> INFO 002 Successfully submitted channel update
验证,获取通道信息
1
2
3
(base) w:supply-finance apple$ peer channel getinfo -c firstandsecondchannel
2020-12-29 15:04:10.414 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Blockchain info: {"height":4,"currentBlockHash":"PWXXje7tci4mk1ggQ9QMVzkvkP3i+N8WslOGDXreIQ0=","previousBlockHash":"DPXkm090OpH9ww862WmR4EktxT0NHEM2i3Py0yHAGPE="}

部署supply-v7到二级供应商的peer节点

打包

1
peer lifecycle chaincode package supply.7.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_7.0

安装链码包

两个二级供应商都要安装:
二级供应商1:

1
peer lifecycle chaincode install supply.7.tar.gz --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt

二级供应商2:

1
peer lifecycle chaincode install supply.7.tar.gz --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_7.0:770f0c8f4fe3a348314f546594d402ccb3eb5f5779f12e7edee48f6ce474227b

批准链码定义

一级供应商和两个二级供应商都需要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID firstandsecondchannel --name supply --version 7.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID firstandsecondchannel --name supply --version 7.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在所有组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID firstandsecondchannel --name supply --version 7.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID firstandsecondchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

错误信息记录:

1
2
(base) w:supply-finance apple$ peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID firstandsecondchannel --name supply --version 7.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt
Error: proposal failed with status: 500 - channel 'firstandsecondchannel' not found

**错误原因:**由于批准的组织中包含核心企业,核心企业并没有加入firstandsecondchannel通道,所以报错。

调用链码

调用链码之前先生成测试的合同hash值和发票hash值如下:

1
2
3
4
76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a  f1_and_s1_contract.txt
792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49 f1_and_s1_invoice.txt
f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb f1_and_s2_contract.txt
f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468 f1_and_s2_invoice.txt

调用转账交易:TODO 问题来了,两个channel之间如何交换资产?这是个问题

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com -C firstandsecondchannel -n supply --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset003", "1000", "一级供应商", "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14", "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"]}'
1
peer chaincode query -C firstandsecondchannel -n supply -c '{"Args":["GetAllAssets"]}'

核心企业、一级和二级供应商加入同一个channel

查看创建channel

部署supply-v7到alljoinchannel通道

打包

1
# peer lifecycle chaincode package supply.7.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_7.0

安装链码包

每个peer都要安装:peer lifecycle chaincode install supply.7.tar.gz

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_7.0:770f0c8f4fe3a348314f546594d402ccb3eb5f5779f12e7edee48f6ce474227b

批准链码定义

每个peer都要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 7.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID alljoinchannel --name supply --version 7.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在所有组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 7.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID alljoinchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

调用链码

调用链码之前先生成测试的合同hash值和发票hash值如下:

1
2
3
4
5
6
83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9  CORE_AND_F1_INVOICE.txt
93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14 CORE_AND_F1_CONTRACT.txt
76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a f1_and_s1_contract.txt
792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49 f1_and_s1_invoice.txt
f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb f1_and_s2_contract.txt
f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468 f1_and_s2_invoice.txt

发行凭证

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset003", "1000", "一级供应商", "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14", "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"]}'

查询资产

1
peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
[
{
"ID": "asset003",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 1000,
"createDate": "2020-12-29T10:07:43.665003Z",
"endDate": "2021-06-29T10:07:43.665003Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
}
]

一级供应商与二级供应商1交易

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset003", "二级供应商1", "500", "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a", "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"]}'

查询资产

1
peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"ID": "asset003",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 500,
"createDate": "2020-12-29T10:07:43.665003Z",
"endDate": "2021-06-29T10:07:43.665003Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
},
{
"ID": "asset0031",
"issuer": "核心企业",
"owner": "二级供应商1",
"amount": 500,
"createDate": "2020-12-29T10:12:37.227293Z",
"endDate": "2021-06-29T10:12:37.227293Z",
"contractHash": "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a",
"invoiceHash": "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"
}
]

一级供应商与二级供应商2交易

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset003", "二级供应商2", "300", "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb", "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"]}'

错误信息记录:

1
Error: endorsement failure during invoke. response: status:500 message:"the asset asset0031 already exists"

原因如下:如果同一个资产ID交易两次,则会出现资产ID重复的问题;代码bug。

1
err := s.CreateAssetAndSave(ctx, asset.ID+"1", amount, asset.Issuer, newOwner, contractHash, invoiceHash)

一级供应商与二级供应商2交易

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset0031", "二级供应商2", "300", "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb", "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"]}'

查询资产,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[
{
"ID": "asset003",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 500,
"createDate": "2020-12-29T10:07:43.665003Z",
"endDate": "2021-06-29T10:07:43.665003Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
},
{
"ID": "asset0031",
"issuer": "核心企业",
"owner": "二级供应商1",
"amount": 200,
"createDate": "2020-12-29T10:12:37.227293Z",
"endDate": "2021-06-29T10:12:37.227293Z",
"contractHash": "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a",
"invoiceHash": "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"
},
{
"ID": "asset00311",
"issuer": "核心企业",
"owner": "二级供应商2",
"amount": 300,
"createDate": "2020-12-29T10:17:26.148125Z",
"endDate": "2021-06-29T10:17:26.148125Z",
"contractHash": "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb",
"invoiceHash": "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"
}
]

部署supply-v8到alljoinchannel通道

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package chaincode

import (
"encoding/json"
"fmt"
"time"

"github.com/golang/protobuf/ptypes"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// SmartContract provides functions for managing an Asset
type SmartContract struct {
contractapi.Contract
}

// Asset describes basic details of what makes up a simple asset
type Asset struct {
ID string `json:"ID"`
Issuer string `json:"issuer"`
Owner string `json:"owner"`
Amount int64 `json:"amount"`
CreateDate time.Time `json:"createDate"`
EndDate time.Time `json:"endDate"`
ContractHash string `json:"contractHash"`
InvoiceHash string `json:"invoiceHash"`
}

// IssueVoucher 发行凭证
func (s *SmartContract) IssueVoucher(ctx contractapi.TransactionContextInterface, assetID string, amount int64, owner string, contractHash string, invoiceHash string) error {
// 创建资产
return s.CreateAssetAndSave(ctx, assetID, amount, "核心企业", owner, contractHash, invoiceHash)
}

// CreateAssetAndSave 创建资产并保存
func (s *SmartContract) CreateAssetAndSave(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) error {
asset, err := s.createAsset(ctx, id, amount, issuerName, owner, contractHash, invoiceHash)
if err != nil {
return err
}
return s.PutState(ctx, asset)
}

// createAsset issues a new asset to the world state with given details.
func (s *SmartContract) createAsset(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) (*Asset, error) {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return nil, err
}
if exists {
return nil, fmt.Errorf("the asset %s already exists", id)
}
now, err := getNow(ctx)
if err != nil {
return nil, err
}
asset := Asset{ID: id, Issuer: issuerName, Amount: amount, Owner: owner, CreateDate: now,
EndDate: now.AddDate(0, 6, 0), ContractHash: contractHash, InvoiceHash: invoiceHash}
return &asset, nil
}

// 获取当前时间
func getNow(ctx contractapi.TransactionContextInterface) (time.Time, error) {
now, err := ctx.GetStub().GetTxTimestamp()
if err != nil {
return time.Now(), err
}
return ptypes.Timestamp(now)
}

// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}

var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}

return &asset, nil
}

// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}

return assetJSON != nil, nil
}

// TransferAssetByID 根据资产ID转账
func (s *SmartContract) TransferAssetByID(ctx contractapi.TransactionContextInterface, id string, newID string, newOwner string, amount int64, contractHash string, invoiceHash string) error {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return err
}
return s.TransferAsset(ctx, asset, newID, newOwner, amount, contractHash, invoiceHash)
}

// TransferAsset updates the owner field of asset with given id in world state.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, asset *Asset, newID string, newOwner string, amount int64, contractHash string, invoiceHash string) error {
// 如果金额刚好等于凭证资产的金额,直接更新凭证资产的拥有者
if asset.Amount == amount {
asset.Owner = newOwner
return s.PutState(ctx, asset)
} else if asset.Amount > amount { // 如果凭证资产的金额大于转账的金额,则创建一个新的资产
if newID == "" {
return fmt.Errorf("转账金额小于资产的金额时,newID必须不能为空")
}
// 创建新的资产并保存
err := s.CreateAssetAndSave(ctx, newID, amount, asset.Issuer, newOwner, contractHash, invoiceHash)
if err != nil {
return err
}
// 更新旧资产的金额
asset.Amount = asset.Amount - amount
return s.PutState(ctx, asset)
} else if asset.Amount < amount { // 如果资产的额度小于要转账的金额,则直接报错
return fmt.Errorf("转账金额=%d,不能超过资产的金额=%d", amount, asset.Amount)
}
return nil
}

// PutState 更新资产
func (s *SmartContract) PutState(ctx contractapi.TransactionContextInterface, asset *Asset) error {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(asset.ID, assetJSON)
}

// GetAllAssets returns all assets found in world state
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
// range query with empty string for startKey and endKey does an
// open-ended query of all assets in the chaincode namespace.
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()

var assets []*Asset
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}

var asset Asset
err = json.Unmarshal(queryResponse.Value, &asset)
if err != nil {
return nil, err
}
assets = append(assets, &asset)
}

return assets, nil
}

打包

1
peer lifecycle chaincode package supply.8.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_8.0

安装链码包

每个peer都要安装:peer lifecycle chaincode install supply.8.tar.gz

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_8.0:797ec1d00145482b746640d0b8bb9bea64cb69dea3e95abb69a1195a19e34511

批准链码定义

每个peer都要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 8.0 --package-id $CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID alljoinchannel --name supply --version 8.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在所有组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 8.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID alljoinchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

调用链码

调用链码之前先生成测试的合同hash值和发票hash值如下:

1
2
3
4
5
6
83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9  CORE_AND_F1_INVOICE.txt
93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14 CORE_AND_F1_CONTRACT.txt
76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a f1_and_s1_contract.txt
792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49 f1_and_s1_invoice.txt
f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb f1_and_s2_contract.txt
f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468 f1_and_s2_invoice.txt

发行凭证

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"IssueVoucher","Args":["asset001", "1000", "一级供应商", "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14", "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"]}'

查询资产

1
peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 1000,
"createDate": "2020-12-30T06:57:06.963617Z",
"endDate": "2021-06-30T06:57:06.963617Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
}
]

一级供应商与二级供应商1交易

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset001", "asset0011", "二级供应商1", "500", "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a", "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"]}'

查询资产

1
peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 500,
"createDate": "2020-12-30T06:57:06.963617Z",
"endDate": "2021-06-30T06:57:06.963617Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
},
{
"ID": "asset0011",
"issuer": "核心企业",
"owner": "二级供应商1",
"amount": 500,
"createDate": "2020-12-30T06:57:50.047189Z",
"endDate": "2021-06-30T06:57:50.047189Z",
"contractHash": "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a",
"invoiceHash": "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"
}
]

一级供应商与二级供应商2交易

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset001", "asset0012", "二级供应商2", "300", "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb", "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"]}'

查询资产,结果如下peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "一级供应商",
"amount": 200,
"createDate": "2020-12-30T06:57:06.963617Z",
"endDate": "2021-06-30T06:57:06.963617Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
},
{
"ID": "asset0011",
"issuer": "核心企业",
"owner": "二级供应商1",
"amount": 500,
"createDate": "2020-12-30T06:57:50.047189Z",
"endDate": "2021-06-30T06:57:50.047189Z",
"contractHash": "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a",
"invoiceHash": "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"
},
{
"ID": "asset0012",
"issuer": "核心企业",
"owner": "二级供应商2",
"amount": 300,
"createDate": "2020-12-30T06:58:33.143818Z",
"endDate": "2021-06-30T06:58:33.143818Z",
"contractHash": "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb",
"invoiceHash": "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"
}
]

转账金额大于凭证资产的金额(期待错误)

出现错误:

1
2
(base) w:supply-finance apple$ peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset001", "asset0013", "二级供应商2", "300", "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb", "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"]}'
Error: endorsement failure during invoke. response: status:500 message:"\350\275\254\350\264\246\351\207\221\351\242\235=300,\344\270\215\350\203\275\350\266\205\350\277\207\350\265\204\344\272\247\347\232\204\351\207\221\351\242\235=200"

错误信息解码如下:

转账金额等于凭证资产的金额(变更owner,不产生新的凭证资产)

一级供应商把剩余的200转给二级供应商2:

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"TransferAssetByID","Args":["asset001", "asset0013", "二级供应商2", "200", "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb", "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"]}'

查询资产,结果如下peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[
{
"ID": "asset001",
"issuer": "核心企业",
"owner": "二级供应商2",
"amount": 200,
"createDate": "2020-12-30T06:57:06.963617Z",
"endDate": "2021-06-30T06:57:06.963617Z",
"contractHash": "93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14",
"invoiceHash": "83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9"
},
{
"ID": "asset0011",
"issuer": "核心企业",
"owner": "二级供应商1",
"amount": 500,
"createDate": "2020-12-30T06:57:50.047189Z",
"endDate": "2021-06-30T06:57:50.047189Z",
"contractHash": "76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a",
"invoiceHash": "792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49"
},
{
"ID": "asset0012",
"issuer": "核心企业",
"owner": "二级供应商2",
"amount": 300,
"createDate": "2020-12-30T06:58:33.143818Z",
"endDate": "2021-06-30T06:58:33.143818Z",
"contractHash": "f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb",
"invoiceHash": "f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468"
}
]

没有产生新的资产,而是把原来的资产的拥有者变更了。

注意:这样有个问题,合同hash和发票hash不应该还是原来的。

部署supply-v9到alljoinchannel通道

源码

与v8版本相比,增加删除资产的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// DelState 删除资产
func (s *SmartContract) DelState(ctx contractapi.TransactionContextInterface, assetIds ...string) error {
for _, assetID := range assetIds {
exists, err := s.AssetExists(ctx, assetID)
if err != nil {
return nil
}
if !exists {
return fmt.Errorf("assetID=%s的资产不存在", assetID)
}
return ctx.GetStub().DelState(assetID)
}
return nil
}

打包

1
peer lifecycle chaincode package supply.18.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance-chaincode/ --lang golang --label secured_supply_22.0

安装链码包

每个peer都要安装:peer lifecycle chaincode install supply.18.tar.gz

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=secured_supply_22.0:e815ca2d270dea029bc6992952140b1288a440aba8c430853f72eee7d5de24a7

批准链码定义

每个peer都要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name secured_supply --version 22.0 --package-id $CC_PACKAGE_ID --sequence 22 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID alljoinchannel --name secured_supply --version 22.0 --sequence 22 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在所有组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name secured_supply --version 22.0 --sequence 22 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID alljoinchannel --name secured_supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

调用链码

调用链码之前先生成测试的合同hash值和发票hash值如下:

1
2
3
4
5
6
83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9  CORE_AND_F1_INVOICE.txt
93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14 CORE_AND_F1_CONTRACT.txt
76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a f1_and_s1_contract.txt
792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49 f1_and_s1_invoice.txt
f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb f1_and_s2_contract.txt
f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468 f1_and_s2_invoice.txt

删除资产

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"DelState","Args":["asset001 asset0011 asset0012 asset003 asset0031 asset00311"]}'

错误信息记录:

1
2
(base) w:supply-finance apple$ peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"DelState","Args":["asset001 asset0011 asset0012 asset003 asset0031 asset00311"]}'
Error: endorsement failure during invoke. response: status:500 message:"Error managing parameter param0. Conversion error. Value asset001 asset0011 asset0012 asset003 asset0031 asset00311 was not passed in expected format []string"

**错误原因:**因为方法使用的是可变长参数,但是不知道该怎么给他传参数

部署supply-v9.1到alljoinchannel通道

源码

与v9版本相比,修改删除资产的方法为删除单个资产

1
2
3
4
5
6
7
8
9
10
11
// DelState 删除资产
func (s *SmartContract) DelState(ctx contractapi.TransactionContextInterface, assetID string) error {
exists, err := s.AssetExists(ctx, assetID)
if err != nil {
return nil
}
if !exists {
return fmt.Errorf("assetID=%s的资产不存在", assetID)
}
return ctx.GetStub().DelState(assetID)
}

打包

1
peer lifecycle chaincode package supply.9.1.tar.gz --path /Users/apple/code/open-source/blockchain/hyperledger/supply-finance/chaincode-go/ --lang golang --label supply_9.1

安装链码包

每个peer都要安装:peer lifecycle chaincode install supply.9.1.tar.gz

批准链码定义

查看已经安装的chaincode

1
peer lifecycle chaincode queryinstalled

将链码的信息保存为一个变量,两个组织都需要定义此变量:

1
export CC_PACKAGE_ID=supply_9.1:f733e8484c17cb415e38ac1fb14ed646622f2980762906c97d6e7e1c1a90f2c3

批准链码定义

每个peer都要执行此命令:

1
peer lifecycle chaincode approveformyorg -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 9.1 --package-id $CC_PACKAGE_ID --sequence 4 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

将链码定义提交到通道

检查channel上的成员是否已经批准了链码定义:

1
peer lifecycle chaincode checkcommitreadiness --channelID alljoinchannel --name supply --version 9.1 --sequence 4 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --output json

在所有组织都批准之后,执行下面的命令将链码定义提交到通道:

1
peer lifecycle chaincode commit -o localhost:8050  --ordererTLSHostnameOverride orderer.supply.com --channelID alljoinchannel --name supply --version 9.1 --sequence 4 --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt

使用 peer lifecycle chaincode querycommitted 命令来确认链码定义已经提交到通道。

1
peer lifecycle chaincode querycommitted --channelID alljoinchannel --name supply --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem

调用链码

调用链码之前先生成测试的合同hash值和发票hash值如下:

1
2
3
4
5
6
83c02ac2d48c863dab2ccf6870455aadfc2cec073b8db269b517c879d76aa6d9  CORE_AND_F1_INVOICE.txt
93b46869be90a6b1f688357965f89b5a8a5e32bf13710fb4ad00e25cca0f0b14 CORE_AND_F1_CONTRACT.txt
76307cd9d79c76a2a7894677692ce421ff1a31e32717a7de6f07deb5de395e7a f1_and_s1_contract.txt
792376c209f338959be4cf00c54dbf82662b90516082e23106faec4c43c69e49 f1_and_s1_invoice.txt
f46555b7ddd1f8dd232bdc0dcbc5b1f34bdf1d4bb7c123a79a6ed628175f29bb f1_and_s2_contract.txt
f807fe6dc767be2e7021d41540114b33b30fa7784f6de5521251f23a3eb66468 f1_and_s2_invoice.txt

删除资产

资产ID列表:“asset001 asset0011 asset0012 asset003 asset0031 asset00311”

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"DelState","Args":["asset00311"]}'

删除之后查询:

1
peer chaincode query -C alljoinchannel -n supply -c '{"Args":["GetAllAssets"]}'

返回的资产列表为空,删除方法验证成功。

1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n secured_supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"Practice_SmartContract:InitLedger","Args":[]}'
1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n secured_supply --peerAddresses localhost:8053 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/f1.supply.com/peers/peer0.f1.supply.com/tls/ca.crt --peerAddresses localhost:8055 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s1.supply.com/peers/peer0.s1.supply.com/tls/ca.crt --peerAddresses localhost:8151 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/s2.supply.com/peers/peer0.s2.supply.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"Practice_SmartContract:SomeStubMethod","Args":["asset1"]}'
1
peer chaincode invoke -o localhost:8050 --ordererTLSHostnameOverride orderer.supply.com --tls --cafile ${PWD}/organizations/ordererOrganizations/supply.com/orderers/orderer.supply.com/msp/tlscacerts/tlsca.supply.com-cert.pem -C alljoinchannel -n secured_supply --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/core.supply.com/peers/peer0.core.supply.com/tls/ca.crt -c '{"function":"Practice_SmartContract:InitLedger","Args":[]}'