Skip to content

Commit

Permalink
[FABN-940] Contract Namespaces
Browse files Browse the repository at this point in the history
Change-Id: I6535d4695466847791458902cf24684d821d0f1b
Signed-off-by: Matthew B White <whitemat@uk.ibm.com>
  • Loading branch information
mbwhite committed Oct 3, 2018
1 parent ed043c3 commit ab01269
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
17 changes: 12 additions & 5 deletions fabric-network/lib/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ const util = require('util');
*/
class Contract {

constructor(channel, chaincodeId, gateway, queryHandler, eventHandlerFactory) {
constructor(channel, chaincodeId, gateway, queryHandler, eventHandlerFactory, namespace='') {
logger.debug('in Contract constructor');

this.channel = channel;
this.chaincodeId = chaincodeId;
this.gateway = gateway;
this.queryHandler = queryHandler;
this.eventHandlerFactory = eventHandlerFactory;
this.namespace = namespace;
}

/**
Expand Down Expand Up @@ -87,7 +88,10 @@ class Contract {
async submitTransaction(transactionName, ...parameters) {
logger.debug('in submitTransaction: ' + transactionName);

this._verifyTransactionDetails('submitTransaction', transactionName, parameters);
// form the transaction name with the namespace
const fullTxName = (this.namespace==='') ? transactionName : `${this.namespace}:${transactionName}`;

this._verifyTransactionDetails('submitTransaction', fullTxName, parameters);

const txId = this.gateway.getClient().newTransactionID();
// createTxEventHandler() will return null if no event handler is requested
Expand All @@ -97,7 +101,7 @@ class Contract {
const request = {
chaincodeId: this.chaincodeId,
txId,
fcn: transactionName,
fcn: fullTxName,
args: parameters
};

Expand Down Expand Up @@ -192,9 +196,12 @@ class Contract {
* @returns {Buffer} Payload response from the transaction function
*/
async executeTransaction(transactionName, ...parameters) {
this._verifyTransactionDetails('executeTransaction', transactionName, parameters);

// form the transaction name with the namespace
const fullTxName = (this.namespace==='') ? transactionName : `${this.namespace}:${transactionName}`;
this._verifyTransactionDetails('executeTransaction', fullTxName, parameters);
const txId = this.gateway.getClient().newTransactionID();
const result = await this.queryHandler.queryChaincode(this.chaincodeId, txId, transactionName, parameters);
const result = await this.queryHandler.queryChaincode(this.chaincodeId, txId, fullTxName, parameters);
return result ? result : null;
}
}
Expand Down
12 changes: 7 additions & 5 deletions fabric-network/lib/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,25 +148,27 @@ class Network {
/**
* Returns an instance of a contract (chaincode) on the current network
* @param {string} chaincodeId the chaincode Identifier
* @param {string} [namespace] optional namespace for the contract
* @returns {Contract} the contract
* @api
*/
getContract(chaincodeId) {
getContract(chaincodeId,namespace='') {
logger.debug('in getContract');
if (!this.initialized) {
throw new Error('Unable to get contract as network has failed to initialize');
}

let contract = this.contracts.get(chaincodeId);
const key = `${chaincodeId}:${namespace}`;
let contract = this.contracts.get(key);
if (!contract) {
contract = new Contract(
this.channel,
chaincodeId,
this.gateway,
this.queryHandler,
this.eventHandlerManager
this.eventHandlerManager,
namespace
);
this.contracts.set(chaincodeId, contract);
this.contracts.set(key, contract);
}
return contract;
}
Expand Down
53 changes: 53 additions & 0 deletions fabric-network/test/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,40 @@ describe('Contract', () => {
.should.be.rejectedWith(/Failed to send/);
});

it('should preprend the namespace if one has been given',()=>{
const stubEventHandler = sinon.createStubInstance(TransactionEventHandler);
const stubEventHandlerFactory = {
createTxEventHandler: () => stubEventHandler
};
const nscontract = new Contract(mockChannel, 'someid', mockGateway, mockQueryHandler, stubEventHandlerFactory,'my.name.space');
const proposalResponses = [{
response: {
status: 200
}
}];
const proposal = { proposal: 'i do' };
const header = { header: 'gooooal' };
mockChannel.sendTransactionProposal.resolves([ proposalResponses, proposal, header ]);
// This is the commit proposal and response (from the orderer).
const response = {
status: 'SUCCESS'
};
mockChannel.sendTransaction.withArgs({ proposalResponses: proposalResponses, proposal: proposal }).resolves(response);
return nscontract.submitTransaction('myfunc', 'arg1', 'arg2')
.then((result) => {
should.equal(result, null);
sinon.assert.calledOnce(mockClient.newTransactionID);
sinon.assert.calledOnce(mockChannel.sendTransactionProposal);
sinon.assert.calledWith(mockChannel.sendTransactionProposal, {
chaincodeId: 'someid',
txId: mockTransactionID,
fcn: 'my.name.space:myfunc',
args: ['arg1', 'arg2']
});
sinon.assert.calledOnce(mockChannel.sendTransaction);
});
});

});

describe('#executeTransaction', () => {
Expand Down Expand Up @@ -360,5 +394,24 @@ describe('Contract', () => {
.should.be.rejectedWith(/such error/);

});

it('should query chaincode with namespace added to the function', async () => {

const stubEventHandler = sinon.createStubInstance(TransactionEventHandler);
const stubEventHandlerFactory = {
createTxEventHandler: () => stubEventHandler
};
const nscontract = new Contract(mockChannel, 'someid', mockGateway, mockQueryHandler, stubEventHandlerFactory,'my.name.space');

mockQueryHandler.queryChaincode.withArgs('someid', mockTransactionID, 'myfunc', ['arg1', 'arg2']).resolves();

await nscontract.executeTransaction('myfunc', 'arg1', 'arg2');
sinon.assert.calledOnce(mockQueryHandler.queryChaincode);
sinon.assert.calledWith(mockQueryHandler.queryChaincode,
sinon.match.any,
sinon.match.any,
'my.name.space:myfunc',
sinon.match.any);
});
});
});
17 changes: 16 additions & 1 deletion fabric-network/test/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ describe('Network', () => {

it('should return a cached contract object', () => {
const mockContract = sinon.createStubInstance(Contract);
network.contracts.set('foo', mockContract);
network.contracts.set('foo:', mockContract);
network.initialized = true;
network.getContract('foo').should.equal(mockContract);
});
Expand All @@ -231,6 +231,21 @@ describe('Network', () => {
contract.should.be.instanceof(Contract);
contract.chaincodeId.should.equal('bar');
});

it('should return a newly created contract, with namespace', () => {
const mockContract = sinon.createStubInstance(Contract);
network.contracts.set('foo:my.name.space', mockContract);
network.initialized = true;
network.getContract('foo','my.name.space').should.equal(mockContract);
});

it('should create a non-existent contract object with namespace', () => {
network.initialized = true;
const contract = network.getContract('bar','my.name.space');
contract.should.be.instanceof(Contract);
contract.chaincodeId.should.equal('bar');
contract.namespace.should.equal('my.name.space');
});
});

describe('#_dispose', () => {
Expand Down

0 comments on commit ab01269

Please sign in to comment.