我理解Chaincode Invoke函数是异步的,除非达成共识,否则无法传达分类账修改的成功/失败。然而,在调用任何链码存根api之前捕获的简单验证错误怎么办?在验证失败的情况下,应该有一种方法将错误返回给调用者。否则函数的返回值有什么用。例如
func (t *MyChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
if len(args) == 0 {
return nil, errors.New("Incorrect number of arguments. Expecting greater than 0")
}
err = stub.PutState("Somevalue", args[0])
if err != nil {
return nil, err
}
return nil, nil
}
现在,如果我在调用时不传递任何参数给REST API,我仍然会得到成功的响应。
{ "jsonrpc": "2.0" "result": { "status": "OK" "message": "bf4f2e2c-ed0f-4240-aae5-1dc295515b3f" }, "id": 4 }
。仅表示事务已成功提交。它没有给出任何指示,如果链码功能完成成功或失败。
如果你使用node.js HFC客户端发送事务,它会返回一个错误消息,这是推荐的发送事务的方式。
据我所知,调用事务确实没有办法根据链码的执行返回值。更多详细信息请参阅这篇文章https://github.com/IBM-Blockchain/ibm-blockchain-issues/issues/85
然而,你能做的是在执行出错或一切按计划进行的情况下,从你的链码发出一个事件。例如:
func (t *SimpleChaincode) publish(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
...
//Execution of chaincode finished successfully
tosend := "Tx chaincode finished OK." + stub.GetTxID()
err = stub.SetEvent("evtsender", []byte(tosend))
if err != nil {
return nil, err
}
...
//transactions cannot return errors this way we have to use an event
// return nil, errors.New("No Supplement Found with the given ID")
tosend := "Error, No Supplement Found with the given ID" + suplementId + "." + stub.GetTxID()
err = stub.SetEvent("evtsender", []byte(tosend))
if err != nil {
return nil, err
}
...
在这些事件中,您可以添加事务Id。因此,在你的sdk应用程序(在使用hfc与nodejs的情况下),你包装调用事务调用在一个承诺和解决它,拒绝它取决于发出的事件。例如:
function invokeWithParams(userObj,invReq) {
var txHash="qwe";
return new Promise(function(resolve,reject){
var eh = networkConfig.chain.getEventHub();
// Trigger the invoke transaction
var invokeTx = userObj.invoke(invReq);
// Print the invoke results
invokeTx.on('submitted', function(results) {
// Invoke transaction submitted successfully
console.log(util.format("nSuccessfully submitted chaincode invoke transaction: request=%j, response=%j", invReq, results));
txHash = results.uuid;
});
invokeTx.on('complete', function(results) {
// Invoke transaction completed successfully
console.log(util.format("nSuccessfully completed chaincode invoke transaction: request=%j, response=%j", invReq, results));
// resolve(results);
// txHash = results.uuid;
});
invokeTx.on('error', function(err) {
// Invoke transaction submission failed
console.log(util.format("nFailed to submit chaincode invoke transaction: request=%j, error=%j", invReq, err));
reject(err);
});
//Listen to custom events
var regid = eh.registerChaincodeEvent(invReq.chaincodeID, "evtsender", function(event) {
console.log(util.format("Custom event received, payload: %jn", event.payload.toString()));
if(event.payload.toString().indexOf("Error") >= 0){
let uuid = event.payload.toString().split(".")[1];
eh.unregisterChaincodeEvent(regid);
if(uuid === txHash){ //resolve promise only when the current transaction has finished
eh.unregisterChaincodeEvent(regid);
reject(event.payload.toString());
}
}
if(event.payload.toString().indexOf("Tx chaincode finished OK") >= 0){
let uuid = event.payload.toString().split(".")[1];
console.log("nUUID " + uuid);
console.log("ntxHash " + txHash);
if(uuid === txHash){ //resolve promise only when the current transaction has finished
eh.unregisterChaincodeEvent(regid);
resolve(event.payload.toString());
}
}
});
});
}
无论如何,我知道这是一个远非完美的方法,但它帮助了我,所以我希望它能帮助你:)