mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
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 <lehors@us.ibm.com>
391 lines
15 KiB
Bash
Executable file
391 lines
15 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# Copyright IBM Corp All Rights Reserved
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
# This script will orchestrate a sample end-to-end execution of the Hyperledger
|
|
# Fabric network.
|
|
#
|
|
# The end-to-end verification provisions a sample Fabric network consisting of
|
|
# two organizations, each maintaining two peers, and a “solo” ordering service.
|
|
#
|
|
# This verification makes use of two fundamental tools, which are necessary to
|
|
# create a functioning transactional network with digital signature validation
|
|
# and access control:
|
|
#
|
|
# * cryptogen - generates the x509 certificates used to identify and
|
|
# authenticate the various components in the network.
|
|
# * configtxgen - generates the requisite configuration artifacts for orderer
|
|
# bootstrap and channel creation.
|
|
#
|
|
# Each tool consumes a configuration yaml file, within which we specify the topology
|
|
# of our network (cryptogen) and the location of our certificates for various
|
|
# configuration operations (configtxgen). Once the tools have been successfully run,
|
|
# we are able to launch our network. More detail on the tools and the structure of
|
|
# the network will be provided later in this document. For now, let's get going...
|
|
|
|
# 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 " byfn.sh up|down|restart|generate [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>]"
|
|
echo " byfn.sh -h|--help (print this message)"
|
|
echo " <mode> - 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> - channel name to use (defaults to \"mychannel\")"
|
|
echo " -t <timeout> - CLI timeout duration in seconds (defaults to 10)"
|
|
echo " -d <delay> - delay duration in seconds (defaults to 3)"
|
|
echo " -f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
|
|
echo " -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
|
|
echo " -l <language> - 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 " byfn.sh generate -c mychannel"
|
|
echo " byfn.sh up -c mychannel -s couchdb"
|
|
echo " byfn.sh up -l node"
|
|
echo " byfn.sh down -c mychannel"
|
|
echo
|
|
echo "Taking all defaults:"
|
|
echo " byfn.sh generate"
|
|
echo " byfn.sh up"
|
|
echo " byfn.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 "crypto-config" ]; then
|
|
generateCerts
|
|
replacePrivateKey
|
|
generateChannelArtifacts
|
|
fi
|
|
if [ "${IF_COUCHDB}" == "couchdb" ]; then
|
|
docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1
|
|
else
|
|
docker-compose -f $COMPOSE_FILE up -d 2>&1
|
|
fi
|
|
if [ $? -ne 0 ]; then
|
|
echo "ERROR !!!! Unable to start network"
|
|
exit 1
|
|
fi
|
|
# now run the end to end script
|
|
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT
|
|
if [ $? -ne 0 ]; then
|
|
echo "ERROR !!!! Test failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Tear down running network
|
|
function networkDown () {
|
|
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
|
|
}
|
|
|
|
# Using docker-compose-e2e-template.yaml, replace constants with private key file names
|
|
# generated by the cryptogen tool and output a docker-compose.yaml specific to this
|
|
# configuration
|
|
function replacePrivateKey () {
|
|
# sed on MacOSX does not support -i flag with a null extension. We will use
|
|
# 't' for our back-up's extension and depete it at the end of the function
|
|
ARCH=`uname -s | grep Darwin`
|
|
if [ "$ARCH" == "Darwin" ]; then
|
|
OPTS="-it"
|
|
else
|
|
OPTS="-i"
|
|
fi
|
|
|
|
# Copy the template to the file that will be modified to add the private key
|
|
cp docker-compose-e2e-template.yaml docker-compose-e2e.yaml
|
|
|
|
# The next steps will replace the template's contents with the
|
|
# actual values of the private key file names for the two CAs.
|
|
CURRENT_DIR=$PWD
|
|
cd crypto-config/peerOrganizations/org1.example.com/ca/
|
|
PRIV_KEY=$(ls *_sk)
|
|
cd "$CURRENT_DIR"
|
|
sed $OPTS "s/CA1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
|
|
cd crypto-config/peerOrganizations/org2.example.com/ca/
|
|
PRIV_KEY=$(ls *_sk)
|
|
cd "$CURRENT_DIR"
|
|
sed $OPTS "s/CA2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
|
|
# If MacOSX, remove the temporary backup of the docker-compose file
|
|
if [ "$ARCH" == "Darwin" ]; then
|
|
rm docker-compose-e2e.yamlt
|
|
fi
|
|
}
|
|
|
|
# We will use the cryptogen tool to generate the cryptographic material (x509 certs)
|
|
# for our various network entities. The certificates are based on a standard PKI
|
|
# implementation where validation is achieved by reaching a common trust anchor.
|
|
#
|
|
# Cryptogen consumes a file - ``crypto-config.yaml`` - that contains the network
|
|
# topology and allows us to generate a library of certificates for both the
|
|
# Organizations and the components that belong to those Organizations. Each
|
|
# Organization is provisioned a unique root certificate (``ca-cert``), that binds
|
|
# specific components (peers and orderers) to that Org. Transactions and communications
|
|
# within Fabric are signed by an entity's private key (``keystore``), and then verified
|
|
# by means of a public key (``signcerts``). You will notice a "count" variable within
|
|
# this file. We use this to specify the number of peers per Organization; in our
|
|
# case it's two peers per Org. The rest of this template is extremely
|
|
# self-explanatory.
|
|
#
|
|
# After we run the tool, the certs will be parked in a folder titled ``crypto-config``.
|
|
|
|
# Generates Org 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 certificates using cryptogen tool #########"
|
|
echo "##########################################################"
|
|
|
|
if [ -d "crypto-config" ]; then
|
|
rm -Rf crypto-config
|
|
fi
|
|
cryptogen generate --config=./crypto-config.yaml
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate certificates..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
}
|
|
|
|
# The `configtxgen tool is used to create four artifacts: orderer **bootstrap
|
|
# block**, fabric **channel configuration transaction**, and two **anchor
|
|
# peer transactions** - one for each Peer Org.
|
|
#
|
|
# The orderer block is the genesis block for the ordering service, and the
|
|
# channel transaction file is broadcast to the orderer at channel creation
|
|
# time. The anchor peer transactions, as the name might suggest, specify each
|
|
# Org's anchor peer on this channel.
|
|
#
|
|
# Configtxgen consumes a file - ``configtx.yaml`` - that contains the definitions
|
|
# for the sample network. There are three members - one Orderer Org (``OrdererOrg``)
|
|
# and two Peer Orgs (``Org1`` & ``Org2``) each managing and maintaining two peer nodes.
|
|
# This file also specifies a consortium - ``SampleConsortium`` - consisting of our
|
|
# two Peer Orgs. Pay specific attention to the "Profiles" section at the top of
|
|
# this file. You will notice that we have two unique headers. One for the orderer genesis
|
|
# block - ``TwoOrgsOrdererGenesis`` - and one for our channel - ``TwoOrgsChannel``.
|
|
# These headers are important, as we will pass them in as arguments when we create
|
|
# our artifacts. This file also contains two additional specifications that are worth
|
|
# noting. Firstly, we specify the anchor peers for each Peer Org
|
|
# (``peer0.org1.example.com`` & ``peer0.org2.example.com``). Secondly, we point to
|
|
# the location of the MSP directory for each member, in turn allowing us to store the
|
|
# root certificates for each Org in the orderer genesis block. This is a critical
|
|
# concept. Now any network entity communicating with the ordering service can have
|
|
# its digital signature verified.
|
|
#
|
|
# This function will generate the crypto material and our four configuration
|
|
# artifacts, and subsequently output these files into the ``channel-artifacts``
|
|
# folder.
|
|
#
|
|
# If you receive the following warning, it can be safely ignored:
|
|
#
|
|
# [bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.
|
|
#
|
|
# You can ignore the logs regarding intermediate certs, we are not using them in
|
|
# this crypto implementation.
|
|
|
|
# Generate orderer genesis block, channel configuration transaction and
|
|
# anchor peer update transactions
|
|
function generateChannelArtifacts() {
|
|
which configtxgen
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "configtxgen tool not found. exiting"
|
|
exit 1
|
|
fi
|
|
|
|
echo "##########################################################"
|
|
echo "######### Generating Orderer Genesis block ##############"
|
|
echo "##########################################################"
|
|
# Note: For some unknown reason (at least for now) the block file can't be
|
|
# named orderer.genesis.block or the orderer will fail to launch!
|
|
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate orderer genesis block..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
echo "#################################################################"
|
|
echo "### Generating channel configuration transaction 'channel.tx' ###"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate channel configuration transaction..."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "#################################################################"
|
|
echo "####### Generating anchor peer update for Org1MSP ##########"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate anchor peer update for Org1MSP..."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "#################################################################"
|
|
echo "####### Generating anchor peer update for Org2MSP ##########"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate \
|
|
./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate anchor peer update for Org2MSP..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
}
|
|
|
|
# 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 between commands
|
|
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 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
|
|
replacePrivateKey
|
|
generateChannelArtifacts
|
|
elif [ "${MODE}" == "restart" ]; then ## Restart the network
|
|
networkDown
|
|
networkUp
|
|
else
|
|
printHelp
|
|
exit 1
|
|
fi
|