diff --git a/build/tasks/test.js b/build/tasks/test.js index b3afd45510..cfad4f8648 100644 --- a/build/tasks/test.js +++ b/build/tasks/test.js @@ -145,11 +145,12 @@ gulp.task('test', ['clean-up', 'lint', 'pre-test', 'compile', 'docker-ready', 'c 'test/integration/e2e/invoke-transaction.js', 'test/integration/e2e/query.js', 'test/integration/invoke.js', - 'test/integration/perf/orderer.js', - 'test/integration/perf/peer.js', 'test/integration/network-config.js', // channel: mychannel, chaincode: e2enodecc:v0 - 'test/integration/nodechaincode/e2e.js' + 'test/integration/nodechaincode/e2e.js', + 'test/integration/only-admin.js', + 'test/integration/perf/orderer.js', + 'test/integration/perf/peer.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 65b418fa40..1654424f63 100755 --- a/fabric-client/lib/Channel.js +++ b/fabric-client/lib/Channel.js @@ -653,8 +653,8 @@ var Channel = class { var self = this; var orderer = this._clientContext.getTargetOrderer(null, this._orderers, this._name); - var signer = this._clientContext._getSigningIdentity(); - var txId = new TransactionID(signer); + var signer = this._clientContext._getSigningIdentity(true); + var txId = new TransactionID(signer, true); // seek the latest block var seekSpecifiedStart = new _abProto.SeekNewest(); diff --git a/fabric-client/lib/ChannelEventHub.js b/fabric-client/lib/ChannelEventHub.js index 3776402e9c..07a8ec9a08 100644 --- a/fabric-client/lib/ChannelEventHub.js +++ b/fabric-client/lib/ChannelEventHub.js @@ -256,8 +256,8 @@ var ChannelEventHub = class { */ connect(full_block){ logger.debug('connect - start'); - if (!this._clientContext._userContext) { - throw new Error('The clientContext has not been properly initialized, missing userContext'); + if (!this._clientContext._userContext && !this._clientContext._adminSigningIdentity) { + throw new Error('The clientContext has not been properly initialized, missing userContext or admin identity'); } if(typeof full_block === 'boolean') { @@ -499,8 +499,8 @@ var ChannelEventHub = class { // the blocks come in // FAIL_IF_NOT_READY will mean if the block is not there throw an error seekInfo.setBehavior(_abProto.SeekInfo.SeekBehavior.BLOCK_UNTIL_READY); - let tx_id = this._clientContext.newTransactionID(); - let signer = this._clientContext._getSigningIdentity(); + let tx_id = this._clientContext.newTransactionID(true); + let signer = this._clientContext._getSigningIdentity(true); // build the header for use with the seekInfo payload let seekInfoHeader = clientUtils.buildChannelHeader( diff --git a/test/fixtures/channel/adminconfig.tx b/test/fixtures/channel/adminconfig.tx new file mode 100644 index 0000000000..0582170f75 Binary files /dev/null and b/test/fixtures/channel/adminconfig.tx differ diff --git a/test/fixtures/network-ad.yaml b/test/fixtures/network-ad.yaml new file mode 100644 index 0000000000..8d01a62015 --- /dev/null +++ b/test/fixtures/network-ad.yaml @@ -0,0 +1,89 @@ +name: "global-trade-network" +description: "The network to be in if you want to stay in the global trade business" +version: "1.0" + +channels: + adminconfig: + orderers: + - orderer.example.com + peers: + peer0.org1.example.com: + endorsingPeer: true + chaincodeQuery: true + ledgerQuery: true + eventSource: true + peer0.org2.example.com: + endorsingPeer: true + chaincodeQuery: false + ledgerQuery: true + eventSource: true + +organizations: + Org1: + mspid: Org1MSP + + peers: + - peer0.org1.example.com + certificateAuthorities: + - ca-org1 + adminPrivateKey: + path: test/fixtures/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/keystore/9022d671ceedbb24af3ea69b5a8136cc64203df6b9920e26f48123fcfcb1d2e9_sk + signedCert: + path: test/fixtures/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/signcerts/Admin@org1.example.com-cert.pem + Org2: + mspid: Org2MSP + peers: + - peer0.org2.example.com + certificateAuthorities: + - ca-org2 + adminPrivateKey: + path: test/fixtures/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/keystore/5a983ddcbefe52a7f9b8ee5b85a590c3e3a43c4ccd70c7795bec504e7f74848d_sk + signedCert: + path: test/fixtures/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/signcerts/Admin@org2.example.com-cert.pem +orderers: + orderer.example.com: + url: grpcs://localhost:7050 + grpcOptions: + ssl-target-name-override: orderer.example.com + grpc-max-send-message-length: 15 + + tlsCACerts: + path: test/fixtures/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tlscacerts/example.com-cert.pem +peers: + peer0.org1.example.com: + url: grpcs://localhost:7051 + grpcOptions: + ssl-target-name-override: peer0.org1.example.com + grpc.http2.keepalive_time: 15 + tlsCACerts: + path: test/fixtures/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tlscacerts/org1.example.com-cert.pem + + peer0.org2.example.com: + url: grpcs://localhost:8051 + grpcOptions: + ssl-target-name-override: peer0.org2.example.com + tlsCACerts: + path: test/fixtures/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tlscacerts/org2.example.com-cert.pem + +certificateAuthorities: + ca-org1: + url: https://localhost:7054 + httpOptions: + verify: false + tlsCACerts: + path: test/fixtures/channel/crypto-config/peerOrganizations/org1.example.com/ca/org1.example.com-cert.pem + registrar: + - enrollId: admin + enrollSecret: adminpw + caName: ca-org1 + + ca-org2: + url: https://localhost:8054 + httpOptions: + verify: false + tlsCACerts: + path: test/fixtures/channel/crypto-config/peerOrganizations/org2.example.com/ca/org2.example.com-cert.pem + registrar: + - enrollId: admin + enrollSecret: adminpw + caName: ca-org2 diff --git a/test/integration/e2e/create-channel.js b/test/integration/e2e/create-channel.js index 832429e1b5..7c1521701b 100644 --- a/test/integration/e2e/create-channel.js +++ b/test/integration/e2e/create-channel.js @@ -26,16 +26,10 @@ var Client = require('fabric-client'); var util = require('util'); var fs = require('fs'); var path = require('path'); -var grpc = require('grpc'); - -var _commonProto = grpc.load(path.join(__dirname, '../../../fabric-client/lib/protos/common/common.proto')).common; -var _configtxProto = grpc.load(path.join(__dirname, '../../../fabric-client/lib/protos/common/configtx.proto')).common; var testUtil = require('../../unit/util.js'); var e2eUtils = require('./e2eUtils.js'); -var the_user = null; - var ORGS; var channel_name = 'mychannel'; @@ -54,51 +48,15 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { Client.addConfigFile(path.join(__dirname, './config.json')); ORGS = Client.getConfigSetting('test-network'); - // - // Create and configure the test channel - // var client = new Client(); var caRootsPath = ORGS.orderer.tls_cacerts; let data = fs.readFileSync(path.join(__dirname, caRootsPath)); let caroots = Buffer.from(data).toString(); - var TWO_ORG_MEMBERS_AND_ADMIN = [{ - role: { - name: 'member', - mspId: 'Org1MSP' - } - }, { - role: { - name: 'member', - mspId: 'Org2MSP' - } - }, { - role: { - name: 'admin', - mspId: 'OrdererMSP' - } - }]; - - var ONE_OF_TWO_ORG_MEMBER = { - identities: TWO_ORG_MEMBERS_AND_ADMIN, - policy: { - '1-of': [{ 'signed-by': 0 }, { 'signed-by': 1 }] - } - }; - - var ACCEPT_ALL = { - identities: [], - policy: { - '0-of': [] - } - }; - var config = null; var signatures = []; var orderer = null; - var orderer_bad = null; - var orderer_bad2 = null; var tlsInfo = null; // Acting as a client in org1 when creating the channel @@ -117,53 +75,11 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { cryptoSuite.setCryptoKeyStore(Client.newCryptoKeyStore({path: testUtil.storePathForOrg(org)})); client.setCryptoSuite(cryptoSuite); - return testUtil.getOrderAdminSubmitter(client, t); - }).then((admin) =>{ - t.pass('Successfully enrolled user \'admin\' for orderer (create_channel 1)'); - - orderer = client.newOrderer( - ORGS.orderer.url, - { - 'pem': caroots, - 'clientCert': tlsInfo.certificate, - 'clientKey': tlsInfo.key, - 'ssl-target-name-override': ORGS.orderer['server-hostname'] - } - ); - - orderer_bad = client.newOrderer( - ORGS.orderer.url, - { - 'pem': caroots, - 'clientCert': tlsInfo.certificate, - 'clientKey': tlsInfo.key, - 'ssl-target-name-override': ORGS.orderer['server-hostname'], - 'grpc.max_send_message_length': 6800 - } - ); - - // set something to fail to test that the code picks up values from the config - let keep = Client.getConfigSetting('grpc.max_send_message_length'); - Client.setConfigSetting('grpc.max_send_message_length', 6800); - orderer_bad2 = client.newOrderer( - ORGS.orderer.url, - { - 'pem': caroots, - 'clientCert': tlsInfo.certificate, - 'clientKey': tlsInfo.key, - 'ssl-target-name-override': ORGS.orderer['server-hostname'], - 'grpc.max_send_message_length': 6800 - } - ); - // put back the setting - Client.setConfigSetting('grpc.max_send_message_length',keep); - // use the config update created by the configtx tool let envelope_bytes = fs.readFileSync(path.join(__dirname, '../../fixtures/channel/mychannel.tx')); config = client.extractChannelConfig(envelope_bytes); t.pass('Successfull extracted the config update from the configtx envelope'); - client._userContext = null; return testUtil.getSubmitter(client, t, true /*get the org admin*/, 'org1'); }).then((admin) => { t.pass('Successfully enrolled user \'admin\' for org1'); @@ -174,15 +90,10 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { // fabric-client SDK will convert back during create var string_signature = signature.toBuffer().toString('hex'); t.pass('Successfully signed config update'); + // collect signature from org1 admin - // TODO: signature counting against policies on the orderer - // at the moment is being investigated, but it requires this - // weird double-signature from each org admin - signatures.push(string_signature); signatures.push(string_signature); - // make sure we do not reuse the user - client._userContext = null; return testUtil.getSubmitter(client, t, true /*get the org admin*/, 'org2'); }).then((admin) => { t.pass('Successfully enrolled user \'admin\' for org2'); @@ -192,35 +103,23 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { t.pass('Successfully signed config update'); // collect signature from org2 admin - // TODO: signature counting against policies on the orderer - // at the moment is being investigated, but it requires this - // weird double-signature from each org admin - signatures.push(signature); signatures.push(signature); - // make sure we do not reuse the user - client._userContext = null; return testUtil.getOrderAdminSubmitter(client, t); }).then((admin) => { - t.pass('Successfully enrolled user \'admin\' for orderer (create_channel 2)'); - the_user = admin; - - // sign the config - var signature = client.signChannelConfig(config); - t.pass('Successfully signed config update'); + t.pass('Successfully enrolled user \'admin\' for orderer'); - // collect signature from orderer org admin - // TODO: signature counting against policies on the orderer - // at the moment is being investigated, but it requires this - // weird double-signature from each org admin - signatures.push(signature); - signatures.push(signature); - - logger.debug('\n***\n done signing \n***\n'); + let orderer_bad = client.newOrderer( + ORGS.orderer.url, + { + 'pem': caroots, + 'clientCert': tlsInfo.certificate, + 'clientKey': tlsInfo.key, + 'ssl-target-name-override': ORGS.orderer['server-hostname'], + 'grpc.max_send_message_length': 1000 //something too small for the request + } + ); - // build up a create request to include - // an orderer that will fail because the - // orderer is defined with a bad options value let tx_id = client.newTransactionID(); var request = { config: config, @@ -233,51 +132,40 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { // send create request to bad orderer return client.createChannel(request); }).then((result) => { - logger.debug('\n***\n completed the create \n***\n'); + logger.debug('\n***\n completed the create successfully with an orderer with a bad max send size \n***\n'); logger.debug(' response ::%j',result); - t.fail('Failed when this Successfully created the channel.'); - t.end(); + t.fail('Failed when successfully created the channel with a bad max send size'); throw new Error('Failed to get max send error'); }, (err) => { if(err.toString().indexOf('Sent message larger than max') > -1) { t.pass('Successfully failed with max error on the create channel: ' + err.toString()); } else { t.fail('Failed to fail with max error on the create channel: ' + err.stack ? err.stack : err); + throw new Error('Failed'); } return true; }).then((nothing) => { - // build up a create request to - // an orderer that will fail - let tx_id = client.newTransactionID(); - var request = { - config: config, - signatures : signatures, - name : channel_name, - orderer : orderer_bad2, - txId : tx_id - }; - - // send create request to bad orderer - return client.createChannel(request); - }).then((result) => { - logger.debug('\n***\n completed the create \n***\n'); + orderer = client.newOrderer( + ORGS.orderer.url, + { + 'pem': caroots, + 'clientCert': tlsInfo.certificate, + 'clientKey': tlsInfo.key, + 'ssl-target-name-override': ORGS.orderer['server-hostname'] + } + ); - logger.debug(' response ::%j',result); - t.fail('Failed when this Successfully created the channel.'); - t.end(); - throw new Error('Failed to get max send error'); - }, (err) => { - if(err.toString().indexOf('Sent message larger than max') > -1) { - t.pass('Successfully failed with max error on the create channel: ' + err.toString()); - } else { - t.fail('Failed to fail with max error on the create channel: ' + err.stack ? err.stack : err); - } + // let's try to get some info from the orderer + // Get the system channel config decoded + let sys_channel = client.newChannel('testchainid'); + sys_channel.addOrderer(orderer); + return sys_channel.getChannelConfigFromOrderer(); + }).then((config_envelope) => { + t.pass('Successfully received the configuration'); - return true; - }).then((nothing) => { // build up the create request let tx_id = client.newTransactionID(); var request = { @@ -299,16 +187,13 @@ test('\n\n***** SDK Built config update create flow *****\n\n', function(t) { return e2eUtils.sleep(5000); } else { t.fail('Failed to create the channel. '); - t.end(); + throw new Error('Failed'); } - }, (err) => { - t.fail('Failed to create the channel: ' + err.stack ? err.stack : err); - t.end(); }).then((nothing) => { t.pass('Successfully waited to make sure new channel was created.'); t.end(); - }, (err) => { - t.fail('Failed to sleep due to error: ' + err.stack ? err.stack : err); + }).catch((err)=> { + t.fail('Failed error: ' + err.stack ? err.stack : err); t.end(); }); }); diff --git a/test/integration/network-config.js b/test/integration/network-config.js index 7a24b8741d..6a437509ee 100644 --- a/test/integration/network-config.js +++ b/test/integration/network-config.js @@ -73,28 +73,33 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // this connection profile 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'); + var client_org1 = Client.loadFromConfig('test/fixtures/network.yaml'); + var client_org2 = Client.loadFromConfig('test/fixtures/network.yaml'); t.pass('Successfully loaded a connection profile'); var config = null; var signatures = []; var genesis_block = null; - var channel = null; + var channel_on_org1 = null; + var channel_on_org2 = null; var query_tx_id = null; var instansiate_tx_id = null; // Load the client information for an organization. // The file only has the client section. // A real application might do this when a new user logs in. - client.loadFromConfig('test/fixtures/org1.yaml'); + client_org1.loadFromConfig('test/fixtures/org1.yaml'); + client_org2.loadFromConfig('test/fixtures/org2.yaml'); // tell this client instance where the state and key stores are located - client.initCredentialStores() + client_org1.initCredentialStores() .then((nothing) => { t.pass('Successfully created the key value store and crypto store based on the sdk config and connection profile'); // get the CA associated with this client's organization - let caService = client.getCertificateAuthority(); + let caService = client_org1.getCertificateAuthority(); + t.equals(caService._fabricCAClient._caName,'ca-org1', 'checking that caname is correct after resetting the config'); + let request = { enrollmentID: 'admin', enrollmentSecret: 'adminpw', @@ -107,14 +112,36 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { let cert = enrollment.certificate; // set the material on the client to be used when building endpoints for the user - client.setTlsClientCertAndKey(cert, key); + client_org1.setTlsClientCertAndKey(cert, key); + + // tell this client instance where the state and key stores are located + return client_org2.initCredentialStores(); + }).then((nothing) => { + t.pass('Successfully created the key value store and crypto store based on the sdk config and connection profile'); + + // get the CA associated with this client's organization + let caService = client_org2.getCertificateAuthority(); + t.equals(caService._fabricCAClient._caName,'ca-org2', 'checking that caname is correct after resetting the config'); + let request = { + enrollmentID: 'admin', + enrollmentSecret: 'adminpw', + profile: 'tls' + }; + return caService.enroll(request); + }).then((enrollment) => { + t.pass('Successfully called the CertificateAuthority to get the TLS material'); + let key = enrollment.key.toBytes(); + let cert = enrollment.certificate; + + // set the material on the client to be used when building endpoints for the user + client_org2.setTlsClientCertAndKey(cert, key); // 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 + // have the sdk get the config update object from the envelope generated by configtxgen // the config update object is what is required to be signed by all // participating organizations - config = client.extractChannelConfig(envelope_bytes); + config = client_org1.extractChannelConfig(envelope_bytes); t.pass('Successfully extracted the config update from the configtx envelope'); // Sign the config bytes @@ -124,39 +151,21 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // connection profile that has a client section that also has // an admin defined for the organization defined in that client // section it will be automatically assigned to the client instance. - let signature = client.signChannelConfig(config); + let signature1 = client_org1.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 - let string_signature = signature.toBuffer().toString('hex'); + let string_signature1 = signature1.toBuffer().toString('hex'); t.pass('Successfully signed config update by org1'); // collect signature from org1 admin - signatures.push(string_signature); - - /* - * Switch to organization org2 by loading a different connection profile. - * The file only has the client section. - * A real application might do this when a new user logs in to put - * the client instance in that user's organization. Note that - * the loadFromConfig() can also take a JSON object rather than a file - * location. - */ - - return client.loadFromConfig('test/fixtures/org2.yaml'); - }).then((nothing) =>{ - t.pass('Successfully loaded the client configuration for org2'); - - // reset the stores to the loaded organization's locations - return client.initCredentialStores(); - }).then((nothing) =>{ - t.pass('Successfully set the stores for org2'); + signatures.push(string_signature1); // sign the config by admin from org2 - let signature = client.signChannelConfig(config); + let signature2 = client_org2.signChannelConfig(config); t.pass('Successfully signed config update for org2'); // collect the signature from org2's admin - signatures.push(signature); + signatures.push(signature2); // now we have enough signatures... @@ -166,7 +175,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // client part of the connection profile, otherwise the setAdminSigningIdentity() // method would need to be called to setup the admin. If no admin is in the config // or has been assigned the transaction will based on the current user. - let tx_id = client.newTransactionID(true); + let tx_id = client_org2.newTransactionID(true); // build up the create request let request = { config: config, @@ -177,7 +186,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { }; // send create request to orderer - return client.createChannel(request); //logged in as org2 + return client_org2.createChannel(request); //admin from org2 }).then((result) => { logger.debug('\n***\n completed the create \n***\n'); @@ -190,23 +199,24 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { throw new Error('Failed to create the channel. '); } }).then((nothing) => { - t.pass('Successfully waited to make sure new channel was created.'); + t.pass('Successfully waited to make sure new channel was created on orderer.'); - // have the client build a channel with all peers and orderers - channel = client.getChannel(channel_name); + // have the clients build a channel with all peers and orderers + channel_on_org1 = client_org1.getChannel(channel_name); + channel_on_org2 = client_org2.getChannel(channel_name); // get an admin based transaction - let tx_id = client.newTransactionID(true); + let tx_id = client_org2.newTransactionID(true); let request = { txId : tx_id }; - return channel.getGenesisBlock(request); //admin from org2 + return channel_on_org2.getGenesisBlock(request); //admin from org2 }).then((block) =>{ t.pass('Successfully got the genesis block'); genesis_block = block; - let tx_id = client.newTransactionID(true); + let tx_id = client_org2.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 @@ -215,7 +225,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { txId : tx_id }; - return channel.joinChannel(request); //admin from org2 + return channel_on_org2.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)); @@ -235,17 +245,8 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { 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 connection profile'); - let tx_id = client.newTransactionID(true); + let tx_id = client_org1.newTransactionID(true); let request = { targets: ['peer0.org1.example.com'], // this does assume that we have loaded a // connection profile with a peer by this name @@ -253,7 +254,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { txId : tx_id }; - return channel.joinChannel(request); //logged in as org1 + return channel_on_org1.joinChannel(request); }).then((results) => { logger.debug(util.format('Join Channel R E S P O N S E for a string target: %j', results)); @@ -268,19 +269,18 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { t.pass('Successfully waited for peers to join the channel'); process.env.GOPATH = path.join(__dirname, '../fixtures'); - let tx_id = client.newTransactionID(true); + let tx_id = client_org1.newTransactionID(true); // send proposal to endorser let request = { - //targets: ['peer0.org1.example.com'] + //targets: get peers for this clients organization chaincodePath: 'github.com/example_cc', chaincodeId: 'example', chaincodeVersion: 'v1', chaincodePackage: '', - channelNames : 'mychannel2', //targets will based on peers in this channel txId : tx_id }; - return client.installChaincode(request); //still logged as org1 + return client_org1.installChaincode(request); }).then((results) => { if(results && results[0] && results[0][0].response && results[0][0].response.status == 200) { t.pass('Successfully installed chain code on org1'); @@ -289,17 +289,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { 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 connection profile'); - - let tx_id = client.newTransactionID(true); // be sure to get a admin transaction ID + let tx_id = client_org2.newTransactionID(true); // be sure to get a admin transaction ID // send proposal to endorser let request = { targets: ['peer0.org2.example.com'], @@ -310,7 +300,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { txId : tx_id }; - return client.installChaincode(request); // org2 admin is the signer + return client_org2.installChaincode(request); }).then((results) => { if(results && results[0] && results[0][0].response && results[0][0].response.status == 200) { t.pass('Successfully installed chain code on org2'); @@ -323,7 +313,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { * I N S T A N S I A T E */ - let tx_id = client.newTransactionID(true); + let tx_id = client_org1.newTransactionID(true); instansiate_tx_id = tx_id; let request = { chaincodeId: 'example', @@ -335,7 +325,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { //targets: ['peer0.org1.example.com'], }; - return channel.sendInstantiateProposal(request); // still have org2 admin signer + return channel_on_org1.sendInstantiateProposal(request); }).then((results) => { var proposalResponses = results[0]; var proposal = results[1]; @@ -349,7 +339,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // connection profile for this channel will be used }; - return channel.sendTransaction(request); // still have org2 admin as signer + return channel_on_org1.sendTransaction(request); } 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...'); @@ -365,57 +355,23 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { }).then((results) => { t.pass('Successfully waited for chaincode to startup'); - /* - * S T A R T U S I N G - */ - /* - * 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 connection profile'); - - let ca = client.getCertificateAuthority(); - if(ca) { - t.equals(ca._fabricCAClient._caName,'ca-org2', 'checking that caname is correct for the newly created ca'); - } else { - t.fail('Failed - CertificateAuthority should have been created'); - } - - /* - * switch to organization org1 - */ - client.loadFromConfig('test/fixtures/org1.yaml'); - t.pass('Successfully loaded config for org1'); - - return client.initCredentialStores(); - }).then((nothing) => { - t.pass('Successfully created the key value store and crypto store based on the config and network'); - - return client.setUserContext({username:'admin', password:'adminpw'}); + // this will enroll the user using the ca as defined in the connection profile + // for this organization and then set in on the client as the current user context + return client_org1.setUserContext({username:'admin', password:'adminpw'}); }).then((admin) => { t.pass('Successfully enrolled user \'admin\' for org1'); - let ca = client.getCertificateAuthority(); - if(ca) { - t.equals(ca._fabricCAClient._caName,'ca-org1', 'checking that caname is correct after resetting the config'); - } else { - t.fail('Failed - CertificateAuthority should have been created'); - } - - return ca.register({enrollmentID: 'user1', affiliation: 'org1'}, admin); + let ca1 = client_org1.getCertificateAuthority(); + return ca1.register({enrollmentID: 'user1', affiliation: 'org1'}, admin); }).then((secret) => { t.pass('Successfully registered user \'user1\' for org1'); - return client.setUserContext({username:'user1', password:secret}); + return client_org1.setUserContext({username:'user1', password:secret}); }).then((user)=> { t.pass('Successfully enrolled user \'user1\' for org1'); // try again ...this time use a longer timeout - let tx_id = client.newTransactionID(); // get a non admin transaction ID + let tx_id = client_org1.newTransactionID(); // get a non admin transaction ID query_tx_id = tx_id.getTransactionID(); //save transaction string for later let request = { chaincodeId : 'example', @@ -425,7 +381,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { //targets - Letting default to all endorsing peers defined on the channel in the connection profile }; - return channel.sendTransactionProposal(request); //logged in as org1 user + return channel_on_org1.sendTransactionProposal(request); //logged in as org1 user }).then((results) => { let proposalResponses = results[0]; let proposal = results[1]; @@ -466,7 +422,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { let promises = []; // be sure to get an channel event hub the current user is authorized to use - let eventhub = channel.newChannelEventHub('peer0.org1.example.com'); + let eventhub = channel_on_org1.newChannelEventHub('peer0.org1.example.com'); let txPromise = new Promise((resolve, reject) => { let handle = setTimeout(() => { @@ -499,7 +455,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { eventhub.connect(true); promises.push(txPromise); - promises.push(channel.sendTransaction(request)); + promises.push(channel_on_org1.sendTransaction(request)); return Promise.all(promises); }).then((results) => { @@ -520,7 +476,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // with startBlock or endBlock when doing a replay // The ChannelEventHub must not have been connected or have other // listeners. - let channel_event_hub = channel.newChannelEventHub('peer0.org1.example.com'); + let channel_event_hub = channel_on_org1.newChannelEventHub('peer0.org1.example.com'); let handle = setTimeout(() => { t.fail('Timeout - Failed to receive replay the event for event1'); @@ -559,7 +515,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // a different port than the peer services. The peers with the // "eventSource" tag are running the channel-based event service // on the same port as the other peer services. - let channel_event_hubs = channel.getChannelEventHubsForOrg(); + let channel_event_hubs = channel_on_org1.getChannelEventHubsForOrg(); // we should have the an channel event hub defined on the "peer0.org1.example.com" t.equals(channel_event_hubs.length,1,'Checking that the channel event hubs has just one'); @@ -597,7 +553,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { // check that we can get the user again without password // also verifies that we can get a complete user properly stored // when using a connection profile - return client.setUserContext({username:'admin'}); + return client_org1.setUserContext({username:'admin'}); }).then((admin) => { t.pass('Successfully loaded user \'admin\' from store for org1'); @@ -607,7 +563,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { args: ['b'] }; - return channel.queryByChaincode(request); //logged in as user on org1 + return channel_on_org1.queryByChaincode(request); //logged in as user on org1 }).then((response_payloads) => { // should only be one response ...as only one peer is defined as CHAINCODE_QUERY_ROLE var query_responses = 0; @@ -625,7 +581,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { } t.equals(query_responses,1,'Checking that only one response was seen'); - return client.queryChannels('peer0.org1.example.com'); + return client_org1.queryChannels('peer0.org1.example.com'); }).then((results) => { logger.debug(' queryChannels ::%j',results); let found = false; @@ -641,7 +597,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { t.fail('Failed to find our channel in the result list'); } - return client.queryInstalledChaincodes('peer0.org1.example.com', true); // use admin + return client_org1.queryInstalledChaincodes('peer0.org1.example.com', true); // use admin }).then((results) => { logger.debug(' queryInstalledChaincodes ::%j',results); let found = false; @@ -657,67 +613,67 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { t.fail('Failed to find our chaincode in the result list'); } - return channel.queryBlock(1); + return channel_on_org1.queryBlock(1); }).then((results) => { logger.debug(' queryBlock ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number'); - return channel.queryInfo(); + return channel_on_org1.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); + return channel_on_org1.queryBlockByHash(results.previousBlockHash); }).then((results) => { logger.debug(' queryBlockHash ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number by hash'); - return channel.queryTransaction(query_tx_id); + return channel_on_org1.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'); + return channel_on_org1.queryBlock(1,'peer0.org1.example.com'); }).then((results) => { logger.debug(' queryBlock ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number with string peer name'); - return channel.queryInfo('peer0.org1.example.com'); + return channel_on_org1.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'); + return channel_on_org1.queryBlockByHash(results.previousBlockHash, 'peer0.org1.example.com'); }).then((results) => { logger.debug(' queryBlockHash ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number by hash with string peer name'); - return channel.queryTransaction(query_tx_id,'peer0.org1.example.com'); + return channel_on_org1.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); + return channel_on_org1.queryBlock(1,'peer0.org1.example.com', true); }).then((results) => { logger.debug(' queryBlock ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number by admin'); - return channel.queryInfo('peer0.org1.example.com', true); + return channel_on_org1.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); + return channel_on_org1.queryBlockByHash(results.previousBlockHash, 'peer0.org1.example.com', true); }).then((results) => { logger.debug(' queryBlockHash ::%j',results); t.equals('1', results.header.number, 'Should be able to find our block number by hash by admin'); - return channel.queryTransaction(query_tx_id,'peer0.org1.example.com', true); + return channel_on_org1.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'); - let tx_id = client.newTransactionID(); // get a non admin transaction ID + let tx_id = client_org1.newTransactionID(); // get a non admin transaction ID var request = { chaincodeId : 'example', fcn: 'move', @@ -727,7 +683,7 @@ test('\n\n***** use the connection profile file *****\n\n', function(t) { }; // put in a very small timeout to force a failure, thereby checking that the timeout value was being used - return channel.sendTransactionProposal(request, 1); //logged in as org1 user + return channel_on_org1.sendTransactionProposal(request, 1); //logged in as org1 user }).then((results) => { var proposalResponses = results[0]; for(var i in proposalResponses) { diff --git a/test/integration/only-admin.js b/test/integration/only-admin.js new file mode 100644 index 0000000000..bfb70a1663 --- /dev/null +++ b/test/integration/only-admin.js @@ -0,0 +1,518 @@ +/** + * Copyright 2018 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('ONLY-ADMIN'); + +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 testUtil = require('../unit/util.js'); + +// Testing will demostrate how the connetion profile configuration may hold a +// admin user identity and it will be used for all fabric interactions. +// However since the network is using mutual TLS, the TLS connection will get +// valid certificates from the CertificateAuthority as a testing convenience. +// The CertificateAuthority will not be used to get the required signing certificates +// for the fabric requests. +// +// Testing will also demostrate how to read and set the admin identity manually +// Only one call will be made with this, however if the identity has access, all +// the calls made by connection profile demonstration may also be made. +test('\n\n***** use only admin identity *****\n\n', async function(t) { + const channel_name = 'adminconfig'; + + let client_org1 = await getClientForOrg(t, 'org1'); + let client_org2 = await getClientForOrg(t, 'org2'); + + let channel = await setupChannel(t, client_org1, client_org2, channel_name); + + let tx_id_string = await invoke(t, client_org1, channel); + await queries(t, client_org1, channel, tx_id_string); + + await manually(t, client_org1); + + t.end(); +}); + +async function getClientForOrg(t, org) { + // build a 'Client' instance that knows of a 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-ad.yaml'); + t.pass('Successfully loaded a network configuration'); + + // load the client information for this organization + // this file only has the client section + client.loadFromConfig('test/fixtures/'+ org +'.yaml'); + t.pass('Successfully loaded client section of network config for organization:'+ org); + if(client._adminSigningIdentity) { + t.pass('Successfully assigned an admin idenity to this client'); + } else { + t.fail('Failed to assigne an admin idenity to this client'); + } + + // tell this client instance where the state and key stores are located + await client.initCredentialStores(); + t.pass('Successfully created the key value store and crypto store based on the config and network config'); + + // the network is using mutual TLS, get the client side certs from the CA + await getTlsCACerts(t, client); + + return client; +} + +async function getTlsCACerts(t, client) { + // get the CA associated with this client's organization + // ---- this must only be run after the client has been loaded with a + // client section of the connection profile + let caService = client.getCertificateAuthority(); + t.pass('Successfully got the CertificateAuthority from the client'); + + let request = { + enrollmentID: 'admin', + enrollmentSecret: 'adminpw', + profile: 'tls' + }; + let enrollment = await caService.enroll(request); + + t.pass('Successfully called the CertificateAuthority to get the TLS material'); + let key = enrollment.key.toBytes(); + let cert = enrollment.certificate; + + // set the material on the client to be used when building endpoints for the user + client.setTlsClientCertAndKey(cert, key); + + return; +} + +async function setupChannel(t, client_org1, client_org2, channel_name) { + let channel_org1 = null; // these are for the same + let channel_org2 = null; + try { + // get the config envelope created by the configtx tool + let envelope_bytes = fs.readFileSync(path.join(__dirname, '../fixtures/channel/adminconfig.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 + let config = client_org1.extractChannelConfig(envelope_bytes); + t.pass('Successfully extracted the config update from the configtx envelope'); + + let signatures = []; + // sign the config by the admins + let signature1 = client_org1.signChannelConfig(config); + signatures.push(signature1); + t.pass('Successfully signed config update for org1'); + let signature2 = client_org2.signChannelConfig(config); + signatures.push(signature2); + t.pass('Successfully signed config update for org2'); + // now we have enough signatures... + + // get an admin based transaction + let create_tx_id = client_org1.newTransactionID(true); + + let create_request = { + config: config, + signatures : signatures, + name : channel_name, + orderer : 'orderer.example.com', + txId : create_tx_id + }; + + let create_results = await client_org1.createChannel(create_request); + if(create_results.status && create_results.status === 'SUCCESS') { + t.pass('Successfully created the channel.'); + await sleep(5000); + } else { + t.fail('Failed to create the channel. '); + throw new Error('Failed to create the channel. '); + } + + // have the client build a channel instance with all peers and orderers + // as defined in the loaded connection profile + // The channel will hold a reference to client + // --- the TLS certs will be applied from the client to each of the + // of the orderes and peers as they are added to the channel + channel_org1 = client_org1.getChannel(channel_name); + channel_org2 = client_org2.getChannel(channel_name); + + // get an admin based transaction + let gen_tx_id = client_org1.newTransactionID(true); + request = { + txId : gen_tx_id + }; + + let genesis_block = await channel_org1.getGenesisBlock(request); + t.pass('Successfully got the genesis block'); + + let join_tx_id = client_org1.newTransactionID(true); + request = { + targets: ['peer0.org1.example.com'], + block : genesis_block, + txId : join_tx_id + }; + + // send join request to peer on org2 as admin of org2 + let join_results = await channel_org1.joinChannel(request, 30000); + if(join_results && join_results[0] && join_results[0].response && join_results[0].response.status == 200) { + t.pass('Successfully joined channnel on org1'); + } else { + t.fail('Failed to join channel on org1'); + throw new Error('Failed to join channel on org1'); + } + + join_tx_id = client_org2.newTransactionID(true); + request = { + targets: ['peer0.org2.example.com'], + block : genesis_block, + txId : join_tx_id + }; + + // send join request to peer on org2 as admin of org2 + join_results = await channel_org2.joinChannel(request, 30000); + if(join_results && join_results[0] && join_results[0].response && join_results[0].response.status == 200) { + t.pass('Successfully joined channnel on org2'); + } else { + t.fail('Failed to join channel on org2'); + throw new Error('Failed to join channel on org2'); + } + + await sleep(10000); + t.pass('Successfully waited for peers to join the channel'); + + /* + * I N S T A L L C H A I N C O D E + */ + process.env.GOPATH = path.join(__dirname, '../fixtures'); + let install_tx_id = client_org1.newTransactionID(true);//get an admin transaction ID + var request = { + targets: ['peer0.org1.example.com'], + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v2', + txId : install_tx_id + }; + + // send install request as admin of org1 + let install_results = await client_org1.installChaincode(request); + if(install_results && install_results[0] && install_results[0][0].response && install_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'); + } + + install_tx_id = client_org2.newTransactionID(true); //get an admin transaction ID + var request = { + targets: ['peer0.org2.example.com'], + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v2', + txId : install_tx_id + }; + + // send install as org2 admin + install_results = await client_org2.installChaincode(request); + if(install_results && install_results[0] && install_results[0][0].response && install_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 instan_tx_id = client_org1.newTransactionID(true); + request = { + chaincodePath: 'github.com/example_cc', + chaincodeId: 'example', + chaincodeVersion: 'v2', + args: ['a', '100', 'b', '200'], + txId: instan_tx_id, + targets: ['peer0.org1.example.com','peer0.org2.example.com'], + }; + + // send proposal + let instan_results = await channel_org1.sendInstantiateProposal(request); + var proposalResponses = instan_results[0]; + var proposal = instan_results[1]; + if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) { + t.pass('Successfully sent Proposal and received ProposalResponse'); + } 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...'); + } + + let commit_request = { + proposalResponses: proposalResponses, + proposal: proposal, + txId : instan_tx_id + }; + + // submit the transaction to the orderer + let commit_response = await channel_org1.sendTransaction(commit_request); + if (!(commit_response instanceof Error) && commit_response.status === 'SUCCESS') { + t.pass('Successfully sent transaction to instantiate the chaincode to the orderer.'); + await 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); + } + + t.pass('Successfully waited for chaincodes to startup'); + } catch(error) { + logger.error('catch network config test error:: %s', error.stack ? error.stack : error); + t.fail('Test failed with '+ error); + } + + // just return the one channel instance + return channel_org1; +} + +async function invoke(t, client, channel) { + let tx_id_string = null; + try { + // get a admin based transaction id + let tx_id = client.newTransactionID(true); + tx_id_string = tx_id.getTransactionID(); + let request = { + chaincodeId : 'example', + fcn: 'move', + args: ['a', 'b','100'], + txId: tx_id + }; + + let results = await channel.sendTransactionProposal(request); + let proposalResponses = results[0]; + let proposal = results[1]; + let 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...'); + } + request = { + proposalResponses: proposalResponses, + proposal: proposal, + txId : tx_id // to use the admin idenity must include the transactionID + // that was created for the proposal that was based on the admin Identity + }; + + let responses = await send_and_wait_on_events(t, channel, request, tx_id_string); + if (!(responses[0] instanceof Error) && responses[0].status === 'SUCCESS') { + t.pass('Successfully committed transaction ' + tx_id_string); + await sleep(5000); + } else { + t.fail('Failed transaction '+ tx_id_string); + throw new Error('Failed transaction'); + } + } catch(error) { + logger.error('catch network config test error:: %s', error.stack ? error.stack : error); + t.fail('Test failed with '+ error); + } + + return tx_id_string; +} + +async function send_and_wait_on_events(t, channel, request, tx_id) { + let promises = []; + promises.push(channel.sendTransaction(request)); + + let channel_event_hubs = channel.getChannelEventHubsForOrg(); + for(let i in channel_event_hubs) { + let channel_event_hub = channel_event_hubs[i]; + let event_monitor = transaction_monitor(t, channel_event_hub, tx_id); + promises.push(event_monitor); + } + + return Promise.all(promises); +} + +function transaction_monitor(t, channel_event_hub, tx_id) { + let a_promise = new Promise((resolve, reject) => { + let handle = setTimeout(() => { + t.fail('Timeout - Failed to receive event for tx_id '+ tx_id); + channel_event_hub.disconnect(); //shutdown + throw new Error('TIMEOUT - no event received'); + }, 10000); + + channel_event_hub.registerTxEvent(tx_id, (txnid, code, block_num) => { + clearTimeout(handle); + t.pass('Event has been seen with transaction code:'+ code + ' for transaction id:'+ txnid + ' for block_num:' + block_num); + resolve('Got the replayed transaction'); + }, (error) => { + clearTimeout(handle); + t.fail('Failed to receive event replay for Event for transaction id ::'+tx_id); + throw(error); + }, + // Setting the disconnect to true as we do not want to use this + // ChannelEventHub after the event we are looking for comes in + {disconnect: true} + ); + t.pass('Successfully registered event for '+tx_id); + + // this connect will send a request to the peer event service that has + // been signed by the admin identity + channel_event_hub.connect(); + t.pass('Successfully called connect on '+ channel_event_hub.getPeerAddr()); + }); + + return a_promise; +} + +async function queries(t, client, channel, tx_id_string) { + try { + let request = { + chaincodeId : 'example', + fcn: 'query', + args: ['b'] + }; + + let response_payloads = await channel.queryByChaincode(request, true); + if (response_payloads) { + for(let i = 0; i < response_payloads.length; i++) { + t.pass('Successfully got query results :: '+ response_payloads[i].toString('utf8')); + } + } else { + t.fail('response_payloads is null'); + throw new Error('Failed to get response on query'); + } + + let results = await client.queryChannels('peer0.org1.example.com', true); + let found = false; + for(let i in results.channels) { + if(results.channels[i].channel_id === channel.getName()) { + 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'); + } + + results = await client.queryInstalledChaincodes('peer0.org1.example.com', true); // use admin + found = false; + for(let i in results.chaincodes) { + 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'); + } + + results = await channel.queryBlock(1, 'peer0.org1.example.com', true); + t.equals('1', results.header.number, 'Checking able to find our block number by admin'); + + results = await channel.queryInfo('peer0.org1.example.com', true); + t.pass('Successfully got the block height by admin:: '+ results.height); + + results = await channel.queryBlockByHash(results.previousBlockHash, 'peer0.org1.example.com', true); + t.pass('Successfully got block by hash by admin ::' + results.header.number); + + results = await channel.queryTransaction(tx_id_string, 'peer0.org1.example.com', true); + t.equals(0, results.validationCode, 'Checking able to find our transaction validationCode by admin'); + } catch(error) { + logger.error('catch network config test error:: %s', error.stack ? error.stack : error); + t.fail('Test failed with '+ error); + } +} + +async function manually(t, client) { + try { + let data = fs.readFileSync(path.join(__dirname, '../fixtures/channel/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/keystore/ef8e88d28a86f23466ad378003d819561adbedc77fe90cc250424ce4de179a3c_sk')); + let key = data; + let keyPem = Buffer.from(data).toString(); + data = fs.readFileSync(path.join(__dirname, '../fixtures/channel/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/signcerts/Admin@example.com-cert.pem')); + let cert = Buffer.from(data).toString(); + data = fs.readFileSync(path.join(__dirname, '../fixtures/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tlscacerts/example.com-cert.pem')); + let pem = Buffer.from(data).toString(); + t.pass('Successfully read all crypto material'); + + client.setAdminSigningIdentity(key, cert, 'OrdererMSP'); + t.pass('Successfully set the client with admin signing identity'); + + let sys_channel = client.newChannel('testchainid'); + + let options = { + pem: pem, + 'ssl-target-name-override': 'orderer.example.com' + }; + + // this is to allow mutual TLS on the orderer by adding client TLS + // information into the options object used to create the orderer + client.addTlsClientCertAndKey(options); + + let orderer = client.newOrderer( + 'grpcs://localhost:7050', + options + ); + + sys_channel.addOrderer(orderer); + t.pass('Successfully added orderer to channel'); + + let config_envelope = await sys_channel.getChannelConfigFromOrderer(); + t.pass('Successfully got the config envelope by using the admin identity'); + + client._adminSigningIdentity = null; //remove the admin assigned above + client._userContext = null; + + // this will create the user and also assign it to client instance + // as a userContext + let user = await client.createUser({ + username: 'ordererAdmin', + mspid: 'OrdererMSP', + cryptoContent: { privateKeyPEM: keyPem, signedCertPEM: cert } + }); + t.equals(user.getName(), 'ordererAdmin', 'Checking that the user was created'); + t.equals(client._userContext.getName(), 'ordererAdmin', 'Checking that the user was set'); + + config_envelope = await sys_channel.getChannelConfigFromOrderer(); + t.pass('Successfully got the config envelope by user the user context'); + + } catch(error) { + logger.error('catch network config test error:: %s', error.stack ? error.stack : error); + t.fail('Test failed with '+ error); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +}