diff --git a/balance-transfer/app.js b/balance-transfer/app.js index cffddce80a..83b1226ab4 100644 --- a/balance-transfer/app.js +++ b/balance-transfer/app.js @@ -34,6 +34,7 @@ var hfc = require('fabric-client'); var helper = require('./app/helper.js'); var createChannel = require('./app/create-channel.js'); var join = require('./app/join-channel.js'); +var updateAnchorPeers = require('./app/update-anchor-peers.js'); var install = require('./app/install-chaincode.js'); var instantiate = require('./app/instantiate-chaincode.js'); var invoke = require('./app/invoke-transaction.js'); @@ -179,6 +180,25 @@ app.post('/channels/:channelName/peers', async function(req, res) { let message = await join.joinChannel(channelName, peers, req.username, req.orgname); res.send(message); }); +// Update anchor peers +app.post('/channels/:channelName/anchorpeers', async function(req, res) { + logger.debug('==================== UPDATE ANCHOR PEERS =================='); + var channelName = req.params.channelName; + var configUpdatePath = req.body.configUpdatePath; + logger.debug('Channel name : ' + channelName); + logger.debug('configUpdatePath : ' + configUpdatePath); + if (!channelName) { + res.json(getErrorMessage('\'channelName\'')); + return; + } + if (!configUpdatePath) { + res.json(getErrorMessage('\'configUpdatePath\'')); + return; + } + + let message = await updateAnchorPeers.updateAnchorPeers(channelName, configUpdatePath, req.username, req.orgname); + res.send(message); +}); // Install chaincode on target peers app.post('/chaincodes', async function(req, res) { logger.debug('==================== INSTALL CHAINCODE =================='); diff --git a/balance-transfer/app/update-anchor-peers.js b/balance-transfer/app/update-anchor-peers.js new file mode 100644 index 0000000000..aa961c87c7 --- /dev/null +++ b/balance-transfer/app/update-anchor-peers.js @@ -0,0 +1,114 @@ +/** + * Copyright Hitachi America, Ltd. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; +var util = require('util'); +var fs = require('fs'); +var path = require('path'); + +var helper = require('./helper.js'); +var logger = helper.getLogger('update-anchor-peers'); + +var updateAnchorPeers = async function(channelName, configUpdatePath, username, org_name) { + logger.debug('\n====== Updating Anchor Peers on \'' + channelName + '\' ======\n'); + var error_message = null; + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } + + // read in the envelope for the channel config raw bytes + var envelope = fs.readFileSync(path.join(__dirname, configUpdatePath)); + // extract the channel config bytes from the envelope to be signed + var channelConfig = client.extractChannelConfig(envelope); + + //Acting as a client in the given organization provided with "orgName" param + // sign the channel config bytes as "endorsement", this is required by + // the orderer's channel creation policy + // this will use the admin identity assigned to the client when the connection profile was loaded + let signature = client.signChannelConfig(channelConfig); + + let request = { + config: channelConfig, + signatures: [signature], + name: channelName, + txId: client.newTransactionID(true) // get an admin based transactionID + }; + + var promises = []; + let event_hubs = channel.getChannelEventHubsForOrg(); + logger.debug('found %s eventhubs for this organization %s',event_hubs.length, org_name); + event_hubs.forEach((eh) => { + let anchorUpdateEventPromise = new Promise((resolve, reject) => { + logger.debug('anchorUpdateEventPromise - setting up event'); + let event_timeout = setTimeout(() => { + let message = 'REQUEST_TIMEOUT:' + eh.getPeerAddr(); + logger.error(message); + eh.disconnect(); + }, 60000); + eh.registerBlockEvent((block) => { + logger.info('The config update has been committed on peer %s',eh.getPeerAddr()); + clearTimeout(event_timeout); + resolve(); + }, (err) => { + clearTimeout(event_timeout); + logger.error(err); + reject(err); + }, + // the default for 'unregister' is true for block listeners + // so no real need to set here, however for 'disconnect' + // the default is false as most event hubs are long running + // in this use case we are using it only once + {unregister: true, disconnect: true} + ); + eh.connect(); + }); + promises.push(anchorUpdateEventPromise); + }); + + var sendPromise = client.updateChannel(request); + // put the send to the orderer last so that the events get registered and + // are ready for the orderering and committing + promises.push(sendPromise); + let results = await Promise.all(promises); + logger.debug(util.format('------->>> R E S P O N S E : %j', results)); + let response = results.pop(); // orderer results are last in the results + + if (response && response.status === 'SUCCESS') { + logger.info('Successfully update anchor peers to the channel %s', channelName); + } else { + error_message = util.format('Failed to update anchor peers to the channel %s', channelName); + logger.error(error_message); + } + } catch (error) { + logger.error('Failed to update anchor peers due to error: ' + error.stack ? error.stack : error); + error_message = error.toString(); + } + + if (!error_message) { + let message = util.format( + 'Successfully update anchor peers in organization %s to the channel \'%s\'', + org_name, channelName); + logger.info(message); + let response = { + success: true, + message: message + }; + return response; + } else { + let message = util.format('Failed to update anchor peers. cause:%s',error_message); + logger.error(message); + throw new Error(message); + } +}; + +exports.updateAnchorPeers = updateAnchorPeers; diff --git a/balance-transfer/artifacts/channel/Org1MSPanchors.tx b/balance-transfer/artifacts/channel/Org1MSPanchors.tx new file mode 100644 index 0000000000..104ee50e05 Binary files /dev/null and b/balance-transfer/artifacts/channel/Org1MSPanchors.tx differ diff --git a/balance-transfer/artifacts/channel/Org2MSPanchors.tx b/balance-transfer/artifacts/channel/Org2MSPanchors.tx new file mode 100644 index 0000000000..eaaf1d7f12 Binary files /dev/null and b/balance-transfer/artifacts/channel/Org2MSPanchors.tx differ diff --git a/balance-transfer/testAPIs.sh b/balance-transfer/testAPIs.sh index 8528924c32..e48ec039d3 100755 --- a/balance-transfer/testAPIs.sh +++ b/balance-transfer/testAPIs.sh @@ -112,6 +112,30 @@ curl -s -X POST \ echo echo +echo "POST request Update anchor peers on Org1" +echo +curl -s -X POST \ + http://localhost:4000/channels/mychannel/anchorpeers \ + -H "authorization: Bearer $ORG1_TOKEN" \ + -H "content-type: application/json" \ + -d '{ + "configUpdatePath":"../artifacts/channel/Org1MSPanchors.tx" +}' +echo +echo + +echo "POST request Update anchor peers on Org2" +echo +curl -s -X POST \ + http://localhost:4000/channels/mychannel/anchorpeers \ + -H "authorization: Bearer $ORG2_TOKEN" \ + -H "content-type: application/json" \ + -d '{ + "configUpdatePath":"../artifacts/channel/Org2MSPanchors.tx" +}' +echo +echo + echo "POST Install chaincode on Org1" echo curl -s -X POST \