diff --git a/chaincode/fabcar/javascript/.editorconfig b/chaincode/fabcar/javascript/.editorconfig new file mode 100755 index 000000000..75a13be20 --- /dev/null +++ b/chaincode/fabcar/javascript/.editorconfig @@ -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 diff --git a/chaincode/fabcar/javascript/.eslintignore b/chaincode/fabcar/javascript/.eslintignore new file mode 100644 index 000000000..159584701 --- /dev/null +++ b/chaincode/fabcar/javascript/.eslintignore @@ -0,0 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +coverage diff --git a/chaincode/fabcar/javascript/.eslintrc.js b/chaincode/fabcar/javascript/.eslintrc.js new file mode 100644 index 000000000..6d5751a5d --- /dev/null +++ b/chaincode/fabcar/javascript/.eslintrc.js @@ -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 }] + } +}; diff --git a/chaincode/fabcar/javascript/.gitignore b/chaincode/fabcar/javascript/.gitignore new file mode 100644 index 000000000..a00ca9415 --- /dev/null +++ b/chaincode/fabcar/javascript/.gitignore @@ -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 diff --git a/chaincode/fabcar/javascript/index.js b/chaincode/fabcar/javascript/index.js new file mode 100644 index 000000000..f5911c8c0 --- /dev/null +++ b/chaincode/fabcar/javascript/index.js @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const FabCar = require('./lib/fabcar'); + +module.exports.FabCar = FabCar; +module.exports.contracts = [ FabCar ]; diff --git a/chaincode/fabcar/javascript/lib/fabcar.js b/chaincode/fabcar/javascript/lib/fabcar.js new file mode 100644 index 000000000..53f2faefa --- /dev/null +++ b/chaincode/fabcar/javascript/lib/fabcar.js @@ -0,0 +1,156 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { Contract } = require('fabric-contract-api'); + +class FabCar extends Contract { + + async initLedger(ctx) { + console.info('============= START : Initialize Ledger ==========='); + const cars = [ + { + color: 'blue', + make: 'Toyota', + model: 'Prius', + owner: 'Tomoko', + }, + { + color: 'red', + make: 'Ford', + model: 'Mustang', + owner: 'Brad', + }, + { + color: 'green', + make: 'Hyundai', + model: 'Tucson', + owner: 'Jin Soo', + }, + { + color: 'yellow', + make: 'Volkswagen', + model: 'Passat', + owner: 'Max', + }, + { + color: 'black', + make: 'Tesla', + model: 'S', + owner: 'Adriana', + }, + { + color: 'purple', + make: 'Peugeot', + model: '205', + owner: 'Michel', + }, + { + color: 'white', + make: 'Chery', + model: 'S22L', + owner: 'Aarav', + }, + { + color: 'violet', + make: 'Fiat', + model: 'Punto', + owner: 'Pari', + }, + { + color: 'indigo', + make: 'Tata', + model: 'Nano', + owner: 'Valeria', + }, + { + color: 'brown', + make: 'Holden', + model: 'Barina', + owner: 'Shotaro', + }, + ]; + + for (let i = 0; i < cars.length; i++) { + cars[i].docType = 'car'; + await ctx.stub.putState('CAR' + i, Buffer.from(JSON.stringify(cars[i]))); + console.info('Added <--> ', cars[i]); + } + console.info('============= END : Initialize Ledger ==========='); + } + + async queryCar(ctx, carNumber) { + 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`); + } + console.log(carAsBytes.toString()); + return carAsBytes.toString(); + } + + async createCar(ctx, carNumber, make, model, color, owner) { + console.info('============= START : Create Car ==========='); + + const car = { + color, + docType: 'car', + make, + model, + owner, + }; + + await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car))); + console.info('============= END : Create Car ==========='); + } + + async queryAllCars(ctx) { + const startKey = 'CAR0'; + const endKey = 'CAR999'; + + const iterator = await ctx.stub.getStateByRange(startKey, endKey); + + const allResults = []; + while (true) { + const res = await iterator.next(); + + if (res.value && res.value.value.toString()) { + console.log(res.value.value.toString('utf8')); + + const Key = res.value.key; + let Record; + try { + Record = JSON.parse(res.value.value.toString('utf8')); + } catch (err) { + console.log(err); + Record = res.value.value.toString('utf8'); + } + allResults.push({ Key, Record }); + } + if (res.done) { + console.log('end of data'); + await iterator.close(); + console.info(allResults); + return JSON.stringify(allResults); + } + } + } + + async changeCarOwner(ctx, carNumber, newOwner) { + console.info('============= START : changeCarOwner ==========='); + + 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 : changeCarOwner ==========='); + } + +} + +module.exports = FabCar; diff --git a/chaincode/fabcar/javascript/package.json b/chaincode/fabcar/javascript/package.json new file mode 100644 index 000000000..2f9b98fba --- /dev/null +++ b/chaincode/fabcar/javascript/package.json @@ -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": "1.4.0-beta", + "fabric-shim": "1.4.0-beta" + }, + "devDependencies": { + "chai": "^4.1.2", + "eslint": "^4.19.1", + "mocha": "^5.2.0", + "nyc": "^12.0.2", + "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 + } +}