From a1698aae68e26db8c8b54d5bf9e49236fffa3596 Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Fri, 2 Dec 2016 15:31:28 -0500 Subject: [PATCH] NodeSDK updates for new protobufs Updates include signing of the transaction and allowing for transaction IDs. Will not work against current fabric as we are getting an error about hash missmatches. Patch 6: Fixed failed headless tests Patch 7: Fixed missing require()'s in test/unit/util.js Patch 8: Fixed the code that caused hash mismatch by the committer logic. Thanks to Alessandro and Murali's help. As a result, no hack on the Peer code is needed. This changeset can go in by itself. Change-Id: I0b801bcf249009054b982c0a2cf54c16c0ce102c Signed-off-by: Bret Harrison Signed-off-by: Jim Zhang --- build/tasks/watch.js | 5 +- hfc-cop/config/default.json | 4 +- hfc/config/default.json | 4 +- hfc/index.js | 26 ++ hfc/lib/Chain.js | 4 +- hfc/lib/Member.js | 171 ++++--- hfc/lib/protos/common/common.proto | 12 +- hfc/lib/protos/peer/api.proto | 58 --- hfc/lib/protos/peer/chaincode.proto | 27 +- hfc/lib/protos/peer/devops.proto | 96 ---- hfc/lib/protos/peer/events.proto | 5 +- hfc/lib/protos/peer/fabric.proto | 218 +-------- hfc/lib/protos/peer/fabric_message.proto | 4 +- .../peer/fabric_proposal_response.proto | 4 +- hfc/lib/protos/peer/fabric_transaction.proto | 4 +- .../peer/fabric_transaction_header.proto | 71 --- hfc/lib/utils.js | 30 ++ test/fixtures/docker-compose.yml | 42 +- test/unit/end-to-end.js | 44 +- test/unit/headless-tests.js | 421 +++++++++++++----- test/unit/util.js | 2 + 21 files changed, 584 insertions(+), 668 deletions(-) delete mode 100644 hfc/lib/protos/peer/api.proto delete mode 100644 hfc/lib/protos/peer/devops.proto delete mode 100644 hfc/lib/protos/peer/fabric_transaction_header.proto diff --git a/build/tasks/watch.js b/build/tasks/watch.js index ba58a15171..0e70d75f7d 100644 --- a/build/tasks/watch.js +++ b/build/tasks/watch.js @@ -10,7 +10,10 @@ gulp.task('watch', function () { watch([ 'hfc/lib/**/*', - 'hfc-cop/lib/**/*' + 'hfc/index.js', + 'hfc/config/**/*', + 'hfc-cop/lib/**/*', + 'hfc-cop/config/**/*' ], { ignoreInitial: false, base: './' }) .pipe(debug()) .pipe(gulp.dest('node_modules')); diff --git a/hfc-cop/config/default.json b/hfc-cop/config/default.json index f9d144448a..750c64de22 100644 --- a/hfc-cop/config/default.json +++ b/hfc-cop/config/default.json @@ -2,7 +2,7 @@ "request-timeout" : 3000, "tcert-batch-size" : 10, "crypto-asymmetric-key-algo": "ECDSA", - "crypto-hash-algo": "SHA3", - "crypto-keysize": 384, + "crypto-hash-algo": "SHA2", + "crypto-keysize": 256, "crypto-suite": "./impl/CryptoSuite_ECDSA_AES.js", } diff --git a/hfc/config/default.json b/hfc/config/default.json index 5e70335fa6..9374f76da1 100644 --- a/hfc/config/default.json +++ b/hfc/config/default.json @@ -2,8 +2,8 @@ "request-timeout" : 3000, "tcert-batch-size" : 10, "crypto-asymmetric-key-algo": "ECDSA", - "crypto-hash-algo": "SHA3", - "crypto-keysize": 384, + "crypto-hash-algo": "SHA2", + "crypto-keysize": 256, "crypto-suite": "./impl/CryptoSuite_ECDSA_AES.js", "key-value-store": "./impl/FileKeyValueStore.js", "member-service": "./impl/FabricCOPImpl.js", diff --git a/hfc/index.js b/hfc/index.js index e4cd43731a..f3de967bc0 100644 --- a/hfc/index.js +++ b/hfc/index.js @@ -198,3 +198,29 @@ module.exports.getConfigSetting = function(name, default_value) { return utils.getConfigSetting(name, default_value); }; +/** + * Builds an unique transaction ID based on the values in + * the request object. + * + * @param {Object} request - An object with the values to be used + * to build an unique transaction ID. + * @returns {String} An unique transaction ID + */ +module.exports.buildTransactionID = function(request) { + + return utils.buildTransactionID(request); +}; + +/** + * Gets a random number for a one time use + * + * @param {int} length - Optional value to control the length of the number. + * The configuration setting 'nonce-size' will be used if not + * passed in. + * @return {int} Random number of the specified length + */ +module.exports.getNonce = function(length) { + + return utils.buildTransactionID(length); +}; + diff --git a/hfc/lib/Chain.js b/hfc/lib/Chain.js index 6c48a0893e..330e8a3549 100644 --- a/hfc/lib/Chain.js +++ b/hfc/lib/Chain.js @@ -208,7 +208,9 @@ var Chain = class { member.restoreState() .then( function() { - self._members[name] = member; + if (member.isEnrolled()) { + self._members[name] = member; + } logger.debug('Requested member "%s" loaded from key value store', name); return resolve(member); } diff --git a/hfc/lib/Member.js b/hfc/lib/Member.js index a94a6d0609..65c41bffb7 100644 --- a/hfc/lib/Member.js +++ b/hfc/lib/Member.js @@ -29,7 +29,6 @@ var _ccProto = grpc.load(__dirname + '/protos/peer/chaincode.proto').protos; var _ccProposalProto = grpc.load(__dirname + '/protos/peer/chaincode_proposal.proto').protos; var _ccTransProto = grpc.load(__dirname + '/protos/peer/chaincode_transaction.proto').protos; var _transProto = grpc.load(__dirname + '/protos/peer/fabric_transaction.proto').protos; -var _headerProto = grpc.load(__dirname + '/protos/peer/fabric_transaction_header.proto').protos; var _proposalProto = grpc.load(__dirname + '/protos/peer/fabric_proposal.proto').protos; var _responseProto = grpc.load(__dirname + '/protos/peer/fabric_proposal_response.proto').protos; var _commonProto = grpc.load(__dirname + '/protos/common/common.proto').common; @@ -241,18 +240,34 @@ var Member = class { * This will be an acknowledgement from the orderer of successfully submitted transaction. * @see the ./proto/atomicbroadcast/ab.proto */ - sendTransaction(proposalResponses, chaincodeProposal) { + sendTransaction(request) { logger.debug('Member.sendTransaction - start :: chain '+this._chain); + var errorMsg = null; - // Verify that data is being passed in - if (!proposalResponses) { - logger.error('Member.sendTransaction - input proposalResponse missing'); - return Promise.reject(new Error('Missing proposalResponse object parameter')); + if (request) { + // Verify that data is being passed in + if (!request.proposalResponses) { + errorMsg = 'Missing "proposalResponse" parameter in transaction request'; + } + if (!request.proposal) { + errorMsg = 'Missing "proposal" parameter in transaction request'; + } + if (!request.header) { + errorMsg = 'Missing "header" parameter in transaction request'; + } + } else { + errorMsg = 'Missing input request object on the proposal request'; } - if (!chaincodeProposal) { - logger.error('Member.sendTransaction - input chaincodeProposal missing'); - return Promise.reject(new Error('Missing chaincodeProposal object parameter')); + + if(errorMsg) { + logger.error('Member.sendTransaction error '+ errorMsg); + return Promise.reject(new Error(errorMsg)); } + + let proposalResponses = request.proposalResponses; + let chaincodeProposal = request.proposal; + let header = request.header; + // verify that we have an orderer configured if(!this._chain.getOrderer()) { logger.error('Member.sendTransaction - no orderer defined'); @@ -274,36 +289,43 @@ var Member = class { endorsements.push(proposalResponse.endorsement); } -// logger.debug('Member.sendTransaction - proposalResponse %j', proposalResponse); -// logger.debug('Member.sendTransaction - chaincodePropsoal %j', chaincodeProposal); - var chaincodeEndorsedAction = new _ccTransProto.ChaincodeEndorsedAction(); chaincodeEndorsedAction.setProposalResponsePayload(proposalResponse.payload); chaincodeEndorsedAction.setEndorsements(endorsements); var chaincodeActionPayload = new _ccTransProto.ChaincodeActionPayload(); chaincodeActionPayload.setAction(chaincodeEndorsedAction); - chaincodeActionPayload.setChaincodeProposalPayload(chaincodeProposal.payload); + var chaincodeProposalPayloadNoTrans = _ccProposalProto.ChaincodeProposalPayload.decode(chaincodeProposal.payload); + chaincodeProposalPayloadNoTrans.transient = null; + var payload_hash = this._chain.cryptoPrimitives.hash(chaincodeProposalPayloadNoTrans.toBuffer()); + chaincodeActionPayload.setChaincodeProposalPayload(Buffer.from(payload_hash, 'hex')); + + //let header = Member._buildHeader(this._enrollment.certificate, request.chainId, request.chaincodeId, request.txId, request.nonce); var transactionAction = new _transProto.TransactionAction(); - transactionAction.setHeader(chaincodeProposal.header); + transactionAction.setHeader(header.getSignatureHeader().toBuffer()); transactionAction.setPayload(chaincodeActionPayload.toBuffer()); var actions = []; actions.push(transactionAction); - var transaction2 = new _transProto.Transaction2(); - transaction2.setActions(actions); + var transaction = new _transProto.Transaction(); + transaction.setActions(actions); - let header = Member._buildHeader(this._enrollment.certificate, null); var payload = new _commonProto.Payload(); payload.setHeader(header); - payload.setData(transaction2.toBuffer()); + payload.setData(transaction.toBuffer()); + + let payload_bytes = payload.toBuffer(); + // sign the proposal + let sig = this._chain.cryptoPrimitives.sign(this._enrollment.privateKey, payload_bytes); + let signature = Buffer.from(sig.toDER()); // building manually or will get protobuf errors on send var envelope = { - payload : payload.toBuffer() + signature: signature, + payload : payload_bytes }; var orderer = this._chain.getOrderer(); @@ -317,6 +339,9 @@ var Member = class { *
`targets` : required - An array or single Endorsing {@link Peer} objects as the targets of the request *
`chaincodePath` : required - String of the path to location of the source code of the chaincode *
`chaincodeId` : required - String of the name of the chaincode + *
`chainId` : required - String of the name of the chain + *
`txId` : required - String of the transaction id + *
`nonce` : required - Integer of the once time number *
`fcn` : optional - String of the function to be called on the chaincode once deployed (default 'init') *
`args` : optional - String Array arguments specific to the chaincode being deployed *
`dockerfile-contents` : optional - String defining the @@ -324,21 +349,18 @@ var Member = class { * @see /protos/peer/fabric_proposal_response.proto */ sendDeploymentProposal(request) { - // Verify that chaincodePath is being passed - if (!request.chaincodePath || request.chaincodePath === '') { - logger.error('Invalid input parameter to "sendDeploymentProposal": must have "chaincodePath"'); - return Promise.reject(new Error('Missing chaincodePath in Deployment proposal request')); - } + var errorMsg = null; - if(!request.chaincodeId) { - logger.error('Missing chaincodeId in the Deployment proposal request'); - return Promise.reject(new Error('Missing chaincodeId in the Deployment proposal request')); + // Verify that chaincodePath is being passed + if (request && (!request.chaincodePath || request.chaincodePath === '')) { + errorMsg = 'Missing chaincodePath parameter in Deployment proposal request'; + } else { + errorMsg = Member._checkProposalRequest(request); } - // verify that the caller has included a peer object - if(!request.targets) { - logger.error('Invalid input parameter to "sendDeploymentProposal": must have "targets" object'); - return Promise.reject(new Error('Missing "targets" for the endorsing peer objects in the Deployment proposal request')); + if(errorMsg) { + logger.error('Member.sendDeploymentProposal error '+ errorMsg); + return Promise.reject(new Error(errorMsg)); } // args is optional because some chaincode may not need any input parameters during initialization @@ -395,13 +417,14 @@ var Member = class { } }; - let proposal = self._buildProposal(lcccSpec, 'lccc'); - let signed_proposal = self._signProposal(proposal); + let header = Member._buildHeader(self._enrollment.certificate, request.chainId, 'lccc', request.txId, request.nonce); + let proposal = self._buildProposal(lcccSpec, header); + let signed_proposal = self._signProposal(self._enrollment, proposal); return Member._sendPeersProposal(request.targets, signed_proposal) .then( function(responses) { - resolve([responses, proposal]); + resolve([responses, proposal, header]); } ).catch( function(err) { @@ -427,27 +450,25 @@ var Member = class { * @param {Object} request *
`targets` : An array or single Endorsing {@link Peer} objects as the targets of the request *
`chaincodeId` : The id of the chaincode to perform the transaction proposal + *
`chainId` : required - String of the name of the chain + *
`txId` : required - String of the transaction id + *
`nonce` : required - Integer of the once time number *
`args` : an array of arguments specific to the chaincode 'innvoke' * @returns {Promise} A Promise for a `ProposalResponse` */ sendTransactionProposal(request) { logger.debug('Member.sendTransactionProposal - start'); - - // verify that the caller has included a peer object - if(!request.targets) { - logger.error('Missing "targets" endorser peer objects in the Transaction proposal request'); - return Promise.reject(new Error('Missing "targets" for endorser peer objects in the Transaction proposal request')); - } - - if(!request.chaincodeId) { - logger.error('Missing chaincodeId in the Transaction proposal request'); - return Promise.reject(new Error('Missing chaincodeId in the Transaction proposal request')); + var errorMsg = null; + // args is not optional because we need for transaction to execute + if (request && !request.args) { + errorMsg = 'Missing "args" in Transaction proposal request'; + } else { + errorMsg = Member._checkProposalRequest(request); } - // args is not optional because we need for transaction to execute - if (!request.args) { - logger.error('Missing arguments in Transaction proposal request'); - return Promise.reject(new Error('Missing arguments in Transaction proposal request')); + if(errorMsg) { + logger.error('Member.sendTransactionProposal error '+ errorMsg); + return Promise.reject(new Error(errorMsg)); } var args = []; @@ -470,13 +491,14 @@ var Member = class { } }; - let proposal = this._buildProposal(invokeSpec, request.chaincodeId); - let signed_proposal = this._signProposal(proposal); + let header = Member._buildHeader(this._enrollment.certificate, request.chainId, request.chaincodeId, request.txId, request.nonce); + let proposal = this._buildProposal(invokeSpec, header); + let signed_proposal = this._signProposal(this._enrollment, proposal); return Member._sendPeersProposal(request.targets, signed_proposal) .then( function(responses) { - return Promise.resolve([responses,proposal]); + return Promise.resolve([responses, proposal, header]); } ).catch( function(err) { @@ -532,26 +554,25 @@ var Member = class { /** * @private */ - static _buildHeader(creator, chaincode_id) { + static _buildHeader(creator, chain_id, chaincode_id, tx_id, nonce) { let chainHeader = new _commonProto.ChainHeader(); chainHeader.setType(_commonProto.HeaderType.ENDORSER_TRANSACTION); - chainHeader.setVersion(0); //TODO what should this be + chainHeader.setTxID(tx_id.toString()); + chainHeader.setChainID(Buffer.from(chain_id)); if(chaincode_id) { let chaincodeID = new _ccProto.ChaincodeID(); chaincodeID.setName(chaincode_id); let headerExt = new _ccProposalProto.ChaincodeHeaderExtension(); headerExt.setChaincodeID(chaincodeID); -// headerExt.setPayloadVisibility(TODO); - chainHeader.setChainID(chaincodeID.toBuffer()); chainHeader.setExtension(headerExt.toBuffer()); } let signatureHeader = new _commonProto.SignatureHeader(); signatureHeader.setCreator(Buffer.from(creator)); - signatureHeader.setNonce(crypto.randomBytes(sdkUtils.getConfigSetting('nonce-size', 24))); + signatureHeader.setNonce(nonce); let header = new _commonProto.Header(); header.setSignatureHeader(signatureHeader); @@ -564,7 +585,7 @@ var Member = class { /** * @private */ - _buildProposal(invokeSpec, chaincode_id) { + _buildProposal(invokeSpec, header) { // construct the ChaincodeInvocationSpec let cciSpec = new _ccProto.ChaincodeInvocationSpec(); cciSpec.setChaincodeSpec(invokeSpec); @@ -572,9 +593,7 @@ var Member = class { let cc_payload = new _ccProposalProto.ChaincodeProposalPayload(); cc_payload.setInput(cciSpec.toBuffer()); - //cc_payload.setTransient(n/a); // TODO application-level confidentiality related - - let header = Member._buildHeader(this._enrollment.certificate, chaincode_id); + //cc_payload.setTransient(null); // TODO application-level confidentiality related // proposal -- will switch to building the proposal once the signProposal is used let proposal = new _proposalProto.Proposal(); @@ -632,11 +651,11 @@ var Member = class { /** * @private */ - _signProposal(proposal) { + _signProposal(enrollment, proposal) { let proposal_bytes = proposal.toBuffer(); // sign the proposal - let sig = this._chain.cryptoPrimitives.sign(this._enrollment.privateKey, proposal_bytes); - let signature = new Buffer(sig.toDER()); + let sig = this._chain.cryptoPrimitives.sign(enrollment.privateKey, proposal_bytes); + let signature = Buffer.from(sig.toDER()); logger.debug('_signProposal - signature::'+JSON.stringify(signature)); @@ -704,6 +723,32 @@ var Member = class { return JSON.stringify(state); } + + /* + * @private + */ + static _checkProposalRequest(request) { + var errorMsg = null; + + if(request) { + if(!request.chaincodeId) { + errorMsg = 'Missing "chaincodeId" parameter in the proposal request'; + } else if(!request.chainId) { + errorMsg = 'Missing "chainId" parameter in the proposal request'; + } else if(!request.targets) { + errorMsg = 'Missing "targets" parameter in the proposal request'; + } else if(!request.txId) { + errorMsg = 'Missing "txId" parameter in the proposal request'; + } else if(!request.chainId) { + errorMsg = 'Missing "chainId" parameter in the proposal request'; + } else if(!request.nonce) { + errorMsg = 'Missing "nonce" parameter in the proposal request'; + } + } else { + errorMsg = 'Missing input request object on the proposal request'; + } + return errorMsg; + } }; function toKeyValueStoreName(name) { diff --git a/hfc/lib/protos/common/common.proto b/hfc/lib/protos/common/common.proto index 1d16831e19..1484a3bb62 100644 --- a/hfc/lib/protos/common/common.proto +++ b/hfc/lib/protos/common/common.proto @@ -59,6 +59,14 @@ message ChainHeader { // Identifier of the chain this message is bound for bytes chainID = 4; + // An unique identifier that is used end-to-end. + // - set by higher layers such as end user or SDK + // - passed to the endorser (which will check for uniqueness) + // - as the header is passed along unchanged, it will be + // be retrieved by the committer (uniqueness check here as well) + // - to be stored in the ledger + string txID = 5; + // The epoch in which this header was generated, where epoch is defined based on block height // Epoch in which the response has been generated. This field identifies a // logical window of time. A proposal response is accepted by a peer only if @@ -66,10 +74,10 @@ message ChainHeader { // 1. the epoch specified in the message is the current epoch // 2. this message has been only seen once during this epoch (i.e. it hasn't // been replayed) - uint64 epoch = 5; + uint64 epoch = 6; // Extension that may be attached based on the header type - bytes extension = 6; + bytes extension = 7; } message SignatureHeader { diff --git a/hfc/lib/protos/peer/api.proto b/hfc/lib/protos/peer/api.proto deleted file mode 100644 index 6fa87c3758..0000000000 --- a/hfc/lib/protos/peer/api.proto +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright IBM Corp. 2016 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. -*/ - -syntax = "proto3"; - -package protos; - -import "fabric.proto"; -import "../google/protobuf/empty.proto"; - -option go_package = "github.com/hyperledger/fabric/protos/peer"; - -// Interface exported by the server. -service Openchain { - - // GetBlockchainInfo returns information about the blockchain ledger such as - // height, current block hash, and previous block hash. - rpc GetBlockchainInfo(google.protobuf.Empty) returns (BlockchainInfo) {} - - // GetBlockByNumber returns the data contained within a specific block in the - // blockchain. The genesis block is block zero. - rpc GetBlockByNumber(BlockNumber) returns (Block) {} - - // GetBlockCount returns the current number of blocks in the blockchain data - // structure. - rpc GetBlockCount(google.protobuf.Empty) returns (BlockCount) {} - - // GetPeers returns a list of all peer nodes currently connected to the target - // peer. - rpc GetPeers(google.protobuf.Empty) returns (PeersMessage) {} -} - -// Specifies the block number to be returned from the blockchain. -message BlockNumber { - - uint64 number = 1; - -} - -// Specifies the current number of blocks in the blockchain. -message BlockCount { - - uint64 count = 1; - -} diff --git a/hfc/lib/protos/peer/chaincode.proto b/hfc/lib/protos/peer/chaincode.proto index 18971a62dd..cc66e0cfda 100644 --- a/hfc/lib/protos/peer/chaincode.proto +++ b/hfc/lib/protos/peer/chaincode.proto @@ -106,20 +106,6 @@ message ChaincodeInvocationSpec { string idGenerationAlg = 2; } -// This structure contain transaction data that we send to the chaincode -// container shim and allow the chaincode to access through the shim interface. -// TODO: Consider remove this message and just pass the transaction object -// to the shim and/or allow the chaincode to query transactions. -message ChaincodeSecurityContext { - bytes callerCert = 1; - bytes callerSign = 2; - bytes payload = 3; - bytes binding = 4; - bytes metadata = 5; - bytes parentMetadata = 6; - google.protobuf.Timestamp txTimestamp = 7; // transaction timestamp -} - message ChaincodeMessage { enum Type { @@ -135,22 +121,17 @@ message ChaincodeMessage { PUT_STATE = 9; DEL_STATE = 10; INVOKE_CHAINCODE = 11; - INVOKE_QUERY = 12; RESPONSE = 13; - QUERY = 14; - QUERY_COMPLETED = 15; - QUERY_ERROR = 16; - RANGE_QUERY_STATE = 17; - RANGE_QUERY_STATE_NEXT = 18; - RANGE_QUERY_STATE_CLOSE = 19; - KEEPALIVE = 20; + RANGE_QUERY_STATE = 14; + RANGE_QUERY_STATE_NEXT = 15; + RANGE_QUERY_STATE_CLOSE = 16; + KEEPALIVE = 17; } Type type = 1; google.protobuf.Timestamp timestamp = 2; bytes payload = 3; string txid = 4; - ChaincodeSecurityContext securityContext = 5; //event emmited by chaincode. Used only with Init or Invoke. // This event is then stored (currently) diff --git a/hfc/lib/protos/peer/devops.proto b/hfc/lib/protos/peer/devops.proto deleted file mode 100644 index e78fd462fd..0000000000 --- a/hfc/lib/protos/peer/devops.proto +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright IBM Corp. 2016 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. -*/ - -syntax = "proto3"; - -package protos; - -option go_package = "github.com/hyperledger/fabric/protos/peer"; - -import "chaincode.proto"; -import "fabric.proto"; - -// Interface exported by the server. -service Devops { - // Log in - passed Secret object and returns Response object, where - // msg is the security context to be used in subsequent invocations - rpc Login(Secret) returns (Response) {} - - // Build the chaincode package. - rpc Build(ChaincodeSpec) returns (ChaincodeDeploymentSpec) {} - - // Deploy the chaincode package to the chain. - rpc Deploy(ChaincodeSpec) returns (ChaincodeDeploymentSpec) {} - - // Invoke chaincode. - rpc Invoke(ChaincodeInvocationSpec) returns (Response) {} - - // Query chaincode. - rpc Query(ChaincodeInvocationSpec) returns (Response) {} - - // Retrieve a TCert. - rpc EXP_GetApplicationTCert(Secret) returns (Response) {} - - // Prepare for performing a TX, which will return a binding that can later be used to sign and then execute a transaction. - rpc EXP_PrepareForTx(Secret) returns (Response) {} - - // Prepare for performing a TX, which will return a binding that can later be used to sign and then execute a transaction. - rpc EXP_ProduceSigma(SigmaInput) returns (Response) {} - - // Execute a transaction with a specific binding - rpc EXP_ExecuteWithBinding(ExecuteWithBinding) returns (Response) {} -} - -// Secret is a temporary object to establish security with the Devops. -// A better solution using certificate will be introduced later -message Secret { - string enrollId = 1; - string enrollSecret = 2; -} - -message SigmaInput { - Secret secret = 1; - bytes appTCert = 2; - bytes data = 3; -} - -message ExecuteWithBinding { - ChaincodeInvocationSpec chaincodeInvocationSpec = 1; - bytes binding = 2; -} - -message SigmaOutput { - bytes tcert = 1; - bytes sigma = 2; - bytes asn1Encoding = 3; -} - -message BuildResult { - - enum StatusCode { - UNDEFINED = 0; - SUCCESS = 1; - FAILURE = 2; - } - - StatusCode status = 1; - string msg = 2; - ChaincodeDeploymentSpec deploymentSpec = 3; -} - -message TransactionRequest { - string transactionUuid = 1; -} diff --git a/hfc/lib/protos/peer/events.proto b/hfc/lib/protos/peer/events.proto index 9ce2ec59ea..29273e5100 100644 --- a/hfc/lib/protos/peer/events.proto +++ b/hfc/lib/protos/peer/events.proto @@ -17,7 +17,8 @@ limitations under the License. syntax = "proto3"; import "chaincodeevent.proto"; -import "fabric.proto"; +import "fabric_transaction.proto"; +import "fabric_block.proto"; option go_package = "github.com/hyperledger/fabric/protos/peer"; @@ -81,7 +82,7 @@ message Event { Register register = 1; //producer events - Block block = 2; + Block2 block = 2; ChaincodeEvent chaincodeEvent = 3; Rejection rejection = 4; diff --git a/hfc/lib/protos/peer/fabric.proto b/hfc/lib/protos/peer/fabric.proto index 528709a847..0d7ac13fdd 100644 --- a/hfc/lib/protos/peer/fabric.proto +++ b/hfc/lib/protos/peer/fabric.proto @@ -18,118 +18,6 @@ syntax = "proto3"; option go_package = "github.com/hyperledger/fabric/protos/peer"; package protos; -import "chaincode.proto"; -import "chaincodeevent.proto"; -import "../google/protobuf/timestamp.proto"; - - -// Transaction defines a function call to a contract. -// `args` is an array of type string so that the chaincode writer can choose -// whatever format they wish for the arguments for their chaincode. -// For example, they may wish to use JSON, XML, or a custom format. -// TODO: Defined remaining fields. -message Transaction { - enum Type { - UNDEFINED = 0; - // deploy a chaincode to the network and call `Init` function - CHAINCODE_DEPLOY = 1; - // call a chaincode `Invoke` function as a transaction - CHAINCODE_INVOKE = 2; - // call a chaincode `query` function - CHAINCODE_QUERY = 3; - // terminate a chaincode; not implemented yet - CHAINCODE_TERMINATE = 4; - } - Type type = 1; - //store ChaincodeID as bytes so its encrypted value can be stored - bytes chaincodeID = 2; - bytes payload = 3; - bytes metadata = 4; - string txid = 5; - google.protobuf.Timestamp timestamp = 6; - - ConfidentialityLevel confidentialityLevel = 7; - string confidentialityProtocolVersion = 8; - bytes nonce = 9; - - bytes toValidators = 10; - bytes cert = 11; - bytes signature = 12; -} - -// TransactionBlock carries a batch of transactions. -message TransactionBlock { - repeated Transaction transactions = 1; -} - -// TransactionResult contains the return value of a transaction. It does -// not track potential state changes that were a result of the transaction. -// txid - The unique identifier of this transaction. -// result - The return value of the transaction. -// errorCode - An error code. 5xx will be logged as a failure in the dashboard. -// error - An error string for logging an issue. -// chaincodeEvent - any event emitted by a transaction -message TransactionResult { - string txid = 1; - bytes result = 2; - uint32 errorCode = 3; - string error = 4; - ChaincodeEvent chaincodeEvent = 5; -} - -// Block carries The data that describes a block in the blockchain. -// version - Version used to track any protocol changes. -// timestamp - The time at which the block or transaction order -// was proposed. This may not be used by all consensus modules. -// transactions - The ordered list of transactions in the block. -// stateHash - The state hash after running transactions in this block. -// previousBlockHash - The hash of the previous block in the chain. -// consensusMetadata - Consensus modules may optionally store any -// additional metadata in this field. -// nonHashData - Data stored with the block, but not included in the blocks -// hash. This allows this data to be different per peer or discarded without -// impacting the blockchain. -message Block { - uint32 version = 1; - google.protobuf.Timestamp timestamp = 2; - repeated Transaction transactions = 3; - bytes stateHash = 4; - bytes previousBlockHash = 5; - bytes consensusMetadata = 6; - NonHashData nonHashData = 7; -} - -// Contains information about the blockchain ledger such as height, current -// block hash, and previous block hash. -message BlockchainInfo { - - uint64 height = 1; - bytes currentBlockHash = 2; - bytes previousBlockHash = 3; - -} - -// NonHashData is data that is recorded on the block, but not included in -// the block hash when verifying the blockchain. -// localLedgerCommitTimestamp - The time at which the block was added -// to the ledger on the local peer. -// chaincodeEvent - is an array ChaincodeEvents, one per transaction in the -// block -message NonHashData { - google.protobuf.Timestamp localLedgerCommitTimestamp = 1; - repeated ChaincodeEvent chaincodeEvents = 2; -} - -// Interface exported by the server. -service Peer { - // Accepts a stream of Message during chat session, while receiving - // other Message (e.g. from other peers). - rpc Chat(stream Message) returns (stream Message) {} - - // Process a transaction from a remote source. - rpc ProcessTransaction(Transaction) returns (Response) {} - -} message PeerAddress { string host = 1; @@ -160,106 +48,12 @@ message PeersAddresses { repeated string addresses = 1; } -message HelloMessage { - PeerEndpoint peerEndpoint = 1; - BlockchainInfo blockchainInfo = 2; -} - -message Message { - enum Type { - UNDEFINED = 0; - - DISC_HELLO = 1; - DISC_DISCONNECT = 2; - DISC_GET_PEERS = 3; - DISC_PEERS = 4; - DISC_NEWMSG = 5; - - CHAIN_TRANSACTION = 6; - - SYNC_GET_BLOCKS = 11; - SYNC_BLOCKS = 12; - SYNC_BLOCK_ADDED = 13; - - SYNC_STATE_GET_SNAPSHOT = 14; - SYNC_STATE_SNAPSHOT = 15; - SYNC_STATE_GET_DELTAS = 16; - SYNC_STATE_DELTAS = 17; - - RESPONSE = 20; - CONSENSUS = 21; - } - Type type = 1; - google.protobuf.Timestamp timestamp = 2; - bytes payload = 3; - bytes signature = 4; -} - -message Response { - enum StatusCode { - UNDEFINED = 0; - SUCCESS = 200; - FAILURE = 500; - } - StatusCode status = 1; - bytes msg = 2; -} - -// BlockState is the payload of Message.SYNC_BLOCK_ADDED. When a VP -// commits a new block to the ledger, it will notify its connected NVPs of the -// block and the delta state. The NVP may call the ledger APIs to apply the -// block and the delta state to its ledger if the block's previousBlockHash -// equals to the NVP's current block hash -message BlockState { - Block block = 1; - bytes stateDelta = 2; -} - -// SyncBlockRange is the payload of Message.SYNC_GET_BLOCKS, where -// start and end indicate the starting and ending blocks inclusively. The order -// in which blocks are returned is defined by the start and end values. For -// example, if start=3 and end=5, the order of blocks will be 3, 4, 5. -// If start=5 and end=3, the order will be 5, 4, 3. -message SyncBlockRange { - uint64 correlationId = 1; - uint64 start = 2; - uint64 end = 3; -} - -// SyncBlocks is the payload of Message.SYNC_BLOCKS, where the range -// indicates the blocks responded to the request SYNC_GET_BLOCKS -message SyncBlocks { - SyncBlockRange range = 1; - repeated Block blocks = 2; -} - -// SyncSnapshotRequest Payload for the penchainMessage.SYNC_GET_SNAPSHOT message. -message SyncStateSnapshotRequest { - uint64 correlationId = 1; -} - -// SyncStateSnapshot is the payload of Message.SYNC_SNAPSHOT, which is a response -// to penchainMessage.SYNC_GET_SNAPSHOT. It contains the snapshot or a chunk of the -// snapshot on stream, and in which case, the sequence indicate the order -// starting at 0. The terminating message will have len(delta) == 0. -message SyncStateSnapshot { - bytes delta = 1; - uint64 sequence = 2; - uint64 blockNumber = 3; - SyncStateSnapshotRequest request = 4; -} +// Contains information about the blockchain ledger such as height, current +// block hash, and previous block hash. +message BlockchainInfo { -// SyncStateDeltasRequest is the payload of Message.SYNC_GET_STATE. -// blockNumber indicates the block number for the delta which is being -// requested. If no payload is included with SYNC_GET_STATE, it represents -// a request for a snapshot of the current state. -message SyncStateDeltasRequest { - SyncBlockRange range = 1; -} + uint64 height = 1; + bytes currentBlockHash = 2; + bytes previousBlockHash = 3; -// SyncStateDeltas is the payload of the Message.SYNC_STATE in response to -// the Message.SYNC_GET_STATE message. -message SyncStateDeltas { - SyncBlockRange range = 1; - repeated bytes deltas = 2; } diff --git a/hfc/lib/protos/peer/fabric_message.proto b/hfc/lib/protos/peer/fabric_message.proto index 2b12d4935e..9bbcfe6292 100644 --- a/hfc/lib/protos/peer/fabric_message.proto +++ b/hfc/lib/protos/peer/fabric_message.proto @@ -20,8 +20,8 @@ option go_package = "github.com/hyperledger/fabric/protos/peer"; package protos; -// A Message2 encapsulates a payload of the indicated type in this message. -message Message2 { +// A Message encapsulates a payload of the indicated type in this message. +message Message { enum Type { diff --git a/hfc/lib/protos/peer/fabric_proposal_response.proto b/hfc/lib/protos/peer/fabric_proposal_response.proto index 3ba30f9a2b..1353e64dfa 100644 --- a/hfc/lib/protos/peer/fabric_proposal_response.proto +++ b/hfc/lib/protos/peer/fabric_proposal_response.proto @@ -41,7 +41,7 @@ message ProposalResponse { // A response message indicating whether the // endorsement of the action was successful - Response2 response = 4; + Response response = 4; // The payload of response. It is the bytes of ProposalResponsePayload bytes payload = 5; @@ -53,7 +53,7 @@ message ProposalResponse { // A response with a representation similar to an HTTP response that can // be used within another message. -message Response2 { +message Response { // A status code that should follow the HTTP status codes. int32 status = 1; diff --git a/hfc/lib/protos/peer/fabric_transaction.proto b/hfc/lib/protos/peer/fabric_transaction.proto index 75d3bacc78..a2621831eb 100644 --- a/hfc/lib/protos/peer/fabric_transaction.proto +++ b/hfc/lib/protos/peer/fabric_transaction.proto @@ -43,7 +43,7 @@ message InvalidTransaction { TxIdAlreadyExists = 0; RWConflictDuringCommit = 1; } - Transaction2 transaction = 1; + Transaction transaction = 1; Cause cause = 2; } @@ -59,7 +59,7 @@ message InvalidTransaction { // (ProposalResponsePayload) with one signature per Endorser. Any number of // independent proposals (and their action) might be included in a transaction // to ensure that they are treated atomically. -message Transaction2 { +message Transaction { // Version indicates message protocol version. int32 version = 1; diff --git a/hfc/lib/protos/peer/fabric_transaction_header.proto b/hfc/lib/protos/peer/fabric_transaction_header.proto deleted file mode 100644 index 4a1b30435a..0000000000 --- a/hfc/lib/protos/peer/fabric_transaction_header.proto +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright IBM Corp. 2016 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. -*/ - -syntax = "proto3"; - -option go_package = "github.com/hyperledger/fabric/protos/peer"; - -package protos; - -import "../google/protobuf/timestamp.proto"; - -// A Header contains fields that are common to all proposals and all -// transactions, no matter their type. It can include also type-dependant -// fields by using the 'extensions' field. This header is on purpose the same -// header for proposals (a request to do "something" on the ledger) and a -// transaction (the endorsed actions following from some request). -// Furthermore, a proposal, its endorsements and the resulting transaction are -// linked together by this message, as follows -// 1. a Proposal contains a Header -// 2. the hash of the Header of a proposal is included in the proposal response -// generated by each endorser as a result of that proposal -// 3. a TransactionAction contains both i) the *same* Header (byte-by-byte) of -// the corresponsing Proposal and ii) the hash of the Header in each of the -// endorsed actions -message Header { - - enum Type { - UNDEFINED = 0; - CHAINCODE = 1; - } - - // Version indicates message protocol version - int32 version = 1; - - // Timestamp is the local time when the message was created - // by the sender - google.protobuf.Timestamp timestamp = 2; - - // Type of the transaction - Type type = 3; - - // Creator of the header (and encapsulating message). This is usually a tcert - // or ecert identifying the entity who submits the proposal/transaction. The - // creator identifies the signer of - // 1. a proposal (if this is the header of a Proposal message) - // 2. a transaction (if this is the header of a TransactionAction message) - bytes creator = 4; - - // Arbitrary number that may only be used once. This ensures the hash of - // the proposal is unique and may be used in replay detection - bytes nonce = 5; - - // Identifier of the chain this header targets to - bytes chainID = 6; - - // Extensions is used to include type-dependant fields - bytes extensions = 7; -} diff --git a/hfc/lib/utils.js b/hfc/lib/utils.js index b74a96aa93..816dbafb76 100644 --- a/hfc/lib/utils.js +++ b/hfc/lib/utils.js @@ -24,6 +24,7 @@ var zlib = require('zlib'); var urlParser = require('url'); var winston = require('winston'); var Config = require('./Config.js'); +var crypto = require('crypto'); // // Load required crypto stuff. @@ -366,3 +367,32 @@ module.exports.existsSync = function(absolutePath /*string*/) { } }; +// utility function to build an unique transaction id +// The request object may contain values that could be +// used to help generate the result value +module.exports.buildTransactionID = function(request /*object*/) { + var length = 10; + if(request && request.length) { + length = request.length; + } + var value = crypto.randomBytes(10); //TODO how should we really generate this value + return value; +}; + +// utility function to create a random number of +// the specified length. +module.exports.getNonce = function(length) { + if(length) { + if(Number.isInteger(length)) { + // good, it is a number + } else { + throw new Error('Parameter must be an integer'); + } + } else { + length = this.getConfigSetting('nonce-size', 24); + } + + var value = crypto.randomBytes(length); + return value; +}; + diff --git a/test/fixtures/docker-compose.yml b/test/fixtures/docker-compose.yml index 3f68b91fc2..86e5cf8327 100644 --- a/test/fixtures/docker-compose.yml +++ b/test/fixtures/docker-compose.yml @@ -33,24 +33,24 @@ vp0: ports: - 7051:7051 -vp1: - image: hyperledger/fabric-peer - environment: - - CORE_PEER_ADDRESSAUTODETECT=true - - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - - CORE_LOGGING_LEVEL=DEBUG - - CORE_PEER_NETWORKID=${CORE_PEER_NETWORKID} - - CORE_NEXT=true - - CORE_PEER_ENDORSER_ENABLED=true - - CORE_PEER_ID=vp1 - - CORE_PEER_PROFILE_ENABLED=true - - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer:7050 - - CORE_PEER_DISCOVERY_ROOTNODE=vp0:7051 - volumes: - - /var/run/:/host/var/run/ - command: peer node start - links: - - orderer - - vp0 - ports: - - 7056:7051 +# vp1: +# image: hyperledger/fabric-peer +# environment: +# - CORE_PEER_ADDRESSAUTODETECT=true +# - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock +# - CORE_LOGGING_LEVEL=DEBUG +# - CORE_PEER_NETWORKID=${CORE_PEER_NETWORKID} +# - CORE_NEXT=true +# - CORE_PEER_ENDORSER_ENABLED=true +# - CORE_PEER_ID=vp1 +# - CORE_PEER_PROFILE_ENABLED=true +# - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer:7050 +# - CORE_PEER_DISCOVERY_ROOTNODE=vp0:7051 +# volumes: +# - /var/run/:/host/var/run/ +# command: peer node start +# links: +# - orderer +# - vp0 +# ports: +# - 7056:7051 diff --git a/test/unit/end-to-end.js b/test/unit/end-to-end.js index a04e088902..f91736bd42 100644 --- a/test/unit/end-to-end.js +++ b/test/unit/end-to-end.js @@ -31,7 +31,10 @@ var utils = require('hfc/lib/utils.js'); var chain = hfc.newChain('testChain-e2e'); var webUser; -var chaincode_id = 'mycc1'; +var chaincode_id = 'mycc2'; +var chain_id = '**TEST_CHAINID**'; +var tx_id = null; +var nonce = null; testUtil.setupChaincodeDeploy(); @@ -52,14 +55,19 @@ test('End-to-end flow of chaincode deploy, transaction invocation, and query', f function(admin) { t.pass('Successfully enrolled user \'admin\''); webUser = admin; + tx_id = hfc.buildTransactionID({length:12}); + nonce = hfc.getNonce(); // send proposal to endorser var request = { - targets: [hfc.getPeer('grpc://localhost:7051'), hfc.getPeer('grpc://localhost:7056')], + targets: [hfc.getPeer('grpc://localhost:7051')], // hfc.getPeer('grpc://localhost:7056')], chaincodePath: testUtil.CHAINCODE_PATH, chaincodeId: chaincode_id, fcn: 'init', args: ['a', '100', 'b', '200'], + chainId: chain_id, + txId: tx_id, + nonce: nonce, 'dockerfile-contents' : 'from hyperledger/fabric-ccenv\n' + 'COPY . $GOPATH/src/build-chaincode/\n' + @@ -78,9 +86,15 @@ test('End-to-end flow of chaincode deploy, transaction invocation, and query', f var proposalResponses = results[0]; //console.log('proposalResponses:'+JSON.stringify(proposalResponses)); var proposal = results[1]; + var header = results[2]; if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) { t.pass(util.format('Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s', proposalResponses[0].response.status, proposalResponses[0].response.message, proposalResponses[0].response.payload, proposalResponses[0].endorsement.signature)); - return webUser.sendTransaction(proposalResponses, proposal); + var request = { + proposalResponses: proposalResponses, + proposal: proposal, + header: header + }; + return webUser.sendTransaction(request); } else { t.fail('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'); t.end(); @@ -108,12 +122,17 @@ test('End-to-end flow of chaincode deploy, transaction invocation, and query', f } ).then( function() { + tx_id = hfc.buildTransactionID({length:12}); + nonce = hfc.getNonce(); // send proposal to endorser var request = { - targets: [hfc.getPeer('grpc://localhost:7051'), hfc.getPeer('grpc://localhost:7056')], + targets: [hfc.getPeer('grpc://localhost:7051')], // hfc.getPeer('grpc://localhost:7056')], chaincodeId : chaincode_id, fcn: 'invoke', - args: ['move', 'a', 'b','100'] + args: ['move', 'a', 'b','100'], + chainId: chain_id, + txId: tx_id, + nonce: nonce }; return webUser.sendTransactionProposal(request); }, @@ -125,9 +144,15 @@ test('End-to-end flow of chaincode deploy, transaction invocation, and query', f function(results) { var proposalResponses = results[0]; var proposal = results[1]; + var header = results[2]; if (proposalResponses[0].response.status === 200) { - t.pass('Successfully obtained transaction endorsement.' + JSON.stringify(proposalResponses)); - return webUser.sendTransaction(proposalResponses, proposal); + t.pass('Successfully obtained transaction endorsement.'); // + JSON.stringify(proposalResponses)); + var request = { + proposalResponses: proposalResponses, + proposal: proposal, + header: header + }; + return webUser.sendTransaction(request); } else { t.fail('Failed to obtain transaction endorsement. Error code: ' + status); t.end(); @@ -156,8 +181,11 @@ test('End-to-end flow of chaincode deploy, transaction invocation, and query', f function() { // send query var request = { - targets: [hfc.getPeer('grpc://localhost:7051'), hfc.getPeer('grpc://localhost:7056')], + targets: [hfc.getPeer('grpc://localhost:7051')], // hfc.getPeer('grpc://localhost:7056')], chaincodeId : chaincode_id, + chainId: chain_id, + txId: hfc.buildTransactionID(), + nonce: hfc.getNonce(), fcn: 'invoke', args: ['query','b'] }; diff --git a/test/unit/headless-tests.js b/test/unit/headless-tests.js index 44e637ac05..b533bbc441 100644 --- a/test/unit/headless-tests.js +++ b/test/unit/headless-tests.js @@ -567,13 +567,17 @@ test('\n\n ** Member sendDeploymentProposal() tests **\n\n', function (t) { var m = new Member('does not matter', _chain); var p1 = m.sendDeploymentProposal({ - chaincodePath: 'blah', + targets: [hfc.getPeer('grpc://localhost:7051')], chaincodeId: 'blah', - fcn: 'init' + fcn: 'init', + args: ['a', '100', 'b', '200'], + chainId: 'blah', + txId: 'blah', + nonce: 'blah' }).then(function () { t.fail('Should not have been able to resolve the promise because of missing "peer" parameter'); }).catch(function (err) { - if (err.message === 'Missing "targets" for the endorsing peer objects in the Deployment proposal request') { + if (err.message.indexOf('Missing chaincodePath parameter in Deployment proposal request') >= 0) { t.pass('Successfully caught missing peer error'); } else { t.fail('Failed to catch the missing peer error. Error: ' + err.stack ? err.stask : err); @@ -581,32 +585,106 @@ test('\n\n ** Member sendDeploymentProposal() tests **\n\n', function (t) { }); var p2 = m.sendDeploymentProposal({ - endorserUrl: 'blah', - fcn: 'init' + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodePath: 'blah', + chaincodeId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodePath" parameter'); + t.fail('Should not have been able to resolve the promise because of missing "chainId" parameter'); }).catch(function (err) { - if (err.message === 'Missing chaincodePath in Deployment proposal request') { - t.pass('Successfully caught missing chaincodePath error'); + if (err.message.indexOf('Missing "chainId" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing chainId error'); } else { - t.fail('Failed to catch the missing chaincodePath error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing chainId error. Error: ' + err.stack ? err.stask : err); } }); var p3 = m.sendDeploymentProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], chaincodePath: 'blah', - fcn: 'init' + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: '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 === 'Missing chaincodeId in the Deployment proposal request') { + 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.stask : err); } }); - Promise.all([p1, p2, p3]) + var p4 = m.sendDeploymentProposal({ + chaincodePath: 'blah', + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' + }).then(function () { + t.fail('Should not have been able to resolve the promise because of missing "targets" parameter'); + }).catch(function (err) { + if (err.message.indexOf('Missing "targets" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing targets error'); + } else { + t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); + } + }); + + var p5 = m.sendDeploymentProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodePath: 'blah', + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + nonce: 'blah' + }).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.stask : err); + } + }); + + var p6 = m.sendDeploymentProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodePath: 'blah', + chaincodeId: 'blah', + chainId: '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 "nonce" parameter'); + }).catch(function (err) { + if (err.message.indexOf('Missing "nonce" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing nonce error'); + } else { + t.fail('Failed to catch the missing nonce error. Error: ' + err.stack ? err.stask : err); + } + }); + + var p7 = m.sendDeploymentProposal().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.stask : err); + } + }); + + Promise.all([p1, p2, p3, p4, p6, p7]) .then( function (data) { t.end(); @@ -623,61 +701,118 @@ test('\n\n ** Member sendTransactionProposal() tests **\n\n', function (t) { var m = new Member('does not matter', _chain); var p1 = m.sendTransactionProposal({ - chaincodeId: 'someid' + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId : 'blah', + fcn: 'invoke', + chainId: 'blah', + txId: 'blah', + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "targets" parameter'); - }, function (err) { - if (err.message === 'Missing "targets" for endorser peer objects in the Transaction proposal request') { + t.fail('Should not have been able to resolve the promise because of missing "args" parameter'); + }).catch(function (err) { + if (err.message.indexOf('Missing "targets" for endorser peer objects in the Transaction proposal request')) { t.pass('Successfully caught missing targets error'); } else { t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); } + }); + + var p2 = m.sendTransactionProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' + }).then(function () { + t.fail('Should not have been able to resolve the promise because of missing "chainId" parameter'); }).catch(function (err) { - if (err.message === 'Missing "targets" for endorser peer objects in the Transaction proposal request') { - t.pass('Successfully caught missing targets error'); + if (err.message.indexOf('Missing "chainId" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing chainId error'); } else { - t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing chainId error. Error: ' + err.stack ? err.stask : err); } }); - var p2 = m.sendTransactionProposal({ - targets: [hfc.getPeer('grpc://somehost.com:9000')] + var p3 = m.sendTransactionProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodePath" parameter'); - }, function (err) { - if (err.message === 'Missing chaincodeId in the Transaction proposal request') { - t.pass('Successfully caught missing chaincodeid error'); + 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.stask : err); + t.fail('Failed to catch the missing chaincodeId error. Error: ' + err.stack ? err.stask : err); } + }); + + var p4 = m.sendTransactionProposal({ + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' + }).then(function () { + t.fail('Should not have been able to resolve the promise because of missing "targets" parameter'); }).catch(function (err) { - if (err.message === 'Missing chaincode ID in the Transaction proposal request') { - t.pass('Successfully caught missing chaincodeid error'); + if (err.message.indexOf('Missing "targets" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing targets error'); } else { - t.fail('Failed to catch the missing chaincodeid error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); } }); - var p3 = m.sendTransactionProposal({ - targets: [hfc.getPeer('grpc://somehost.com:9000')], - chaincodeId: 'someid' + var p5 = m.sendTransactionProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodePath" parameter'); - }, function (err) { - if (err.message === 'Missing arguments in Transaction proposal request') { - t.pass('Successfully caught missing args error'); + 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 args error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing txId error. Error: ' + err.stack ? err.stask : err); } + }); + + var p6 = m.sendTransactionProposal({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + chainId: '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 "nonce" parameter'); + }).catch(function (err) { + if (err.message.indexOf('Missing "nonce" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing nonce error'); + } else { + t.fail('Failed to catch the missing nonce error. Error: ' + err.stack ? err.stask : err); + } + }); + + var p7 = m.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 === 'Missing arguments in Transaction proposal request') { - t.pass('Successfully caught missing args error'); + 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 args error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing request error. Error: ' + err.stack ? err.stask : err); } }); - Promise.all([p1, p2, p3]) + Promise.all([p1, p2, p3, p4, p5, p6, p7]) .then( function (data) { t.end(); @@ -694,61 +829,118 @@ test('\n\n ** Member queryByChaincode() tests **\n\n', function (t) { var m = new Member('does not matter', _chain); var p1 = m.queryByChaincode({ - chaincodeId: 'someid' + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId : 'blah', + fcn: 'invoke', + chainId: 'blah', + txId: 'blah', + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "targets" parameter'); - }, function (err) { - if (err.message === 'Missing "targets" for endorser peer objects in the Transaction proposal request') { + t.fail('Should not have been able to resolve the promise because of missing "args" parameter'); + }).catch(function (err) { + if (err.message.indexOf('Missing "targets" for endorser peer objects in the Transaction proposal request')) { t.pass('Successfully caught missing targets error'); } else { t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); } + }); + + var p2 = m.queryByChaincode({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' + }).then(function () { + t.fail('Should not have been able to resolve the promise because of missing "chainId" parameter'); }).catch(function (err) { - if (err.message === 'Missing "targets" for endorser peer objects in the Transaction proposal request') { - t.pass('Successfully caught missing targets error'); + if (err.message.indexOf('Missing "chainId" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing chainId error'); } else { - t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing chainId error. Error: ' + err.stack ? err.stask : err); } }); - var p2 = m.queryByChaincode({ - targets: [hfc.getPeer('grpc://somehost.com:9000')] + var p3 = m.queryByChaincode({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodePath" parameter'); - }, function (err) { - if (err.message === 'Missing chaincodeId in the Transaction proposal request') { - t.pass('Successfully caught missing chaincodeid error'); + 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.stask : err); + t.fail('Failed to catch the missing chaincodeId error. Error: ' + err.stack ? err.stask : err); } + }); + + var p4 = m.queryByChaincode({ + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + txId: 'blah', + nonce: 'blah' + }).then(function () { + t.fail('Should not have been able to resolve the promise because of missing "targets" parameter'); }).catch(function (err) { - if (err.message === 'Missing chaincode ID in the Transaction proposal request') { - t.pass('Successfully caught missing chaincodeid error'); + if (err.message.indexOf('Missing "targets" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing targets error'); } else { - t.fail('Failed to catch the missing chaincodeid error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing targets error. Error: ' + err.stack ? err.stask : err); } }); - var p3 = m.queryByChaincode({ - targets: [hfc.getPeer('grpc://somehost.com:9000')], - chaincodeId: 'someid' + var p5 = m.queryByChaincode({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + chainId: 'blah', + fcn: 'init', + args: ['a', '100', 'b', '200'], + nonce: 'blah' }).then(function () { - t.fail('Should not have been able to resolve the promise because of missing "chaincodePath" parameter'); - }, function (err) { - if (err.message === 'Missing arguments in Transaction proposal request') { - t.pass('Successfully caught missing args error'); + 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 args error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing txId error. Error: ' + err.stack ? err.stask : err); } + }); + + var p6 = m.queryByChaincode({ + targets: [hfc.getPeer('grpc://localhost:7051')], + chaincodeId: 'blah', + chainId: '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 "nonce" parameter'); }).catch(function (err) { - if (err.message === 'Missing arguments in Transaction proposal request') { - t.pass('Successfully caught missing args error'); + if (err.message.indexOf('Missing "nonce" parameter in the proposal request') >= 0) { + t.pass('Successfully caught missing nonce error'); } else { - t.fail('Failed to catch the missing args error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing nonce error. Error: ' + err.stack ? err.stask : err); } }); - Promise.all([p1, p2, p3]) + var p7 = m.queryByChaincode().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.stask : err); + } + }); + + Promise.all([p1, p2, p3, p4, p5, p6, p7]) .then( function (data) { t.end(); @@ -768,36 +960,56 @@ test('\n\n ** Member sendTransaction() tests **\n\n', function (t) { .then(function () { t.fail('Should not have been able to resolve the promise because of missing parameters'); }, function (err) { - if (err.message === 'Missing proposalResponse object parameter') { + 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.stask : err); + } + }); + + var p2 = m.sendTransaction({ + proposal: 'blah', + header: '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 "proposalResponse" parameter in transaction request') >= 0) { t.pass('Successfully caught missing proposalResponse error'); } else { - t.fail('Failed to catch the missing object error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing proposalResponse error. Error: ' + err.stack ? err.stask : err); } }); - var p2 = m.sendTransaction('data') + var p3 = m.sendTransaction({ + proposalResponses: 'blah', + header: 'blah' + }) .then(function () { t.fail('Should not have been able to resolve the promise because of missing parameters'); }, function (err) { - if (err.message === 'Missing chaincodeProposal object parameter') { - t.pass('Successfully caught missing chaincodeProposal error'); + 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 objet error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing proposal error. Error: ' + err.stack ? err.stask : err); } }); - var p3 = m.sendTransaction('data', 'data') + var p4 = m.sendTransaction({ + proposalResponses: 'blah', + proposal: 'blah' + }) .then(function () { t.fail('Should not have been able to resolve the promise because of missing parameters'); }, function (err) { - if (err.message === 'no Orderer defined') { - t.pass('Successfully caught missing orderer error'); + if (err.message.indexOf('Missing "header" parameter in transaction request') >= 0) { + t.pass('Successfully caught missing header error'); } else { - t.fail('Failed to catch the missing order error. Error: ' + err.stack ? err.stask : err); + t.fail('Failed to catch the missing header error. Error: ' + err.stack ? err.stask : err); } }); - Promise.all([p1, p2, p3]) + Promise.all([p1, p2, p3, p4]) .then( function (data) { t.end(); @@ -822,6 +1034,13 @@ var TEST_LONG_MSG = 'The Hyperledger project is an open source collaborative eff 'ensure the transparency, longevity, interoperability and support required to bring blockchain technologies forward to mainstream commercial adoption. That ' + 'is what Hyperledger is about – communities of software developers building blockchain frameworks and platforms.'; +var HASH_MSG_SHA3_384 = '9e9c2e5edf6cbc0b512807a8efa2917daff71b83e04dee28fcc00b1a1dd935fb5afc5eafa06bf55bd64792a597e2a8f3'; +var HASH_LONG_MSG_SHA3_384 = '47a90d6721523682e09b81da0a60e6ee1faf839f0503252316638daf038cf682c0a842edaf310eb0f480a2e181a07af0'; +var HASH_MSG_SHA256 = '4e4aa09b6d80efbd684e80f54a70c1d8605625c3380f4cb012b32644a002b5be'; +var HASH_LONG_MSG_SHA256 = '0d98987f5e4e3ea611f0e3d768c594ff9aac25404265d73554d12c86d7f6fbbc'; +var HASH_MSG_SHA3_256 = '7daeff454f7e91e3cd2d1c1bd5fcd1b6c9d4d5fffc6c327710d8fae7b06ee4a3'; +var HASH_LONG_MSG_SHA3_256 = '577174210438a85ae4311a62e5fccf2441b960013f5691993cdf38ed6ba0c84f'; + var TEST_KEY_PRIVATE = '93f15b31e3c3f3bddcd776d9219e93d8559e31453757b79e193a793cbd239573'; var TEST_KEY_PUBLIC = '04f46815aa00fe2ba2814b906aa4ef1755caf152658de8997a6a858088296054baf45b06b2eba514bcbc37ae0c0cc7465115d36429d0e0bff23dc40e3760c10aa9'; var TEST_MSG_SIGNATURE_SHA2_256 = '3046022100a6460b29373fa16ee96172bfe04666140405fdef78182280545d451f08547736022100d9022fe620ceadabbef1714b894b8d6be4b74c0f9c573bd774871764f4f789c9'; @@ -842,20 +1061,20 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) { t.equal(true, (typeof cryptoUtils._ecdsaCurve !== 'undefined' && typeof cryptoUtils._ecdsa !== 'undefined'), 'CryptoSuite_ECDSA_AES function tests: default instance has "_ecdsaCurve" and "_ecdsa" properties'); - // test default curve 384 with SHA3_384 - t.equal(cryptoUtils.hash(TEST_MSG), '9e9c2e5edf6cbc0b512807a8efa2917daff71b83e04dee28fcc00b1a1dd935fb5afc5eafa06bf55bd64792a597e2a8f3', - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with default key size which should be 384'); + // test default curve 256 with SHA256 + t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA256, + 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with default key size which should be 256'); - t.equal(cryptoUtils.hash(TEST_LONG_MSG), '47a90d6721523682e09b81da0a60e6ee1faf839f0503252316638daf038cf682c0a842edaf310eb0f480a2e181a07af0', - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with default key size which should be 384'); + t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA256, + 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with default key size which should be 256'); cryptoUtils.generateKey() .then(function (key) { - t.equal('secp384r1', key.getPublicKey()._key.curveName, - 'CryptoSuite_ECDSA_AES constructor tests: cryptoUtils generated public key curveName == secp384r1'); + t.equal('secp256r1', key.getPublicKey()._key.curveName, + 'CryptoSuite_ECDSA_AES constructor tests: cryptoUtils generated public key curveName == secp256r1'); // test curve 256 with SHA3_256 - utils.setConfigSetting('crypto-keysize', 256); + utils.setConfigSetting('crypto-hash-algo', 'SHA3'); cryptoUtils = utils.getCryptoSuite(); return cryptoUtils.generateKey(); }) @@ -863,26 +1082,28 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) { t.equal('secp256r1', key.getPublicKey()._key.curveName, 'CryptoSuite_ECDSA_AES constructor tests: ccryptoUtils generated public key curveName == secp256r1'); - t.equal(cryptoUtils.hash(TEST_MSG), '7daeff454f7e91e3cd2d1c1bd5fcd1b6c9d4d5fffc6c327710d8fae7b06ee4a3', + t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_256, 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 256'); - t.equal(cryptoUtils.hash(TEST_LONG_MSG), '577174210438a85ae4311a62e5fccf2441b960013f5691993cdf38ed6ba0c84f', + t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA3_256, 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 256'); - // test SHA2_256 - utils.setConfigSetting('crypto-hash-algo', 'SHA2'); + // test SHA3_384 + utils.setConfigSetting('crypto-keysize', 384); cryptoUtils = utils.getCryptoSuite(); - t.equal(cryptoUtils.hash(TEST_MSG), '4e4aa09b6d80efbd684e80f54a70c1d8605625c3380f4cb012b32644a002b5be', - 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with key size 256'); - - t.equal(cryptoUtils.hash(TEST_LONG_MSG), '0d98987f5e4e3ea611f0e3d768c594ff9aac25404265d73554d12c86d7f6fbbc', - 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with key size 256'); + t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_384, + 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with key size 384'); + t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA3_384, + 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with key size 384'); return cryptoUtils.generateKey(); }) .then(function (key) { + t.equal('secp384r1', key.getPublicKey()._key.curveName, + 'CryptoSuite_ECDSA_AES constructor tests: ccryptoUtils generated public key curveName == secp384r1'); + if (!!key._key) t.pass('CryptoSuite_ECDSA_AES function tests: verify generateKey return object'); else @@ -890,8 +1111,8 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', function (t) { utils.setConfigSetting('crypto-hash-algo', 'sha3'); //lower or upper case is allowed cryptoUtils = utils.getCryptoSuite(); - t.equal(cryptoUtils.hash(TEST_MSG), '7daeff454f7e91e3cd2d1c1bd5fcd1b6c9d4d5fffc6c327710d8fae7b06ee4a3', - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 256'); + t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_384, + 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 384'); // test generation options return cryptoUtils.generateKey({ ephemeral: true }); diff --git a/test/unit/util.js b/test/unit/util.js index 66afc34ea2..4158132b0f 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -1,4 +1,6 @@ var path = require('path'); +var copService = require('hfc-cop/lib/FabricCOPImpl.js'); +var Member = require('hfc/lib/Member.js'); module.exports.CHAINCODE_PATH = 'github.com/example_cc'; module.exports.CHAINCODE_MARBLES_PATH = 'github.com/marbles_cc';