Skip to content

Commit 4203ea8

Browse files
committed
Check for duplicates when adding peers to the chain
Prior to this fix, it was possible to add duplicate peers to the chain. This fix now adds check to the addPeer method and throws a DuplicatePeer error if a peer with the same URL is already a member of the chain. Also added a test for adding multiple valid peers to the chain Fixes FAB-264 Change-Id: I575200325bf8e8aedc72e1f41419099689c3a6fc Signed-off-by: Gari Singh <[email protected]>
1 parent dc2d339 commit 4203ea8

File tree

2 files changed

+174
-76
lines changed

2 files changed

+174
-76
lines changed

sdk/node/src/hfc.ts

+12
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,18 @@ export class Chain {
454454
* @returns {Peer} Returns a new peer.
455455
*/
456456
addPeer(url:string, pem?:string):Peer {
457+
458+
//check to see if the peer is already part of the chain
459+
this.peers.forEach(function(peer){
460+
if (peer.getUrl()===url)
461+
{
462+
var error = new Error();
463+
error.name = "DuplicatePeer";
464+
error.message = "Peer with URL " + url + " is already a member of the chain";
465+
throw error;
466+
}
467+
})
468+
457469
let peer = new Peer(url, this, pem);
458470
this.peers.push(peer);
459471
return peer;

sdk/node/test/unit/chain-tests.js

+162-76
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ chain.addPeer("grpc://localhost:7051");
5454
// or network mode (code package built and sent to the peer).
5555
//
5656

57-
var mode = process.env['DEPLOY_MODE'];
57+
var mode = process.env['DEPLOY_MODE'];
5858
console.log("$DEPLOY_MODE: " + mode);
5959
if (mode === 'dev') {
6060
chain.setDevMode(true);
@@ -104,7 +104,7 @@ var deltaAB = "1";
104104
function getUser(name, cb) {
105105
chain.getUser(name, function (err, user) {
106106
if (err) return cb(err);
107-
if (user.isEnrolled()) return cb(null,user);
107+
if (user.isEnrolled()) return cb(null, user);
108108
// User is not enrolled yet, so perform both registration and enrollment
109109
// The chain registrar is already set inside 'Set chain registrar' test
110110
var registrationRequest = {
@@ -201,6 +201,92 @@ test('Add valid peer URLs to the chain', function (t) {
201201

202202
});
203203

204+
//
205+
// Test adding multiple peers to the chain
206+
//
207+
test('Add multiple peers to the chain', function (t) {
208+
209+
t.plan(1);
210+
211+
var chain_multiple = hfc.newChain("chain_multiple");
212+
213+
var peers = [
214+
"grpc://localhost:7051",
215+
"grpc://localhost:7052",
216+
"grpc://localhost:7053",
217+
"grpc://localhost:7054"
218+
];
219+
220+
peers.forEach(function (peer) {
221+
222+
try {
223+
chain_multiple.addPeer(peer);
224+
}
225+
catch (err) {
226+
t.fail("Failed to add multiple peers to the chain");
227+
}
228+
229+
})
230+
231+
//check to see we have the correct number of peers
232+
if (chain_multiple.getPeers().length == peers.length) {
233+
t.pass("Successfully added multiple peers to the chain(" + peers.length +
234+
" expected | " + chain_multiple.getPeers().length + " found)");
235+
236+
}
237+
else {
238+
t.fail("Failed to add multiple peers to the chain(" + peers.length +
239+
" expected | " + chain_multiple.getPeers().length + " found)");
240+
}
241+
});
242+
243+
//
244+
// Test adding duplicate peers to the chain
245+
//
246+
test('Catch duplicate peer added to chain', function (t) {
247+
248+
t.plan(2);
249+
250+
var chain_duplicate = hfc.newChain("chain_duplicate");
251+
252+
var peers = [
253+
"grpc://localhost:7051",
254+
"grpc://localhost:7052",
255+
"grpc://localhost:7053",
256+
"grpc://localhost:7051"
257+
];
258+
259+
//we have one duplicate to set the expected value
260+
var expected = peers.length - 1;
261+
262+
peers.forEach(function (peer) {
263+
264+
try {
265+
chain_duplicate.addPeer(peer);
266+
}
267+
catch (err) {
268+
if (err.name != "DuplicatePeer"){
269+
t.fail("Unexpected error " + err.toString());
270+
}
271+
else {
272+
t.pass("Expected error message 'DuplicatePeer' thrown");
273+
}
274+
}
275+
276+
})
277+
278+
//check to see we have the correct number of peers
279+
if (chain_duplicate.getPeers().length == expected) {
280+
t.pass("Duplicate peer not added to the chain(" + expected +
281+
" expected | " + chain_duplicate.getPeers().length + " found)");
282+
283+
}
284+
else {
285+
t.fail("Failed to detect duplicate peer (" + expected +
286+
" expected | " + chain_duplicate.getPeers().length + " found)");
287+
}
288+
});
289+
204290
//
205291
// Set Invalid security level and hash algorithm.
206292
//
@@ -363,35 +449,35 @@ test('Register and enroll a new user', function (t) {
363449
// the missing parameter.
364450
//
365451

366-
test('Deploy with missing chaincodeName or chaincodePath', function(t) {
367-
t.plan(1);
368-
369-
// Construct the deploy request with a missing chaincodeName/chaincodePath
370-
var deployRequest = {
371-
// Function to trigger
372-
fcn: "init",
373-
// Arguments to the initializing function
374-
args: ["a", initA, "b", initB]
375-
};
376-
377-
// Trigger the deploy transaction
378-
var deployTx = test_user_Member1.deploy(deployRequest);
379-
380-
// Print the deploy results
381-
deployTx.on('complete', function(results) {
382-
// Deploy request completed successfully
383-
console.log(util.format("deploy results: %j",results));
384-
// Set the testChaincodeID for subsequent tests
385-
testChaincodeID = results.chaincodeID;
386-
console.log("testChaincodeID:" + testChaincodeID);
387-
t.fail(util.format("Successfully deployed chaincode: request=%j, response=%j", deployRequest, results));
388-
// Exit the test script after a failure
389-
process.exit(1);
390-
});
391-
deployTx.on('error', function(err) {
392-
// Deploy request failed
393-
t.pass(util.format("Failed to deploy chaincode: request=%j, error=%j",deployRequest,err));
394-
});
452+
test('Deploy with missing chaincodeName or chaincodePath', function (t) {
453+
t.plan(1);
454+
455+
// Construct the deploy request with a missing chaincodeName/chaincodePath
456+
var deployRequest = {
457+
// Function to trigger
458+
fcn: "init",
459+
// Arguments to the initializing function
460+
args: ["a", initA, "b", initB]
461+
};
462+
463+
// Trigger the deploy transaction
464+
var deployTx = test_user_Member1.deploy(deployRequest);
465+
466+
// Print the deploy results
467+
deployTx.on('complete', function (results) {
468+
// Deploy request completed successfully
469+
console.log(util.format("deploy results: %j", results));
470+
// Set the testChaincodeID for subsequent tests
471+
testChaincodeID = results.chaincodeID;
472+
console.log("testChaincodeID:" + testChaincodeID);
473+
t.fail(util.format("Successfully deployed chaincode: request=%j, response=%j", deployRequest, results));
474+
// Exit the test script after a failure
475+
process.exit(1);
476+
});
477+
deployTx.on('error', function (err) {
478+
// Deploy request failed
479+
t.pass(util.format("Failed to deploy chaincode: request=%j, error=%j", deployRequest, err));
480+
});
395481
});
396482

397483
//
@@ -400,43 +486,43 @@ test('Deploy with missing chaincodeName or chaincodePath', function(t) {
400486
// a local directory in the user's $GOPATH.
401487
//
402488

403-
test('Deploy a chaincode by enrolled user', function(t) {
404-
t.plan(1);
405-
406-
// Construct the deploy request
407-
var deployRequest = {
408-
// Function to trigger
409-
fcn: "init",
410-
// Arguments to the initializing function
411-
args: ["a", initA, "b", initB]
412-
};
413-
414-
if (mode === 'dev') {
415-
// Name required for deploy in development mode
416-
deployRequest.chaincodeName = testChaincodeName;
417-
} else {
418-
// Path (under $GOPATH) required for deploy in network mode
419-
deployRequest.chaincodePath = testChaincodePath;
420-
}
421-
422-
// Trigger the deploy transaction
423-
var deployTx = test_user_Member1.deploy(deployRequest);
424-
425-
// Print the deploy results
426-
deployTx.on('complete', function(results) {
427-
// Deploy request completed successfully
428-
console.log(util.format("deploy results: %j",results));
429-
// Set the testChaincodeID for subsequent tests
430-
testChaincodeID = results.chaincodeID;
431-
console.log("testChaincodeID:" + testChaincodeID);
432-
t.pass(util.format("Successfully deployed chaincode: request=%j, response=%j", deployRequest, results));
433-
});
434-
deployTx.on('error', function(err) {
435-
// Deploy request failed
436-
t.fail(util.format("Failed to deploy chaincode: request=%j, error=%j",deployRequest,err));
437-
// Exit the test script after a failure
438-
process.exit(1);
439-
});
489+
test('Deploy a chaincode by enrolled user', function (t) {
490+
t.plan(1);
491+
492+
// Construct the deploy request
493+
var deployRequest = {
494+
// Function to trigger
495+
fcn: "init",
496+
// Arguments to the initializing function
497+
args: ["a", initA, "b", initB]
498+
};
499+
500+
if (mode === 'dev') {
501+
// Name required for deploy in development mode
502+
deployRequest.chaincodeName = testChaincodeName;
503+
} else {
504+
// Path (under $GOPATH) required for deploy in network mode
505+
deployRequest.chaincodePath = testChaincodePath;
506+
}
507+
508+
// Trigger the deploy transaction
509+
var deployTx = test_user_Member1.deploy(deployRequest);
510+
511+
// Print the deploy results
512+
deployTx.on('complete', function (results) {
513+
// Deploy request completed successfully
514+
console.log(util.format("deploy results: %j", results));
515+
// Set the testChaincodeID for subsequent tests
516+
testChaincodeID = results.chaincodeID;
517+
console.log("testChaincodeID:" + testChaincodeID);
518+
t.pass(util.format("Successfully deployed chaincode: request=%j, response=%j", deployRequest, results));
519+
});
520+
deployTx.on('error', function (err) {
521+
// Deploy request failed
522+
t.fail(util.format("Failed to deploy chaincode: request=%j, error=%j", deployRequest, err));
523+
// Exit the test script after a failure
524+
process.exit(1);
525+
});
440526
});
441527

442528
//
@@ -538,10 +624,10 @@ test('Query existing chaincode state by enrolled user with batch size of 100', f
538624
t.pass(util.format("Successfully queried existing chaincode state: request=%j, response=%j, value=%s", queryRequest, results, results.result.toString()));
539625
});
540626
queryTx.on('error', function (err) {
541-
// Query failed
542-
t.fail(util.format("Failed to query existing chaincode state: request=%j, error=%j", queryRequest, err));
543-
// Exit the test script after a failure
544-
process.exit(1);
627+
// Query failed
628+
t.fail(util.format("Failed to query existing chaincode state: request=%j, error=%j", queryRequest, err));
629+
// Exit the test script after a failure
630+
process.exit(1);
545631
});
546632
});
547633

@@ -576,7 +662,7 @@ test('Query non-existing chaincode state by enrolled user', function (t) {
576662
});
577663
queryTx.on('error', function (err) {
578664
// Query failed
579-
t.pass(util.format("Failed to query non-existing chaincode state: request=%j, error=%j",queryRequest,err));
665+
t.pass(util.format("Failed to query non-existing chaincode state: request=%j, error=%j", queryRequest, err));
580666
});
581667
});
582668

@@ -611,7 +697,7 @@ test('Query non-existing chaincode function by enrolled user', function (t) {
611697
});
612698
queryTx.on('error', function (err) {
613699
// Query failed
614-
t.pass(util.format("Failed to query non-existing chaincode function: request=%j, error=%j",queryRequest,err));
700+
t.pass(util.format("Failed to query non-existing chaincode function: request=%j, error=%j", queryRequest, err));
615701
});
616702
});
617703

@@ -638,7 +724,7 @@ test('Invoke with missing chaincodeID', function (t) {
638724
// Print the invoke results
639725
invokeTx.on('submitted', function (results) {
640726
// Invoke transaction submitted successfully
641-
t.fail(util.format("Successfully submitted chaincode invoke transaction: request=%j, response=%j", invokeRequest,results));
727+
t.fail(util.format("Successfully submitted chaincode invoke transaction: request=%j, response=%j", invokeRequest, results));
642728
// Exit the test script after a failure
643729
process.exit(1);
644730
});
@@ -672,7 +758,7 @@ test('Invoke a chaincode by enrolled user', function (t) {
672758
// Print the invoke results
673759
invokeTx.on('submitted', function (results) {
674760
// Invoke transaction submitted successfully
675-
t.pass(util.format("Successfully submitted chaincode invoke transaction: request=%j, response=%j", invokeRequest,results));
761+
t.pass(util.format("Successfully submitted chaincode invoke transaction: request=%j, response=%j", invokeRequest, results));
676762
});
677763
invokeTx.on('error', function (err) {
678764
// Invoke transaction submission failed

0 commit comments

Comments
 (0)