diff --git a/asset-transfer-events/application-gateway-typescript/.eslintrc.json b/asset-transfer-events/application-gateway-typescript/.eslintrc.json index cc7230a8..fabcde92 100644 --- a/asset-transfer-events/application-gateway-typescript/.eslintrc.json +++ b/asset-transfer-events/application-gateway-typescript/.eslintrc.json @@ -1,7 +1,7 @@ { "env": { "node": true, - "es6": true + "es2020": true }, "root": true, "ignorePatterns": [ @@ -30,15 +30,16 @@ "sourceType": "module", "ecmaFeatures": { "impliedStrict": true - } + }, + "project": "./tsconfig.json" }, "plugins": [ "@typescript-eslint" ], "extends": [ "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" ] } ] diff --git a/asset-transfer-events/application-gateway-typescript/package.json b/asset-transfer-events/application-gateway-typescript/package.json index c766be23..d0421b9b 100755 --- a/asset-transfer-events/application-gateway-typescript/package.json +++ b/asset-transfer-events/application-gateway-typescript/package.json @@ -1,7 +1,7 @@ { - "name": "asset-transfer-basic", + "name": "asset-transfer-events", "version": "1.0.0", - "description": "Asset Transfer Basic Application implemented in typeScript using fabric-gateway", + "description": "Asset Transfer Events Application implemented in typeScript using fabric-gateway", "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { diff --git a/asset-transfer-events/application-gateway-typescript/src/app.ts b/asset-transfer-events/application-gateway-typescript/src/app.ts index 36128004..ee48b3fc 100755 --- a/asset-transfer-events/application-gateway-typescript/src/app.ts +++ b/asset-transfer-events/application-gateway-typescript/src/app.ts @@ -7,7 +7,6 @@ import * as grpc from '@grpc/grpc-js'; import { ChaincodeEvent, CloseableAsyncIterable, connect, Contract, GatewayError, Network } from '@hyperledger/fabric-gateway'; import { TextDecoder } from 'util'; - import { newGrpcConnection, newIdentity, newSigner } from './connect'; const channelName = 'mychannel'; @@ -19,9 +18,7 @@ const assetId = `asset${now}`; async function main(): Promise { - // The gRPC client connection should be shared by all Gateway connections to this endpoint. const client = await newGrpcConnection(); - const gateway = connect({ client, identity: await newIdentity(), @@ -43,30 +40,19 @@ async function main(): Promise { let events: CloseableAsyncIterable | undefined; try { - // Get a network instance representing the channel where the smart contract is deployed. const network = gateway.getNetwork(channelName); - - // Get the smart contract from the network. const contract = network.getContract(chaincodeName); - //Start Listening to events. + // Listen for events emitted by subsequent transactions events = await startEventListening(network); - // Create a new asset on the ledger. const firstBlockNumber = await createAsset(contract); - - // Update an existing asset. - await updateAsset(contract) - - // Transfer an existing asset. + await updateAsset(contract); await transferAsset(contract); - - // Delete asset by assetID. await deleteAssetByID(contract); - // Replay all the events received. - await replayChaincodeEvents(network,firstBlockNumber) - + // Replay events from the block containing the first transaction + await replayChaincodeEvents(network,firstBlockNumber); } finally { events?.close(); gateway.close(); @@ -79,106 +65,91 @@ main().catch(error => { process.exitCode = 1; }); -/** - * Start listening to events. - */ async function startEventListening(network: Network): Promise> { - console.log('\n*** Start chaincode event listening\n'); + console.log('\n*** Start chaincode event listening'); const events = await network.getChaincodeEvents(chaincodeName); - readEvents(events); + void readEvents(events); // Don't await - run asynchronously return events; } -/** - * Read events. - */ async function readEvents(events: CloseableAsyncIterable): Promise { try { for await (const event of events) { - const payload = utf8Decoder.decode(event.payload); - console.log(`\n<-- Chaincode event received, name: ${event.eventName}, payload: ${payload}, txID: ${event.transactionId}, blockNumber:${event.blockNumber}`); + const payload = parseJson(event.payload); + console.log(`\n<-- Chaincode event received: ${event.eventName} -`, payload); } } catch (error: unknown) { + // Ignore the read error when events.close() is called explicitly if (!(error instanceof GatewayError) || error.code !== grpc.status.CANCELLED) { throw error; } } } -/** - * Submit a transaction asynchronously to create a new asset. - */ -async function createAsset(contract: Contract): Promise { - console.log(`\n --> Submit Transaction: CreateAsset, creates ${assetId} owned by Tom with appraised value 100`); +function parseJson(jsonBytes: Uint8Array): unknown { + const json = utf8Decoder.decode(jsonBytes); + return JSON.parse(json); +} - const result = await contract.submitAsync('CreateAsset', - {arguments: [assetId,'yellow','5','Tom','100',]}); +async function createAsset(contract: Contract): Promise { + console.log(`\n--> Submit Transaction: CreateAsset, ${assetId} owned by Sam with appraised value 100`); + + const result = await contract.submitAsync('CreateAsset', { + arguments: [ assetId, 'blue', '10', 'Sam', '100' ], + }); const status = await result.getStatus(); if (!status.successful) { throw new Error(`failed to commit transaction ${status.transactionId} with status code ${status.code}`); } - console.log('\n*** CreateAsset committed successfully\n') + console.log('\n*** CreateAsset committed successfully'); return status.blockNumber; } -/** - * Submit transaction synchronously, to updateAsset the asset appraised value. - */ + async function updateAsset(contract: Contract): Promise { console.log(`\n--> Submit transaction: UpdateAsset, ${assetId} update appraised value to 200`); - await contract.submitTransaction('UpdateAsset', - assetId,'yellow','5','Tom','200',); + await contract.submitTransaction('UpdateAsset', assetId, 'blue', '10', 'Sam', '200'); - console.log('\n*** UpdateAsset committed successfully\n') + console.log('\n*** UpdateAsset committed successfully'); } -/** - * Submit transaction synchronously, to transfer the asset. - */ async function transferAsset(contract: Contract): Promise { - console.log(`\n--> Submit transaction: TransferAsset, ${assetId} to Saptha\n`); + console.log(`\n--> Submit transaction: TransferAsset, ${assetId} to Mary`); - await contract.submitTransaction('TransferAsset', - assetId, 'Saptha',); + await contract.submitTransaction('TransferAsset', assetId, 'Mary'); - console.log('\n*** TransferAsset committed successfully\n') + console.log('\n*** TransferAsset committed successfully'); } -/** - * Submit a transaction synchronously to delete an asset by ID. - */ -async function deleteAssetByID(contract:Contract): Promise{ - console.log(`\n--> Submit transaction: DeleteAsset ${assetId}`); +async function deleteAssetByID(contract: Contract): Promise{ + console.log(`\n--> Submit transaction: DeleteAsset, ${assetId}`); - await contract.submitTransaction('DeleteAsset', - assetId - ); + await contract.submitTransaction('DeleteAsset', assetId); - console.log('\n*** DeleteAsset committed successfully\n') + console.log('\n*** DeleteAsset committed successfully'); } -/** - * Replay all the events from the start block. - */ -async function replayChaincodeEvents(network:Network,startBlock:bigint):Promise{ +async function replayChaincodeEvents(network: Network, startBlock: bigint): Promise{ const events = await network.getChaincodeEvents(chaincodeName, { - startBlock + startBlock, }); + try { for await (const event of events) { - const payload = utf8Decoder.decode(event.payload); - console.log(`<-- Chaincode event replayed: ${event.eventName}, payload: ${payload}`); - if(event.eventName === 'DeleteAsset'){ - break + const payload = parseJson(event.payload); + console.log(`\n<-- Chaincode event replayed: ${event.eventName} -`, payload); + + if (event.eventName === 'DeleteAsset') { + break; } } - }finally { - events.close() + } finally { + events.close(); } -} \ No newline at end of file +}