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 +}