From a49429553fc850caca36581bb56fbfa96d175708 Mon Sep 17 00:00:00 2001 From: cdaughtr Date: Wed, 31 May 2017 10:49:23 -0400 Subject: [PATCH] FAB-2991 Improve query interfaces - Change the queryXXX methods to default to use the first peer in the channel object's list of peers. - Add an optional target to the end of the arguments list which takes a singular Peer object. - Remove set/getPrimaryPeer methods. Change-Id: I0c7df57c1a6909cca292e993602ea78d79d5b81d Signed-off-by: cdaughtr --- fabric-client/lib/Channel.js | 106 ++++++++++++++++++----------------- test/integration/query.js | 11 ++-- test/unit/channel.js | 67 ++++++++++++++++------ 3 files changed, 108 insertions(+), 76 deletions(-) diff --git a/fabric-client/lib/Channel.js b/fabric-client/lib/Channel.js index 760e3624f2..cd84b79bda 100755 --- a/fabric-client/lib/Channel.js +++ b/fabric-client/lib/Channel.js @@ -95,7 +95,6 @@ var Channel = class { this._securityEnabled = true;//to do this._peers = []; - this._primary_peer = null; // if not set, will use the first peer on the list this._anchor_peers = []; this._orderers = []; this._kafka_brokers = []; @@ -237,45 +236,6 @@ var Channel = class { return this._peers; } - /** - * Set the primary peer - * The peer to use for doing queries. - * Peer must be a peer on this channel's peer list. - * Default: When no primary peer has been set the first peer - * on the list will be used. - * @param {Peer} peer An instance of the Peer class. - * @throws Error when peer is not on the existing peer list - */ - setPrimaryPeer(peer) { - if(peer) { - for (let i = 0; i < this._peers.length; i++) { - if (this._peers[i] === peer) { - this._primary_peer = this._peers[i]; - return; - } - } - } - throw new Error('The primary peer must be on this channel\'s peer list'); - } - - /** - * Get the primary peer - * The peer to use for doing queries. - * Default: When no primary peer has been set the first peer - * on the list will be used. - * @returns {Peer} peer An instance of the Peer class. - */ - getPrimaryPeer() { - logger.debug('getPrimaryPeer :: start'); - var result = this._primary_peer; - if(!result) { - result = this._peers[0]; - logger.info(' Primary peer was not set, using %s',result); - } - // return what we found - return result; - } - /** * Add orderer endpoint to a channel object, this is a local-only operation. * A channel instance may choose to use a single orderer node, which will broadcast @@ -811,16 +771,21 @@ var Channel = class { /** * Queries for various useful information on the state of the Channel * (height, known peers). - * This query will be made to the primary peer. + * @param {Peer} target Optional. The peer that is the target for this query. If no target + * is passed, the query will use the first peer that was added to the channel. * @returns {object} With height, currently the only useful info. */ - queryInfo() { + queryInfo(target) { logger.debug('queryInfo - start'); + var peer = this._getPeerForQuery(target); + if (peer instanceof Error) { + throw peer; + } var self = this; var userContext = this._clientContext.getUserContext(); var txId = new TransactionID(userContext); var request = { - targets: [self.getPrimaryPeer()], + targets: [peer], chaincodeId : Constants.QSCC, chainId: '', txId: txId, @@ -859,22 +824,43 @@ var Channel = class { ); } + _getPeerForQuery(target) { + if (target) { + if (Array.isArray(target)) { + return new Error('"target" parameter is an array, but should be a singular peer object'); + } + return target; + } else { + var peers = this.getPeers(); + if (peers.length < 1) { + return new Error('"target" parameter not specified and no peers are set on Channel.'); + } + return peers[0]; + } + } + /** * Queries the ledger for Block by block hash. * This query will be made to the primary peer. * @param {byte[]} block hash of the Block. + * @param {Peer} target Optional. The peer that is the target for this query. If no target + * is passed, the query will use the first peer that was added to the channel. * @returns {object} Object containing the block. */ - queryBlockByHash(blockHash) { + queryBlockByHash(blockHash, target) { logger.debug('queryBlockByHash - start'); if(!blockHash) { return Promise.reject( new Error('Blockhash bytes are required')); } + var peer = this._getPeerForQuery(target); + if (peer instanceof Error) { + throw peer; + } var self = this; var userContext = this._clientContext.getUserContext(); var txId = new TransactionID(userContext); var request = { - targets: [self.getPrimaryPeer()], + targets: [peer], chaincodeId : Constants.QSCC, chainId: '', txId: txId, @@ -919,9 +905,11 @@ var Channel = class { * Queries the ledger for Block by block number. * This query will be made to the primary peer. * @param {number} blockNumber The number which is the ID of the Block. + * @param {Peer} target Optional. The peer that is the target for this query. If no target + * is passed, the query will use the first peer that was added to the channel. * @returns {object} Object containing the block. */ - queryBlock(blockNumber) { + queryBlock(blockNumber, target) { logger.debug('queryBlock - start blockNumber %s',blockNumber); var block_number = null; if(Number.isInteger(blockNumber) && blockNumber >= 0) { @@ -929,11 +917,15 @@ var Channel = class { } else { return Promise.reject( new Error('Block number must be a postive integer')); } + var peer = this._getPeerForQuery(target); + if (peer instanceof Error) { + throw peer; + } var self = this; var userContext = self._clientContext.getUserContext(); var txId = new TransactionID(userContext); var request = { - targets: [self.getPrimaryPeer()], + targets: [peer], chaincodeId : Constants.QSCC, chainId: '', txId: txId, @@ -977,9 +969,11 @@ var Channel = class { * Queries the ledger for Transaction by number. * This query will be made to the primary peer. * @param tx_id The id of the transaction + * @param {Peer} target Optional. The peer that is the target for this query. If no target + * is passed, the query will use the first peer that was added to the channel. * @returns {object} Transaction information containing the transaction. */ - queryTransaction(tx_id) { + queryTransaction(tx_id, target) { logger.debug('queryTransaction - start transactionID %s',tx_id); var transaction_id = null; if(tx_id) { @@ -987,11 +981,15 @@ var Channel = class { } else { return Promise.reject( new Error('Missing "tx_id" parameter')); } + var peer = this._getPeerForQuery(target); + if (peer instanceof Error) { + throw peer; + } var self = this; var userContext = self._clientContext.getUserContext(); var txId = new TransactionID(userContext); var request = { - targets: [self.getPrimaryPeer()], + targets: [peer], chaincodeId : Constants.QSCC, chainId: '', txId: txId, @@ -1032,15 +1030,21 @@ var Channel = class { /** * Queries the instantiated chaincodes on this channel. + * @param {Peer} target Optional. The peer that is the target for this query. If no target + * is passed, the query will use the first peer that was added to the channel. * @returns {object} ChaincodeQueryResponse proto */ - queryInstantiatedChaincodes() { + queryInstantiatedChaincodes(target) { logger.debug('queryInstantiatedChaincodes - start'); + var peer = this._getPeerForQuery(target); + if (peer instanceof Error) { + throw peer; + } var self = this; var userContext = self._clientContext.getUserContext(); var txId = new TransactionID(userContext); var request = { - targets: [self.getPrimaryPeer()], + targets: [peer], chaincodeId : Constants.LSCC, chainId: self._name, txId: txId, diff --git a/test/integration/query.js b/test/integration/query.js index f581ae480c..d05a4a7c94 100644 --- a/test/integration/query.js +++ b/test/integration/query.js @@ -148,7 +148,6 @@ test(' ---->>>>> Query channel working <<<<<-----', function(t) { t.equal(block.header.number.toString(),'1','checking query results are correct that we got a transaction block back'); t.equal(block.data.data[0].payload.data.actions[0].payload.action.endorsements[0].endorser.Mspid,'Org1MSP','checking query results are correct that we got a transaction block back with correct endorsement MSP id'); logger.info('%j',block); - channel.setPrimaryPeer(peer0); tx_id = utils.getConfigSetting('E2E_TX_ID', 'notfound'); logger.info('getConfigSetting("E2E_TX_ID") = %s', tx_id); @@ -158,7 +157,7 @@ test(' ---->>>>> Query channel working <<<<<-----', function(t) { } else { t.pass('Got tx_id from ConfigSetting "E2E_TX_ID"'); // send query - return channel.queryTransaction(tx_id); //assumes the end-to-end has run first + return channel.queryTransaction(tx_id, peer0); //assumes the end-to-end has run first } }).then((processed_transaction) => { logger.info(' processed_transaction :: %j',processed_transaction); @@ -186,20 +185,18 @@ test(' ---->>>>> Query channel working <<<<<-----', function(t) { .rwset.reads[1].version.block_num.toString(), 'test for read set block num'); - // the "primary peer" must be a peer in the same org as the app + // the "target peer" must be a peer in the same org as the app // which in this case is "peer0" - channel.setPrimaryPeer(peer0); // send query - return channel.queryInfo(); + return channel.queryInfo(peer0); }).then((blockchainInfo) => { t.pass('got back blockchain info '); logger.info(' Channel queryInfo() returned block height='+blockchainInfo.height); logger.info(' Channel queryInfo() returned block previousBlockHash='+blockchainInfo.previousBlockHash); logger.info(' Channel queryInfo() returned block currentBlockHash='+blockchainInfo.currentBlockHash); var block_hash = blockchainInfo.currentBlockHash; - channel.setPrimaryPeer(peer0); // send query - return channel.queryBlockByHash(block_hash); + return channel.queryBlockByHash(block_hash, peer0); }).then((block) => { logger.info(' Channel queryBlockByHash() returned block number=%s',block.header.number); t.pass('got back block number '+ block.header.number); diff --git a/test/unit/channel.js b/test/unit/channel.js index 20281728d2..71f77e0596 100644 --- a/test/unit/channel.js +++ b/test/unit/channel.js @@ -107,40 +107,71 @@ test('\n\n ** Channel - method tests **\n\n', function (t) { t.end(); }); -test('\n\n ** Channel query tests', function(t) { - var peer = new Peer('grpc://localhost:7051'); - _channel.addPeer(peer); - var test_peer = new Peer('grpc://localhost:7051'); +test('\n\n ** Channel query target parameter tests', function(t) { + var msg = '"target" parameter not specified and no peers are set on Channel'; t.throws( function () { - _channel.setPrimaryPeer(test_peer); + _channel.queryBlockByHash(Buffer.from('12345')); }, - /^Error: The primary peer must be on this channel\'s peer list/, - 'Not able to set a primary peer even if has the same addresss' + /^Error: "target" parameter not specified and no peers are set on Channel./, + 'Channel tests, queryBlockByHash: "target" parameter not specified and no peers are set on Channel.' ); - t.doesNotThrow( + + t.throws( function () { - _channel.setPrimaryPeer(peer); + _channel.queryBlockByHash(Buffer.from('12345'), [new Peer('grpc://localhost:7051')]); }, - null, - 'Able to set a primary peer as long as same peer' + /^Error: "target" parameter is an array, but should be a singular peer object/, + 'Channel tests, queryBlockByHash: checking for "target" parameter is an array, but should be a singular peer object.' + ); + + t.throws( + function () { + _channel.queryBlockByHash(Buffer.from('12345'), new Peer('grpc://localhost:7051')); + }, + /^[Error: Missing userContext parameter]/, + 'Channel tests, queryBlockByHash: good target, checking for Missing userContext parameter.' ); - test_peer = new Peer('grpc://localhost:7099'); + t.throws( function () { - _channel.setPrimaryPeer(test_peer); + _channel.queryInfo([new Peer('grpc://localhost:7051')]); }, - /^Error: The primary peer must be on this channel\'s peer list/, - 'Not Able to set a primary peer when not on the list' + /^Error: "target" parameter is an array, but should be a singular peer object/, + 'Channel tests, queryInfo: checking for "target" parameter is an array, but should be a singular peer object.' ); + t.throws( function () { - _channel.setPrimaryPeer(); + _channel.queryBlock(123, [new Peer('grpc://localhost:7051')]); }, - /^Error: The primary peer must be on this channel\'s peer list/, - 'Not Able to set a primary peer to a null peer' + /^Error: "target" parameter is an array, but should be a singular peer object/, + 'Channel tests, queryBlock: checking for "target" parameter is an array, but should be a singular peer object.' ); + t.throws( + function () { + _channel.queryTransaction('abc', [new Peer('grpc://localhost:7051')]); + }, + /^Error: "target" parameter is an array, but should be a singular peer object/, + 'Channel tests, queryTransaction: checking for "target" parameter is an array, but should be a singular peer object.' + ); + + t.throws( + function () { + _channel.queryInstantiatedChaincodes([new Peer('grpc://localhost:7051')]); + }, + /^Error: "target" parameter is an array, but should be a singular peer object/, + 'Channel tests, queryInstantiatedChaincodes: checking for "target" parameter is an array, but should be a singular peer object.' + ); + + t.end(); +}); + +test('\n\n ** Channel query tests', function(t) { + var peer = new Peer('grpc://localhost:7051'); + _channel.addPeer(peer); + _channel.queryBlockByHash() .then( function(results) {