Skip to content

Commit

Permalink
Add ability to pass transient data and peer targets to a gateway tran…
Browse files Browse the repository at this point in the history
…saction

Signed-off-by: [email protected] <[email protected]>
  • Loading branch information
nklincoln committed Jan 21, 2020
1 parent 7e84fea commit 8d355df
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 47 deletions.
2 changes: 1 addition & 1 deletion packages/caliper-core/lib/common/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ caliper:
# Path to the blockchain configuration file that contains information required to interact with the SUT
networkconfig:
# Sets the frequency of the progress reports in milliseconds
txupdatetime: 1000
txupdatetime: 5000
# Configurations related to the logging mechanism
logging:
# Specifies the message structure through placeholders
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class CaliperLocalClient {
Logger.debug('prepareTest() with:', test);
let cb = require(CaliperUtils.resolvePath(test.cb));

this.txUpdateTime = Config.get(Config.keys.TxUpdateTime, 1000);
this.txUpdateTime = Config.get(Config.keys.TxUpdateTime, 5000);
const self = this;
let initUpdateInter = setInterval( () => { self.initUpdate(); } , self.txUpdateTime);

Expand Down
110 changes: 65 additions & 45 deletions packages/caliper-fabric/lib/adaptor-versions/v2/fabric-gateway-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class Fabric extends BlockchainInterface {
this.wallet = undefined;
this.userContracts = new Map();
this.userGateways = new Map();
this.peerCache = new Map();

// this value is hardcoded, if it's used, that means that the provided timeouts are not sufficient
this.configSmallestTimeout = 1000;
Expand Down Expand Up @@ -974,6 +975,28 @@ class Fabric extends BlockchainInterface {
return gateway;
}

/**
* Initialize channel objects for use in peer targeting. Requires user gateways to have been
* formed in advance.
*/
async _initializePeerCache() {

for (const userName of this.userGateways.keys()) {
const gateway = this.userGateways.get(userName);
// Loop over known channel names
const channelNames = this.networkUtil.getChannels();
for (const channelName of channelNames) {
const network = await gateway.getNetwork(channelName);
const channel = network.getChannel();

// Add all peers
for (const peerObject of channel.getPeers()) {
this.peerCache.set(peerObject.getName(), peerObject);
}
}
}
}

/**
* Install the specified chaincodes to their target peers.
* @private
Expand Down Expand Up @@ -1519,73 +1542,67 @@ class Fabric extends BlockchainInterface {
}

/**
* Submit a transaction using a Gateway contract
* Perform a transaction using a Gateway contract
* @param {object} context The context previously created by the Fabric adapter.
* @param {ChaincodeInvokeSettings} invokeSettings The settings associated with the transaction submission.
* @param {boolean} isSubmit boolean flag to indicate if the transaction is a submit or evaluate
* @return {Promise<TxStatus>} The result and stats of the transaction invocation.
* @async
*/
async _submitGatewayTransaction(context, invokeSettings) {
async _performGatewayTransaction(context, invokeSettings, isSubmit) {

// Retrieve the existing contract and a client
const contract = await this._getUserContract(invokeSettings.invokerIdentity, invokeSettings.chaincodeId);
const client = this.clientProfiles.get(invokeSettings.invokerIdentity);
const smartContract = await this._getUserContract(invokeSettings.invokerIdentity, invokeSettings.chaincodeId);

// Create a transaction
const transaction = smartContract.createTransaction(invokeSettings.chaincodeFunction);

// Build the Caliper TxStatus, this is a reduced item when compared to the low level API capabilities
const txIdObject = client.newTransactionID();
const txId = txIdObject.getTransactionID();
const txId = transaction.getTransactionID();
let invokeStatus = new TxStatus(txId);
invokeStatus.Set('request_type', 'transaction');

if(context.engine) {
if (context.engine) {
context.engine.submitCallback(1);
}

try {
const result = await contract.submitTransaction(invokeSettings.chaincodeFunction, ...invokeSettings.chaincodeArguments);
invokeStatus.result = result;
invokeStatus.verified = true;
invokeStatus.SetStatusSuccess();
return invokeStatus;
} catch (err) {
logger.error(`Failed to submit transaction [${invokeSettings.chaincodeFunction}] using arguments [${invokeSettings.chaincodeArguments}], with error: ${err.stack ? err.stack : err}`);
invokeStatus.SetStatusFail();
invokeStatus.result = [];
return invokeStatus;
// Add transient data if present
// - passed as key value pairing such as {"hello":"world"}
if (invokeSettings.transientData) {
const transientData = {};
const keys = Array.from(Object.keys(invokeSettings.transientData));
keys.forEach((key) => {
transientData[key] = Buffer.from(transientData[key]);
});
transaction.setTransient(transientData);
}
}

/**
* Submit a transaction using a Gateway contract
* @param {object} context The context previously created by the Fabric adapter.
* @param {ChaincodeQuerySettings} querySettings The settings associated with the transaction evaluation.
* @return {Promise<TxStatus>} The result and stats of the transaction invocation.
* @async
*/
async _evaluateGatewayTransaction(context, querySettings) {

// Retrieve the existing contract and a client
const contract = await this._getUserContract(querySettings.invokerIdentity, querySettings.chaincodeId);
const client = this.clientProfiles.get(querySettings.invokerIdentity);

// Build the Caliper TxStatus, this is a reduced item when compared to the low level API capabilities
const txIdObject = client.newTransactionID();
const txId = txIdObject.getTransactionID();
let invokeStatus = new TxStatus(txId);
invokeStatus.Set('request_type', 'query');

if (context.engine) {
context.engine.submitCallback(1);
// Set endorsing peers if passed as a string array
if (invokeSettings.targetPeers) {
// Retrieved cached peer objects
const targetPeerObjects = [];
for (const name of invokeSettings.targetPeers) {
const peer = this.peerCache.get(name);
targetPeerObjects.push(peer);
}
// Set the peer objects in the transaction
transaction.setEndorsingPeers(targetPeerObjects);
}

try {
const result = await contract.evaluateTransaction(querySettings.chaincodeFunction, ...querySettings.chaincodeArguments);
let result;
if (isSubmit) {
invokeStatus.Set('request_type', 'transaction');
result = await transaction.submit(...invokeSettings.chaincodeArguments);
} else {
invokeStatus.Set('request_type', 'query');
result = await transaction.evaluate(...invokeSettings.chaincodeArguments);
}
invokeStatus.result = result;
invokeStatus.verified = true;
invokeStatus.SetStatusSuccess();
return invokeStatus;
} catch (err) {
logger.error(`Failed to evaluate transaction [${querySettings.chaincodeFunction}] using arguments [${querySettings.chaincodeArguments}], with error: ${err.stack ? err.stack : err}`);
logger.error(`Failed to perform ${isSubmit ? 'submit' : 'query' } transaction [${invokeSettings.chaincodeFunction}] using arguments [${invokeSettings.chaincodeArguments}], with error: ${err.stack ? err.stack : err}`);
invokeStatus.SetStatusFail();
invokeStatus.result = [];
return invokeStatus;
Expand Down Expand Up @@ -1658,6 +1675,9 @@ class Fabric extends BlockchainInterface {
// - within submit/evaluate, a contract will be used for a nominated user
await this._initializeContracts();

// - use gateways to build a peer cache
await this._initializePeerCache();

// We are done - return the networkUtil object
return {
networkInfo: this.networkUtil,
Expand Down Expand Up @@ -1742,7 +1762,7 @@ class Fabric extends BlockchainInterface {
settings.invokerIdentity = this.defaultInvoker;
}

promises.push(this._submitGatewayTransaction(context, settings));
promises.push(this._performGatewayTransaction(context, settings, true));
}

return await Promise.all(promises);
Expand Down Expand Up @@ -1782,7 +1802,7 @@ class Fabric extends BlockchainInterface {
settings.invokerIdentity = this.defaultInvoker;
}

promises.push(this._evaluateGatewayTransaction(context, settings));
promises.push(this._performGatewayTransaction(context, settings, false));
}

return await Promise.all(promises);
Expand Down

0 comments on commit 8d355df

Please sign in to comment.