Hyperledger Fabric 2.4.1 2.3.3 问题汇总

Ubuntu 20.04
Hyperledger Fabric 2.3.3
SDK对应的Go 1.17.5
链码对应的Go 1.18
Fabric-sdk-go 1.0.0
Docker 20.10.12
Docker-Compose 2.11.2

1. 链码提交后,调用合约函数出错,channelID为空:

调用命令:
peer chaincode invoke -o localhost:7050 – ordererTLSHostnameOverride orderer.example.com –tls –cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem –channelID cychannel –name marriage –peerAddresses localhost:7051 –tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt –peerAddresses localhost:9051 –tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c ‘{“function”:“Register”,“Args”:[“1001”,“jack”]}’

出现如下错误:
Error: The required parameter ‘channelID’ is empty. Rerun the command with -C flag

原因:
所调用命令的缩进有问题(命令从本地拷贝到虚拟机易出错), –后不能有空格

解决后:
2023-01-03 21:54:08.247 CST 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200

2. 链码提交后,调用合约函数出错,状态码500,链码未安装:

调用命令:
peer chaincode query -C cychannel -n marriage -c ‘{“Args”:[“searchMarriageInfoByClientId”,“1001”]}’

出现如下错误:
Error: endorsement failure during query. response: status:500 message:“make sure the chaincode marriage has been successfully defined on channel cychannel and try again: chaincode definition for ‘marriage’ exists, but chaincode is not installed”

原因:
在确保链码提交成功的情况下出现该错误,原因是函数名小写开头,只在本包内调用有效,外部无法调用。将函数名改为大写开头即可。

解决后:
{“id”:“1001”,“marriage_id”:“”,“person_name”:“jack”,“is_married”:false}

补充:另一种情况也出现了这个问题

情景:
本地主机通过Go-SDK调用远程云服务器的链码(防火墙已开放 TCP 7051 和 9051 端口)。

原因:
我在链码函数中添加了权限判断(只有拥有org1证书的客户端才能访问):

结果,我在sdk中初始化合约对象时,用的是org2的证书。于是,删除生成的wallet文件(这一步很关键),将代码中的org2全部修改成org1,成功。

3. 本地SDK调用远程主机的链码,报错,connection is in TRANSIENT_FAILURE:

出现如下错误:
event service creation failed: could not get chConfig cache reference: QueryBlockConfig failed: QueryBlockConfig failed: queryChaincode failed: Transaction processing for endorser [192.168.6.149:7051]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [192.168.6.149:7051]: connection is in TRANSIENT_FAILURE

原因:
我本地的SDK项目结构如下:

我使用的配置文件是fabric-samples下test-network下的,需要提前准备三件事情:
① 修改本地的organizations中的connection-org1.yaml的url为远程主机的IP:

② 在本地hosts文件中添加远程主机的域名解析。

③ 每次链码部署成功后,都需要从test-network中更新本地项目的organizations(一个organizations只能用于一个SDK项目)。

确保上述工作无误后,运行main.go调用远程链码报错…
原因是fabric-sdk-go与fabric2.4.x版本不兼容,更换为fabric2.3.3后成功解决问题。
(如果想使用2.4.x的版本,需要借助新的sdk:fabric-gateway,其Github地址为https://github.com/hyperledger/fabric-gateway)

4. 本地SDK调用远程主机的链码,报错,configure MSP failed: sanitizeCert failed the supplied identity is not valid: x509: certificate signed by unknown authority:

原因:
Go的版本问题,我本地的Go版本是1.19.2,更换为1.17.5后,问题解决。

解决后:
SDK终于启动成功,并能正常调用远程链码。

5. 在创建通道时./network.sh up createChannel命令报错,报错信息为osnadmin: error: unknown long flag ‘–channel -id’, try –help

解决方法:
需要修改fabric-samples/test-network/scripts下的createChannel.sh文件,将createChannel函数中的–channel -id修改为–channelID

6. 通过SDK调用远程主机的链码时,报错:UTC – lazyref.(*Reference).refreshValue -> WARN Error – initializer returned error: load MSPs from config failed: configure MSP failed: sanitizeCert failed the supplied identity is not valid: x509: certificate signed by unknown authority. Will retry again later

解决方法:
还是Go版本的问题,我将Go 1.19.2更换为Go 1.17.5之后,问题解决。

7. SDK如何设置wallet的生成路径?

解决方法:
wallet, err := gateway.NewFileSystemWallet(“org1/wallet”)

8. 调用链码失败

报错信息:
Error: endorsement failure during invoke. response: status:500 message:“error in simulation: failed to execute transaction 306ed1ca53720d68d6e392198014ca2e91fbfa79a9f6e6be7a7e40f497bf4b1e: could not launch chaincode rent_1.0:e678092929f2e636a5bcb1ddbfd52dd04c45b1fc5128a2a4cf883cb5c7991ee9: chaincode registration failed: container exited with 2”

原因:
链码本身的问题。链码函数都有一个指针类型的receiver,对应的实例是继承了contractapi.Contract的合约。而我不小心,将实例写成了某个自定义的结构体,导致出错。

解决方法:
定义的合约:

错误:

正确:

9. 链码中,contractapi版本的问题

go mod tidy默认导入最新版本,截至目前(2023.03.17)contractapi的最新版本是1.2.1,要求go的版本是1.19以上(一个月前,contractapi最新版本是1.2.0,支持go 1.18,并不会出现这个问题),而我本地的go是1.18版本,因此安装链码会出现错误。

而我将go版本更换为1.19之后,安装链码时会有意外的错误…因此,我只能修改contractapi的版本使其支持低版本的go。由于我链码所在的虚拟机的go版本是1.18,因此我将contractapi的版本更改为1.2.0(1.2.0要求go版本是1.17以上),这样就兼容了。

module xxxgo 1.18require github.com/hyperledger/fabric-contract-api-go v1.2.0require (github.com/go-openapi/jsonpointer v0.19.5 // indirectgithub.com/go-openapi/jsonreference v0.20.0 // indirectgithub.com/go-openapi/spec v0.20.6 // indirectgithub.com/go-openapi/swag v0.21.1 // indirectgithub.com/gobuffalo/envy v1.10.1 // indirectgithub.com/gobuffalo/packd v1.0.1 // indirectgithub.com/gobuffalo/packr v1.30.1 // indirectgithub.com/golang/protobuf v1.5.2 // indirectgithub.com/hyperledger/fabric-chaincode-go v0.0.0-20220720122508-9207360bbddd // indirectgithub.com/hyperledger/fabric-protos-go v0.0.0-20220613214546-bf864f01d75e // indirectgithub.com/joho/godotenv v1.4.0 // indirectgithub.com/josharian/intern v1.0.0 // indirectgithub.com/mailru/easyjson v0.7.7 // indirectgithub.com/rogpeppe/go-internal v1.8.1 // indirectgithub.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirectgithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirectgithub.com/xeipuuv/gojsonschema v1.2.0 // indirectgolang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirectgolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirectgolang.org/x/text v0.3.7 // indirectgoogle.golang.org/genproto v0.0.0-20220719170305-83ca9fad585f // indirectgoogle.golang.org/grpc v1.48.0 // indirectgoogle.golang.org/protobuf v1.28.0 // indirectgopkg.in/yaml.v2 v2.4.0 // indirect)

10. 本地SDK访问服务器中的链码失败

报错信息:
“Failed to submit: Multiple errors occurred: – Transaction processing for endorser [localhost:7051]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [localhost:7051]: connection is in TRANSIENT_FAILURE – Transaction processing for endorser [localhost:9051]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [localhost:9051]: connection is in TRANSIENT_FAILURE”

解决方法:
SDK中设置DISCOVERY_AS_LOCALHOST为false,否则会向本地发送请求,链码放在服务器中,显然不可能访问到。

11. 本地SDK访问服务器中的链码失败

报错信息:
panic: Failed to submit: CreateAndSendTransaction failed: SendTransaction failed: calling orderer ‘orderer.example.com:7050’ failed: Orderer Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [orderer.example.com:7050]: waiting for connection failed: context deadline exceeded [recovered]
panic: Failed to submit: CreateAndSendTransaction failed: SendTransaction failed: calling orderer ‘orderer.example.com:7050’ failed: Orderer Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [orderer.example.com:7050]: waiting for connection failed: context deadline exceeded

分析:
看报错信息,好像是访问orderer节点失败,原来是服务器没有开放7050端口。

解决方法:
开放服务器端口

另一种情况也出现了类似的问题:
我在本地host文件中添加了多个服务器的域名解析,也就是同一个组织域名对应了多个ip。需要保证host文件中的ip是你要访问的链码所在服务器的ip。

12. 重新打开一个终端后,如何调用链码的函数?

方法:

PWD=‘/myFabric/fabric-samples/test-network’

export PATH=${PWD}/…/bin:$PATH

export FABRIC_CFG_PATH=${PWD}/…/config/

export CORE_PEER_TLS_ENABLED=true

export CORE_PEER_LOCALMSPID=“Org1MSP”

export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

export CORE_PEER_ADDRESS=localhost:7051

设置以上环境变量后,命令行调用链码函数即可。

13. 通过SDK查询得到的字符切片如何转换为对象?

方法:
对于表示单个对象的json串,反序列化到map[string]interface{};
对于表示对象数组的json串,反序列化到[]map[string]interface{};

//根据用户ID获取该用户的缴税记录taxes, err := utils.TaxContract.EvaluateTransaction("GetAllTaxesByUserId", userId)if err != nil {return err}var res []map[string]interface{}json.Unmarshal(taxes, &res)fmt.Println(res)