mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-23 01:55:10 +00:00
adopted best practises
Signed-off-by: sapthasurendran <saptha.surendran@ibm.com>
This commit is contained in:
parent
2090a88157
commit
9d2f8f0579
4 changed files with 232 additions and 134 deletions
|
|
@ -4,16 +4,11 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { connect, Contract} from '@hyperledger/fabric-gateway';
|
import { connect } from '@hyperledger/fabric-gateway';
|
||||||
import { TextDecoder } from 'util';
|
|
||||||
import crpto from 'crypto';
|
import crpto from 'crypto';
|
||||||
import { newGrpcConnection,newIdentity,newSigner,tlsCertPathOrg1,peerEndpointOrg1,peerNameOrg1,certPathOrg1,mspIdOrg1,keyDirectoryPathOrg1,tlsCertPathOrg2,peerEndpointOrg2,peerNameOrg2,certPathOrg2,mspIdOrg2,keyDirectoryPathOrg2} from './connect'
|
import { newGrpcConnection, newIdentity, newSigner, tlsCertPathOrg1, peerEndpointOrg1, peerNameOrg1, certPathOrg1, mspIdOrg1, keyDirectoryPathOrg1, tlsCertPathOrg2, peerEndpointOrg2, peerNameOrg2, certPathOrg2, mspIdOrg2, keyDirectoryPathOrg2 } from './connect';
|
||||||
|
import { Asset, AssetPrice, AssetProperties, GREEN, RED, RESET } from './utils';
|
||||||
const utf8Decoder = new TextDecoder();
|
import { ContractWrapper } from './contractWrapper';
|
||||||
|
|
||||||
const RED = '\x1b[31m\n';
|
|
||||||
const GREEN = '\x1b[32m\n';
|
|
||||||
const RESET = '\x1b[0m';
|
|
||||||
|
|
||||||
const channelName = 'mychannel';
|
const channelName = 'mychannel';
|
||||||
const chaincodeName = 'secured';
|
const chaincodeName = 'secured';
|
||||||
|
|
@ -23,7 +18,7 @@ const now = Date.now();
|
||||||
const assetKey = `asset${now}`;
|
const assetKey = `asset${now}`;
|
||||||
|
|
||||||
//Generate random bytes using crypto
|
//Generate random bytes using crypto
|
||||||
const randomBytes = crpto.randomBytes(256).toString('hex')
|
const randomBytes = crpto.randomBytes(256).toString('hex');
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
|
|
||||||
|
|
@ -55,119 +50,122 @@ async function main(): Promise<void> {
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Get the smart contract from the network for Org1.
|
// Get the smart contract from the network for Org1.
|
||||||
const contractOrg1 = gatewayOrg1.getNetwork(channelName).getContract(chaincodeName);
|
const contractOrg1 = gatewayOrg1.getNetwork(channelName).getContract(chaincodeName);
|
||||||
|
const contractWrapperOrg1 = new ContractWrapper(contractOrg1);
|
||||||
|
|
||||||
// Get the smart contract from the network for Org2.
|
// Get the smart contract from the network for Org2.
|
||||||
const contractOrg2 = gatewayOrg2.getNetwork(channelName).getContract(chaincodeName);
|
const contractOrg2 = gatewayOrg2.getNetwork(channelName).getContract(chaincodeName);
|
||||||
|
const contractWrapperOrg2 = new ContractWrapper(contractOrg2);
|
||||||
|
|
||||||
// Create an asset by organization Org1, this only requires the owning organization to endorse.
|
// Create an asset by organization Org1, this only requires the owning organization to endorse.
|
||||||
await createAsset(contractOrg1,mspIdOrg1);
|
await createAsset(contractWrapperOrg1, mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2);
|
||||||
|
|
||||||
// Org1 should be able to read the private data details of the asset.
|
// Org1 should be able to read the private data details of the asset.
|
||||||
await readPrivateAsset(assetKey,mspIdOrg1,contractOrg1)
|
await readPrivateAsset(contractWrapperOrg1, assetKey, mspIdOrg1)
|
||||||
|
|
||||||
// Org2 is not the owner and does not have the private details, read expected to fail.
|
// Org2 is not the owner and does not have the private details, read expected to fail.
|
||||||
await readPrivateAsset(assetKey,mspIdOrg2,contractOrg2)
|
await readPrivateAsset(contractWrapperOrg2, assetKey, mspIdOrg2)
|
||||||
|
|
||||||
// Org1 updates the assets public description.
|
// Org1 updates the assets public description.
|
||||||
await changePublicDescription(assetKey,mspIdOrg1,`Asset ${assetKey} owned by ${mspIdOrg1} is for sale`,contractOrg1)
|
await changePublicDescription(contractWrapperOrg1, assetKey, mspIdOrg1, `Asset ${assetKey} owned by ${mspIdOrg1} is for sale`)
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1,mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1,mspIdOrg2);
|
||||||
|
|
||||||
// This is an update to the public state and requires the owner(Org1) to endorse and sent by the owner org client (Org1).
|
// 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
|
// Since the client is from Org2, which is not the owner, this will fail
|
||||||
await changePublicDescription(assetKey,mspIdOrg2,`Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`,contractOrg2);
|
await changePublicDescription(contractWrapperOrg2, assetKey, mspIdOrg2, `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`);
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2);
|
||||||
|
|
||||||
// Agree to a sell by org1.
|
// Agree to a sell by org1.
|
||||||
await agreeToSell(assetKey,mspIdOrg1,110,contractOrg1);
|
await agreeToSell(contractWrapperOrg1, assetKey, mspIdOrg1, 110);
|
||||||
|
|
||||||
// Check the private information about the asset from Org2. Org1 would have to send Org2 asset details,
|
// Check the private information about the asset from Org2. Org1 would have to send Org2 asset details,
|
||||||
// so the hash of the details may be checked by the chaincode.
|
// so the hash of the details may be checked by the chaincode.
|
||||||
await verifyAssetProperties(assetKey,mspIdOrg2,contractOrg2);
|
await verifyAssetProperties(contractWrapperOrg2, assetKey, mspIdOrg2);
|
||||||
|
|
||||||
// Agree to a buy by org2.
|
// Agree to a buy by org2.
|
||||||
await agreeToBuy(assetKey,mspIdOrg2,100,contractOrg2);
|
await agreeToBuy(contractWrapperOrg2, assetKey, mspIdOrg2, 100);
|
||||||
|
|
||||||
// Org1 should be able to read the sale price of this asset
|
// Org1 should be able to read the sale price of this asset
|
||||||
await readSalePrice(assetKey, mspIdOrg1, contractOrg1);
|
await readSalePrice(contractWrapperOrg1, assetKey, mspIdOrg1);
|
||||||
|
|
||||||
// Org2 has not set a sale price and this should fail
|
// Org2 has not set a sale price and this should fail
|
||||||
await readSalePrice(assetKey, mspIdOrg2, contractOrg2);
|
await readSalePrice(contractWrapperOrg2, assetKey, mspIdOrg2);
|
||||||
|
|
||||||
// Org1 has not agreed to buy so this should fail
|
// Org1 has not agreed to buy so this should fail
|
||||||
await readBidPrice(assetKey, mspIdOrg1, contractOrg1);
|
await readBidPrice(contractWrapperOrg1, assetKey, mspIdOrg1);
|
||||||
|
|
||||||
// Org2 should be able to see the price it has agreed
|
// Org2 should be able to see the price it has agreed
|
||||||
await readBidPrice(assetKey, mspIdOrg2, contractOrg2);
|
await readBidPrice(contractWrapperOrg2, assetKey, mspIdOrg2);
|
||||||
|
|
||||||
// Org1 will try to transfer the asset to Org2
|
// 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
|
// This will fail due to the sell price and the bid price are not the same
|
||||||
await transferAsset(assetKey, mspIdOrg1,mspIdOrg2, 110,contractOrg1);
|
await transferAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg2, 110);
|
||||||
|
|
||||||
// Agree to a sell by Org1,the seller will agree to the bid price of Org2
|
// Agree to a sell by Org1,the seller will agree to the bid price of Org2
|
||||||
await agreeToSell(assetKey,mspIdOrg1,100,contractOrg1);
|
await agreeToSell(contractWrapperOrg1, assetKey, mspIdOrg1, 100);
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1,mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg1, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2);
|
||||||
|
|
||||||
// Org1 should be able to read the private data details of the asset.
|
// Org1 should be able to read the private data details of the asset.
|
||||||
await readPrivateAsset(assetKey,mspIdOrg1,contractOrg1)
|
await readPrivateAsset(contractWrapperOrg1, assetKey, mspIdOrg1,)
|
||||||
|
|
||||||
// Org1 should be able to read the sale price of this asset
|
// Org1 should be able to read the sale price of this asset
|
||||||
await readSalePrice(assetKey, mspIdOrg1, contractOrg1);
|
await readSalePrice(contractWrapperOrg1, assetKey, mspIdOrg1);
|
||||||
|
|
||||||
// Org2 should be able to see the price it has agreed
|
// Org2 should be able to see the price it has agreed
|
||||||
await readBidPrice(assetKey, mspIdOrg2, contractOrg2);
|
await readBidPrice(contractWrapperOrg2, assetKey, mspIdOrg2);
|
||||||
|
|
||||||
// Org2 user will try to transfer the asset to Org1
|
// Org2 user will try to transfer the asset to Org1
|
||||||
// This will fail as the owner is Org1
|
// This will fail as the owner is Org1
|
||||||
await transferAsset(assetKey, mspIdOrg2,mspIdOrg2, 100,contractOrg2);
|
await transferAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2, 100);
|
||||||
|
|
||||||
// Org1 will transfer the asset to Org2
|
// Org1 will transfer the asset to Org2
|
||||||
// This will now complete as the sell price and the bid price are the same
|
// This will now complete as the sell price and the bid price are the same
|
||||||
await transferAsset(assetKey, mspIdOrg1,mspIdOrg2, 100, contractOrg1);
|
await transferAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg2, 100);
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg2, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg2, mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg2, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2);
|
||||||
|
|
||||||
// Org2 should be able to read the private data details of this asset
|
// Org2 should be able to read the private data details of this asset
|
||||||
await readPrivateAssetAfterTransfer(assetKey, mspIdOrg2, contractOrg2);
|
await readPrivateAssetAfterTransfer(contractWrapperOrg2, assetKey, mspIdOrg2);
|
||||||
|
|
||||||
// Org1 should not be able to read the private data details of this asset,expected to fail
|
// Org1 should not be able to read the private data details of this asset,expected to fail
|
||||||
await readPrivateAssetAfterTransfer(assetKey, mspIdOrg1, contractOrg1);
|
await readPrivateAssetAfterTransfer(contractWrapperOrg1, assetKey, mspIdOrg1);
|
||||||
|
|
||||||
// This is an update to the public state and requires only the owner to endorse.
|
// 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
|
// Org2 wants to indicate that the items is no longer for sale
|
||||||
await changePublicDescriptionAfterTransfer(assetKey,mspIdOrg2,`Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`,contractOrg2);
|
await changePublicDescriptionAfterTransfer(contractWrapperOrg2, assetKey, mspIdOrg2, `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`);
|
||||||
|
|
||||||
// Read the public details by org1.
|
// Read the public details by org1.
|
||||||
await readAsset(assetKey, mspIdOrg2, contractOrg1,mspIdOrg1);
|
await readAsset(contractWrapperOrg1, assetKey, mspIdOrg2, mspIdOrg1);
|
||||||
|
|
||||||
// Read the public details by org2.
|
// Read the public details by org2.
|
||||||
await readAsset(assetKey, mspIdOrg2, contractOrg2,mspIdOrg2);
|
await readAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
gatewayOrg1.close();
|
gatewayOrg1.close();
|
||||||
|
|
@ -182,53 +180,45 @@ main().catch(error => {
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
async function createAsset(contract:Contract,org:string):Promise<void> {
|
async function createAsset(contract:ContractWrapper, org:string):Promise<void> {
|
||||||
const asset_properties = {
|
|
||||||
object_type: 'asset_properties',
|
|
||||||
asset_id: assetKey,
|
|
||||||
color: 'blue',
|
|
||||||
size: 35,
|
|
||||||
salt: randomBytes
|
|
||||||
};
|
|
||||||
console.log(`${GREEN}--> Submit Transaction: CreateAsset, ${assetKey} as ${org} - endorsed by Org1${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: CreateAsset, ${assetKey} as ${org} - endorsed by Org1${RESET}`);
|
||||||
|
|
||||||
await contract.submit('CreateAsset', {
|
await contract.submit('CreateAsset', {
|
||||||
arguments:[assetKey,`Asset ${assetKey} owned by ${org} is not for sale`],
|
arguments: [assetKey,`Asset ${assetKey} owned by ${org} is not for sale`],
|
||||||
transientData: { asset_properties: JSON.stringify(asset_properties) },
|
transientData: { asset_properties: AssetProperties.instance('asset_properties', assetKey, 'blue', 35, randomBytes)},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`*** Result: committed, asset ${assetKey} is owned by Org1`);
|
console.log(`*** Result: committed, asset ${assetKey} is owned by Org1`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readAsset(assetKey:string, ownerOrg:string, contract:Contract,org:string):Promise<void> {
|
async function readAsset(contract:ContractWrapper, assetKey:string, ownerOrg:string, org:string):Promise<void> {
|
||||||
|
|
||||||
console.log(`${GREEN}--> Evaluate Transactions: ReadAsset as ${org}, - ${assetKey} should be owned by ${ownerOrg}${RESET}`);
|
console.log(`${GREEN}--> Evaluate Transactions: ReadAsset as ${org}, - ${assetKey} should be owned by ${ownerOrg}${RESET}`);
|
||||||
|
|
||||||
const resultBytes = await contract.evaluateTransaction('ReadAsset', assetKey);
|
const resultString = await contract.evaluateTransaction('ReadAsset', assetKey);
|
||||||
|
const result = Asset.parse(resultString);
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
|
||||||
if (resultString.length !== 0) {
|
if (resultString.length !== 0) {
|
||||||
|
|
||||||
const result:{ objectType: string, assetID: string, ownerOrg: string, publicDescription: string } = JSON.parse(resultString);
|
|
||||||
if (result?.ownerOrg === ownerOrg) {
|
if (result?.ownerOrg === ownerOrg) {
|
||||||
console.log(`*** Result from ${org} - asset ${result.assetID} owned by ${result.ownerOrg} DESC:${result.publicDescription}`);
|
console.log(`*** Result from ${org} - asset ${result.assetID} owned by ${result.ownerOrg} DESC:${result.publicDescription}`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`${RED}*** Failed owner check from ${org} - asset ${result.assetID} owned by ${result.ownerOrg} DESC:${result.publicDescription}${RESET}`);
|
console.log(`${RED}*** Failed owner check from ${org} - asset ${result.assetID} owned by ${result.ownerOrg} DESC:${result.publicDescription}${RESET}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
console.log(`${RED}*** Failed ReadAsset ${RESET}`);
|
console.log(`${RED}*** Failed ReadAsset ${RESET}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readPrivateAsset(assetKey:string, org:string, contract:Contract):Promise<void> {
|
async function readPrivateAsset(contract:ContractWrapper, assetKey:string, org:string):Promise<void> {
|
||||||
try{
|
try{
|
||||||
console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`);
|
console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`);
|
||||||
if(org === mspIdOrg2){
|
if(org === mspIdOrg2){
|
||||||
console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`)
|
console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`)
|
||||||
}
|
}
|
||||||
const resultBytes = await contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
|
const resultString = await contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
|
||||||
|
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
const result = Asset.parse(resultString);
|
||||||
const result = JSON.parse(resultString);
|
|
||||||
|
|
||||||
console.log('*** Result:', result);
|
console.log('*** Result:', result);
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +227,7 @@ async function readPrivateAsset(assetKey:string, org:string, contract:Contract):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changePublicDescription(assetKey:string, org:string, description:string,contract:Contract):Promise<void> {
|
async function changePublicDescription(contract:ContractWrapper, assetKey:string, org:string, description:string):Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`);
|
||||||
if(org===mspIdOrg2){
|
if(org===mspIdOrg2){
|
||||||
|
|
@ -254,18 +244,13 @@ async function changePublicDescription(assetKey:string, org:string, description:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function agreeToSell(assetKey:string, org:string, price:number,contract:Contract):Promise<void> {
|
async function agreeToSell(contract:ContractWrapper, assetKey:string, org:string, price:number):Promise<void> {
|
||||||
try {
|
try {
|
||||||
const asset_price = {
|
|
||||||
asset_id: assetKey,
|
|
||||||
price:price,
|
|
||||||
trade_id: now.toString()
|
|
||||||
};
|
|
||||||
console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
||||||
|
|
||||||
await contract.submit('AgreeToSell',{
|
await contract.submit('AgreeToSell',{
|
||||||
arguments:[assetKey],
|
arguments:[assetKey],
|
||||||
transientData: { asset_price: JSON.stringify(asset_price) }
|
transientData: { asset_price: AssetPrice.instance(assetKey, price, now.toString()) }
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`*** Result: committed, ${org} has agreed to sell asset ${assetKey} for ${price}`);
|
console.log(`*** Result: committed, ${org} has agreed to sell asset ${assetKey} for ${price}`);
|
||||||
|
|
@ -274,26 +259,17 @@ async function agreeToSell(assetKey:string, org:string, price:number,contract:Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verifyAssetProperties(assetKey:string, org:string, contract:Contract):Promise<void> {
|
async function verifyAssetProperties(contract:ContractWrapper, assetKey:string, org:string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const asset_properties = {
|
|
||||||
object_type: 'asset_properties',
|
|
||||||
asset_id: assetKey,
|
|
||||||
color: 'blue',
|
|
||||||
size: 35,
|
|
||||||
salt: randomBytes
|
|
||||||
};
|
|
||||||
console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
||||||
|
|
||||||
const resultBytes = await contract.evaluate('VerifyAssetProperties',{
|
const resultString = await contract.evaluate('VerifyAssetProperties',{
|
||||||
arguments:[assetKey],
|
arguments:[assetKey],
|
||||||
transientData: { asset_properties: JSON.stringify(asset_properties) },
|
transientData: { asset_properties: AssetProperties.instance('asset_properties', assetKey, 'blue', 35, randomBytes) },
|
||||||
});
|
});
|
||||||
|
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
if (resultString.length !== 0) {
|
||||||
|
const result = Asset.parse(resultString);
|
||||||
if (resultString.length !==0) {
|
|
||||||
const result = JSON.parse(resultString);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
console.log(`*** Success VerifyAssetProperties, private information about asset ${assetKey} has been verified by ${org}`);
|
console.log(`*** Success VerifyAssetProperties, private information about asset ${assetKey} has been verified by ${org}`);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -307,18 +283,13 @@ async function verifyAssetProperties(assetKey:string, org:string, contract:Contr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function agreeToBuy(assetKey:string, org:string, price:number, contract:Contract):Promise<void> {
|
async function agreeToBuy(contract:ContractWrapper, assetKey:string, org:string, price:number):Promise<void> {
|
||||||
try {
|
try {
|
||||||
const asset_price = {
|
|
||||||
asset_id: assetKey,
|
|
||||||
price:price,
|
|
||||||
trade_id: now.toString()
|
|
||||||
};
|
|
||||||
console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
||||||
|
|
||||||
await contract.submit('AgreeToBuy',{
|
await contract.submit('AgreeToBuy',{
|
||||||
arguments:[assetKey],
|
arguments:[assetKey],
|
||||||
transientData: { asset_price: JSON.stringify(asset_price) }
|
transientData: { asset_price: AssetPrice.instance(assetKey,price,now.toString()) }
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`*** Result: committed, ${org} has agreed to buy asset ${assetKey} for 100`);
|
console.log(`*** Result: committed, ${org} has agreed to buy asset ${assetKey} for 100`);
|
||||||
|
|
@ -327,34 +298,30 @@ async function agreeToBuy(assetKey:string, org:string, price:number, contract:Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readSalePrice(assetKey:string, org:string, contract:Contract):Promise<void> {
|
async function readSalePrice(contract:ContractWrapper, assetKey:string, org:string):Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${org}${RESET}`);
|
console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${org}${RESET}`);
|
||||||
if(org===mspIdOrg2){
|
if(org===mspIdOrg2){
|
||||||
console.log(`${GREEN}* Expected to fail as ${org} has not set a sale price${RESET}`)
|
console.log(`${GREEN}* Expected to fail as ${org} has not set a sale price${RESET}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resultBytes = await contract.evaluateTransaction('GetAssetSalesPrice', assetKey);
|
const resultString = await contract.evaluateTransaction('GetAssetSalesPrice', assetKey);
|
||||||
|
const result = Asset.parse(resultString);
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
|
||||||
const result = JSON.parse(resultString);
|
|
||||||
console.log('*** Result: GetAssetSalesPrice', result);
|
console.log('*** Result: GetAssetSalesPrice', result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`${RED}*** Failed evaluateTransaction GetAssetSalesPrice: ${e}${RESET}`);
|
console.log(`${RED}*** Failed evaluateTransaction GetAssetSalesPrice: ${e}${RESET}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readBidPrice(assetKey:string, org:string, contract:Contract):Promise<void> {
|
async function readBidPrice(contract:ContractWrapper, assetKey:string, org:string):Promise<void> {
|
||||||
try{
|
try{
|
||||||
console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${org}${RESET}`);
|
console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${org}${RESET}`);
|
||||||
if(org===mspIdOrg1){
|
if(org===mspIdOrg1){
|
||||||
console.log(`${GREEN}* Expected to fail as Org1 has not agreed to buy${RESET}`)
|
console.log(`${GREEN}* Expected to fail as Org1 has not agreed to buy${RESET}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resultBytes = await contract.evaluateTransaction('GetAssetBidPrice', assetKey);
|
const resultString = await contract.evaluateTransaction('GetAssetBidPrice', assetKey);
|
||||||
|
const result = Asset.parse(resultString);
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
|
||||||
const result = JSON.parse(resultString);
|
|
||||||
|
|
||||||
console.log('*** Result: GetAssetBidPrice', result);
|
console.log('*** Result: GetAssetBidPrice', result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -362,20 +329,8 @@ async function readBidPrice(assetKey:string, org:string, contract:Contract):Prom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function transferAsset(assetKey:string, org:string,buyerOrgID:string, price:number,contract:Contract):Promise<void> {
|
async function transferAsset(contract:ContractWrapper, assetKey:string, org:string,buyerOrgID:string, price:number):Promise<void> {
|
||||||
try{
|
try {
|
||||||
const asset_properties = {
|
|
||||||
object_type: 'asset_properties',
|
|
||||||
asset_id: assetKey,
|
|
||||||
color: 'blue',
|
|
||||||
size: 35,
|
|
||||||
salt: randomBytes
|
|
||||||
};
|
|
||||||
const asset_price = {
|
|
||||||
asset_id: assetKey,
|
|
||||||
price:price,
|
|
||||||
trade_id: now.toString()
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as ${org} - endorsed by ${org}${RESET}`);
|
||||||
if(org === mspIdOrg2){
|
if(org === mspIdOrg2){
|
||||||
|
|
@ -387,8 +342,8 @@ async function transferAsset(assetKey:string, org:string,buyerOrgID:string, pric
|
||||||
await contract.submit('TransferAsset', {
|
await contract.submit('TransferAsset', {
|
||||||
arguments:[assetKey,buyerOrgID],
|
arguments:[assetKey,buyerOrgID],
|
||||||
transientData: {
|
transientData: {
|
||||||
asset_properties: JSON.stringify(asset_properties),
|
asset_properties: AssetProperties.instance('asset_properties', assetKey, 'blue', 35, randomBytes),
|
||||||
asset_price: JSON.stringify(asset_price) },
|
asset_price: AssetPrice.instance(assetKey, price, now.toString()) },
|
||||||
endorsingOrganizations:[mspIdOrg1,mspIdOrg2]
|
endorsingOrganizations:[mspIdOrg1,mspIdOrg2]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -398,16 +353,14 @@ async function transferAsset(assetKey:string, org:string,buyerOrgID:string, pric
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readPrivateAssetAfterTransfer(assetKey:string, org:string, contract:Contract):Promise<void> {
|
async function readPrivateAssetAfterTransfer(contract:ContractWrapper, assetKey:string, org:string):Promise<void> {
|
||||||
try{
|
try{
|
||||||
console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`);
|
console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`);
|
||||||
if(org === mspIdOrg1){
|
if(org === mspIdOrg1){
|
||||||
console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`)
|
console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`)
|
||||||
}
|
}
|
||||||
const resultBytes = await contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
|
const resultString = await contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
|
||||||
|
const result = Asset.parse(resultString);
|
||||||
const resultString = utf8Decoder.decode(resultBytes);
|
|
||||||
const result = JSON.parse(resultString);
|
|
||||||
|
|
||||||
console.log('*** Result:', result);
|
console.log('*** Result:', result);
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +369,7 @@ async function readPrivateAssetAfterTransfer(assetKey:string, org:string, contra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changePublicDescriptionAfterTransfer(assetKey:string, org:string, description:string,contract:Contract):Promise<void> {
|
async function changePublicDescriptionAfterTransfer(contract:ContractWrapper, assetKey:string, org:string, description:string):Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`${GREEN}--> Submit Transaction: changePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`);
|
console.log(`${GREEN}--> Submit Transaction: changePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`);
|
||||||
if(org===mspIdOrg1){
|
if(org===mspIdOrg1){
|
||||||
|
|
@ -431,4 +384,4 @@ async function changePublicDescriptionAfterTransfer(assetKey:string, org:string,
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`${RED}*** Failed: changePublicDescription - ${e}${RESET}`);
|
console.log(`${RED}*** Failed: changePublicDescription - ${e}${RESET}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export const mspIdOrg1 = 'Org1MSP';
|
||||||
export const mspIdOrg2 = 'Org2MSP';
|
export const mspIdOrg2 = 'Org2MSP';
|
||||||
|
|
||||||
// Path to org1 crypto materials.
|
// Path to org1 crypto materials.
|
||||||
export const cryptoPathOrg1 = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com');
|
export const cryptoPathOrg1 = path.resolve(__dirname, '..', '..', '..', '../../sample-2.4.3/fabric-samples/test-network', 'organizations', 'peerOrganizations', 'org1.example.com');
|
||||||
|
|
||||||
// Path to user private key directory.
|
// Path to user private key directory.
|
||||||
export const keyDirectoryPathOrg1 = path.resolve(cryptoPathOrg1, 'users', 'User1@org1.example.com', 'msp', 'keystore');
|
export const keyDirectoryPathOrg1 = path.resolve(cryptoPathOrg1, 'users', 'User1@org1.example.com', 'msp', 'keystore');
|
||||||
|
|
@ -32,7 +32,7 @@ export const cryptoPathOrg2 = path.resolve(
|
||||||
'..',
|
'..',
|
||||||
'..',
|
'..',
|
||||||
'..',
|
'..',
|
||||||
'test-network',
|
'../../sample-2.4.3/fabric-samples/test-network',
|
||||||
'organizations',
|
'organizations',
|
||||||
'peerOrganizations',
|
'peerOrganizations',
|
||||||
'org2.example.com'
|
'org2.example.com'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
import { Contract, ProposalOptions } from '@hyperledger/fabric-gateway';
|
||||||
|
import { TextDecoder } from 'util';
|
||||||
|
|
||||||
|
export class ContractWrapper {
|
||||||
|
|
||||||
|
contract?: Contract;
|
||||||
|
utf8Decoder: TextDecoder = new TextDecoder();
|
||||||
|
|
||||||
|
public constructor(contract:Contract) {
|
||||||
|
this.contract = contract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async submit(transactionName:string, options: ProposalOptions ) {
|
||||||
|
await this.contract?.submit(transactionName, options);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async evaluate(transactionName:string, options: ProposalOptions): Promise<string> {
|
||||||
|
const resultBytes = await this.contract?.evaluate(transactionName, options);
|
||||||
|
const result = this.utf8Decoder.decode(resultBytes);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async evaluateTransaction(transactionName:string, ...args: (string | Uint8Array)[]): Promise<string> {
|
||||||
|
const resultBytes = await this.contract?.evaluateTransaction(transactionName, ...args);
|
||||||
|
return this.utf8Decoder.decode(resultBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const RED = '\x1b[31m\n';
|
||||||
|
export const GREEN = '\x1b[32m\n';
|
||||||
|
export const RESET = '\x1b[0m';
|
||||||
|
|
||||||
|
export interface asset {
|
||||||
|
objectType: string,
|
||||||
|
assetID: string,
|
||||||
|
ownerOrg: string,
|
||||||
|
publicDescription: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface asset_properties {
|
||||||
|
object_type: string,
|
||||||
|
asset_id: string,
|
||||||
|
color: string,
|
||||||
|
size: number,
|
||||||
|
salt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface asset_price {
|
||||||
|
asset_id: string,
|
||||||
|
price: number,
|
||||||
|
trade_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface asset_price {
|
||||||
|
asset_id: string,
|
||||||
|
price: number,
|
||||||
|
trade_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AssetProperties {
|
||||||
|
|
||||||
|
asset_properties: asset_properties;
|
||||||
|
|
||||||
|
private constructor (asset_properties: asset_properties) {
|
||||||
|
this.asset_properties = asset_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static instance(object_type: string, asset_id: string, color: string, size: number, salt: string): string {
|
||||||
|
const asset_properties : asset_properties = {
|
||||||
|
object_type,
|
||||||
|
asset_id,
|
||||||
|
color,
|
||||||
|
size,
|
||||||
|
salt,
|
||||||
|
};
|
||||||
|
return new AssetProperties(asset_properties).serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private serialize(): string {
|
||||||
|
return JSON.stringify(this.asset_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Asset {
|
||||||
|
|
||||||
|
asset: asset;
|
||||||
|
|
||||||
|
private constructor (asset: asset) {
|
||||||
|
this.asset = asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static instance( objectType: string, assetID: string, ownerOrg: string, publicDescription: string): string {
|
||||||
|
const asset = {
|
||||||
|
objectType,
|
||||||
|
assetID,
|
||||||
|
ownerOrg,
|
||||||
|
publicDescription
|
||||||
|
}
|
||||||
|
return new Asset(asset).serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private serialize(): string {
|
||||||
|
return JSON.stringify(this.asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse(asset: string): asset {
|
||||||
|
return JSON.parse(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AssetPrice {
|
||||||
|
|
||||||
|
asset_price: asset_price;
|
||||||
|
|
||||||
|
constructor (asset_price : asset_price) {
|
||||||
|
this.asset_price = asset_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
static instance(asset_id: string, price:number, trade_id: string): string {
|
||||||
|
const asset_price = {
|
||||||
|
asset_id,
|
||||||
|
price,
|
||||||
|
trade_id
|
||||||
|
}
|
||||||
|
return new AssetPrice(asset_price).serialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
private serialize(): string {
|
||||||
|
return JSON.stringify(this.asset_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue