Skip to content

Commit

Permalink
FAB-11231 node sdk to handle chaincode errors
Browse files Browse the repository at this point in the history
update the node sdk to ensure it handles the new way that
chaincode errors are returned from the server side

Change-Id: Iae82ee8de969e478ca775aa9b5b18b25574ba87a
Signed-off-by: Dave Kelsey <[email protected]>
  • Loading branch information
Dave Kelsey committed Jul 19, 2018
1 parent 1cd9109 commit cfaf748
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 55 deletions.
32 changes: 23 additions & 9 deletions fabric-client/lib/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@ const Channel = class {
if (response instanceof Error) {
return Promise.reject(response);
}
else if (response.response && response.response.payload) {
else if (response.response && response.response.payload && response.response.status === 200) {
const block = _commonProto.Block.decode(response.response.payload);
const envelope = _commonProto.Envelope.decode(block.data.data[0]);
const payload = _commonProto.Payload.decode(envelope.payload);
Expand Down Expand Up @@ -2002,16 +2002,22 @@ const Channel = class {
return Promise.reject(response);
}
if (response.response) {
logger.debug('queryInstantiatedChaincodes - response status :: %d', response.response.status);
const queryTrans = _queryProto.ChaincodeQueryResponse.decode(response.response.payload);
logger.debug('queryInstantiatedChaincodes - ProcessedTransaction.chaincodeInfo.length :: %s', queryTrans.chaincodes.length);
for (let chaincode of queryTrans.chaincodes) {
logger.debug('queryInstantiatedChaincodes - name %s, version %s, path %s', chaincode.name, chaincode.version, chaincode.path);
if (response.response.status === 200) {
logger.debug('queryInstantiatedChaincodes - response status :: %d', response.response.status);
const queryTrans = _queryProto.ChaincodeQueryResponse.decode(response.response.payload);
logger.debug('queryInstantiatedChaincodes - ProcessedTransaction.chaincodeInfo.length :: %s', queryTrans.chaincodes.length);
for (let chaincode of queryTrans.chaincodes) {
logger.debug('queryInstantiatedChaincodes - name %s, version %s, path %s', chaincode.name, chaincode.version, chaincode.path);
}
return Promise.resolve(queryTrans);
} else {
if (response.response.message) {
return Promise.reject(new Error(response.response.message));
}
}
return Promise.resolve(queryTrans);
}
// no idea what we have, lets fail it and send it back
return Promise.reject(response);
return Promise.reject(new Error(response));
}
return Promise.reject(new Error('Payload results are missing from the query'));
}
Expand Down Expand Up @@ -2625,7 +2631,15 @@ const Channel = class {
results.push(response);
}
else if (response.response && response.response.payload) {
results.push(response.response.payload);
if (response.response.status === 200) {
results.push(response.response.payload);
} else {
if (response.response.message) {
results.push(new Error(response.response.message));
} else {
results.push(new Error(response));
}
}
}
else {
logger.error('queryByChaincode - unknown or missing results in query ::' + results);
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/src/github.com/example_cc/example_cc.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
return t.query(stub, args)
}

if function == "queryError" {
return t.queryError(stub, args)
}

if function == "move" {
// Deletes an entity from its state
return t.move(stub, args)
Expand Down Expand Up @@ -199,6 +203,11 @@ func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string)
return shim.Success(Avalbytes)
}

func (t *SimpleChaincode) queryError(stub shim.ChaincodeStubInterface, args []string) pb.Response {
err := fmt.Errorf("queryError: an error occurred")
return shim.Error(err.Error())
}

func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/src/github.com/example_cc1/example_cc1.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
// queries an entity state
return t.query(stub, args)
}

if function == "queryError" {
return t.queryError(stub, args)
}

if function == "move" {
// Deletes an entity from its state
return t.move(stub, args)
Expand Down Expand Up @@ -173,6 +178,11 @@ func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string)
return shim.Success(Avalbytes)
}

func (t *SimpleChaincode) queryError(stub shim.ChaincodeStubInterface, args []string) pb.Response {
err := fmt.Errorf("queryError: an error occurred")
return shim.Error(err.Error())
}

// used in SDK test code for transient data support
func (t *SimpleChaincode) testTransient(stub shim.ChaincodeStubInterface) pb.Response {
tm, err := stub.GetTransient()
Expand Down
10 changes: 9 additions & 1 deletion test/fixtures/src/node_cc/example_cc/chaincode.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ var Chaincode = class {
return this.query(stub, args);
}

if (fcn === 'queryError') {
return this.queryError(stub, args);
}

if (fcn === 'move') {
return this.move(stub, args);
}
Expand Down Expand Up @@ -178,6 +182,10 @@ var Chaincode = class {

return shim.success(Buffer.from(Aval.toString()));
}

async queryError(stub, args) {
return shim.error(new Error('queryError: an error occurred'));
}
};

shim.start(new Chaincode());
shim.start(new Chaincode());
10 changes: 9 additions & 1 deletion test/fixtures/src/node_cc/example_cc1/chaincode.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ var Chaincode = class {
return this.query(stub, args);
}

if (fcn === 'queryError') {
return this.queryError(stub, args);
}

if (fcn === 'move') {
return this.move(stub, args);
}
Expand Down Expand Up @@ -156,6 +160,10 @@ var Chaincode = class {
return shim.success(Buffer.from(Aval.toString()));
}

async queryError(stub, args) {
return shim.error(new Error('queryError: an error occurred'));
}

async testTransient(stub) {
let tm;

Expand Down Expand Up @@ -186,4 +194,4 @@ var Chaincode = class {
}
};

shim.start(new Chaincode());
shim.start(new Chaincode());
13 changes: 9 additions & 4 deletions test/integration/e2e/e2eUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -797,10 +797,15 @@ function queryChaincode(org, version, targets, fcn, args, value, chaincodeId, t,
transientMap[Object.keys(transientMap)[0]].toString(),
'Checking the result has the transientMap value returned by the chaincode');
} else {
t.equal(
response_payloads[i].toString('utf8'),
value,
'checking query results are correct that value is '+ value);
if (value instanceof Error) {
t.true((response_payloads[i] instanceof Error), 'query result should be an instance of error');
t.true(response_payloads[i].message.includes(value.message), 'error should contain the correct message: ' + value.message);
} else {
t.equal(
response_payloads[i].toString('utf8'),
value,
'checking query results are correct that value is '+ value);
}
}
}
return true;
Expand Down
4 changes: 2 additions & 2 deletions test/integration/e2e/private-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ test('\n\n***** End-to-end flow: private data *****\n\n', async (t) => {
// Pass specific peer from org2
// The corresponding private data are stored in org1 peers, but not in org2 peers, so expected result is ''
targets = ['localhost:8051'];
expectedResult = '';
expectedResult = new Error('Failed to get private state for name1');
await e2eUtils.queryChaincode('org1', 'v0', targets, fcn, args, expectedResult, chaincodeId, t);
t.pass('Got empty value from peers which did not store private data in a collection based on policy.');
t.pass('Got error object from peers which did not store private data in a collection based on policy.');

t.end();
} catch (err) {
Expand Down
46 changes: 27 additions & 19 deletions test/integration/e2e/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@ const e2eUtils = require('./e2eUtils.js');
const testUtils = require('../../unit/util');
const chaincodeId = testUtils.END2END.chaincodeId;

test('\n\n***** End-to-end flow: query chaincode *****\n\n', (t) => {
test('\n\n***** End-to-end flow: query chaincode *****\n\n', async (t) => {
const fcn = 'query';
const args = ['b'];
const expectedResult = '300';
let expectedResult = '300';
const targets = []; // empty array, meaning client will discover the peers
e2eUtils.queryChaincode('org2', 'v0', targets, fcn, args, expectedResult, chaincodeId, t)
.then((result) => {
if(result){
t.pass('Successfully query chaincode on the channel');
t.end();
}
else {
t.fail('Failed to query chaincode ');
t.end();
}
}, (err) => {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
t.end();
}).catch((err) => {
t.fail('Test failed due to unexpected reasons. ' + err.stack ? err.stack : err);
t.end();
});
try {
let result = await e2eUtils.queryChaincode('org2', 'v0', targets, fcn, args, expectedResult, chaincodeId, t);
if(result){
t.pass('Successfully query chaincode on the channel');
}
else {
t.fail('Failed to query chaincode ');
}
} catch(err) {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
}

try {
expectedResult = new Error('queryError: an error occurred');
let result = await e2eUtils.queryChaincode('org2', 'v0', targets, 'queryError', args, expectedResult, chaincodeId, t);
if(result){
t.pass('Successfully query chaincode on the channel');
}
else {
t.fail('Failed to query chaincode ');
}
} catch(err) {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
}
t.end();
});
46 changes: 27 additions & 19 deletions test/integration/nodechaincode/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@ var e2eUtils = require('../e2e/e2eUtils.js');
var testUtils = require('../../unit/util');
var chaincodeId = testUtils.NODE_END2END.chaincodeId;

test('\n\n***** Node-Chaincode End-to-end flow: query chaincode *****\n\n', (t) => {
test('\n\n***** Node-Chaincode End-to-end flow: query chaincode *****\n\n', async (t) => {
const fcn = 'query';
const args = ['b'];
const expectedResult = '300';
let expectedResult = '300';
const targets = []; // empty array, meaning client will get the peers from the channel
e2eUtils.queryChaincode('org2', 'v0', targets, fcn, args, expectedResult, chaincodeId, t)
.then((result) => {
if(result){
t.pass('Successfully query chaincode on the channel');
t.end();
}
else {
t.fail('Failed to query chaincode ');
t.end();
}
}, (err) => {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
t.end();
}).catch((err) => {
t.fail('Test failed due to unexpected reasons. ' + err.stack ? err.stack : err);
t.end();
});
try {
let result = await e2eUtils.queryChaincode('org2', 'v0', targets, fcn, args, expectedResult, chaincodeId, t);
if(result){
t.pass('Successfully query chaincode on the channel');
}
else {
t.fail('Failed to query chaincode ');
}
} catch(err) {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
}

try {
expectedResult = new Error('queryError: an error occurred');
let result = await e2eUtils.queryChaincode('org2', 'v0', targets, 'queryError', args, expectedResult, chaincodeId, t);
if(result){
t.pass('Successfully query chaincode on the channel');
}
else {
t.fail('Failed to query chaincode ');
}
} catch(err) {
t.fail('Failed to query chaincode on the channel. ' + err.stack ? err.stack : err);
}
t.end();
});

0 comments on commit cfaf748

Please sign in to comment.