- Added sample test chaincodes to test bityoga hyperledger fabric environment

- Refer README for more instructions
parent 45230e05
# Fabric Test Chaincodes
Chaincodes to test bityoga hyperledger fabric environment
# Prerequisite
* Hyper ledger fabric should be up and running (https://github.com/achak1987/fabric_as_code.git)
* ssh into the worker machine
* **Example** - ssh root@165.22.198.81
* Get into CLI container shell
* **Command** - docker exec -it $(docker ps -qf "name=^CLI") bash
* cd /root/CLI/chaincodes
* git clone https://github.com/bityoga/fabric_test_chaincodes.git
* cd /root/CLI/chaincodes/fabric_test_chaincodes
# Instructions
* **cd CHAIN_CODE_DIR/shell_scripts**
* **Example** - cd bank_chaincode/shell_scripts
* **Install chaincode** - bash install.sh
* **Instantiate chaincode** - bash instantiate.sh
* **GET request on chaincode** - bash get.sh
* **PUT request on chaincode** - bash put.sh
#
# SPDX-License-Identifier: Apache-2.0
#
coverage
/*
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = {
env: {
node: true,
mocha: true,
es6: 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 }]
}
};
#
# SPDX-License-Identifier: Apache-2.0
#
# Coverage directory used by tools like istanbul
coverage
# Report cache used by istanbul
.nyc_output
# Dependency directories
node_modules/
jspm_packages/
package-lock.json
#!/bin/bash
# peer lifecycle chaincode package basic.tar.gz --path ../src/ --lang node --label basic_1.0
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/articonf_demo/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
peer lifecycle chaincode package ${PACKAGE_NAME} --path ${CHAINCODE_SRC_CODE_PATH} --lang ${CHANCODE_LANGUAGE} --label ${CHAINCODE_LABEL}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode install basic.tar.gz
# peer lifecycle chaincode queryinstalled --output json
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/articonf_demo/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
peer lifecycle chaincode install ${PACKAGE_NAME} &&
peer lifecycle chaincode queryinstalled --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id
# peer lifecycle chaincode approveformyorg -o orderer:7050 --channelID appchannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/articonf_demo/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.member')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode approveformyorg -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --package-id ${CC_PACKAGE_ID} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode checkcommitreadiness --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --output json
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/articonf_demo/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode checkcommitreadiness --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode commit -o orderer:7050 --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt
# peer lifecycle chaincode querycommitted --channelID appchannel --name basic --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/articonf_demo/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode commit -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} &&
peer lifecycle chaincode querycommitted --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --cafile ${ORDERER_CA}
#!/bin/bash
# peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n basic --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c '{"Args":["InitLedger"]}'
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["CreateAsset","ark","100","Initial Credit"]}'
INVOKE_PARAMS2='{"Args":["CreateAsset","srk","100","Initial Credit"]}'
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS} &&
peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS2}
\ No newline at end of file
#!/bin/bash
# peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n basic --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c '{"Args":["InitLedger"]}'
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["InitLedger"]}'
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS}
\ No newline at end of file
#!/bin/bash
# peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n basic --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c '{"Args":["InitLedger"]}'
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["TransferBalance","ark","srk","5"]}'
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
#peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INSTANTIATE_PARAMS}
peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS}
\ No newline at end of file
#!/bin/bash
# peer chaincode query -C appchannel -n basic -c '{"Args":["GetAllAssets"]}'
set -x #echo on
CHAINCODE_NAME="articonf-bank-demo"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["GetAllAssets"]}'
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode query -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c ${QUERY_PARAMS}
\ No newline at end of file
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["GetAllAssets"]}'
#QUERY_PARAMS='{"Args":["ReadAsset","asset10"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode query -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $QUERY_PARAMS
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode install -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -l node -p $CHAINCODE_SRC_CODE_PATH
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
INSTANTIATE_PARAMS='{"Args":["InitLedger"]}'
CHANNEL_NAME="appchannel"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode instantiate -C $CHANNEL_NAME -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -c $INSTANTIATE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["CreateAsset","asset10","blue","70","Tom","200"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode invoke -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $INVOKE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const assetTransfer = require('./lib/assetTransfer');
module.exports.AssetTransfer = assetTransfer;
module.exports.contracts = [assetTransfer];
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
"use strict";
const { Contract } = require("fabric-contract-api");
class AssetTransfer extends Contract {
async InitLedger(ctx) {
const assets = [
{
ID: "demo1",
Balance: 100,
Type: "Initial Credit",
},
{
ID: "demo2",
Balance: 100,
Type: "Initial Credit",
},
];
for (const asset of assets) {
asset.docType = "asset";
await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
console.info(`User ${asset.ID} initialized`);
}
}
// CreateAsset issues a new asset to the world state with given details.
async CreateAsset(ctx, id, balance, type) {
const asset = {
ID: id,
Balance: balance,
Type: type,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
// ReadAsset returns the asset stored in the world state with given id.
async ReadAsset(ctx, id) {
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
if (!assetJSON || assetJSON.length === 0) {
throw new Error(`The user ${id} does not exist`);
}
return assetJSON.toString();
}
// UpdateAsset updates an existing asset in the world state with provided parameters.
async UpdateAsset(ctx, id, balance, type) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The user ${id} does not exist`);
}
// overwriting original asset with new asset
const updatedAsset = {
ID: id,
Balance: balance,
Type: type,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
}
// DeleteAsset deletes an given asset from the world state.
async DeleteAsset(ctx, id) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The user ${id} does not exist`);
}
return ctx.stub.deleteState(id);
}
// AssetExists returns true when asset with given ID exists in world state.
async AssetExists(ctx, id) {
const assetJSON = await ctx.stub.getState(id);
return assetJSON && assetJSON.length > 0;
}
// TransferAsset updates the owner field of asset with given id in the world state.
async TransferAsset(ctx, id, newOwner) {
const assetString = await this.ReadAsset(ctx, id);
const asset = JSON.parse(assetString);
asset.Owner = newOwner;
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
// GetAsset returns the asset stored in the world state with given id.
async GetAsset(ctx, id) {
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
if (!assetJSON || assetJSON.length === 0) {
throw new Error(`The user ${id} does not exist`);
}
return assetJSON;
}
// TransferAsset updates the owner field of asset with given id in the world state.
async TransferBalance(ctx, from_id, to_id, amount) {
const from_asset_string = await this.ReadAsset(ctx, from_id);
const to_asset_string = await this.ReadAsset(ctx, to_id);
let from_asset = JSON.parse(from_asset_string);
let to_asset = JSON.parse(to_asset_string);
console.log("from_asset");
console.log(from_asset);
console.log("to_asset");
console.log(to_asset);
let from_balance = parseInt(from_asset["Balance"].toString());
let to_balance = parseInt(to_asset["Balance"].toString());
let transfer_amount = parseInt(amount);
let updated_from_balance = from_balance - transfer_amount;
let updated_to_balance = to_balance + transfer_amount;
if (updated_from_balance < 0) {
throw new Error(`The user ${from_id} does not have sufficient balance`);
} else {
await this.UpdateAsset(ctx, from_id, updated_from_balance, "Debit");
await this.UpdateAsset(ctx, to_id, updated_to_balance, "Credit");
}
}
// GetAssetHistory returns the chain of custody for an asset since issuance.
async GetAssetHistory(ctx, assetName) {
let resultsIterator = await ctx.stub.getHistoryForKey(assetName);
let results = await this.GetAllResults(resultsIterator, true);
return JSON.stringify(results);
}
// GetAllAssets returns all assets found in the world state.
async GetAllAssets(ctx) {
const allResults = [];
// range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
const iterator = await ctx.stub.getStateByRange("", "");
let result = await iterator.next();
while (!result.done) {
const strValue = Buffer.from(result.value.value.toString()).toString(
"utf8"
);
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push({ Key: result.value.key, Record: record });
result = await iterator.next();
}
return JSON.stringify(allResults);
}
async GetAllResults(iterator, isHistory) {
let allResults = [];
let res = await iterator.next();
while (!res.done) {
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.value.toString("utf8"));
if (isHistory && isHistory === true) {
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
try {
jsonRes.Value = JSON.parse(res.value.value.toString("utf8"));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString("utf8");
}
} else {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString("utf8"));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString("utf8");
}
}
allResults.push(jsonRes);
}
res = await iterator.next();
}
iterator.close();
return allResults;
}
}
module.exports = AssetTransfer;
{
"name": "asset-transfer-basic",
"version": "1.0.0",
"description": "Asset-Transfer-Basic contract implemented in JavaScript",
"main": "index.js",
"engines": {
"node": ">=12",
"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": "^8.0.1",
"nyc": "^14.1.1",
"sinon": "^6.0.0",
"sinon-chai": "^3.2.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**",
"index.js",
".eslintrc.js"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
'use strict';
const sinon = require('sinon');
const chai = require('chai');
const sinonChai = require('sinon-chai');
const expect = chai.expect;
const { Context } = require('fabric-contract-api');
const { ChaincodeStub } = require('fabric-shim');
const AssetTransfer = require('../lib/assetTransfer.js');
let assert = sinon.assert;
chai.use(sinonChai);
describe('Asset Transfer Basic Tests', () => {
let transactionContext, chaincodeStub, asset;
beforeEach(() => {
transactionContext = new Context();
chaincodeStub = sinon.createStubInstance(ChaincodeStub);
transactionContext.setChaincodeStub(chaincodeStub);
chaincodeStub.putState.callsFake((key, value) => {
if (!chaincodeStub.states) {
chaincodeStub.states = {};
}
chaincodeStub.states[key] = value;
});
chaincodeStub.getState.callsFake(async (key) => {
let ret;
if (chaincodeStub.states) {
ret = chaincodeStub.states[key];
}
return Promise.resolve(ret);
});
chaincodeStub.deleteState.callsFake(async (key) => {
if (chaincodeStub.states) {
delete chaincodeStub.states[key];
}
return Promise.resolve(key);
});
chaincodeStub.getStateByRange.callsFake(async () => {
function* internalGetStateByRange() {
if (chaincodeStub.states) {
// Shallow copy
const copied = Object.assign({}, chaincodeStub.states);
for (let key in copied) {
yield {value: copied[key]};
}
}
}
return Promise.resolve(internalGetStateByRange());
});
asset = {
ID: 'asset1',
Color: 'blue',
Size: 5,
Owner: 'Tomoko',
AppraisedValue: 300,
};
});
describe('Test InitLedger', () => {
it('should return error on InitLedger', async () => {
chaincodeStub.putState.rejects('failed inserting key');
let assetTransfer = new AssetTransfer();
try {
await assetTransfer.InitLedger(transactionContext);
assert.fail('InitLedger should have failed');
} catch (err) {
expect(err.name).to.equal('failed inserting key');
}
});
it('should return success on InitLedger', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.InitLedger(transactionContext);
let ret = JSON.parse((await chaincodeStub.getState('asset1')).toString());
expect(ret).to.eql(Object.assign({docType: 'asset'}, asset));
});
});
describe('Test CreateAsset', () => {
it('should return error on CreateAsset', async () => {
chaincodeStub.putState.rejects('failed inserting key');
let assetTransfer = new AssetTransfer();
try {
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
assert.fail('CreateAsset should have failed');
} catch(err) {
expect(err.name).to.equal('failed inserting key');
}
});
it('should return success on CreateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString());
expect(ret).to.eql(asset);
});
});
describe('Test ReadAsset', () => {
it('should return error on ReadAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.ReadAsset(transactionContext, 'asset2');
assert.fail('ReadAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on ReadAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
let ret = JSON.parse(await chaincodeStub.getState(asset.ID));
expect(ret).to.eql(asset);
});
});
describe('Test UpdateAsset', () => {
it('should return error on UpdateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.UpdateAsset(transactionContext, 'asset2', 'orange', 10, 'Me', 500);
assert.fail('UpdateAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on UpdateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.UpdateAsset(transactionContext, 'asset1', 'orange', 10, 'Me', 500);
let ret = JSON.parse(await chaincodeStub.getState(asset.ID));
let expected = {
ID: 'asset1',
Color: 'orange',
Size: 10,
Owner: 'Me',
AppraisedValue: 500
};
expect(ret).to.eql(expected);
});
});
describe('Test DeleteAsset', () => {
it('should return error on DeleteAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.DeleteAsset(transactionContext, 'asset2');
assert.fail('DeleteAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on DeleteAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.DeleteAsset(transactionContext, asset.ID);
let ret = await chaincodeStub.getState(asset.ID);
expect(ret).to.equal(undefined);
});
});
describe('Test TransferAsset', () => {
it('should return error on TransferAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.TransferAsset(transactionContext, 'asset2', 'Me');
assert.fail('DeleteAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on TransferAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.TransferAsset(transactionContext, asset.ID, 'Me');
let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString());
expect(ret).to.eql(Object.assign({}, asset, {Owner: 'Me'}));
});
});
describe('Test GetAllAssets', () => {
it('should return success on GetAllAssets', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100);
await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200);
await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300);
await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400);
let ret = await assetTransfer.GetAllAssets(transactionContext);
ret = JSON.parse(ret);
expect(ret.length).to.equal(4);
let expected = [
{Record: {ID: 'asset1', Color: 'blue', Size: 5, Owner: 'Robert', AppraisedValue: 100}},
{Record: {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}},
{Record: {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}},
{Record: {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400}}
];
expect(ret).to.eql(expected);
});
it('should return success on GetAllAssets for non JSON value', async () => {
let assetTransfer = new AssetTransfer();
chaincodeStub.putState.onFirstCall().callsFake((key, value) => {
if (!chaincodeStub.states) {
chaincodeStub.states = {};
}
chaincodeStub.states[key] = 'non-json-value';
});
await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100);
await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200);
await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300);
await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400);
let ret = await assetTransfer.GetAllAssets(transactionContext);
ret = JSON.parse(ret);
expect(ret.length).to.equal(4);
let expected = [
{Record: 'non-json-value'},
{Record: {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}},
{Record: {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}},
{Record: {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400}}
];
expect(ret).to.eql(expected);
});
});
});
#
# SPDX-License-Identifier: Apache-2.0
#
coverage
/*
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = {
env: {
node: true,
mocha: true,
es6: 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 }]
}
};
#
# SPDX-License-Identifier: Apache-2.0
#
# Coverage directory used by tools like istanbul
coverage
# Report cache used by istanbul
.nyc_output
# Dependency directories
node_modules/
jspm_packages/
package-lock.json
#!/bin/bash
# peer lifecycle chaincode package basic.tar.gz --path ../src/ --lang node --label basic_1.0
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
#peer lifecycle chaincode package basic.tar.gz --path ../src/ --lang node --label basic_1.0
peer lifecycle chaincode package ${PACKAGE_NAME} --path ${CHAINCODE_SRC_CODE_PATH} --lang ${CHANCODE_LANGUAGE} --label ${CHAINCODE_LABEL}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode install basic.tar.gz
# peer lifecycle chaincode queryinstalled --output json
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
#peer lifecycle chaincode install basic.tar.gz
peer lifecycle chaincode install ${PACKAGE_NAME} &&
#peer lifecycle chaincode queryinstalled --output json
peer lifecycle chaincode queryinstalled --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id
# peer lifecycle chaincode approveformyorg -o orderer:7050 --channelID appchannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.member')"
export CHANNEL_NAME="appchannel"
export SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
#peer lifecycle chaincode approveformyorg -o orderer:7050 --channelID appchannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
peer lifecycle chaincode approveformyorg -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --package-id ${CC_PACKAGE_ID} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode checkcommitreadiness --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --output json
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
export CHANNEL_NAME="appchannel"
export SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
#peer lifecycle chaincode checkcommitreadiness --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --output json
peer lifecycle chaincode checkcommitreadiness --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode commit -o orderer:7050 --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt
# peer lifecycle chaincode querycommitted --channelID appchannel --name basic --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer/src"
CHANCODE_LANGUAGE="node"
export ORGANISATION_NAME="hlfMSP"
export SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
export CHANNEL_NAME="appchannel"
export SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
#peer lifecycle chaincode commit -o orderer:7050 --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt
peer lifecycle chaincode commit -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} &&
#peer lifecycle chaincode querycommitted --channelID appchannel --name basic --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
peer lifecycle chaincode querycommitted --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --cafile ${ORDERER_CA}
#!/bin/bash
# peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n basic --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c '{"Args":["InitLedger"]}'
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
INSTANTIATE_PARAMS='{"Args":["InitLedger"]}'
INVOKE_PARAMS='{"Args":["CreateAsset","asset10","blue","70","Tom","200"]}'
export ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n ${CHAINCODE_NAME} --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c $INSTANTIATE_PARAMS
#peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS}
\ No newline at end of file
#!/bin/bash
# peer chaincode query -C appchannel -n basic -c '{"Args":["GetAllAssets"]}'
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["GetAllAssets"]}'
ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode query -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c ${QUERY_PARAMS}
\ No newline at end of file
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["GetAllAssets"]}'
#QUERY_PARAMS='{"Args":["ReadAsset","asset10"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode query -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $QUERY_PARAMS
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/asset_transfer"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode install -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -l node -p $CHAINCODE_SRC_CODE_PATH
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHAINCODE_VERSION="1.0"
INSTANTIATE_PARAMS='{"Args":["InitLedger"]}'
CHANNEL_NAME="appchannel"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode instantiate -C $CHANNEL_NAME -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -c $INSTANTIATE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="asset"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["CreateAsset","asset10","blue","70","Tom","200"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode invoke -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $INVOKE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const assetTransfer = require('./lib/assetTransfer');
module.exports.AssetTransfer = assetTransfer;
module.exports.contracts = [assetTransfer];
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Contract } = require('fabric-contract-api');
class AssetTransfer extends Contract {
async InitLedger(ctx) {
const assets = [
{
ID: 'asset1',
Color: 'blue',
Size: 5,
Owner: 'Tomoko',
AppraisedValue: 300,
},
{
ID: 'asset2',
Color: 'red',
Size: 5,
Owner: 'Brad',
AppraisedValue: 400,
},
{
ID: 'asset3',
Color: 'green',
Size: 10,
Owner: 'Jin Soo',
AppraisedValue: 500,
},
{
ID: 'asset4',
Color: 'yellow',
Size: 10,
Owner: 'Max',
AppraisedValue: 600,
},
{
ID: 'asset5',
Color: 'black',
Size: 15,
Owner: 'Adriana',
AppraisedValue: 700,
},
{
ID: 'asset6',
Color: 'white',
Size: 15,
Owner: 'Michel',
AppraisedValue: 800,
},
];
for (const asset of assets) {
asset.docType = 'asset';
await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
console.info(`Asset ${asset.ID} initialized`);
}
}
// CreateAsset issues a new asset to the world state with given details.
async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
const asset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
// ReadAsset returns the asset stored in the world state with given id.
async ReadAsset(ctx, id) {
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
if (!assetJSON || assetJSON.length === 0) {
throw new Error(`The asset ${id} does not exist`);
}
return assetJSON.toString();
}
// UpdateAsset updates an existing asset in the world state with provided parameters.
async UpdateAsset(ctx, id, color, size, owner, appraisedValue) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The asset ${id} does not exist`);
}
// overwriting original asset with new asset
const updatedAsset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
}
// DeleteAsset deletes an given asset from the world state.
async DeleteAsset(ctx, id) {
const exists = await this.AssetExists(ctx, id);
if (!exists) {
throw new Error(`The asset ${id} does not exist`);
}
return ctx.stub.deleteState(id);
}
// AssetExists returns true when asset with given ID exists in world state.
async AssetExists(ctx, id) {
const assetJSON = await ctx.stub.getState(id);
return assetJSON && assetJSON.length > 0;
}
// TransferAsset updates the owner field of asset with given id in the world state.
async TransferAsset(ctx, id, newOwner) {
const assetString = await this.ReadAsset(ctx, id);
const asset = JSON.parse(assetString);
asset.Owner = newOwner;
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
// GetAllAssets returns all assets found in the world state.
async GetAllAssets(ctx) {
const allResults = [];
// range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
const iterator = await ctx.stub.getStateByRange('', '');
let result = await iterator.next();
while (!result.done) {
const strValue = Buffer.from(result.value.value.toString()).toString('utf8');
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push({ Key: result.value.key, Record: record });
result = await iterator.next();
}
return JSON.stringify(allResults);
}
}
module.exports = AssetTransfer;
{
"name": "asset-transfer-basic",
"version": "1.0.0",
"description": "Asset-Transfer-Basic contract implemented in JavaScript",
"main": "index.js",
"engines": {
"node": ">=12",
"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": "^8.0.1",
"nyc": "^14.1.1",
"sinon": "^6.0.0",
"sinon-chai": "^3.2.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**",
"index.js",
".eslintrc.js"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
'use strict';
const sinon = require('sinon');
const chai = require('chai');
const sinonChai = require('sinon-chai');
const expect = chai.expect;
const { Context } = require('fabric-contract-api');
const { ChaincodeStub } = require('fabric-shim');
const AssetTransfer = require('../lib/assetTransfer.js');
let assert = sinon.assert;
chai.use(sinonChai);
describe('Asset Transfer Basic Tests', () => {
let transactionContext, chaincodeStub, asset;
beforeEach(() => {
transactionContext = new Context();
chaincodeStub = sinon.createStubInstance(ChaincodeStub);
transactionContext.setChaincodeStub(chaincodeStub);
chaincodeStub.putState.callsFake((key, value) => {
if (!chaincodeStub.states) {
chaincodeStub.states = {};
}
chaincodeStub.states[key] = value;
});
chaincodeStub.getState.callsFake(async (key) => {
let ret;
if (chaincodeStub.states) {
ret = chaincodeStub.states[key];
}
return Promise.resolve(ret);
});
chaincodeStub.deleteState.callsFake(async (key) => {
if (chaincodeStub.states) {
delete chaincodeStub.states[key];
}
return Promise.resolve(key);
});
chaincodeStub.getStateByRange.callsFake(async () => {
function* internalGetStateByRange() {
if (chaincodeStub.states) {
// Shallow copy
const copied = Object.assign({}, chaincodeStub.states);
for (let key in copied) {
yield {value: copied[key]};
}
}
}
return Promise.resolve(internalGetStateByRange());
});
asset = {
ID: 'asset1',
Color: 'blue',
Size: 5,
Owner: 'Tomoko',
AppraisedValue: 300,
};
});
describe('Test InitLedger', () => {
it('should return error on InitLedger', async () => {
chaincodeStub.putState.rejects('failed inserting key');
let assetTransfer = new AssetTransfer();
try {
await assetTransfer.InitLedger(transactionContext);
assert.fail('InitLedger should have failed');
} catch (err) {
expect(err.name).to.equal('failed inserting key');
}
});
it('should return success on InitLedger', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.InitLedger(transactionContext);
let ret = JSON.parse((await chaincodeStub.getState('asset1')).toString());
expect(ret).to.eql(Object.assign({docType: 'asset'}, asset));
});
});
describe('Test CreateAsset', () => {
it('should return error on CreateAsset', async () => {
chaincodeStub.putState.rejects('failed inserting key');
let assetTransfer = new AssetTransfer();
try {
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
assert.fail('CreateAsset should have failed');
} catch(err) {
expect(err.name).to.equal('failed inserting key');
}
});
it('should return success on CreateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString());
expect(ret).to.eql(asset);
});
});
describe('Test ReadAsset', () => {
it('should return error on ReadAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.ReadAsset(transactionContext, 'asset2');
assert.fail('ReadAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on ReadAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
let ret = JSON.parse(await chaincodeStub.getState(asset.ID));
expect(ret).to.eql(asset);
});
});
describe('Test UpdateAsset', () => {
it('should return error on UpdateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.UpdateAsset(transactionContext, 'asset2', 'orange', 10, 'Me', 500);
assert.fail('UpdateAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on UpdateAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.UpdateAsset(transactionContext, 'asset1', 'orange', 10, 'Me', 500);
let ret = JSON.parse(await chaincodeStub.getState(asset.ID));
let expected = {
ID: 'asset1',
Color: 'orange',
Size: 10,
Owner: 'Me',
AppraisedValue: 500
};
expect(ret).to.eql(expected);
});
});
describe('Test DeleteAsset', () => {
it('should return error on DeleteAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.DeleteAsset(transactionContext, 'asset2');
assert.fail('DeleteAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on DeleteAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.DeleteAsset(transactionContext, asset.ID);
let ret = await chaincodeStub.getState(asset.ID);
expect(ret).to.equal(undefined);
});
});
describe('Test TransferAsset', () => {
it('should return error on TransferAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
try {
await assetTransfer.TransferAsset(transactionContext, 'asset2', 'Me');
assert.fail('DeleteAsset should have failed');
} catch (err) {
expect(err.message).to.equal('The asset asset2 does not exist');
}
});
it('should return success on TransferAsset', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue);
await assetTransfer.TransferAsset(transactionContext, asset.ID, 'Me');
let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString());
expect(ret).to.eql(Object.assign({}, asset, {Owner: 'Me'}));
});
});
describe('Test GetAllAssets', () => {
it('should return success on GetAllAssets', async () => {
let assetTransfer = new AssetTransfer();
await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100);
await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200);
await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300);
await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400);
let ret = await assetTransfer.GetAllAssets(transactionContext);
ret = JSON.parse(ret);
expect(ret.length).to.equal(4);
let expected = [
{Record: {ID: 'asset1', Color: 'blue', Size: 5, Owner: 'Robert', AppraisedValue: 100}},
{Record: {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}},
{Record: {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}},
{Record: {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400}}
];
expect(ret).to.eql(expected);
});
it('should return success on GetAllAssets for non JSON value', async () => {
let assetTransfer = new AssetTransfer();
chaincodeStub.putState.onFirstCall().callsFake((key, value) => {
if (!chaincodeStub.states) {
chaincodeStub.states = {};
}
chaincodeStub.states[key] = 'non-json-value';
});
await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100);
await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200);
await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300);
await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400);
let ret = await assetTransfer.GetAllAssets(transactionContext);
ret = JSON.parse(ret);
expect(ret.length).to.equal(4);
let expected = [
{Record: 'non-json-value'},
{Record: {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}},
{Record: {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}},
{Record: {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400}}
];
expect(ret).to.eql(expected);
});
});
});
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Init")
_, args := stub.GetFunctionAndParameters()
var A, B string // Entities
var Aval, Bval int // Asset holdings
var err error
if len(args) != 4 {
return shim.Error("Incorrect number of arguments. Expecting 4")
}
// Initialize the chaincode
A = args[0]
Aval, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
B = args[2]
Bval, err = strconv.Atoi(args[3])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Invoke")
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
// Make payment of X units from A to B
return t.invoke(stub, args)
} else if function == "delete" {
// Deletes an entity from its state
return t.delete(stub, args)
} else if function == "query" {
// the old "Query" is now implemtned in invoke
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A, B string // Entities
var Aval, Bval int // Asset holdings
var X int // Transaction value
var err error
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
A = args[0]
B = args[1]
// Get the state from the ledger
// TODO: will be nice to have a GetAllState call to ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
return shim.Error("Failed to get state")
}
if Avalbytes == nil {
return shim.Error("Entity not found")
}
Aval, _ = strconv.Atoi(string(Avalbytes))
Bvalbytes, err := stub.GetState(B)
if err != nil {
return shim.Error("Failed to get state")
}
if Bvalbytes == nil {
return shim.Error("Entity not found")
}
Bval, _ = strconv.Atoi(string(Bvalbytes))
// Perform the execution
X, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("Invalid transaction amount, expecting a integer value")
}
Aval = Aval - X
Bval = Bval + X
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state back to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
A := args[0]
// Delete the key from the state in ledger
err := stub.DelState(A)
if err != nil {
return shim.Error("Failed to delete state")
}
return shim.Success(nil)
}
// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A string // Entities
var err error
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
}
A = args[0]
// Get the state from the ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
return shim.Error(jsonResp)
}
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
fmt.Printf("Query Response:%s\n", jsonResp)
return shim.Success(Avalbytes)
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
bin/
.classpath
.settings/
.gradle
\ No newline at end of file
/*
* Copyright IBM Corp. 2018 All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.3'
id 'java'
}
group 'org.hyperledger.fabric-chaincode-java'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.+'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
shadowJar {
baseName = 'chaincode'
version = null
classifier = null
manifest {
attributes 'Main-Class': 'org.hyperledger.fabric.example.SimpleChaincode'
}
}
/*
* Copyright IBM Corp. 2017 All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
rootProject.name = 'fabric-chaincode-example-gradle'
/*
Copyright IBM Corp., DTCC All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.example;
import java.util.List;
import com.google.protobuf.ByteString;
import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SimpleChaincode extends ChaincodeBase {
private static Log _logger = LogFactory.getLog(SimpleChaincode.class);
@Override
public Response init(ChaincodeStub stub) {
try {
_logger.info("Init java simple chaincode");
String func = stub.getFunction();
if (!func.equals("init")) {
return newErrorResponse("function other than init is not supported");
}
List<String> args = stub.getParameters();
if (args.size() != 4) {
newErrorResponse("Incorrect number of arguments. Expecting 4");
}
// Initialize the chaincode
String account1Key = args.get(0);
int account1Value = Integer.parseInt(args.get(1));
String account2Key = args.get(2);
int account2Value = Integer.parseInt(args.get(3));
_logger.info(String.format("account %s, value = %s; account %s, value %s", account1Key, account1Value, account2Key, account2Value));
stub.putStringState(account1Key, args.get(1));
stub.putStringState(account2Key, args.get(3));
return newSuccessResponse();
} catch (Throwable e) {
return newErrorResponse(e);
}
}
@Override
public Response invoke(ChaincodeStub stub) {
try {
_logger.info("Invoke java simple chaincode");
String func = stub.getFunction();
List<String> params = stub.getParameters();
if (func.equals("invoke")) {
return invoke(stub, params);
}
if (func.equals("delete")) {
return delete(stub, params);
}
if (func.equals("query")) {
return query(stub, params);
}
return newErrorResponse("Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
} catch (Throwable e) {
return newErrorResponse(e);
}
}
private Response invoke(ChaincodeStub stub, List<String> args) {
if (args.size() != 3) {
return newErrorResponse("Incorrect number of arguments. Expecting 3");
}
String accountFromKey = args.get(0);
String accountToKey = args.get(1);
String accountFromValueStr = stub.getStringState(accountFromKey);
if (accountFromValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountFromKey));
}
int accountFromValue = Integer.parseInt(accountFromValueStr);
String accountToValueStr = stub.getStringState(accountToKey);
if (accountToValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountToKey));
}
int accountToValue = Integer.parseInt(accountToValueStr);
int amount = Integer.parseInt(args.get(2));
if (amount > accountFromValue) {
return newErrorResponse(String.format("not enough money in account %s", accountFromKey));
}
accountFromValue -= amount;
accountToValue += amount;
_logger.info(String.format("new value of A: %s", accountFromValue));
_logger.info(String.format("new value of B: %s", accountToValue));
stub.putStringState(accountFromKey, Integer.toString(accountFromValue));
stub.putStringState(accountToKey, Integer.toString(accountToValue));
_logger.info("Transfer complete");
return newSuccessResponse("invoke finished successfully", ByteString.copyFrom(accountFromKey + ": " + accountFromValue + " " + accountToKey + ": " + accountToValue, UTF_8).toByteArray());
}
// Deletes an entity from state
private Response delete(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String key = args.get(0);
// Delete the key from the state in ledger
stub.delState(key);
return newSuccessResponse();
}
// query callback representing the query of a chaincode
private Response query(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting name of the person to query");
}
String key = args.get(0);
//byte[] stateBytes
String val = stub.getStringState(key);
if (val == null) {
return newErrorResponse(String.format("Error: state for %s is null", key));
}
_logger.info(String.format("Query Response:\nName: %s, Amount: %s\n", key, val));
return newSuccessResponse(val, ByteString.copyFrom(val, UTF_8).toByteArray());
}
public static void main(String[] args) {
System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
new SimpleChaincode().start(args);
}
}
/*
Copyright IBM Corp., DTCC All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.example;
import java.util.List;
import com.google.protobuf.ByteString;
import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SimpleChaincode extends ChaincodeBase {
private static Log _logger = LogFactory.getLog(SimpleChaincode.class);
@Override
public Response init(ChaincodeStub stub) {
try {
_logger.info("Init java simple chaincode");
String func = stub.getFunction();
if (!func.equals("init")) {
return newErrorResponse("function other than init is not supported");
}
List<String> args = stub.getParameters();
if (args.size() != 4) {
newErrorResponse("Incorrect number of arguments. Expecting 4");
}
// Initialize the chaincode
String account1Key = args.get(0);
int account1Value = Integer.parseInt(args.get(1));
String account2Key = args.get(2);
int account2Value = Integer.parseInt(args.get(3));
_logger.info(String.format("account %s, value = %s; account %s, value %s", account1Key, account1Value, account2Key, account2Value));
stub.putStringState(account1Key, args.get(1));
stub.putStringState(account2Key, args.get(3));
return newSuccessResponse();
} catch (Throwable e) {
return newErrorResponse(e);
}
}
@Override
public Response invoke(ChaincodeStub stub) {
try {
_logger.info("Invoke java simple chaincode");
String func = stub.getFunction();
List<String> params = stub.getParameters();
if (func.equals("invoke")) {
return invoke(stub, params);
}
if (func.equals("delete")) {
return delete(stub, params);
}
if (func.equals("query")) {
return query(stub, params);
}
return newErrorResponse("Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
} catch (Throwable e) {
return newErrorResponse(e);
}
}
private Response invoke(ChaincodeStub stub, List<String> args) {
if (args.size() != 3) {
return newErrorResponse("Incorrect number of arguments. Expecting 3");
}
String accountFromKey = args.get(0);
String accountToKey = args.get(1);
String accountFromValueStr = stub.getStringState(accountFromKey);
if (accountFromValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountFromKey));
}
int accountFromValue = Integer.parseInt(accountFromValueStr);
String accountToValueStr = stub.getStringState(accountToKey);
if (accountToValueStr == null) {
return newErrorResponse(String.format("Entity %s not found", accountToKey));
}
int accountToValue = Integer.parseInt(accountToValueStr);
int amount = Integer.parseInt(args.get(2));
if (amount > accountFromValue) {
return newErrorResponse(String.format("not enough money in account %s", accountFromKey));
}
accountFromValue -= amount;
accountToValue += amount;
_logger.info(String.format("new value of A: %s", accountFromValue));
_logger.info(String.format("new value of B: %s", accountToValue));
stub.putStringState(accountFromKey, Integer.toString(accountFromValue));
stub.putStringState(accountToKey, Integer.toString(accountToValue));
_logger.info("Transfer complete");
return newSuccessResponse("invoke finished successfully", ByteString.copyFrom(accountFromKey + ": " + accountFromValue + " " + accountToKey + ": " + accountToValue, UTF_8).toByteArray());
}
// Deletes an entity from state
private Response delete(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String key = args.get(0);
// Delete the key from the state in ledger
stub.delState(key);
return newSuccessResponse();
}
// query callback representing the query of a chaincode
private Response query(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting name of the person to query");
}
String key = args.get(0);
//byte[] stateBytes
String val = stub.getStringState(key);
if (val == null) {
return newErrorResponse(String.format("Error: state for %s is null", key));
}
_logger.info(String.format("Query Response:\nName: %s, Amount: %s\n", key, val));
return newSuccessResponse(val, ByteString.copyFrom(val, UTF_8).toByteArray());
}
public static void main(String[] args) {
System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
new SimpleChaincode().start(args);
}
}
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
const shim = require('fabric-shim');
const util = require('util');
var Chaincode = class {
// Initialize the chaincode
async Init(stub) {
console.info('========= example02 Init =========');
let ret = stub.getFunctionAndParameters();
console.info(ret);
let args = ret.params;
// initialise only if 4 parameters passed.
if (args.length != 4) {
return shim.error('Incorrect number of arguments. Expecting 4');
}
let A = args[0];
let B = args[2];
let Aval = args[1];
let Bval = args[3];
if (typeof parseInt(Aval) !== 'number' || typeof parseInt(Bval) !== 'number') {
return shim.error('Expecting integer value for asset holding');
}
try {
await stub.putState(A, Buffer.from(Aval));
try {
await stub.putState(B, Buffer.from(Bval));
return shim.success();
} catch (err) {
return shim.error(err);
}
} catch (err) {
return shim.error(err);
}
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.log('no method of name:' + ret.fcn + ' found');
return shim.success();
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async invoke(stub, args) {
if (args.length != 3) {
throw new Error('Incorrect number of arguments. Expecting 3');
}
let A = args[0];
let B = args[1];
if (!A || !B) {
throw new Error('asset holding must not be empty');
}
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
throw new Error('Failed to get state of asset holder A');
}
let Aval = parseInt(Avalbytes.toString());
let Bvalbytes = await stub.getState(B);
if (!Bvalbytes) {
throw new Error('Failed to get state of asset holder B');
}
let Bval = parseInt(Bvalbytes.toString());
// Perform the execution
let amount = parseInt(args[2]);
if (typeof amount !== 'number') {
throw new Error('Expecting integer value for amount to be transaferred');
}
Aval = Aval - amount;
Bval = Bval + amount;
console.info(util.format('Aval = %d, Bval = %d\n', Aval, Bval));
// Write the states back to the ledger
await stub.putState(A, Buffer.from(Aval.toString()));
await stub.putState(B, Buffer.from(Bval.toString()));
}
// Deletes an entity from state
async delete(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting 1');
}
let A = args[0];
// Delete the key from the state in ledger
await stub.deleteState(A);
}
// query callback representing the query of a chaincode
async query(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the person to query')
}
let jsonResp = {};
let A = args[0];
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
jsonResp.error = 'Failed to get state for ' + A;
throw new Error(JSON.stringify(jsonResp));
}
jsonResp.name = A;
jsonResp.amount = Avalbytes.toString();
console.info('Query Response:');
console.info(jsonResp);
return Avalbytes;
}
};
shim.start(new Chaincode());
{
"name": "chaincode_example02",
"version": "1.0.0",
"description": "chaincode_example02 chaincode implemented in node.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": { "start" : "node chaincode_example02.js" },
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "~1.4.0"
}
}
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode query -C appchannel -n bankcc -c '{"Args":["query","a"]}'
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode install -n bankcc -v 1.0 -l node -p /root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode instantiate -C appchannel -n bankcc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode invoke -C appchannel -n bankcc -c '{"Args":["invoke","a","b","10"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
# peer lifecycle chaincode package basic.tar.gz --path ../src/ --lang node --label basic_1.0
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
CHANCODE_LANGUAGE="node"
ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
peer lifecycle chaincode package ${PACKAGE_NAME} --path ${CHAINCODE_SRC_CODE_PATH} --lang ${CHANCODE_LANGUAGE} --label ${CHAINCODE_LABEL}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode install basic.tar.gz
# peer lifecycle chaincode queryinstalled --output json
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
CHANCODE_LANGUAGE="node"
ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
peer lifecycle chaincode install ${PACKAGE_NAME} &&
peer lifecycle chaincode queryinstalled --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id
# peer lifecycle chaincode approveformyorg -o orderer:7050 --channelID appchannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
CHANCODE_LANGUAGE="node"
ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.member')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode approveformyorg -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --package-id ${CC_PACKAGE_ID} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA}
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode checkcommitreadiness --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --output json
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
CHANCODE_LANGUAGE="node"
ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode checkcommitreadiness --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --output json
\ No newline at end of file
#!/bin/bash
# peer lifecycle chaincode commit -o orderer:7050 --channelID appchannel --name basic --version 1.0 --sequence 1 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt
# peer lifecycle chaincode querycommitted --channelID appchannel --name basic --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
PACKAGE_NAME="${CHAINCODE_NAME}.tar.gz"
CHAINCODE_LABEL="${CHAINCODE_NAME}_${CHAINCODE_VERSION}"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
CHANCODE_LANGUAGE="node"
ORGANISATION_NAME="hlfMSP"
SIGNATURE_POLICY="OR('${ORGANISATION_NAME}.peer')"
CHANNEL_NAME="appchannel"
SEQUENCE="1"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CC_PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
peer lifecycle chaincode commit -o ${ORDERER_HOST}:7050 --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --version ${CHAINCODE_VERSION} --sequence ${SEQUENCE} --tls --cafile ${ORDERER_CA} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} &&
peer lifecycle chaincode querycommitted --channelID ${CHANNEL_NAME} --name ${CHAINCODE_NAME} --cafile ${ORDERER_CA}
#!/bin/bash
# peer chaincode invoke -o orderer:7050 --tls --cafile /root/CLI/orgca/orderer/msp/tls/ca.crt -C appchannel -n bank --peerAddresses peer2:7051 --tlsRootCertFiles /root/CLI/orgca/peer2/msp/tls/ca.crt -c '{"Args":["init","a","100","b","200"]}'
set -x #echo on
CHAINCODE_NAME="bank"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["invoke","a","b","10"]}'
INSTANTIATE_PARAMS='{"Args":["init","a","100","b","200"]}'
ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode invoke -o ${ORDERER_HOST}:7050 --tls --cafile ${ORDERER_CA} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} --peerAddresses ${CORE_PEER_ADDRESS} --tlsRootCertFiles ${CORE_PEER_TLS_ROOTCERT_FILE} -c ${INVOKE_PARAMS}
\ No newline at end of file
#!/bin/bash
# peer chaincode query -C appchannel -n bank -c '{"Args":["query","a"]}'
set -x #echo on
CHAINCODE_NAME="bank"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["query","a"]}'
ORGANISATION_NAME="hlfMSP"
export PEER_HOST=peer2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=${ORGANISATION_NAME}
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export ORDERER_CA=/root/CLI/${ORGCA_HOST}/${ORDERER_HOST}/msp/tls/ca.crt
export PACKAGE_ID=$(peer lifecycle chaincode queryinstalled --output json | jq .installed_chaincodes[0].package_id)
peer chaincode query -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c ${QUERY_PARAMS}
\ No newline at end of file
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="bank"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["query","a"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode query -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $QUERY_PARAMS
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/bank_chaincode/node"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode install -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -l node -p $CHAINCODE_SRC_CODE_PATH
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="bank"
CHAINCODE_VERSION="1.0"
INSTANTIATE_PARAMS='{"Args":["init","a","100","b","200"]}'
CHANNEL_NAME="appchannel"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode instantiate -C $CHANNEL_NAME -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -c $INSTANTIATE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="bank"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["invoke","a","b","10"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode invoke -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $INVOKE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
# carsharing-chaincodes
Node project to develop chaincodes
\ No newline at end of file
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode query -C appchannel -n carcc -c '{"Args":["listCars"]}'
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode install -n carcc -v 1.0 -l node -p /root/CLI/chaincodes/fabric_test_chaincodes/carsharing-chaincodes-develop/src/chaincode
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode instantiate -C appchannel -n carcc -v 1.0 -c '{"Args":["init"]}' -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode invoke -C appchannel -n carcc -c '{"Args":["createCar","NO9276","Opel","Corsa","Blue","5","2019","1"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE} &&
peer chaincode invoke -C appchannel -n carcc -c '{"Args":["createCar","NO9277","Jaguar","ftype","Black","5","2019","1"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE} &&
peer chaincode invoke -C appchannel -n carcc -c '{"Args":["createCar","NO9278","Dacia","Duster","Green","5","2019","1"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE} &&
peer chaincode invoke -C appchannel -n carcc -c '{"Args":["createCar","NO9279","Volvo","V90","White","5","2019","1"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="car"
CHANNEL_NAME="appchannel"
QUERY_PARAMS='{"Args":["listCars"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode query -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $QUERY_PARAMS
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="car"
CHAINCODE_VERSION="1.0"
CHAINCODE_SRC_CODE_PATH="/root/CLI/chaincodes/fabric_test_chaincodes/carsharing-chaincodes-develop/src/chaincode"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode install -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -l node -p $CHAINCODE_SRC_CODE_PATH
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="car"
CHAINCODE_VERSION="1.0"
INSTANTIATE_PARAMS='{"Args":["init"]}'
CHANNEL_NAME="appchannel"
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode instantiate -C $CHANNEL_NAME -n $CHAINCODE_NAME -v $CHAINCODE_VERSION -c $INSTANTIATE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
CHAINCODE_NAME="car"
CHANNEL_NAME="appchannel"
INVOKE_PARAMS='{"Args":["createCar","NO9276","Opel","Corsa","Blue","5","2019","1"]}'
export PEER_HOST=peer2
export CORE_PEER_ADDRESS=${PEER_HOST}:7051
export CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${ADMIN_USER}/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp/tls/ca.crt
CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS CORE_PEER_MSPCONFIGPATH=/root/CLI/${ORGCA_HOST}/${PEER_HOST}/msp CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE peer chaincode invoke -C $CHANNEL_NAME -n $CHAINCODE_NAME -c $INVOKE_PARAMS -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#
# 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
#
# SPDX-License-Identifier: Apache-2.0
#
coverage
/*
* 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],
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']
}
};
#
# 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
# vscode sudo execution files
/~
~
# Network directory
network/
# vscode config
.vscode/
\ No newline at end of file
#
# SPDX-License-Identifier: Apache-2.0
#
# don't package the connection details
local_fabric
# don't package the tests
test
functionalTests
# don't package config files
.vscode
.editorconfig
.eslintignore
.eslintrc.js
.gitignore
.npmignore
'use strict';
const assert = require('assert');
let car = {
docType: String,
carLicensePlate: String,
brand: String,
model: String,
colour: String,
seats: Number,
yearOfEnrollment: Number,
ownerId: String,
notDeleted: Boolean,
status: String,
available: Boolean,
observations: String
};
class CarAsset {
// Car status: 0 = Ok, 1 = notOk, 2 = notChecked
async create(carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations, ownerId) {
assert(carLicensePlate, 'Car license plate not must be undefined');
assert(brand, 'Brand not must be undefined');
assert(model, 'Model not must be undefined');
assert(colour, 'Colour not must be undefined');
assert(seats, 'Seats not must be undefined');
assert(yearOfEnrollment, 'Year of enrollment not must be undefined');
assert(ownerId, 'Owner Id not must be undefined');
assert.equal(isNaN(seats), false, 'Seats must be a number');
assert.equal(isNaN(yearOfEnrollment), false, 'Year of enrollment must be a number');
car.docType = 'car';
car.carLicensePlate = carLicensePlate;
car.brand = brand;
car.model = model;
car.colour = colour;
car.seats = parseInt(seats);
car.yearOfEnrollment = parseInt(yearOfEnrollment);
car.ownerId = ownerId;
car.notDeleted = true;
car.status = 2;
car.available = true;
car.observations = observations;
return car;
}
async edit(carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations, ownerId, notDeleted) {
assert(carLicensePlate, 'Car license plate not must be undefined');
assert(brand, 'Brand not must be undefined');
assert(model, 'Model not must be undefined');
assert(colour, 'Colour not must be undefined');
assert(seats, 'Seats not must be undefined');
assert(yearOfEnrollment, 'Year of enrollment not must be undefined');
assert(ownerId, 'Owner Id not must be undefined');
assert(notDeleted, false, 'The car do not exist')
assert.equal(isNaN(seats), false, 'Seats must be a number');
assert.equal(isNaN(yearOfEnrollment), false, 'Year of enrollment must be a number');
car.docType = 'car';
car.carLicensePlate = carLicensePlate;
car.brand = brand;
car.model = model;
car.colour = colour;
car.seats = parseInt(seats);
car.yearOfEnrollment = parseInt(yearOfEnrollment);
car.ownerId = ownerId;
car.notDeleted = true;
car.observations = observations;
return car;
}
async deleteCar(car, notDeleted){
assert(car, 'Car cannot be undefined');
assert(notDeleted, 'Not deleted state cannot be undefined');
if(notDeleted == "true"){
car.notDeleted = true;
}else{
car.notDeleted = false;
}
return car;
}
}
module.exports = {
CarAsset
};
\ No newline at end of file
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const shim = require('fabric-shim');
// const { Contract } = require('fabric-contract-api');
const { ClientIdentity } = require('fabric-shim');
const assert = require('assert');
const { CarAsset } = require('./carAsset');
const { OfferAsset } = require('./offerAsset');
const { TravelAsset } = require('./travelAsset');
const { UserAsset } = require('./userAsset');
// const { User } = require('./user');
const util = require('./util');
let carAsset = new CarAsset();
let offerAsset = new OfferAsset();
let travelAsset = new TravelAsset();
let userAsset = new UserAsset();
//let user = new User();
let myContract;
class MyContract {
async Init(stub) {
myContract = new MyContract();
try {
return shim.success();
} catch (e) {
return shim.error(e);
}
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
let method = this[ret.fcn];
if (!method) {
console.log('no function of name:' + ret.fcn + ' found');
throw new Error('Received unknown function ' + ret.fcn + ' invocation');
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async createUser(stub, args) {
let [userId] = args;
let asset = await userAsset.create(userId);
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(userId, buffer);
return buffer;
}
// // CAR ------------------------------------------------------------------------------
async createCar(stub, args) {
let [carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations] = args;
const exists = await myContract.assetExists(stub, carLicensePlate);
if (exists) {
let car = await myContract.readAsset(stub, carLicensePlate);
if (car.notDeleted == true) {
throw new Error(`The my asset ${carLicensePlate} exist`);
}
}
let cid = new ClientIdentity(stub);
let ownerId = cid.getID();
let asset = await carAsset.create(carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations, ownerId);
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(carLicensePlate, buffer);
return buffer;
}
async updateCar(stub, args) {
let [carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations] = args;
const exists = await myContract.assetExists(stub, carLicensePlate);
if (!exists) {
throw new Error(`The my asset ${carLicensePlate} does not exist`);
}
const car = await myContract.readAsset(stub, carLicensePlate)
if (car.notDeleted == false) {
throw new Error(`You can not edit a car that is deleted`)
}
const notDeleted = car.notDeleted
let cid = new ClientIdentity(stub);
let ownerId = cid.getID();
assert.equal(car.ownerId, ownerId, 'You can not edit this car');
const asset = await carAsset.edit(carLicensePlate, brand, model, colour, seats, yearOfEnrollment, observations, ownerId, notDeleted);
const buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(carLicensePlate, buffer);
return buffer;
}
async deleteCar(stub, args) {
let [carLicensePlate] = args;
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
const car = await myContract.readAsset(stub, carLicensePlate)
assert.equal(car.ownerId, clientID, 'You cannot delete a car you dont own')
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'offer';
queryString.selector.notDeleted = true;
queryString.selector.car = {};
queryString.selector.car.carLicensePlate = carLicensePlate;
const buffer = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
let offers = JSON.parse(buffer.toString());
assert.equal(offers.length, 0, 'You cannot delete a car within a Offer')
const asset = await carAsset.deleteCar(car, "false");
await myContract.saveAssetState(stub, carLicensePlate, asset);
let bufferCar = Buffer.from(JSON.stringify(asset));
return bufferCar;
}
async findAllCarsByOwner(stub) {
let clientLogged = await myContract.getClientLogged(stub);
clientLogged = JSON.parse(clientLogged.toString());
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'car';
queryString.selector.ownerId = clientLogged;
queryString.selector.notDeleted = true;
const buffer = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
return buffer;
}
async findOneCar(stub, args) {
let [carLicensePlate] = args;
let asset = await myContract.readAsset(stub, carLicensePlate);
assert.equal(asset.docType, 'car', 'Car not found');
let buffer = Buffer.from(JSON.stringify(asset));
return buffer;
}
async listCars(stub) {
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'car';
const buffer = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
const asset = JSON.parse(buffer.toString());
return buffer;
}
// // OFFERS ---------------------------------------------------------------------------
async findOneOffer(stub, args) {
let [offerId] = args;
let offer = await offerAsset.findOne(stub, offerId);
let buffer = Buffer.from(JSON.stringify(offer));
return buffer;
}
async createOffer(stub, args) {
let [carLicensePlate, priceForKm, priceForTime, startDate, endDate, deposit, startPlace,
endPlaces] = args;
// Check if car exists
let car = await myContract.readAsset(stub, carLicensePlate);
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
assert.equal(car.notDeleted, true, 'You cannot create an offer with a deleted car')
assert.equal(clientID, car.ownerId, 'You must be the car owner to add it to an offer');
let asset = await offerAsset.create(car, priceForKm, priceForTime, startDate, endDate,
deposit, startPlace, endPlaces);
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(asset.id, buffer);
return buffer;
}
async updateOffer(stub, args) {
let [id, carLicensePlate, priceForKm, priceForTime, startDate, endDate, deposit,
startPlace, endPlaces, notDeleted] = args;
// Check if assets exists
let car = await myContract.readAsset(stub, carLicensePlate);
let offer = await myContract.readAsset(stub, id);
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
assert.equal(clientID, car.ownerId, 'You must be the car owner to add it to an offer');
assert.equal(clientID, offer.car.ownerId, 'You must be the car owner to add it to an offer');
const asset = await offerAsset.edit(id, car, priceForKm, priceForTime, startDate, endDate,
deposit, startPlace, endPlaces, notDeleted);
const buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(id, buffer);
return buffer;
}
async listOffers(stub, args) {
let [seats, startCoordinates, limitKm, endCoordinates] = args;
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'offer';
// queryString.selector.notDeleted = true;
if (parseInt(seats)) {
queryString.selector.car = {};
queryString.selector.car.seats = { $gte: parseInt(seats) };
}
let buffer = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
let offers = JSON.parse(buffer.toString());
if ((startCoordinates || endCoordinates) && limitKm) {
offers = await offerAsset.filterByLimit(offers, startCoordinates, endCoordinates, limitKm);
buffer = Buffer.from(JSON.stringify(offers));
}
return buffer;
}
// ----------------------------------TRAVELS-----------------------------------------
async editAvailabilityOffer(stub, args) {
let [offerId, available] = args;
let offer = await offerAsset.editAvailability(stub, offerId, available);
let buffer = Buffer.from(JSON.stringify(offer));
return buffer;
}
async createTravel(stub, args) {
let [offerId, initTime, finishTime, passengers, destination, rentForTime, observations] = args;
let clientLogged = await myContract.getClientLogged(stub);
clientLogged = JSON.parse(clientLogged.toString());
clientLogged = await myContract.readAsset(stub, clientLogged);
let offer = await myContract.readAsset(stub, offerId);
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
let asset = await travelAsset.create(offer, initTime, finishTime, clientID, passengers,
destination, rentForTime, observations);
[clientLogged, asset] = await userAsset.transfer(clientLogged, asset, asset.totalPrice, "balance", "priceBalance");
await myContract.saveAssetState(stub, clientLogged.id, clientLogged);
await myContract.saveAssetState(stub, asset.id, asset);
[clientLogged, asset] = await userAsset.transfer(clientLogged, asset, offer.deposit, "balance", "depositBalance");
await myContract.saveAssetState(stub, clientLogged.id, clientLogged);
await myContract.saveAssetState(stub, asset.id, asset);
let buffer = Buffer.from(JSON.stringify(asset));
return buffer;
}
// // 0 = Ok, 1 = NotOk, 2 = NotChecked
async checkCar(stub, args) {
let [carLicensePlate, status] = args;
// Query all travels with car license plate equals to carLicensePlate and status not checked
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'travel';
queryString.selector.carLicensePlate = carLicensePlate;
queryString.selector.carStatus = 2;
let bufferQuery = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
let travels = JSON.parse(bufferQuery.toString());
let sortedTravels = travels.sort((a, b) => (a.Record.initTime - b.Record.initTime));
assert.equal(sortedTravels.length, 2, "You can not check this car");
let travelToCheck = sortedTravels[0].Record;
let nextTravel = sortedTravels[1].Record;
let clientLogged = await myContract.getClientLogged(stub);
clientLogged = JSON.parse(clientLogged.toString());
clientLogged = await myContract.readAsset(stub, clientLogged);
let containsUser = nextTravel.users.filter(function (user) { return user.clientId === clientLogged.id });
assert.equal(containsUser.length, 1, "You must be part of the next travel to check the car");
let statusInt = await parseInt(status);
let asset = await travelAsset.checkCar(travelToCheck, statusInt);
// await this.saveAssetState(ctx, asset.id, asset)
let response = await myContract.resolveTravel(stub, asset);
let buffer = Buffer.from(JSON.stringify(response));
return buffer;
}
async finishTravel(stub, args) {
let [ travelId, location ] = args;
let asset = await travelAsset.finish(stub, travelId, location);
const buffer = Buffer.from(JSON.stringify(asset));
return buffer;
}
async updateTravel(stub, args) {
let [travelId, suggestedDestinations, observations, realDestination, kmTraveled] = args;
let travel = await myContract.readAsset(stub, travelId);
let asset = await travelAsset.edit(travel, suggestedDestinations, observations, realDestination, kmTraveled);
const buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(asset.id, buffer);
return buffer;
}
async addUsersToTravel(stub, args) {
let [travelId, numPassengers] = args;
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
let travel = await myContract.readAsset(stub, travelId);
let offer = await myContract.readAsset(stub, travel.offerId);
let oldTotalNumPassengers = offer.car.seats - travel.seats;
let oldPriceTravelPerPassenger = travel.priceBalance / oldTotalNumPassengers;
let oldPriceDepositPerPassenger = travel.depositBalance / oldTotalNumPassengers;
travel = await travelAsset.addUsers(travel, clientID, numPassengers);
let newTotalNumPassengers = offer.car.seats - travel.seats;
let newPriceTravelPerPassenger = travel.priceBalance / newTotalNumPassengers;
let newPriceDepositPerPassenger = travel.depositBalance / newTotalNumPassengers;
for (let user of travel.users) {
let clientTravel = await myContract.readAsset(stub, user.clientId);
if (user.clientId == clientID) {
let payByTravel = (newPriceTravelPerPassenger * user.passengers);
[clientTravel, travel] = await userAsset.transfer(clientTravel, travel, payByTravel, "balance", "priceBalance");
let payByDeposit = (newPriceDepositPerPassenger * user.passengers);
[clientTravel, travel] = await userAsset.transfer(clientTravel, travel, payByDeposit, "balance", "depositBalance");
}
else {
let paidByTravel = oldPriceTravelPerPassenger * user.passengers;
let returnByTravel = paidByTravel - (newPriceTravelPerPassenger * user.passengers);
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, returnByTravel, "priceBalance", "balance");
let paidByDeposit = oldPriceDepositPerPassenger * user.passengers;
let returnByDeposit = paidByDeposit - (newPriceDepositPerPassenger * user.passengers);
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, returnByDeposit, "depositBalance", "balance");
}
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
}
let buffer = Buffer.from(JSON.stringify(travel));
return buffer;
}
async listTravels(stub, args) {
let [seats, startCoordinates, limitKm, endCoordinates] = args;
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'travel';
queryString.selector.rentForTime = false;
if (parseInt(seats)) {
queryString.selector.seats = { $gte: parseInt(seats) };
}
let buffer = await myContract.getQueryResultForQueryString(stub, JSON.stringify(queryString));
let travels = JSON.parse(buffer.toString());
if ((startCoordinates || endCoordinates) && limitKm) {
travels = await travelAsset.filterByLimit(travels, startCoordinates, endCoordinates, limitKm);
buffer = Buffer.from(JSON.stringify(travels));
}
return buffer;
}
async addSuggestedLocationToTravel(stub, args) {
let [travelId, location, reward] = args;
assert(travelId, 'Travel cannot be undefined');
let travel = await myContract.readAsset(stub, travelId);
let offer = await myContract.readAsset(stub, travel.offerId);
let ownerCarClient = await myContract.readAsset(stub, offer.car.ownerId);
travel = await travelAsset.addSuggestedLocation(stub, travel, location, reward, ownerCarClient);
await myContract.saveAssetState(stub, travel.id, travel);
}
// // TRANSFERS ------------------------------------------------------------------------
async buyCscoin(stub, args) {
let [to, amount] = args;
let asset = await userAsset.buyCscoin(stub, to, amount);
const buffer = Buffer.from(JSON.stringify(asset));
return buffer;
}
async cancelTravel(stub, args) {
let [travelId] = args;
try {
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
let loggedClient = await myContract.readAsset(stub, clientID);
let travel = await myContract.readAsset(stub, travelId);
let offer = await myContract.readAsset(stub, travel.offerId);
let clientCarOwner = await myContract.readAsset(stub, offer.car.ownerId);
let loggedClientIncludedInTravel = await travel.users.filter(user => user.clientId == loggedClient.id);
assert.equal(loggedClientIncludedInTravel.length, 1, 'You can only cancel your trips');
let now = new Date().getTime();
let timeUntilBeginTravel = travel.initTime - now;
let oldTotalNumPassengers = offer.car.seats - travel.seats;
let oldPriceTravelPerPassenger = travel.priceBalance / oldTotalNumPassengers;
let oldPriceDepositPerPassenger = travel.depositBalance / oldTotalNumPassengers;
travel = await travelAsset.deleteUsers(travel, clientID);
let newTotalNumPassengers = offer.car.seats - travel.seats;
let newPriceTravelPerPassenger = travel.priceBalance / newTotalNumPassengers;
let newPriceDepositPerPassenger = travel.depositBalance / newTotalNumPassengers;
let transerByTravel = oldPriceTravelPerPassenger * loggedClientIncludedInTravel[0].passengers;
let transferByDeposit = oldPriceDepositPerPassenger * loggedClientIncludedInTravel[0].passengers;
if (timeUntilBeginTravel >= 900000) {
// Cancel a trip until 15 minutes before it starts
// Return price by travel to client
[travel, loggedClient] = await userAsset.transfer(travel, loggedClient, transerByTravel, "priceBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, loggedClient.id, loggedClient);
// Return price by deposit to client
[travel, loggedClient] = await userAsset.transfer(travel, loggedClient, transferByDeposit, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, loggedClient.id, loggedClient);
for (let user of travel.users) {
let paidByTravel = oldPriceTravelPerPassenger * user.passengers;
let paidByDeposit = oldPriceDepositPerPassenger * user.passengers;
let payByTravel = (newPriceTravelPerPassenger * user.passengers) - paidByTravel;
let payByDeposit = (newPriceDepositPerPassenger * user.passengers) - paidByDeposit;
let clientTravel = await myContract.readAsset(stub, user.clientId);
[clientTravel, travel] = await userAsset.transfer(clientTravel, travel, payByTravel, "balance", "priceBalance");
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
[clientTravel, travel] = await userAsset.transfer(clientTravel, travel, payByDeposit, "balance", "depositBalance");
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
}
}
else if (timeUntilBeginTravel >= 60000) {
// Cancel a trip between 15 and 1 minutes before it starts
// Return price by travel to client
[travel, loggedClient] = await userAsset.transfer(travel, loggedClient, transerByTravel, "priceBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, loggedClient.id, loggedClient);
// Return price by deposit to owner car
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, transferByDeposit, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientCarOwner.id, clientCarOwner);
for (let user of travel.users) {
let paidByTravel = oldPriceTravelPerPassenger * user.passengers;
let payByTravel = (newPriceTravelPerPassenger * user.passengers) - paidByTravel;
let clientTravel = await myContract.readAsset(stub, user.clientId);
[clientTravel, travel] = await userAsset.transfer(clientTravel, travel, payByTravel, "balance", "priceBalance");
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
};
}
else {
// Cancel a trip after it starts
// Return price by travel to owner car
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, transerByTravel, "priceBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientCarOwner.id, clientCarOwner);
// Return price by deposit to owner car
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, transferByDeposit, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientCarOwner.id, clientCarOwner);
}
if (travel.users.length == 0 && travel.priceBalance == 0 && travel.depositBalance == 0 && travel.rewardBalance == 0) {
travel.deleted = true;
await myContract.saveAssetState(stub, travel.id, travel);
}
}
catch (err) {
if (err.message == "Balance must be greater than amount") {
await myContract.cancelTravelForAll(stub, travelId);
}
}
}
async cancelTravelForAll(stub, travelId) {
let travel = await myContract.readAsset(stub, travelId);
let offer = await myContract.readAsset(stub, travel.offerId);
let clientCarOwner = await myContract.readAsset(stub, offer.car.ownerId);
let now = new Date().getTime();
let timeUntilBeginTravel = travel.initTime - now;
let totalNumPassengers = offer.car.seats - travel.seats;
let priceTravelPerPassenger = travel.priceBalance / totalNumPassengers;
let priceDepositPerPassenger = travel.depositBalance / totalNumPassengers;
if (timeUntilBeginTravel >= 900000) {
// Cancel a trip until 15 minutes before it starts
for (let user of travel.users) {
let paidByTravel = priceTravelPerPassenger * user.passengers;
let paidByDeposit = priceDepositPerPassenger * user.passengers;
let clientTravel = await myContract.readAsset(stub, user.clientId);
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByTravel, "priceBalance", "balance");
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByDeposit, "depositBalance", "balance");
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
}
}
else if (timeUntilBeginTravel >= 60000) {
// Cancel a trip between 15 and 1 minutes before it starts
// Return price by deposit to owner car
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, travel.depositBalance, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientCarOwner.id, clientCarOwner);
for (let user of travel.users) {
let paidByTravel = priceTravelPerPassenger * user.passengers;
let clientTravel = await myContract.readAsset(stub, user.clientId);
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByTravel, "priceBalance", "balance");
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
await myContract.saveAssetState(stub, travel.id, travel);
};
}
else {
// Cancel a trip after it starts
// Return price and deposit to owner car
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, travel.priceBalance, "priceBalance", "balance");
[travel, clientCarOwner] = await userAsset.transfer(travel, clientCarOwner, travel.depositBalance, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientCarOwner.id, clientCarOwner);
}
travel.deleted = true;
await myContract.saveAssetState(stub, travel.id, travel);
return travel;
}
async resolveTravel(stub, travel) {
let offer = await myContract.readAsset(stub, travel.offerId);
let ownerCarClient = await myContract.readAsset(stub, offer.car.ownerId);
let totalNumPassengers = offer.car.seats - travel.seats;
let priceDepositPerPassenger = travel.depositBalance / totalNumPassengers;
assert(travel.priceBalance > 0, 'Unable to resolve a resolved travel');
let isPenalizedByTime = await travelAsset.isPenalizedByTime(travel);
let [isPenalizedByDestination, reward, rewardToOwner, rewardToSystem] = await travelAsset.isPenalizedByDestination(travel, ownerCarClient);
let rewardByPerPassenger = reward / totalNumPassengers;
[travel, ownerCarClient] = await userAsset.transfer(travel, ownerCarClient, rewardToOwner, "rewardBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, ownerCarClient.id, ownerCarClient);
travel = await userAsset.deleteBalanceTo(travel, rewardToSystem, "rewardBalance");
await myContract.saveAssetState(stub, travel.id, travel);
if (travel.carStatus == 0 && !isPenalizedByTime && !isPenalizedByDestination) {
[travel, ownerCarClient] = await userAsset.transfer(travel, ownerCarClient, travel.priceBalance, "priceBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, ownerCarClient.id, ownerCarClient);
for (let user of travel.users) {
let clientTravel = await myContract.readAsset(stub, user.clientId);
let paidByDeposit = priceDepositPerPassenger * user.passengers;
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByDeposit, "depositBalance", "balance");
let paidByReward = rewardByPerPassenger * user.passengers;
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByReward, "rewardBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
};
}
else if (travel.carStatus == 1 || isPenalizedByTime || isPenalizedByDestination) {
if (!isPenalizedByDestination && reward > 0) {
for (let user of travel.users) {
let paidByReward = rewardByPerPassenger * user.passengers;
let clientTravel = await myContract.readAsset(stub, user.clientId);
[travel, clientTravel] = await userAsset.transfer(travel, clientTravel, paidByReward, "rewardBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, clientTravel.id, clientTravel);
};
}
[travel, ownerCarClient] = await userAsset.transfer(travel, ownerCarClient, travel.priceBalance, "priceBalance", "balance");
[travel, ownerCarClient] = await userAsset.transfer(travel, ownerCarClient, travel.depositBalance, "depositBalance", "balance");
await myContract.saveAssetState(stub, travel.id, travel);
await myContract.saveAssetState(stub, ownerCarClient.id, ownerCarClient);
}
return travel;
}
// // OTHERS ---------------------------------------------------------------------------
async saveAssetState(stub, id, asset) {
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(id, buffer);
}
async getClientLogged(stub) {
let cid = new ClientIdentity(stub);
let clientLogged = cid.getID();
// assert(clientLogged.includes('OU=client'), 'User logged must be a client');
let buffer = Buffer.from(JSON.stringify(clientLogged));
return buffer;
}
async getAdminLogged(stub) {
let cid = new ClientIdentity(stub);
let adminLogged = cid.getID();
assert(adminLogged.includes('OU=admin'), 'User logged must be a admin');
return adminLogged;
}
async assetExists(stub, assetId) {
const buffer = await stub.getState(assetId);
return (!!buffer && buffer.length > 0);
}
async readAsset(stub, assetId) {
const exists = await myContract.assetExists(stub, assetId);
if (!exists) {
throw new Error(`The my asset ${assetId} does not exist`);
}
const buffer = await stub.getState(assetId);
const asset = JSON.parse(buffer.toString());
return asset;
}
async deleteAsset(stub, args) {
let [assetId] = args;
await util.deleteAsset(stub, assetId);
}
async getQueryResultForQueryString(stub, queryString) {
let resultsIterator = await stub.getQueryResult(queryString);
let results = await myContract.getAllResults(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
async getAllResults(iterator, isHistory) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
if (isHistory && isHistory === true) {
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.IsDelete = res.value.is_delete.toString();
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
} else {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
}
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
await iterator.close();
console.info(allResults);
return allResults;
}
}
}
}
// module.exports = MyContract;
shim.start(new MyContract());
\ No newline at end of file
'use strict';
const assert = require('assert');
const geodist = require('geodist');
const util = require('./util');
const { TravelAsset } = require('./travelAsset');
let offer = {
docType: String,
id: String,
car: Object,
priceForKm: Number,
priceForTime: Number,
startDate: Number,
deposit: Number,
startPlace: String,
endPlaces: [],
available: Boolean
};
// TODO: Add status to the car or offer. Make an assert to check if the status is "checking/pending";
/*
Once the travel is finished the status of the car's offer will be "checking/pending"
While the offer is in that status, anyone cannot make a trip with that offer;
*/
class OfferAsset {
/**
* @description This function create a new offer to a car
* @param {Object} car
* @param {Number} priceForKm Price per kilometer
* @param {Number} priceForTime Price per time
* @param {Number} startDate Start date of the offer (in milliseconds)
* @param {Number} endDate End date of the offer (in milliseconds)
* @param {Number} deposit
* @param {String} startPlace Coordinates of the place where is the car
* @param {String[]} endPlaces
*/
async create(car, priceForKm, priceForTime, startDate, endDate, deposit, startPlace, endPlaces) {
assert(car, 'Car not must be undefined');
assert((priceForKm || priceForTime), 'Price not must be undefined');
assert(startDate, 'Start date not must be undefined');
assert(endDate, 'End date not must be undefined');
assert(deposit, 'Deposit not must be undefined');
assert(startPlace, 'Start place not must be undefined');
assert.equal(isNaN(priceForKm), false, 'Price for km must be a number');
assert.equal(isNaN(priceForTime), false, 'Price for time must be a number');
assert.equal(isNaN(startDate), false, 'Start date must be a number');
assert.equal(isNaN(endDate), false, 'Start date must be a number');
assert.equal(isNaN(deposit), false, 'Deposit must be a number');
assert(parseInt(deposit) > 0, '');
assert(parseInt(startDate) < parseInt(endDate), 'End date must be later than start date');
assert(parseInt(startDate) >= new Date().getTime(), 'Start date must be later than now');
offer.docType = 'offer';
offer.id = await this.generateId(car.carLicensePlate);
offer.car = car;
if (priceForKm) {
assert(parseInt(priceForKm) > 0, '');
offer.priceForKm = parseInt(priceForKm);
}
if (priceForTime) {
assert(parseInt(priceForTime) > 0, '');
offer.priceForTime = parseInt(priceForTime);
}
offer.startDate = parseInt(startDate);
offer.endDate = parseInt(endDate);
offer.deposit = parseInt(deposit);
offer.startPlace = startPlace;
offer.endPlaces = [];
if (endPlaces) {
offer.endPlaces = endPlaces.split(',');
}
offer.available = true;
return offer;
}
/**
* @description This function edit a offer object
* @param {String} id Offer ID to edit
* @param {Object} car
* @param {Number} priceForKm
* @param {Number} priceForTime
* @param {Number} startDate
* @param {Number} endDate
* @param {Number} deposit
* @param {String} startPlace
* @param {String[]} endPlaces
*/
async edit(id, car, priceForKm, priceForTime, startDate, endDate, deposit, startPlace, endPlaces, available) {
assert(id, 'ID not must be undefined');
assert((priceForKm || priceForTime), 'Price not must be undefined');
assert(startDate, 'Start date not must be undefined');
assert(endDate, 'End date not must be undefined');
assert(deposit, 'Deposit not must be undefined');
assert(startPlace, 'Start place not must be undefined');
assert.equal(isNaN(priceForKm), false, 'Price for km must be a number');
assert.equal(isNaN(priceForTime), false, 'Price for time must be a number');
assert.equal(isNaN(startDate), false, 'Start date must be a number');
assert.equal(isNaN(deposit), false, 'Deposit must be a number');
offer.docType = 'offer';
offer.id = id;
offer.car = car;
if (priceForKm) {
offer.priceForKm = parseInt(priceForKm);
}
if (priceForTime) {
offer.priceForTime = parseInt(priceForTime);
}
offer.startDate = parseInt(startDate);
offer.endDate = parseInt(endDate);
offer.deposit = parseInt(deposit);
offer.startPlace = startPlace;
if (endPlaces) {
offer.endPlaces = endPlaces.split(',');
}
offer.available = Boolean(available);
return offer;
}
async generateId(carLicensePlate) {
let now = new Date().getTime();
let id = carLicensePlate + now;
return id;
}
async isInTheLimit(startCoordinate, endCoordinate, limit) {
let startCoordinateArray = startCoordinate.split(';');
let endCoordinateArray = endCoordinate.split(';');
let isInTheLimit = geodist(startCoordinateArray, endCoordinateArray, { limit: parseInt(limit), unit: 'km' });
return isInTheLimit;
}
async filterByLimit(offersArrray, startCoordinate, endCoordinate, limit) {
let result = [];
let resultStart = [];
let resultEnd = [];
if (startCoordinate && limit) {
await offersArrray.forEach(offer => {
this.isInTheLimit(startCoordinate, offer.Record.startPlace, limit).then(isInLimitStart => {
if (isInLimitStart) {
resultStart.push(offer);
}
})
});
}
if (endCoordinate && limit) {
await offersArrray.forEach(offer => {
if (offer.Record.endPlaces) {
offer.Record.endPlaces.forEach(endPlace => {
this.isInTheLimit(endCoordinate, endPlace, limit).then(isInLimitEnd => {
if (isInLimitEnd) {
console.info('Esta en el inicio y en el fin: ' + offer.Record.startPlace + ' - ' + offer.Record.endPlaces);
resultEnd.push(offer);
}
})
})
}
});
}
if (startCoordinate && endCoordinate && limit) {
result = resultStart.filter(value => -1 !== resultEnd.indexOf(value));
}
else if (startCoordinate && !endCoordinate && limit) {
result = resultStart;
} else if (!startCoordinate && endCoordinate && limit) {
result = resultEnd;
}
return result;
}
async findOne(stub, offerId) {
let asset = await this.readOffer(stub, offerId);
assert.equal(asset.docType, 'offer', 'Offer not found');
return asset;
}
async offerExists(stub, offerId) {
let buffer = await stub.getState(offerId);
return (!!buffer && buffer.length > 0);
}
async readOffer(stub, offerId) {
let exists = await this.offerExists(stub, offerId);
assert.equal(exists, true, 'Offer not found');
let buffer = await stub.getState(offerId);
let offer = JSON.parse(buffer.toString());
return offer;
}
async editAvailability(stub, offerId, available) {
let travelAsset = new TravelAsset();
let userLogged = await util.getUserLogged(stub);
userLogged = JSON.parse(userLogged.toString());
let asset = await this.readOffer(stub, offerId);
assert.equal(asset.docType, 'offer', 'Offer not found');
assert.equal(asset.car.ownerId, userLogged, 'You cannot edit the availability of this offer');
let travels = await travelAsset.findAllByOffer(stub, offerId);
travels = await travels.filter(travel => travel.Record.realFinalDate == undefined);
assert.equal(travels.length, 0, 'You cannot edit the availability of an offer with pending travels');
asset.available = available.toLowerCase() == 'true' ? true : false;
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(asset.id, buffer);
return asset;
}
}
module.exports = {
OfferAsset
};
\ No newline at end of file
{
"name": "my-contract",
"version": "0.0.5",
"description": "My Smart Contract",
"main": "my-contract.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "nyc mocha --recursive",
"start": "node my-contract.js"
},
"engineStrict": true,
"author": "John Doe",
"license": "Apache-2.0",
"dependencies": {
"fabric-client": "^1.4.1",
"fabric-network": "^1.4.1",
"fabric-ca-client": "^1.4.1",
"fabric-contract-api": "1.4.1",
"fabric-shim": "~1.4.0",
"geodist": "^0.2.1"
},
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^5.9.0",
"mocha": "^5.2.0",
"nyc": "^14.0.0",
"sinon": "^7.1.1",
"sinon-chai": "^3.3.0",
"winston": "^3.2.1"
},
"nyc": {
"exclude": [
".eslintrc.js",
"coverage/**",
"test/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
// TODO: Edit the asset to use it as we speak.
const geodist = require('geodist');
const assert = require('assert');
const { ClientIdentity } = require('fabric-shim');
const util = require('./util');
const { UserAsset } = require('./userAsset');
let userAsset = new UserAsset();
var travel = {
docType: String,
id: String,
carLicensePlate: String,
users: [{
userId: String,
passengers: Number
}],
offerId: String,
origin: String,
destination: String,
initTime: Number,
finishTime: Number,
suggestedDestinations: [],
rentForTime: Boolean,
seats: Number,
totalPrice: Number,
observations: String,
finished: [],
realDestination: String,
realFinalDate: Number,
kmTraveled: Number,
priceBalance: Number,
depositBalance: Number,
rewardBalance: Number,
carStatus: Number
};
// asdasd ad
class TravelAsset {
/**
*
* @param {Object} offer
* @param {Date} initTime
* @param {Date} finishTime (?)
* @param {String} clientId
* @param {number} passengers
* @param {number} destination
* @param {Boolean} rentForTime
* @param {String} observations
* When you create a travel, the offer related to it is edited to "Not avalible"
*/
async create(offer, initTime, finishTime, clientId, passengers, destination, rentForTime, observations) {
assert.notEqual(offer, undefined, 'Offer cannot be undefined');
assert.notEqual(initTime, undefined, 'Init time cannot be undefined');
assert.notEqual(finishTime, undefined, 'Init time cannot be undefined');
assert.notEqual(passengers, 'Number of passanger cannot be undefined');
assert.notEqual(rentForTime, 'Rent for time cannot be undefined');
initTime = parseInt(initTime);
finishTime = parseInt(finishTime);
let now = new Date().getTime();
assert.ok(initTime >= offer.startDate, 'Init time must be equals or greater than start date of the offer');
assert.ok(initTime >= now, 'Init time must be equals or greater than now')
assert.ok(finishTime <= offer.endDate, 'Finish time must be equal or lower than end date of the offer');
assert.ok(initTime < finishTime, 'Init time must be lower than finish time');
assert.equal(isNaN(passengers), false, 'Number of passengers should be a number');
let totalPrice = 0;
if (rentForTime == "true") {
assert.notEqual(offer.priceForTime, null, 'To create a travel, the offer must have a price for time');
totalPrice = ((finishTime - initTime) / 1000 / 60 / 60) * offer.priceForTime;
travel.rentForTime = true;
} else {
assert.notEqual(offer.priceForKm, null, 'To create a travel, the offer must have a price for km');
assert.notEqual(destination, undefined, 'Destination cannot be undefined');
totalPrice = (geodist(offer.startPlace.split(';'), destination.split(';'), { unit: 'km' })) * offer.priceForKm;
travel.rentForTime = false;
}
passengers = parseInt(passengers);
assert.ok(passengers <= offer.car.seats, 'There are no seats for all passengers');
travel.docType = 'travel';
travel.id = await this.generateId(offer.car.carLicensePlate);
travel.totalPrice = totalPrice;
travel.seats = offer.car.seats - passengers;
travel.offerId = offer.id;
travel.initTime = initTime;
travel.carLicensePlate = offer.car.carLicensePlate;
travel.finishTime = finishTime;
travel.users = [];
travel.users.push({ clientId: clientId, passengers: passengers })
travel.origin = offer.startPlace;
travel.destination = destination;
travel.observations = observations;
travel.suggestedDestinations = [];
travel.finished = [];
travel.priceBalance = 0;
travel.depositBalance = 0;
travel.rewardBalance = 0;
travel.carStatus = 2;
return travel;
}
// ["1234ABC1561547330049", "1701385500000", "1703890200000", "1", "45.2564;75.5885", "false", "[]"]
// "1234ABC1559897298956", "46.2555;76.5876", "", "46.8762;77.5876", "1703890500000", "348"
async edit(travelObject, suggestedDestination, observations, realDestination, kmTraveled) {
assert(travelObject, 'Travel cannot be undefined');
assert.equal(isNaN(kmTraveled), false, 'Kilometer traveled should be a number');
travelObject.suggestedDestinations.push(suggestedDestination);
travelObject.observations = observations;
travelObject.realDestination = realDestination;
travelObject.kmTraveled = kmTraveled;
return travelObject;
}
async finish(stub, travelId, coordinate) {
assert.notEqual(travelId, undefined, 'Travel ID cannot be undefined');
assert.notEqual(coordinate, undefined, 'Coordinate cannot be undefined');
let asset = await util.readAsset(stub, travelId);
assert.equal(asset.docType, 'travel', 'Travel not found');
let userLogged = await util.getUserLogged(stub);
userLogged = JSON.parse(userLogged.toString());
let loggedUserIsAddedToUsers = await asset.users.filter(user => user.clientId == userLogged);
assert.equal(loggedUserIsAddedToUsers.length, 1, 'You cannot finish this travel');
let loggedUserAddedToFinished = await asset.finished.filter(finish => finish.user == userLogged);
assert.equal(loggedUserAddedToFinished.length, 0, 'You have already finished this travel');
let realFinalDate = new Date().getTime();
coordinate = JSON.parse(coordinate);
await util.validateCoordinate(coordinate);
asset.finished.push({
user: userLogged,
moment: realFinalDate,
coordinate: coordinate
});
await util.saveAsset(stub, travelId, asset);
return asset;
}
async addUsers(travelObject, clientId, passengers) {
assert(travelObject, 'Travel cannot be undefined');
assert(clientId, 'Client cannot be undefined');
assert(passengers, 'Number of passengers cannot be undefined');
assert.equal(isNaN(passengers), false, 'Number of passengers should be a number');
let numPassengers = parseInt(passengers);
assert(numPassengers > 0, 'The number of passengers must be greater than zero');
assert(travelObject.seats >= numPassengers, 'You cannot add all the passengers to the travel');
let clientAddedBefore = await travelObject.users.filter(user => user.clientId == clientId);
assert.equal(clientAddedBefore.length, 0, 'The client was already added to this travel');
travelObject.seats = travelObject.seats - numPassengers;
travelObject.users.push({ clientId: clientId, passengers: numPassengers });
return travelObject;
}
async deleteUsers(travelObject, clientId) {
assert(travelObject, 'Travel cannot be undefined');
assert(clientId, 'Client cannot be undefined');
let clientAddedBefore = await travelObject.users.filter(user => user.clientId == clientId);
assert.equal(clientAddedBefore.length, 1, 'The client was already added to this travel');
travelObject.seats = travelObject.seats + clientAddedBefore[0].passengers;
var index = travelObject.users.indexOf(clientAddedBefore[0]);
if (index > -1) {
travelObject.users.splice(index, 1);
// delete travelObject.users[index];
}
return travelObject;
}
async checkCar(travelObject, status) {
assert.notEqual(status, undefined, 'Status cannot be undefined');
assert(travelObject, 'Travel cannot be undefined');
travelObject.carStatus = status;
return travelObject;
}
async generateId(carLicensePlate) {
let now = new Date().getTime();
let id = carLicensePlate + now;
return id;
}
async isInTheLimit(startCoordinate, endCoordinate, limit) {
let startCoordinateArray = startCoordinate.split(';');
let endCoordinateArray = endCoordinate.split(';');
let isInTheLimit = geodist(startCoordinateArray, endCoordinateArray, { limit: parseInt(limit), unit: 'km' });
return isInTheLimit;
}
async filterByLimit(travelsArray, startCoordinate, endCoordinate, limit) {
let result = [];
let resultStart = [];
let resultEnd = [];
if (startCoordinate && limit) {
// "","45.2554;75.5875","2000","45.2554;75.5875"
await travelsArray.forEach(travel => {
this.isInTheLimit(startCoordinate, travel.Record.origin, limit).then(isInLimitStart => {
if (isInLimitStart) {
resultStart.push(travel);
}
})
});
}
if (endCoordinate && limit) {
await travelsArray.forEach(travel => {
this.isInTheLimit(endCoordinate, travel.Record.destination, limit).then(isInLimitEnd => {
if (isInLimitEnd) {
resultEnd.push(travel);
}
})
});
}
if (startCoordinate && endCoordinate && limit) {
result = resultStart.filter(value => -1 !== resultEnd.indexOf(value));
}
else if (startCoordinate && !endCoordinate && limit) {
result = resultStart;
} else if (!startCoordinate && endCoordinate && limit) {
result = resultEnd;
}
return result;
}
async isPenalizedByTime(travel) {
let isPenalized = false;
assert(travel, "Travel not must be undefined");
if (travel.realFinalDate > travel.finishTime) {
isPenalized = true;
}
return isPenalized;
}
async isPenalizedByDestination(travel, ownerCarClient) {
let isPenalized = true;
let reward = 0;
let rewardToOwner = 0;
let rewardToSystem = 0;
assert(travel, "Travel not must be undefined");
if (travel.rentForTime == false) {
let sortedSuggestedDestinations = await travel.suggestedDestinations.sort((a, b) => (b.reward - a.reward));
for (let suggestedDestination of sortedSuggestedDestinations) {
if (rewardToOwner == 0 && suggestedDestination.suggestedBy == ownerCarClient.id) {
rewardToOwner = suggestedDestination.reward;
}
else if (rewardToSystem == 0 && suggestedDestination.suggestedBy == "system") {
rewardToSystem = suggestedDestination.reward;
}
if (await this.isInDestination(suggestedDestination.destination, travel.realDestination)) {
isPenalized = false;
reward = suggestedDestination.reward;
if (suggestedDestination.suggestedBy == ownerCarClient.id) {
rewardToOwner -= reward;
}
else {
rewardToSystem -= reward;
}
break;
}
}
if (await this.isInDestination(travel.destination, travel.realDestination)) {
isPenalized = false;
}
}
else {
isPenalized = false;
}
return [isPenalized, reward, rewardToOwner, rewardToSystem];
}
async getRewards(travel) {
let isPenalized = true;
assert(travel, "Travel not must be undefined");
if (travel.rentForTime == false) {
// Example suggestedDestinations
// [
// { destination: '45.62;78.3', reward: 10 },
// { destination: '67.2;24.7', reward: 5 }
// ]
for (let suggestedDestination of travel.suggestedDestinations) {
if (await this.isInDestination(suggestedDestination.destination, travel.realDestination)) {
isPenalized = false;
}
}
if (await this.isInDestination(travel.destination, travel.realDestination)) {
isPenalized = false;
}
}
else {
isPenalized = false;
}
return isPenalized;
}
async isInDestination(destination, realDestination) {
let destinationArray = destination.split(';');
let realDestinationArray = realDestination.split(';');
// TODO: Add range destination in config file
let isInDestination = geodist(destinationArray, realDestinationArray, { limit: 1, unit: 'km' });
return isInDestination;
}
async addSuggestedLocation(stub, travel, location, reward, ownerCarClient) {
assert(travel, 'Travel cannot be undefined');
assert(location, 'Location cannot be undefined');
assert(reward, 'Reward cannot be undefined');
assert.equal(isNaN(reward), false, 'Reward should be a number');
let cid = new ClientIdentity(stub);
let clientID = cid.getID();
// TODO: Create certificate to system
let arrayClients = [ownerCarClient.id, "system"];
assert.notEqual(arrayClients.indexOf(clientID), -1, "You do not have permissions");
let now = new Date().getTime();
assert(travel.initTime < now, "You cannot add a suggested destination to a travel that has not started");
reward = parseInt(reward);
assert(reward > 0, 'Reward must be greater than zero');
// TODO: Valid coordinates
let locationAddedBefore = await travel.suggestedDestinations.filter(
function (destination) { return destination.destination === location }
);
assert.equal(locationAddedBefore.length, 0, 'The suggested destination was already added to this travel');
let suggestedDestinationsByClient = await travel.suggestedDestinations.filter(function (destination) { return destination.suggestedBy === clientID });
let sortedSuggestedDestinations = suggestedDestinationsByClient.sort((a, b) => (b.reward - a.reward));
let diff = reward;
if (sortedSuggestedDestinations.length > 0) {
diff -= sortedSuggestedDestinations[0].reward;
}
if (diff > 0) {
if (clientID == "system") {
travel = await userAsset.transferTo(travel, diff, "rewardBalance");
}
else {
[ownerCarClient, travel] = await userAsset.transfer(ownerCarClient, travel, diff, "balance", "rewardBalance");
let buffer = Buffer.from(JSON.stringify(ownerCarClient));
await stub.putState(ownerCarClient.id, buffer);
}
let buffer = Buffer.from(JSON.stringify(travel));
await stub.putState(travel.id, buffer);
}
travel.suggestedDestinations.push({ destination: location, reward: reward, suggestedBy: clientID });
return travel;
}
async findAllByOffer(stub, offerId) {
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'travel';
queryString.selector.offerId = offerId;
let travels = await util.getQueryResultForQueryString(stub, JSON.stringify(queryString));
return travels;
}
}
module.exports = {
TravelAsset
};
const { FileSystemWallet, X509WalletMixin, Gateway } = require('fabric-network');
const Fabric_Client = require('fabric-client');
const Fabric_CA_Client = require('fabric-ca-client');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
class User {
async create(userId, rol) {
let fabric_client = new Fabric_Client();
let fabric_ca_client = null;
let admin_user = null;
let member_user = null;
// let store_path = path.resolve('wallets/' + userId);
var store_path = path.join(__dirname, "../../../../../.hfc-key-store")
// create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting
Fabric_Client.newDefaultKeyValueStore({
path: store_path
}).then(async (state_store) => {
// assign the store to the fabric client
fabric_client.setStateStore(state_store);
let crypto_suite = Fabric_Client.newCryptoSuite();
// use the same location for the state store (where the users' certificate are kept)
// and the crypto store (where the users' keys are kept)
let crypto_store = Fabric_Client.newCryptoKeyStore({ path: store_path });
crypto_suite.setCryptoKeyStore(crypto_store);
fabric_client.setCryptoSuite(crypto_suite);
var tlsOptions = {
trustedRoots: [],
verify: true
};
// be sure to change the http to https when the CA is running TLS enabled
fabric_ca_client = new Fabric_CA_Client('http://localhost:17054', null, '', crypto_suite);
// first check to see if the admin is already enrolled
// return fabric_client.getUserContext('admin', true);
return await this.getAdmin();
}).then((user_from_store) => {
console.log('user_from_store: ', user_from_store);
if (user_from_store && user_from_store.isEnrolled()) {
console.log('Successfully loaded admin from persistence');
admin_user = user_from_store;
} else {
throw new Error('Failed to get admin.... run enrollAdmin.js');
}
// at this point we should have the admin user
// first need to register the user with the CA server
return fabric_ca_client.register({ enrollmentID: userId, affiliation: '', role: rol }, admin_user);
}).then((secret) => {
// next we need to enroll the user with CA server
console.log('Successfully registered ' + userId + ' - secret:' + secret);
return fabric_ca_client.enroll({ enrollmentID: userId, enrollmentSecret: secret });
}).then((enrollment) => {
console.log('Successfully enrolled member user ' + userId);
return fabric_client.createUser(
{
username: userId,
mspid: 'Org1MSP',
cryptoContent: { privateKeyPEM: enrollment.key.toBytes(), signedCertPEM: enrollment.certificate }
});
}).then((user) => {
member_user = user;
return fabric_client.setUserContext(member_user);
}).then(async () => {
let userCtx1 = fabric_client.getUserContext();
let userCtx = await fabric_client.getUserContext();
console.log(userId + ' was successfully registered and enrolled and is ready to intreact with the fabric network');
}).catch((err) => {
console.error('Failed to register: ' + err);
if (err.toString().indexOf('Authorization') > -1) {
console.error('Authorization failures may be caused by having admin credentials from a previous CA instance.\n' +
'Try again after deleting the contents of the store directory ' + store_path);
}
});
}
async getAdmin() {
let ccpPath = path.join(process.cwd(), '/network/runtime/gateways/local_fabric.json');
const ccpJSON = fs.readFileSync(ccpPath);
const ccp = JSON.parse(ccpJSON);
let walletPathAdmin = path.join(process.cwd(), '/network/local_fabric_wallet');
const wallet = new FileSystemWallet(walletPathAdmin);
console.log('Wallet path admin: ', walletPathAdmin);
const adminExists = await wallet.exists('admin');
assert(adminExists, 'An identity for the admin user "admin" does not exist in the wallet');
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'admin', discovery: { enabled: false } });
//const ca = gateway.getClient().getCertificateAuthority();
const adminIdentity = await gateway.getCurrentIdentity();
return adminIdentity;
};
async createIdentityAndWallet(userId) {
console.info('------------------process.cwd(): ', process.cwd());
var ca2 = new FabricCAServices("http://localhost:17054")
let ccpPath = path.join(process.cwd(), '/network/runtime/gateways/local_fabric.json');
const ccpJSON = fs.readFileSync(ccpPath);
const ccp = JSON.parse(ccpJSON);
let walletPathAdmin = path.join(process.cwd(), '/network/local_fabric_wallet');
const wallet = new FileSystemWallet(walletPathAdmin);
console.log('Wallet path admin: ', walletPathAdmin);
let walletPathUser = path.join(process.cwd(), '/wallets/local_fabric_wallet_' + userId);
const wallet2 = new FileSystemWallet(walletPathUser);
console.log('Wallet path user: ', walletPathUser);
const adminExists = await wallet.exists('admin');
assert(adminExists, 'An identity for the admin user "admin" does not exist in the wallet');
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'admin', discovery: { enabled: false } })
.then(async function () {
const ca = gateway.getClient().getCertificateAuthority();
const adminIdentity = gateway.getCurrentIdentity();
console.info('CA and adminIdentity created');
const userExists = await wallet2.exists(userId);
if (userExists) {
console.log('An identity for the user ' + userId + ' already exists in the wallet');
}
else {
console.log(userId + ' no exist');
console.log('................', ca2);
console.log('----------------', ca);
let secret2 = await ca2.register({ affiliation: 'org1.department1', enrollmentID: userId, role: 'client' }, adminIdentity);
console.log('Secret2: ', secret);
let secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: userId, role: 'client' }, adminIdentity);
console.log('Secret: ', secret);
let enrollment = await ca.enroll({ enrollmentID: userId, enrollmentSecret: secret });
console.log('Enrollment: ', enrollment);
const userIdentity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
console.log('UserIdentity: ', userIdentity);
await wallet2.import(userId, userIdentity);
console.log('Successfully registered and enrolled admin user ' + userId + ' and imported it into the wallet');
return userId;
}
});
};
}
module.exports = {
User
};
'use strict';
const assert = require('assert');
const util = require('./util');
let user = {
docType: String,
id: String,
balance: Number
};
class UserAsset {
async create(id) {
assert(id, 'ID not must be undefined');
user.docType = 'user';
user.id = id;
user.balance = 0;
return user;
}
async balanceOf(user) {
assert(user, 'User not must be undefinied');
return user.balance;
}
async transfer(fromAccount, toAccount, amount, fromBalance, toBalance) {
assert(fromAccount, 'Origin wallet not must be undefinied');
assert(toAccount, 'Destination wallet not must be undefinied');
assert(fromBalance, 'Origin not must be undefinied');
assert(toBalance, 'Destination not must be undefinied');
assert(!isNaN(amount), 'Amount must be a number');
let amountNumber = parseFloat(amount);
if (amountNumber > 0) {
assert(fromAccount[fromBalance] >= amountNumber, 'Balance must be greater than amount');
fromAccount[fromBalance] -= amountNumber;
toAccount[toBalance] += amountNumber;
}
return [fromAccount, toAccount];
}
async transferTo(to, amount, balanceName) {
assert(to, 'Destination wallet not must be undefinied');
assert(balanceName, 'Balance name not must be undefinied');
assert(!isNaN(amount), 'Amount must be a number');
let amountNumber = parseFloat(amount);
if (amountNumber > 0) {
to[balanceName] += amountNumber;
}
return to;
}
async buyCscoin(stub, to, amount) {
assert.notEqual(to, undefined, 'Destination wallet cannot be undefined');
assert.notEqual(amount, undefined, 'Amount cannot be undefined');
assert.equal(isNaN(amount), false, 'Amount must be a number');
amount = parseFloat(amount);
assert.ok(amount > 0, 'Amount to transfer must be greather than zero');
let destinationUser = await util.readAsset(stub, to);
assert.equal(destinationUser.docType, 'user', 'Destination user not found');
destinationUser = await this.transferTo(destinationUser, amount, "balance");
await util.saveAsset(stub, destinationUser.id, destinationUser);
return destinationUser;
}
async deleteBalanceTo(to, amount, balanceName) {
assert(to, 'Destination wallet not must be undefinied');
assert(balanceName, 'Balance name not must be undefinied');
assert(!isNaN(amount), 'Amount must be a number');
let amountNumber = parseFloat(amount);
if (amountNumber > 0) {
to[balanceName] -= amountNumber;
}
return to;
}
}
module.exports = {
UserAsset
};
\ No newline at end of file
const { ClientIdentity } = require('fabric-shim');
const assert = require('assert');
async function saveAsset(stub, id, asset) {
let buffer = Buffer.from(JSON.stringify(asset));
await stub.putState(id, buffer);
}
async function getUserLogged(stub) {
let cid = new ClientIdentity(stub);
let clientLogged = cid.getID();
let buffer = Buffer.from(JSON.stringify(clientLogged));
return buffer;
}
async function assetExists(stub, assetId) {
let buffer = await stub.getState(assetId);
return (!!buffer && buffer.length > 0);
}
async function readAsset(stub, assetId) {
let exists = await assetExists(stub, assetId);
assert.equal(exists, true, 'Asset not found');
let buffer = await stub.getState(assetId);
let asset = JSON.parse(buffer.toString());
return asset;
}
async function deleteAsset(stub, assetId) {
await stub.deleteState(assetId);
}
async function getQueryResultForQueryString(stub, queryString) {
let resultsIterator = await stub.getQueryResult(queryString);
let results = await getAllResults(resultsIterator, false);
return results;
}
async function getAllResults(iterator, isHistory) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
if (isHistory && isHistory === true) {
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.IsDelete = res.value.is_delete.toString();
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
} else {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
}
allResults.push(jsonRes);
}
if (res.done) {
await iterator.close();
return allResults;
}
}
}
async function validateCoordinate(coordinate) {
assert.notEqual(coordinate, undefined, 'Location not must be undefined');
assert.notEqual(coordinate.latitude, undefined, 'Latitude not must be undefined');
assert.notEqual(coordinate.longitude, undefined, 'Longitude not must be undefined');
// Validate latitude
assert.equal(isNaN(coordinate.latitude), false, 'Latitude must be a number');
assert.ok(coordinate.latitude >= -90, 'Latitude must be greater than -90');
assert.ok(coordinate.latitude <= 90, 'Latitude must be less than 90');
// Validate longitude
assert.equal(isNaN(coordinate.longitude), false, 'Longitude must be a number');
assert.ok(coordinate.longitude >= -180, 'Longitude must be greater than -180');
assert.ok(coordinate.longitude <= 180, 'Longitude must be less than 180');
}
module.exports = {
saveAsset,
getUserLogged,
assetExists,
deleteAsset,
readAsset,
getQueryResultForQueryString,
validateCoordinate
};
\ No newline at end of file
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode query -C appchannel -n marblecc -c '{"Args":["readMarble","marble1"]}'
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode install -n marblecc -v 1.0 -l node -p /root/CLI/chaincodes/fabric_test_chaincodes/marble_chaincode/src/
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode instantiate -C appchannel -n marblecc -v 1.0 -c '{"Args":["init"]}' -o ${ORDERER_HOST}:7050 --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
#!/bin/bash
set -x #echo on
export CORE_PEER_ADDRESS="peer2:7051"
export CORE_PEER_MSPCONFIGPATH="/root/admin/msp"
export CORE_PEER_TLS_ROOTCERT_FILE="/root/${PEER2_HOST}/tls-msp/tlscacerts/tls-${TLSCA_HOST}-7054.pem"
export CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS
export CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH
export CORE_PEER_TLS_ROOTCERT_FILE=$CORE_PEER_TLS_ROOTCERT_FILE
peer chaincode invoke -C appchannel -n marblecc -c '{"Args":["initMarble","marble1","blue","35","tom"]}' --tls --cafile ${CORE_PEER_TLS_ROOTCERT_FILE}
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
// ====CHAINCODE EXECUTION SAMPLES (CLI) ==================
// ==== Invoke marbles ====
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["delete","marble1"]}'
// ==== Query marbles ====
// peer chaincode query -C myc1 -n marbles -c '{"Args":["readMarble","marble1"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getMarblesByRange","marble1","marble3"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getMarblesByRangeWithPagination","marble1","marble3","3",""]}'
// Rich Query (Only supported if CouchDB is used as state database):
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
// Rich Query with Pagination (Only supported if CouchDB is used as state database):
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesWithPagination","{\"selector\":{\"owner\":\"tom\"}}","3",""]}'
'use strict';
const shim = require('fabric-shim');
const util = require('util');
let Chaincode = class {
async Init(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
console.info('=========== Instantiated Marbles Chaincode ===========');
return shim.success();
}
async Invoke(stub) {
console.info('Transaction ID: ' + stub.getTxID());
console.info(util.format('Args: %j', stub.getArgs()));
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.log('no function of name:' + ret.fcn + ' found');
throw new Error('Received unknown function ' + ret.fcn + ' invocation');
}
try {
let payload = await method(stub, ret.params, this);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
// ===============================================
// initMarble - create a new marble
// ===============================================
async initMarble(stub, args, thisClass) {
if (args.length != 4) {
throw new Error('Incorrect number of arguments. Expecting 4');
}
// ==== Input sanitation ====
console.info('--- start init marble ---')
if (args[0].lenth <= 0) {
throw new Error('1st argument must be a non-empty string');
}
if (args[1].lenth <= 0) {
throw new Error('2nd argument must be a non-empty string');
}
if (args[2].lenth <= 0) {
throw new Error('3rd argument must be a non-empty string');
}
if (args[3].lenth <= 0) {
throw new Error('4th argument must be a non-empty string');
}
let marbleName = args[0];
let color = args[1].toLowerCase();
let owner = args[3].toLowerCase();
let size = parseInt(args[2]);
if (typeof size !== 'number') {
throw new Error('3rd argument must be a numeric string');
}
// ==== Check if marble already exists ====
let marbleState = await stub.getState(marbleName);
if (marbleState.toString()) {
throw new Error('This marble already exists: ' + marbleName);
}
// ==== Create marble object and marshal to JSON ====
let marble = {};
marble.docType = 'marble';
marble.name = marbleName;
marble.color = color;
marble.size = size;
marble.owner = owner;
// === Save marble to state ===
await stub.putState(marbleName, Buffer.from(JSON.stringify(marble)));
let indexName = 'color~name'
let colorNameIndexKey = await stub.createCompositeKey(indexName, [marble.color, marble.name]);
console.info(colorNameIndexKey);
// Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble.
// Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value
await stub.putState(colorNameIndexKey, Buffer.from('\u0000'));
// ==== Marble saved and indexed. Return success ====
console.info('- end init marble');
}
// ===============================================
// readMarble - read a marble from chaincode state
// ===============================================
async readMarble(stub, args, thisClass) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the marble to query');
}
let name = args[0];
if (!name) {
throw new Error(' marble name must not be empty');
}
let marbleAsbytes = await stub.getState(name); //get the marble from chaincode state
if (!marbleAsbytes.toString()) {
let jsonResp = {};
jsonResp.Error = 'Marble does not exist: ' + name;
throw new Error(JSON.stringify(jsonResp));
}
console.info('=======================================');
console.log(marbleAsbytes.toString());
console.info('=======================================');
return marbleAsbytes;
}
// ==================================================
// delete - remove a marble key/value pair from state
// ==================================================
async delete(stub, args, thisClass) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the marble to delete');
}
let marbleName = args[0];
if (!marbleName) {
throw new Error('marble name must not be empty');
}
// to maintain the color~name index, we need to read the marble first and get its color
let valAsbytes = await stub.getState(marbleName); //get the marble from chaincode state
let jsonResp = {};
if (!valAsbytes) {
jsonResp.error = 'marble does not exist: ' + name;
throw new Error(jsonResp);
}
let marbleJSON = {};
try {
marbleJSON = JSON.parse(valAsbytes.toString());
} catch (err) {
jsonResp = {};
jsonResp.error = 'Failed to decode JSON of: ' + marbleName;
throw new Error(jsonResp);
}
await stub.deleteState(marbleName); //remove the marble from chaincode state
// delete the index
let indexName = 'color~name';
let colorNameIndexKey = stub.createCompositeKey(indexName, [marbleJSON.color, marbleJSON.name]);
if (!colorNameIndexKey) {
throw new Error(' Failed to create the createCompositeKey');
}
// Delete index entry to state.
await stub.deleteState(colorNameIndexKey);
}
// ===========================================================
// transfer a marble by setting a new owner name on the marble
// ===========================================================
async transferMarble(stub, args, thisClass) {
// 0 1
// 'name', 'bob'
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting marblename and owner')
}
let marbleName = args[0];
let newOwner = args[1].toLowerCase();
console.info('- start transferMarble ', marbleName, newOwner);
let marbleAsBytes = await stub.getState(marbleName);
if (!marbleAsBytes || !marbleAsBytes.toString()) {
throw new Error('marble does not exist');
}
let marbleToTransfer = {};
try {
marbleToTransfer = JSON.parse(marbleAsBytes.toString()); //unmarshal
} catch (err) {
let jsonResp = {};
jsonResp.error = 'Failed to decode JSON of: ' + marbleName;
throw new Error(jsonResp);
}
console.info(marbleToTransfer);
marbleToTransfer.owner = newOwner; //change the owner
let marbleJSONasBytes = Buffer.from(JSON.stringify(marbleToTransfer));
await stub.putState(marbleName, marbleJSONasBytes); //rewrite the marble
console.info('- end transferMarble (success)');
}
// ===========================================================================================
// getMarblesByRange performs a range query based on the start and end keys provided.
// Read-only function results are not typically submitted to ordering. If the read-only
// results are submitted to ordering, or if the query is used in an update transaction
// and submitted to ordering, then the committing peers will re-execute to guarantee that
// result sets are stable between endorsement time and commit time. The transaction is
// invalidated by the committing peers if the result set has changed between endorsement
// time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
async getMarblesByRange(stub, args, thisClass) {
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting 2');
}
let startKey = args[0];
let endKey = args[1];
let resultsIterator = await stub.getStateByRange(startKey, endKey);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
// ==== Example: GetStateByPartialCompositeKey/RangeQuery =========================================
// transferMarblesBasedOnColor will transfer marbles of a given color to a certain new owner.
// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'.
// Committing peers will re-execute range queries to guarantee that result sets are stable
// between endorsement time and commit time. The transaction is invalidated by the
// committing peers if the result set has changed between endorsement time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
async transferMarblesBasedOnColor(stub, args, thisClass) {
// 0 1
// 'color', 'bob'
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting color and owner');
}
let color = args[0];
let newOwner = args[1].toLowerCase();
console.info('- start transferMarblesBasedOnColor ', color, newOwner);
// Query the color~name index by color
// This will execute a key range query on all keys starting with 'color'
let coloredMarbleResultsIterator = await stub.getStateByPartialCompositeKey('color~name', [color]);
let method = thisClass['transferMarble'];
// Iterate through result set and for each marble found, transfer to newOwner
while (true) {
let responseRange = await coloredMarbleResultsIterator.next();
if (!responseRange || !responseRange.value || !responseRange.value.key) {
return;
}
console.log(responseRange.value.key);
// let value = res.value.value.toString('utf8');
let objectType;
let attributes;
({
objectType,
attributes
} = await stub.splitCompositeKey(responseRange.value.key));
let returnedColor = attributes[0];
let returnedMarbleName = attributes[1];
console.info(util.format('- found a marble from index:%s color:%s name:%s\n', objectType, returnedColor, returnedMarbleName));
// Now call the transfer function for the found marble.
// Re-use the same function that is used to transfer individual marbles
let response = await method(stub, [returnedMarbleName, newOwner]);
}
let responsePayload = util.format('Transferred %s marbles to %s', color, newOwner);
console.info('- end transferMarblesBasedOnColor: ' + responsePayload);
}
// ===== Example: Parameterized rich query =================================================
// queryMarblesByOwner queries for marbles based on a passed in owner.
// This is an example of a parameterized query where the query logic is baked into the chaincode,
// and accepting a single query parameter (owner).
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
async queryMarblesByOwner(stub, args, thisClass) {
// 0
// 'bob'
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting owner name.')
}
let owner = args[0].toLowerCase();
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'marble';
queryString.selector.owner = owner;
let method = thisClass['getQueryResultForQueryString'];
let queryResults = await method(stub, JSON.stringify(queryString), thisClass);
return queryResults; //shim.success(queryResults);
}
// ===== Example: Ad hoc rich query ========================================================
// queryMarbles uses a query string to perform a query for marbles.
// Query string matching state database syntax is passed in and executed as is.
// Supports ad hoc queries that can be defined at runtime by the client.
// If this is not desired, follow the queryMarblesForOwner example for parameterized queries.
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
async queryMarbles(stub, args, thisClass) {
// 0
// 'queryString'
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting queryString');
}
let queryString = args[0];
if (!queryString) {
throw new Error('queryString must not be empty');
}
let method = thisClass['getQueryResultForQueryString'];
let queryResults = await method(stub, queryString, thisClass);
return queryResults;
}
async getAllResults(iterator, isHistory) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.value.toString('utf8'));
if (isHistory && isHistory === true) {
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.IsDelete = res.value.is_delete.toString();
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
} else {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
}
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
await iterator.close();
console.info(allResults);
return allResults;
}
}
}
// =========================================================================================
// getQueryResultForQueryString executes the passed in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
async getQueryResultForQueryString(stub, queryString, thisClass) {
console.info('- getQueryResultForQueryString queryString:\n' + queryString)
let resultsIterator = await stub.getQueryResult(queryString);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
async getHistoryForMarble(stub, args, thisClass) {
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting 1')
}
let marbleName = args[0];
console.info('- start getHistoryForMarble: %s\n', marbleName);
let resultsIterator = await stub.getHistoryForKey(marbleName);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, true);
return Buffer.from(JSON.stringify(results));
}
// ====== Pagination =========================================================================
// Pagination provides a method to retrieve records with a defined pagesize and
// start point (bookmark). An empty string bookmark defines the first "page" of a query
// result. Paginated queries return a bookmark that can be used in
// the next query to retrieve the next page of results. Paginated queries extend
// rich queries and range queries to include a pagesize and bookmark.
//
// Two examples are provided in this example. The first is getMarblesByRangeWithPagination
// which executes a paginated range query.
// The second example is a paginated query for rich ad-hoc queries.
// =========================================================================================
// ====== Example: Pagination with Range Query ===============================================
// getMarblesByRangeWithPagination performs a range query based on the start & end key,
// page size and a bookmark.
//
// The number of fetched records will be equal to or lesser than the page size.
// Paginated range queries are only valid for read only transactions.
// ===========================================================================================
async getMarblesByRangeWithPagination(stub, args, thisClass) {
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting 2');
}
const startKey = args[0];
const endKey = args[1];
const pageSize = parseInt(args[2], 10);
const bookmark = args[3];
const { iterator, metadata } = await stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark);
const getAllResults = thisClass['getAllResults'];
const results = await getAllResults(iterator, false);
// use RecordsCount and Bookmark to keep consistency with the go sample
results.ResponseMetadata = {
RecordsCount: metadata.fetched_records_count,
Bookmark: metadata.bookmark,
};
return Buffer.from(JSON.stringify(results));
}
// =========================================================================================
// getQueryResultForQueryStringWithPagination executes the passed in query string with
// pagination info. Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
async queryMarblesWithPagination(stub, args, thisClass) {
// 0
// "queryString"
if (args.length < 3) {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
const queryString = args[0];
const pageSize = parseInt(args[1], 10);
const bookmark = args[2];
const { iterator, metadata } = await stub.getQueryResultWithPagination(queryString, pageSize, bookmark);
const getAllResults = thisClass['getAllResults'];
const results = await getAllResults(iterator, false);
// use RecordsCount and Bookmark to keep consistency with the go sample
results.ResponseMetadata = {
RecordsCount: metadata.fetched_records_count,
Bookmark: metadata.bookmark,
};
return Buffer.from(JSON.stringify(results));
}
};
shim.start(new Chaincode());
{
"name": "marbles",
"version": "1.0.0",
"description": "marbles chaincode implemented in node.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": {
"start": "node marbles_chaincode.js"
},
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "^2.0.0"
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment