Skip to content

Commit

Permalink
Enhance the default endorsement policy
Browse files Browse the repository at this point in the history
FAB-2617
Create a more robust default endorsement policy that looks for
a single signature for any of the chain's participating orgs,
signed by a "member" of the orgs.

Uses the MSPs discovered from the config block of the chain.

Change-Id: I98be752120582a10bc3402e84d7f663385359789
Signed-off-by: Jim Zhang <[email protected]>
  • Loading branch information
jimthematrix committed Mar 5, 2017
1 parent 665fc61 commit 45a3778
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
45 changes: 29 additions & 16 deletions fabric-client/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ var Chain = class {
Buffer.from('deploy', 'utf8'),
Buffer.from('default', 'utf8'),
chaincodeDeploymentSpec.toBuffer(),
self._buildChaincodePolicy(userContext.mspImpl._id)
self._buildDefaultEndorsementPolicy()
]
}
};
Expand Down Expand Up @@ -1956,33 +1956,46 @@ var Chain = class {

// internal utility method to build chaincode policy
// FIXME: for now always construct a 'Signed By any member of an organization by mspid' policy
_buildChaincodePolicy(mspid) {
_buildDefaultEndorsementPolicy() {
// construct a list of msp principals to select from using the 'n out of' operator
var onePrn = new _mspPrProto.MSPPrincipal();
onePrn.setPrincipalClassification(_mspPrProto.MSPPrincipal.Classification.ROLE);
var msps = this.getMSPManager().getMSPs();
var principals = [], signedBys = [];
var index = 0;
for (let name in msps) {
if (msps.hasOwnProperty(name)) {
let onePrn = new _mspPrProto.MSPPrincipal();
onePrn.setPrincipalClassification(_mspPrProto.MSPPrincipal.Classification.ROLE);

var memberRole = new _mspPrProto.MSPRole();
memberRole.setRole(_mspPrProto.MSPRole.MSPRoleType.MEMBER);
memberRole.setMspIdentifier(mspid);
let memberRole = new _mspPrProto.MSPRole();
memberRole.setRole(_mspPrProto.MSPRole.MSPRoleType.MEMBER);
memberRole.setMspIdentifier(name);

onePrn.setPrincipal(memberRole.toBuffer());
onePrn.setPrincipal(memberRole.toBuffer());

// construct 'signed by msp principal at index 0'
var signedBy = new _policiesProto.SignaturePolicy();
signedBy.set('signed_by', 0);
principals.push(onePrn);

var signedBy = new _policiesProto.SignaturePolicy();
signedBy.set('signed_by', index++);
signedBys.push(signedBy);
}
}

if (principals.length === 0) {
throw new Error('Verifying MSPs not found in the chain object, make sure "intialize()" is called first.');
}

// construct 'one of one' policy
var oneOfone = new _policiesProto.SignaturePolicy.NOutOf();
oneOfone.setN(1);
oneOfone.setPolicies([signedBy]);
var oneOfAny = new _policiesProto.SignaturePolicy.NOutOf();
oneOfAny.setN(1);
oneOfAny.setPolicies(signedBys);

var noutof = new _policiesProto.SignaturePolicy();
noutof.set('n_out_of', oneOfone);
noutof.set('n_out_of', oneOfAny);

var envelope = new _policiesProto.SignaturePolicyEnvelope();
envelope.setVersion(0);
envelope.setPolicy(noutof);
envelope.setIdentities([onePrn]);
envelope.setIdentities(principals);

return envelope.toBuffer();
}
Expand Down
15 changes: 13 additions & 2 deletions test/integration/e2e/instantiate-chaincode.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ test('\n\n***** End-to-end flow: instantiate chaincode *****', (t) => {

the_user.mspImpl._id = ORGS[org].mspid;

// read the config block from the orderer for the chain
// and initialize the verify MSPs based on the participating
// organizations
return chain.initialize();
}, (err) => {

t.fail('Failed to enroll user \'admin\'. ' + err);
throw new Error('Failed to enroll user \'admin\'. ' + err);

}).then((success) => {

nonce = utils.getNonce();
tx_id = chain.buildTransactionID(nonce, the_user);

Expand All @@ -118,8 +129,8 @@ test('\n\n***** End-to-end flow: instantiate chaincode *****', (t) => {

}, (err) => {

t.fail('Failed to enroll user \'admin\'. ' + err);
throw new Error('Failed to enroll user \'admin\'. ' + err);
t.fail('Failed to initialize the chain');
throw new Error('Failed to initialize the chain');

}).then((results) => {

Expand Down
8 changes: 5 additions & 3 deletions test/integration/e2e/invoke-transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ test('\n\n***** End-to-end flow: instantiate chaincode *****', (t) => {
};
})(t, allEventhubs, t.end);

// this is a transaction, will just use org1's identity to
// submit the request
var org = 'org1';
// this is a transaction, will just use org2's identity to
// submit the request. intentionally we are using a different org
// than the one that instantiated the chaincode, although either org
// should work properly
var org = 'org2';
var client = new hfc();
var chain = client.newChain(e2e.channel);
chain.addOrderer(new Orderer(ORGS.orderer));
Expand Down
14 changes: 14 additions & 0 deletions test/unit/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,20 @@ test('\n\n ** Chain sendInstallProposal() tests **\n\n', function (t) {
);
});

test('\n\n ** Chain _buildDefaultEndorsementPolicy() tests **\n\n', function (t) {
var c = new Chain('does not matter', client);

t.throws(
() => {
c._buildDefaultEndorsementPolicy();
},
/Verifying MSPs not found in the chain object, make sure "intialize\(\)" is called first/,
'Checking that "initialize()" must be called before calling "instantiate()" that uses the endorsement policy'
);

t.end();
});

test('\n\n ** Chain sendInstantiateProposal() tests **\n\n', function (t) {
var c = new Chain('does not matter', client);
var peer = new Peer('grpc://localhost:7051');
Expand Down

0 comments on commit 45a3778

Please sign in to comment.