Skip to content

Commit

Permalink
Fix issue installing chaincode package
Browse files Browse the repository at this point in the history
Client.installChaincode is supposed to
support installing both from source (which
creates a chaincode package behind the scenes)
as well as installing an existing package.

The code was wrapping an existing package
as as a ChaincodeDeploymentSpec rather than
just using the package bytes directly when
invoking install.

This fixes that issue and adds a unit test
as well.

Fixes FABN-855

Change-Id: Ie8d5b7205e6248600bd80188169871d871702a9e
Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
  • Loading branch information
mastersingh24 committed Sep 1, 2018
1 parent 36710ae commit 117a00f
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 129 deletions.
66 changes: 34 additions & 32 deletions fabric-client/lib/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -985,36 +985,15 @@ const Client = class extends BaseClient {
throw new Error(error_msg);
}

const ccSpec = {
type: clientUtils.translateCCType(request.chaincodeType),
chaincode_id: {
name: request.chaincodeId,
path: request.chaincodePath,
version: request.chaincodeVersion
}
};
logger.debug(`installChaincode - ccSpec ${JSON.stringify(ccSpec)} `);

// step 2: construct the ChaincodeDeploymentSpec
const chaincodeDeploymentSpec = new _ccProto.ChaincodeDeploymentSpec();
chaincodeDeploymentSpec.setChaincodeSpec(ccSpec);

const data = await _getChaincodePackageData(request, this.isDevMode());
// DATA may or may not be present depending on devmode settings
if (data) {
chaincodeDeploymentSpec.setCodePackage(data);
logger.debug('installChaincode - found packaged data');
}
logger.debug(`installChaincode - sending deployment spec ${chaincodeDeploymentSpec} `);

const cdsBytes = await _getChaincodeDeploymentSpec(request, this.isDevMode());
// TODO add ESCC/VSCC info here ??????
const lcccSpec = {
type: ccSpec.type,
type: clientUtils.translateCCType(request.chaincodeType),
chaincode_id: {
name: Constants.LSCC
},
input: {
args: [Buffer.from('install', 'utf8'), chaincodeDeploymentSpec.toBuffer()]
args: [Buffer.from('install', 'utf8'), cdsBytes]
}
};

Expand Down Expand Up @@ -1683,15 +1662,38 @@ function readFile(path) {
});
}

// internal utility method to get the chaincodePackage data in bytes
async function _getChaincodePackageData(request, devMode) {
if (!request.chaincodePackage) {
logger.debug('_getChaincodePackageData - build package with chaincodepath %s, chaincodeType %s, devMode %s, metadataPath %s',
request.chaincodePath, request.chaincodeType, devMode, request.metadataPath);
return Packager.package(request.chaincodePath, request.chaincodeType, devMode, request.metadataPath);
} else {
logger.debug('_getChaincodePackageData - working with included chaincodePackage');
// internal utility to get the serialized deployment spec for installing chaincode
async function _getChaincodeDeploymentSpec(request, devMode) {

if (request.chaincodePackage && Buffer.isBuffer(request.chaincodePackage)) {
logger.debug('installChaincode - using included package');
return request.chaincodePackage;
} else {
return new Promise((resolve, reject) => {
return Packager.package(request.chaincodePath, request.chaincodeType, devMode)
.then((data) => {
let ccSpec = {
type: clientUtils.translateCCType(request.chaincodeType),
chaincode_id: {
name: request.chaincodeId,
path: request.chaincodePath,
version: request.chaincodeVersion
}
};
logger.debug('installChaincode - ccSpec %s ', JSON.stringify(ccSpec));
let chaincodeDeploymentSpec = new _ccProto.ChaincodeDeploymentSpec();
chaincodeDeploymentSpec.setChaincodeSpec(ccSpec);
// DATA may or may not be present depending on devmode settings
if (data) {
chaincodeDeploymentSpec.setCodePackage(data);
logger.debug('installChaincode - created new package');
}
resolve(chaincodeDeploymentSpec.toBuffer());
})
.catch((err) => {
reject(err);
});
});
}
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"elliptic": "^6.3.2",
"eslint": "^5.1.0",
"fabric-ca-client": "file:./fabric-ca-client",
"fabric-client": "file:./fabric-client",
"fabric-network": "file:./fabric-network",
"fabric-client": "file:./fabric-client",
"fabric-network": "file:./fabric-network",
"fs-extra": "^6.0.1",
"gulp": "^3.9.1",
"gulp-add-src": "^1.0.0",
Expand Down
192 changes: 98 additions & 94 deletions test/integration/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// in a happy-path scenario
'use strict';

var rewire = require('rewire');
var utils = require('fabric-client/lib/utils.js');
var logger = utils.getLogger('install');

Expand Down Expand Up @@ -51,33 +52,33 @@ test('\n\n** Test chaincode install using chaincodePath to create chaincodePacka
t.end();
}
},
(err) => {
t.fail('install reject: '+err);
t.end();
}).catch((err) => {
t.fail('install error. ' + err.stack ? err.stack : err);
t.end();
}).then (() => {
params.channelName = params.channelName+'0';
params.testDesc = params.testDesc+'0';
installChaincode(params, t)
.then((info) => {
if (info && info instanceof Error && info.message.includes('install.'+params.chaincodeVersion+' exists')) {
t.pass('passed check for exists on install again');
t.end();
} else {
t.fail('failed check for exists on install again');
t.end();
}
},
(err) => {
t.fail('install reject: '+err);
t.end();
}).catch((err) => {
t.fail('install error. ' + err.stack ? err.stack : err);
t.end();
});
});
(err) => {
t.fail('install reject: ' + err);
t.end();
}).catch((err) => {
t.fail('install error. ' + err.stack ? err.stack : err);
t.end();
}).then(() => {
params.channelName = params.channelName + '0';
params.testDesc = params.testDesc + '0';
installChaincode(params, t)
.then((info) => {
if (info && info instanceof Error && info.message.includes('install.' + params.chaincodeVersion + ' exists')) {
t.pass('passed check for exists on install again');
t.end();
} else {
t.fail('failed check for exists on install again');
t.end();
}
},
(err) => {
t.fail('install reject: ' + err);
t.end();
}).catch((err) => {
t.fail('install error. ' + err.stack ? err.stack : err);
t.end();
});
});
});

test('\n\n** Test chaincode install using chaincodePackage[byte] **\n\n', (t) => {
Expand All @@ -86,54 +87,57 @@ test('\n\n** Test chaincode install using chaincodePackage[byte] **\n\n', (t) =>
testDesc: 'using chaincodePackage',
channelName: 'test-install-package',
chaincodeId: 'install-package',
chaincodePath: testUtil.CHAINCODE_PATH+'_pkg',//not an existing path
chaincodePath: testUtil.CHAINCODE_PATH,
chaincodeVersion: testUtil.getUniqueVersion()
};

Packager.package(testUtil.CHAINCODE_PATH, null, false) //use good path here to get data
.then((data) => {
params.chaincodePackage = data;
let _getChaincodeDeploymentSpec = rewire('fabric-client/lib/Client.js').__get__('_getChaincodeDeploymentSpec');

// install from source
let p = _getChaincodeDeploymentSpec(params, false)
.then((cdsBytes) => {
params.chaincodePackage = cdsBytes;
installChaincode(params, t)
.then((info) => {
if (info === 'success') {
t.pass(params.testDesc+' - success');
t.pass(params.testDesc + ' - success');
return true;
} else {
t.fail(params.testDesc+' - '+info);
t.fail(params.testDesc + ' - ' + info);
t.end();
}
},
(err) => {
t.fail(params.testDesc+' - install reject: '+err);
t.end();
}).catch((err) => {
t.fail(params.testDesc+' - install error. ' + err.stack ? err.stack : err);
t.end();
}).then (() => {
params.channelName = params.channelName+'0';
params.testDesc = params.testDesc+'0';
installChaincode(params, t)
.then((info) => {
if (info && info instanceof Error && info.message.includes('install-package.'+params.chaincodeVersion+' exists')) {
t.pass('passed check for exists same code again');
t.end();
} else {
t.fail('failed check for exists same code again');
t.end();
}
},
(err) => {
t.fail(params.testDesc+' - install same chaincode again - reject, error');
logger.error(err.stack ? err.stack : err);
t.end();
}).catch((err) => {
t.fail(params.testDesc+' - install same chaincode again - error');
logger.error(err.stack ? err.stack : err);
t.end();
});
});
(err) => {
t.fail(params.testDesc + ' - install reject: ' + err);
t.end();
}).catch((err) => {
t.fail(params.testDesc + ' - install error. ' + err.stack ? err.stack : err);
t.end();
}).then(() => {
params.channelName = params.channelName + '0';
params.testDesc = params.testDesc + '0';
installChaincode(params, t)
.then((info) => {
if (info && info instanceof Error && info.message.includes('install-package.' + params.chaincodeVersion + ' exists')) {
t.pass('passed check for exists same code again');
t.end();
} else {
t.fail('failed check for exists same code again');
t.end();
}
},
(err) => {
t.fail(params.testDesc + ' - install same chaincode again - reject, error');
logger.error(err.stack ? err.stack : err);
t.end();
}).catch((err) => {
t.fail(params.testDesc + ' - install same chaincode again - error');
logger.error(err.stack ? err.stack : err);
t.end();
});
});
});
t.end();
});

function installChaincode(params, t) {
Expand All @@ -153,14 +157,14 @@ function installChaincode(params, t) {
t.pass('Successfully retrieved TLS certificate');
tlsInfo = enrollment;
client.setTlsClientCertAndKey(tlsInfo.certificate, tlsInfo.key);
return Client.newDefaultKeyValueStore({path: testUtil.storePathForOrg(orgName)});
return Client.newDefaultKeyValueStore({ path: testUtil.storePathForOrg(orgName) });
}).then((store) => {
client.setStateStore(store);

// get the peer org's admin required to send install chaincode requests
return testUtil.getSubmitter(client, t, true /* get peer org admin */, org);
}).then(() => {
t.pass(params.testDesc+' - Successfully enrolled user \'admin\'');
t.pass(params.testDesc + ' - Successfully enrolled user \'admin\'');

channel.addOrderer(
client.newOrderer(
Expand Down Expand Up @@ -204,38 +208,38 @@ function installChaincode(params, t) {

return client.installChaincode(request);
},
(err) => {
t.fail(params.testDesc+' - Failed to enroll user \'admin\'. ' + err);
throw new Error(params.testDesc+' - Failed to enroll user \'admin\'. ' + err);
}).then((results) => {
var proposalResponses = results[0];

//var proposal = results[1];
var all_good = true;
var error = null;
for(var i in proposalResponses) {
let one_good = false;
if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) {
one_good = true;
logger.info(params.testDesc+' - install proposal was good');
} else {
logger.error(params.testDesc+' - install proposal was bad');
error = proposalResponses[i];
(err) => {
t.fail(params.testDesc + ' - Failed to enroll user \'admin\'. ' + err);
throw new Error(params.testDesc + ' - Failed to enroll user \'admin\'. ' + err);
}).then((results) => {
var proposalResponses = results[0];

//var proposal = results[1];
var all_good = true;
var error = null;
for (var i in proposalResponses) {
let one_good = false;
if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) {
one_good = true;
logger.info(params.testDesc + ' - install proposal was good');
} else {
logger.error(params.testDesc + ' - install proposal was bad');
error = proposalResponses[i];
}
all_good = all_good & one_good;
}
all_good = all_good & one_good;
}
if (all_good) {
return 'success';
} else {
if (error) {
return error;
if (all_good) {
return 'success';
} else {
if (error) {
return error;
}
else return 'fail';
}
else return 'fail';
}
},
(err) => {
return new Error(err.stack ? err.stack : err);
});
},
(err) => {
return new Error(err.stack ? err.stack : err);
});
} catch (err) {
return Promise.reject(new Error(err.stack ? err.stack : err));
}
Expand Down
42 changes: 41 additions & 1 deletion test/unit/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test('\n\n ** Test per-call timeout support [client] **\n', (t) => {
sandbox.stub(clientUtils, 'buildProposal').returns(Buffer.from('dummyProposal'));
sandbox.stub(clientUtils, 'signProposal').returns(Buffer.from('dummyProposal'));
ClientRewired.__set__(
'_getChaincodePackageData',
'_getChaincodeDeploymentSpec',
() => {
return Promise.resolve(Buffer.from('dummyChaincodePackage'));
});
Expand Down Expand Up @@ -1120,3 +1120,43 @@ test('\n\n*** Test Client.getPeersForOrgOnChannel ***\n', (t) => {

t.end();
});


test('\n\n Test _getChaincodeDeploymentSpec ***\n', function (t) {
let ccPath = testutil.NODE_CHAINCODE_PATH;
let ccInstallRequest = {
chaincodeType: 'node',
chaincodePath: ccPath,
chaincodeId: 'example_cc',
chaincodeVersion: '1.0.0'
};
let _getChaincodeDeploymentSpec = rewire('fabric-client/lib/Client.js').__get__('_getChaincodeDeploymentSpec');

// install from source
_getChaincodeDeploymentSpec(ccInstallRequest, false)
.then((cdsBytes) => {
t.pass('Successfully got chaincode deployment spec from source');
// capture the cdsBytes for next test
return Buffer.from(cdsBytes);
})
.then((packageBytes) => {
// install using existing package
ccInstallRequest.chaincodePackage = packageBytes;
_getChaincodeDeploymentSpec(ccInstallRequest, false)
.then((cdsBytes) => {
// should get back what was passed in
if (packageBytes.equals(cdsBytes)) {
t.pass('Successfully got chaincode deployment spec from existing package');
} else {
t.fail('Failed to get correct deployment spec from existing package ' + cdsBytes.length + ' | ' + packageBytes.length);
}
})
.catch((err) => {
t.fail('Failed to get deployment spec from existing package. Error: ' + err.stack ? err.stack : err);
});
})
.catch((err) => {
t.fail('Failed to get deployment spec. Error: ' + err.stack ? err.stack : err);
});
t.end();
});

0 comments on commit 117a00f

Please sign in to comment.