Skip to content

Commit

Permalink
[FABN-1163] Update token support with latest proto msgs
Browse files Browse the repository at this point in the history
- Update fabric-protos with latest protobuf msgs
- Update token code for the following changes in protobuf msgs
  quantity is changed to hex string,
  recipient is renamed to owner,
  import is renamed to issue,
  TokenOutput is renamed to UnspentToken,
  TokenToIssue is replaced by Token
- move v2 channel config under channel-config dir

Change-Id: I49d5932c4df8e266c2ebb5d93e9ae8b66babeb96
Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>
  • Loading branch information
wenjianqiao committed Mar 5, 2019
1 parent 2484072 commit f12d5f5
Show file tree
Hide file tree
Showing 16 changed files with 323 additions and 788 deletions.
17 changes: 9 additions & 8 deletions fabric-client/lib/TokenClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const {HashPrimitives} = require('fabric-common');
* const txId = tokenClient1.newTransactionID();
* const owner = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: user2Identity.serialize()};
* const tokenType = 'myTokenType';
* let param = {recipient: owner, type: tokenType, quantity: 200};
* let param = {owner: owner, type: tokenType, quantity: 200};
* let request = {params: [param], txId: txId};
*
* // user1 calls issue method to issue tokens to user2
Expand Down Expand Up @@ -93,7 +93,7 @@ const {HashPrimitives} = require('fabric-common');
*
* // user2 calls transfer method to transfer the token to user1
* const newOwner = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: user1Identity.serialize()};
* param = {recipient: newOwner, quantity: 150};
* param = {owner: newOwner, quantity: 150};
* request = {params: [param], tokenId: token.id, txId: txId};
* result = await tokenClient1.transfer(request);
*
Expand Down Expand Up @@ -164,11 +164,12 @@ const TokenClient = class {

/**
* @typedef {Object} TokenParam
* This object contains properties that specify the recipient, type,
* This object contains properties that specify the owner, type,
* and quantity of a token kind.
* @property {byte[]} recipient - Required for issue and transfer. The owner of the token.
* @property {byte[]} owner - Required for issue and transfer. The owner of the token.
* @property {string} type - Required for issue. The type of the token.
* @property {Number} quantity - Required. The quantity of the token.
* @property {HexString} quantity - Required. The quantity of the token in a HexString
* of the numeric value.
*/

/**
Expand All @@ -192,7 +193,7 @@ const TokenClient = class {
* and broadcast the transaction to orderers.
*
* @param {TokenRequest} request - Required. A TokenRequest object.
* Must contain a 'params' TokenParam[] with recipient, type, and quantity properties.
* Must contain a 'params' TokenParam[] with owner, type, and quantity properties.
* @param {Number} timeout - Optional. A number indicating milliseconds to wait on the
* response before rejecting the promise with a timeout error. This
* overrides the default timeout of the Peer instance and the global
Expand Down Expand Up @@ -220,7 +221,7 @@ const TokenClient = class {
* and broadcast the transaction to orderers.
*
* @param {TokenRequest} request - Required. A TokenRequest object.
* Must contain a 'params' TokenParam[] with recipient and quantity properties.
* Must contain a 'params' TokenParam[] with owner and quantity properties.
* @param {Number} timeout - Optional. A number indicating milliseconds to wait on the
* response before rejecting the promise with a timeout error. This
* overrides the default timeout of the Peer instance and the global
Expand Down Expand Up @@ -279,7 +280,7 @@ const TokenClient = class {
* response before rejecting the promise with a timeout error. This
* overrides the default timeout of the Peer instance and the global
* timeout in the config settings.
* @returns {Promise} A Promise for TokenOutput[] array returned by the prover peer
* @returns {Promise} A Promise for UnspentToken[] array returned by the prover peer
* that contains all unspent tokens owned by the user.
*/
async list(request, timeout) {
Expand Down
23 changes: 16 additions & 7 deletions fabric-client/lib/token-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ module.exports.buildIssueCommand = (request) => {
// iterate params to populate tokensToIssue
const tokensToIssue = [];
params.forEach((param) => {
const token = {recipient: param.recipient, type: param.type, quantity: param.quantity};
const token = {owner: param.owner, type: param.type, quantity: param.quantity};
tokensToIssue.push(token);
});

// construct import request and token command
const importRequest = {tokens_to_issue: tokensToIssue};
const issueRequest = {tokens_to_issue: tokensToIssue};
const tokenCmd = new fabprotos.token.Command();
tokenCmd.set('import_request', importRequest);
tokenCmd.set('issue_request', issueRequest);

return tokenCmd;
};
Expand All @@ -62,7 +62,7 @@ module.exports.buildTransferCommand = (request) => {
// iterate params to populate transfer shares
const shares = [];
params.forEach((param) => {
const share = {recipient: param.recipient, quantity: param.quantity};
const share = {recipient: param.owner, quantity: param.quantity};
shares.push(share);
});

Expand All @@ -86,7 +86,7 @@ module.exports.buildRedeemCommand = (request) => {
}

// construct redeem request and token command
const redeemRequest = {token_ids: request.tokenIds, quantity_to_redeem: param.quantity};
const redeemRequest = {token_ids: request.tokenIds, quantity: param.quantity};
const tokenCmd = new fabprotos.token.Command();
tokenCmd.set('redeem_request', redeemRequest);

Expand Down Expand Up @@ -227,9 +227,9 @@ module.exports.checkTokenRequest = (request, command_name, txIdRequired) => {
}

params.forEach((param) => {
if (!param.recipient) {
if (!param.owner) {
if (command_name === 'issue' || command_name === 'transfer') {
throw new Error(util.format('Missing required "recipient" in request on %s call', command_name));
throw new Error(util.format('Missing required "owner" in request on %s call', command_name));
}
}
if (!param.type) {
Expand All @@ -256,3 +256,12 @@ exports.toSignedCommand = (signature, command_bytes) => ({signature: signature,
* @param payload_bytes
*/
exports.toEnvelope = (signature, payload_bytes) => ({signature: signature, payload: payload_bytes});

/**
* convert an uint to Hex string
*/
function toHex(value) {
return '0x' + value.toString(16);
}

module.exports.toHex = toHex;
4 changes: 2 additions & 2 deletions fabric-client/test/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3666,8 +3666,8 @@ describe('Channel', () => {

// create token command request
command = new fabprotos.token.Command();
const importRequest = new fabprotos.token.ImportRequest();
command.set('import_request', importRequest);
const issueRequest = new fabprotos.token.IssueRequest();
command.set('issue_request', issueRequest);
request = {tokenCommand: command, txId: txIdStub};
});

Expand Down
11 changes: 6 additions & 5 deletions fabric-client/test/TokenClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const Client = require('../lib/Client');
const {Identity} = require('fabric-common');
const TokenClient = rewire('../lib/TokenClient');
const TransactionID = require('../lib/TransactionID.js');
const token_utils = require('../lib/token-utils.js');
const fabprotos = require('fabric-protos');

const sinon = require('sinon');
Expand Down Expand Up @@ -125,7 +126,7 @@ describe('TokenClient', () => {

beforeEach(() => {
// prepare token request for issue
param = {recipient: testowner, type: 'abc123', quantity: 210};
param = {owner: testowner, type: 'abc123', quantity: 210};
request = {params: [param], txId: txId};
tokenClient = new TokenClient(client, mockChannel);
});
Expand Down Expand Up @@ -228,7 +229,7 @@ describe('TokenClient', () => {
beforeEach(() => {
// prepare token request for transfer
const tokenId = {tx_id: 'mock_tx_id', index: 0};
param = {recipient: testowner, quantity: 210};
param = {owner: testowner, quantity: 210};
request = {params: [param], tokenIds: [tokenId], txId: txId};

tokenClient = new TokenClient(client, mockChannel);
Expand Down Expand Up @@ -442,8 +443,8 @@ describe('TokenClient', () => {
// prepare mockResponse for sendTokenComandStub
const tokenId1 = {tx_id: 'mock_tx_id1', index: 0};
const tokenId2 = {tx_id: 'mock_tx_id2', index: 0};
const token1 = {id: tokenId1, type: 'abc123', quantity: 100};
const token2 = {id: tokenId2, type: 'xyz', quantity: 200};
const token1 = {id: tokenId1, type: 'abc123', quantity: token_utils.toHex(100)};
const token2 = {id: tokenId2, type: 'xyz', quantity: token_utils.toHex(200)};
mockTokens = [token1, token2];
mockResponse = new fabprotos.token.CommandResponse();
mockResponse.setUnspentTokens({tokens: mockTokens});
Expand Down Expand Up @@ -597,7 +598,7 @@ describe('TokenClient', () => {

// prepare request parameters
tokenIds = [{tx_id: 'mock_tx_id', index: 0}];
param = {recipient: testowner, type: 'abc123', quantity: 210};
param = {owner: testowner, type: 'abc123', quantity: 210};

// create stubs
buildTokenCommandHeaderStub = sinon.stub();
Expand Down
38 changes: 20 additions & 18 deletions fabric-client/test/token-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('token-utils', () => {
beforeEach(() => {
// prepare token request
const owner = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: Buffer.from('test-owner')};
param = {recipient: owner, type: 'abc123', quantity: 210};
param = {owner: owner, type: 'abc123', quantity: TokenUtils.toHex(210)};
request = {params: [param], txId: txId, tokenIds: tokenIds};
});

Expand Down Expand Up @@ -80,11 +80,11 @@ describe('token-utils', () => {
}).should.throw('Missing required "params" in request on issue call');
});

it('should get error when parameter has no recipient', () => {
it('should get error when parameter has no owner', () => {
(() => {
param.recipient = undefined;
param.owner = undefined;
TokenUtils.checkTokenRequest(request, 'issue');
}).should.throw('Missing required "recipient" in request on issue call');
}).should.throw('Missing required "owner" in request on issue call');
});

it('should get error when parameter has no type', () => {
Expand Down Expand Up @@ -128,11 +128,11 @@ describe('token-utils', () => {
}).should.throw('Missing required "params" in request on transfer call');
});

it('should get error when parameter has no recipient', () => {
it('should get error when parameter has no owner', () => {
(() => {
param.recipient = undefined;
param.owner = undefined;
TokenUtils.checkTokenRequest(request, 'transfer');
}).should.throw('Missing required "recipient" in request on transfer call');
}).should.throw('Missing required "owner" in request on transfer call');
});

it('should get error when parameter has no quantity', () => {
Expand Down Expand Up @@ -241,18 +241,18 @@ describe('token-utils', () => {
// prepare token request for issue
const owner1 = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: Buffer.from('owner1')};
const owner2 = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: Buffer.from('owner2')};
param1 = {recipient: owner1, type: 'abc123', quantity: 210};
param2 = {recipient: owner2, type: 'horizon', quantity: 300};
param1 = {owner: owner1, type: 'abc123', quantity: TokenUtils.toHex(210)};
param2 = {owner: owner2, type: 'horizon', quantity: TokenUtils.toHex(300)};
request = {
params: [param1, param2],
txId: txId,
};

// create expected command based on request
const importRequest = new fabprotos.token.ImportRequest();
importRequest.setTokensToIssue([param1, param2]);
const issueRequest = new fabprotos.token.IssueRequest();
issueRequest.setTokensToIssue([param1, param2]);
expectedCommand = new fabprotos.token.Command();
expectedCommand.set('import_request', importRequest);
expectedCommand.set('issue_request', issueRequest);
});

it('should return a valid token command', () => {
Expand All @@ -267,8 +267,8 @@ describe('token-utils', () => {
const tokenId = {tx_id: 'mock_tx_id', index: 0};
const owner1 = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: Buffer.from('owner1')};
const owner2 = {type: fabprotos.token.TokenOwner_MSP_IDENTIFIER, raw: Buffer.from('owner2')};
param1 = {recipient: owner1, quantity: 100};
param2 = {recipient: owner2, quantity: 200};
param1 = {owner: owner1, quantity: TokenUtils.toHex(100)};
param2 = {owner: owner2, quantity: TokenUtils.toHex(200)};

request = {
tokenIds: [tokenId],
Expand All @@ -279,7 +279,9 @@ describe('token-utils', () => {
// create expected command based on request
const transferRequest = new fabprotos.token.TransferRequest();
transferRequest.setTokenIds([tokenId]);
transferRequest.setShares([param1, param2]);
const share1 = {recipient: param1.owner, quantity: param1.quantity};
const share2 = {recipient: param2.owner, quantity: param2.quantity};
transferRequest.setShares([share1, share2]);
expectedCommand = new fabprotos.token.Command();
expectedCommand.set('transfer_request', transferRequest);
});
Expand All @@ -294,7 +296,7 @@ describe('token-utils', () => {
beforeEach(() => {
// prepare token request for redeem
const tokenId = {tx_id: 'mock_tx_id', index: 0};
param1 = {quantity: 100};
param1 = {quantity: TokenUtils.toHex(100)};
request = {
tokenIds: [tokenId],
params: param1,
Expand All @@ -304,7 +306,7 @@ describe('token-utils', () => {
// create expected command based on request
const redeemRequest = new fabprotos.token.RedeemRequest();
redeemRequest.setTokenIds([tokenId]);
redeemRequest.setQuantityToRedeem(param1.quantity);
redeemRequest.setQuantity(param1.quantity);
expectedCommand = new fabprotos.token.Command();
expectedCommand.set('redeem_request', redeemRequest);
});
Expand Down Expand Up @@ -503,7 +505,7 @@ describe('token-utils', () => {
mockSigningIdentity = {sign: signStub};

command = new fabprotos.token.Command();
command.set('import_request', new fabprotos.token.ImportRequest());
command.set('issue_request', new fabprotos.token.IssueRequest());

});

Expand Down
Loading

0 comments on commit f12d5f5

Please sign in to comment.