From 1d69e9e2d154ced37193f4474ce7dbbc728ffcb5 Mon Sep 17 00:00:00 2001 From: Arnaud J Le Hors Date: Fri, 22 Dec 2017 16:52:49 +0100 Subject: [PATCH] [FAB-7540] Simplifies Reconfigure Your Network tutorial This change brings a new set of scripts and configuration files to the first-network sample to make it easier for people to follow the new tutorial on how to add a third org to the network setup in BYFN. To function properly the new Extend You First Network script (eyfn.sh) must be run after byfn.sh is run and with the same parameters. So, valid uses include: ./byfn.sh up ./eyfn.sh up or ./byfn.sh up -c testchannel -s couchdb -l node ./eyfn.sh up -c testchannel -s couchdb -l node A single './eyfn.sh down' command is however necessary to take the whole network down. Patch-set #2: fixes ./eyfn.sh down Patch-set #3: removed unused option from Usage and spurious whitespaces Patch-set #4: added missing test file Change-Id: I9c926b52f2243dda1c5f9368112c314a6c5c6929 Signed-off-by: Arnaud J Le Hors --- first-network/byfn.sh | 2 +- first-network/docker-compose-couch-org3.yaml | 64 ++++ first-network/eyfn.sh | 310 +++++++++++++++++++ first-network/scripts/script.sh | 160 +--------- first-network/scripts/step1org3.sh | 91 ++++++ first-network/scripts/step2org3.sh | 57 ++++ first-network/scripts/step3org3.sh | 51 +++ first-network/scripts/testorg3.sh | 61 ++++ first-network/scripts/utils.sh | 190 ++++++++++++ 9 files changed, 831 insertions(+), 155 deletions(-) create mode 100644 first-network/docker-compose-couch-org3.yaml create mode 100755 first-network/eyfn.sh create mode 100755 first-network/scripts/step1org3.sh create mode 100755 first-network/scripts/step2org3.sh create mode 100755 first-network/scripts/step3org3.sh create mode 100755 first-network/scripts/testorg3.sh create mode 100755 first-network/scripts/utils.sh diff --git a/first-network/byfn.sh b/first-network/byfn.sh index c6462ed80b..6d2c16be38 100755 --- a/first-network/byfn.sh +++ b/first-network/byfn.sh @@ -341,7 +341,7 @@ else exit 1 fi -while getopts "h?c:t:d:f:s:l:a?" opt; do +while getopts "h?c:t:d:f:s:l:" opt; do case "$opt" in h|\?) printHelp diff --git a/first-network/docker-compose-couch-org3.yaml b/first-network/docker-compose-couch-org3.yaml new file mode 100644 index 0000000000..03e57ac8d7 --- /dev/null +++ b/first-network/docker-compose-couch-org3.yaml @@ -0,0 +1,64 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +version: '2' + +networks: + byfn: + +services: + couchdb4: + container_name: couchdb4 + image: hyperledger/fabric-couchdb + # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password + # for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode. + environment: + - COUCHDB_USER= + - COUCHDB_PASSWORD= + # Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service, + # for example map it to utilize Fauxton User Interface in dev environments. + ports: + - "9984:5984" + networks: + - byfn + + peer0.org3.example.com: + environment: + - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984 + # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD + # provide the credentials for ledger to connect to CouchDB. The username and password must + # match the username and password set for the associated CouchDB. + - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= + - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= + depends_on: + - couchdb4 + + couchdb5: + container_name: couchdb5 + image: hyperledger/fabric-couchdb + # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password + # for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode. + environment: + - COUCHDB_USER= + - COUCHDB_PASSWORD= + # Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service, + # for example map it to utilize Fauxton User Interface in dev environments. + ports: + - "10984:5984" + networks: + - byfn + + peer1.org3.example.com: + environment: + - CORE_LEDGER_STATE_STATEDATABASE=CouchDB + - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 + # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD + # provide the credentials for ledger to connect to CouchDB. The username and password must + # match the username and password set for the associated CouchDB. + - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= + - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= + depends_on: + - couchdb5 diff --git a/first-network/eyfn.sh b/first-network/eyfn.sh new file mode 100755 index 0000000000..e89abfcbb9 --- /dev/null +++ b/first-network/eyfn.sh @@ -0,0 +1,310 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This script extends the Hyperledger Fabric By Your First Network by +# adding a third organization to the network previously setup in the +# BYFN tutorial. +# + +# prepending $PWD/../bin to PATH to ensure we are picking up the correct binaries +# this may be commented out to resolve installed version of tools if desired +export PATH=${PWD}/../bin:${PWD}:$PATH +export FABRIC_CFG_PATH=${PWD} + +# Print the usage message +function printHelp () { + echo "Usage: " + echo " eyfn.sh up|down|restart|generate [-c ] [-t ] [-d ] [-f ] [-s ]" + echo " eyfn.sh -h|--help (print this message)" + echo " - one of 'up', 'down', 'restart' or 'generate'" + echo " - 'up' - bring up the network with docker-compose up" + echo " - 'down' - clear the network with docker-compose down" + echo " - 'restart' - restart the network" + echo " - 'generate' - generate required certificates and genesis block" + echo " -c - channel name to use (defaults to \"mychannel\")" + echo " -t - CLI timeout duration in seconds (defaults to 10)" + echo " -d - delay duration in seconds (defaults to 3)" + echo " -f - specify which docker-compose file use (defaults to docker-compose-cli.yaml)" + echo " -s - the database backend to use: goleveldb (default) or couchdb" + echo " -l - the chaincode language: golang (default) or node" + echo + echo "Typically, one would first generate the required certificates and " + echo "genesis block, then bring up the network. e.g.:" + echo + echo " eyfn.sh generate -c mychannel" + echo " eyfn.sh up -c mychannel -s couchdb" + echo " eyfn.sh up -l node" + echo " eyfn.sh down -c mychannel" + echo + echo "Taking all defaults:" + echo " eyfn.sh generate" + echo " eyfn.sh up" + echo " eyfn.sh down" +} + +# Ask user for confirmation to proceed +function askProceed () { + read -p "Continue? [Y/n] " ans + case "$ans" in + y|Y|"" ) + echo "proceeding ..." + ;; + n|N ) + echo "exiting..." + exit 1 + ;; + * ) + echo "invalid response" + askProceed + ;; + esac +} + +# Obtain CONTAINER_IDS and remove them +# TODO Might want to make this optional - could clear other containers +function clearContainers () { + CONTAINER_IDS=$(docker ps -aq) + if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then + echo "---- No containers available for deletion ----" + else + docker rm -f $CONTAINER_IDS + fi +} + +# Delete any images that were generated as a part of this setup +# specifically the following images are often left behind: +# TODO list generated image naming patterns +function removeUnwantedImages() { + DOCKER_IMAGE_IDS=$(docker images | grep "dev\|none\|test-vp\|peer[0-9]-" | awk '{print $3}') + if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then + echo "---- No images available for deletion ----" + else + docker rmi -f $DOCKER_IMAGE_IDS + fi +} + +# Generate the needed certificates, the genesis block and start the network. +function networkUp () { + # generate artifacts if they don't exist + if [ ! -d "org3-artifacts/crypto-config" ]; then + generateCerts + generateChannelArtifacts + createConfigTx + fi + # start org3 peers + if [ "${IF_COUCHDB}" == "couchdb" ]; then + docker-compose -f $COMPOSE_FILE_ORG3 -f $COMPOSE_FILE_COUCH_ORG3 up -d 2>&1 + else + docker-compose -f $COMPOSE_FILE_ORG3 up -d 2>&1 + fi + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to start Org3 network" + exit 1 + fi + echo + echo "###############################################################" + echo "############### Have Org3 peers join network ##################" + echo "###############################################################" + docker exec Org3cli ./scripts/step2org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to have Org3 peers join network" + exit 1 + fi + echo + echo "###############################################################" + echo "##### Upgrade chaincode to have Org3 peers on the network #####" + echo "###############################################################" + docker exec cli ./scripts/step3org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to add Org3 peers on network" + exit 1 + fi + # finish by running the test + docker exec Org3cli ./scripts/testorg3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to run test" + exit 1 + fi +} + +# Tear down running network +function networkDown () { + docker-compose -f $COMPOSE_FILE_ORG3 down + docker-compose -f $COMPOSE_FILE_ORG3 -f $COMPOSE_FILE_COUCH_ORG3 down + docker-compose -f $COMPOSE_FILE down + docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH down + # Don't remove containers, images, etc if restarting + if [ "$MODE" != "restart" ]; then + #Cleanup the chaincode containers + clearContainers + #Cleanup images + removeUnwantedImages + # remove orderer block and other channel configuration transactions and certs + rm -rf channel-artifacts/*.block channel-artifacts/*.tx crypto-config ./org3-artifacts/crypto-config/ channel-artifacts/org3.json + # remove the docker-compose yaml file that was customized to the example + rm -f docker-compose-e2e.yaml + fi +} + +# Use the CLI container to create the configuration transaction needed to add +# Org3 to the network +function createConfigTx () { + echo + echo "###############################################################" + echo "####### Generate and submit config tx to add Org3 #############" + echo "###############################################################" + docker exec cli scripts/step1org3.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT + if [ $? -ne 0 ]; then + echo "ERROR !!!! Unable to create config tx" + exit 1 + fi +} + +# We use the cryptogen tool to generate the cryptographic material +# (x509 certs) for the new org. After we run the tool, the certs will +# be parked in the BYFN folder titled ``crypto-config``. + +# Generates Org3 certs using cryptogen tool +function generateCerts (){ + which cryptogen + if [ "$?" -ne 0 ]; then + echo "cryptogen tool not found. exiting" + exit 1 + fi + echo + echo "###############################################################" + echo "##### Generate Org3 certificates using cryptogen tool #########" + echo "###############################################################" + + (cd org3-artifacts + cryptogen generate --config=./org3-crypto.yaml + if [ "$?" -ne 0 ]; then + echo "Failed to generate certificates..." + exit 1 + fi + ) + echo +} + +# Generate channel configuration transaction +function generateChannelArtifacts() { + which configtxgen + if [ "$?" -ne 0 ]; then + echo "configtxgen tool not found. exiting" + exit 1 + fi + echo "##########################################################" + echo "######### Generating Org3 config material ###############" + echo "##########################################################" + (cd org3-artifacts + export FABRIC_CFG_PATH=$PWD + configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json + if [ "$?" -ne 0 ]; then + echo "Failed to generate Org3 config material..." + exit 1 + fi + ) + cp -r crypto-config/ordererOrganizations org3-artifacts/crypto-config/ + echo +} + + +# If BYFN wasn't run abort +if [ ! -d crypto-config ]; then + echo + echo "ERROR: Please, run byfn.sh first." + echo + exit 1 +fi + +# Obtain the OS and Architecture string that will be used to select the correct +# native binaries for your platform +OS_ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}') +# timeout duration - the duration the CLI should wait for a response from +# another container before giving up +CLI_TIMEOUT=10 +#default for delay +CLI_DELAY=3 +# channel name defaults to "mychannel" +CHANNEL_NAME="mychannel" +# use this as the default docker-compose yaml definition +COMPOSE_FILE=docker-compose-cli.yaml +# +COMPOSE_FILE_COUCH=docker-compose-couch.yaml +# use this as the default docker-compose yaml definition +COMPOSE_FILE_ORG3=docker-compose-org3.yaml +# +COMPOSE_FILE_COUCH_ORG3=docker-compose-couch-org3.yaml +# use golang as the default language for chaincode +LANGUAGE=golang + +# Parse commandline args +if [ "$1" = "-m" ];then # supports old usage, muscle memory is powerful! + shift +fi +MODE=$1;shift +# Determine whether starting, stopping, restarting or generating for announce +if [ "$MODE" == "up" ]; then + EXPMODE="Starting" +elif [ "$MODE" == "down" ]; then + EXPMODE="Stopping" +elif [ "$MODE" == "restart" ]; then + EXPMODE="Restarting" +elif [ "$MODE" == "generate" ]; then + EXPMODE="Generating certs and genesis block for" +else + printHelp + exit 1 +fi +while getopts "h?c:t:d:f:s:l:" opt; do + case "$opt" in + h|\?) + printHelp + exit 0 + ;; + c) CHANNEL_NAME=$OPTARG + ;; + t) CLI_TIMEOUT=$OPTARG + ;; + d) CLI_DELAY=$OPTARG + ;; + f) COMPOSE_FILE=$OPTARG + ;; + s) IF_COUCHDB=$OPTARG + ;; + l) LANGUAGE=$OPTARG + ;; + esac +done + +# Announce what was requested + + if [ "${IF_COUCHDB}" == "couchdb" ]; then + echo + echo "${EXPMODE} with channel '${CHANNEL_NAME}' and CLI timeout of '${CLI_TIMEOUT}' seconds and CLI delay of '${CLI_DELAY}' seconds and using database '${IF_COUCHDB}'" + else + echo "${EXPMODE} with channel '${CHANNEL_NAME}' and CLI timeout of '${CLI_TIMEOUT}' seconds and CLI delay of '${CLI_DELAY}' seconds" + fi +# ask for confirmation to proceed +askProceed + +#Create the network using docker compose +if [ "${MODE}" == "up" ]; then + networkUp +elif [ "${MODE}" == "down" ]; then ## Clear the network + networkDown +elif [ "${MODE}" == "generate" ]; then ## Generate Artifacts + generateCerts + generateChannelArtifacts + createConfigTx +elif [ "${MODE}" == "restart" ]; then ## Restart the network + networkDown + networkUp +else + printHelp + exit 1 +fi diff --git a/first-network/scripts/script.sh b/first-network/scripts/script.sh index e1bf9cceaa..3f9953a322 100755 --- a/first-network/scripts/script.sh +++ b/first-network/scripts/script.sh @@ -12,9 +12,11 @@ echo CHANNEL_NAME="$1" DELAY="$2" LANGUAGE="$3" +TIMEOUT="$4" : ${CHANNEL_NAME:="mychannel"} -: ${TIMEOUT:="10"} +: ${DELAY:="3"} : ${LANGUAGE:="golang"} +: ${TIMEOUT:="10"} LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` COUNTER=1 MAX_RETRY=5 @@ -27,41 +29,8 @@ fi echo "Channel name : "$CHANNEL_NAME -# verify the result of the end-to-end test -verifyResult () { - if [ $1 -ne 0 ] ; then - echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!" - echo "========= ERROR !!! FAILED to execute End-2-End Scenario ===========" - echo - exit 1 - fi -} - -setGlobals () { - PEER=$1 - ORG=$2 - if [ $ORG -eq 1 ] ; then - CORE_PEER_LOCALMSPID="Org1MSP" - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - if [ $PEER -eq 0 ]; then - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - else - CORE_PEER_ADDRESS=peer1.org1.example.com:7051 - fi - elif [ $ORG -eq 2 ] ; then - CORE_PEER_LOCALMSPID="Org2MSP" - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp - if [ $PEER -eq 0 ]; then - CORE_PEER_ADDRESS=peer0.org2.example.com:7051 - else - CORE_PEER_ADDRESS=peer1.org2.example.com:7051 - fi - fi - - env |grep CORE -} +# import utils +. scripts/utils.sh createChannel() { setGlobals 0 0 @@ -78,48 +47,10 @@ createChannel() { echo } -updateAnchorPeers() { - PEER=$1 - ORG=$2 - setGlobals $PEER $ORG - - if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then - peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt - else - peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt - fi - res=$? - cat log.txt - verifyResult $res "Anchor peer update failed" - echo "===================== Anchor peers for org \"$CORE_PEER_LOCALMSPID\" on \"$CHANNEL_NAME\" is updated successfully ===================== " - sleep $DELAY - echo -} - -## Sometimes Join takes time hence RETRY at least for 5 times -joinWithRetry () { - PEER=$1 - ORG=$2 - - peer channel join -b $CHANNEL_NAME.block >&log.txt - res=$? - cat log.txt - if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then - COUNTER=` expr $COUNTER + 1` - echo "peer${PEER}.org${ORG} failed to join the channel, Retry after $DELAY seconds" - sleep $DELAY - joinWithRetry $PEER $ORG - else - COUNTER=1 - fi - verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to Join the Channel" -} - joinChannel () { for org in 1 2; do for peer in 0 1; do - setGlobals $peer $org - joinWithRetry $peer $org + joinChannelWithRetry $peer $org echo "===================== peer${peer}.org${org} joined on the channel \"$CHANNEL_NAME\" ===================== " sleep $DELAY echo @@ -127,85 +58,6 @@ joinChannel () { done } -installChaincode () { - PEER=$1 - ORG=$2 - setGlobals $PEER $ORG - peer chaincode install -n mycc -v 1.0 -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt - res=$? - cat log.txt - verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has Failed" - echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== " - echo -} - -instantiateChaincode () { - PEER=$1 - ORG=$2 - setGlobals $PEER $ORG - # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful), - # lets supply it directly as we know it using the "-o" option - if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then - peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt - else - peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt - fi - res=$? - cat log.txt - verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed" - echo "===================== Chaincode Instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " - echo -} - -chaincodeQuery () { - PEER=$1 - ORG=$2 - setGlobals $PEER $ORG - EXPECTED_RESULT=$3 - echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== " - local rc=1 - local starttime=$(date +%s) - - # continue to poll - # we either get a successful response, or reach TIMEOUT - while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0 - do - sleep $DELAY - echo "Attempting to Query peer${PEER}.org${ORG} ...$(($(date +%s)-starttime)) secs" - peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt - test $? -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}') - test "$VALUE" = "$EXPECTED_RESULT" && let rc=0 - done - echo - cat log.txt - if test $rc -eq 0 ; then - echo "===================== Query on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " - else - echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!" - echo "================== ERROR !!! FAILED to execute End-2-End Scenario ==================" - echo - exit 1 - fi -} - -chaincodeInvoke () { - PEER=$1 - ORG=$2 - setGlobals $PEER $ORG - # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful), - # lets supply it directly as we know it using the "-o" option - if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then - peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt - else - peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt - fi - res=$? - cat log.txt - verifyResult $res "Invoke execution on peer${PEER}.org${ORG} failed " - echo "===================== Invoke transaction on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " - echo -} - ## Create channel echo "Creating channel..." createChannel diff --git a/first-network/scripts/step1org3.sh b/first-network/scripts/step1org3.sh new file mode 100755 index 0000000000..c2aa326504 --- /dev/null +++ b/first-network/scripts/step1org3.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This script is designed to be run in the org3cli container as the +# first step of the EYFN tutorial. It creates and submits a +# configuration transaction to add org3 to the network previously +# setup in the BYFN tutorial. +# + +CHANNEL_NAME="$1" +DELAY="$2" +LANGUAGE="$3" +TIMEOUT="$4" +: ${CHANNEL_NAME:="mychannel"} +: ${DELAY:="3"} +: ${LANGUAGE:="golang"} +: ${TIMEOUT:="10"} +LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` +COUNTER=1 +MAX_RETRY=5 +ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem + +CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" +if [ "$LANGUAGE" = "node" ]; then + CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" +fi + +echo +echo "========= Creating config transaction to add org3 to network =========== " +echo + +echo "Installing and starting configtxlater" +apt-get -y update && apt-get -y install jq +configtxlator start >/dev/null 2>&1 & +CONFIGTXLATOR_URL=http://127.0.0.1:7059 + +echo "Fetching the most recent configuration block for the channel" +peer channel fetch config config_block.pb -o orderer.example.com:7050 -c ${CHANNEL_NAME} --tls --cafile ${ORDERER_CA} + +echo "Creating config transaction adding org3 to the network" +# translate channel configuration block into JSON format +curl -X POST --data-binary @config_block.pb "$CONFIGTXLATOR_URL/protolator/decode/common.Block" | jq . > config_block.json + +# strip away all of the encapsulating wrappers +jq .data.data[0].payload.data.config config_block.json > config.json + +# append new org to the configuration +jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ./channel-artifacts/org3.json >& updated_config.json + +# translate json config files back to protobuf +curl -X POST --data-binary @config.json "$CONFIGTXLATOR_URL/protolator/encode/common.Config" > config.pb +curl -X POST --data-binary @updated_config.json "$CONFIGTXLATOR_URL/protolator/encode/common.Config" > updated_config.pb + +# get delta between old and new configs +curl -X POST -F channel=${CHANNEL_NAME} -F "original=@config.pb" -F "updated=@updated_config.pb" "${CONFIGTXLATOR_URL}/configtxlator/compute/update-from-configs" > org3_update.pb + +# translate protobuf delta to json +curl -X POST --data-binary @org3_update.pb "$CONFIGTXLATOR_URL/protolator/decode/common.ConfigUpdate" | jq . > org3_update.json + +# wrap delta in an envelope message +echo '{"payload":{"header":{"channel_header":{"channel_id":"'${CHANNEL_NAME}'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json + +# translate json back to protobuf +curl -X POST --data-binary @org3_update_in_envelope.json "$CONFIGTXLATOR_URL/protolator/encode/common.Envelope" > org3_update_in_envelope.pb + +echo +echo "========= Config transaction to add org3 to network created ===== " +echo + +echo "Signing config transaction" +echo +peer channel signconfigtx -f org3_update_in_envelope.pb + +echo +echo "========= Submitting transaction from a different peer (peer0.org2) which also signs it ========= " +echo +export CORE_PEER_LOCALMSPID="Org2MSP" +export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt +export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp +export CORE_PEER_ADDRESS=peer0.org2.example.com:7051 +peer channel update -f org3_update_in_envelope.pb -c ${CHANNEL_NAME} -o orderer.example.com:7050 --tls --cafile ${ORDERER_CA} + +echo +echo "========= Config transaction to add org3 to network submitted! =========== " +echo + +exit 0 diff --git a/first-network/scripts/step2org3.sh b/first-network/scripts/step2org3.sh new file mode 100755 index 0000000000..b5ccb36170 --- /dev/null +++ b/first-network/scripts/step2org3.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This script is designed to be run in the org3cli container as the +# second step of the EYFN tutorial. It joins the org3 peers to the +# channel previously setup in the BYFN tutorial and install the +# chaincode as version 2.0 on peer0.org3. +# + +echo +echo "========= Getting Org3 on to your first network ========= " +echo +CHANNEL_NAME="$1" +DELAY="$2" +LANGUAGE="$3" +TIMEOUT="$4" +: ${CHANNEL_NAME:="mychannel"} +: ${DELAY:="3"} +: ${LANGUAGE:="golang"} +: ${TIMEOUT:="10"} +LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` +COUNTER=1 +MAX_RETRY=5 +ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem + +CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" +if [ "$LANGUAGE" = "node" ]; then + CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" +fi + +# import utils +. scripts/utils.sh + +echo "Fetching channel config block from orderer..." +peer channel fetch 0 $CHANNEL_NAME.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA >&log.txt +res=$? +cat log.txt +verifyResult $res "Fetching config block from orderer has Failed" + +echo "===================== Having peer0.org3 join the channel ===================== " +joinChannelWithRetry 0 3 +echo "===================== peer0.org3 joined the channel \"$CHANNEL_NAME\" ===================== " +echo "===================== Having peer1.org3 join the channel ===================== " +joinChannelWithRetry 1 3 +echo "===================== peer1.org3 joined the channel \"$CHANNEL_NAME\" ===================== " +echo "Installing chaincode 2.0 on peer0.org3..." +installChaincode 0 3 2.0 + +echo +echo "========= Got Org3 halfway onto your first network ========= " +echo + +exit 0 diff --git a/first-network/scripts/step3org3.sh b/first-network/scripts/step3org3.sh new file mode 100755 index 0000000000..585fa203f0 --- /dev/null +++ b/first-network/scripts/step3org3.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This script is designed to be run in the cli container as the third +# step of the EYFN tutorial. It installs the chaincode as version 2.0 +# on peer0.org1 and peer0.org2, and uprage the chaincode on the +# channel to version 2.0, thus completing the addition of org3 to the +# network previously setup in the BYFN tutorial. +# + +echo +echo "========= Finish adding Org3 to your first network ========= " +echo +CHANNEL_NAME="$1" +DELAY="$2" +LANGUAGE="$3" +TIMEOUT="$4" +: ${CHANNEL_NAME:="mychannel"} +: ${DELAY:="3"} +: ${LANGUAGE:="golang"} +: ${TIMEOUT:="10"} +LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` +COUNTER=1 +MAX_RETRY=5 +ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem + +CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" +if [ "$LANGUAGE" = "node" ]; then + CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" +fi + +# import utils +. scripts/utils.sh + +echo "===================== Installing chaincode 2.0 on peer0.org1 ===================== " +installChaincode 0 1 2.0 +echo "===================== Installing chaincode 2.0 on peer0.org2 ===================== " +installChaincode 0 2 2.0 + +echo "===================== Upgrading chaincode on peer0.org1 ===================== " +upgradeChaincode 0 1 + +echo +echo "========= Finished adding Org3 to your first network! ========= " +echo + +exit 0 diff --git a/first-network/scripts/testorg3.sh b/first-network/scripts/testorg3.sh new file mode 100755 index 0000000000..1668f45efb --- /dev/null +++ b/first-network/scripts/testorg3.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This script is designed to be run in the org3cli container as the +# final step of the EYFN tutorial. It simply issues a couple of +# chaincode requests through the org3 peers to check that org3 was +# properly added to the network previously setup in the BYFN tutorial. +# + +echo +echo " ____ _____ _ ____ _____ " +echo "/ ___| |_ _| / \ | _ \ |_ _|" +echo "\___ \ | | / _ \ | |_) | | | " +echo " ___) | | | / ___ \ | _ < | | " +echo "|____/ |_| /_/ \_\ |_| \_\ |_| " +echo +echo "Extend your first network (EYFN) test" +echo +CHANNEL_NAME="$1" +DELAY="$2" +LANGUAGE="$3" +TIMEOUT="$4" +: ${CHANNEL_NAME:="mychannel"} +: ${TIMEOUT:="10"} +: ${LANGUAGE:="golang"} +LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]` +COUNTER=1 +MAX_RETRY=5 +ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem + +CC_SRC_PATH="github.com/chaincode/chaincode_example02/go/" +if [ "$LANGUAGE" = "node" ]; then + CC_SRC_PATH="/opt/gopath/src/github.com/chaincode/chaincode_example02/node/" +fi + +echo "Channel name : "$CHANNEL_NAME + +# import functions +. scripts/utils.sh + +chaincodeQuery 0 3 90 +chaincodeInvoke 0 3 +chaincodeQuery 0 3 80 + +echo +echo "========= All GOOD, EYFN test execution completed =========== " +echo + +echo +echo " _____ _ _ ____ " +echo "| ____| | \ | | | _ \ " +echo "| _| | \| | | | | | " +echo "| |___ | |\ | | |_| | " +echo "|_____| |_| \_| |____/ " +echo + +exit 0 diff --git a/first-network/scripts/utils.sh b/first-network/scripts/utils.sh new file mode 100755 index 0000000000..12d07327cc --- /dev/null +++ b/first-network/scripts/utils.sh @@ -0,0 +1,190 @@ +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +# This is a collection of bash functions used by different scripts + + +# verify the result of the end-to-end test +verifyResult () { + if [ $1 -ne 0 ] ; then + echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!" + echo "========= ERROR !!! FAILED to execute End-2-End Scenario ===========" + echo + exit 1 + fi +} + +setGlobals () { + PEER=$1 + ORG=$2 + if [ $ORG -eq 1 ] ; then + CORE_PEER_LOCALMSPID="Org1MSP" + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + if [ $PEER -eq 0 ]; then + CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + else + CORE_PEER_ADDRESS=peer1.org1.example.com:7051 + fi + elif [ $ORG -eq 2 ] ; then + CORE_PEER_LOCALMSPID="Org2MSP" + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp + if [ $PEER -eq 0 ]; then + CORE_PEER_ADDRESS=peer0.org2.example.com:7051 + else + CORE_PEER_ADDRESS=peer1.org2.example.com:7051 + fi + + elif [ $ORG -eq 3 ] ; then + CORE_PEER_LOCALMSPID="Org3MSP" + CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt + CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp + if [ $PEER -eq 0 ]; then + CORE_PEER_ADDRESS=peer0.org3.example.com:7051 + else + CORE_PEER_ADDRESS=peer1.org3.example.com:7051 + fi + else + echo "================== ERROR !!! ORG Unknown ==================" + fi + + env |grep CORE +} + + +updateAnchorPeers() { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt + else + peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Anchor peer update failed" + echo "===================== Anchor peers for org \"$CORE_PEER_LOCALMSPID\" on \"$CHANNEL_NAME\" is updated successfully ===================== " + sleep $DELAY + echo +} + +## Sometimes Join takes time hence RETRY at least for 5 times +joinChannelWithRetry () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + + peer channel join -b $CHANNEL_NAME.block >&log.txt + res=$? + cat log.txt + if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then + COUNTER=` expr $COUNTER + 1` + echo "peer${PEER}.org${ORG} failed to join the channel, Retry after $DELAY seconds" + sleep $DELAY + joinChannelWithRetry $PEER $ORG + else + COUNTER=1 + fi + verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to Join the Channel" +} + +installChaincode () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + VERSION=${3:-1.0} + peer chaincode install -n mycc -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt + res=$? + cat log.txt + verifyResult $res "Chaincode installation on peer${PEER}.org${ORG} has Failed" + echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== " + echo +} + +instantiateChaincode () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + VERSION=${3:-1.0} + + # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful), + # lets supply it directly as we know it using the "-o" option + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v ${VERSION} -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt + else + peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed" + echo "===================== Chaincode Instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " + echo +} + +upgradeChaincode () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + + peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a","90","b","210"]}' -P "OR ('Org1MSP.member','Org2MSP.member','Org3MSP.member')" + res=$? + cat log.txt + verifyResult $res "Chaincode upgrade on org${ORG} peer${PEER} has Failed" + echo "===================== Chaincode is upgraded on org${ORG} peer${PEER} ===================== " + echo +} + +chaincodeQuery () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + EXPECTED_RESULT=$3 + echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== " + local rc=1 + local starttime=$(date +%s) + + # continue to poll + # we either get a successful response, or reach TIMEOUT + while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0 + do + sleep $DELAY + echo "Attempting to Query peer${PEER}.org${ORG} ...$(($(date +%s)-starttime)) secs" + peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt + test $? -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}') + test "$VALUE" = "$EXPECTED_RESULT" && let rc=0 + done + echo + cat log.txt + if test $rc -eq 0 ; then + echo "===================== Query on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " + else + echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!" + echo "================== ERROR !!! FAILED to execute End-2-End Scenario ==================" + echo + exit 1 + fi +} + +chaincodeInvoke () { + PEER=$1 + ORG=$2 + setGlobals $PEER $ORG + # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful), + # lets supply it directly as we know it using the "-o" option + if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then + peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt + else + peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt + fi + res=$? + cat log.txt + verifyResult $res "Invoke execution on peer${PEER}.org${ORG} failed " + echo "===================== Invoke transaction on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' is successful ===================== " + echo +}