Add secured agreement javascript application

Add the asset-transfer-secured-agreement javascript application
and have it run during CI.

Signed-off-by: Bret Harrison <beharrison@nc.rr.com>
This commit is contained in:
Bret Harrison 2020-08-27 16:22:55 -04:00 committed by denyeart
parent 0bc6f89cf2
commit fdea4f0f89
6 changed files with 649 additions and 2 deletions

View file

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

View file

@ -0,0 +1,37 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
module.exports = {
env: {
node: true,
mocha: true
},
parserOptions: {
ecmaVersion: 8,
sourceType: 'script'
},
extends: 'eslint:recommended',
rules: {
indent: ['error', 'tab'],
'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-trailing-spaces': 'error',
'no-use-before-define': 'error',
'no-useless-call': 'error',
'no-with': 'error',
'operator-linebreak': 'error',
yoda: 'error',
'quote-props': ['error', 'as-needed']
}
};

View file

@ -0,0 +1,14 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Coverage directory used by tools like istanbul
coverage
# Dependency directories
node_modules/
jspm_packages/
package-lock.json
wallet
!wallet/.gitkeep

View file

@ -0,0 +1,567 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
/**
* Application that uses implicit private data collections, state-based endorsement,
* and organization-based ownership and access control to keep data private and securely
* transfer an asset with the consent of both the current owner and buyer
* -- How to submit a transaction
* -- How to query
* -- How to limit the organizations involved in a transaction
*
* To see the SDK workings, try setting the logging to show on the console before running
* export HFC_LOGGING='{"debug":"console"}'
*/
// pre-requisites:
// - fabric-sample two organization test-network setup with two peers, ordering service,
// and 2 certificate authorities
// ===> from directory /fabric-samples/test-network
// ./network.sh up createChannel -ca
// - Use the asset-transfer-secured-agreement/chaincode-go chaincode deployed on
// the channel "mychannel". The following deploy command will package, install,
// approve, and commit the golang chaincode, all the actions it takes
// to deploy a chaincode to a channel with the endorsement and private collection
// settings.
// ===> from directory /fabric-samples/test-network
// ./network.sh deployCC -ccn secured -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
//
// - Be sure that node.js is installed
// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript
// node -v
// - npm installed code dependencies
// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript
// npm install
// - to run this test application
// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript
// node app.js
// NOTE: If you see an error like these:
/*
Error in setup: Error: DiscoveryService: mychannel error: access denied
OR
Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]]
*/
// Delete the /fabric-samples/asset-transfer-sbe/application-javascript/wallet directory
// and retry this application.
//
// The certificate authority must have been restarted and the saved certificates for the
// admin and application user are not valid. Deleting the wallet store will force these to be reset
// with the new certificate authority.
//
const { Gateway, Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const path = require('path');
const { buildCAClient, registerAndEnrollUser, enrollAdmin } = require('../../test-application/javascript/CAUtil.js');
const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js');
const channelName = 'mychannel';
const chaincodeName = 'secured';
const org1 = 'Org1MSP';
const org2 = 'Org2MSP';
const Org1UserId = 'appUser1';
const Org2UserId = 'appUser2';
const RED = '\x1b[31m\n';
const GREEN = '\x1b[32m\n';
const RESET = '\x1b[0m';
async function initGatewayForOrg1() {
console.log(`${GREEN}--> Fabric client user & Gateway init: Using Org1 identity to Org1 Peer${RESET}`);
// build an in memory object with the network configuration (also known as a connection profile)
const ccpOrg1 = buildCCPOrg1();
// build an instance of the fabric ca services client based on
// the information in the network configuration
const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com');
// setup the wallet to cache the credentials of the application user, on the app server locally
const walletPathOrg1 = path.join(__dirname, 'wallet', 'org1');
const walletOrg1 = await buildWallet(Wallets, walletPathOrg1);
// in a real application this would be done on an administrative flow, and only once
// stores admin identity in local wallet, if needed
await enrollAdmin(caOrg1Client, walletOrg1, org1);
// register & enroll application user with CA, which is used as client identify to make chaincode calls
// and stores app user identity in local wallet
// In a real application this would be done only when a new user was required to be added
// and would be part of an administrative flow
await registerAndEnrollUser(caOrg1Client, walletOrg1, org1, Org1UserId, 'org1.department1');
try {
// Create a new gateway for connecting to Org's peer node.
const gatewayOrg1 = new Gateway();
//connect using Discovery enabled
await gatewayOrg1.connect(ccpOrg1,
{ wallet: walletOrg1, identity: Org1UserId, discovery: { enabled: true, asLocalhost: true } });
return gatewayOrg1;
} catch (error) {
console.error(`Error in connecting to gateway for Org1: ${error}`);
process.exit(1);
}
}
async function initGatewayForOrg2() {
console.log(`${GREEN}--> Fabric client user & Gateway init: Using Org2 identity to Org2 Peer${RESET}`);
const ccpOrg2 = buildCCPOrg2();
const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com');
const walletPathOrg2 = path.join(__dirname, 'wallet', 'org2');
const walletOrg2 = await buildWallet(Wallets, walletPathOrg2);
await enrollAdmin(caOrg2Client, walletOrg2, org2);
await registerAndEnrollUser(caOrg2Client, walletOrg2, org2, Org2UserId, 'org2.department1');
try {
// Create a new gateway for connecting to Org's peer node.
const gatewayOrg2 = new Gateway();
await gatewayOrg2.connect(ccpOrg2,
{ wallet: walletOrg2, identity: Org2UserId, discovery: { enabled: true, asLocalhost: true } });
return gatewayOrg2;
} catch (error) {
console.error(`Error in connecting to gateway for Org2: ${error}`);
process.exit(1);
}
}
async function readPrivateAsset(assetKey, org, contract) {
console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`);
try {
const resultBuffer = await contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
const asset = JSON.parse(resultBuffer.toString('utf8'));
console.log(`*** Result: GetAssetPrivateProperties, ${JSON.stringify(asset)}`);
} catch (evalError) {
console.log(`*** Failed evaluateTransaction readPrivateAsset: ${evalError}`);
}
}
async function readBidPrice(assetKey, org, contract) {
console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${org}${RESET}`);
try {
const resultBuffer = await contract.evaluateTransaction('GetAssetBidPrice', assetKey);
const asset = JSON.parse(resultBuffer.toString('utf8'));
console.log(`*** Result: GetAssetBidPrice, ${JSON.stringify(asset)}`);
} catch (evalError) {
console.log(`*** Failed evaluateTransaction GetAssetBidPrice: ${evalError}`);
}
}
async function readSalePrice(assetKey, org, contract) {
console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${org}${RESET}`);
try {
const resultBuffer = await contract.evaluateTransaction('GetAssetSalesPrice', assetKey);
const asset = JSON.parse(resultBuffer.toString('utf8'));
console.log(`*** Result: GetAssetSalesPrice, ${JSON.stringify(asset)}`);
} catch (evalError) {
console.log(`*** Failed evaluateTransaction GetAssetSalesPrice: ${evalError}`);
}
}
function checkAsset(org, resultBuffer, ownerOrg) {
let asset;
if (resultBuffer) {
asset = JSON.parse(resultBuffer.toString('utf8'));
}
if (asset) {
if (asset.ownerOrg === ownerOrg) {
console.log(`*** Result from ${org} - asset ${asset.assetID} owned by ${asset.ownerOrg} DESC:${asset.publicDescription}`);
} else {
console.log(`${RED}*** Failed owner check from ${org} - asset ${asset.assetID} owned by ${asset.ownerOrg} DESC:${asset.publicDescription}${RESET}`);
}
}
}
// This is not a real function for an application, this simulates when two applications are running
// from different organizations and what they would see if they were to both query the asset
async function readAssetByBothOrgs(assetKey, ownerOrg, contractOrg1, contractOrg2) {
console.log(`${GREEN}--> Evaluate Transactions: ReadAsset, - ${assetKey} should be owned by ${ownerOrg}${RESET}`);
let resultBuffer;
resultBuffer = await contractOrg1.evaluateTransaction('ReadAsset', assetKey);
checkAsset('Org1', resultBuffer, ownerOrg);
resultBuffer = await contractOrg2.evaluateTransaction('ReadAsset', assetKey);
checkAsset('Org2', resultBuffer, ownerOrg);
}
// This application uses fabric-samples/test-network based setup and the companion chaincode
// For this illustration, both Org1 & Org2 client identities will be used, however
// notice they are used by two different "gateway"s to simulate two different running
// applications from two different organizations.
async function main() {
console.log(`${GREEN} **** START ****${RESET}`);
try {
const randomNumber = Math.floor(Math.random() * 100) + 1;
// use a random key so that we can run multiple times
const assetKey = `asset-${randomNumber}`;
/** ******* Fabric client init: Using Org1 identity to Org1 Peer ******* */
const gatewayOrg1 = await initGatewayForOrg1();
const networkOrg1 = await gatewayOrg1.getNetwork(channelName);
const contractOrg1 = networkOrg1.getContract(chaincodeName);
/** ******* Fabric client init: Using Org2 identity to Org2 Peer ******* */
const gatewayOrg2 = await initGatewayForOrg2();
const networkOrg2 = await gatewayOrg2.getNetwork(channelName);
const contractOrg2 = networkOrg2.getContract(chaincodeName);
try {
let transaction;
try {
// Create an asset by organization Org1, this only requires the owning
// organization to endorse.
// With the gateway using discovery, we should limit the organizations used
// to endorse. This only requires knowledge of the Organizations and not
// the actual peers that may be active at any given time.
const asset_properties = {
object_type: 'asset_properties',
asset_id: assetKey,
color: 'blue',
size: 35,
salt: Buffer.from(randomNumber.toString()).toString('hex')
};
const asset_properties_string = JSON.stringify(asset_properties);
console.log(`${GREEN}--> Submit Transaction: CreateAsset, ${assetKey} as Org1 - endorsed by Org1${RESET}`);
console.log(`${asset_properties_string}`);
transaction = contractOrg1.createTransaction('CreateAsset');
transaction.setEndorsingOrganizations(org1);
transaction.setTransient({
asset_properties: Buffer.from(asset_properties_string)
});
await transaction.submit(assetKey, `Asset ${assetKey} owned by ${org1} is not for sale`);
console.log(`*** Result: committed, asset ${assetKey} is owned by Org1`);
} catch (createError) {
console.log(`${RED}*** Failed: CreateAsset - ${createError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org1, contractOrg1, contractOrg2);
// Org1 should be able to read the private data details of this asset
await readPrivateAsset(assetKey, org1, contractOrg1);
// Org2 is not the owner and does not have the private details, this should fail
await readPrivateAsset(assetKey, org2, contractOrg2);
try {
// This is an update to the public state and requires only the owner to endorse.
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as Org1 - endorse by Org1${RESET}`);
transaction = contractOrg1.createTransaction('ChangePublicDescription');
transaction.setEndorsingOrganizations(org1);
await transaction.submit(assetKey, `Asset ${assetKey} owned by ${org1} is for sale`);
console.log(`*** Result: committed, asset ${assetKey} is now for sale by Org1`);
} catch (updateError) {
console.log(`${RED}*** Failed: ChangePublicDescription - ${updateError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org1, contractOrg1, contractOrg2);
try {
// This is an update to the public state and requires the owner(Org1) to endorse and
// sent by the owner org client (Org1).
// Since the client is from Org2, which is not the owner, this will fail
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as Org2 - endorse by Org2${RESET}`);
transaction = contractOrg2.createTransaction('ChangePublicDescription');
transaction.setEndorsingOrganizations(org2);
await transaction.submit(assetKey, `Asset ${assetKey} owned by ${org2} is NOT for sale`);
console.log(`${RESET}*** Failed: Org2 is not the owner and this should have failed${RESET}`);
} catch (updateError) {
console.log(`*** Success: ChangePublicDescription has failed endorsememnt by Org2 sent by Org2 - ${updateError}`);
}
try {
// This is an update to the public state and requires the owner(Org1) to endorse and
// sent by the owner org client (Org1).
// Since this is being sent by Org2, which is not the owner, this will fail
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as Org2 - endorse by Org1${RESET}`);
transaction = contractOrg2.createTransaction('ChangePublicDescription');
transaction.setEndorsingOrganizations(org1);
await transaction.submit(assetKey, `Asset ${assetKey} owned by ${org2} is NOT for sale`);
console.log(`${RESET}*** Failed: Org2 is not the owner and this should have failed${RESET}`);
} catch (updateError) {
console.log(`*** Success: ChangePublicDescription has failed endorsement by Org1 sent by Org2 - ${updateError}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org1, contractOrg1, contractOrg2);
try {
// Agree to a sell by Org1
const asset_price = {
asset_id: assetKey,
price: 110,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetKey} as Org1 - endorsed by Org1${RESET}`);
transaction = contractOrg1.createTransaction('AgreeToSell');
transaction.setEndorsingOrganizations(org1);
transaction.setTransient({
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey);
console.log(`*** Result: committed, Org1 has agreed to sell asset ${assetKey} for 110`);
} catch (sellError) {
console.log(`${RED}*** Failed: AgreeToSell - ${sellError}${RESET}`);
}
try {
// check the private information about the asset from Org2
// Org1 would have to send Org2 these details, so the hash of the
// details may be checked by the chaincode.
const asset_properties = {
object_type: 'asset_properties',
asset_id: assetKey,
color: 'blue',
size: 35,
salt: Buffer.from(randomNumber.toString()).toString('hex')
};
const asset_properties_string = JSON.stringify(asset_properties);
console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetKey} as Org2 - endorsed by Org2${RESET}`);
console.log(`${asset_properties_string}`);
transaction = contractOrg2.createTransaction('VerifyAssetProperties');
transaction.setTransient({
asset_properties: Buffer.from(asset_properties_string)
});
const verifyResultBuffer = await transaction.evaluate(assetKey);
if (verifyResultBuffer) {
const verifyResult = Boolean(verifyResultBuffer.toString());
if (verifyResult) {
console.log(`*** Successfully VerifyAssetProperties, private information about asset ${assetKey} has been verified by Org2`);
} else {
console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetKey} has not been verified by Org2`);
}
} else {
console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetKey} has not been verified by Org2`);
}
} catch (verifyError) {
console.log(`${RED}*** Failed: VerifyAssetProperties - ${verifyError}${RESET}`);
}
try {
// Agree to a buy by Org2
const asset_price = {
asset_id: assetKey,
price: 100,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetKey} as Org2 - endorsed by Org2${RESET}`);
transaction = contractOrg2.createTransaction('AgreeToBuy');
transaction.setEndorsingOrganizations(org2);
transaction.setTransient({
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey);
console.log(`*** Result: committed, Org2 has agreed to buy asset ${assetKey} for 100`);
} catch (buyError) {
console.log(`${RED}*** Failed: AgreeToBuy - ${buyError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org1, contractOrg1, contractOrg2);
// Org1 should be able to read the private data details of this asset
await readPrivateAsset(assetKey, org1, contractOrg1);
// Org2 is not the owner and does not have the private details, this should fail
await readPrivateAsset(assetKey, org2, contractOrg2);
// Org1 should be able to read the sale price of this asset
await readSalePrice(assetKey, org1, contractOrg1);
// Org2 has not set a sale price and this should fail
await readSalePrice(assetKey, org2, contractOrg2);
// Org1 has not agreed to buy so this should fail
await readBidPrice(assetKey, org1, contractOrg1);
// Org2 should be able to see the price it has agreed
await readBidPrice(assetKey, org2, contractOrg2);
try {
// Org1 will try to transfer the asset to Org2
// This will fail due to the sell price and the bid price
// are not the same
const asset_properties = {
object_type: 'asset_properties',
asset_id: assetKey,
color: 'blue',
size: 35,
salt: Buffer.from(randomNumber.toString()).toString('hex')
};
const asset_properties_string = JSON.stringify(asset_properties);
const asset_price = {
asset_id: assetKey,
price: 110,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as Org1 - endorsed by Org1${RESET}`);
console.log(`${asset_properties_string}`);
transaction = contractOrg1.createTransaction('TransferAsset');
transaction.setEndorsingOrganizations(org1);
transaction.setTransient({
asset_properties: Buffer.from(asset_properties_string),
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey, org2);
console.log(`${RED}*** Failed: committed, TransferAsset should have failed for asset ${assetKey}${RESET}`);
} catch (transferError) {
console.log(`*** Success: TransferAsset - ${transferError}`);
}
try {
// Agree to a sell by Org1
// Org1, the seller will agree to the bid price of Org2
const asset_price = {
asset_id: assetKey,
price: 100,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetKey} as Org1 - endorsed by Org1${RESET}`);
transaction = contractOrg1.createTransaction('AgreeToSell');
transaction.setEndorsingOrganizations(org1);
transaction.setTransient({
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey);
console.log(`*** Result: committed, Org1 has agreed to sell asset ${assetKey} for 100`);
} catch (sellError) {
console.log(`${RED}*** Failed: AgreeToSell - ${sellError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org1, contractOrg1, contractOrg2);
// Org1 should be able to read the private data details of this asset
await readPrivateAsset(assetKey, org1, contractOrg1);
// Org1 should be able to read the sale price of this asset
await readSalePrice(assetKey, org1, contractOrg1);
// Org2 should be able to see the price it has agreed
await readBidPrice(assetKey, org2, contractOrg2);
try {
// Org2 user will try to transfer the asset to Org2
// This will fail as the owner is Org1
const asset_properties = {
object_type: 'asset_properties',
asset_id: assetKey,
color: 'blue',
size: 35,
salt: Buffer.from(randomNumber.toString()).toString('hex')
};
const asset_properties_string = JSON.stringify(asset_properties);
const asset_price = {
asset_id: assetKey,
price: 100,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as Org2 - endorsed by Org1${RESET}`);
console.log(`${asset_properties_string}`);
transaction = contractOrg2.createTransaction('TransferAsset');
transaction.setEndorsingOrganizations(org1, org2);
transaction.setTransient({
asset_properties: Buffer.from(asset_properties_string),
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey, org2);
console.log(`${RED}*** FAILED: committed, TransferAsset - Org2 now owns the asset ${assetKey}${RESET}`);
} catch (transferError) {
console.log(`*** Succeded: TransferAsset - ${transferError}`);
}
try {
// Org1 will transfer the asset to Org2
// This will now complete as the sell price and the bid price are the same
const asset_properties = {
object_type: 'asset_properties',
asset_id: assetKey,
color: 'blue',
size: 35,
salt: Buffer.from(randomNumber.toString()).toString('hex')
};
const asset_properties_string = JSON.stringify(asset_properties);
const asset_price = {
asset_id: assetKey,
price: 100,
trade_id: randomNumber.toString()
};
const asset_price_string = JSON.stringify(asset_price);
console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as Org1 - endorsed by Org1${RESET}`);
console.log(`${asset_properties_string}`);
transaction = contractOrg1.createTransaction('TransferAsset');
transaction.setEndorsingOrganizations(org1, org2);
transaction.setTransient({
asset_properties: Buffer.from(asset_properties_string),
asset_price: Buffer.from(asset_price_string)
});
await transaction.submit(assetKey, org2);
console.log(`*** Results: committed, TransferAsset - Org2 now owns the asset ${assetKey}`);
} catch (transferError) {
console.log(`${RED}*** Failed: TransferAsset - ${transferError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org2, contractOrg1, contractOrg2);
// Org2 should be able to read the private data details of this asset
await readPrivateAsset(assetKey, org2, contractOrg2);
// Org1 should not be able to read the private data details of this asset
await readPrivateAsset(assetKey, org1, contractOrg1);
try {
// This is an update to the public state and requires only the owner to endorse.
// Org2 wants to indicate that the items is no longer for sale
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as Org2 - endorse by Org2${RESET}`);
transaction = contractOrg2.createTransaction('ChangePublicDescription');
transaction.setEndorsingOrganizations(org2);
await transaction.submit(assetKey, `Asset ${assetKey} owned by ${org2} is NOT for sale`);
console.log('*** Results: committed - Org2 is now the owner and asset is not for sale');
} catch (updateError) {
console.log(`${RED}*** Failed: ChangePublicDescription has failed by Org2 - ${updateError}${RESET}`);
}
// read the public details by both orgs
await readAssetByBothOrgs(assetKey, org2, contractOrg1, contractOrg2);
} catch (runError) {
console.error(`Error in transaction: ${runError}`);
if (runError.stack) {
console.error(runError.stack);
}
process.exit(1);
} finally {
// Disconnect from the gateway peer when all work for this client identity is complete
console.log(`${GREEN}--> Close gateways`);
gatewayOrg1.disconnect();
gatewayOrg2.disconnect();
}
} catch (error) {
console.error(`Error in setup: ${error}`);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
console.log(`${GREEN} **** END ****${RESET}`);
}
main();

View file

@ -0,0 +1,16 @@
{
"name": "asset-transfer-secured-agreement",
"version": "1.0.0",
"description": "Javascript application that uses implicit private data collections, state-based endorsement, and organization-based ownership and access control to keep data private and securely transfer an asset with the consent of both the current owner and buyer",
"engines": {
"node": ">=12",
"npm": ">=5"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-ca-client": "^2.2.2",
"fabric-network": "^2.2.2"
}
}

View file

@ -13,9 +13,9 @@ function print() {
function createNetwork() {
print "Creating network"
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
./network.sh up createChannel -ca
print "Deploying ${CHAINCODE_NAME} chaincode"
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccl "${CHAINCODE_LANGUAGE}" -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
}
function stopNetwork() {
@ -25,4 +25,12 @@ function stopNetwork() {
# Run Javascript application
createNetwork
print "Initializing Javascript application"
pushd ../asset-transfer-secured-agreement/application-javascript
npm install
print "Executing app.js"
node app.js
popd
stopNetwork
print "Remove wallet storage"
rm -R ../asset-transfer-secured-agreement/application-javascript/wallet