mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-20 16:45:09 +00:00
Private data samples migration (#574)
Signed-off-by: sapthasurendran <saptha.surendran@ibm.com> Updated application flow Signed-off-by: sapthasurendran <saptha.surendran@ibm.com> Add grpc dependency in package.json Signed-off-by: sapthasurendran <saptha.surendran@ibm.com> Update CI pipelines to run new app Updated application description in package.json Fixed chaincode name Code Refactor Signed-off-by: sapthasurendran <saptha.surendran@ibm.com>
This commit is contained in:
parent
70cce456d4
commit
f01eeab663
9 changed files with 624 additions and 0 deletions
78
asset-transfer-private-data/README.md
Normal file
78
asset-transfer-private-data/README.md
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Asset transfer private data sample
|
||||||
|
|
||||||
|
The asset transfer private data sample demonstrates:
|
||||||
|
|
||||||
|
- Usage of organization private data collections
|
||||||
|
- Read data from the organization private data collection.
|
||||||
|
- Store data in organization private data collection.
|
||||||
|
|
||||||
|
For more information about private data, visit the
|
||||||
|
[Private Data](https://hyperledger-fabric.readthedocs.io/en/latest/private-data-arch.html)
|
||||||
|
page in the Fabric documentation.
|
||||||
|
|
||||||
|
## About the sample
|
||||||
|
|
||||||
|
This sample includes smart contract and application code in multiple languages. In a use-case similar to basic asset transfer (see [asset-transfer-basic](../asset-transfer-basic) folder) this sample shows sending and receiving of asset along with its private data owned by organizations during create / delete of an asset , and during transfer of an asset to a new owner.
|
||||||
|
|
||||||
|
### Application
|
||||||
|
|
||||||
|
Please refer the below link to understand the application flow.
|
||||||
|
https://hyperledger-fabric.readthedocs.io/en/latest/private-data/private-data.html#example-scenario-asset-transfer-using-private-data-collections
|
||||||
|
|
||||||
|
### Smart Contract
|
||||||
|
|
||||||
|
The smart contract (in folder `chaincode-xyz`) implements the following functions to support the application:
|
||||||
|
|
||||||
|
CreateAsset
|
||||||
|
AgreeToTransfer
|
||||||
|
TransferAsset
|
||||||
|
DeleteAsset
|
||||||
|
DeleteTranferAgreement
|
||||||
|
|
||||||
|
ReadAsset
|
||||||
|
ReadAssetPrivateDetails
|
||||||
|
ReadTransferAgreement
|
||||||
|
GetAssetByRange
|
||||||
|
QueryAssetByOwner
|
||||||
|
QueryAssets
|
||||||
|
getQueryResultForQueryString
|
||||||
|
|
||||||
|
## Running the sample
|
||||||
|
|
||||||
|
Like other samples, the Fabric test network is used to deploy and run this sample. Follow these steps in order:
|
||||||
|
|
||||||
|
1. Create the test network and a channel (from the `test-network` folder).
|
||||||
|
```
|
||||||
|
./network.sh up createChannel -c mychannel -ca
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Deploy one of the smart contract implementations (from the `test-network` folder).
|
||||||
|
```
|
||||||
|
# To deploy the Java chaincode implementation
|
||||||
|
./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-java -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg '../asset-transfer-private-data/chaincode-java/collections_config.json' -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
|
||||||
|
|
||||||
|
# To deploy the go chaincode implementation
|
||||||
|
./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-go -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg '../asset-transfer-private-data/chaincode-go/collections_config.json' -ccep "OR('Org1MSP.peer','Org2MSP.peer')"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the application (from the `asset-transfer-private-data` folder).
|
||||||
|
```
|
||||||
|
# To run the Javascript sample application
|
||||||
|
cd application-javascript
|
||||||
|
npm install
|
||||||
|
node app.js
|
||||||
|
|
||||||
|
# To run the Typescript sample application
|
||||||
|
cd application-gateway-typescript
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clean up
|
||||||
|
|
||||||
|
When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created.
|
||||||
|
|
||||||
|
```
|
||||||
|
./network.sh down
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"root": true,
|
||||||
|
"ignorePatterns": [
|
||||||
|
"dist/"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"**/*.ts"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"sourceType": "module",
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"impliedStrict": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
asset-transfer-private-data/application-gateway-typescript/.gitignore
vendored
Normal file
14
asset-transfer-private-data/application-gateway-typescript/.gitignore
vendored
Normal 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/
|
||||||
|
|
||||||
|
# Compiled TypeScript files
|
||||||
|
dist
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Asset Transfer Private Data Sample
|
||||||
|
|
||||||
|
This app uses fabric-samples/test-network based setup and the companion chaincode asset-transfer-private-data/chaincode-go/ with chaincode endorsement policy as "OR('Org1MSP.peer','Org2MSP.peer')"
|
||||||
|
|
||||||
|
For this usecase illustration, we will use both Org1 & Org2 client identity from this same app
|
||||||
|
In real world the Org1 & Org2 identity will be used in different apps to achieve asset transfer.
|
||||||
|
|
||||||
|
For more details refer:
|
||||||
|
https://hyperledger-fabric.readthedocs.io/en/release-2.4/private_data_tutorial.html#pd-use-case
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "asset-transfer-private-data",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Asset transfer private data application implemented in typeScript using fabric-gateway",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"typings": "dist/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"build:watch": "tsc -w",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"prepare": "npm run build",
|
||||||
|
"pretest": "npm run lint",
|
||||||
|
"start": "node dist/app.js"
|
||||||
|
},
|
||||||
|
"engineStrict": true,
|
||||||
|
"author": "Hyperledger",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@grpc/grpc-js": "^1.5.0",
|
||||||
|
"@hyperledger/fabric-gateway": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tsconfig/node14": "^1.0.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
||||||
|
"@typescript-eslint/parser": "^5.6.0",
|
||||||
|
"eslint": "^8.4.1",
|
||||||
|
"typescript": "~4.5.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,286 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { connect, Contract } from '@hyperledger/fabric-gateway';
|
||||||
|
import { TextDecoder } from 'util';
|
||||||
|
import {
|
||||||
|
certPathOrg1, certPathOrg2, keyDirectoryPathOrg1, keyDirectoryPathOrg2, newGrpcConnection, newIdentity,
|
||||||
|
newSigner, peerEndpointOrg1, peerEndpointOrg2, peerNameOrg1, peerNameOrg2, tlsCertPathOrg1, tlsCertPathOrg2
|
||||||
|
} from './connect';
|
||||||
|
|
||||||
|
const channelName = 'mychannel';
|
||||||
|
const chaincodeName = 'private';
|
||||||
|
const mspIdOrg1 = 'Org1MSP';
|
||||||
|
const mspIdOrg2 = 'Org2MSP';
|
||||||
|
|
||||||
|
const utf8Decoder = new TextDecoder();
|
||||||
|
|
||||||
|
// Collection Names
|
||||||
|
const org1PrivateCollectionName = 'Org1MSPPrivateCollection';
|
||||||
|
const org2PrivateCollectionName = 'Org2MSPPrivateCollection';
|
||||||
|
|
||||||
|
const RED = '\x1b[31m\n';
|
||||||
|
const RESET = '\x1b[0m';
|
||||||
|
|
||||||
|
// Use a unique key so that we can run multiple times
|
||||||
|
const now = Date.now();
|
||||||
|
const assetID1 = `asset${now}`;
|
||||||
|
const assetID2 = `asset${now + 1}`;
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
const clientOrg1 = await newGrpcConnection(
|
||||||
|
tlsCertPathOrg1,
|
||||||
|
peerEndpointOrg1,
|
||||||
|
peerNameOrg1
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayOrg1 = connect({
|
||||||
|
client: clientOrg1,
|
||||||
|
identity: await newIdentity(certPathOrg1, mspIdOrg1),
|
||||||
|
signer: await newSigner(keyDirectoryPathOrg1),
|
||||||
|
});
|
||||||
|
|
||||||
|
const clientOrg2 = await newGrpcConnection(
|
||||||
|
tlsCertPathOrg2,
|
||||||
|
peerEndpointOrg2,
|
||||||
|
peerNameOrg2
|
||||||
|
);
|
||||||
|
|
||||||
|
const gatewayOrg2 = connect({
|
||||||
|
client: clientOrg2,
|
||||||
|
identity: await newIdentity(certPathOrg2, mspIdOrg2),
|
||||||
|
signer: await newSigner(keyDirectoryPathOrg2),
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the smart contract as an Org1 client.
|
||||||
|
const contractOrg1 = gatewayOrg1
|
||||||
|
.getNetwork(channelName)
|
||||||
|
.getContract(chaincodeName);
|
||||||
|
|
||||||
|
// Get the smart contract as an Org2 client.
|
||||||
|
const contractOrg2 = gatewayOrg2
|
||||||
|
.getNetwork(channelName)
|
||||||
|
.getContract(chaincodeName);
|
||||||
|
|
||||||
|
console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~');
|
||||||
|
|
||||||
|
// Create new assets on the ledger.
|
||||||
|
await createAssets(contractOrg1);
|
||||||
|
|
||||||
|
// Read asset from the Org1's private data collection with ID in the given range.
|
||||||
|
await getAssetsByRange(contractOrg1);
|
||||||
|
|
||||||
|
try{
|
||||||
|
//Attempt to transfer asset without prior aprroval from Org2, transaction expected to fail.
|
||||||
|
console.log('\nAttempt TransferAsset without prior AgreeToTransfer');
|
||||||
|
await transferAsset(contractOrg1, assetID1);
|
||||||
|
doFail('TransferAsset transaction succeeded when it was expected to fail');
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.log(`*** Received expected error: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~');
|
||||||
|
|
||||||
|
// Read the asset by ID.
|
||||||
|
await readAssetByID(contractOrg2, assetID1);
|
||||||
|
|
||||||
|
// Make agreement to transfer the asset from Org1 to Org2.
|
||||||
|
await agreeToTransfer(contractOrg2, assetID1);
|
||||||
|
|
||||||
|
console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~');
|
||||||
|
|
||||||
|
// Read transfer agreement.
|
||||||
|
await readTransferAgreement(contractOrg1, assetID1);
|
||||||
|
|
||||||
|
// Transfer asset to Org2.
|
||||||
|
await transferAsset(contractOrg1, assetID1);
|
||||||
|
|
||||||
|
// Again ReadAsset : results will show that the buyer identity now owns the asset.
|
||||||
|
await readAssetByID(contractOrg1, assetID1);
|
||||||
|
|
||||||
|
// Confirm that transfer removed the private details from the Org1 collection.
|
||||||
|
const org1ReadSuccess = await readAssetPrivateDetails(contractOrg1, assetID1, org1PrivateCollectionName);
|
||||||
|
if (org1ReadSuccess) {
|
||||||
|
doFail(`Asset private data still exists in ${org1PrivateCollectionName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~');
|
||||||
|
|
||||||
|
// Org2 can read asset private details: Org2 is owner, and private details exist in new owner's Collection
|
||||||
|
const org2ReadSuccess = await readAssetPrivateDetails(contractOrg2, assetID1, org2PrivateCollectionName);
|
||||||
|
if (!org2ReadSuccess) {
|
||||||
|
doFail(`Asset private data not found in ${org2PrivateCollectionName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('\nAttempt DeleteAsset using non-owner organization');
|
||||||
|
await deleteAsset(contractOrg2, assetID2);
|
||||||
|
doFail('DeleteAsset transaction succeeded when it was expected to fail');
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`*** Received expected error: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~');
|
||||||
|
|
||||||
|
// Delete AssetID2 as Org1.
|
||||||
|
await deleteAsset(contractOrg1, assetID2);
|
||||||
|
} finally {
|
||||||
|
gatewayOrg1.close();
|
||||||
|
clientOrg1.close();
|
||||||
|
|
||||||
|
gatewayOrg2.close();
|
||||||
|
clientOrg2.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error('******** FAILED to run the application:', error);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a transaction synchronously, blocking until it has been committed to the ledger.
|
||||||
|
*/
|
||||||
|
async function createAssets(contract: Contract): Promise<void> {
|
||||||
|
const assetType = 'ValuableAsset';
|
||||||
|
|
||||||
|
console.log(`\n--> Submit Transaction: CreateAsset, ID: ${assetID1}`);
|
||||||
|
|
||||||
|
const asset1Data = {
|
||||||
|
objectType: assetType,
|
||||||
|
assetID: assetID1,
|
||||||
|
color: 'green',
|
||||||
|
size: 20,
|
||||||
|
appraisedValue: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
await contract.submit('CreateAsset', {
|
||||||
|
transientData: { asset_properties: JSON.stringify(asset1Data) },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
console.log(`\n--> Submit Transaction: CreateAsset, ID: ${assetID2}`);
|
||||||
|
|
||||||
|
const asset2Data = {
|
||||||
|
objectType: assetType,
|
||||||
|
assetID: assetID2,
|
||||||
|
color: 'blue',
|
||||||
|
size: 35,
|
||||||
|
appraisedValue: 727,
|
||||||
|
};
|
||||||
|
|
||||||
|
await contract.submit('CreateAsset', {
|
||||||
|
transientData: { asset_properties: JSON.stringify(asset2Data) },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAssetsByRange(contract: Contract): Promise<void> {
|
||||||
|
// GetAssetByRange returns assets on the ledger with ID in the range of startKey (inclusive) and endKey (exclusive).
|
||||||
|
console.log(`\n--> Evaluate Transaction: ReadAssetPrivateDetails from ${org1PrivateCollectionName}`);
|
||||||
|
|
||||||
|
const resultBytes = await contract.evaluateTransaction(
|
||||||
|
'GetAssetByRange',
|
||||||
|
assetID1,
|
||||||
|
`asset${now + 2}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultString = utf8Decoder.decode(resultBytes);
|
||||||
|
if (!resultString) {
|
||||||
|
doFail('Received empty query list for readAssetPrivateDetailsOrg1');
|
||||||
|
}
|
||||||
|
const result = JSON.parse(resultString);
|
||||||
|
console.log('*** Result:', result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readAssetByID(contract: Contract, assetID: string): Promise<void> {
|
||||||
|
console.log(`\n--> Evaluate Transaction: ReadAsset, ID: ${assetID}`);
|
||||||
|
const resultBytes = await contract.evaluateTransaction('ReadAsset', assetID);
|
||||||
|
|
||||||
|
const resultString = utf8Decoder.decode(resultBytes);
|
||||||
|
if (!resultString) {
|
||||||
|
doFail('Received empty result for ReadAsset');
|
||||||
|
}
|
||||||
|
const result = JSON.parse(resultString);
|
||||||
|
console.log('*** Result:', result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function agreeToTransfer(contract: Contract, assetID: string): Promise<void> {
|
||||||
|
// Buyer from Org2 agrees to buy the asset//
|
||||||
|
// To purchase the asset, the buyer needs to agree to the same value as the asset owner
|
||||||
|
|
||||||
|
const dataForAgreement = { assetID, appraisedValue: 100 };
|
||||||
|
console.log('\n--> Submit Transaction: AgreeToTransfer, payload:', dataForAgreement);
|
||||||
|
|
||||||
|
await contract.submit('AgreeToTransfer', {
|
||||||
|
transientData: { asset_value: JSON.stringify(dataForAgreement) },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readTransferAgreement(contract: Contract, assetID: string): Promise<void> {
|
||||||
|
console.log(`\n--> Evaluate Transaction: ReadTransferAgreement, ID: ${assetID}`);
|
||||||
|
|
||||||
|
const resultBytes = await contract.evaluateTransaction(
|
||||||
|
'ReadTransferAgreement',
|
||||||
|
assetID
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultString = utf8Decoder.decode(resultBytes);
|
||||||
|
if (!resultString) {
|
||||||
|
doFail('Received no result for ReadTransferAgreement');
|
||||||
|
}
|
||||||
|
const result = JSON.parse(resultString);
|
||||||
|
console.log('*** Result:', result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferAsset(contract: Contract, assetID: string): Promise<void> {
|
||||||
|
console.log(`\n--> Submit Transaction: TransferAsset, ID: ${assetID}`);
|
||||||
|
|
||||||
|
const buyerDetails = { assetID, buyerMSP: mspIdOrg2 };
|
||||||
|
await contract.submit('TransferAsset', {
|
||||||
|
transientData: { asset_owner: JSON.stringify(buyerDetails) },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteAsset(contract: Contract, assetID: string): Promise<void> {
|
||||||
|
console.log('\n--> Submit Transaction: DeleteAsset, ID:', assetID);
|
||||||
|
const dataForDelete = { assetID };
|
||||||
|
await contract.submit('DeleteAsset', {
|
||||||
|
transientData: { asset_delete: JSON.stringify(dataForDelete) },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
}
|
||||||
|
async function readAssetPrivateDetails(contract: Contract, assetID: string, collectionName: string): Promise<boolean> {
|
||||||
|
console.log(`\n--> Evaluate Transaction: ReadAssetPrivateDetails from ${collectionName}, ID: ${assetID}`);
|
||||||
|
|
||||||
|
const resultBytes = await contract.evaluateTransaction(
|
||||||
|
'ReadAssetPrivateDetails',
|
||||||
|
collectionName,
|
||||||
|
assetID
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultJson = utf8Decoder.decode(resultBytes);
|
||||||
|
if (!resultJson) {
|
||||||
|
console.log('*** No result');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const result = JSON.parse(resultJson);
|
||||||
|
console.log('*** Result:', result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doFail(msgString: string): never {
|
||||||
|
console.error(`${RED}\t${msgString}${RESET}`);
|
||||||
|
throw new Error(msgString);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as grpc from '@grpc/grpc-js';
|
||||||
|
import { Identity, Signer, signers } from '@hyperledger/fabric-gateway';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
// Path to org1 crypto materials.
|
||||||
|
const cryptoPathOrg1 = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'test-network',
|
||||||
|
'organizations',
|
||||||
|
'peerOrganizations',
|
||||||
|
'org1.example.com'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org1 user private key directory.
|
||||||
|
export const keyDirectoryPathOrg1 = path.resolve(
|
||||||
|
cryptoPathOrg1,
|
||||||
|
'users',
|
||||||
|
'User1@org1.example.com',
|
||||||
|
'msp',
|
||||||
|
'keystore'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org1 user certificate.
|
||||||
|
export const certPathOrg1 = path.resolve(
|
||||||
|
cryptoPathOrg1,
|
||||||
|
'users',
|
||||||
|
'User1@org1.example.com',
|
||||||
|
'msp',
|
||||||
|
'signcerts',
|
||||||
|
'cert.pem'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org1 peer tls certificate.
|
||||||
|
export const tlsCertPathOrg1 = path.resolve(
|
||||||
|
cryptoPathOrg1,
|
||||||
|
'peers',
|
||||||
|
'peer0.org1.example.com',
|
||||||
|
'tls',
|
||||||
|
'ca.crt'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org2 crypto materials.
|
||||||
|
export const cryptoPathOrg2 = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'test-network',
|
||||||
|
'organizations',
|
||||||
|
'peerOrganizations',
|
||||||
|
'org2.example.com'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org2 user private key directory.
|
||||||
|
export const keyDirectoryPathOrg2 = path.resolve(
|
||||||
|
cryptoPathOrg2,
|
||||||
|
'users',
|
||||||
|
'User1@org2.example.com',
|
||||||
|
'msp',
|
||||||
|
'keystore'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org2 user certificate.
|
||||||
|
export const certPathOrg2 = path.resolve(
|
||||||
|
cryptoPathOrg2,
|
||||||
|
'users',
|
||||||
|
'User1@org2.example.com',
|
||||||
|
'msp',
|
||||||
|
'signcerts',
|
||||||
|
'cert.pem'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path to org2 peer tls certificate.
|
||||||
|
export const tlsCertPathOrg2 = path.resolve(
|
||||||
|
cryptoPathOrg2,
|
||||||
|
'peers',
|
||||||
|
'peer0.org2.example.com',
|
||||||
|
'tls',
|
||||||
|
'ca.crt'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Gateway peer endpoint.
|
||||||
|
export const peerEndpointOrg1 = 'localhost:7051';
|
||||||
|
export const peerEndpointOrg2 = 'localhost:9051';
|
||||||
|
|
||||||
|
// Gateway peer container name.
|
||||||
|
export const peerNameOrg1 = 'peer0.org1.example.com';
|
||||||
|
export const peerNameOrg2 = 'peer0.org2.example.com';
|
||||||
|
|
||||||
|
|
||||||
|
export async function newGrpcConnection(
|
||||||
|
tlsCertPath: string,
|
||||||
|
peerEndpoint: string,
|
||||||
|
peerName: string
|
||||||
|
): Promise<grpc.Client> {
|
||||||
|
const tlsRootCert = await fs.readFile(tlsCertPath);
|
||||||
|
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
||||||
|
return new grpc.Client(peerEndpoint, tlsCredentials, {
|
||||||
|
'grpc.ssl_target_name_override': peerName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function newIdentity(
|
||||||
|
certPath: string,
|
||||||
|
mspId: string
|
||||||
|
): Promise<Identity> {
|
||||||
|
const credentials = await fs.readFile(certPath);
|
||||||
|
return { mspId, credentials };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function newSigner(keyDirectoryPath: string): Promise<Signer> {
|
||||||
|
const files = await fs.readdir(keyDirectoryPath);
|
||||||
|
const keyPath = path.resolve(keyDirectoryPath, files[0]);
|
||||||
|
const privateKeyPem = await fs.readFile(keyPath);
|
||||||
|
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
||||||
|
return signers.newPrivateKeySigner(privateKey);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends":"@tsconfig/node14/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"noImplicitAny": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"./src/**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -32,3 +32,16 @@ print "Executing app.js"
|
||||||
node app.js
|
node app.js
|
||||||
popd
|
popd
|
||||||
stopNetwork
|
stopNetwork
|
||||||
|
|
||||||
|
|
||||||
|
# Run typescript gateway application
|
||||||
|
createNetwork
|
||||||
|
print "Initializing typescript application"
|
||||||
|
pushd ../asset-transfer-private-data/application-gateway-typescript
|
||||||
|
npm install
|
||||||
|
print "Build typescript app"
|
||||||
|
npm run build
|
||||||
|
print "Executing app.js"
|
||||||
|
npm start
|
||||||
|
popd
|
||||||
|
stopNetwork
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue