diff --git a/Jenkinsfile b/Jenkinsfile index 304305ca86..21965e5413 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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 post { always { diff --git a/fabtoken/README.md b/fabtoken/README.md deleted file mode 100644 index c91000d99b..0000000000 --- a/fabtoken/README.md +++ /dev/null @@ -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 ` 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 `. 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 ` command. -* `` and `` are the "tx_id" and "index" that you found using the list -command -* `` 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 ` to redeem any tokens -belonging to user1 or user2. -* `` and `` are the "tx_id" and "index" returned from the list command -* `` 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. \ No newline at end of file diff --git a/fabtoken/javascript/.gitignore b/fabtoken/javascript/.gitignore deleted file mode 100644 index 3be8dfd89c..0000000000 --- a/fabtoken/javascript/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Dependency directories -node_modules/ -package-lock.json - diff --git a/fabtoken/javascript/fabtoken.js b/fabtoken/javascript/fabtoken.js deleted file mode 100644 index 54d0c6b4bd..0000000000 --- a/fabtoken/javascript/fabtoken.js +++ /dev/null @@ -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)); -} diff --git a/fabtoken/javascript/package.json b/fabtoken/javascript/package.json deleted file mode 100644 index 433febde5e..0000000000 --- a/fabtoken/javascript/package.json +++ /dev/null @@ -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" - ] -} diff --git a/fabtoken/startFabric.sh b/fabtoken/startFabric.sh deleted file mode 100755 index 664f8c3fb1..0000000000 --- a/fabtoken/startFabric.sh +++ /dev/null @@ -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 < - - example: node fabtoken issue user1 USD 100 - node fabtoken list - - example: node fabtoken list user1 - - select a token to transfer or redeem and pass "tx_id" and "index" as input parameters - node fabtoken transfer - - example: node fabtoken transfer user1 user2 30 c9b1211d9ad809e6ee1b542de6886d8d1d9e1c938d88eff23a3ddb4e8c080e4d 0 - - and are the "tx_id" and "index" returned from the list operation that specifies the token id for transfer - node fabtoken redeem - - example: node fabtoken redeem user2 10 477c7bf2002814497c228fd8cbc4d80c8b7f1602b2c17ffadb6cf7e5783fa47a 0 - - and are the "tx_id" and "index" returned from the list operation - -EOF diff --git a/scripts/ci_scripts/ciScript.sh b/scripts/ci_scripts/ciScript.sh index 8b2ffa03b4..f2edebf10a 100755 --- a/scripts/ci_scripts/ciScript.sh +++ b/scripts/ci_scripts/ciScript.sh @@ -16,9 +16,6 @@ Parse_Arguments() { --fabcar_Tests) fabcar_Tests ;; - --fabtoken_Tests) - fabtoken_Tests - ;; esac shift done @@ -54,22 +51,4 @@ fabcar_Tests() { ./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 $@ diff --git a/scripts/ci_scripts/fabtoken.sh b/scripts/ci_scripts/fabtoken.sh deleted file mode 100755 index 336c92cf9e..0000000000 --- a/scripts/ci_scripts/fabtoken.sh +++ /dev/null @@ -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"