PerformanceLicense Chaincode

This commit is contained in:
Will Clinton 2020-05-12 03:39:56 +00:00
parent d53c1ef3b3
commit a6f928bc99
21 changed files with 4236 additions and 1 deletions

3
PerformanceLicense/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/node_modules/
/package-lock.json
/hfc-key-store/

View file

@ -0,0 +1,16 @@
#
# SPDX-License-Identifier: Apache-2.0
#
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View file

@ -0,0 +1,5 @@
#
# SPDX-License-Identifier: Apache-2.0
#
coverage

View file

@ -0,0 +1,37 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = {
env: {
node: true,
mocha: true
},
parserOptions: {
ecmaVersion: 8,
sourceType: 'script'
},
extends: "eslint:recommended",
rules: {
indent: ['error', 4],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'no-unused-vars': ['error', { args: 'none' }],
'no-console': 'off',
curly: 'error',
eqeqeq: 'error',
'no-throw-literal': 'error',
strict: 'error',
'no-var': 'error',
'dot-notation': 'error',
'no-tabs': 'error',
'no-trailing-spaces': 'error',
'no-use-before-define': 'error',
'no-useless-call': 'error',
'no-with': 'error',
'operator-linebreak': 'error',
yoda: 'error',
'quote-props': ['error', 'as-needed']
}
};

View file

@ -0,0 +1,80 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
wallet
!wallet/.gitkeep

View file

@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const FabricCAServices = require('fabric-ca-client');
const { Wallets } = require('fabric-network');
const fs = require('fs');
const path = require('path');
async function main() {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new CA client for interacting with the CA.
const caInfo = ccp.certificateAuthorities['ca.org1.example.com'];
const caTLSCACerts = caInfo.tlsCACerts.pem;
const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName);
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the admin user.
const identity = await wallet.get('admin');
if (identity) {
console.log('An identity for the admin user "admin" already exists in the wallet');
return;
}
// Enroll the admin user, and import the new identity into the wallet.
const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
const x509Identity = {
credentials: {
certificate: enrollment.certificate,
privateKey: enrollment.key.toBytes(),
},
mspId: 'Org1MSP',
type: 'X.509',
};
await wallet.put('admin', x509Identity);
console.log('Successfully enrolled admin user "admin" and imported it into the wallet');
} catch (error) {
console.error(`Failed to enroll admin user "admin": ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,55 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const fs = require('fs');
const path = require('path');
async function main() {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const identity = await wallet.get('appUser');
if (!identity) {
console.log('An identity for the user "appUser" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}
// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');
// Get the contract from the network.
const contractPerformance = network.getContract('PerformanceLicense', 'Performance');
const contractLicense = network.getContract('PerformanceLicense', 'License');
// Submit the specified transaction
await contractPerformance.submitTransaction('createPerformance', 'PER0', 'willc', 'Time 2 Boogie');
console.log('Transaction has been submitted');
await contractLicense.submitTransaction('createLicense', 'LIC0', 'PER0', 'Paramount', 'flat', '12/31/21');
// Disconnect from the gateway.
await gateway.disconnect();
} catch (error) {
console.error(`Failed to submit transaction: ${error}`);
process.exit(1);
}
}
main();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,46 @@
"name": "fabcar",
"version": "1.0.0",
"description": "FabCar application implemented in JavaScript",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "nyc mocha --recursive"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-ca-client": "^2.1.0",
"fabric-network": "^2.1.0"
},
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^5.9.0",
"mocha": "^5.2.0",
"nyc": "^14.1.1",
"sinon": "^7.1.1",
"sinon-chai": "^3.3.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}

View file

@ -0,0 +1,53 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Gateway, Wallets } = require('fabric-network');
const path = require('path');
const fs = require('fs');
async function main() {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const identity = await wallet.get('appUser');
if (!identity) {
console.log('An identity for the user "appUser" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}
// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');
// Get the contract from the network.
const contract = network.getContract('fabcar');
// Evaluate the specified transaction.
// queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4')
// queryAllCars transaction - requires no arguments, ex: ('queryAllCars')
const result = await contract.evaluateTransaction('queryAllCars');
console.log(`Transaction has been evaluated, result is: ${result.toString()}`);
} catch (error) {
console.error(`Failed to evaluate transaction: ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,73 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const fs = require('fs');
const path = require('path');
async function main() {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new CA client for interacting with the CA.
const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
const ca = new FabricCAServices(caURL);
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const userIdentity = await wallet.get('appUser');
if (userIdentity) {
console.log('An identity for the user "appUser" already exists in the wallet');
return;
}
// Check to see if we've already enrolled the admin user.
const adminIdentity = await wallet.get('admin');
if (!adminIdentity) {
console.log('An identity for the admin user "admin" does not exist in the wallet');
console.log('Run the enrollAdmin.js application before retrying');
return;
}
// build a user object for authenticating with the CA
const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
const adminUser = await provider.getUserContext(adminIdentity, 'admin');
// Register the user, enroll the user, and import the new identity into the wallet.
const secret = await ca.register({
affiliation: 'org1.department1',
enrollmentID: 'appUser',
role: 'client'
}, adminUser);
const enrollment = await ca.enroll({
enrollmentID: 'appUser',
enrollmentSecret: secret
});
const x509Identity = {
credentials: {
certificate: enrollment.certificate,
privateKey: enrollment.key.toBytes(),
},
mspId: 'Org1MSP',
type: 'X.509',
};
await wallet.put('appUser', x509Identity);
console.log('Successfully registered and enrolled admin user "appUser" and imported it into the wallet');
} catch (error) {
console.error(`Failed to register user "appUser": ${error}`);
process.exit(1);
}
}
main();

View file

@ -0,0 +1,18 @@
#!/bin/bash
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# Exit on first error
set -ex
# Bring the test network down
pushd ../test-network
./network.sh down
popd
# clean out any old identites in the wallets
rm -rf javascript/wallet/*
rm -rf java/wallet/*
rm -rf typescript/wallet/*

106
PerformanceLicense/startFabric.sh Executable file
View file

@ -0,0 +1,106 @@
#!/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)
CC_SRC_LANGUAGE=${1:-"go"}
CC_SRC_LANGUAGE=`echo "$CC_SRC_LANGUAGE" | tr [:upper:] [:lower:]`
if [ "$CC_SRC_LANGUAGE" != "go" -a "$CC_SRC_LANGUAGE" != "golang" -a "$CC_SRC_LANGUAGE" != "java" \
-a "$CC_SRC_LANGUAGE" != "javascript" -a "$CC_SRC_LANGUAGE" != "typescript" ] ; then
echo The chaincode language ${CC_SRC_LANGUAGE} is not supported by this script
echo Supported chaincode languages are: go, java, javascript, and typescript
exit 1
fi
# clean out any old identites in the wallets
rm -rf javascript/wallet/*
rm -rf java/wallet/*
rm -rf typescript/wallet/*
# launch network; create channel and join peer to channel
pushd ../test-network
./network.sh down
./network.sh up createChannel -ca -s couchdb
./network.sh deployCC -l ${CC_SRC_LANGUAGE}
popd
cat <<EOF
Total setup execution time : $(($(date +%s) - starttime)) secs ...
Next, use the FabCar applications to interact with the deployed FabCar contract.
The FabCar applications are available in multiple programming languages.
Follow the instructions for the programming language of your choice:
JavaScript:
Start by changing into the "javascript" directory:
cd javascript
Next, install all required packages:
npm install
Then run the following applications to enroll the admin user, and register a new user
called appUser which will be used by the other applications to interact with the deployed
FabCar contract:
node enrollAdmin
node registerUser
You can run the invoke application as follows. By default, the invoke application will
create a new car, but you can update the application to submit other transactions:
node invoke
You can run the query application as follows. By default, the query application will
return all cars, but you can update the application to evaluate other transactions:
node query
TypeScript:
Start by changing into the "typescript" directory:
cd typescript
Next, install all required packages:
npm install
Next, compile the TypeScript code into JavaScript:
npm run build
Then run the following applications to enroll the admin user, and register a new user
called appUser which will be used by the other applications to interact with the deployed
FabCar contract:
node dist/enrollAdmin
node dist/registerUser
You can run the invoke application as follows. By default, the invoke application will
create a new car, but you can update the application to submit other transactions:
node dist/invoke
You can run the query application as follows. By default, the query application will
return all cars, but you can update the application to evaluate other transactions:
node dist/query
Java:
Start by changing into the "java" directory:
cd java
Then, install dependencies and run the test using:
mvn test
The test will invoke the sample client app which perform the following:
- Enroll admin and appUser and import them into the wallet (if they don't already exist there)
- Submit a transaction to create a new car
- Evaluate a transaction (query) to return details of this car
- Submit a transaction to change the owner of this car
- Evaluate a transaction (query) to return the updated details of this car
EOF

View file

@ -0,0 +1,16 @@
#
# SPDX-License-Identifier: Apache-2.0
#
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View file

@ -0,0 +1,5 @@
#
# SPDX-License-Identifier: Apache-2.0
#
coverage

View file

@ -0,0 +1,38 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = {
env: {
node: true,
mocha: true
},
parserOptions: {
ecmaVersion: 8,
sourceType: 'script'
},
extends: "eslint:recommended",
rules: {
indent: ['error', 4],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'no-unused-vars': ['error', { args: 'none' }],
'no-console': 'off',
curly: 'error',
eqeqeq: 'error',
'no-throw-literal': 'error',
strict: 'error',
'no-var': 'error',
'dot-notation': 'error',
'no-tabs': 'error',
'no-trailing-spaces': 'error',
'no-use-before-define': 'error',
'no-useless-call': 'error',
'no-with': 'error',
'operator-linebreak': 'error',
yoda: 'error',
'quote-props': ['error', 'as-needed'],
'no-constant-condition': ["error", { "checkLoops": false }]
}
};

View file

@ -0,0 +1,77 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless

View file

@ -0,0 +1,12 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const Performance = require('./lib/PerformanceLicense').Performance;
const License = require('./lib/PerformanceLicense').License;
module.exports.Performance = Performance;
module.exports.License = License;
module.exports.contracts = [ Performance, License ];

View file

@ -0,0 +1,83 @@
/*
* * SPDX-License-Identifier: Apache-2.0
* */
'use strict';
const { Contract } = require('fabric-contract-api');
class Performance extends Contract {
async createPerformance(ctx, performanceID, artist, title) {
console.info('============= START : Create Performance ===========');
const performance = {
performanceID,
docType: 'performance',
artist,
title
};
await ctx.stub.putState(performanceID, Buffer.from(JSON.stringify(performance)));
console.info('============= END : Create Performance ===========');
}
async queryPerformance(ctx, performanceID) {
console.info('============= START : Query Performance ===========');
const performanceAsBytes = await ctx.stub.getState(performanceID); // get the car from chaincode state
if (!performanceAsBytes || performanceAsBytes.length === 0) {
throw new Error(`${performanceID} does not exist`);
}
console.log(performanceAsBytes.toString());
return performanceAsBytes.toString();
console.info('============= End : Query Performance ===========');
}
}
class License extends Contract {
async createLicense(ctx, licenseID, performanceID, license_recipient, type, expiration) {
console.info('============= START : Create License ===========');
const license = {
licenseID,
docType: 'license',
performanceID,
license_recipient,
type,
expiration,
};
await ctx.stub.putState(licenseID, Buffer.from(JSON.stringify(licenseID)));
console.info('============= END : Create License ===========');
}
async queryLicense(ctx, licenseID) {
console.info('============= START : Query License ===========');
const licenseAsBytes = await ctx.stub.getState(licenseID);
if (!licenseAsBytes || licenseAsBytes.length === 0) {
throw new Error(`${licenseID} does not exist`);
}
console.log(licenseAsBytes.toString());
return licenseAsBytes.toString();
console.info('============= END : Query License ===========');
}
async changeLicenseExpiration(ctx, licenseID, newExpiration) {
console.info('============= Begin : Change License Expiration ===========');
const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state
if (!carAsBytes || carAsBytes.length === 0) {
throw new Error(`${carNumber} does not exist`);
}
const car = JSON.parse(carAsBytes.toString());
car.owner = newOwner;
await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
console.info('============= END : Change License Expiration ===========');
}
}
module.exports.Performance = Performance;
module.exports.License = Liscense;

View file

@ -0,0 +1,47 @@
{
"name": "fabcar",
"version": "1.0.0",
"description": "FabCar contract implemented in JavaScript",
"main": "index.js",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "nyc mocha --recursive",
"start": "fabric-chaincode-node start"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "^2.0.0",
"fabric-shim": "^2.0.0"
},
"devDependencies": {
"chai": "^4.1.2",
"eslint": "^4.19.1",
"mocha": "^5.2.0",
"nyc": "^14.1.1",
"sinon": "^6.0.0",
"sinon-chai": "^3.2.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}

View file

@ -1,4 +1,5 @@
{
"name": "fabcar",
"version": "1.0.0",
"description": "FabCar application implemented in JavaScript",