mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35: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
|
||||
popd
|
||||
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