mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-22 17:45:10 +00:00
Merge "[FAB-16232] Remove FabToken sample"
This commit is contained in:
commit
33b43b6550
8 changed files with 0 additions and 696 deletions
21
Jenkinsfile
vendored
21
Jenkinsfile
vendored
|
|
@ -136,27 +136,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Run fabtoken tests
|
|
||||||
stage('Run FabToken Tests') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
// making the output color coded
|
|
||||||
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'xterm']) {
|
|
||||||
try {
|
|
||||||
dir("$ROOTDIR/$BASE_DIR/scripts/ci_scripts") {
|
|
||||||
// Run fabtoken tests
|
|
||||||
sh './ciScript.sh --fabtoken_Tests'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
failure_stage = "fabtoken_Tests"
|
|
||||||
currentBuild.result = 'FAILURE'
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // stages
|
} // stages
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
|
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
|
|
||||||
# FabToken Sample Application
|
|
||||||
|
|
||||||
This is a Node.js sample application that demonstrates how to perform token operations on
|
|
||||||
a Fabric network using Fabric Node SDK.
|
|
||||||
|
|
||||||
The sample assumes an understanding of the Hyperledger Fabric network (orderers, peers,
|
|
||||||
and channels) and of Node.js application development, including the use of the Javascript
|
|
||||||
promise, async and await.
|
|
||||||
|
|
||||||
For more information about tokens on Hyperledger Fabric, see
|
|
||||||
[Using Fabtoken](https://hyperledger-fabric.readthedocs.io/en/latest/token/FabToken.html)
|
|
||||||
|
|
||||||
For more information about the Fabric SDK for Node.js, refer to
|
|
||||||
[Node SDK documentation](https://fabric-sdk-node.github.io/master/index.html)
|
|
||||||
|
|
||||||
For more information about the Node SDK TokenClient API, refer to the following:
|
|
||||||
* [TokenClient API reference](https://fabric-sdk-node.github.io/master/TokenClient.html)
|
|
||||||
* [FabToken tutorial](https://fabric-sdk-node.github.io/master/tutorial-fabtoken.html)
|
|
||||||
|
|
||||||
## Run the sample
|
|
||||||
You can find the `fabtoken.js` sample application in the `javascript` directory. You will
|
|
||||||
use this application to create and transfer tokens on a network created using the
|
|
||||||
`basic-network` sample. First, you need to have an initial setup.
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
You will need to install version 8.9.x of Node.js and download the application dependencies.
|
|
||||||
* Change to `javascript` directory: `cd javascript`
|
|
||||||
* Run the following command to install the required packages: `npm install`
|
|
||||||
|
|
||||||
Now you can start the network:
|
|
||||||
* Navigate back to the main `FabToken` directory: `cd ..`
|
|
||||||
* Start fabric network: `./startFabric.sh`
|
|
||||||
|
|
||||||
This command will create a fabric network with 1 peer, an ordering service, one
|
|
||||||
channel, and two users that our application will use to issue and transfer tokens.
|
|
||||||
|
|
||||||
### Run the app right away
|
|
||||||
|
|
||||||
The `fabtoken.js` application includes a `demo` method that runs an end to end token flow
|
|
||||||
with hardcoded parameters.
|
|
||||||
|
|
||||||
* Navigate to the `javascript` directory
|
|
||||||
* Run the command `node fabtoken` without any arguments to run the demo.
|
|
||||||
|
|
||||||
You should see the output of the demo in your terminal. The demo uses user1 and user2 of
|
|
||||||
the basic network to do the following token operations:
|
|
||||||
* Issue a token worth 100 USD to user1
|
|
||||||
* Transfer 30 USD from user1 to user2
|
|
||||||
* Redeem 10 USD as user1 and 30 USD as user2
|
|
||||||
* Check that user1 has a token worth 60 USD and user2 has no tokens
|
|
||||||
|
|
||||||
### Use the sample app to create your own tokens
|
|
||||||
|
|
||||||
You can pass arguments to `fabtoken.js` to create your own tokens and follow your own
|
|
||||||
token flow.
|
|
||||||
|
|
||||||
#### Issue tokens
|
|
||||||
|
|
||||||
Tokens need to be issued before they can be spent. You can use the command
|
|
||||||
`node fabtoken issue <username> <token_type> <quantity>` to issue tokens of any
|
|
||||||
type and quantity to user1 or user2.
|
|
||||||
|
|
||||||
* As an example, the first command issues a token worth 100 US dollars to user1. The
|
|
||||||
second command issues a token worth 200 Euros to user2:
|
|
||||||
|
|
||||||
```
|
|
||||||
node fabtoken issue user1 USD 100
|
|
||||||
node fabtoken issue user2 EURO 200
|
|
||||||
```
|
|
||||||
|
|
||||||
#### List tokens
|
|
||||||
|
|
||||||
After you issue tokens, you can use the list method to query the tokens that you own. Run
|
|
||||||
the command `node fabtoken list <username>`. You need to use this command to recover the
|
|
||||||
tokenIDs that you will need to transfer or redeem your tokens.
|
|
||||||
|
|
||||||
* As an example, you can use the command below to list the tokens owned by user1:
|
|
||||||
|
|
||||||
```
|
|
||||||
node fabtoken list user1
|
|
||||||
```
|
|
||||||
* The command returns a list of tokens, with the tokenID consisting of a tx_id and
|
|
||||||
index. You will need to use these values for future commands.
|
|
||||||
|
|
||||||
```
|
|
||||||
[ { id:
|
|
||||||
{ tx_id: 'c9b1211d9ad809e6ee1b542de6886d8d1d9e1c938d88eff23a3ddb4e8c080e4d',
|
|
||||||
index: 0 },
|
|
||||||
type: 'USD',
|
|
||||||
quantity: '100' }
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
* To list the tokens owned by user2, use the `node fabtoken list user2` command.
|
|
||||||
|
|
||||||
```
|
|
||||||
[ { id:
|
|
||||||
{ tx_id: 'ab5670d3b20b6247b17a342dd2c5c4416f79db95c168beccb7d32b3dd382e5a5',
|
|
||||||
index: 0 },
|
|
||||||
type: 'EURO',
|
|
||||||
quantity: '200' }
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Transfer tokens
|
|
||||||
|
|
||||||
Tokens can be transferred between users on a channel using the
|
|
||||||
`node fabtoken transfer <from_user> <to_user> <quantity> <tx_id> <index>` command.
|
|
||||||
* `<tx_id>` and `<index>` are the "tx_id" and "index" that you found using the list
|
|
||||||
command
|
|
||||||
* `<quantity>` is the quantity to be transferred
|
|
||||||
|
|
||||||
Any remaining quantity will be transferred back to the owner by creating a new token with
|
|
||||||
a new tokenID.
|
|
||||||
* As an example, the following command transfers 30 dollars from user1 to user2:
|
|
||||||
|
|
||||||
```
|
|
||||||
node fabtoken transfer user1 user2 30 c9b1211d9ad809e6ee1b542de6886d8d1d9e1c938d88eff23a3ddb4e8c080e4d 0
|
|
||||||
```
|
|
||||||
|
|
||||||
You can run the command `node fabtoken list user2` to verify that user2 now owns a new token
|
|
||||||
worth 30 dollars. You can also run the command `node fabtoken list user1` to verify that
|
|
||||||
a new token worth 70 dollars now belongs to user1.
|
|
||||||
|
|
||||||
|
|
||||||
#### Redeem tokens
|
|
||||||
|
|
||||||
Tokens can be taken out of circulation by being redeemed. Redeemed tokens can no longer
|
|
||||||
be transfered to any member of the channel. Run the command
|
|
||||||
`node fabtoken redeem <username> <quantity> <tx_id> <index>` to redeem any tokens
|
|
||||||
belonging to user1 or user2.
|
|
||||||
* `<tx_id>` and `<index>` are the "tx_id" and "index" returned from the list command
|
|
||||||
* `<quantity>` is the quantity to be redeemed
|
|
||||||
|
|
||||||
Any remaining quantity will be transferred back to the owner with a new tokenID.
|
|
||||||
* As an example, the following command redeems 10 Euro's belonging to user2:
|
|
||||||
|
|
||||||
```
|
|
||||||
node fabtoken redeem user2 10 ab5670d3b20b6247b17a342dd2c5c4416f79db95c168beccb7d32b3dd382e5a5 0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Clean up
|
|
||||||
|
|
||||||
If you are finished using the sample application, you can bring down the network and any
|
|
||||||
accompanying artifacts.
|
|
||||||
|
|
||||||
* Change to `fabric-samples/basic-network` directory
|
|
||||||
* To stop the network, run `./stop.sh`
|
|
||||||
* To completely remove all incriminating evidence of the network, run `./teardown.sh`
|
|
||||||
|
|
||||||
## Understanding the `fabtoken.js` application
|
|
||||||
|
|
||||||
You can examine the `fabtoken.js` file to get a better understanding of how the
|
|
||||||
sample application uses the FabToken APIs.
|
|
||||||
|
|
||||||
|
|
||||||
1. The `createFabricClient` method creates an instance of the fabric-client, and is
|
|
||||||
used to connect to the components of your network.
|
|
||||||
|
|
||||||
2. The `createUsers` method uses the certificates generated by the basic network to
|
|
||||||
create `admin`, `user1` and `user2` users for the application.
|
|
||||||
|
|
||||||
3. To perform token operations, you must create a `TokenClient` instance from a `Client`
|
|
||||||
object. Make sure the client has set the user context. Below is the code snippet.
|
|
||||||
|
|
||||||
```
|
|
||||||
// set user context to the client
|
|
||||||
await client.setUserContext(user, true);
|
|
||||||
|
|
||||||
// create a TokenClient instance
|
|
||||||
const tokenClient = client.newTokenClient(channel, 'localhost:7051');
|
|
||||||
```
|
|
||||||
|
|
||||||
4. The `issue` method creates an issue request and submits the request to issue tokens to
|
|
||||||
your network.
|
|
||||||
|
|
||||||
5. The `list` method submits the request to list tokens of a
|
|
||||||
given owner. You will need the token IDs returned from this method to transfer or redeem tokens.
|
|
||||||
|
|
||||||
6. The `transfer` method creates a transfer request and submits the request to transfer tokens
|
|
||||||
between users.
|
|
||||||
|
|
||||||
7. The `redeem` method creates a redeem request and submits the request to redeem a user's
|
|
||||||
tokens.
|
|
||||||
8
fabtoken/javascript/.gitignore
vendored
8
fabtoken/javascript/.gitignore
vendored
|
|
@ -1,8 +0,0 @@
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
|
|
||||||
|
|
@ -1,345 +0,0 @@
|
||||||
'use strict';
|
|
||||||
/*
|
|
||||||
* Copyright IBM Corp All Rights Reserved
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Chaincode Invoke
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Fabric_Client = require('fabric-client');
|
|
||||||
const path = require('path');
|
|
||||||
const util = require('util');
|
|
||||||
const os = require('os');
|
|
||||||
const fs = require('fs-extra');
|
|
||||||
|
|
||||||
const channel_name = "mychannel"
|
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
async function start() {
|
|
||||||
console.log('\n\n --- fabtoken.js - start');
|
|
||||||
try {
|
|
||||||
console.log('Setting up client side network objects');
|
|
||||||
|
|
||||||
// create fabric client and related instances
|
|
||||||
// starting point for all interactions with the fabric network
|
|
||||||
const {fabric_client, channel} = createFabricClient();
|
|
||||||
|
|
||||||
// create users from existing crypto materials
|
|
||||||
const {admin, user1, user2} = await createUsers();
|
|
||||||
|
|
||||||
console.log('Successfully setup client side');
|
|
||||||
|
|
||||||
let operation = null;
|
|
||||||
let user = null;
|
|
||||||
const args = [];
|
|
||||||
|
|
||||||
// if there is no argument, it will run demo by calling hardcoded token operations
|
|
||||||
// if there are arguments, it will invoke corresponding issue, list, transfer, redeem operations
|
|
||||||
if (process.argv.length == 2) {
|
|
||||||
demo(fabric_client, channel, admin, user1, user2)
|
|
||||||
return
|
|
||||||
} else if (process.argv.length >= 4) {
|
|
||||||
operation = process.argv[2];
|
|
||||||
if (process.argv[3] === 'user1') {
|
|
||||||
user = user1;
|
|
||||||
} else if (process.argv[3] === 'user2') {
|
|
||||||
user = user2;
|
|
||||||
} else {
|
|
||||||
throw new Error(util.format('Invalid username "%s". Must be user1 or user2', process.argv[3]));
|
|
||||||
}
|
|
||||||
for (let i = 4; i < process.argv.length; i++) {
|
|
||||||
if (process.argv[i]) {
|
|
||||||
console.log(' Token arg: ' + process.argv[i]);
|
|
||||||
args.push(process.argv[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error('Missing required arguments: operation, user');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\n\nStart %s token operation', operation);
|
|
||||||
let result = null;
|
|
||||||
switch (operation) {
|
|
||||||
case 'issue':
|
|
||||||
if (args.length < 2) {
|
|
||||||
throw new Error('Missing required parameter for issue: token_type, quantity');
|
|
||||||
}
|
|
||||||
result = await issue(fabric_client, channel, admin, user, args);
|
|
||||||
break;
|
|
||||||
case 'transfer':
|
|
||||||
if (args.length < 4) {
|
|
||||||
throw new Error('Missing required parameters for transfer: recipient, transfer_quantity, tx_id, index');
|
|
||||||
}
|
|
||||||
let recipient
|
|
||||||
if (args[0] === 'user1') {
|
|
||||||
recipient = user1;
|
|
||||||
} else if (args[0] === 'user2') {
|
|
||||||
recipient = user2;
|
|
||||||
} else {
|
|
||||||
throw new Error(util.format('Invalid recipient "%s". Must be user1 or user2', process.argv[3]));
|
|
||||||
}
|
|
||||||
// shift out args[0] because recipient object is passed separately
|
|
||||||
args.shift();
|
|
||||||
result = await transfer(fabric_client, channel, user, recipient, args);
|
|
||||||
break;
|
|
||||||
case 'redeem':
|
|
||||||
if (args.length < 3) {
|
|
||||||
throw new Error('Missing required parameter for redeem: quantity, tx_id, index');
|
|
||||||
}
|
|
||||||
result = await redeem(fabric_client, channel, user, args);
|
|
||||||
break;
|
|
||||||
case 'list':
|
|
||||||
result = await list(fabric_client, channel, user);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(' Unknown operation requested: ' + operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('End %s token operation, returns\n %s', operation, util.inspect(result, {depth: null}));
|
|
||||||
|
|
||||||
} catch(error) {
|
|
||||||
console.log('Problem with fabric token ::'+ error.toString());
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
console.log('\n\n --- fabtoken.js - end');
|
|
||||||
};
|
|
||||||
|
|
||||||
// demo invokes token operations using hardcoded parameters
|
|
||||||
async function demo(client, channel, admin, user1, user2) {
|
|
||||||
await reset(client, channel, user1, user2);
|
|
||||||
|
|
||||||
console.log('admin issues token to user1, wait 5 seconds for transaction to be committed');
|
|
||||||
await issue(client, channel, admin, user1, ['USD', '100']);
|
|
||||||
await sleep(5000)
|
|
||||||
|
|
||||||
let user1_tokens = await list(client, channel, user1);
|
|
||||||
console.log('\nuser1 has a token in USD type and 100 quantity after issue:\n%s', util.inspect(user1_tokens, {depth: null}));
|
|
||||||
|
|
||||||
console.log('\nuser1 transfers 30 quantity of the token to user2, wait 5 seconds for transaction to be committed');
|
|
||||||
let token_id = user1_tokens[0].id;
|
|
||||||
await transfer(client, channel, user1, user2, ['30', token_id.tx_id, token_id.index]);
|
|
||||||
await sleep(5000)
|
|
||||||
|
|
||||||
user1_tokens = await list(client, channel, user1);
|
|
||||||
console.log('\nuser1 has a token in 70 quantity after transfer:\n%s', util.inspect(user1_tokens, {depth: null}));
|
|
||||||
|
|
||||||
let user2_tokens = await list(client, channel, user2);
|
|
||||||
console.log('\nuser2 has a token in 30 quantity after transfer:\n%s', util.inspect(user2_tokens, {depth: null}));
|
|
||||||
|
|
||||||
console.log('\nuser1 redeems 10 out of 70 quantity of the token');
|
|
||||||
token_id = user1_tokens[0].id;
|
|
||||||
await redeem(client, channel, user1, ['10', token_id.tx_id, token_id.index]);
|
|
||||||
|
|
||||||
console.log('\nuser2 redeems entire token, wait 5 seconds for transaction to be committed');
|
|
||||||
token_id = user2_tokens[0].id;
|
|
||||||
await redeem(client, channel, user2, ['30', token_id.tx_id, token_id.index]);
|
|
||||||
await sleep(5000)
|
|
||||||
|
|
||||||
user1_tokens = await list(client, channel, user1);
|
|
||||||
console.log('\nuser1 has a token in 60 quantity after redeem:\n%s', util.inspect(user1_tokens, {depth: null}));
|
|
||||||
|
|
||||||
user2_tokens = await list(client, channel, user2);
|
|
||||||
console.log('\nuser2 has no token after redeem:\n%s', util.inspect(user2_tokens, {depth: null}));
|
|
||||||
|
|
||||||
await reset(client, channel, user1, user2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset removes all the existing tokens on the channel to get a fresh env
|
|
||||||
async function reset(client, channel, user1, user2) {
|
|
||||||
console.log('\nReset: remove all the tokens on the channel\n');
|
|
||||||
|
|
||||||
let tokens = await list(client, channel, user1);
|
|
||||||
for (const token of tokens) {
|
|
||||||
await redeem(client, channel, user1, [token.quantity, token.id.tx_id, token.id.index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens = await list(client, channel, user2);
|
|
||||||
for (const token of tokens) {
|
|
||||||
await redeem(client, channel, user2, [token.quantity, token.id.tx_id, token.id.index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue token to the user with args [type, quantity]
|
|
||||||
// It uses "admin" to issue tokens, but other users can also issue tokens as long as they have the permission.
|
|
||||||
async function issue(client, channel, admin, user, args) {
|
|
||||||
console.log('Start token issue with args ' + args);
|
|
||||||
|
|
||||||
await client.setUserContext(admin, true);
|
|
||||||
|
|
||||||
const tokenClient = client.newTokenClient(channel, 'localhost:7051');
|
|
||||||
|
|
||||||
// build the request to issue tokens to the user
|
|
||||||
const txId = client.newTransactionID();
|
|
||||||
const param = {
|
|
||||||
owner: user.getIdentity().serialize(),
|
|
||||||
type: args[0],
|
|
||||||
quantity: args[1]
|
|
||||||
};
|
|
||||||
const request = {
|
|
||||||
params: [param],
|
|
||||||
txId: txId,
|
|
||||||
};
|
|
||||||
|
|
||||||
return await tokenClient.issue(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfers token from the user to the recipient with args [quantity, tx_id, index]
|
|
||||||
async function transfer(client, channel, user, recipient, args) {
|
|
||||||
console.log('Start token transfer with args ' + args);
|
|
||||||
|
|
||||||
await client.setUserContext(user, true);
|
|
||||||
|
|
||||||
const tokenClient = client.newTokenClient(channel, 'localhost:7051');
|
|
||||||
|
|
||||||
// build the request to transfer tokens to the recipient
|
|
||||||
const txId = client.newTransactionID();
|
|
||||||
const param1 = {
|
|
||||||
owner: recipient.getIdentity().serialize(),
|
|
||||||
quantity: args[0]
|
|
||||||
};
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
tokenIds: [{tx_id: args[1], index: parseInt(args[2])}],
|
|
||||||
params: [param1],
|
|
||||||
txId: txId,
|
|
||||||
};
|
|
||||||
|
|
||||||
return await tokenClient.transfer(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redeem tokens from the user with args [quantity, tx_id, index]
|
|
||||||
async function redeem(client, channel, user, args) {
|
|
||||||
console.log('Start token redeem with args ' + args);
|
|
||||||
|
|
||||||
await client.setUserContext(user, true);
|
|
||||||
|
|
||||||
const tokenClient = client.newTokenClient(channel, 'localhost:7051');
|
|
||||||
|
|
||||||
// build the request to redeem tokens
|
|
||||||
const txId = client.newTransactionID();
|
|
||||||
const param = {
|
|
||||||
quantity: args[0]
|
|
||||||
};
|
|
||||||
const request = {
|
|
||||||
tokenIds: [{tx_id: args[1], index: parseInt(args[2])}],
|
|
||||||
params: [param],
|
|
||||||
txId: txId,
|
|
||||||
};
|
|
||||||
|
|
||||||
return await tokenClient.redeem(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List tokens for the user
|
|
||||||
async function list(client, channel, user) {
|
|
||||||
await client.setUserContext(user, true);
|
|
||||||
|
|
||||||
const tokenClient = client.newTokenClient(channel, 'localhost:7051');
|
|
||||||
|
|
||||||
return await tokenClient.list();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create fabric client, channel, orderer, and peer instances.
|
|
||||||
// These are needed for SDK to invoke token operations.
|
|
||||||
function createFabricClient() {
|
|
||||||
// fabric client instance
|
|
||||||
// starting point for all interactions with the fabric network
|
|
||||||
const fabric_client = new Fabric_Client();
|
|
||||||
|
|
||||||
// -- channel instance to represent the ledger
|
|
||||||
const channel = fabric_client.newChannel(channel_name);
|
|
||||||
console.log(' Created client side object to represent the channel');
|
|
||||||
|
|
||||||
// -- peer instance to represent a peer on the channel
|
|
||||||
const peer = fabric_client.newPeer('grpc://localhost:7051');
|
|
||||||
console.log(' Created client side object to represent the peer');
|
|
||||||
|
|
||||||
// -- orderer instance to reprsent the channel's orderer
|
|
||||||
const orderer = fabric_client.newOrderer('grpc://localhost:7050')
|
|
||||||
console.log(' Created client side object to represent the orderer');
|
|
||||||
|
|
||||||
// add peer and orderer to the channel
|
|
||||||
channel.addPeer(peer);
|
|
||||||
channel.addOrderer(orderer);
|
|
||||||
|
|
||||||
return {fabric_client: fabric_client, channel: channel};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create admin, user1 and user2 by loading crypto files
|
|
||||||
async function createUsers() {
|
|
||||||
// This sample application will read user idenitity information from
|
|
||||||
// pre-generated crypto files and create users. It will use a client object as
|
|
||||||
// an easy way to create the user objects from known cyrpto material.
|
|
||||||
|
|
||||||
const client = new Fabric_Client();
|
|
||||||
|
|
||||||
// load admin
|
|
||||||
let keyPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore');
|
|
||||||
let keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
|
|
||||||
let certPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts');
|
|
||||||
let certPEM = readAllFiles(certPath)[0];
|
|
||||||
|
|
||||||
let user_opts = {
|
|
||||||
username: 'admin',
|
|
||||||
mspid: 'Org1MSP',
|
|
||||||
skipPersistence: true,
|
|
||||||
cryptoContent: {
|
|
||||||
privateKeyPEM: keyPEM,
|
|
||||||
signedCertPEM: certPEM
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const admin = await client.createUser(user_opts);
|
|
||||||
|
|
||||||
// load user1
|
|
||||||
keyPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore');
|
|
||||||
keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
|
|
||||||
certPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts');
|
|
||||||
certPEM = readAllFiles(certPath)[0];
|
|
||||||
|
|
||||||
user_opts = {
|
|
||||||
username: 'user1',
|
|
||||||
mspid: 'Org1MSP',
|
|
||||||
skipPersistence: true,
|
|
||||||
cryptoContent: {
|
|
||||||
privateKeyPEM: keyPEM,
|
|
||||||
signedCertPEM: certPEM
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const user1 = await client.createUser(user_opts);
|
|
||||||
|
|
||||||
// load user2
|
|
||||||
keyPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/User2@org1.example.com/msp/keystore');
|
|
||||||
keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
|
|
||||||
certPath = path.join(__dirname, '../../basic-network/crypto-config/peerOrganizations/org1.example.com/users/User2@org1.example.com/msp/signcerts');
|
|
||||||
certPEM = readAllFiles(certPath)[0];
|
|
||||||
|
|
||||||
user_opts = {
|
|
||||||
username: 'user2',
|
|
||||||
mspid: 'Org1MSP',
|
|
||||||
skipPersistence: true,
|
|
||||||
cryptoContent: {
|
|
||||||
privateKeyPEM: keyPEM,
|
|
||||||
signedCertPEM: certPEM
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const user2 = await client.createUser(user_opts);
|
|
||||||
|
|
||||||
return {admin: admin, user1: user1, user2: user2};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readAllFiles(dir) {
|
|
||||||
const files = fs.readdirSync(dir);
|
|
||||||
const certs = [];
|
|
||||||
files.forEach((file_name) => {
|
|
||||||
const file_path = path.join(dir, file_name);
|
|
||||||
const data = fs.readFileSync(file_path);
|
|
||||||
certs.push(data);
|
|
||||||
});
|
|
||||||
return certs;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sleep(ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "fabtoken",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Hyperledger Fabric Token Sample Application",
|
|
||||||
"main": "fabtoken.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"fabric-client": "unstable",
|
|
||||||
"fs-extra": "^6.0.1",
|
|
||||||
"util": "^0.10.3"
|
|
||||||
},
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"keywords": [
|
|
||||||
"Hyperledger",
|
|
||||||
"Fabric",
|
|
||||||
"Token",
|
|
||||||
"Sample",
|
|
||||||
"Application"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Copyright IBM Corp All Rights Reserved
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
# Exit on first error
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# don't rewrite paths for Windows Git Bash users
|
|
||||||
export MSYS_NO_PATHCONV=1
|
|
||||||
starttime=$(date +%s)
|
|
||||||
|
|
||||||
# launch network; create channel and join peer to channel
|
|
||||||
cd ../basic-network
|
|
||||||
./start.sh
|
|
||||||
|
|
||||||
cat <<EOF
|
|
||||||
|
|
||||||
Total setup execution time : $(($(date +%s) - starttime)) secs ...
|
|
||||||
|
|
||||||
Next, use the FabToken application to interact with the Fabric network.
|
|
||||||
|
|
||||||
Start by changing into the "javascript" directory:
|
|
||||||
cd javascript
|
|
||||||
|
|
||||||
Next, install all required packages:
|
|
||||||
npm install
|
|
||||||
|
|
||||||
Then run the fabtoken application to perform the token operations.
|
|
||||||
|
|
||||||
node fabtoken
|
|
||||||
- when no argument is passed, it will run a demo with predefined token operations
|
|
||||||
node fabtoken issue <username> <token_type> <quantity>
|
|
||||||
- example: node fabtoken issue user1 USD 100
|
|
||||||
node fabtoken list <username>
|
|
||||||
- example: node fabtoken list user1
|
|
||||||
- select a token to transfer or redeem and pass "tx_id" and "index" as input parameters
|
|
||||||
node fabtoken transfer <from_user> <to_user> <quantity> <tx_id> <index>
|
|
||||||
- example: node fabtoken transfer user1 user2 30 c9b1211d9ad809e6ee1b542de6886d8d1d9e1c938d88eff23a3ddb4e8c080e4d 0
|
|
||||||
- <tx_id> and <index> are the "tx_id" and "index" returned from the list operation that specifies the token id for transfer
|
|
||||||
node fabtoken redeem <username> <quantity> <tx_id> <index>
|
|
||||||
- example: node fabtoken redeem user2 10 477c7bf2002814497c228fd8cbc4d80c8b7f1602b2c17ffadb6cf7e5783fa47a 0
|
|
||||||
- <tx_id> and <index> are the "tx_id" and "index" returned from the list operation
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
@ -16,9 +16,6 @@ Parse_Arguments() {
|
||||||
--fabcar_Tests)
|
--fabcar_Tests)
|
||||||
fabcar_Tests
|
fabcar_Tests
|
||||||
;;
|
;;
|
||||||
--fabtoken_Tests)
|
|
||||||
fabtoken_Tests
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
@ -54,22 +51,4 @@ fabcar_Tests() {
|
||||||
./fabcar.sh
|
./fabcar.sh
|
||||||
}
|
}
|
||||||
|
|
||||||
# run fabtoken tests
|
|
||||||
fabtoken_Tests() {
|
|
||||||
|
|
||||||
echo " #############################"
|
|
||||||
echo "npm version ------> $(npm -v)"
|
|
||||||
echo "node version ------> $(node -v)"
|
|
||||||
echo " #############################"
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo " _____ _ ____ _______ __ ___ __ _____ __ __ "
|
|
||||||
echo " | ___| / \ | __ ) |__ __| / _ \ | | / / | ____| | |\ | | "
|
|
||||||
echo " | |_ / _ \ | _ \ | | | | | | | |/ / | |___ | | \ | | "
|
|
||||||
echo " | _| / ___ \ | |_) | | | | |_ | | | |\ \ | ___| | | \ | | "
|
|
||||||
echo " |_| /_/ \_\ |____/ |_| \ __ / |_| \_\ |_|____ |_| \|_| "
|
|
||||||
|
|
||||||
./fabtoken.sh
|
|
||||||
}
|
|
||||||
|
|
||||||
Parse_Arguments $@
|
Parse_Arguments $@
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
# docker container list - Check these from basic-network/docker-compose.yaml
|
|
||||||
CONTAINER_LIST=(peer0.org1 orderer ca)
|
|
||||||
|
|
||||||
logs() {
|
|
||||||
|
|
||||||
for CONTAINER in ${CONTAINER_LIST[*]}; do
|
|
||||||
docker logs $CONTAINER.example.com >& $WORKSPACE/$CONTAINER-$1.log
|
|
||||||
echo
|
|
||||||
done
|
|
||||||
# Write couchdb container logs into couchdb.log file
|
|
||||||
docker logs couchdb >& couchdb.log
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_logs() {
|
|
||||||
|
|
||||||
# Call logs function
|
|
||||||
logs $2 $3
|
|
||||||
|
|
||||||
if [ $1 != 0 ]; then
|
|
||||||
echo -e "\033[31m $2 test case is FAILED" "\033[0m"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cd $WORKSPACE/$BASE_DIR/fabtoken || exit
|
|
||||||
export PATH=gopath/src/github.com/hyperledger/fabric-samples/bin:$PATH
|
|
||||||
|
|
||||||
LANGUAGE="javascript"
|
|
||||||
|
|
||||||
echo -e "\033[32m starting fabtoken test (${LANGUAGE})" "\033[0m"
|
|
||||||
./startFabric.sh
|
|
||||||
copy_logs $? fabtoken-start-script-${LANGUAGE}
|
|
||||||
|
|
||||||
pushd ${LANGUAGE}
|
|
||||||
npm install
|
|
||||||
node fabtoken.js
|
|
||||||
copy_logs $? fabtoken-${LANGUAGE}
|
|
||||||
popd
|
|
||||||
|
|
||||||
docker ps -aq | xargs docker rm -f
|
|
||||||
docker rmi -f $(docker images -aq dev-*)
|
|
||||||
echo -e "\033[32m finished fabtoken tests (${LANGUAGE})" "\033[0m"
|
|
||||||
Loading…
Reference in a new issue