mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 07:25:10 +00:00
Signed-off-by: Varun Agarwal <varunagarwal315@gmail.com> Change-Id: Idb6c57e047bba9a176b312f86d05c2ee21aeb175
216 lines
7.6 KiB
JavaScript
216 lines
7.6 KiB
JavaScript
/*
|
|
* Copyright IBM Corp. All Rights Reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const couchdbutil = require('./couchdbutil.js');
|
|
|
|
const configPath = path.resolve(__dirname, 'nextblock.txt');
|
|
|
|
exports.processBlockEvent = async function (channelname, block, use_couchdb, nano) {
|
|
|
|
return new Promise((async (resolve, reject) => {
|
|
|
|
// reject the block if the block number is not defined
|
|
if (block.header.number == undefined) {
|
|
reject(new Error('Undefined block number'));
|
|
}
|
|
|
|
const blockNumber = block.header.number
|
|
|
|
console.log(`------------------------------------------------`);
|
|
console.log(`Block Number: ${blockNumber}`);
|
|
|
|
// reject if the data is not set
|
|
if (block.data.data == undefined) {
|
|
reject(new Error('Data block is not defined'));
|
|
}
|
|
|
|
const dataArray = block.data.data;
|
|
|
|
// transaction filter for each transaction in dataArray
|
|
const txSuccess = block.metadata.metadata[2];
|
|
|
|
for (var dataItem in dataArray) {
|
|
|
|
// reject if a timestamp is not set
|
|
if (dataArray[dataItem].payload.header.channel_header.timestamp == undefined) {
|
|
reject(new Error('Transaction timestamp is not defined'));
|
|
}
|
|
|
|
// tx may be rejected at commit stage by peers
|
|
// only valid transactions (code=0) update the word state and off-chain db
|
|
// filter through valid tx, refer below for list of error codes
|
|
// https://github.com/hyperledger/fabric-sdk-node/blob/release-1.4/fabric-client/lib/protos/peer/transaction.proto
|
|
if (txSuccess[dataItem] !== 0) {
|
|
continue();
|
|
}
|
|
|
|
const timestamp = dataArray[dataItem].payload.header.channel_header.timestamp;
|
|
|
|
// continue to next tx if no actions are set
|
|
if (dataArray[dataItem].payload.data.actions == undefined) {
|
|
continue();
|
|
}
|
|
|
|
// actions are stored as an array. In Fabric 1.4.3 only one
|
|
// action exists per tx so we may simply use actions[0]
|
|
// in case Fabric adds support for multiple actions
|
|
// a for loop is used for demonstration
|
|
const actions = dataArray[dataItem].payload.data.actions;
|
|
|
|
// iterate through all actions
|
|
for (var actionItem in actions) {
|
|
|
|
// reject if a chaincode id is not defined
|
|
if (actions[actionItem].payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name == undefined) {
|
|
reject(new Error('Chaincode name is not defined'));
|
|
}
|
|
|
|
const chaincodeID = actions[actionItem].payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name
|
|
|
|
// reject if there is no readwrite set
|
|
if (actions[actionItem].payload.action.proposal_response_payload.extension.results.ns_rwset == undefined) {
|
|
reject(new Error('No readwrite set is defined'));
|
|
}
|
|
|
|
const rwSet = actions[actionItem].payload.action.proposal_response_payload.extension.results.ns_rwset
|
|
|
|
for (var record in rwSet) {
|
|
|
|
// ignore lscc events
|
|
if (rwSet[record].namespace != 'lscc') {
|
|
// create object to store properties
|
|
const writeObject = new Object();
|
|
writeObject.blocknumber = blockNumber;
|
|
writeObject.chaincodeid = chaincodeID;
|
|
writeObject.timestamp = timestamp;
|
|
writeObject.values = rwSet[record].rwset.writes;
|
|
|
|
console.log(`Transaction Timestamp: ${writeObject.timestamp}`);
|
|
console.log(`ChaincodeID: ${writeObject.chaincodeid}`);
|
|
console.log(writeObject.values);
|
|
|
|
const logfilePath = path.resolve(__dirname, 'nextblock.txt');
|
|
|
|
// send the object to a log file
|
|
fs.appendFileSync(channelname + '_' + chaincodeID + '.log', JSON.stringify(writeObject) + "\n");
|
|
|
|
// if couchdb is configured, then write to couchdb
|
|
if (use_couchdb) {
|
|
try {
|
|
await writeValuesToCouchDBP(nano, channelname, writeObject);
|
|
} catch (error) {
|
|
|
|
}
|
|
}
|
|
}
|
|
};
|
|
};
|
|
};
|
|
|
|
// update the nextblock.txt file to retrieve the next block
|
|
fs.writeFileSync(configPath, parseInt(blockNumber, 10) + 1)
|
|
|
|
resolve(true);
|
|
|
|
}));
|
|
}
|
|
|
|
async function writeValuesToCouchDBP(nano, channelname, writeObject) {
|
|
|
|
return new Promise((async (resolve, reject) => {
|
|
|
|
try {
|
|
|
|
// define the database for saving block events by key - this emulates world state
|
|
const dbname = channelname + '_' + writeObject.chaincodeid;
|
|
// define the database for saving all block events - this emulates history
|
|
const historydbname = channelname + '_' + writeObject.chaincodeid + '_history';
|
|
// set values to the array of values received
|
|
const values = writeObject.values;
|
|
|
|
try {
|
|
for (var sequence in values) {
|
|
let keyvalue =
|
|
values[
|
|
sequence
|
|
];
|
|
|
|
if (
|
|
keyvalue.is_delete ==
|
|
true
|
|
) {
|
|
await couchdbutil.deleteRecord(
|
|
nano,
|
|
dbname,
|
|
keyvalue.key
|
|
);
|
|
} else {
|
|
if (
|
|
isJSON(
|
|
keyvalue.value
|
|
)
|
|
) {
|
|
// insert or update value by key - this emulates world state behavior
|
|
await couchdbutil.writeToCouchDB(
|
|
nano,
|
|
dbname,
|
|
keyvalue.key,
|
|
JSON.parse(
|
|
keyvalue.value
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
// add additional fields for history
|
|
keyvalue.timestamp =
|
|
writeObject.timestamp;
|
|
keyvalue.blocknumber = parseInt(
|
|
writeObject.blocknumber,
|
|
10
|
|
);
|
|
keyvalue.sequence = parseInt(
|
|
sequence,
|
|
10
|
|
);
|
|
|
|
await couchdbutil.writeToCouchDB(
|
|
nano,
|
|
historydbname,
|
|
null,
|
|
keyvalue
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.log(error);
|
|
reject(error);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`Failed to write to couchdb: ${error}`);
|
|
reject(error);
|
|
}
|
|
|
|
resolve(true);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
function isJSON(value) {
|
|
try {
|
|
JSON.parse(value);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|