From e2428efa5272fcb91bb6aea5c6fd3d0025f8f7f5 Mon Sep 17 00:00:00 2001 From: Bret Harrison Date: Thu, 17 Aug 2017 14:04:24 -0400 Subject: [PATCH] [FAB-5363] NodeSDK - common config part 2 Have the NodeSDK provide automatic selection of orderers and peers based on the network config and the roles assigned to the peers. Provide built-in CA access to enroll users with the CA defined in the network configuration. Provide a means to have a admin signer asigned to the client as defined in the configuration. Allows for easy access to the admin for requests that require admin authority. Change-Id: I08df1445fe535b543b42f7d82c8a407dcee49444 Signed-off-by: Bret Harrison --- build/tasks/test.js | 3 +- fabric-client/lib/Channel.js | 461 ++++++------ fabric-client/lib/Client.js | 334 ++++++--- fabric-client/lib/TransactionID.js | 37 +- fabric-client/lib/client-utils.js | 45 -- fabric-client/lib/impl/CryptoKeyStore.js | 4 +- fabric-client/lib/impl/NetworkConfig_1_0.js | 10 +- test/fixtures/channel/mychannel2.tx | Bin 0 -> 622 bytes test/fixtures/network.yaml | 18 +- test/integration/invoke.js | 2 +- test/integration/network-config.js | 480 +++++++++++++ test/unit/channel.js | 738 ++++++++------------ test/unit/client.js | 113 ++- test/unit/network-config.js | 168 +++-- test/unit/transactionid.js | 18 +- 15 files changed, 1469 insertions(+), 962 deletions(-) create mode 100644 test/fixtures/channel/mychannel2.tx create mode 100644 test/integration/network-config.js diff --git a/build/tasks/test.js b/build/tasks/test.js index 884dff180a..720ccae01d 100644 --- a/build/tasks/test.js +++ b/build/tasks/test.js @@ -96,7 +96,8 @@ gulp.task('test', ['clean-up', 'lint', 'pre-test', 'docker-ready', 'ca'], functi 'test/integration/e2e/query.js', 'test/integration/invoke.js', 'test/integration/perf/orderer.js', - 'test/integration/perf/peer.js' + 'test/integration/perf/peer.js', + 'test/integration/network-config.js' ])) .pipe(addsrc.append( 'test/unit/logger.js' // put this to the last so the debugging levels are not mixed up diff --git a/fabric-client/lib/Channel.js b/fabric-client/lib/Channel.js index 009332b7dd..0370f4981b 100755 --- a/fabric-client/lib/Channel.js +++ b/fabric-client/lib/Channel.js @@ -307,43 +307,38 @@ var Channel = class { /** * @typedef {Object} OrdererRequest - * @property {TransactionId} txId + * @property {TransactionID} txId - Optional. Object with the transaction id and nonce + * @property {Orderer} orderer - Optional. The orderer instance or string name + * of the orderer to retrieve genesis block from */ /** * A channel's first block is called the "genesis block". This block captures the * initial channel configuration. For a peer node to join the channel, it must be - * provided the genesis block. The method [joinChannel()]{@link Channel#joinChannel} - * calls this method under the covers to automate the acquisition of the genesis block - * and sending it to the target peer to join. + * provided the genesis block. This method must be called before calling + * [joinChannel()]{@link Channel#joinChannel}. * - * @param {OrdererRequest} request - A transaction ID object + * @param {OrdererRequest} request - Optional - A transaction ID object * @returns {Promise} A Promise for an encoded protobuf "Block" */ getGenesisBlock(request) { logger.debug('getGenesisBlock - start'); - var errorMsg = null; - // verify that we have an orderer configured - if(!this.getOrderers()[0]) { - errorMsg = 'Missing orderer assigned to this channel for the getGenesisBlock request'; - } - // verify that we have transaction id - else if(!request.txId) { - errorMsg = 'Missing txId input parameter with the required transaction identifier'; + if(!request) { + request = {}; } - if(errorMsg) { - logger.error('getGenesisBlock - error '+ errorMsg); - return Promise.reject(new Error(errorMsg)); + // verify that we have an orderer configured + var orderer = this._clientContext.getTargetOrderer(request.orderer, this._orderers, this._name); + var signer = null; + var tx_id = request.txId; + if(!tx_id) { + signer = this._clientContext._getSigningIdentity(true); + tx_id = new TransactionID(signer, true); + } else { + signer = this._clientContext._getSigningIdentity(tx_id.isAdmin()); } - var self = this; - var userContext = null; - var orderer = self.getOrderers()[0]; - - userContext = this._clientContext.getUserContext(); - // now build the seek info, will be used once the channel is created // to get the genesis block back // build start @@ -367,18 +362,18 @@ var Channel = class { // build the header for use with the seekInfo payload var seekInfoHeader = clientUtils.buildChannelHeader( _commonProto.HeaderType.DELIVER_SEEK_INFO, - self._name, - request.txId.getTransactionID(), - self._initial_epoch + this._name, + tx_id.getTransactionID(), + this._initial_epoch ); - var seekHeader = clientUtils.buildHeader(userContext.getIdentity(), seekInfoHeader, request.txId.getNonce()); + var seekHeader = clientUtils.buildHeader(signer, seekInfoHeader, tx_id.getNonce()); var seekPayload = new _commonProto.Payload(); seekPayload.setHeader(seekHeader); seekPayload.setData(seekInfo.toBuffer()); var seekPayloadBytes = seekPayload.toBuffer(); - let sig = userContext.getSigningIdentity().sign(seekPayloadBytes); + let sig = signer.sign(seekPayloadBytes); let signature = Buffer.from(sig); // building manually or will get protobuf errors on send @@ -418,8 +413,11 @@ var Channel = class { /** * @typedef {Object} JoinChannelRequest - * @property {Peer[]} targets - Required. An array of Peer objects that will - * be asked to join this channel + * @property {Peer[]} targets - Optional. An array of Peer objects or Peer names that will + * be asked to join this channel. When using Peer names or left + * empty (use default targets) there must be a loaded network + * configuration. + * See [loadFromConfig()]{@link Client#loadFromConfig} * @property {byte[]} block - The encoded bytes of the channel's genesis block. * See [getGenesisBlock()]{@link Channel#getGenesisBlock} method * @property {TransactionID} txId - Required. TransactionID object with the transaction id and nonce @@ -428,9 +426,7 @@ var Channel = class { /** * For a peer node to become part of a channel, it must be sent the genesis * block, as explained [here]{@link Channel#getGenesisBlock}. This method - * sends a join channel proposal to one or more endorsing peers. It automatically - * acquires the channel's genesis block from the channel object's orderer and - * includes the block in the proposal request. + * sends a join channel proposal to one or more endorsing peers. * * @param {JoinChannelRequest} request * @param {Number} timeout - A number indicating milliseconds to wait on the @@ -448,28 +444,21 @@ var Channel = class { if(!request) { errorMsg = 'Missing all required input request parameters'; } - - // verify that a Peer(s) has been selected to join this channel - else if (!request.targets) { - errorMsg = 'Missing targets input parameter with the peer objects for the join channel proposal'; - } - // verify that we have transaction id else if(!request.txId) { errorMsg = 'Missing txId input parameter with the required transaction identifier'; } - else if(!request.block) { errorMsg = 'Missing block input parameter with the required genesis block'; } if(errorMsg) { logger.error('joinChannel - error '+ errorMsg); - return Promise.reject(new Error(errorMsg)); + throw new Error(errorMsg); } - var self = this; - var userContext = this._clientContext.getUserContext(); + var targets = this._getTargets(request.targets); //no role, will get all peers + var signer = this._clientContext._getSigningIdentity(request.txId.isAdmin()); var chaincodeInput = new _ccProto.ChaincodeInput(); var args = []; args.push(Buffer.from('JoinChain', 'utf8')); @@ -493,11 +482,11 @@ var Channel = class { Constants.CSCC ); - var header = clientUtils.buildHeader(userContext.getIdentity(), channelHeader, request.txId.getNonce()); + var header = clientUtils.buildHeader(signer, channelHeader, request.txId.getNonce()); var proposal = clientUtils.buildProposal(chaincodeSpec, header); - var signed_proposal = clientUtils.signProposal(userContext.getSigningIdentity(), proposal); + var signed_proposal = clientUtils.signProposal(signer, proposal); - return clientUtils.sendPeersProposal(request.targets, signed_proposal, timeout) + return clientUtils.sendPeersProposal(targets, signed_proposal, timeout) .then( function(responses) { return Promise.resolve(responses); @@ -522,11 +511,10 @@ var Channel = class { logger.debug('getChannelConfig - start for channel %s',this._name); var self = this; - var userContext = null; - var orderer = self.getOrderers()[0]; + var orderer = this._clientContext.getTargetOrderer(null, this._orderers, this._name); - userContext = this._clientContext.getUserContext(); - var txId = new TransactionID(userContext); + var signer = this._clientContext._getSigningIdentity(); + var txId = new TransactionID(signer); // seek the latest block var seekSpecifiedStart = new _abProto.SeekNewest(); @@ -551,13 +539,13 @@ var Channel = class { self._initial_epoch ); - var seekHeader = clientUtils.buildHeader(userContext.getIdentity(), seekInfoHeader, txId.getNonce()); + var seekHeader = clientUtils.buildHeader(signer, seekInfoHeader, txId.getNonce()); var seekPayload = new _commonProto.Payload(); seekPayload.setHeader(seekHeader); seekPayload.setData(seekInfo.toBuffer()); var seekPayloadBytes = seekPayload.toBuffer(); - let sig = userContext.getSigningIdentity().sign(seekPayloadBytes); + let sig = signer.sign(seekPayloadBytes); let signature = Buffer.from(sig); // building manually or will get protobuf errors on send @@ -585,7 +573,7 @@ var Channel = class { var last_config = _commonProto.LastConfig.decode(metadata.value); logger.debug('getChannelConfig - latest block has config block of %s',last_config.index); - var txId = new TransactionID(userContext); + var txId = new TransactionID(signer); // now build the seek info to get the block called out // as the latest config block @@ -615,13 +603,13 @@ var Channel = class { self._initial_epoch ); - var seekHeader = clientUtils.buildHeader(userContext.getIdentity(), seekInfoHeader, txId.getNonce()); + var seekHeader = clientUtils.buildHeader(signer, seekInfoHeader, txId.getNonce()); var seekPayload = new _commonProto.Payload(); seekPayload.setHeader(seekHeader); seekPayload.setData(seekInfo.toBuffer()); var seekPayloadBytes = seekPayload.toBuffer(); - let sig = userContext.getSigningIdentity().sign(seekPayloadBytes); + let sig = signer.sign(seekPayloadBytes); let signature = Buffer.from(sig); // building manually or will get protobuf errors on send @@ -751,27 +739,26 @@ var Channel = class { * * @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 object. + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials should be used in making + * this call to the peer. * @returns {Promise} A Promise for a {@link BlockchainInfo} object with blockchain height, * current block hash and previous block hash. */ - queryInfo(target) { + queryInfo(target, useAdmin) { 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 targets = this._getTargetForQuery(target); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var tx_id = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.QSCC, chainId: '', - txId: txId, + txId: tx_id, + signer: signer, fcn : 'GetChainInfo', - args: [ self._name] + args: [ this._name] }; - return self.sendTransactionProposal(request) + return this.sendTransactionProposal(request) .then( function(results) { var responses = results[0]; @@ -803,102 +790,35 @@ 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]; - } - } - - /* - * utility method to decide on the target for queries that only need ledger access - */ - _getTargetForQuery(target) { - if (Array.isArray(target)) { - return new Error('"target" parameter is an array, but should be a singular peer object'); - } - - var targets = this._getTargets(target, Constants.NetworkConfig.LEDGER_QUERY_ROLE); - if(Array.isArray(targets)) { - targets = targets[0]; - } - - return targets; - } - - /* - * utility method to decide on the targets for requests - */ - _getTargets(request_targets, role) { - var targets = null; - if (request_targets) { - // first check to see if they have passed a peer or peer name - try { - targets = this._clientContext.getTargetPeers(request_targets); - } catch(err) { - return err; - } - } - // so nothing passed in - // see if we can find in the network configuration - if (!targets || targets.length < 1 ) try { - targets = this._getTargetsFromConfig(role); - } catch(err) { - return err; - } - - // nothing yet - // maybe there are peers on the channel - if (!targets || targets.length < 1 ) { - var targets = this.getPeers(); - if (this.getPeers().length < 1) { - return new Error('"targets" parameter not specified and no peers are set on Channel.'); - } else { - targets = this.getPeers(); - } - } - - return targets; - } - /** * Queries the ledger on the target peer for a Block by block hash. * * @param {byte[]} block hash of the Block in question. * @param {Peer} target - Optional. The peer to send the query to. If no target is passed, * the query is sent to the first peer that was added to the channel object. + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials should be used in making + * this call to the peer. * @returns {Promise} A Promise for a {@link Block} matching the hash, fully decoded into an object. */ - queryBlockByHash(blockHash, target) { + queryBlockByHash(blockHash, target, useAdmin) { logger.debug('queryBlockByHash - start'); if(!blockHash) { - return Promise.reject( new Error('Blockhash bytes are required')); + throw 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 targets = this._getTargetForQuery(target); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.QSCC, chainId: '', txId: txId, + signer: signer, fcn : 'GetBlockByHash', - args: [ self._name], + args: [ this._name], argbytes : blockHash }; - return self.sendTransactionProposal(request) + return this.sendTransactionProposal(request) .then( function(results) { var responses = results[0]; @@ -937,32 +857,31 @@ var Channel = class { * @param {number} blockNumber - The number of the Block in question. * @param {Peer} target - Optional. The peer to send this query to. If no target is passed, * the query is sent to the first peer that was added to the channel object. + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials should be used in making + * this call to the peer. * @returns {Promise} A Promise for a {@link Block} at the blockNumber slot in the ledger, fully decoded into an object. */ - queryBlock(blockNumber, target) { + queryBlock(blockNumber, target, useAdmin) { 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 positive integer')); - } - var peer = this._getPeerForQuery(target); - if (peer instanceof Error) { - throw peer; + throw new Error('Block number must be a positive integer'); } - var self = this; - var userContext = self._clientContext.getUserContext(); - var txId = new TransactionID(userContext); + var targets = this._getTargetForQuery(target); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.QSCC, chainId: '', txId: txId, + signer, signer, fcn : 'GetBlockByNumber', - args: [ self._name, block_number] + args: [ this._name, block_number] }; - return self.sendTransactionProposal(request) + return this.sendTransactionProposal(request) .then( function(results) { var responses = results[0]; @@ -1001,32 +920,31 @@ var Channel = class { * @param {string} tx_id - The id of the transaction * @param {Peer} target - Optional. The peer to send this query to. If no target is passed, * the query is sent to the first peer that was added to the channel object. + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials should be used in making + * this call to the peer. * @returns {Promise} A Promise for a fully decoded {@link ProcessedTransaction} object. */ - queryTransaction(tx_id, target) { + queryTransaction(tx_id, target, useAdmin) { 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; + throw new Error('Missing "tx_id" parameter'); } - var self = this; - var userContext = self._clientContext.getUserContext(); - var txId = new TransactionID(userContext); + var targets = this._getTargetForQuery(target); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.QSCC, chainId: '', txId: txId, + signer: signer, fcn : 'GetTransactionByID', - args: [ self._name, tx_id] + args: [ this._name, tx_id] }; - return self.sendTransactionProposal(request) + return this.sendTransactionProposal(request) .then( function(results) { var responses = results[0]; @@ -1063,26 +981,25 @@ var Channel = class { * * @param {Peer} target - Optional. The peer to send this query to. If no target is passed, * the query is sent to the first peer that was added to the channel object. + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials should be used in making + * this call to the peer. * @returns {Promise} A Promise for a fully decoded {@link ChaincodeQueryResponse} object. */ - queryInstantiatedChaincodes(target) { + queryInstantiatedChaincodes(target, useAdmin) { 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 targets = this._getTargetForQuery(target); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.LSCC, - chainId: self._name, + chainId: this._name, txId: txId, + signer: signer, fcn : 'getchaincodes', args: [] }; - return self.sendTransactionProposal(request) + return this.sendTransactionProposal(request) .then( function(results) { var responses = results[0]; @@ -1101,7 +1018,7 @@ var Channel = class { var queryTrans = _queryProto.ChaincodeQueryResponse.decode(response.response.payload); logger.debug('queryInstantiatedChaincodes - ProcessedTransaction.chaincodeInfo.length :: %s', queryTrans.chaincodes.length); for (let i=0; i>> name %s, version %s, path %s',queryTrans.chaincodes[i].name,queryTrans.chaincodes[i].version,queryTrans.chaincodes[i].path); + logger.debug('queryInstantiatedChaincodes - name %s, version %s, path %s',queryTrans.chaincodes[i].name,queryTrans.chaincodes[i].version,queryTrans.chaincodes[i].path); } return Promise.resolve(queryTrans); } @@ -1218,34 +1135,19 @@ var Channel = class { _sendChaincodeProposal(request, command, timeout) { var errorMsg = null; - var peers = null; - if (request) { - peers = request.targets; - } - if (!peers || peers.length < 1) { - peers = this.getPeers(); - } - // Verify that a Peer has been added - if (peers.length < 1) { - errorMsg = 'Missing peer objects in Instantiate proposal'; - logger.error('Channel.sendInstantiateProposal error '+ errorMsg); - return Promise.reject(new Error(errorMsg)); - } - //validate the incoming request if(!errorMsg) errorMsg = clientUtils.checkProposalRequest(request); if(!errorMsg) errorMsg = clientUtils.checkInstallRequest(request); - if(errorMsg) { logger.error('sendChainCodeProposal error ' + errorMsg); return Promise.reject(new Error(errorMsg)); } + var peers = this._getTargets(request.targets, Constants.ENDORSING_PEER_ROLE); // args is optional because some chaincode may not need any input parameters during initialization if (!request.args) { request.args = []; } - let self = this; // step 1: construct a ChaincodeSpec var args = []; @@ -1270,32 +1172,32 @@ var Channel = class { chaincodeDeploymentSpec.setChaincodeSpec(ccSpec); var header, proposal; - var userContext = self._clientContext.getUserContext(); + var signer = this._clientContext._getSigningIdentity(request.txId.isAdmin()); + let lcccSpec_args = [ + Buffer.from(command), + Buffer.from(this._name), + chaincodeDeploymentSpec.toBuffer() + ]; + if(request['endorsement-policy']) { + lcccSpec_args[3] = this._buildEndorsementPolicy(request['endorsement-policy']); + } + let lcccSpec = { type: _ccProto.ChaincodeSpec.Type.GOLANG, - chaincode_id: { - name: Constants.LSCC - }, - input: { - args: [ - Buffer.from(command), - Buffer.from(self._name), - chaincodeDeploymentSpec.toBuffer(), - self._buildEndorsementPolicy(request['endorsement-policy']) - ] - } + chaincode_id: { name: Constants.LSCC }, + input: { args : lcccSpec_args} }; var channelHeader = clientUtils.buildChannelHeader( _commonProto.HeaderType.ENDORSER_TRANSACTION, - self._name, + this._name, request.txId.getTransactionID(), null, Constants.LSCC ); - header = clientUtils.buildHeader(userContext.getIdentity(), channelHeader, request.txId.getNonce()); + header = clientUtils.buildHeader(signer, channelHeader, request.txId.getNonce()); proposal = clientUtils.buildProposal(lcccSpec, header, request.transientMap); - let signed_proposal = clientUtils.signProposal(userContext.getSigningIdentity(), proposal); + let signed_proposal = clientUtils.signProposal(signer, proposal); return clientUtils.sendPeersProposal(peers, signed_proposal, timeout) .then( @@ -1339,16 +1241,10 @@ var Channel = class { logger.debug('sendTransactionProposal - start'); if(!request) { - return Promise.reject(new Error('Missing request object for this transaction proposal')); - } - var targets = null; - if(request && request.targets) { - logger.debug('sendTransactionProposal - request has targets'); - } - else { - logger.debug('sendTransactionProposal - request does not have targets using this channels endorsing peers'); - request.targets = this.getPeers(); + throw new Error('Missing request object for this transaction proposal'); } + request.targets = this._getTargets(request.targets, Constants.ENDORSING_PEER_ROLE); + return Channel.sendTransactionProposal(request, this._name, this._clientContext); } @@ -1358,24 +1254,20 @@ var Channel = class { */ static sendTransactionProposal(request, channelId, clientContext, timeout) { // Verify that a Peer has been added - var errorMsg = null; + var errorMsg = clientUtils.checkProposalRequest(request); - // args is not optional because we need for transaction to execute - if (request && !request.args) { + if (errorMsg){ + // do nothing so we skip the rest of the checks + } else if (!request.args) { + // args is not optional because we need for transaction to execute errorMsg = 'Missing "args" in Transaction proposal request'; - } else { - errorMsg = clientUtils.checkProposalRequest(request); - } - - if (!request.targets || request.targets.length < 1) { + } else if (!request.targets || request.targets.length < 1) { errorMsg = 'Missing peer objects in Transaction proposal'; - logger.error('sendTransactionProposal Error:'+ errorMsg); - return Promise.reject(new Error(errorMsg)); } if(errorMsg) { logger.error('sendTransactionProposal error '+ errorMsg); - return Promise.reject(new Error(errorMsg)); + throw new Error(errorMsg); } var args = []; @@ -1405,7 +1297,12 @@ var Channel = class { }; var proposal, header; - var userContext = clientContext.getUserContext(); + var signer = null; + if(request.signer) { + signer = request.signer; + } else { + signer = clientContext._getSigningIdentity(request.txId.isAdmin()); + } var channelHeader = clientUtils.buildChannelHeader( _commonProto.HeaderType.ENDORSER_TRANSACTION, channelId, @@ -1413,9 +1310,9 @@ var Channel = class { null, request.chaincodeId ); - header = clientUtils.buildHeader(userContext.getIdentity(), channelHeader, request.txId.getNonce()); + header = clientUtils.buildHeader(signer, channelHeader, request.txId.getNonce()); proposal = clientUtils.buildProposal(invokeSpec, header, request.transientMap); - let signed_proposal = clientUtils.signProposal(userContext.getSigningIdentity(), proposal); + let signed_proposal = clientUtils.signProposal(signer, proposal); return clientUtils.sendPeersProposal(request.targets, signed_proposal, timeout) .then( @@ -1476,23 +1373,17 @@ var Channel = class { errorMsg = 'Missing "proposal" parameter in transaction request'; } } else { - errorMsg = 'Missing input request object on the proposal request'; + errorMsg = 'Missing input request object on the transaction request'; } if(errorMsg) { logger.error('sendTransaction error '+ errorMsg); - return Promise.reject(new Error(errorMsg)); + throw new Error(errorMsg); } let proposalResponses = request.proposalResponses; let chaincodeProposal = request.proposal; - // verify that we have an orderer configured - if(!this.getOrderers()) { - logger.error('sendTransaction - no orderers defined'); - return Promise.reject(new Error('no Orderer defined')); - } - var endorsements = []; let proposalResponse = proposalResponses; if(Array.isArray(proposalResponses)) { @@ -1512,7 +1403,15 @@ var Channel = class { if(endorsements.length < 1) { logger.error('sendTransaction - no valid endorsements found'); - return Promise.reject(new Error('no valid endorsements found')); + throw new Error('no valid endorsements found'); + } + + // verify that we have an orderer configured + var orderer = this._clientContext.getTargetOrderer(request.orderer, this._orderers, this._name); + + var use_admin_signer = false; + if(request.txId) { + use_admin_signer = request.txId.isAdmin(); } let header = _commonProto.Header.decode(chaincodeProposal.getHeader()); @@ -1551,9 +1450,8 @@ var Channel = class { let payload_bytes = payload.toBuffer(); - var self = this; - var userContext = this._clientContext.getUserContext(); - let sig = userContext.getSigningIdentity().sign(payload_bytes); + var signer = this._clientContext._getSigningIdentity(use_admin_signer); + let sig = signer.sign(payload_bytes); let signature = Buffer.from(sig); // building manually or will get protobuf errors on send @@ -1562,7 +1460,6 @@ var Channel = class { payload : payload_bytes }; - var orderer = self.getOrderers()[0]; return orderer.sendBroadcast(envelope); } @@ -1599,22 +1496,26 @@ var Channel = class { * } * }); */ - queryByChaincode(request) { + queryByChaincode(request, useAdmin) { logger.debug('queryByChaincodel - start'); if(!request) { - return Promise.reject(new Error('Missing request object for this queryByChaincode call.')); + throw new Error('Missing request object for this queryByChaincode call.'); } - var userContext = this._clientContext.getUserContext(); - var txId = new TransactionID(userContext); + + var targets = this._getTargets(request.targets, Constants.CHAINCODE_QUERY_ROLE); + var signer = this._clientContext._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); + // make a new request object so we can add in the txId and not change the user's var trans_request = { - targets : request.targets, + targets : targets, chaincodeId : request.chaincodeId, chainId : request.channelId, fcn : request.fcn, args : request.args, transientMap : request.transientMap, - txId : txId + txId : txId, + signer : signer }; return this.sendTransactionProposal(trans_request) @@ -1759,6 +1660,60 @@ var Channel = class { return true; } + /* + * utility method to decide on the target for queries that only need ledger access + */ + _getTargetForQuery(target) { + if (Array.isArray(target)) { + throw new Error('"target" parameter is an array, but should be a singular peer object' + + ' ' + 'or peer name according to the network configuration loaded by the client instance'); + } + var targets = this._getTargets(target, Constants.NetworkConfig.LEDGER_QUERY_ROLE, true); + // only want to query one peer + if(targets.length > 1) { + targets = [targets[0]]; + } + + return targets; + } + + /* + * utility method to decide on the targets for requests + */ + _getTargets(request_targets, role, isTarget) { + var targets = null; + if (request_targets) { + // first check to see if they have passed a peer or peer name + targets = this._clientContext.getTargetPeers(request_targets); + } + + // nothing yet, maybe there are peers on the channel + if (!targets || targets.length < 1) { + let peers = this.getPeers(); + targets = []; + for(let i in peers) { + if(peers[i].isInRole(role)){ + targets.push(peers[i]); + } + } + } + + // so nothing passed in or set on channel, let's + // see if we can find in the network configuration + if (!targets || targets.length < 1 ) { + targets = this._getTargetsFromConfig(role); + } + + if (!targets || targets.length < 1 ) { + let target_msg = 'targets'; + if(isTarget) target_msg = 'target'; + throw new Error(util.format('"%s" parameter not specified and no peers' + + ' ' + 'are set on this Channel instance' + + ' ' + 'or specfied for this channel in the network ',target_msg)); + } + + return targets; + } /* * Utility method to return a list of targets from the network configuration diff --git a/fabric-client/lib/Client.js b/fabric-client/lib/Client.js index ef53f30a1c..0b94a6844f 100644 --- a/fabric-client/lib/Client.js +++ b/fabric-client/lib/Client.js @@ -105,6 +105,9 @@ var Client = class extends BaseClient { static loadFromConfig(config) { var client = new Client(); client._network_config = _getNetworkConfig(config, client); + if(client._network_config.hasClient()) { + client._setAdminFromConfig(); + } return client; } @@ -121,6 +124,9 @@ var Client = class extends BaseClient { } else { this._network_config.mergeSettings(additional_network_config); } + if(this._network_config.hasClient()) { + this._setAdminFromConfig(); + } } /** @@ -247,6 +253,15 @@ var Client = class extends BaseClient { return event_hub; } + getEventHub(name) { + var event_hub = null; + if(this._network_config) { + event_hub = this._network_config.getEventHub(name); + } + + return event_hub; + } + /** * Returns an {@link Orderer} object with the given url and opts. An orderer object * encapsulates the properties of an orderer node and the interactions with it via @@ -270,16 +285,27 @@ var Client = class extends BaseClient { * as a coherent pair. *

* This method requires the client instance to have been assigned a userContext. + * @param {boolean} If this transactionID should be built based on the admin credentials + * Default is a non admin TransactionID * @returns {TransactionID} An object that contains a transaction id based on the * client's userContext and a randomly generated nonce value. */ - newTransactionID() { - if (typeof this._userContext === 'undefined' || this._userContext === null) { - throw new Error('This client instance must be assigned an user context'); + newTransactionID(admin) { + if(admin) { + if(typeof admin === 'boolean') { + if(admin) { + logger.debug('newTransactionID - getting an admin TransactionID'); + } else { + logger.debug('newTransactionID - getting non admin TransactionID'); + } + } else { + throw new Error('"admin" parameter must be of type boolean'); + } + } else { + admin = false; + logger.debug('newTransactionID - no admin parameter, returning non admin TransactionID'); } - let trans_id = new TransactionID(this._userContext); - - return trans_id; + return new TransactionID(this._getSigningIdentity(admin), admin); } /** @@ -342,17 +368,19 @@ var Client = class extends BaseClient { if(!(config instanceof Buffer)) { throw new Error('Channel configuration update parameter is not in the correct form.'); } - var userContext = this.getUserContext(); + // should try to use the admin signer if assigned + // then use the assigned user + var signer = this._getSigningIdentity(true); // signature is across a signature header and the config update let proto_signature_header = new _commonProto.SignatureHeader(); - proto_signature_header.setCreator(userContext.getIdentity().serialize()); + proto_signature_header.setCreator(signer.serialize()); proto_signature_header.setNonce(sdkUtils.getNonce()); var signature_header_bytes = proto_signature_header.toBuffer(); // get all the bytes to be signed together, then sign let signing_bytes = Buffer.concat([signature_header_bytes, config]); - let sig = userContext.getSigningIdentity().sign(signing_bytes); + let sig = signer.sign(signing_bytes); let signature_bytes = Buffer.from(sig); // build the return object @@ -436,48 +464,48 @@ var Client = class extends BaseClient { */ _createOrUpdateChannel(request, have_envelope) { logger.debug('_createOrUpdateChannel - start'); - var errorMsg = null; + var error_msg = null; + var orderer = null; if(!request) { - errorMsg = 'Missing all required input request parameters for initialize channel'; + error_msg = 'Missing all required input request parameters for initialize channel'; + } + // Verify that a config envelope or config has been included in the request object + else if (!request.config && !have_envelope) { + error_msg = 'Missing config request parameter containing the configuration of the channel'; + } + else if(!request.signatures && !have_envelope) { + error_msg = 'Missing signatures request parameter for the new channel'; + } + else if(!Array.isArray(request.signatures ) && !have_envelope) { + error_msg = 'Signatures request parameter must be an array of signatures'; + } + else if(!request.txId && !have_envelope) { + error_msg = 'Missing txId request parameter'; + } + // verify that we have the name of the new channel + else if(!request.name) { + error_msg = 'Missing name request parameter'; } - else { - // Verify that a config envelope or config has been included in the request object - if (!request.config && !have_envelope) { - errorMsg = 'Missing config request parameter containing the configuration of the channel'; - } - if(!request.signatures && !have_envelope) { - errorMsg = 'Missing signatures request parameter for the new channel'; - } - else if(!Array.isArray(request.signatures ) && !have_envelope) { - errorMsg = 'Signatures request parameter must be an array of signatures'; - } - if(!request.txId && !have_envelope) { - errorMsg = 'Missing txId request parameter'; - } - // verify that we have an orderer configured - if(!request.orderer) { - errorMsg = 'Missing orderer request parameter'; - } - // verify that we have the name of the new channel - if(!request.name) { - errorMsg = 'Missing name request parameter'; - } + if(error_msg) { + logger.error('_createOrUpdateChannel error %s',error_msg); + return Promise.reject(new Error(error_msg)); } - if(errorMsg) { - logger.error('_createOrUpdateChannel error %s',errorMsg); - return Promise.reject(new Error(errorMsg)); + try { + orderer = this.getTargetOrderer(request.orderer, null, request.name); + } catch (err) { + return Promise.reject(err); } var self = this; var channel_id = request.name; - var orderer = request.orderer; - var userContext = null; var channel = null; - userContext = this.getUserContext(); + // caller should have gotten a admin based TransactionID + // but maybe not, so go with whatever they have decided + var signer = this._getSigningIdentity(request.txId.isAdmin()); var signature = null; var payload = null; @@ -500,13 +528,13 @@ var Client = class extends BaseClient { request.txId.getTransactionID() ); - var proto_header = clientUtils.buildHeader(userContext.getIdentity(), proto_channel_header, request.txId.getNonce()); + var proto_header = clientUtils.buildHeader(signer, proto_channel_header, request.txId.getNonce()); var proto_payload = new _commonProto.Payload(); proto_payload.setHeader(proto_header); proto_payload.setData(proto_config_Update_envelope.toBuffer()); var payload_bytes = proto_payload.toBuffer(); - let sig = userContext.getSigningIdentity().sign(payload_bytes); + let sig = signer.sign(payload_bytes); let signature_bytes = Buffer.from(sig); signature = signature_bytes; @@ -556,20 +584,31 @@ var Client = class extends BaseClient { * Queries the target peer for the names of all the channels that a * peer has joined. * - * @param {Peer} peer - The target peer to send the query to + * @param {Peer} peer - The target peer to send the query + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials + * should be used in making this call to the peer. * @returns {Promise} A promise to return a {@link ChannelQueryResponse} */ - queryChannels(peer) { + queryChannels(peer, useAdmin) { logger.debug('queryChannels - start'); + var targets = null; if(!peer) { return Promise.reject( new Error('Peer is required')); + } else { + try { + targets = this.getTargetPeers(peer); + } catch (err) { + return Promise.reject(err); + } } var self = this; - var txId = new TransactionID(this._userContext); + var signer = this._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.CSCC, txId: txId, + signer: signer, fcn : 'GetChannels', args: [] }; @@ -632,19 +671,30 @@ var Client = class extends BaseClient { * Queries the installed chaincodes on a peer. * * @param {Peer} peer - The target peer + * @param {boolean} useAdmin - Optional. Indicates that the admin credentials + * should be used in making this call to the peer. * @returns {Promise} Promise for a {@link ChaincodeQueryResponse} object */ - queryInstalledChaincodes(peer) { + queryInstalledChaincodes(peer, useAdmin) { logger.debug('queryInstalledChaincodes - start peer %s',peer); + var targets = null; if(!peer) { return Promise.reject( new Error('Peer is required')); + } else { + try { + targets = this.getTargetPeers(peer); + } catch (err) { + return Promise.reject(err); + } } var self = this; - var txId = new TransactionID(this._userContext); + var signer = this._getSigningIdentity(useAdmin); + var txId = new TransactionID(signer, useAdmin); var request = { - targets: [peer], + targets: targets, chaincodeId : Constants.LSCC, txId: txId, + signer: signer, fcn : 'getinstalledchaincodes', args: [] }; @@ -733,29 +783,34 @@ var Client = class extends BaseClient { installChaincode(request, timeout) { logger.debug('installChaincode - start'); - var errorMsg = null; + var error_msg = null; var peers = null; if (request) { - peers = request.targets; + try { + peers = this.getTargetPeers(request.targets); + } catch (err) { + return Promise.reject(err); + } + // Verify that a Peer has been added if (peers && peers.length > 0) { logger.debug('installChaincode - found peers ::%s',peers.length); } else { - errorMsg = 'Missing peer objects in install chaincode request'; + error_msg = 'Missing peer objects in install chaincode request'; } } else { - errorMsg = 'Missing input request object on install chaincode request'; + error_msg = 'Missing input request object on install chaincode request'; } - if (!errorMsg) errorMsg = clientUtils.checkProposalRequest(request, true); - if (!errorMsg) errorMsg = clientUtils.checkInstallRequest(request); + if (!error_msg) error_msg = clientUtils.checkProposalRequest(request, true); + if (!error_msg) error_msg = clientUtils.checkInstallRequest(request); - if (errorMsg) { - logger.error('installChaincode error ' + errorMsg); - return Promise.reject(new Error(errorMsg)); + if (error_msg) { + logger.error('installChaincode error ' + error_msg); + return Promise.reject(new Error(error_msg)); } let self = this; @@ -795,19 +850,25 @@ var Client = class extends BaseClient { } }; - var header, proposal; - var userContext = self.getUserContext(); - var txId = new TransactionID(userContext); + var header, proposal, signer; + var tx_id = request.txId; + if(!tx_id) { + signer = self._getSigningIdentity(true); + tx_id = new TransactionID(signer, true); + } else { + signer = self._getSigningIdentity(tx_id.isAdmin()); + } + var channelHeader = clientUtils.buildChannelHeader( _commonProto.HeaderType.ENDORSER_TRANSACTION, '', //install does not target a channel - txId.getTransactionID(), + tx_id.getTransactionID(), null, Constants.LSCC ); - header = clientUtils.buildHeader(userContext.getIdentity(), channelHeader, txId.getNonce()); + header = clientUtils.buildHeader(signer, channelHeader, tx_id.getNonce()); proposal = clientUtils.buildProposal(lcccSpec, header); - let signed_proposal = clientUtils.signProposal(userContext.getSigningIdentity(), proposal); + let signed_proposal = clientUtils.signProposal(signer, proposal); logger.debug('installChaincode - about to sendPeersProposal'); return clientUtils.sendPeersProposal(peers, signed_proposal, timeout) .then( @@ -826,7 +887,7 @@ var Client = class extends BaseClient { * * @returns {Promise} - A promise to build a key value store and crypto store. */ - setStoresFromConfig() { + initCredentialStores() { if(this._network_config) { let client_config = this._network_config.getClientConfig(); if(client_config && client_config.credentialStore) { @@ -882,13 +943,23 @@ var Client = class extends BaseClient { this._userContext = null; } - /** - * Get the {@link SigningIdentity} object for this User's organization's admin. - * Will return the current user's SigningIdentity when the organizational admin has not been assigned to this client. - * @returns {SigningIdentity} the signing identity object that encapsulates the private key for signing + /* + * Internal utility method to get an available {@link SigningIdentity}. + * Will return a SigningIdentity of either the admin for this organization + * if one has been assigned or the SigningIdentity of the currently assigned user. + * @param admin - To indicate would prefer the admin signer + * Default is to return a non admin signer + * @returns {SigningIdentity} the signing identity object that encapsulates + * the private key for signing */ - getAdminSigningIdentity() { - if(this._adminSigningIdentity) { + _getSigningIdentity(admin) { + if(typeof admin === 'boolean') { + logger.debug('_getSigningIdentity - admin parameter is boolean :%s',admin); + } else { + admin = false; + logger.debug('_getSigningIdentity - admin parameter missing, default is false'); + } + if(admin && this._adminSigningIdentity) { return this._adminSigningIdentity; } else { if(this._userContext) { @@ -918,22 +989,23 @@ var Client = class extends BaseClient { if (typeof mspid === 'undefined' || mspid === null || mspid === '') { throw new Error('Invalid parameter. Must have a valid mspid.'); } - if(!this._cryptoSuite) { - throw new Error('A crypto suite must be assigned to this client'); + let crypto_suite = this.getCryptoSuite(); + if(!crypto_suite) { + crypto_suite = BaseClient.newCryptoSuite(); } - let key = this.getCryptoSuite().importKey(private_key, {ephemeral : true}); - var public_key = this._cryptoSuite.importKey(certificate, {ephemeral: true}); + let key = crypto_suite.importKey(private_key, {ephemeral : true}); + var public_key = crypto_suite.importKey(certificate, {ephemeral: true}); - this._adminSigningIdentity = new SigningIdentity(certificate, public_key, mspid, this._cryptoSuite, new Signer(this._cryptoSuite, key)); + this._adminSigningIdentity = new SigningIdentity(certificate, public_key, mspid, crypto_suite, new Signer(crypto_suite, key)); } - /** - * Set the admin signing identity object based on the current organization - * defined in the network configuration. A network configuration must loaded - * that defines an organization for this client and have an admin credentials - * defined. + /* + * Utility method to set the admin signing identity object based on the current + * organization defined in the network configuration. A network configuration + * be must loaded that defines an organization for this client and have an + * admin credentials defined. */ - setAdminFromConfig() { + _setAdminFromConfig() { let admin_key, admin_cert, mspid = null; if(!this._network_config) { throw new Error('No network configuration has been loaded'); @@ -948,10 +1020,9 @@ var Client = class extends BaseClient { admin_cert = organization_config.getAdminCert(); } } + // if we found all we need then set the admin if(admin_key && admin_cert && mspid) { this.setAdminSigningIdentity(admin_key, admin_cert, mspid); - } else { - throw new Error('No admin defined for the current organization'); } } /** @@ -971,9 +1042,6 @@ var Client = class extends BaseClient { if (typeof username === 'undefined' || username === null || username === '') { return Promise.reject( new Error('Missing parameter. Must have a username.')); } - if (typeof password === 'undefined' || password === null || password === '') { - return Promise.reject( new Error('Missing parameter. Must have a password.')); - } if(!this._network_config || !this._stateStore || !this._cryptoSuite ) { return Promise.reject(new Error('Client requires a network configuration loaded, stores attached, and crypto suite.')); } @@ -984,6 +1052,14 @@ var Client = class extends BaseClient { return self.getUserContext(username, true) .then((user) => { return new Promise((resolve, reject) => { + if (user && user.isEnrolled()) { + logger.debug('Successfully loaded member from persistence'); + return resolve(user); + } + + if (typeof password === 'undefined' || password === null || password === '') { + return reject( new Error('Missing parameter. Must have a password.')); + } let ca_url, tls_options, ca_name = null; let client_config = self._network_config.getClientConfig(); @@ -1004,23 +1080,18 @@ var Client = class extends BaseClient { } } - if (user && user.isEnrolled()) { - logger.debug('Successfully loaded member from persistence'); - return resolve(user); - } - - var member = new User(username); - var crypto_suite = self.getCryptoSuite(); - member.setCryptoSuite(crypto_suite); - if(!ca_url || !tls_options || !mspid) { return reject(new Error('Configuration is missing this client\'s organization and certificate authority')); } - let ca_service_class = Client.getConfigSetting('certificate-authority-software'); + let ca_service_class = Client.getConfigSetting('certificate-authority-client'); var ca_service_impl = require(ca_service_class); var ca_service = new ca_service_impl(ca_url, tls_options, ca_name, crypto_suite); + var member = new User(username); + var crypto_suite = self.getCryptoSuite(); + member.setCryptoSuite(crypto_suite); + return ca_service.enroll({ enrollmentID: username, enrollmentSecret: password @@ -1425,6 +1496,55 @@ var Client = class extends BaseClient { } }; + /* + * Utility method to get the orderer for the request + * Will find the orderer is this sequence: + * if request_orderer is an object, will check that it is an orderer + * if request_orderer is a string will look up in the network configuration the orderer by that name + * if channel_orderers is not null then this index 0 will be used + * if channel_name is not null will look up the channel to see if there is an orderer defined in the + * network configuration + * will throw an error in all cases if there is not a valid orderer to return + */ + getTargetOrderer(request_orderer, channel_orderers, channel_name) { + var method = 'getTargetOrderer'; + logger.debug('%s - start',method); + var orderer = null; + if(request_orderer) { + if(typeof request_orderer === 'string') { + if(this._network_config) { + orderer = this._network_config.getOrderer(request_orderer); + if(!orderer) { + throw new Error('Orderer name was not found in the network configuration'); + } + } + } else if(request_orderer && request_orderer.constructor && request_orderer.constructor.name === 'Orderer') { + orderer = request_orderer; + } else { + throw new Error('"orderer" request parameter is not valid. Must be an orderer name or "Orderer" object.'); + } + } else if(channel_orderers && Array.isArray(channel_orderers) && channel_orderers[0]) { + orderer = channel_orderers[0]; + } else if(channel_name && this._network_config) { + let temp_channel = this.getChannel(channel_name, false); + if(temp_channel) { + let temp_orderers = temp_channel.getOrderers(); + if(temp_orderers && temp_orderers.length > 0) { + orderer = temp_orderers[0]; + } + else { + throw new Error('"orderer" request parameter is missing and there' + ' ' + + 'are no orderers defined on this channel in the network configuration'); + } + } else { + throw new Error(util.format('Channel name %s was not found in the network configuration',channel_name)); + } + } else { + throw new Error('Missing "orderer" request parameter'); + } + + return orderer; + }; }; function readFile(path) { @@ -1493,16 +1613,20 @@ function _getNetworkConfig(config, client) { } var error_msg = null; - if(network_data && network_data.version) { - let parsing = Client.getConfigSetting('network-config-schema'); - if(parsing) { - let pieces = network_data.version.toString().split('.'); - let version = pieces[0] + '.' + pieces[1]; - if(parsing[version]) { - var NetworkConfig = require(parsing[version]); - network_config = new NetworkConfig(network_data, client); + if(network_data) { + if(network_data.version) { + let parsing = Client.getConfigSetting('network-config-schema'); + if(parsing) { + let pieces = network_data.version.toString().split('.'); + let version = pieces[0] + '.' + pieces[1]; + if(parsing[version]) { + var NetworkConfig = require(parsing[version]); + network_config = new NetworkConfig(network_data, client); + } else { + error_msg = 'network configuration has an unknown "version"'; + } } else { - error_msg = 'network configuration has an unknown "version"'; + error_msg = 'missing "network-config-schema" configuration setting'; } } else { error_msg = '"version" is missing'; diff --git a/fabric-client/lib/TransactionID.js b/fabric-client/lib/TransactionID.js index dedf1f8574..511bcdd4d6 100644 --- a/fabric-client/lib/TransactionID.js +++ b/fabric-client/lib/TransactionID.js @@ -33,24 +33,31 @@ var TransactionID = class { /** * Builds a new tranaction Id based on a user's certificate and an automatically - * generated nonce value. - * @param {User} userContext - An instance of {@link User} that provides an unique - * base for this transaction id. + * generates a nonce value. + * @param {Identity} signer_or_userContext - An instance of {@link Identity} that provides an unique + * base for this transaction id. This also may be an instance of a {@User}. + * @param {boolean} admin - Indicates that this instance will be used for administrative transactions. */ - constructor(userContext) { + constructor(signer_or_userContext, admin) { logger.debug('const - start'); - if (typeof userContext === 'undefined' || userContext === null) { - throw new Error('Missing userContext parameter'); + if (typeof signer_or_userContext === 'undefined' || signer_or_userContext === null) { + throw new Error('Missing userContext or signing identity parameter'); } - if(!(User.isInstance(userContext))) { - throw new Error('Parameter "userContext" must be an instance of the "User" class'); + var signer = null; + if((User.isInstance(signer_or_userContext))) { + signer = signer_or_userContext.getSigningIdentity(); + } else { + signer = signer_or_userContext; } + this._nonce = sdkUtils.getNonce(); //nonce is in bytes - let creator_bytes = userContext.getIdentity().serialize();//same as signatureHeader.Creator + let creator_bytes = signer.serialize();//same as signatureHeader.Creator let trans_bytes = Buffer.concat([this._nonce, creator_bytes]); let trans_hash = hashPrimitives.sha2_256(trans_bytes); this._transaction_id = Buffer.from(trans_hash).toString(); logger.debug('const - transaction_id %s',this._transaction_id); + + this._admin = admin; } /** @@ -66,7 +73,17 @@ var TransactionID = class { getNonce() { return this._nonce; } + + /** + * indicates if this transactionID was generated for an admin + */ + isAdmin() { + if(this._admin) { + return true; + } else { + return false; + } + } }; module.exports = TransactionID; - diff --git a/fabric-client/lib/client-utils.js b/fabric-client/lib/client-utils.js index f925dd870f..f3f3adbbfe 100644 --- a/fabric-client/lib/client-utils.js +++ b/fabric-client/lib/client-utils.js @@ -223,48 +223,3 @@ module.exports.buildCurrentTimestamp = function() { timestamp.setNanos((now.getTime() % 1000) * 1000000); return timestamp; }; - -/* - * Utility method to get the orderer for the request - * Will: - * if request is an object, will check that it is an orderer - * if request is a string will look up in the network configuration the orderer by that name - * if request is null will look up the channel to see if there is an orderer defined in the - * network configuration - * will throw an error in all cases if there is not a valid orderer to return - */ -module.exports.getOrderer = function(request_orderer, client, channel_name) { - var orderer = null; - if(request_orderer) { - if(typeof request_orderer === 'string') { - if(client._network_config) { - orderer = client._network_config.getOrderer(request_orderer); - if(!orderer) { - throw new Error('Orderer name was not found in the network configuration'); - } - } - } else if(request_orderer && request_orderer.constructor && request_orderer.constructor.name === 'Orderer') { - orderer = request_orderer; - } else { - throw new Error('"orderer" request parameter is not valid. Must be an orderer name or "Orderer" object.'); - } - } else { - if(client._network_config) { - let temp_channel = client.getChannel(channel_name, false); - if(temp_channel) { - let temp_orderers = temp_channel.getOrderers(); - if(temp_orderers && temp_orderers.length > 0) { - orderer = temp_orderers[0]; - } - else { - throw new Error('"orderer" request parameter is missing and there' + ' ' + - 'is no orderer defined on this channel in the network configuration'); - } - } else { - throw new Error(util.format('Channel name %s was not found in the network configuration',channel_name)); - } - } - } - - return orderer; -}; diff --git a/fabric-client/lib/impl/CryptoKeyStore.js b/fabric-client/lib/impl/CryptoKeyStore.js index 827345f53a..a5cc1146f1 100644 --- a/fabric-client/lib/impl/CryptoKeyStore.js +++ b/fabric-client/lib/impl/CryptoKeyStore.js @@ -88,7 +88,9 @@ var CryptoKeyStore = function(KVSImplClass, opts) { var superClass; if (typeof KVSImplClass !== 'function') { - superClass = require(utils.getConfigSetting('key-value-store')); + let impl_class = utils.getConfigSetting('crypto-value-store'); + if(!impl_class) impl_class = utils.getConfigSetting('key-value-store'); + superClass = require(impl_class); } else { superClass = KVSImplClass; } diff --git a/fabric-client/lib/impl/NetworkConfig_1_0.js b/fabric-client/lib/impl/NetworkConfig_1_0.js index 1dd521f60f..fb62b3e887 100644 --- a/fabric-client/lib/impl/NetworkConfig_1_0.js +++ b/fabric-client/lib/impl/NetworkConfig_1_0.js @@ -39,7 +39,7 @@ var TLS_CACERTS = 'tlsCACerts'; var ADMIN_PRIVATE_KEY = 'adminPrivateKey'; var ADMIN_CERT = 'signedCert'; var GRPC_CONNECTION_OPTIONS = 'grpcOptions'; -var HTTP_CONNECTION_OPTIONS = 'grpcOptions'; +var HTTP_CONNECTION_OPTIONS = 'httpOptions'; var URL = 'url'; var EVENT_URL = 'eventUrl'; var NAME = 'name'; @@ -93,6 +93,14 @@ var NetworkConfig_1_0 = class { } } + hasClient() { + if(this._network_config && this._network_config.client) { + return true; + } + + return false; + } + getClientConfig() { var result = {}; if(this._network_config && this._network_config.client) { diff --git a/test/fixtures/channel/mychannel2.tx b/test/fixtures/channel/mychannel2.tx new file mode 100644 index 0000000000000000000000000000000000000000..f9f9cff85858cb08f1bca9e1f2744661cd99b9bd GIT binary patch literal 622 zcma)3K~BOz6m_sd9ReX=6G@FOy3#JhmML@+7m~&$L1m$FL#ETIHlc;IHPIuOxbO(x z!XvO@?bZW$16Nik2n&hJ_x^it{(pl%C47Ug<(!h2-@e|*8!8SS`5g;G(KobHQFo3x zAqKTPu5+DG<~bhW7Nrf(p$0LUOb}g=2B8kE6V3=VDb<~(Wg3oUn(!>)CkZcPLI)0U zu{9j_ea;ep5P||lTp5&kV0|kqHEhnXAhI(4LJB&Cqv3^&7OW(ZK2lM^bV!H iY}Mfe_V7x_s-e0+e-^etPFt2B2W!e~7j2cfioO9W#;>LT literal 0 HcmV?d00001 diff --git a/test/fixtures/network.yaml b/test/fixtures/network.yaml index 46efab7a74..a429e57b7e 100644 --- a/test/fixtures/network.yaml +++ b/test/fixtures/network.yaml @@ -29,28 +29,28 @@ version: "1.0" # # The client section is SDK-specific. The sample below is for the node.js SDK # -client: +#client: # Which organization does this application instance belong to? The value must be the name of an org # defined under "organizations" - organization: Org1 + #organization: Org1 # Some SDKs support pluggable KV stores, the properties under "credentialStore" # are implementation specific - credentialStore: + #credentialStore: # [Optional]. Specific to FileKeyValueStore.js or similar implementations in other SDKs. Can be others # if using an alternative impl. For instance, CouchDBKeyValueStore.js would require an object # here for properties like url, db name, etc. - path: "/tmp/hfc-kvs" + #path: "/tmp/hfc-kvs" # [Optional]. Specific to the CryptoSuite implementation. Software-based implementations like # CryptoSuite_ECDSA_AES.js in node SDK requires a key store. PKCS#11 based implementations does # not. - cryptoStore: + #cryptoStore: # Specific to the underlying KeyValueStore that backs the crypto key store. - path: "/tmp/hfc-cvs" + #path: "/tmp/hfc-cvs" # [Optional]. Specific to Composer environment - wallet: wallet-name + #wallet: wallet-name # # [Optional]. But most apps would have this section so that channel objects can be constructed @@ -59,7 +59,7 @@ client: # channels: # name of the channel - mychannel: + mychannel2: # Required. list of orderers designated by the application to use for transactions on this # channel. This list can be a result of access control ("org1" can only access "ordererA"), or # operational decisions to share loads from applications among the orderers. The values must @@ -220,7 +220,7 @@ certificateAuthorities: ca-org2: url: https://localhost:8054 - grpcOptions: + httpOptions: verify: false tlsCACerts: path: test/fixtures/channel/crypto-config/peerOrganizations/org2.example.com/ca/org2.example.com-cert.pem diff --git a/test/integration/invoke.js b/test/integration/invoke.js index 1127eff1a4..728697cef7 100644 --- a/test/integration/invoke.js +++ b/test/integration/invoke.js @@ -180,7 +180,7 @@ function invokeChaincode(userOrg, version, t, shouldFail, peers){ return channel.initialize(); }).then((nothing) => { - tx_id = client.newTransactionID(the_user); + tx_id = client.newTransactionID(); // send proposal to endorser var request = { diff --git a/test/integration/network-config.js b/test/integration/network-config.js new file mode 100644 index 0000000000..026d3130da --- /dev/null +++ b/test/integration/network-config.js @@ -0,0 +1,480 @@ +/** + * Copyright 2017 IBM All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +var utils = require('fabric-client/lib/utils.js'); +var logger = utils.getLogger('Network Config'); + +var tape = require('tape'); +var _test = require('tape-promise'); +var test = _test(tape); + +var Client = require('fabric-client'); +var util = require('util'); +var fs = require('fs'); +var path = require('path'); +var grpc = require('grpc'); + +var testUtil = require('../unit/util.js'); + +var channel_name = 'mychannel2'; + +test('\n\n***** use the network configuration file *****\n\n', function(t) { + testUtil.resetDefaults(); + Client.setConfigSetting('request-timeout', 60000); + + // build a 'Client' instance that knows the network + // this network config does not have the client information, we will + // load that later so that we can switch this client to be in a different + // organization + var client = Client.loadFromConfig('test/fixtures/network.yaml'); + t.pass('Successfully loaded a network configuration'); + + var config = null; + var signatures = []; + var genesis_block = null; + var channel = null; + var query_tx_id = null; + var instansiate_tx_id = null; + + // lets load the client information for this organization + // the file only has the client section + client.loadFromConfig('test/fixtures/org1.yaml'); + // tell this client instance where the state and key stores are located + client.initCredentialStores() + .then((nothing) => { + t.pass('Successfully created the key value store and crypto store based on the config and network config'); + + // get the config envelope created by the configtx tool + let envelope_bytes = fs.readFileSync(path.join(__dirname, '../fixtures/channel/mychannel2.tx')); + // have the sdk get the config update object from the envelope + // the config update object is what is required to be signed by all + // participating organizations + config = client.extractChannelConfig(envelope_bytes); + t.pass('Successfully extracted the config update from the configtx envelope'); + + // sign the config by admin from org1 + var signature = client.signChannelConfig(config); + // convert signature to a storable string + // fabric-client SDK will convert any strings it finds back + // to GRPC protobuf objects during the channel create + var string_signature = signature.toBuffer().toString('hex'); + t.pass('Successfully signed config update by org1'); + // collect signature from org1 admin + signatures.push(string_signature); + + /* + * switch to organization org2 + */ + + return client.loadFromConfig('test/fixtures/org2.yaml'); + }).then((nothing) =>{ + t.pass('Successfully loaded the client configuration for org2'); + + // reset the stores to be using the ones for this organization + return client.initCredentialStores(); + }).then((nothing) =>{ + t.pass('Successfully set the stores for org2'); + + // sign the config by admin from org2 + var signature = client.signChannelConfig(config); + t.pass('Successfully signed config update for org2'); + + // collect signature from org2 admin + signatures.push(signature); + + // now we have enough signatures... + + // get an admin based transaction + let tx_id = client.newTransactionID(true); + // build up the create request + let request = { + config: config, + signatures : signatures, + name : channel_name, + orderer : 'orderer.example.com', //this assumes we have loaded a network config + txId : tx_id + }; + + // send create request to orderer + return client.createChannel(request); //logged in as org2 + }).then((result) => { + logger.debug('\n***\n completed the create \n***\n'); + + logger.debug(' response ::%j',result); + t.pass('Successfully created the channel.'); + if(result.status && result.status === 'SUCCESS') { + return sleep(5000); + } else { + t.fail('Failed to create the channel. '); + throw new Error('Failed to create the channel. '); + } + }).then((nothing) => { + t.pass('Successfully waited to make sure new channel was created.'); + + // have the client build a channel with all peers and orderers + channel = client.getChannel(channel_name); + + // get an admin based transaction + let tx_id = client.newTransactionID(true); + let request = { + txId : tx_id + }; + + return channel.getGenesisBlock(request); //admin from org2 + }).then((block) =>{ + t.pass('Successfully got the genesis block'); + genesis_block = block; + + let tx_id = client.newTransactionID(true); + let request = { + //targets: // this time we will leave blank so that we can use + // all the peers assigned to the channel ...some may fail + // if the submitter is not allowed, let's see what we get + block : genesis_block, + txId : tx_id + }; + + return channel.joinChannel(request); //admin from org2 + }).then((results) => { + logger.debug(util.format('Join Channel R E S P O N S E using default targets: %j', results)); + + // first of the results should not have good status as submitter does not have permission + if(results && results[0] && results[0].response && results[0].response.status == 200) { + t.fail(util.format('Successfully had peer in organization %s join the channel', 'org1')); + throw new Error('Should not have been able to join channel with this submitter'); + } else { + t.pass(' Submitter on "org2" Failed to have peer on org1 channel'); + } + + // second of the results should have good status + if(results && results[1] && results[1].response && results[1].response.status == 200) { + t.pass(util.format('Successfully had peer in organization %s join the channel', 'org2')); + } else { + t.fail(' Failed to join channel'); + throw new Error('Failed to join channel'); + } + + /* + * switch to organization org1 + */ + client.loadFromConfig('test/fixtures/org1.yaml'); + t.pass('Successfully loaded \'admin\' for org1'); + + return client.initCredentialStores(); + }).then((nothing) => { + t.pass('Successfully created the key value store and crypto store based on the config and network config'); + + let tx_id = client.newTransactionID(true); + let request = { + targets: ['peer0.org1.example.com'], // this does assume that we have loaded a + // network config with a peer by this name + block : genesis_block, + txId : tx_id + }; + + return channel.joinChannel(request); //logged in as org1 + }).then((results) => { + logger.debug(util.format('Join Channel R E S P O N S E for a string target: %j', results)); + + if(results && results[0] && results[0].response && results[0].response.status == 200) { + t.pass(util.format('Successfully had peer in organization %s join the channel', 'org1')); + } else { + t.fail(' Failed to join channel on org1'); + throw new Error('Failed to join channel on org1'); + } + return sleep(10000); + }).then(()=>{ + t.pass('Successfully waited for peers to join the channel'); + + process.env.GOPATH = path.join(__dirname, '../fixtures'); + let tx_id = client.newTransactionID(true); + // send proposal to endorser + var request = { + targets: ['peer0.org1.example.com'], + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v1', + chaincodePackage: '', + txId : tx_id + }; + + return client.installChaincode(request); //still logged as org1 + }).then((results) => { + if(results && results[0] && results[0][0].response && results[0][0].response.status == 200) { + t.pass('Successfully installed chain code on org1'); + } else { + t.fail(' Failed to install chaincode on org1'); + throw new Error('Failed to install chain code on org1'); + } + + /* + * switch to organization org2 + */ + + client.loadFromConfig('test/fixtures/org2.yaml'); + + return client.initCredentialStores(); + }).then((nothing) => { + t.pass('Successfully created the key value store and crypto store based on the config and network config'); + + let tx_id = client.newTransactionID(true); // be sure to get a admin transaction ID + // send proposal to endorser + var request = { + targets: ['peer0.org2.example.com'], + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v1', + chaincodePackage: '', + txId : tx_id + }; + + return client.installChaincode(request); // org2 admin is the signer + }).then((results) => { + if(results && results[0] && results[0][0].response && results[0][0].response.status == 200) { + t.pass('Successfully installed chain code on org2'); + } else { + t.fail(' Failed to install chaincode'); + throw new Error('Failed to install chain code'); + } + + /* + * I N S T A N S I A T E + */ + + let tx_id = client.newTransactionID(true); + instansiate_tx_id = tx_id; + let request = { + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v1', + args: ['a', '100', 'b', '200'], + txId: tx_id + // targets is not required, however the logged in user may not have + // admin access to all the peers defined in the network configuration + //targets: ['peer0.org1.example.com'], + }; + + return channel.sendInstantiateProposal(request); // still have org2 admin signer + }).then((results) => { + var proposalResponses = results[0]; + var proposal = results[1]; + if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) { + t.pass('Successfully sent Proposal and received ProposalResponse'); + var request = { + proposalResponses: proposalResponses, + proposal: proposal, + txId : instansiate_tx_id //required to indicate that this is an admin transaction + //orderer : not specifying, the first orderer defined in the + // network configuration for this channel will be used + }; + + return channel.sendTransaction(request); // still have org2 admin as signer + } else { + t.fail('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'); + throw new Error('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'); + } + }).then((response) => { + if (!(response instanceof Error) && response.status === 'SUCCESS') { + t.pass('Successfully sent transaction to instantiate the chaincode to the orderer.'); + return sleep(10000); // use sleep for now until the eventhub is integrated into the network config changes + } else { + t.fail('Failed to order the transaction to instantiate the chaincode. Error code: ' + response.status); + throw new Error('Failed to order the transaction to instantiate the chaincode. Error code: ' + response.status); + } + }).then((results) => { + t.pass('Successfully waited for chaincodes to startup'); + + /* + * S T A R T U S I N G + */ + return client.setUserFromConfig('admin', 'adminpw', true); + }).then((admin) => { + t.pass('Successfully enrolled user \'admin\' for org2'); + + let tx_id = client.newTransactionID(); // get a non admin transaction ID + query_tx_id = tx_id.getTransactionID(); + var request = { + chaincodeId : 'example', + fcn: 'move', + args: ['a', 'b','100'], + txId: tx_id + //targets - Letting default to all endorsing peers defined on the channel in the network configuration + }; + + return channel.sendTransactionProposal(request); //logged in as org2 user + }).then((results) => { + var proposalResponses = results[0]; + var proposal = results[1]; + var all_good = true; + for(var i in proposalResponses) { + let one_good = false; + let proposal_response = proposalResponses[i]; + if( proposal_response.response && proposal_response.response.status === 200) { + t.pass('transaction proposal has response status of good'); + one_good = true; + } else { + t.fail('transaction proposal was bad'); + } + all_good = all_good & one_good; + } + + if (!all_good) { + t.fail('Failed to send invoke Proposal or receive valid response. Response null or status is not 200. exiting...'); + throw new Error('Failed to send invoke Proposal or receive valid response. Response null or status is not 200. exiting...'); + } + var request = { + proposalResponses: proposalResponses, + proposal: proposal, + admin : true + }; + + return channel.sendTransaction(request); //logged in as org2 user + }).then((response) => { + if (!(response instanceof Error) && response.status === 'SUCCESS') { + t.pass('Successfully sent transaction to invoke the chaincode to the orderer.'); + + return sleep(3000); // use sleep until the eventhub is integrated into the network config changes + } else { + t.fail('Failed to order the transaction to invoke the chaincode. Error code: ' + response.status); + throw new Error('Failed to order the transaction to invoke the chaincode. Error code: ' + response.status); + } + }).then((results) => { + var request = { + chaincodeId : 'example', + fcn: 'query', + args: ['b'] + }; + + return channel.queryByChaincode(request); //logged in as user on org1 + }).then((response_payloads) => { + if (response_payloads) { + for(let i = 0; i < response_payloads.length; i++) { + t.equal( + response_payloads[i].toString('utf8'), + '300', + 'checking query results are correct that user b has 300 now after the move'); + } + } else { + t.fail('response_payloads is null'); + throw new Error('Failed to get response on query'); + } + + return client.queryChannels('peer0.org2.example.com'); + }).then((results) => { + logger.debug(' queryChannels ::%j',results); + let found = false; + for(let i in results.channels) { + logger.debug(' queryChannels has found %s', results.channels[i].channel_id); + if(results.channels[i].channel_id === channel_name) { + found = true; + } + } + if(found) { + t.pass('Successfully found our channel in the result list'); + } else { + t.fail('Failed to find our channel in the result list'); + } + + return client.queryInstalledChaincodes('peer0.org2.example.com', true); // use admin + }).then((results) => { + logger.debug(' queryInstalledChaincodes ::%j',results); + let found = false; + for(let i in results.chaincodes) { + logger.debug(' queryInstalledChaincodes has found %s', results.chaincodes[i].name); + if(results.chaincodes[i].name === 'example') { + found = true; + } + } + if(found) { + t.pass('Successfully found our chaincode in the result list'); + } else { + t.fail('Failed to find our chaincode in the result list'); + } + + return channel.queryBlock(1); + }).then((results) => { + logger.debug(' queryBlock ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number'); + + return channel.queryInfo(); + }).then((results) => { + logger.debug(' queryInfo ::%j',results); + t.equals(3, results.height.low, 'Should be able to find our block height'); + + return channel.queryBlockByHash(results.previousBlockHash); + }).then((results) => { + logger.debug(' queryBlockHash ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number by hash'); + + return channel.queryTransaction(query_tx_id); + }).then((results) => { + logger.debug(' queryTransaction ::%j',results); + t.equals(0, results.validationCode, 'Should be able to find our transaction validationCode'); + + return channel.queryBlock(1,'peer0.org1.example.com'); + }).then((results) => { + logger.debug(' queryBlock ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number with string peer name'); + + return channel.queryInfo('peer0.org1.example.com'); + }).then((results) => { + logger.debug(' queryInfo ::%j',results); + t.equals(3, results.height.low, 'Should be able to find our block height with string peer name'); + + return channel.queryBlockByHash(results.previousBlockHash, 'peer0.org1.example.com'); + }).then((results) => { + logger.debug(' queryBlockHash ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number by hash with string peer name'); + + return channel.queryTransaction(query_tx_id,'peer0.org1.example.com'); + }).then((results) => { + logger.debug(' queryTransaction ::%j',results); + t.equals(0, results.validationCode, 'Should be able to find our transaction validationCode with string peer name'); + + return channel.queryBlock(1,'peer0.org1.example.com', true); + }).then((results) => { + logger.debug(' queryBlock ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number by admin'); + + return channel.queryInfo('peer0.org1.example.com', true); + }).then((results) => { + logger.debug(' queryInfo ::%j',results); + t.equals(3, results.height.low, 'Should be able to find our block height by admin'); + + return channel.queryBlockByHash(results.previousBlockHash, 'peer0.org1.example.com', true); + }).then((results) => { + logger.debug(' queryBlockHash ::%j',results); + t.equals(1, results.header.number.low, 'Should be able to find our block number by hash by admin'); + + return channel.queryTransaction(query_tx_id,'peer0.org1.example.com', true); + }).then((results) => { + logger.debug(' queryTransaction ::%j',results); + t.equals(0, results.validationCode, 'Should be able to find our transaction validationCode by admin'); + + return true; + }).then((results) => { + t.end(); + }).catch((error) =>{ + logger.error('catch network config test error:: %s', error.stack ? error.stack : error); + t.fail('Test failed with '+ error); + t.end(); + }); +}); + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/test/unit/channel.js b/test/unit/channel.js index 8fa61d3eb2..5f596b46c2 100644 --- a/test/unit/channel.js +++ b/test/unit/channel.js @@ -43,18 +43,15 @@ var MSPManager = require('fabric-client/lib/msp/msp-manager.js'); var idModule = require('fabric-client/lib/msp/identity.js'); var SigningIdentity = idModule.SigningIdentity; -var _channel = null; -var channelName = 'testChannel'; -var client = new Client(); - var utils = require('fabric-client/lib/utils.js'); var logger = utils.getLogger('channel'); // Channel tests ///////////// test('\n\n ** Channel - constructor test **\n\n', function (t) { testutil.resetDefaults(); - - _channel = new Channel(channelName, client); + var channelName = 'testChannel'; + var client = new Client(); + var _channel = new Channel(channelName, client); if (_channel.getName() === channelName) t.pass('Channel constructor test: getName successful'); else t.fail('Channel constructor test: getName not successful'); @@ -79,6 +76,9 @@ test('\n\n ** Channel - constructor test **\n\n', function (t) { }); test('\n\n ** Channel - method tests **\n\n', function (t) { + var client = new Client(); + var _channel = new Channel('testChannel', client); + t.doesNotThrow( function () { var orderer = new Orderer('grpc://somehost.com:1234'); @@ -111,13 +111,23 @@ test('\n\n ** Channel - method tests **\n\n', function (t) { }); test('\n\n ** Channel query target parameter tests', function(t) { - var msg = '"target" parameter not specified and no peers are set on Channel'; + var client = new Client(); + var _channel = new Channel('testChannel', client); + + t.throws( + function () { + _channel.queryBlockByHash(); + }, + /Blockhash bytes are required/, + 'Channel tests, queryBlockByHash(): checking for Blockhash bytes are required.' + ); + t.throws( function () { _channel.queryBlockByHash(Buffer.from('12345')); }, - /^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.' + /^Error: "target" parameter not specified and no peers are set on this Channel./, + 'Channel tests, queryBlockByHash(): "target" parameter not specified and no peers are set on Channel.' ); t.throws( @@ -125,7 +135,7 @@ test('\n\n ** Channel query target parameter tests', function(t) { _channel.queryBlockByHash(Buffer.from('12345'), [new Peer('grpc://localhost:7051')]); }, /^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.' + 'Channel tests, queryBlockByHash(): checking for "target" parameter is an array, but should be a singular peer object.' ); t.throws( @@ -133,7 +143,15 @@ test('\n\n ** Channel query target parameter tests', function(t) { _channel.queryBlockByHash(Buffer.from('12345'), new Peer('grpc://localhost:7051')); }, /^[Error: Missing userContext parameter]/, - 'Channel tests, queryBlockByHash: good target, checking for Missing userContext parameter.' + 'Channel tests, queryBlockByHash(): good target, checking for Missing userContext parameter.' + ); + + t.throws( + function () { + _channel.queryInfo(); + }, + /^Error: "target" parameter not specified and no peers are set on this Channel./, + 'Channel tests, queryInfo(): "target" parameter not specified and no peers are set on Channel.' ); t.throws( @@ -144,20 +162,84 @@ test('\n\n ** Channel query target parameter tests', function(t) { 'Channel tests, queryInfo: checking for "target" parameter is an array, but should be a singular peer object.' ); + t.throws( + function () { + _channel.queryBlock(); + }, + /Block number must be a positive integer/, + 'Channel tests, queryBlock(): Block number must be a positive integer with nothing specified' + ); + + t.throws( + function () { + _channel.queryBlock('abc'); + }, + /Block number must be a positive integer/, + 'Channel tests, queryBlock(): Block number must be a positive integer with "abc" specified' + ); + + t.throws( + function () { + _channel.queryBlock(1.1); + }, + /Block number must be a positive integer/, + 'Channel tests, queryBlock(): Block number must be a positive integer with "1.1" specified' + ); + + t.throws( + function () { + _channel.queryBlock(-1); + }, + /Block number must be a positive integer/, + 'Channel tests, queryBlock(): Block number must be a positive integer with "-1" specified' + ); + + t.throws( + function () { + _channel.queryBlock(123); + }, + /^Error: "target" parameter not specified and no peers are set on this Channel./, + 'Channel tests, queryBlock(): "target" parameter not specified and no peers are set on Channel.' + ); + t.throws( function () { _channel.queryBlock(123, [new Peer('grpc://localhost:7051')]); }, /^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.' + 'Channel tests, queryBlock(): checking for "target" parameter is an array, but should be a singular peer object.' + ); + + t.throws( + function () { + _channel.queryTransaction(); + }, + /Missing "tx_id" parameter/, + 'Channel tests, queryTransaction(): checking for Missing "tx_id" parameter.' + ); + + t.throws( + function () { + _channel.queryTransaction('abc'); + }, + /"target" parameter not specified and no peers are set/, + 'Channel tests, queryTransaction(): "target" parameter not specified and no peers are set' ); 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.' + /target" parameter is an array/, + 'Channel tests, queryTransaction(): checking for "target" parameter is an array' + ); + + t.throws( + function () { + _channel.queryInstantiatedChaincodes(); + }, + /"target" parameter not specified and no peers are set/, + 'Channel tests, queryInstantiatedChaincodes(): checking for "target" parameter not specified and no peers are set' ); t.throws( @@ -165,90 +247,14 @@ test('\n\n ** Channel query target parameter tests', function(t) { _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.' + '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) { - t.fail('Error: Blockhash bytes are required'); - t.end(); - }, - function(err) { - var errMessage = 'Error: Blockhash bytes are required'; - if(err.toString() == errMessage) t.pass(errMessage); - else t.fail(errMessage); - return _channel.queryTransaction(); - } - ).then( - function(results) { - t.fail('Error: Transaction id is required'); - t.end(); - }, - function(err) { - t.pass(err); - return _channel.queryBlock('a'); - } - ).then( - function(results) { - t.fail('Error: block id must be integer'); - t.end(); - }, - function(err) { - var errMessage = 'Error: Block number must be a positive integer'; - if(err.toString() == errMessage) t.pass(errMessage); - else t.fail(errMessage); - return _channel.queryBlock(); - } - ).then( - function(results) { - t.fail('Error: block id is required'); - t.end(); - }, - function(err) { - var errMessage = 'Error: Block number must be a positive integer'; - if(err.toString() == errMessage) t.pass(errMessage); - else t.fail(errMessage); - return _channel.queryBlock(-1); - } - ).then( - function(results) { - t.fail('Error: block id must be postive integer'); - t.end(); - }, - function(err) { - var errMessage = 'Error: Block number must be a positive integer'; - if(err.toString() == errMessage) t.pass(errMessage); - else t.fail(errMessage); - return _channel.queryBlock(10.5); - } - ).then( - function(results) { - t.fail('Error: block id must be integer'); - t.end(); - }, - function(err) { - var errMessage = 'Error: Block number must be a positive integer'; - if(err.toString() == errMessage) t.pass(errMessage); - else t.fail(errMessage); - t.end(); - } - ).catch( - function(err) { - t.fail('should not have gotten the catch ' + err); - t.end(); - } - ); -}); - test('\n\n ** Channel addPeer() duplicate tests **\n\n', function (t) { + var client = new Client(); var channel_duplicate = new Channel('channel_duplicate', client); var peers = [ 'grpc://localhost:7051', @@ -287,83 +293,66 @@ test('\n\n ** Channel addPeer() duplicate tests **\n\n', function (t) { }); test('\n\n ** Channel joinChannel() tests **\n\n', function (t) { - var c = new Channel('joinChannel', client); - var orderer = new Orderer('grpc://localhost:7050'); + var client = new Client(); + var channel = new Channel('joinChannel', client); - var p1 = c.getGenesisBlock({} - ).then(function () { - t.fail('Should not have been able to resolve the promise because of orderer missing'); - }).catch(function (err) { - if (err.message.indexOf('Missing orderer') >= 0) { - t.pass('Successfully caught missing orderer error'); - } else { - t.fail('Failed to catch the missing orderer error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); + t.throws( + () => { + channel.getGenesisBlock(); + }, + /Missing "orderer" request parameter/, + 'Checking getGenesisBlock(): Missing "orderer" request parameter' + ); - c.addOrderer(orderer); + t.throws( + () => { + channel.joinChannel(); + }, + /Missing all/, + 'Checking joinChannel(): Missing all' + ); - var p2 = c.joinChannel( - ).then(function () { - t.fail('Should not have been able to resolve the promise because of missing request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing all') >= 0) { - t.pass('Successfully caught missing request error'); - } else { - t.fail('Failed to catch the missing request error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); + t.throws( + () => { + channel.joinChannel({}); + }, + /Missing txId/, + 'Checking joinChannel(): Missing txId' + ); - var p3 = c.joinChannel({} - ).then(function () { - t.fail('Should not have been able to resolve the promise because of targets request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing targets') >= 0) { - t.pass('Successfully caught missing targets request error'); - } else { - t.fail('Failed to catch the missing targets request error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); + t.throws( + () => { + channel.joinChannel({txId : 'txid'}); + }, + /Missing block input parameter/, + 'Checking joinChannel(): Missing block input parameter' + ); - var p4 = c.joinChannel({targets: 'targets'} - ).then(function () { - t.fail('Should not have been able to resolve the promise because of txId request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing txId') >= 0) { - t.pass('Successfully caught missing txId request error'); - } else { - t.fail('Failed to catch the missing txId request error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); + t.throws( + () => { + channel.joinChannel({txId : 'txid', block : 'something'}); + }, + /"targets" parameter not specified and no peers are set on this Channel/, + 'Checking joinChannel(): "targets" parameter not specified and no peers are set on this Channel' + ); - var p4a = c.getGenesisBlock({targets: 'targets'} - ).then(function () { - t.fail('Should not have been able to resolve the promise because of txId request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing txId') >= 0) { - t.pass('Successfully caught missing txId request error'); - } else { - t.fail('Failed to catch the missing txId request error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); + t.throws( + () => { + channel.joinChannel({txId : 'txid', block : 'something', targets : [{}]}); + }, + /Target peer is not a valid peer object instance/, + 'Checking joinChannel(): Target peer is not a valid peer object instance' + ); - Promise.all([p1, p2, p3, p4, p4a]) - .then( - function (data) { - t.end(); - } - ).catch( - function (err) { - t.fail('Channel joinChannel() tests, Promise.all: '); - logger.error(err.stack ? err.stack : err); - t.end(); - } + t.throws( + () => { + channel.joinChannel({txId : 'txid', block : 'something', targets : 'somename'}); + }, + /No network configuraton loaded/, + 'Checking joinChannel(): No network configuraton loaded' ); + + t.end(); }); test('\n\n** Packager tests **\n\n', function(t) { @@ -467,6 +456,7 @@ var CRAZY_SPEC = { }; test('\n\n ** Channel _buildDefaultEndorsementPolicy() tests **\n\n', function (t) { + var client = new Client(); var c = new Channel('does not matter', client); t.throws( @@ -650,181 +640,96 @@ test('\n\n ** Channel _buildDefaultEndorsementPolicy() tests **\n\n', function ( t.end(); }); -test('\n\n ** Channel sendInstantiateProposal() tests **\n\n', function (t) { - var c = new Channel('does not matter', client); +test('\n\n ** Channel sendTransactionProposal() tests **\n\n', function (t) { + var client = new Client(); + var channel = new Channel('does not matter', client); var peer = new Peer('grpc://localhost:7051'); - c.addPeer(peer); - var p1 = c.sendInstantiateProposal({ - targets: [new Peer('grpc://localhost:7051')], - chaincodePath: 'blah', - chaincodeId: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'], - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodeVersion" parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing "chaincodeVersion" parameter in the proposal request') >= 0) { - t.pass('Successfully caught missing chaincodeVersion error'); - } else { - t.fail('Failed to catch the missing chaincodeVersion error. Error: '); - logger.error(err.stack ? err.stack : err); - } - }); - - var p3 = c.sendInstantiateProposal({ - targets: [new Peer('grpc://localhost:7051')], - chaincodePath: 'blah', - chaincodeVersion: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'], - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodeId" parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing "chaincodeId" parameter in the proposal request') >= 0) { - t.pass('Successfully caught missing chaincodeId error'); - } else { - t.fail('Failed to catch the missing chaincodeId error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + channel.sendTransactionProposal({ + chaincodeId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah' + }); + }, + /"targets" parameter not specified and no peers are set on this Channel/, + 'Channel tests, sendTransactionProposal(): "targets" parameter not specified and no peers are set on this Channel' + ); - c.removePeer(peer); - var p4 = c.sendInstantiateProposal({ - chaincodePath: 'blah', - chaincodeId: 'blah', - chaincodeVersion: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'], - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "peer" objects on channel'); - }).catch(function (err) { - var msg = 'Missing peer objects in Instantiate proposal'; - if (err.message.indexOf(msg) >= 0) { - t.pass('Successfully caught error: '+msg); - } else { - t.fail('Failed to catch error: '+msg+'. Error: ' + err.stack ? err.stack : err); - } - }); + channel.addPeer(peer); - c.addPeer(peer); - var p7 = c.sendInstantiateProposal().then(function () { - t.fail('Should not have been able to resolve the promise because of missing request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing input request object on the proposal request') >= 0) { - t.pass('Successfully caught missing request error'); - } else { - t.fail('Failed to catch the missing request error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + channel.sendTransactionProposal(); + }, + /Missing request object for this transaction proposal/, + 'Channel tests, sendTransactionProposal(): Missing request object for this transaction proposal' + ); - Promise.all([p1, p3, p4, p7]) - .then( - function (data) { - t.end(); - } - ).catch( - function (err) { - t.fail('Channel sendInstantiateProposal() tests, Promise.all: '+err.stack ? err.stack : err); - t.end(); - } + t.throws( + function () { + channel.sendTransactionProposal({ + chaincodeId : 'blah', + fcn: 'invoke', + txId: 'blah' + }); + }, + /Missing "args" in Transaction/, + 'Channel tests, sendTransactionProposal(): Missing "args" in Transaction' ); -}); -test('\n\n ** Channel sendTransactionProposal() tests **\n\n', function (t) { - var c = new Channel('does not matter', client); - var peer = new Peer('grpc://localhost:7051'); - c.addPeer(peer); - - var p1 = c.sendTransactionProposal({ - chaincodeId : 'blah', - fcn: 'invoke', - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "args" parameter'); - }).catch(function (err) { - var msg = 'Missing "args" in Transaction proposal request'; - if (err.message.indexOf(msg) >= 0) { - t.pass('Successfully caught error: '+msg); - } else { - t.fail('Failed to catch error: '+msg+'. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + channel.sendTransactionProposal({ + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah' + }); + }, + /Missing "chaincodeId" parameter/, + 'Channel tests, sendTransactionProposal(): Missing "chaincodeId" parameter' + ); - var p3 = c.sendTransactionProposal({ - fcn: 'init', - args: ['a', '100', 'b', '200'], - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodeId" parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing "chaincodeId" parameter in the proposal request') >= 0) { - t.pass('Successfully caught missing chaincodeId error'); - } else { - t.fail('Failed to catch the missing chaincodeId error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + channel.sendTransactionProposal({ + chaincodeId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'] + }); + }, + /Missing "txId" parameter in the proposal request/, + 'Channel tests, sendTransactionProposal(): Missing "txId" parameter in the proposal request' + ); - c.removePeer(peer); - var p4 = c.sendTransactionProposal({ - chaincodeId: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'], - txId: 'blah' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "peer" objects on channel'); - }).catch(function (err) { - var msg = 'Missing peer objects in Transaction proposal'; - if (err.message.indexOf(msg) >= 0) { - t.pass('Successfully caught error: '+msg); - } else { - t.fail('Failed to catch error: '+msg+'. Error: ' + err.stack ? err.stack : err); - } - }); + t.end(); +}); - c.addPeer(peer); - var p5 = c.sendTransactionProposal({ - chaincodeId: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'] - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "txId" parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing "txId" parameter in the proposal request') >= 0) { - t.pass('Successfully caught missing txId error'); - } else { - t.fail('Failed to catch the missing txId error. Error: ' + err.stack ? err.stack : err); - } - }); +test('\n\n ** Channel queryByChaincode() tests **\n\n', function (t) { + var client = new Client(); + var _channel = new Channel('testChannel', client); - var p7 = c.sendTransactionProposal().then(function () { - t.fail('Should not have been able to resolve the promise because of missing request parameter'); - }).catch(function (err) { - if (err.message.indexOf('Missing request object for this transaction proposal') >= 0) { - t.pass('Successfully caught missing request error'); - } else { - t.fail('Failed to catch the missing request error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + _channel.queryByChaincode(); + }, + /Missing request object for this queryByChaincode call/, + 'Channel tests, queryByChaincode(): Missing request object for this queryByChaincode call.' + ); - Promise.all([p1, p3, p4, p5, p7]) - .then( - function (data) { - t.end(); - } - ).catch( - function (err) { - t.fail('Channel sendTransactionProposal() tests, Promise.all: '+err.stack ? err.stack : err); - t.end(); - } + t.throws( + function () { + _channel.queryByChaincode({}); + }, + /"targets" parameter not specified and no peers are set/, + 'Channel tests, queryByChaincode(): "targets" parameter not specified and no peers are set.' ); -}); -test('\n\n ** Channel queryByChaincode() tests **\n\n', function (t) { var TEST_CERT_PEM = require('./user.js').TEST_CERT_PEM; var member = new User('admin'); + var client = new Client(); // do some setup for following test utils.setConfigSetting('key-value-store', 'fabric-client/lib/impl/FileKeyValueStore.js'); @@ -843,74 +748,28 @@ test('\n\n ** Channel queryByChaincode() tests **\n\n', function (t) { var peer = client.newPeer('grpc://localhost:7051'); channel.addPeer(peer); - var p1 = channel.queryByChaincode({ - chaincodeId : 'blah', - fcn: 'invoke' - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "args" parameter in queryByChaincode'); - }).catch(function (err) { - var msg = 'Missing "args" in Transaction proposal request'; - if (err.message.indexOf(msg) >= 0 ) { - t.pass('Successfully caught error: '+msg); - } else { - t.fail('Failed to catch queryByChaincode error: '+msg+'. Error: ' + err.stack ? err.stack : err); - } - }); - - var p3 = channel.queryByChaincode({ - fcn: 'init', - args: ['a', '100', 'b', '200'] - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodeId" parameter in queryByChaincode'); - }).catch(function (err) { - if (err.message.indexOf('Missing "chaincodeId" parameter in the proposal request') >= 0) { - t.pass('Successfully caught missing chaincodeId error'); - } else { - t.fail('Failed to catch the queryByChaincode missing chaincodeId error. Error: ' + err.stack ? err.stack : err); - } - }); - - channel.removePeer(peer); - var p4 = channel.queryByChaincode({ - chaincodeId: 'blah', - fcn: 'init', - args: ['a', '100', 'b', '200'] - }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "peers" on channel in queryByChaincode'); - }).catch(function (err) { - var msg = 'Missing peer objects in Transaction proposal'; - if (err.message.indexOf(msg) >= 0) { - t.pass('Successfully caught error: '+msg); - } else { - t.fail('Failed to catch queryByChaincode error: '+msg+'. Error: ' + err.stack ? err.stack : err); - } - }); - - channel.addPeer(peer); - - var p7 = channel.queryByChaincode().then(function () { - t.fail('Should not have been able to resolve the promise because of missing request parameter in queryByChaincode'); - }).catch(function (err) { - if (err.message.indexOf('Missing request object for this queryByChaincode') >= 0) { - t.pass('Successfully caught missing request error'); - } else { - t.fail('Failed to catch the queryByChaincode missing request error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + channel.queryByChaincode({ + chaincodeId : 'blah', + fcn: 'invoke' + }); + }, + /Missing "args" in Transaction/, + 'Channel tests, queryByChaincode(): Missing "args" in Transaction' + ); - Promise.all([p1, p3, p4, p7]) - .then( - function (data) { - t.pass('all test done'); - t.end(); - } - ).catch( - function (err) { - t.fail('Channel queryByChaincode() tests, Promise.all: '); - logger.error(err.stack ? err.stack : err); - t.end(); - } + t.throws( + function () { + channel.queryByChaincode({ + fcn: 'init', + args: ['a', '100', 'b', '200'] + }); + }, + /Missing "chaincodeId" parameter/, + 'Channel tests, queryByChaincode(): Missing "chaincodeId" parameter' ); + t.end(); }).catch( function (err) { t.fail('Channel queryByChaincode() failed '); @@ -918,76 +777,47 @@ test('\n\n ** Channel queryByChaincode() tests **\n\n', function (t) { t.end(); } ); - }); test('\n\n ** Channel sendTransaction() tests **\n\n', function (t) { - let o = _channel.getOrderers(); - for (let i = 0; i < o.length; i++) { - _channel.removeOrderer(o[i]); - } - var p1 = _channel.sendTransaction() - .then(function () { - t.fail('Should not have been able to resolve the promise because of missing parameters'); - }, function (err) { - if (err.message.indexOf('Missing input request object on the proposal request') >= 0) { - t.pass('Successfully caught missing request error'); - } else { - t.fail('Failed to catch the missing request error. Error: ' + err.stack ? err.stack : err); - } - }); + var client = new Client(); + var _channel = new Channel('testChannel', client); - var p2 = _channel.sendTransaction({ - proposal: 'blah' - }) - .then(function () { - t.fail('Should not have been able to resolve the promise because of missing parameters'); - }, function (err) { - if (err.message.indexOf('Missing "proposalResponses" parameter in transaction request') >= 0) { - t.pass('Successfully caught missing proposalResponses error'); - } else { - t.fail('Failed to catch the missing proposalResponses error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + _channel.sendTransaction(); + }, + /Missing input request/, + 'Channel tests, sendTransaction: Missing request object.' + ); - var p3 = _channel.sendTransaction({ - proposalResponses: 'blah' - }) - .then(function () { - t.fail('Should not have been able to resolve the promise because of missing parameters'); - }, function (err) { - if (err.message.indexOf('Missing "proposal" parameter in transaction request') >= 0) { - t.pass('Successfully caught missing proposal error'); - } else { - t.fail('Failed to catch the missing proposal error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + _channel.sendTransaction({proposal: 'blah'}); + }, + /Missing "proposalResponses"/, + 'Channel tests, sendTransaction: Missing "proposalResponses" object.' + ); - var p4 = _channel.sendTransaction({ - proposal: 'blah', - proposalResponses: {response : { status : 500}} - }) - .then(function () { - t.fail('Should not have been able to resolve the promise because of missing endorsement'); - }, function (err) { - if (err.message.indexOf('no valid endorsements found') >= 0) { - t.pass('Successfully caught missing endorsement error'); - } else { - t.fail('Failed to catch the missing endorsement error. Error: ' + err.stack ? err.stack : err); - } - }); + t.throws( + function () { + _channel.sendTransaction({proposalResponses: 'blah'}); + }, + /Missing "proposal"/, + 'Channel tests, sendTransaction: Missing "proposal" object.' + ); - Promise.all([p1, p2, p3, p4]) - .then( - function (data) { - t.end(); - } - ).catch( - function (err) { - t.fail('Channel sendTransaction() tests, Promise.all: '+err.stack ? err.stack : err); - t.end(); - } + t.throws( + function () { + _channel.sendTransaction({ + proposal: 'blah', + proposalResponses: {response : { status : 500}} + }); + }, + /no valid endorsements found/, + 'Channel tests, sendTransaction: no valid endorsements found.' ); + t.end(); }); // @@ -998,6 +828,7 @@ test('\n\n ** Channel sendTransaction() tests **\n\n', function (t) { // process by updating the orderer URL to a different address. // test('\n\n** TEST ** orderer via channel setOrderer/getOrderer', function(t) { + var client = new Client(); // // Create and configure the test channel // @@ -1036,6 +867,11 @@ test('\n\n** TEST ** orderer via channel setOrderer/getOrderer', function(t) { t.fail('Failed to retieve the updated orderer URL from the channel'); } + for (let i = 0; i < orderers.length; i++) { + channel.removeOrderer(orderers[i]); + t.pass('Successfully removed orderer'); + } + t.end(); } catch(err2) { t.fail('Failed to update the order URL ' + err2); @@ -1056,6 +892,7 @@ test('\n\n** TEST ** orderer via channel setOrderer/getOrderer', function(t) { // Verify that an error is reported when trying to set a bad address. // test('\n\n** TEST ** orderer via channel set/get bad address', function(t) { + var client = new Client(); // // Create and configure the test channel // @@ -1084,6 +921,7 @@ test('\n\n** TEST ** orderer via channel set/get bad address', function(t) { //Verify the verify compareProposalResponseResults method. // test('\n\n** TEST ** verify compareProposalResponseResults', function(t) { + var client = new Client(); // // Create and configure the test channel // @@ -1126,6 +964,7 @@ test('\n\n** TEST ** verify compareProposalResponseResults', function(t) { //Verify the verify verifyProposalResponse method. // test('\n\n** TEST ** verify verifyProposalResponse', function(t) { + var client = new Client(); // // Create and configure the test channel // @@ -1166,6 +1005,7 @@ test('\n\n** TEST ** verify verifyProposalResponse', function(t) { }); test('\n\n*** Test per-call timeout support ***\n', function(t) { + var client = new Client(); let sandbox = sinon.sandbox.create(); let stub = sandbox.stub(Peer.prototype, 'sendProposal'); sandbox.stub(Policy, 'buildPolicy').returns(Buffer.from('dummyPolicy')); @@ -1192,6 +1032,7 @@ test('\n\n*** Test per-call timeout support ***\n', function(t) { args: ['a', '100', 'b', '200'], txId: { getTransactionID: function() { return '1234567'; }, + isAdmin: function() { return false;}, getNonce: function() { return Buffer.from('dummyNonce'); } } }, 12345).then(function () { t.equal(stub.calledTwice, true, 'Peer.sendProposal() is called exactly twice'); @@ -1207,4 +1048,3 @@ test('\n\n*** Test per-call timeout support ***\n', function(t) { t.end(); }); }); - diff --git a/test/unit/client.js b/test/unit/client.js index 55925b9887..f894a7d43a 100644 --- a/test/unit/client.js +++ b/test/unit/client.js @@ -30,6 +30,7 @@ var Client = require('fabric-client'); var utils = require('fabric-client/lib/utils.js'); var User = require('fabric-client/lib/User.js'); var Peer = require('fabric-client/lib/Peer.js'); +var NetworkConfig = require('fabric-client/lib/impl/NetworkConfig_1_0.js'); var testutil = require('./util.js'); var caImport; @@ -304,6 +305,16 @@ test('\n\n ** testing query calls fail without correct parameters on client **\n } }); + var p1a = client.queryInstalledChaincodes('somename').then(function () { + t.fail('Should not have been able to resolve the promise because of No network configuraton loaded'); + }).catch(function (err) { + if (err.message.indexOf('No network configuraton loaded') >= 0) { + t.pass('Successfully caught No network configuraton loaded error'); + } else { + t.fail('Failed to catch the No network configuraton loaded error. Error: ' + err.stack ? err.stack : err); + } + }); + var p2 = client.queryChannels().then(function () { t.fail('Should not have been able to resolve the promise because of missing request parameter'); }).catch(function (err) { @@ -314,7 +325,47 @@ test('\n\n ** testing query calls fail without correct parameters on client **\n } }); - Promise.all([p1, p2]) + var p3 = client.queryChannels('somename').then(function () { + t.fail('Should not have been able to resolve the promise because of no network loaded'); + }).catch(function (err) { + if (err.message.indexOf('No network configuraton loaded') >= 0) { + t.pass('Successfully caught no network loaded error'); + } else { + t.fail('Failed to catch the no network loaded error. Error: ' + err.stack ? err.stack : err); + } + }); + + client._network_config = new NetworkConfig({}, client); + var p4 = client.queryChannels('somename').then(function () { + t.fail('Should not have been able to resolve the promise because of wrong request parameter'); + }).catch(function (err) { + if (err.message.indexOf('Target peer name was not found') >= 0) { + t.pass('Successfully caught wrong request error'); + } else { + t.fail('Failed to catch the wrong request error. Error: ' + err.stack ? err.stack : err); + } + }); + + var p4a = client.queryInstalledChaincodes('somename').then(function () { + t.fail('Should not have been able to resolve the promise because of wrong request parameter'); + }).catch(function (err) { + if (err.message.indexOf('Target peer name was not found') >= 0) { + t.pass('Successfully caught wrong request error'); + } else { + t.fail('Failed to catch the wrong request error. Error: ' + err.stack ? err.stack : err); + } + }); + + var p5 = client.queryChannels({}).then(function () { + t.fail('Should not have been able to resolve the promise because of wrong object request parameter'); + }).catch(function (err) { + if (err.message.indexOf('Target peer is not a valid peer object instance') >= 0) { + t.pass('Successfully caught wrong object request error'); + } else { + t.fail('Failed to catch the wrong object request error. Error: ' + err.stack ? err.stack : err); + } + }); + Promise.all([p1, p1a, p2, p3, p4, p4a, p5]) .then( function (data) { t.end(); @@ -363,8 +414,8 @@ test('\n\n ** testing get transaction ID call on client **\n\n', function (t) { t.throws(function() { client.newTransactionID(); }, - /This client instance must be assigned an user context/, - 'Test This client instance must be assigned an user context'); + /No identity has been assigned to this client/, + 'Test - No identity has been assigned to this client'); t.end(); }); @@ -467,7 +518,35 @@ test('\n\n ** client installChaincode() tests **\n\n', function (t) { } }); - Promise.all([p1, p2, p3, p4, p5]) + var p6 = client.installChaincode({ + targets : ['somename'], + chaincodePath: 'blahp4', + chaincodeId: 'blah', + chaincodeVersion: 'blah'}).then(function () { + t.fail('p6 - Should not have been able to resolve the promise because of bad request parameter'); + }).catch(function (err) { + if (err.message.indexOf('No network configuraton loaded') >= 0) { + t.pass('p6 - Successfully caught bad request error'); + } else { + t.fail('p6 - Failed to catch the bad request error. Error: ' + err.stack ? err.stack : err); + } + }); + + var p7 = client.installChaincode({ + targets : [{}], + chaincodePath: 'blahp4', + chaincodeId: 'blah', + chaincodeVersion: 'blah'}).then(function () { + t.fail('p7 - Should not have been able to resolve the promise because of bad request parameter'); + }).catch(function (err) { + if (err.message.indexOf('Target peer is not a valid peer object') >= 0) { + t.pass('p7 - Successfully caught bad request error'); + } else { + t.fail('p7 - Failed to catch the bad request error. Error: ' + err.stack ? err.stack : err); + } + }); + + Promise.all([p1, p2, p3, p4, p5, p6]) .then( function (data) { t.end(); @@ -489,7 +568,7 @@ test('\n\n ** Client createChannel() tests **\n\n', function (t) { ).then(function () { t.fail('Should not have been able to resolve the promise because of orderer missing'); }).catch(function (err) { - if (err.message.indexOf('Missing orderer') >= 0) { + if (err.message.indexOf('Missing "orderer"') >= 0) { t.pass('Successfully caught missing orderer error'); } else { t.fail('Failed to catch the missing orderer error. Error: '); @@ -993,7 +1072,19 @@ test('\n\n ** test related APIs for create channel **\n\n', function (t) { ).then(function () { t.fail('Should not have been able to resolve the promise'); }).catch(function (err) { - let msg = 'Missing orderer request parameter'; + let msg = 'Missing "orderer" request parameter'; + if (err.message.indexOf(msg) >= 0) { + t.pass('Successfully caught the ' + msg ); + } else { + t.fail('Failed to catch the ' + msg + ' Error: '); + console.log(err.stack ? err.stack : err); + } + }); + var p6a= client.updateChannel({config : 'a', signatures : [], txId : 'a', name : 'a', orderer : {}} + ).then(function () { + t.fail('Should not have been able to resolve the promise'); + }).catch(function (err) { + let msg = '"orderer" request parameter is not valid'; if (err.message.indexOf(msg) >= 0) { t.pass('Successfully caught the ' + msg ); } else { @@ -1025,7 +1116,7 @@ test('\n\n ** test related APIs for create channel **\n\n', function (t) { console.log(err.stack ? err.stack : err); } }); - Promise.all([p3a, p3b, p4, p6, p7, p8]) + Promise.all([p3a, p3b, p4, p6, p6a, p7, p8]) .then( function (data) { t.end(); @@ -1089,7 +1180,11 @@ test('\n\n*** Test per-call timeout support ***\n', function(t) { serialize: function() { return Buffer.from(''); } }; }; - client._userContext.getSigningIdentity = function() { return ''; }; + client._userContext.getSigningIdentity = function() { + return { + serialize: function() { return Buffer.from(''); } + }; + }; let p = client.installChaincode({ targets: [new Peer('grpc://localhost:7051'), new Peer('grpc://localhost:7052')], @@ -1109,4 +1204,4 @@ test('\n\n*** Test per-call timeout support ***\n', function(t) { sandbox.restore(); t.end(); }); -}); \ No newline at end of file +}); diff --git a/test/unit/network-config.js b/test/unit/network-config.js index 1aadbc6569..c4d2b6ebaf 100644 --- a/test/unit/network-config.js +++ b/test/unit/network-config.js @@ -80,7 +80,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.doesNotThrow( () => { var client = Client.loadFromConfig('test/fixtures/network.json'); - var channel = client.newChannel('mychannel'); + var channel = client.newChannel('mychannel2'); client.loadFromConfig('test/fixtures/network.json'); }, null, @@ -103,7 +103,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.equals('Org1', client._network_config._network_config.client.organization, ' org should be Org1'); client.loadFromConfig({ version:'1.0.0', client : {organization : 'Org2'}}); t.equals('Org2', client._network_config._network_config.client.organization, ' org should be Org2'); - var channel = client.getChannel('mychannel'); + var channel = client.getChannel('mychannel2'); }, null, '2 Should be able to instantiate a new instance of "Channel" with the definition in the network configuration' @@ -115,7 +115,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { var file_data = fs.readFileSync(config_loc); var network_data = yaml.safeLoad(file_data); var client = Client.loadFromConfig(network_data); - var channel = client.newChannel('mychannel'); + var channel = client.newChannel('mychannel2'); client.loadFromConfig(network_data); }, null, @@ -402,7 +402,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { }, null, - 'Should not get an error' + 'Should not get an error when working with credentialStore settings' ); t.doesNotThrow( @@ -474,25 +474,53 @@ test('\n\n ** configuration testing **\n\n', function (t) { checkTarget(channel._getTargets(null, 'ledgerQuery'), '7053', 'finding a default ledger query', t); checkTarget(channel._getTargetForQuery('peer1'), '7051', 'finding a string target for ledger query', t); checkTarget(channel._getTargets('peer1'), '7051', 'finding a string target', t); - checkTarget(channel._getTargetForQuery(['peer1']), 'array', 'should get an error back when passing an array', t); - checkTarget(channel._getTargetForQuery(['peer1']), 'array', 'should get an error back when passing an array', t); - checkTarget(channel._getTargets('bad'), 'found', 'should get an error back when passing a bad name', t); checkTarget(channel._getTargetForQuery(peer1), '9999', 'should get back the same target if a good peer', t); checkTarget(channel._getTargets(peer1), '9999', 'should get back the same target if a good peer', t); - client._network_config = null; - checkTarget(channel._getTargetForQuery(), '7051', 'finding a default ledger query without networkconfig', t); - checkTarget(channel._getTargets(), '7051', 'finding a default targets without networkconfig', t); + client = new Client(); + channel = client.newChannel('mychannel'); + channel.addPeer(peer1); + checkTarget(channel._getTargetForQuery(), '9999', 'finding a default ledger query without networkconfig', t); + checkTarget(channel._getTargets(), '9999', 'finding a default targets without networkconfig', t); }, null, 'Should be able to run channel target methods' ); + t.throws( + () => { + var client = new Client(); + var channel = client.newChannel('mychannel'); + channel._getTargetForQuery(); + }, + /"target" parameter not specified and no peers are set on this Channel instance or specfied for this channel in the network/, + 'Should get an error back when no targets are available' + ); + + t.throws( + () => { + var client = Client.loadFromConfig(network_config); + var channel = client.getChannel('mychannel'); + channel._getTargetForQuery(['peer1']); + }, + /array/, + 'Should get an error back when passing an array' + ); + + t.throws( + () => { + var client = Client.loadFromConfig(network_config); + var channel = client.getChannel('mychannel'); + channel._getTargets('bad'); + }, + /found/, + 'Should get an error back when passing a bad name' + ); t.throws( () => { var client = new Client(); client._network_config = new NetworkConfig({}, client); - var targets = client_utils.getOrderer('someorderer', client, 'somechannel'); + client.getTargetOrderer('someorderer'); }, /Orderer name was not found in the network configuration/, 'Should get an error when the request orderer name is not found' @@ -502,9 +530,9 @@ test('\n\n ** configuration testing **\n\n', function (t) { () => { var client = new Client(); client._network_config = new NetworkConfig({}, client); - var targets = client_utils.getOrderer({}, client, 'somechannel'); + client.getTargetOrderer({}); }, - /request parameter is not valid/, + /"orderer" request parameter is not valid. Must be an orderer name or "Orderer" object./, 'Should get an error when the request orderer is not a valid object' ); @@ -512,9 +540,9 @@ test('\n\n ** configuration testing **\n\n', function (t) { () => { var client = new Client(); client._network_config = new NetworkConfig({ channels : {somechannel : {}}}, client); - var targets = client_utils.getOrderer(null, client, 'somechannel'); + client.getTargetOrderer(null, null, 'somechannel'); }, - /"orderer" request parameter is missing and there is no orderer defined on this channel in the network configuration/, + /"orderer" request parameter is missing and there are no orderers defined on this channel in the network configuration/, 'Should get an error when the request orderer is not defined and the channel does not have any orderers' ); @@ -523,17 +551,21 @@ test('\n\n ** configuration testing **\n\n', function (t) { var client = new Client(); client._network_config = new NetworkConfig(network_config, client); - var orderer = client_utils.getOrderer('orderer0', client); + var orderer = client.getTargetOrderer('orderer0'); if(orderer instanceof Orderer) t.pass('orderer has a orderer '); else t.fail('orderer does not have a orderer'); var orderer1 = new Orderer('grpcs://localhost:9999', {pem : '-----BEGIN CERTIFICATE-----MIIB8TCC5l-----END CERTIFICATE-----'}); - orderer = client_utils.getOrderer(orderer1, client); + orderer = client.getTargetOrderer(orderer1); if(orderer instanceof Orderer) t.pass('orderer has a orderer '); else t.fail('orderer does not have a orderer'); - orderer = client_utils.getOrderer(null, client, 'mychannel'); + orderer = client.getTargetOrderer(null, null, 'mychannel'); + if(orderer instanceof Orderer) t.pass('orderer has a orderer '); + else t.fail('orderer does not have a orderer'); + + orderer = client.getTargetOrderer(null, [orderer1]); if(orderer instanceof Orderer) t.pass('orderer has a orderer '); else t.fail('orderer does not have a orderer'); }, @@ -587,17 +619,17 @@ test('\n\n ** configuration testing **\n\n', function (t) { 'Should be able to run all methods of CertificateAuthority' ); - var client = new Client(); - var p1 = client.setStoresFromConfig().then(function () { - t.fail('p1 Should not have been able to resolve the promise'); + var clientpr1 = new Client(); + var pr1 = clientpr1.initCredentialStores().then(function () { + t.fail('pr1 Should not have been able to resolve the promise'); }).catch(function (err) { if (err.message.indexOf('No network configuration settings found') >= 0) { - t.pass('p1 Successfully caught error'); + t.pass('pr1 Successfully caught error'); } else { - t.fail('p1 Failed to catch error. Error: ' + err.stack ? err.stack : err); + t.fail('pr1 Failed to catch error. Error: ' + err.stack ? err.stack : err); } }); - Promise.all([p1]) + Promise.all([pr1]) .then( function (data) { t.end(); @@ -605,7 +637,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { ).catch( function (err) { t.fail('Channel query calls, Promise.all: '); - console.log(err.stack ? err.stack : err); + logger.error(err.stack ? err.stack : err); t.end(); } ); @@ -613,7 +645,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.throws( () => { var client = new Client(); - client.setAdminFromConfig(); + client._setAdminFromConfig(); }, /No network configuration has been loaded/, 'Should get an error No network configuration has been loaded' @@ -649,53 +681,48 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.throws( () => { var client = new Client(); - client.setAdminSigningIdentity('privateKey','cert', 'msipid'); - }, - /A crypto suite must be assigned to this client/, - 'Should get an error A crypto suite must be assigned to this client' - ); - - t.throws( - () => { - var client = new Client(); - client.getAdminSigningIdentity(); + client._getSigningIdentity(); }, /No identity has been assigned to this client/, 'Should get an error No identity has been assigned to this client' ); + try { + var client = Client.loadFromConfig('test/fixtures/network.yaml'); + t.pass('Successfully loaded a network configuration'); + t.pass('Should be able to try to load an admin from the config'); + + client.loadFromConfig('test/fixtures/org1.yaml'); + t.pass('Should be able to load an additional config ...this one has the client section'); + t.pass('Should be able to try to load an admin from the config'); + } catch(err) { + t.fail('Fail - caught an error while trying to load a config and run the set admin'); + } - var client = Client.loadFromConfig('test/fixtures/network.yaml'); + var clientp1 = Client.loadFromConfig('test/fixtures/network.yaml'); t.pass('Successfully loaded a network configuration'); + clientp1.loadFromConfig('test/fixtures/org1.yaml'); + t.pass('Should be able to load an additional config ...this one has the client section'); - var p1 = client.setStoresFromConfig().then(()=> { + var p1 = clientp1.initCredentialStores().then(()=> { t.pass('Should be able to load the stores from the config'); - client.setAdminFromConfig(); + clientp1._setAdminFromConfig(); t.pass('Should be able to load an admin from the config'); - client.getAdminSigningIdentity(); + clientp1._getSigningIdentity(true); t.pass('Should be able to get the loaded admin identity'); }).catch(function (err) { - t.fail('Should not get an error'); - }); - - var p2 = client.setStoresFromConfig().then(()=> { - t.pass('Should be able to load the stores from the config'); - client._network_config._network_config.client = {}; - client.setAdminFromConfig(); - t.fail('Should not be able to load an admin from the config'); - }).catch(function (err) { - if (err.message.indexOf('No admin defined for the current organization') >= 0) { - t.pass('Successfully caught No admin defined for the current organization'); - } else { - t.fail('Failed to catch No admin defined for the current organization'); - console.log(err.stack ? err.stack : err); - } + t.fail('Should not get an error when doing get signer '); + logger.error(err.stack ? err.stack : err); }); - var p3 = client.setStoresFromConfig().then(()=> { + var clientp2 = Client.loadFromConfig('test/fixtures/network.yaml'); + t.pass('Successfully loaded a network configuration'); + clientp2.loadFromConfig('test/fixtures/org1.yaml'); + t.pass('Should be able to load an additional config ...this one has the client section'); + var p2 = clientp2.initCredentialStores().then(()=> { t.pass('Should be able to load the stores from the config'); - client._network_config._network_config.client = {}; - return client.setUserFromConfig(); + clientp2._network_config._network_config.client = {}; + return clientp2.setUserFromConfig(); }).then((user)=>{ t.fail('Should not be able to load an user based on the config'); }).catch(function (err) { @@ -703,14 +730,18 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.pass('Successfully caught Missing parameter. Must have a username.'); } else { t.fail('Failed to catch Missing parameter. Must have a username.'); - console.log(err.stack ? err.stack : err); + logger.error(err.stack ? err.stack : err); } }); - var p4 = client.setStoresFromConfig().then(()=> { + var clientp3 = Client.loadFromConfig('test/fixtures/network.yaml'); + t.pass('Successfully loaded a network configuration'); + clientp3.loadFromConfig('test/fixtures/org1.yaml'); + t.pass('Should be able to load an additional config ...this one has the client section'); + var p3 = clientp3.initCredentialStores().then(()=> { t.pass('Should be able to load the stores from the config'); - client._network_config._network_config.client = {}; - return client.setUserFromConfig('username'); + clientp4._network_config._network_config.client = {}; + return clientp3.setUserFromConfig('username'); }).then((user)=>{ t.fail('Should not be able to load an user based on the config'); }).catch(function (err) { @@ -718,23 +749,24 @@ test('\n\n ** configuration testing **\n\n', function (t) { t.pass('Successfully caught Missing parameter. Must have a password.'); } else { t.fail('Failed to catch Missing parameter. Must have a password.'); - console.log(err.stack ? err.stack : err); + logger.error(err.stack ? err.stack : err); } }); - var other_client = new Client(); - var p5 = other_client.setUserFromConfig('username', 'password').then(()=> { + var clientp4 = Client.loadFromConfig('test/fixtures/network.yaml'); + t.pass('Successfully loaded a network configuration'); + var p4 = clientp4.setUserFromConfig('username', 'password').then(()=> { t.fail('Should not be able to load an user based on the config'); }).catch(function (err) { if (err.message.indexOf('Client requires a network configuration loaded, stores attached, and crypto suite.') >= 0) { t.pass('Successfully caught Client requires a network configuration loaded, stores attached, and crypto suite.'); } else { t.fail('Failed to catch Client requires a network configuration loaded, stores attached, and crypto suite.'); - console.log(err.stack ? err.stack : err); + logger.error(err.stack ? err.stack : err); } }); - Promise.all([p1,p2, p3, p4, p5]) + Promise.all([p1,p2, p3, p4]) .then( function (data) { t.end(); @@ -742,7 +774,7 @@ test('\n\n ** configuration testing **\n\n', function (t) { ).catch( function (err) { t.fail('Client network config calls failed during the Promise.all'); - console.log(err.stack ? err.stack : err); + logger.error(err.stack ? err.stack : err); t.end(); } ); diff --git a/test/unit/transactionid.js b/test/unit/transactionid.js index 114b859aaa..408c8e65e5 100644 --- a/test/unit/transactionid.js +++ b/test/unit/transactionid.js @@ -40,14 +40,8 @@ test('\n\n ** Transaction - constructor set get tests **\n\n', function (t) { t.throws(function() { new TransactionID(); }, - /Missing userContext parameter/, - 'Test Missing userContext parameter'); - - t.throws(function() { - new TransactionID({}); - }, - /Parameter "userContext" must be an instance of the "User" class/, - 'Test Parameter "userContext" must be an instance of the "User" class'); + /Missing userContext or signing identity parameter/, + 'Test Missing signer parameter'); var member = new User('admin'); // test set enrollment for identity and signing identity @@ -57,12 +51,16 @@ test('\n\n ** Transaction - constructor set get tests **\n\n', function (t) { // the private key and cert don't match, but it's ok, the code doesn't check return member.setEnrollment(key, TEST_CERT_PEM, 'DEFAULT'); }).then(() =>{ - var trans_id = new TransactionID(member); + var trans_id = new TransactionID(member.getSigningIdentity()); t.pass('Successfully created a new TransactionID'); + t.equals(trans_id.isAdmin(), false, ' should have false admin'); + trans_id = new TransactionID(member.getSigningIdentity(), true); + t.equals(trans_id.isAdmin(), true, ' should have true admin'); + t.end(); }).catch((err) => { t.fail(err.stack ? err.stack : err); t.end(); }); -}); \ No newline at end of file +});