一、问题背景
在b站学习fabric的过程中,博主DevX_有一个java链码的例子
hepeng/hyperledger-fabric-contract-java-demo
在该链码中存在着两套智能合约:分别是CatContract和UserContract。
两个Contract彼此并不关联,但是写在了同一个链码中。我们将链码打成jar包,在jar包中两套智能合约应该都存在。按道理两个应该都可以去调用。
我首先调用CatContract的链码发现是可以调用的,然而调用UserContract却发现并不能够调用。
【此处放一张图片】
按道理我们直接调用函数方法名即可,为什么会存在只能调用CatContract,但不能调用UserContract的情况呢。
二、原因分析
原因分析如下:
![](/qrcode.jpg)
看到上面两个图片的区别后,可以发现UserContract有一个@Default的注解而UserContract并没有这样的注解。
结合fabric-gateway中getContract()方法
可以看出 一个链码中如果有多个合约的话,@Default就是默认的那个合约。
而此时CatContract就是默认的那个合约,所以直接调用非默认的合约就会报错。
三、解决方案
那么我们该如何去调用非默认的合约呢?
3.1 fabric-gateway中调用非默认合约的办法
由上面的例子可以看出,想要调用链码中非默认的智能合约,就要将ContractName明确写入,然后进行调用。
这是fabric-gateway中规定的方法,那么我们可以去查看一下源码来明确命令行中怎么调用。
3.2 命令行中调用
可以看到在fabric-gateway去访问区块兰底层的过程中
合约名contractName是通过 contract:方法名进行调用的,这非常重要,我们在命令行中也需要这样进行调用。
四、实践
我重新部署了链码 将@Default给到了UserContract,而CatContract将作为非默认的合约。
我们具体去调用CatContract
当我在命令行中填写:
peer chaincode invoke -o orderer0.example.com:7050 --ordererTLSHostnameOverride orderer0.example.com --tls --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C businesschannel -n hyperledger-fabric-contract-java-demo --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"CatContract:createCat","Args":["cat-0" , "tom" , "3" , "蓝色" , "大懒猫"]}'
结果如下:
竟然成功了!
说明contractName:方法名是有效的!!
问题成功解决!!
五、过程中的一些坑
5.1 在命令行中传JSON参数
在这个智能合约中,我们需要传入JSON格式的数据
不能这样传:
peer chaincode invoke -o orderer0.example.com:7050 --ordererTLSHostnameOverride orderer0.example.com --tls --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C businesschannel -n hyperledger-fabric-contract-java-demo --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"regUser","Args":["person-30" , "20211" , "aa" , "男" , "10月1日","19525"]}'
这样传并不是JSON格式的,而是一个一个参数去传,会报错!
JSON格式应该是:
peer chaincode invoke -o orderer0.example.com:7050 --ordererTLSHostnameOverride orderer0.example.com --tls --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C businesschannel -n hyperledger-fabric-contract-java-demo --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"regUser","Args":["{\"key\": \"person-30\",\"idCard\": \"202125201151\",\"name\": \"aaa\",\"sex\": \"男\",\"birthday\": \"1001\",\"phone\": \"123456\"}"]}'
将JSON写成一个参数并且将每个引号都用\进行转义,这样就能传参成功!