Skip to content

Commit

Permalink
FAB-2991 Improve query interfaces
Browse files Browse the repository at this point in the history
- 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 <cdaughtr@us.ibm.com>
  • Loading branch information
cdaughtr committed May 31, 2017
1 parent dc1b011 commit a494295
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 76 deletions.
106 changes: 55 additions & 51 deletions fabric-client/lib/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -919,21 +905,27 @@ 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) {
block_number = blockNumber.toString();
} 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,
Expand Down Expand Up @@ -977,21 +969,27 @@ 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) {
tx_id = tx_id.toString();
} 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,
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 4 additions & 7 deletions test/integration/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
67 changes: 49 additions & 18 deletions test/unit/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit a494295

Please sign in to comment.