部署新的智能合约到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 chaincodeimport ( "encoding/json" "fmt" "time" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) type SmartContract struct { contractapi.Contract } 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"` } 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) } 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) } 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 } 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 } 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 } 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) } func (s *SmartContract) GetAllAssets (ctx contractapi.TransactionContextInterface) ([]*Asset, error) { 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 chaincodeimport ( "encoding/json" "fmt" "time" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) type SmartContract struct { contractapi.Contract } 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"` } 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) } 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) } 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) } 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 } 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 } 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) } 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 } 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) } func (s *SmartContract) GetAllAssets (ctx contractapi.TransactionContextInterface) ([]*Asset, error) { 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
设置环境变量,以一级供应商管理员身份操作peer
CLI,使用下面的命令把交易发给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 chaincodeimport ( "encoding/json" "fmt" "time" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) type SmartContract struct { contractapi.Contract } 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"` } 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) } 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) } 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) } 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 } 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 } 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) } 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 } 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) } func (s *SmartContract) GetAllAssets (ctx contractapi.TransactionContextInterface) ([]*Asset, error) { 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 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 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":[]}'