From faac18e6dae4c8dd22ec4e0440e0dd8140ff977f Mon Sep 17 00:00:00 2001 From: nikhil550 Date: Fri, 20 Mar 2020 10:23:54 -0400 Subject: [PATCH] [FAB-17461] Move off_chain_data sample to test network (#122) Signed-off-by: NIKHIL E GUPTA Co-authored-by: NIKHIL E GUPTA --- off_chain_data/README.md | 63 ++++---- off_chain_data/addMarbles.js | 4 +- off_chain_data/blockEventListener.js | 8 +- off_chain_data/deleteMarble.js | 4 +- off_chain_data/enrollAdmin.js | 4 +- off_chain_data/network-clean.sh | 20 +++ off_chain_data/registerUser.js | 18 +-- off_chain_data/startFabric.sh | 211 +++++++++++++-------------- off_chain_data/transferMarble.js | 4 +- 9 files changed, 169 insertions(+), 167 deletions(-) create mode 100755 off_chain_data/network-clean.sh diff --git a/off_chain_data/README.md b/off_chain_data/README.md index d5b64d4725..81e3480186 100644 --- a/off_chain_data/README.md +++ b/off_chain_data/README.md @@ -1,28 +1,32 @@ # Off Chain data -This sample demonstrates how you can use [Peer channel-based event services](https://hyperledger-fabric.readthedocs.io/en/release-1.4/peer_event_services.html) +This sample demonstrates how you can use [Peer channel-based event services](https://hyperledger-fabric.readthedocs.io/en/release-2.0/peer_event_services.html) to replicate the data on your blockchain network to an off chain database. Using an off chain database allows you to analyze the data from your network or build a dashboard without degrading the performance of your application. -This sample uses the [Fabric network event listener](https://fabric-sdk-node.github.io/release-1.4/tutorial-listening-to-events.html) from the Node.JS Fabric SDK to write data to local instance of +This sample uses the [Fabric network event listener](https://hyperledger.github.io/fabric-sdk-node/release-1.4/tutorial-channel-events.html) from the Node.JS Fabric SDK to write data to local instance of CouchDB. ## Getting started This sample uses Node Fabric SDK application code similar to the `fabcar` sample -to connect to a network created using the `first-network` sample. +to connect to a running instance of the Fabric test network. Make sure that you +are running the following commands from the `off_chain_data` directory. -### Install dependencies +### Starting the Network -You need to install Node.js version 8.9.x to use the sample application code. -Execute the following commands to install the required dependencies: +Use the following command to start the sample network: ``` -cd fabric-samples/off_chain_data -npm install +./startFabric.sh ``` +This command will deploy an instance of the Fabric test network. The network +consists of an ordering service, two peer organizations with one peers each, and +a CA for each org. The command also creates a channel named `mychannel`. The +marbles chaincode will be installed on both peers and deployed to the channel. + ### Configuration The configuration for the listener is stored in the `config.json` file: @@ -51,29 +55,24 @@ If you set the "use_couchdb" option to true in `config.json`, you can run the following command start a local instance of CouchDB using docker: ``` -docker run --publish 5990:5984 --detach --name offchaindb hyperledger/fabric-couchdb +docker run --publish 5990:5984 --detach --name offchaindb couchdb docker start offchaindb ``` -### Starting the Network +### Install dependencies -Use the following command to start the sample network: +You need to install Node.js version 8.9.x to use the sample application code. +Execute the following commands to install the required dependencies: ``` -./startFabric.sh +npm install ``` -This command uses the `first-network` sample to deploy a fabric network with an -ordering service, two peer organizations with two peers each, and a channel -named `mychannel`. The marbles chaincode will be installed on all four peers and -instantiated on the channel. - ### Starting the Channel Event Listener -Once the network has started, we can use the Node.js SDK to create the user and -certificates our listener application will use to interact with the network. Run -the following command to enroll the admin user: - +After we have installed the application dependencies, we can use the Node.js SDK +to create the identity our listener application will use to interact with the +network. Run the following command to enroll the admin user: ``` node enrollAdmin.js ``` @@ -358,18 +357,16 @@ database: ## Clean up If you are finished using the sample application, you can bring down the network -and any accompanying artifacts. +and any accompanying artifacts by running the following command: +``` +./network-clean.sh +``` + +Running the script will complete the following actions: -* Change to `fabric-samples/first-network` directory. -* To stop the network, run `./byfn.sh down`. -* Change back to `fabric-samples/off_chain_data` directory. +* Bring down the Fabric test network. +* Takes down the local CouchDB database. * Remove the certificates you generated by deleting the `wallet` folder. * Delete `nextblock.txt` so you can start with the first block next time you - operate the listener. You can also reset the `nextMarbleNumber` in - `addMarbles.json` to 100. -* To take down the local CouchDB database, first stop and then remove the - docker container: - ``` - docker stop offchaindb - docker rm offchaindb - ``` + operate the listener. +* Removes `addMarbles.json`. diff --git a/off_chain_data/addMarbles.js b/off_chain_data/addMarbles.js index 1f3c8d4f61..8fdbdffc0e 100644 --- a/off_chain_data/addMarbles.js +++ b/off_chain_data/addMarbles.js @@ -69,7 +69,7 @@ async function main() { // 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, '..', 'first-network', 'connection-org1.json'); + 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 @@ -80,7 +80,7 @@ async function main() { // 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: 'user1', discovery: { enabled: true, asLocalhost: true } }); + 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); diff --git a/off_chain_data/blockEventListener.js b/off_chain_data/blockEventListener.js index 6e3974442d..697cf8efdc 100644 --- a/off_chain_data/blockEventListener.js +++ b/off_chain_data/blockEventListener.js @@ -98,20 +98,20 @@ async function main() { console.log(`Wallet path: ${walletPath}`); // Check to see if we've already enrolled the user. - const userExists = await wallet.get('user1'); + const userExists = await wallet.get('appUser'); if (!userExists) { - console.log('An identity for the user "user1" does not exist in the wallet'); + console.log('An identity for the user "appUser" 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, '..', 'first-network', 'connection-org1.json'); + const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', '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: 'user1', discovery: { enabled: true, asLocalhost: true } }); + await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } }); // Get the network (channel) our contract is deployed to. const network = await gateway.getNetwork('mychannel'); diff --git a/off_chain_data/deleteMarble.js b/off_chain_data/deleteMarble.js index 67bc7b6e66..b12706c0cd 100644 --- a/off_chain_data/deleteMarble.js +++ b/off_chain_data/deleteMarble.js @@ -36,7 +36,7 @@ async function main() { // 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, '..', 'first-network', 'connection-org1.json'); + 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 @@ -47,7 +47,7 @@ async function main() { // 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: 'user1', discovery: { enabled: true, asLocalhost: true } }); + 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); diff --git a/off_chain_data/enrollAdmin.js b/off_chain_data/enrollAdmin.js index a7b157be05..38424bed09 100644 --- a/off_chain_data/enrollAdmin.js +++ b/off_chain_data/enrollAdmin.js @@ -1,6 +1,4 @@ /* - * Copyright IBM Corp. All Rights Reserved. - * * SPDX-License-Identifier: Apache-2.0 * */ @@ -15,7 +13,7 @@ const path = require('path'); async function main() { try { // load the network configuration - const ccpPath = path.resolve(__dirname, '..', 'first-network', 'connection-org1.json'); + const ccpPath = path.resolve(__dirname, '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); // Create a new CA client for interacting with the CA. diff --git a/off_chain_data/network-clean.sh b/off_chain_data/network-clean.sh new file mode 100755 index 0000000000..14dc70989b --- /dev/null +++ b/off_chain_data/network-clean.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# +# Exit on first error +set -ex + +# Bring the test network down +pushd ../test-network +./network.sh down +popd + +# clean out any old identites in the wallets +rm -rf wallet +rm -rf addMarbles.json mychannel_marbles.log mychannel__lifecycle.log nextblock.txt + +docker stop offchaindb +docker rm offchaindb diff --git a/off_chain_data/registerUser.js b/off_chain_data/registerUser.js index 6eba3b20cf..c58042717f 100644 --- a/off_chain_data/registerUser.js +++ b/off_chain_data/registerUser.js @@ -1,6 +1,4 @@ /* - * Copyright IBM Corp. All Rights Reserved. - * * SPDX-License-Identifier: Apache-2.0 * */ @@ -15,7 +13,7 @@ const path = require('path'); async function main() { try { // load the network configuration - const ccpPath = path.resolve(__dirname, '..', 'first-network', 'connection-org1.json'); + const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json'); const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); // Create a new CA client for interacting with the CA. @@ -28,9 +26,9 @@ async function main() { console.log(`Wallet path: ${walletPath}`); // Check to see if we've already enrolled the user. - const userExists = await wallet.get('user1'); + const userExists = await wallet.get('appUser'); if (userExists) { - console.log('An identity for the user "user1" already exists in the wallet'); + console.log('An identity for the user "appUser" already exists in the wallet'); return; } @@ -49,11 +47,11 @@ async function main() { // Register the user, enroll the user, and import the new identity into the wallet. const secret = await ca.register({ affiliation: 'org1.department1', - enrollmentID: 'user1', + enrollmentID: 'appUser', role: 'client' }, adminUser); const enrollment = await ca.enroll({ - enrollmentID: 'user1', + enrollmentID: 'appUser', enrollmentSecret: secret }); const x509Identity = { @@ -64,11 +62,11 @@ async function main() { mspId: 'Org1MSP', type: 'X.509', }; - await wallet.put('user1', x509Identity); - console.log('Successfully registered and enrolled admin user "user1" and imported it into the wallet'); + await wallet.put('appUser', x509Identity); + console.log('Successfully registered and enrolled admin user "appUser" and imported it into the wallet'); } catch (error) { - console.error(`Failed to register user "user1": ${error}`); + console.error(`Failed to register user "appUser": ${error}`); process.exit(1); } } diff --git a/off_chain_data/startFabric.sh b/off_chain_data/startFabric.sh index 6f9dfc64ca..1f54e6ead6 100755 --- a/off_chain_data/startFabric.sh +++ b/off_chain_data/startFabric.sh @@ -7,98 +7,64 @@ # Exit on first error set -e pipefail - # don't rewrite paths for Windows Git Bash users export MSYS_NO_PATHCONV=1 starttime=$(date +%s) CC_SRC_LANGUAGE=golang CC_RUNTIME_LANGUAGE=golang -CC_SRC_PATH=github.com/hyperledger/fabric-samples/chaincode/marbles02/go +CC_SRC_PATH=../chaincode/marbles02/go + echo Vendoring Go dependencies ... pushd ../chaincode/marbles02/go GO111MODULE=on go mod vendor popd echo Finished vendoring Go dependencies -# clean the keystore -rm -rf ./hfc-key-store - # launch network; create channel and join peer to channel -pushd ../first-network -echo y | ./byfn.sh down -echo y | ./byfn.sh up -a -n -s couchdb -popd +pushd ../test-network +./network.sh down +./network.sh up createChannel -ca -s couchdb + +export PATH=${PWD}/../bin:${PWD}:$PATH +export FABRIC_CFG_PATH=${PWD}/../config -CONFIG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer -ORG1_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp -ORG1_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -ORG2_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -ORG2_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -ORDERER_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +# import environment variables +. scripts/envVar.sh echo "Packaging the marbles smart contract" -docker exec \ - cli \ - peer lifecycle chaincode package marbles.tar.gz \ - --path $CC_SRC_PATH \ - --lang $CC_RUNTIME_LANGUAGE \ - --label marblesv1 + +setGlobals 1 + +peer lifecycle chaincode package marbles.tar.gz \ + --path $CC_SRC_PATH \ + --lang $CC_RUNTIME_LANGUAGE \ + --label marblesv1 echo "Installing smart contract on peer0.org1.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode install marbles.tar.gz - -echo "Installing smart contract on peer1.org1.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode install marbles.tar.gz + +peer lifecycle chaincode install marbles.tar.gz + echo "Installing smart contract on peer0.org2.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org2MSP \ - -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode install marbles.tar.gz - -echo "Installing smart contract on peer1.org2.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org2MSP \ - -e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode install marbles.tar.gz + +setGlobals 2 + +peer lifecycle chaincode install marbles.tar.gz + echo "Query the chaincode package id" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ - cli \ - /bin/bash -c "peer lifecycle chaincode queryinstalled > log" - PACKAGE_ID=`docker exec cli sed -nr '/Label: marblesv1/s/Package ID: (.*), Label: marblesv1/\1/p;' log` + +setGlobals 1 + +peer lifecycle chaincode queryinstalled >&log.txt + +PACKAGE_ID=$(sed -n "/marblesv1/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt) echo "Approving the chaincode definition for org1.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode approveformyorg \ - -o orderer.example.com:7050 \ + +peer lifecycle chaincode approveformyorg \ + -o localhost:7050 \ + --ordererTLSHostnameOverride orderer.example.com \ --channelID mychannel \ --name marbles \ --version 1.0 \ @@ -107,17 +73,15 @@ docker exec \ --sequence 1 \ --package-id $PACKAGE_ID \ --tls \ - --cafile ${ORDERER_TLS_ROOTCERT_FILE} + --cafile ${ORDERER_CA} echo "Approving the chaincode definition for org2.example.com" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org2MSP \ - -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ - -e CORE_PEER_MSPCONFIGPATH=${ORG2_MSPCONFIGPATH} \ - -e CORE_PEER_TLS_ROOTCERT_FILE=${ORG2_TLS_ROOTCERT_FILE} \ - cli \ - peer lifecycle chaincode approveformyorg \ - -o orderer.example.com:7050 \ + +setGlobals 2 + +peer lifecycle chaincode approveformyorg \ + -o localhost:7050 \ + --ordererTLSHostnameOverride orderer.example.com \ --channelID mychannel \ --name marbles \ --version 1.0 \ @@ -126,19 +90,38 @@ docker exec \ --sequence 1 \ --package-id $PACKAGE_ID \ --tls \ - --cafile ${ORDERER_TLS_ROOTCERT_FILE} + --cafile ${ORDERER_CA} + +echo "Checking if the chaincode definition is ready to commit" + +peer lifecycle chaincode checkcommitreadiness \ + --channelID mychannel \ + --name marbles \ + --version 1.0 \ + --sequence 1 \ + --output json \ + --init-required \ + --signature-policy AND"('Org1MSP.member','Org2MSP.member')" >&log.txt -echo "Waiting for the approvals to be committed ..." +rc=0 +for var in "\"Org1MSP\": true" "\"Org2MSP\": true" +do + grep "$var" log.txt &>/dev/null || let rc=1 +done -sleep 10 +if test $rc -eq 0; then + echo "Chaincode definition is ready to commit" +else + sleep 10 +fi + +parsePeerConnectionParameters 1 2 echo "Commit the chaincode definition to the channel" -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \ - cli \ - peer lifecycle chaincode commit \ - -o orderer.example.com:7050 \ + +peer lifecycle chaincode commit \ + -o localhost:7050 \ + --ordererTLSHostnameOverride orderer.example.com \ --channelID mychannel \ --name marbles \ --version 1.0 \ @@ -146,35 +129,41 @@ docker exec \ --signature-policy AND"('Org1MSP.member','Org2MSP.member')" \ --sequence 1 \ --tls \ - --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ - --peerAddresses peer0.org1.example.com:7051 \ - --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ - --peerAddresses peer0.org2.example.com:9051 \ - --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} + --cafile ${ORDERER_CA} \ + $PEER_CONN_PARMS + +echo "Check if the chaincode has been committed to the channel ..." + +peer lifecycle chaincode querycommitted \ + --channelID mychannel \ + --name marbles >&log.txt -echo "Waiting for the chaincode to be committed ..." +EXPECTED_RESULT="Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc" +VALUE=$(grep -o "Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc" log.txt) +echo "$VALUE" -sleep 10 +if [ "$VALUE" = "Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc" ] ; then + echo "chaincode has been committed" +else + sleep 10 +fi echo "invoke the marbles chaincode init function ... " -docker exec \ - -e CORE_PEER_LOCALMSPID=Org1MSP \ - -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ - cli \ - peer chaincode invoke \ - -o orderer.example.com:7050 \ - -C mychannel \ - -n marbles \ - --isInit \ - -c '{"Args":["Init"]}' \ - --tls \ - --cafile ${ORDERER_TLS_ROOTCERT_FILE} \ - --peerAddresses peer0.org1.example.com:7051 \ - --tlsRootCertFiles ${ORG1_TLS_ROOTCERT_FILE} \ - --peerAddresses peer0.org2.example.com:9051 \ - --tlsRootCertFiles ${ORG2_TLS_ROOTCERT_FILE} -sleep 10 +peer chaincode invoke \ + -o localhost:7050 \ + --ordererTLSHostnameOverride orderer.example.com \ + -C mychannel \ + -n marbles \ + --isInit \ + -c '{"Args":["Init"]}' \ + --tls \ + --cafile ${ORDERER_CA} \ + $PEER_CONN_PARMS + +rm log.txt + +popd cat <