mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-26 03:25:09 +00:00
customize off chain data: use custom listener as docker container
This commit is contained in:
parent
c02c49be55
commit
dbabd42c9e
27 changed files with 5089 additions and 0 deletions
4
off_chain_data/addMarbles.json
Normal file
4
off_chain_data/addMarbles.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"nextMarbleNumber": 120,
|
||||
"numberMarblesToAdd": 20
|
||||
}
|
||||
87
off_chain_data/addMarbles2.js
Normal file
87
off_chain_data/addMarbles2.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* addMarbles.js will add random sample data to blockchain.
|
||||
*
|
||||
* $ node addMarbles.js
|
||||
*
|
||||
* addMarbles will add 10 marbles by default with a starting marble name of "marble100".
|
||||
* Additional marbles will be added by incrementing the number at the end of the marble name.
|
||||
*
|
||||
* The properties for adding marbles are stored in addMarbles.json. This file will be created
|
||||
* during the first execution of the utility if it does not exist. The utility can be run
|
||||
* multiple times without changing the properties. The nextMarbleNumber will be incremented and
|
||||
* stored in the JSON file.
|
||||
*
|
||||
* {
|
||||
* "nextMarbleNumber": 100,
|
||||
* "numberMarblesToAdd": 10
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const addMarblesConfigFile = path.resolve(__dirname, 'addMarbles.json');
|
||||
|
||||
const colors=[ 'blue', 'red', 'yellow', 'green', 'white', 'purple' ];
|
||||
const owners=[ 'tom', 'fred', 'julie', 'james', 'janet', 'henry', 'alice', 'marie', 'sam', 'debra', 'nancy'];
|
||||
const sizes=[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ];
|
||||
const docType='marble'
|
||||
|
||||
const config = require('./config.json');
|
||||
const channelid = config.channelid;
|
||||
|
||||
async function main() {
|
||||
|
||||
try {
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Configure a wallet. This wallet must already be primed with an identity that
|
||||
// the application can use to interact with the peer node.
|
||||
const walletPath = path.resolve(__dirname, 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
|
||||
// Create a new gateway, and connect to the gateway peer node(s). The identity
|
||||
// specified must already exist in the specified wallet.
|
||||
const gateway = new Gateway();
|
||||
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
|
||||
|
||||
// Get the network channel that the smart contract is deployed to.
|
||||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('marbles');
|
||||
|
||||
var randomColor = Math.floor(Math.random() * (6));
|
||||
var randomOwner = Math.floor(Math.random() * (11));
|
||||
var randomSize = Math.floor(Math.random() * (10));
|
||||
|
||||
// Submit the 'initMarble' transaction to the smart contract, and wait for it
|
||||
// to be committed to the ledger.
|
||||
var counter = Math.floor(Math.random() * (10000));
|
||||
await contract.submitTransaction('initMarble', docType+counter, colors[randomColor], ''+sizes[randomSize], owners[randomOwner]);
|
||||
console.log("Adding marble: " + docType + counter + " owner:" + owners[randomOwner] + " color:" + colors[randomColor] + " size:" + '' + sizes[randomSize] );
|
||||
|
||||
await gateway.disconnect();
|
||||
} catch (error) {
|
||||
console.error(`Failed to submit transaction: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
55
off_chain_data/enrollAdmin.tmp.js
Normal file
55
off_chain_data/enrollAdmin.tmp.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const FabricCAServices = require('fabric-ca-client');
|
||||
const { Wallets, X509WalletMixin } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// load the network configuration
|
||||
const ccpPath = path.resolve(__dirname, 'files', 'connection-org1.json');
|
||||
let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Create a new CA client for interacting with the CA.
|
||||
const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
|
||||
const ca = new FabricCAServices(caURL);
|
||||
|
||||
// Create a new file system based wallet for managing identities.
|
||||
const walletPath = path.join(process.cwd(), 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
console.log(`Wallet path: ${walletPath}`);
|
||||
|
||||
// Check to see if we've already enrolled the admin user.
|
||||
const adminExists = await wallet.get('admin');
|
||||
if (adminExists) {
|
||||
console.log('An identity for the admin user "admin" already exists in the wallet');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enroll the admin user, and import the new identity into the wallet.
|
||||
const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
|
||||
const x509Identity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
privateKey: enrollment.key.toBytes(),
|
||||
},
|
||||
mspId: 'Org1MSP',
|
||||
type: 'X.509',
|
||||
};
|
||||
await wallet.put('admin', x509Identity);
|
||||
console.log('Successfully enrolled admin user "admin" and imported it into the wallet');
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to enroll admin user "admin": ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
11
off_chain_data/listener/Dockerfile
Normal file
11
off_chain_data/listener/Dockerfile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
FROM node:8.17.0
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["node", "blockEventListener.js"]
|
||||
87
off_chain_data/listener/addMarbles.js
Normal file
87
off_chain_data/listener/addMarbles.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* addMarbles.js will add random sample data to blockchain.
|
||||
*
|
||||
* $ node addMarbles.js
|
||||
*
|
||||
* addMarbles will add 10 marbles by default with a starting marble name of "marble100".
|
||||
* Additional marbles will be added by incrementing the number at the end of the marble name.
|
||||
*
|
||||
* The properties for adding marbles are stored in addMarbles.json. This file will be created
|
||||
* during the first execution of the utility if it does not exist. The utility can be run
|
||||
* multiple times without changing the properties. The nextMarbleNumber will be incremented and
|
||||
* stored in the JSON file.
|
||||
*
|
||||
* {
|
||||
* "nextMarbleNumber": 100,
|
||||
* "numberMarblesToAdd": 10
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const addMarblesConfigFile = path.resolve(__dirname, 'addMarbles.json');
|
||||
|
||||
const colors=[ 'blue', 'red', 'yellow', 'green', 'white', 'purple' ];
|
||||
const owners=[ 'tom', 'fred', 'julie', 'james', 'janet', 'henry', 'alice', 'marie', 'sam', 'debra', 'nancy'];
|
||||
const sizes=[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ];
|
||||
const docType='marble'
|
||||
|
||||
const config = require('./config.json');
|
||||
const channelid = config.channelid;
|
||||
|
||||
async function main() {
|
||||
|
||||
try {
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Configure a wallet. This wallet must already be primed with an identity that
|
||||
// the application can use to interact with the peer node.
|
||||
const walletPath = path.resolve(__dirname, 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
|
||||
// Create a new gateway, and connect to the gateway peer node(s). The identity
|
||||
// specified must already exist in the specified wallet.
|
||||
const gateway = new Gateway();
|
||||
await gateway.connect(ccp, { wallet, identity: 'listenerUser', discovery: { enabled: true, asLocalhost: true } });
|
||||
|
||||
// Get the network channel that the smart contract is deployed to.
|
||||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('marbles');
|
||||
|
||||
var randomColor = Math.floor(Math.random() * (6));
|
||||
var randomOwner = Math.floor(Math.random() * (11));
|
||||
var randomSize = Math.floor(Math.random() * (10));
|
||||
|
||||
// Submit the 'initMarble' transaction to the smart contract, and wait for it
|
||||
// to be committed to the ledger.
|
||||
var counter = Math.floor(Math.random() * (10000));
|
||||
await contract.submitTransaction('initMarble', docType+counter, colors[randomColor], ''+sizes[randomSize], owners[randomOwner]);
|
||||
console.log("Adding marble: " + docType + counter + " owner:" + owners[randomOwner] + " color:" + colors[randomColor] + " size:" + '' + sizes[randomSize] );
|
||||
|
||||
await gateway.disconnect();
|
||||
} catch (error) {
|
||||
console.error(`Failed to submit transaction: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
183
off_chain_data/listener/blockEventListener.js
Normal file
183
off_chain_data/listener/blockEventListener.js
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
blockEventListener.js is an nodejs application to listen for block events from
|
||||
a specified channel.
|
||||
|
||||
Configuration is stored in config.json:
|
||||
|
||||
{
|
||||
"peer_name": "peer0.org1.example.com",
|
||||
"channelid": "mychannel",
|
||||
"use_couchdb":false,
|
||||
"couchdb_address": "http://admin:adminpw@localhost:5990"
|
||||
}
|
||||
|
||||
peer_name: target peer for the listener
|
||||
channelid: channel name for block events
|
||||
use_couchdb: if set to true, events will be stored in a local couchdb
|
||||
couchdb_address: local address for an off chain couchdb database
|
||||
|
||||
Note: If use_couchdb is set to false, only a local log of events will be stored.
|
||||
|
||||
Usage:
|
||||
|
||||
node bockEventListener.js
|
||||
|
||||
The block event listener will log events received to the console and write event blocks to
|
||||
a log file based on the channelid and chaincode name.
|
||||
|
||||
The event listener stores the next block to retrieve in a file named nextblock.txt. This file
|
||||
is automatically created and initialized to zero if it does not exist.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const couchdbutil = require('./couchdbutil.js');
|
||||
const blockProcessing = require('./blockProcessing.js');
|
||||
|
||||
const config = require('./config.json');
|
||||
const channelid = config.channelid;
|
||||
const peer_name = config.peer_name;
|
||||
const use_couchdb = config.use_couchdb;
|
||||
const couchdb_address = config.couchdb_address;
|
||||
|
||||
const configPath = path.resolve(__dirname, 'nextblock.txt');
|
||||
|
||||
const nano = require('nano')(couchdb_address);
|
||||
|
||||
// simple map to hold blocks for processing
|
||||
class BlockMap {
|
||||
constructor() {
|
||||
this.list = []
|
||||
}
|
||||
get(key) {
|
||||
key = parseInt(key, 10).toString();
|
||||
return this.list[`block${key}`];
|
||||
}
|
||||
set(key, value) {
|
||||
this.list[`block${key}`] = value;
|
||||
}
|
||||
remove(key) {
|
||||
key = parseInt(key, 10).toString();
|
||||
delete this.list[`block${key}`];
|
||||
}
|
||||
}
|
||||
|
||||
let ProcessingMap = new BlockMap()
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
|
||||
// initialize the next block to be 0
|
||||
let nextBlock = 0;
|
||||
|
||||
// check to see if there is a next block already defined
|
||||
if (fs.existsSync(configPath)) {
|
||||
// read file containing the next block to read
|
||||
nextBlock = fs.readFileSync(configPath, 'utf8');
|
||||
} else {
|
||||
// store the next block as 0
|
||||
fs.writeFileSync(configPath, parseInt(nextBlock, 10))
|
||||
}
|
||||
|
||||
// Create a new file system based wallet for managing identities.
|
||||
const walletPath = path.join(process.cwd(), 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
console.log(`Wallet path: ${walletPath}`);
|
||||
|
||||
// Check to see if we've already enrolled the user.
|
||||
const userExists = await wallet.get('listenerUser');
|
||||
if (!userExists) {
|
||||
console.log('An identity for the user "listenerUser" does not exist in the wallet');
|
||||
console.log('Run the enrollUser.js application before retrying');
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
const ccpPath = path.resolve(__dirname, 'files', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
// Create a new gateway for connecting to our peer node.
|
||||
const gateway = new Gateway();
|
||||
await gateway.connect(ccp, { wallet, identity: 'listenerUser', discovery: { enabled: true, asLocalhost: false } });
|
||||
|
||||
// Get the network (channel) our contract is deployed to.
|
||||
const network = await gateway.getNetwork('mychannel');
|
||||
|
||||
const listener = await network.addBlockListener(
|
||||
async (event) => {
|
||||
// Add the block to the processing map by block number
|
||||
const blockNum = event.blockNumber.low;
|
||||
const block = event.blockData;
|
||||
await ProcessingMap.set(block.header.number, block);
|
||||
|
||||
console.log(`Added block ${blockNum} to ProcessingMap`)
|
||||
},
|
||||
// set the starting block for the listener
|
||||
{ filtered: false, startBlock: parseInt(nextBlock, 10) }
|
||||
);
|
||||
|
||||
console.log(`Listening for block events, nextblock: ${nextBlock}`);
|
||||
|
||||
// start processing, looking for entries in the ProcessingMap
|
||||
processPendingBlocks(ProcessingMap);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to evaluate transaction: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// listener function to check for blocks in the ProcessingMap
|
||||
async function processPendingBlocks(ProcessingMap) {
|
||||
setTimeout(async () => {
|
||||
|
||||
// get the next block number from nextblock.txt
|
||||
let nextBlockNumber = fs.readFileSync(configPath, 'utf8');
|
||||
let processBlock;
|
||||
|
||||
do {
|
||||
|
||||
// get the next block to process from the ProcessingMap
|
||||
processBlock = ProcessingMap.get(nextBlockNumber)
|
||||
if (processBlock == undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
console.log("call block processing event")
|
||||
try {
|
||||
await blockProcessing.processBlockEvent(channelid, processBlock, use_couchdb, nano)
|
||||
} catch (error) {
|
||||
console.error(`Failed to process block: ${error}`);
|
||||
}
|
||||
|
||||
// if successful, remove the block from the ProcessingMap
|
||||
ProcessingMap.remove(nextBlockNumber);
|
||||
|
||||
// increment the next block number to the next block
|
||||
fs.writeFileSync(configPath, parseInt(nextBlockNumber, 10) + 1)
|
||||
|
||||
// retrive the next block number to process
|
||||
nextBlockNumber = fs.readFileSync(configPath, 'utf8');
|
||||
|
||||
} while (true);
|
||||
|
||||
processPendingBlocks(ProcessingMap);
|
||||
|
||||
}, 250);
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
216
off_chain_data/listener/blockProcessing.js
Normal file
216
off_chain_data/listener/blockProcessing.js
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
7
off_chain_data/listener/config.json
Normal file
7
off_chain_data/listener/config.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"peer_name": "peer0.org1.example.com",
|
||||
"channelid": "mychannel",
|
||||
"use_couchdb":true,
|
||||
"create_history_log":true,
|
||||
"couchdb_address": "http://admin:adminpw@offchaindb:5984"
|
||||
}
|
||||
111
off_chain_data/listener/couchdbutil.js
Normal file
111
off_chain_data/listener/couchdbutil.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.createDatabaseIfNotExists = function (nano, dbname) {
|
||||
|
||||
return new Promise((async (resolve, reject) => {
|
||||
await nano.db.get(dbname, async function (err, body) {
|
||||
if (err) {
|
||||
if (err.statusCode == 404) {
|
||||
await nano.db.create(dbname, function (err, body) {
|
||||
if (!err) {
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
exports.writeToCouchDB = async function (nano, dbname, key, value) {
|
||||
|
||||
return new Promise((async (resolve, reject) => {
|
||||
|
||||
try {
|
||||
await this.createDatabaseIfNotExists(nano, dbname);
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
const db = nano.use(dbname);
|
||||
|
||||
// If a key is not specified, then this is an insert
|
||||
if (key == null) {
|
||||
db.insert(value, async function (err, body, header) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
||||
// If a key is specified, then attempt to retrieve the record by key
|
||||
db.get(key, async function (err, body) {
|
||||
// parse the value
|
||||
const updateValue = value;
|
||||
// if the record was found, then update the revision to allow the update
|
||||
if (err == null) {
|
||||
updateValue._rev = body._rev
|
||||
}
|
||||
// update or insert the value
|
||||
db.insert(updateValue, key, async function (err, body, header) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resolve(true);
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
exports.deleteRecord = async function (nano, dbname, key) {
|
||||
|
||||
return new Promise((async (resolve, reject) => {
|
||||
|
||||
try {
|
||||
await this.createDatabaseIfNotExists(nano, dbname);
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
const db = nano.use(dbname);
|
||||
|
||||
// If a key is specified, then attempt to retrieve the record by key
|
||||
db.get(key, async function (err, body) {
|
||||
|
||||
// if the record was found, then update the revision to allow the update
|
||||
if (err == null) {
|
||||
|
||||
let revision = body._rev
|
||||
|
||||
// update or insert the value
|
||||
db.destroy(key, revision, async function (err, body, header) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
resolve(true);
|
||||
|
||||
}));
|
||||
}
|
||||
26
off_chain_data/listener/docker-compose.yml
Normal file
26
off_chain_data/listener/docker-compose.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
version: '2'
|
||||
|
||||
networks:
|
||||
net_test:
|
||||
external: true
|
||||
|
||||
services:
|
||||
offchaindb:
|
||||
container_name: offchaindb
|
||||
image: couchdb:3.1
|
||||
environment:
|
||||
- COUCHDB_USER=admin
|
||||
- COUCHDB_PASSWORD=adminpw
|
||||
ports:
|
||||
- "5990:5984"
|
||||
networks:
|
||||
- net_test
|
||||
|
||||
offchainlistener:
|
||||
container_name: block-listener
|
||||
restart: always
|
||||
build: .
|
||||
networks:
|
||||
- net_test
|
||||
depends_on:
|
||||
- offchaindb
|
||||
55
off_chain_data/listener/enrollAdmin.js
Normal file
55
off_chain_data/listener/enrollAdmin.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const FabricCAServices = require('fabric-ca-client');
|
||||
const { Wallets, X509WalletMixin } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// load the network configuration
|
||||
const ccpPath = path.resolve(__dirname, 'files', 'connection-org1.json');
|
||||
let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Create a new CA client for interacting with the CA.
|
||||
const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
|
||||
const ca = new FabricCAServices(caURL);
|
||||
|
||||
// Create a new file system based wallet for managing identities.
|
||||
const walletPath = path.join(process.cwd(), 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
console.log(`Wallet path: ${walletPath}`);
|
||||
|
||||
// Check to see if we've already enrolled the admin user.
|
||||
const adminExists = await wallet.get('admin');
|
||||
if (adminExists) {
|
||||
console.log('An identity for the admin user "admin" already exists in the wallet');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enroll the admin user, and import the new identity into the wallet.
|
||||
const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
|
||||
const x509Identity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
privateKey: enrollment.key.toBytes(),
|
||||
},
|
||||
mspId: 'Org1MSP',
|
||||
type: 'X.509',
|
||||
};
|
||||
await wallet.put('admin', x509Identity);
|
||||
console.log('Successfully enrolled admin user "admin" and imported it into the wallet');
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to enroll admin user "admin": ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "test-network-org1",
|
||||
"version": "1.0.0",
|
||||
"client": {
|
||||
"organization": "Org1",
|
||||
"connection": {
|
||||
"timeout": {
|
||||
"peer": {
|
||||
"endorser": "300"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"Org1": {
|
||||
"mspid": "Org1MSP",
|
||||
"peers": [
|
||||
"peer0.org1.example.com"
|
||||
],
|
||||
"certificateAuthorities": [
|
||||
"ca.org1.example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"peers": {
|
||||
"peer0.org1.example.com": {
|
||||
"url": "grpcs://localhost:7051",
|
||||
"tlsCACerts": {
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIURi+1fFD+OW/8hkW3oGqvmyrKe5cwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTIzOTAwWhcNMzUwODMwMTIzOTAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA8o\nTFVDKJAYRFhme5CIe4NoUC6dBA2n0wu00gdU4wxYN3t5jgvNfND9rbz69IxcTx25\nA56qWnG6M8TxP3oCKyOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBTwjphcJEd3xvAI/OpZXDCd/aoMxDAKBggqhkjOPQQD\nAgNHADBEAiAu63pJTw5kr7ua/MDVIcZ+eoqVDbyRVku5yp8ETwyxiwIgGfiyOJEm\nMIeKkhyNrYSwqCLUR0wUp+H9dagC9X18MDI=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"grpcOptions": {
|
||||
"ssl-target-name-override": "peer0.org1.example.com",
|
||||
"hostnameOverride": "peer0.org1.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certificateAuthorities": {
|
||||
"ca.org1.example.com": {
|
||||
"url": "https://localhost:7054",
|
||||
"caName": "ca-org1",
|
||||
"tlsCACerts": {
|
||||
"pem": ["-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIURi+1fFD+OW/8hkW3oGqvmyrKe5cwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTIzOTAwWhcNMzUwODMwMTIzOTAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA8o\nTFVDKJAYRFhme5CIe4NoUC6dBA2n0wu00gdU4wxYN3t5jgvNfND9rbz69IxcTx25\nA56qWnG6M8TxP3oCKyOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBTwjphcJEd3xvAI/OpZXDCd/aoMxDAKBggqhkjOPQQD\nAgNHADBEAiAu63pJTw5kr7ua/MDVIcZ+eoqVDbyRVku5yp8ETwyxiwIgGfiyOJEm\nMIeKkhyNrYSwqCLUR0wUp+H9dagC9X18MDI=\n-----END CERTIFICATE-----\n"]
|
||||
},
|
||||
"httpOptions": {
|
||||
"verify": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
off_chain_data/listener/files/connection-org1.json
Normal file
49
off_chain_data/listener/files/connection-org1.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "test-network-org1",
|
||||
"version": "1.0.0",
|
||||
"client": {
|
||||
"organization": "Org1",
|
||||
"connection": {
|
||||
"timeout": {
|
||||
"peer": {
|
||||
"endorser": "300"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"Org1": {
|
||||
"mspid": "Org1MSP",
|
||||
"peers": [
|
||||
"peer0.org1.example.com"
|
||||
],
|
||||
"certificateAuthorities": [
|
||||
"ca.org1.example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"peers": {
|
||||
"peer0.org1.example.com": {
|
||||
"url": "grpcs://peer0.org1.example.com:7051",
|
||||
"tlsCACerts": {
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIURi+1fFD+OW/8hkW3oGqvmyrKe5cwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTIzOTAwWhcNMzUwODMwMTIzOTAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA8o\nTFVDKJAYRFhme5CIe4NoUC6dBA2n0wu00gdU4wxYN3t5jgvNfND9rbz69IxcTx25\nA56qWnG6M8TxP3oCKyOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBTwjphcJEd3xvAI/OpZXDCd/aoMxDAKBggqhkjOPQQD\nAgNHADBEAiAu63pJTw5kr7ua/MDVIcZ+eoqVDbyRVku5yp8ETwyxiwIgGfiyOJEm\nMIeKkhyNrYSwqCLUR0wUp+H9dagC9X18MDI=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"grpcOptions": {
|
||||
"ssl-target-name-override": "peer0.org1.example.com",
|
||||
"hostnameOverride": "peer0.org1.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certificateAuthorities": {
|
||||
"ca.org1.example.com": {
|
||||
"url": "https://ca_org{ORG}:7054",
|
||||
"caName": "ca-org1",
|
||||
"tlsCACerts": {
|
||||
"pem": ["-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIURi+1fFD+OW/8hkW3oGqvmyrKe5cwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTIzOTAwWhcNMzUwODMwMTIzOTAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA8o\nTFVDKJAYRFhme5CIe4NoUC6dBA2n0wu00gdU4wxYN3t5jgvNfND9rbz69IxcTx25\nA56qWnG6M8TxP3oCKyOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBTwjphcJEd3xvAI/OpZXDCd/aoMxDAKBggqhkjOPQQD\nAgNHADBEAiAu63pJTw5kr7ua/MDVIcZ+eoqVDbyRVku5yp8ETwyxiwIgGfiyOJEm\nMIeKkhyNrYSwqCLUR0wUp+H9dagC9X18MDI=\n-----END CERTIFICATE-----\n"]
|
||||
},
|
||||
"httpOptions": {
|
||||
"verify": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "test-network-org2",
|
||||
"version": "1.0.0",
|
||||
"client": {
|
||||
"organization": "Org2",
|
||||
"connection": {
|
||||
"timeout": {
|
||||
"peer": {
|
||||
"endorser": "300"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"Org2": {
|
||||
"mspid": "Org2MSP",
|
||||
"peers": [
|
||||
"peer0.org2.example.com"
|
||||
],
|
||||
"certificateAuthorities": [
|
||||
"ca.org2.example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"peers": {
|
||||
"peer0.org2.example.com": {
|
||||
"url": "grpcs://localhost:9051",
|
||||
"tlsCACerts": {
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICHzCCAcWgAwIBAgIUGt1JOlE1zJ31uO7t8ed5n4d7V0YwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yMDA5MDIxMjM5MDBaFw0zNTA4MzAxMjM5MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATrGlQj2uW/FXjr\nZcrSzHMY4yHNyeEmfMJfKWyzrOpHIbVcUDfvmOlyUwmWN9hNrELw8V8I+I1LKdtx\nE4mcha0To0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUa06sGaGWJeWPZK42DmgCaXrkrCMwCgYIKoZIzj0EAwIDSAAwRQIh\nAMvQVC/bz0fchGBLzJaaUan3EnHyCsgJ+3jXefKwRT4aAiArRMyTkFJtcUP428YR\n/4qB0m37B+GiMHgrjZCGBNmVDA==\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"grpcOptions": {
|
||||
"ssl-target-name-override": "peer0.org2.example.com",
|
||||
"hostnameOverride": "peer0.org2.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certificateAuthorities": {
|
||||
"ca.org2.example.com": {
|
||||
"url": "https://localhost:8054",
|
||||
"caName": "ca-org2",
|
||||
"tlsCACerts": {
|
||||
"pem": ["-----BEGIN CERTIFICATE-----\nMIICHzCCAcWgAwIBAgIUGt1JOlE1zJ31uO7t8ed5n4d7V0YwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yMDA5MDIxMjM5MDBaFw0zNTA4MzAxMjM5MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATrGlQj2uW/FXjr\nZcrSzHMY4yHNyeEmfMJfKWyzrOpHIbVcUDfvmOlyUwmWN9hNrELw8V8I+I1LKdtx\nE4mcha0To0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUa06sGaGWJeWPZK42DmgCaXrkrCMwCgYIKoZIzj0EAwIDSAAwRQIh\nAMvQVC/bz0fchGBLzJaaUan3EnHyCsgJ+3jXefKwRT4aAiArRMyTkFJtcUP428YR\n/4qB0m37B+GiMHgrjZCGBNmVDA==\n-----END CERTIFICATE-----\n"]
|
||||
},
|
||||
"httpOptions": {
|
||||
"verify": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
off_chain_data/listener/files/connection-org2.json
Normal file
49
off_chain_data/listener/files/connection-org2.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "test-network-org2",
|
||||
"version": "1.0.0",
|
||||
"client": {
|
||||
"organization": "Org2",
|
||||
"connection": {
|
||||
"timeout": {
|
||||
"peer": {
|
||||
"endorser": "300"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"Org2": {
|
||||
"mspid": "Org2MSP",
|
||||
"peers": [
|
||||
"peer0.org2.example.com"
|
||||
],
|
||||
"certificateAuthorities": [
|
||||
"ca.org2.example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"peers": {
|
||||
"peer0.org2.example.com": {
|
||||
"url": "grpcs://peer0.org2.example.com:9051",
|
||||
"tlsCACerts": {
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICHzCCAcWgAwIBAgIUGt1JOlE1zJ31uO7t8ed5n4d7V0YwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yMDA5MDIxMjM5MDBaFw0zNTA4MzAxMjM5MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATrGlQj2uW/FXjr\nZcrSzHMY4yHNyeEmfMJfKWyzrOpHIbVcUDfvmOlyUwmWN9hNrELw8V8I+I1LKdtx\nE4mcha0To0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUa06sGaGWJeWPZK42DmgCaXrkrCMwCgYIKoZIzj0EAwIDSAAwRQIh\nAMvQVC/bz0fchGBLzJaaUan3EnHyCsgJ+3jXefKwRT4aAiArRMyTkFJtcUP428YR\n/4qB0m37B+GiMHgrjZCGBNmVDA==\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"grpcOptions": {
|
||||
"ssl-target-name-override": "peer0.org2.example.com",
|
||||
"hostnameOverride": "peer0.org2.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certificateAuthorities": {
|
||||
"ca.org2.example.com": {
|
||||
"url": "https://ca_org{ORG}:8054",
|
||||
"caName": "ca-org2",
|
||||
"tlsCACerts": {
|
||||
"pem": ["-----BEGIN CERTIFICATE-----\nMIICHzCCAcWgAwIBAgIUGt1JOlE1zJ31uO7t8ed5n4d7V0YwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yMDA5MDIxMjM5MDBaFw0zNTA4MzAxMjM5MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATrGlQj2uW/FXjr\nZcrSzHMY4yHNyeEmfMJfKWyzrOpHIbVcUDfvmOlyUwmWN9hNrELw8V8I+I1LKdtx\nE4mcha0To0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUa06sGaGWJeWPZK42DmgCaXrkrCMwCgYIKoZIzj0EAwIDSAAwRQIh\nAMvQVC/bz0fchGBLzJaaUan3EnHyCsgJ+3jXefKwRT4aAiArRMyTkFJtcUP428YR\n/4qB0m37B+GiMHgrjZCGBNmVDA==\n-----END CERTIFICATE-----\n"]
|
||||
},
|
||||
"httpOptions": {
|
||||
"verify": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3783
off_chain_data/listener/package-lock.json
generated
Normal file
3783
off_chain_data/listener/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
45
off_chain_data/listener/package.json
Normal file
45
off_chain_data/listener/package.json
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "offchaindata",
|
||||
"version": "1.0.0",
|
||||
"description": "Offchain Data application implemented in JavaScript",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "nyc mocha --recursive"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-ca-client": "^2.1.0",
|
||||
"fabric-network": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^5.9.0",
|
||||
"mocha": "^5.2.0",
|
||||
"nyc": "^13.1.0",
|
||||
"sinon": "^7.1.1",
|
||||
"sinon-chai": "^3.3.0"
|
||||
},
|
||||
"nyc": {
|
||||
"exclude": [
|
||||
"coverage/**",
|
||||
"test/**"
|
||||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html"
|
||||
],
|
||||
"all": true,
|
||||
"check-coverage": true,
|
||||
"statements": 100,
|
||||
"branches": 100,
|
||||
"functions": 100,
|
||||
"lines": 100
|
||||
}
|
||||
}
|
||||
75
off_chain_data/listener/registerUser.js
Normal file
75
off_chain_data/listener/registerUser.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway, X509WalletMixin } = require('fabric-network');
|
||||
const FabricCAServices = require('fabric-ca-client');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// load the network configuration
|
||||
const ccpPath = path.resolve(__dirname, 'files', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Create a new CA client for interacting with the CA.
|
||||
const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
|
||||
const ca = new FabricCAServices(caURL);
|
||||
|
||||
// Create a new file system based wallet for managing identities.
|
||||
const walletPath = path.join(process.cwd(), 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
console.log(`Wallet path: ${walletPath}`);
|
||||
|
||||
// Check to see if we've already enrolled the user.
|
||||
const userExists = await wallet.get('listenerUser');
|
||||
if (userExists) {
|
||||
console.log('An identity for the user "listenerUser" already exists in the wallet');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if we've already enrolled the admin user.
|
||||
const adminIdentity = await wallet.get('admin');
|
||||
if (!adminIdentity) {
|
||||
console.log('An identity for the admin user "admin" does not exist in the wallet');
|
||||
console.log('Run the enrollAdmin.js application before retrying');
|
||||
return;
|
||||
}
|
||||
|
||||
// build a user object for authenticating with the CA
|
||||
const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
|
||||
const adminUser = await provider.getUserContext(adminIdentity, 'admin');
|
||||
|
||||
// Register the user, enroll the user, and import the new identity into the wallet.
|
||||
const secret = await ca.register({
|
||||
affiliation: 'org1.department1',
|
||||
enrollmentID: 'listenerUser',
|
||||
role: 'client'
|
||||
}, adminUser);
|
||||
const enrollment = await ca.enroll({
|
||||
enrollmentID: 'listenerUser',
|
||||
enrollmentSecret: secret
|
||||
});
|
||||
const x509Identity = {
|
||||
credentials: {
|
||||
certificate: enrollment.certificate,
|
||||
privateKey: enrollment.key.toBytes(),
|
||||
},
|
||||
mspId: 'Org1MSP',
|
||||
type: 'X.509',
|
||||
};
|
||||
await wallet.put('listenerUser', x509Identity);
|
||||
console.log('Successfully registered and enrolled admin user "listenerUser" and imported it into the wallet');
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to register user "listenerUser": ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
1
off_chain_data/listener/wallet/admin.id
Normal file
1
off_chain_data/listener/wallet/admin.id
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB8jCCAZmgAwIBAgIUZK86p6mQmWUJzhv4EoY5EeGObM4wCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTI0MDAwWhcNMjEwOTAyMTI0NTAw\nWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAE8ANxIy5O+BU02DiF5KRMKdSmQHntJNLjKIuTMWAoZjNp\nB+ylEP4h8174OSL122lOz+j+U1NKWWSANn9MsYn2qqNgMF4wDgYDVR0PAQH/BAQD\nAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKt5l3uuPT/Q5CnezAQKaMhCEvSy\nMB8GA1UdIwQYMBaAFPCOmFwkR3fG8Aj86llcMJ39qgzEMAoGCCqGSM49BAMCA0cA\nMEQCIEpd5ipyrnWYEknfg/ydYSGTwug/SS3smTDaK0R9rZI4AiAtBO9WnfsGgBGd\ntNpJg18QdM8TH6OJglypwI2Q0H/A+Q==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHLXHn0jU6ZRzkdtb\r\nMaZ1VnlruDE0crtGAyaVQ6INEpOhRANCAATwA3EjLk74FTTYOIXkpEwp1KZAee0k\r\n0uMoi5MxYChmM2kH7KUQ/iHzXvg5IvXbaU7P6P5TU0pZZIA2f0yxifaq\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1}
|
||||
1
off_chain_data/listener/wallet/listenerUser.id
Normal file
1
off_chain_data/listener/wallet/listenerUser.id
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICjDCCAjSgAwIBAgIUOAhHDicFm3H63ACoYBVis78SoREwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTI0MDAwWhcNMjEwOTAyMTI0NTAw\nWjBJMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVwYXJ0\nbWVudDExFTATBgNVBAMTDGxpc3RlbmVyVXNlcjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABMvQv3LC0SBoUd0Qzulpi5smB5sX5++vK98irqcRYmcr8l3smHCDmbS4\n0/VYvp6QnQSC18zyHOf5Wt0ZS6cPzrOjgdIwgc8wDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDZjFQb5/b8qp8nj9z6fLZ2hqjcNMB8GA1Ud\nIwQYMBaAFPCOmFwkR3fG8Aj86llcMJ39qgzEMG8GCCoDBAUGBwgBBGN7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9s\nbG1lbnRJRCI6Imxpc3RlbmVyVXNlciIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYI\nKoZIzj0EAwIDRgAwQwIgVZo7YqK1DCyPPSu/nfz8VWqP+g9fYrkUPqvig/AfDb8C\nH3rP+wzF09o0ddH91+TUegflXFceRaPB8uXgz07sYLE=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyn/2qcvazRXWCnLk\r\nNNx51uBeDAck6w2z0VgLAGBPOpahRANCAATL0L9ywtEgaFHdEM7paYubJgebF+fv\r\nryvfIq6nEWJnK/Jd7Jhwg5m0uNP1WL6ekJ0EgtfM8hzn+VrdGUunD86z\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1}
|
||||
|
|
@ -16,5 +16,12 @@ popd
|
|||
rm -rf wallet
|
||||
rm -rf addMarbles.json mychannel_marbles.log mychannel__lifecycle.log nextblock.txt
|
||||
|
||||
pushd listener
|
||||
docker-compose down
|
||||
rm -rf wallet
|
||||
rm -rf mychannel_marbles.log mychannel__lifecycle.log nextblock.txt
|
||||
rm files/*
|
||||
popd
|
||||
|
||||
docker stop offchaindb
|
||||
docker rm offchaindb
|
||||
|
|
|
|||
|
|
@ -25,6 +25,36 @@ pushd ../test-network
|
|||
./network.sh down
|
||||
./network.sh up createChannel -ca -s couchdb
|
||||
|
||||
# COPY CPP to my working dir
|
||||
cp organizations/peerOrganizations/org1.example.com/connection-org1.json ../off_chain_data/listener/files/
|
||||
cp organizations/peerOrganizations/org2.example.com/connection-org2.json ../off_chain_data/listener/files/
|
||||
cp organizations/peerOrganizations/org1.example.com/connection-org1-for-docker.json ../off_chain_data/listener/files/
|
||||
cp organizations/peerOrganizations/org2.example.com/connection-org2-for-docker.json ../off_chain_data/listener/files/
|
||||
|
||||
#echo Starting offchain database
|
||||
#docker run --publish 5990:5984 --detach -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=adminpw --name offchaindb couchdb
|
||||
|
||||
popd
|
||||
pushd listener
|
||||
node enrollAdmin.js
|
||||
node registerUser.js
|
||||
|
||||
mv files/connection-org1.json files/connection-org1-for-localhost.json
|
||||
mv files/connection-org2.json files/connection-org2-for-localhost.json
|
||||
|
||||
mv files/connection-org1-for-docker.json files/connection-org1.json
|
||||
mv files/connection-org2-for-docker.json files/connection-org2.json
|
||||
|
||||
docker-compose up -d --build
|
||||
popd
|
||||
pushd ../test-network
|
||||
|
||||
#echo Creating admin and user wallet
|
||||
#popd
|
||||
#node enrollAdmin.js
|
||||
#node registerUser.js
|
||||
#pushd ../test-network
|
||||
|
||||
export PATH=${PWD}/../bin:${PWD}:$PATH
|
||||
export FABRIC_CFG_PATH=${PWD}/../config
|
||||
|
||||
|
|
|
|||
1
off_chain_data/wallet/admin.id
Normal file
1
off_chain_data/wallet/admin.id
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB8jCCAZmgAwIBAgIUD5BT6A6tbOI1DV6+o5n8e12I8Q0wCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTI0MzAwWhcNMjEwOTAyMTI0ODAw\nWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAE3Q1CrssZsPsi2kBpAA1ET9zc3lLpPyyGSQkm81UfUSL9\n7HldsNSAGhR4RAsnGWPQTtlIOMCN2vMnIxGVLIXQlaNgMF4wDgYDVR0PAQH/BAQD\nAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGKRYFnAJqVfRKGfpL8cL+pJt2bG\nMB8GA1UdIwQYMBaAFPCOmFwkR3fG8Aj86llcMJ39qgzEMAoGCCqGSM49BAMCA0cA\nMEQCIAJE27zMnqeInlRS6+RBQiDKxLu9vc3zkLhe8jaQSvCBAiAL3hNPpvLS99yG\nZUTFtmtBE2cqnPlrQzQyIjEWDyDwAQ==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs2sdp3R/tqHt8KrG\r\nO5Bf6mVQBqw+SuBZ3x6oVIQLJ6ahRANCAATdDUKuyxmw+yLaQGkADURP3NzeUuk/\r\nLIZJCSbzVR9RIv3seV2w1IAaFHhECycZY9BO2Ug4wI3a8ycjEZUshdCV\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1}
|
||||
1
off_chain_data/wallet/appUser.id
Normal file
1
off_chain_data/wallet/appUser.id
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChDCCAiqgAwIBAgIUD75+CCeBRhGk9EcXWlBXWUw0du0wCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwOTAyMTI0MzAwWhcNMjEwOTAyMTI0ODAw\nWjBEMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVwYXJ0\nbWVudDExEDAOBgNVBAMTB2FwcFVzZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAATQC3qTQuhSTQPX9qypSot6gDzt8KdNstH8ZbH9TVQswdkgTMqMhO822X0iWTo2\nPsK7wCFWpDaTq0rm3KlYYvyho4HNMIHKMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB\nAf8EAjAAMB0GA1UdDgQWBBRCSGtwMHSB9NN1Pv1mCNqTqnxCcjAfBgNVHSMEGDAW\ngBTwjphcJEd3xvAI/OpZXDCd/aoMxDBqBggqAwQFBgcIAQReeyJhdHRycyI6eyJo\nZi5BZmZpbGlhdGlvbiI6Im9yZzEuZGVwYXJ0bWVudDEiLCJoZi5FbnJvbGxtZW50\nSUQiOiJhcHBVc2VyIiwiaGYuVHlwZSI6ImNsaWVudCJ9fTAKBggqhkjOPQQDAgNI\nADBFAiEAr+l/dAPgMtXPz+5CMDWUDesa9spsksjwr0u8vRtWxv8CIC+QrZNHeJId\n9N1Ubdav4bMzgntBtLCamhMm5TnE4AaP\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaLfWkqiyUsKH0ZZm\r\nKIAQ+XgEoWIGs1ZDfiFDigtrbKKhRANCAATQC3qTQuhSTQPX9qypSot6gDzt8KdN\r\nstH8ZbH9TVQswdkgTMqMhO822X0iWTo2PsK7wCFWpDaTq0rm3KlYYvyh\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1}
|
||||
|
|
@ -15,6 +15,17 @@ function json_ccp {
|
|||
organizations/ccp-template.json
|
||||
}
|
||||
|
||||
function json_ccp_for_docker {
|
||||
local PP=$(one_line_pem $4)
|
||||
local CP=$(one_line_pem $5)
|
||||
sed -e "s/\${ORG}/$1/" \
|
||||
-e "s/\${P0PORT}/$2/" \
|
||||
-e "s/\${CAPORT}/$3/" \
|
||||
-e "s#\${PEERPEM}#$PP#" \
|
||||
-e "s#\${CAPEM}#$CP#" \
|
||||
organizations/ccp-template-for-docker.json
|
||||
}
|
||||
|
||||
function yaml_ccp {
|
||||
local PP=$(one_line_pem $4)
|
||||
local CP=$(one_line_pem $5)
|
||||
|
|
@ -33,6 +44,7 @@ PEERPEM=organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.exampl
|
|||
CAPEM=organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem
|
||||
|
||||
echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.example.com/connection-org1.json
|
||||
echo "$(json_ccp_for_docker $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.example.com/connection-org1-for-docker.json
|
||||
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.example.com/connection-org1.yaml
|
||||
|
||||
ORG=2
|
||||
|
|
@ -42,4 +54,5 @@ PEERPEM=organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.exampl
|
|||
CAPEM=organizations/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem
|
||||
|
||||
echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.example.com/connection-org2.json
|
||||
echo "$(json_ccp_for_docker $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.example.com/connection-org2-for-docker.json
|
||||
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.example.com/connection-org2.yaml
|
||||
|
|
|
|||
45
test-network/organizations/ccp-generate.sh.original
Executable file
45
test-network/organizations/ccp-generate.sh.original
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
function one_line_pem {
|
||||
echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`"
|
||||
}
|
||||
|
||||
function json_ccp {
|
||||
local PP=$(one_line_pem $4)
|
||||
local CP=$(one_line_pem $5)
|
||||
sed -e "s/\${ORG}/$1/" \
|
||||
-e "s/\${P0PORT}/$2/" \
|
||||
-e "s/\${CAPORT}/$3/" \
|
||||
-e "s#\${PEERPEM}#$PP#" \
|
||||
-e "s#\${CAPEM}#$CP#" \
|
||||
organizations/ccp-template.json
|
||||
}
|
||||
|
||||
function yaml_ccp {
|
||||
local PP=$(one_line_pem $4)
|
||||
local CP=$(one_line_pem $5)
|
||||
sed -e "s/\${ORG}/$1/" \
|
||||
-e "s/\${P0PORT}/$2/" \
|
||||
-e "s/\${CAPORT}/$3/" \
|
||||
-e "s#\${PEERPEM}#$PP#" \
|
||||
-e "s#\${CAPEM}#$CP#" \
|
||||
organizations/ccp-template.yaml | sed -e $'s/\\\\n/\\\n /g'
|
||||
}
|
||||
|
||||
ORG=1
|
||||
P0PORT=7051
|
||||
CAPORT=7054
|
||||
PEERPEM=organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem
|
||||
CAPEM=organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem
|
||||
|
||||
echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.example.com/connection-org1.json
|
||||
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org1.example.com/connection-org1.yaml
|
||||
|
||||
ORG=2
|
||||
P0PORT=9051
|
||||
CAPORT=8054
|
||||
PEERPEM=organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
|
||||
CAPEM=organizations/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem
|
||||
|
||||
echo "$(json_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.example.com/connection-org2.json
|
||||
echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > organizations/peerOrganizations/org2.example.com/connection-org2.yaml
|
||||
49
test-network/organizations/ccp-template-for-docker.json
Executable file
49
test-network/organizations/ccp-template-for-docker.json
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "test-network-org${ORG}",
|
||||
"version": "1.0.0",
|
||||
"client": {
|
||||
"organization": "Org${ORG}",
|
||||
"connection": {
|
||||
"timeout": {
|
||||
"peer": {
|
||||
"endorser": "300"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizations": {
|
||||
"Org${ORG}": {
|
||||
"mspid": "Org${ORG}MSP",
|
||||
"peers": [
|
||||
"peer0.org${ORG}.example.com"
|
||||
],
|
||||
"certificateAuthorities": [
|
||||
"ca.org${ORG}.example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"peers": {
|
||||
"peer0.org${ORG}.example.com": {
|
||||
"url": "grpcs://peer0.org${ORG}.example.com:${P0PORT}",
|
||||
"tlsCACerts": {
|
||||
"pem": "${PEERPEM}"
|
||||
},
|
||||
"grpcOptions": {
|
||||
"ssl-target-name-override": "peer0.org${ORG}.example.com",
|
||||
"hostnameOverride": "peer0.org${ORG}.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certificateAuthorities": {
|
||||
"ca.org${ORG}.example.com": {
|
||||
"url": "https://ca_org{ORG}:${CAPORT}",
|
||||
"caName": "ca-org${ORG}",
|
||||
"tlsCACerts": {
|
||||
"pem": ["${CAPEM}"]
|
||||
},
|
||||
"httpOptions": {
|
||||
"verify": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue