mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
FAB-4073 build your first network sample
address review comments Change-Id: Ia2382005d4503f9dc7ba845a2d04f36237316cde Signed-off-by: Christopher Ferris <chrisfer@us.ibm.com>
This commit is contained in:
parent
54cae68bc4
commit
3297865248
12 changed files with 1352 additions and 0 deletions
4
first-network/README.md
Normal file
4
first-network/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
## Build Your First Network (BYFN)
|
||||||
|
|
||||||
|
The directions for using this are documented in the Hyperledger Fabric
|
||||||
|
["Build Your First Network"](http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html) tutorial.
|
||||||
108
first-network/base/docker-compose-base.yaml
Normal file
108
first-network/base/docker-compose-base.yaml
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
orderer.example.com:
|
||||||
|
container_name: orderer.example.com
|
||||||
|
image: hyperledger/fabric-orderer
|
||||||
|
environment:
|
||||||
|
- ORDERER_GENERAL_LOGLEVEL=debug
|
||||||
|
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
|
||||||
|
- ORDERER_GENERAL_GENESISMETHOD=file
|
||||||
|
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
|
||||||
|
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
|
||||||
|
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
|
||||||
|
# enabled TLS
|
||||||
|
- ORDERER_GENERAL_TLS_ENABLED=true
|
||||||
|
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
|
||||||
|
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
|
||||||
|
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
|
||||||
|
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
|
||||||
|
command: orderer
|
||||||
|
volumes:
|
||||||
|
- ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
|
||||||
|
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
|
||||||
|
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
|
||||||
|
ports:
|
||||||
|
- 7050:7050
|
||||||
|
|
||||||
|
peer0.org1.example.com:
|
||||||
|
container_name: peer0.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: peer-base.yaml
|
||||||
|
service: peer-base
|
||||||
|
environment:
|
||||||
|
- CORE_PEER_ID=peer0.org1.example.com
|
||||||
|
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
|
||||||
|
- CORE_PEER_LOCALMSPID=Org1MSP
|
||||||
|
volumes:
|
||||||
|
- /var/run/:/host/var/run/
|
||||||
|
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
|
||||||
|
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
|
||||||
|
ports:
|
||||||
|
- 7051:7051
|
||||||
|
- 7053:7053
|
||||||
|
|
||||||
|
peer1.org1.example.com:
|
||||||
|
container_name: peer1.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: peer-base.yaml
|
||||||
|
service: peer-base
|
||||||
|
environment:
|
||||||
|
- CORE_PEER_ID=peer1.org1.example.com
|
||||||
|
- CORE_PEER_ADDRESS=peer1.org1.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
|
||||||
|
- CORE_PEER_LOCALMSPID=Org1MSP
|
||||||
|
volumes:
|
||||||
|
- /var/run/:/host/var/run/
|
||||||
|
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
|
||||||
|
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- 8051:7051
|
||||||
|
- 8053:7053
|
||||||
|
|
||||||
|
peer0.org2.example.com:
|
||||||
|
container_name: peer0.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: peer-base.yaml
|
||||||
|
service: peer-base
|
||||||
|
environment:
|
||||||
|
- CORE_PEER_ID=peer0.org2.example.com
|
||||||
|
- CORE_PEER_ADDRESS=peer0.org2.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051
|
||||||
|
- CORE_PEER_LOCALMSPID=Org2MSP
|
||||||
|
volumes:
|
||||||
|
- /var/run/:/host/var/run/
|
||||||
|
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
|
||||||
|
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
|
||||||
|
ports:
|
||||||
|
- 9051:7051
|
||||||
|
- 9053:7053
|
||||||
|
|
||||||
|
peer1.org2.example.com:
|
||||||
|
container_name: peer1.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: peer-base.yaml
|
||||||
|
service: peer-base
|
||||||
|
environment:
|
||||||
|
- CORE_PEER_ID=peer1.org2.example.com
|
||||||
|
- CORE_PEER_ADDRESS=peer1.org2.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051
|
||||||
|
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051
|
||||||
|
- CORE_PEER_LOCALMSPID=Org2MSP
|
||||||
|
volumes:
|
||||||
|
- /var/run/:/host/var/run/
|
||||||
|
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
|
||||||
|
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
|
||||||
|
ports:
|
||||||
|
- 10051:7051
|
||||||
|
- 10053:7053
|
||||||
26
first-network/base/peer-base.yaml
Normal file
26
first-network/base/peer-base.yaml
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
peer-base:
|
||||||
|
image: hyperledger/fabric-peer
|
||||||
|
environment:
|
||||||
|
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||||
|
# the following setting starts chaincode containers on the same
|
||||||
|
# bridge network as the peers
|
||||||
|
# https://docs.docker.com/compose/networking/
|
||||||
|
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=byfn_default
|
||||||
|
#- CORE_LOGGING_LEVEL=ERROR
|
||||||
|
- CORE_LOGGING_LEVEL=DEBUG
|
||||||
|
- CORE_PEER_TLS_ENABLED=true
|
||||||
|
- CORE_PEER_GOSSIP_USELEADERELECTION=true
|
||||||
|
- CORE_PEER_GOSSIP_ORGLEADER=false
|
||||||
|
- CORE_PEER_PROFILE_ENABLED=true
|
||||||
|
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
|
||||||
|
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
|
||||||
|
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
|
||||||
|
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
|
||||||
|
command: peer node start
|
||||||
342
first-network/byfn.sh
Executable file
342
first-network/byfn.sh
Executable file
|
|
@ -0,0 +1,342 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Print the usage message
|
||||||
|
function printHelp () {
|
||||||
|
echo "Usage: "
|
||||||
|
echo " byfn.sh -m up|down|restart|generate [-c <channel name>] [-t <timeout>]"
|
||||||
|
echo " byfn.sh -h|--help (print this message)"
|
||||||
|
echo " -m <mode> - one of 'up', 'down', 'restart' or 'generate'"
|
||||||
|
echo " - 'up' - bring up the network with docker-compose up"
|
||||||
|
echo " - 'down' - bring up the network with docker-compose up"
|
||||||
|
echo " - 'restart' - bring up the network with docker-compose up"
|
||||||
|
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 microseconds (defaults to 10000)"
|
||||||
|
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 -m generate -c <channelname>"
|
||||||
|
echo " byfn.sh -m up -c <channelname>"
|
||||||
|
echo " byfn.sh -m down -c <channelname>"
|
||||||
|
echo
|
||||||
|
echo "Taking all defaults:"
|
||||||
|
echo " byfn.sh -m generate"
|
||||||
|
echo " byfn.sh -m up"
|
||||||
|
echo " byfn.sh -m 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"
|
||||||
|
proceed
|
||||||
|
;;
|
||||||
|
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 () {
|
||||||
|
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT docker-compose -f $COMPOSE_FILE up -d 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR !!!! Unable to start network"
|
||||||
|
docker logs -f cli
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
docker logs -f cli
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tear down running network
|
||||||
|
function networkDown () {
|
||||||
|
docker-compose -f $COMPOSE_FILE 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
|
||||||
|
# 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 "##########################################################"
|
||||||
|
|
||||||
|
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=10000
|
||||||
|
# channel name defaults to "mychannel"
|
||||||
|
CHANNEL_NAME="mychannel"
|
||||||
|
# use this as the default docker-compose yaml definition
|
||||||
|
COMPOSE_FILE=docker-compose-cli.yaml
|
||||||
|
|
||||||
|
# Parse commandline args
|
||||||
|
while getopts "h?m:c:t:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
h|\?)
|
||||||
|
printHelp
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
m) MODE=$OPTARG
|
||||||
|
;;
|
||||||
|
c) CHANNEL_NAME=$OPTARG
|
||||||
|
;;
|
||||||
|
t) CLI_TIMEOUT=$OPTARG
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Announce what was requested
|
||||||
|
echo "${EXPMODE} with channel '${CHANNEL_NAME}' and CLI timeout of '${CLI_TIMEOUT}'"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
Copyright IBM Corp. 2016 All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
|
||||||
|
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
|
||||||
|
//to be modified as well with the new ID of chaincode_example02.
|
||||||
|
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
|
||||||
|
//hard-coding.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hyperledger/fabric/core/chaincode/shim"
|
||||||
|
pb "github.com/hyperledger/fabric/protos/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SimpleChaincode example simple Chaincode implementation
|
||||||
|
type SimpleChaincode struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
|
||||||
|
fmt.Println("ex02 Init")
|
||||||
|
_, args := stub.GetFunctionAndParameters()
|
||||||
|
var A, B string // Entities
|
||||||
|
var Aval, Bval int // Asset holdings
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(args) != 4 {
|
||||||
|
return shim.Error("Incorrect number of arguments. Expecting 4")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the chaincode
|
||||||
|
A = args[0]
|
||||||
|
Aval, err = strconv.Atoi(args[1])
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Expecting integer value for asset holding")
|
||||||
|
}
|
||||||
|
B = args[2]
|
||||||
|
Bval, err = strconv.Atoi(args[3])
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Expecting integer value for asset holding")
|
||||||
|
}
|
||||||
|
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
|
||||||
|
|
||||||
|
// Write the state to the ledger
|
||||||
|
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return shim.Success(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
|
||||||
|
fmt.Println("ex02 Invoke")
|
||||||
|
function, args := stub.GetFunctionAndParameters()
|
||||||
|
if function == "invoke" {
|
||||||
|
// Make payment of X units from A to B
|
||||||
|
return t.invoke(stub, args)
|
||||||
|
} else if function == "delete" {
|
||||||
|
// Deletes an entity from its state
|
||||||
|
return t.delete(stub, args)
|
||||||
|
} else if function == "query" {
|
||||||
|
// the old "Query" is now implemtned in invoke
|
||||||
|
return t.query(stub, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction makes payment of X units from A to B
|
||||||
|
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||||
|
var A, B string // Entities
|
||||||
|
var Aval, Bval int // Asset holdings
|
||||||
|
var X int // Transaction value
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(args) != 3 {
|
||||||
|
return shim.Error("Incorrect number of arguments. Expecting 3")
|
||||||
|
}
|
||||||
|
|
||||||
|
A = args[0]
|
||||||
|
B = args[1]
|
||||||
|
|
||||||
|
// Get the state from the ledger
|
||||||
|
// TODO: will be nice to have a GetAllState call to ledger
|
||||||
|
Avalbytes, err := stub.GetState(A)
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Failed to get state")
|
||||||
|
}
|
||||||
|
if Avalbytes == nil {
|
||||||
|
return shim.Error("Entity not found")
|
||||||
|
}
|
||||||
|
Aval, _ = strconv.Atoi(string(Avalbytes))
|
||||||
|
|
||||||
|
Bvalbytes, err := stub.GetState(B)
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Failed to get state")
|
||||||
|
}
|
||||||
|
if Bvalbytes == nil {
|
||||||
|
return shim.Error("Entity not found")
|
||||||
|
}
|
||||||
|
Bval, _ = strconv.Atoi(string(Bvalbytes))
|
||||||
|
|
||||||
|
// Perform the execution
|
||||||
|
X, err = strconv.Atoi(args[2])
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Invalid transaction amount, expecting a integer value")
|
||||||
|
}
|
||||||
|
Aval = Aval - X
|
||||||
|
Bval = Bval + X
|
||||||
|
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
|
||||||
|
|
||||||
|
// Write the state back to the ledger
|
||||||
|
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return shim.Success(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes an entity from state
|
||||||
|
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return shim.Error("Incorrect number of arguments. Expecting 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
A := args[0]
|
||||||
|
|
||||||
|
// Delete the key from the state in ledger
|
||||||
|
err := stub.DelState(A)
|
||||||
|
if err != nil {
|
||||||
|
return shim.Error("Failed to delete state")
|
||||||
|
}
|
||||||
|
|
||||||
|
return shim.Success(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// query callback representing the query of a chaincode
|
||||||
|
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||||
|
var A string // Entities
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(args) != 1 {
|
||||||
|
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
|
||||||
|
}
|
||||||
|
|
||||||
|
A = args[0]
|
||||||
|
|
||||||
|
// Get the state from the ledger
|
||||||
|
Avalbytes, err := stub.GetState(A)
|
||||||
|
if err != nil {
|
||||||
|
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
|
||||||
|
return shim.Error(jsonResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Avalbytes == nil {
|
||||||
|
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
|
||||||
|
return shim.Error(jsonResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
|
||||||
|
fmt.Printf("Query Response:%s\n", jsonResp)
|
||||||
|
return shim.Success(Avalbytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := shim.Start(new(SimpleChaincode))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error starting Simple chaincode: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
0
first-network/channel-artifacts/.gitkeep
Normal file
0
first-network/channel-artifacts/.gitkeep
Normal file
149
first-network/configtx.yaml
Normal file
149
first-network/configtx.yaml
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
---
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Profile
|
||||||
|
#
|
||||||
|
# - Different configuration profiles may be encoded here to be specified
|
||||||
|
# as parameters to the configtxgen tool
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
Profiles:
|
||||||
|
|
||||||
|
TwoOrgsOrdererGenesis:
|
||||||
|
Orderer:
|
||||||
|
<<: *OrdererDefaults
|
||||||
|
Organizations:
|
||||||
|
- *OrdererOrg
|
||||||
|
Consortiums:
|
||||||
|
SampleConsortium:
|
||||||
|
Organizations:
|
||||||
|
- *Org1
|
||||||
|
- *Org2
|
||||||
|
TwoOrgsChannel:
|
||||||
|
Consortium: SampleConsortium
|
||||||
|
Application:
|
||||||
|
<<: *ApplicationDefaults
|
||||||
|
Organizations:
|
||||||
|
- *Org1
|
||||||
|
- *Org2
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Section: Organizations
|
||||||
|
#
|
||||||
|
# - This section defines the different organizational identities which will
|
||||||
|
# be referenced later in the configuration.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
Organizations:
|
||||||
|
|
||||||
|
# SampleOrg defines an MSP using the sampleconfig. It should never be used
|
||||||
|
# in production but may be used as a template for other definitions
|
||||||
|
- &OrdererOrg
|
||||||
|
# DefaultOrg defines the organization which is used in the sampleconfig
|
||||||
|
# of the fabric.git development environment
|
||||||
|
Name: OrdererOrg
|
||||||
|
|
||||||
|
# ID to load the MSP definition as
|
||||||
|
ID: OrdererMSP
|
||||||
|
|
||||||
|
# MSPDir is the filesystem path which contains the MSP configuration
|
||||||
|
MSPDir: crypto-config/ordererOrganizations/example.com/msp
|
||||||
|
|
||||||
|
- &Org1
|
||||||
|
# DefaultOrg defines the organization which is used in the sampleconfig
|
||||||
|
# of the fabric.git development environment
|
||||||
|
Name: Org1MSP
|
||||||
|
|
||||||
|
# ID to load the MSP definition as
|
||||||
|
ID: Org1MSP
|
||||||
|
|
||||||
|
MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
|
||||||
|
|
||||||
|
AnchorPeers:
|
||||||
|
# AnchorPeers defines the location of peers which can be used
|
||||||
|
# for cross org gossip communication. Note, this value is only
|
||||||
|
# encoded in the genesis block in the Application section context
|
||||||
|
- Host: peer0.org1.example.com
|
||||||
|
Port: 7051
|
||||||
|
|
||||||
|
- &Org2
|
||||||
|
# DefaultOrg defines the organization which is used in the sampleconfig
|
||||||
|
# of the fabric.git development environment
|
||||||
|
Name: Org2MSP
|
||||||
|
|
||||||
|
# ID to load the MSP definition as
|
||||||
|
ID: Org2MSP
|
||||||
|
|
||||||
|
MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
|
||||||
|
|
||||||
|
AnchorPeers:
|
||||||
|
# AnchorPeers defines the location of peers which can be used
|
||||||
|
# for cross org gossip communication. Note, this value is only
|
||||||
|
# encoded in the genesis block in the Application section context
|
||||||
|
- Host: peer0.org2.example.com
|
||||||
|
Port: 7051
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# SECTION: Orderer
|
||||||
|
#
|
||||||
|
# - This section defines the values to encode into a config transaction or
|
||||||
|
# genesis block for orderer related parameters
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
Orderer: &OrdererDefaults
|
||||||
|
|
||||||
|
# Orderer Type: The orderer implementation to start
|
||||||
|
# Available types are "solo" and "kafka"
|
||||||
|
OrdererType: solo
|
||||||
|
|
||||||
|
Addresses:
|
||||||
|
- orderer.example.com:7050
|
||||||
|
|
||||||
|
# Batch Timeout: The amount of time to wait before creating a batch
|
||||||
|
BatchTimeout: 2s
|
||||||
|
|
||||||
|
# Batch Size: Controls the number of messages batched into a block
|
||||||
|
BatchSize:
|
||||||
|
|
||||||
|
# Max Message Count: The maximum number of messages to permit in a batch
|
||||||
|
MaxMessageCount: 10
|
||||||
|
|
||||||
|
# Absolute Max Bytes: The absolute maximum number of bytes allowed for
|
||||||
|
# the serialized messages in a batch.
|
||||||
|
AbsoluteMaxBytes: 99 MB
|
||||||
|
|
||||||
|
# Preferred Max Bytes: The preferred maximum number of bytes allowed for
|
||||||
|
# the serialized messages in a batch. A message larger than the preferred
|
||||||
|
# max bytes will result in a batch larger than preferred max bytes.
|
||||||
|
PreferredMaxBytes: 512 KB
|
||||||
|
|
||||||
|
Kafka:
|
||||||
|
# Brokers: A list of Kafka brokers to which the orderer connects
|
||||||
|
# NOTE: Use IP:port notation
|
||||||
|
Brokers:
|
||||||
|
- 127.0.0.1:9092
|
||||||
|
|
||||||
|
# Organizations is the list of orgs which are defined as participants on
|
||||||
|
# the orderer side of the network
|
||||||
|
Organizations:
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# SECTION: Application
|
||||||
|
#
|
||||||
|
# - This section defines the values to encode into a config transaction or
|
||||||
|
# genesis block for application related parameters
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
Application: &ApplicationDefaults
|
||||||
|
|
||||||
|
# Organizations is the list of orgs which are defined as participants on
|
||||||
|
# the application side of the network
|
||||||
|
Organizations:
|
||||||
81
first-network/crypto-config.yaml
Normal file
81
first-network/crypto-config.yaml
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "OrdererOrgs" - Definition of organizations managing orderer nodes
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
OrdererOrgs:
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Orderer
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
- Name: Orderer
|
||||||
|
Domain: example.com
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "Specs" - See PeerOrgs below for complete description
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Specs:
|
||||||
|
- Hostname: orderer
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "PeerOrgs" - Definition of organizations managing peer nodes
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
PeerOrgs:
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Org1
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
- Name: Org1
|
||||||
|
Domain: org1.example.com
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "Specs"
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Uncomment this section to enable the explicit definition of hosts in your
|
||||||
|
# configuration. Most users will want to use Template, below
|
||||||
|
#
|
||||||
|
# Specs is an array of Spec entries. Each Spec entry consists of two fields:
|
||||||
|
# - Hostname: (Required) The desired hostname, sans the domain.
|
||||||
|
# - CommonName: (Optional) Specifies the template or explicit override for
|
||||||
|
# the CN. By default, this is the template:
|
||||||
|
#
|
||||||
|
# "{{.Hostname}}.{{.Domain}}"
|
||||||
|
#
|
||||||
|
# which obtains its values from the Spec.Hostname and
|
||||||
|
# Org.Domain, respectively.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Specs:
|
||||||
|
# - Hostname: foo # implicitly "foo.org1.example.com"
|
||||||
|
# CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
|
||||||
|
# - Hostname: bar
|
||||||
|
# - Hostname: baz
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "Template"
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Allows for the definition of 1 or more hosts that are created sequentially
|
||||||
|
# from a template. By default, this looks like "peer%d" from 0 to Count-1.
|
||||||
|
# You may override the number of nodes (Count), the starting index (Start)
|
||||||
|
# or the template used to construct the name (Hostname).
|
||||||
|
#
|
||||||
|
# Note: Template and Specs are not mutually exclusive. You may define both
|
||||||
|
# sections and the aggregate nodes will be created for you. Take care with
|
||||||
|
# name collisions
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Template:
|
||||||
|
Count: 2
|
||||||
|
# Start: 5
|
||||||
|
# Hostname: {{.Prefix}}{{.Index}} # default
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# "Users"
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Count: The number of user accounts _in addition_ to Admin
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Users:
|
||||||
|
Count: 1
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Org2: See "Org1" for full specification
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
- Name: Org2
|
||||||
|
Domain: org2.example.com
|
||||||
|
Template:
|
||||||
|
Count: 2
|
||||||
|
Users:
|
||||||
|
Count: 1
|
||||||
69
first-network/docker-compose-cli.yaml
Normal file
69
first-network/docker-compose-cli.yaml
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
orderer.example.com:
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: orderer.example.com
|
||||||
|
container_name: orderer.example.com
|
||||||
|
|
||||||
|
peer0.org1.example.com:
|
||||||
|
container_name: peer0.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer0.org1.example.com
|
||||||
|
|
||||||
|
peer1.org1.example.com:
|
||||||
|
container_name: peer1.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer1.org1.example.com
|
||||||
|
|
||||||
|
peer0.org2.example.com:
|
||||||
|
container_name: peer0.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer0.org2.example.com
|
||||||
|
|
||||||
|
peer1.org2.example.com:
|
||||||
|
container_name: peer1.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer1.org2.example.com
|
||||||
|
|
||||||
|
cli:
|
||||||
|
container_name: cli
|
||||||
|
image: hyperledger/fabric-tools
|
||||||
|
tty: true
|
||||||
|
environment:
|
||||||
|
- GOPATH=/opt/gopath
|
||||||
|
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
|
||||||
|
- CORE_LOGGING_LEVEL=DEBUG
|
||||||
|
- CORE_PEER_ID=cli
|
||||||
|
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||||
|
- CORE_PEER_LOCALMSPID=Org1MSP
|
||||||
|
- CORE_PEER_TLS_ENABLED=true
|
||||||
|
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
|
||||||
|
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
|
||||||
|
- 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
|
||||||
|
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
|
||||||
|
command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'
|
||||||
|
volumes:
|
||||||
|
- /var/run/:/host/var/run/
|
||||||
|
- ./chaincode/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
|
||||||
|
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
|
||||||
|
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
|
||||||
|
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
|
||||||
|
depends_on:
|
||||||
|
- orderer.example.com
|
||||||
|
- peer0.org1.example.com
|
||||||
|
- peer1.org1.example.com
|
||||||
|
- peer0.org2.example.com
|
||||||
|
- peer1.org2.example.com
|
||||||
67
first-network/docker-compose-couch.yaml
Normal file
67
first-network/docker-compose-couch.yaml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
couchdb0:
|
||||||
|
container_name: couchdb0
|
||||||
|
image: hyperledger/fabric-couchdb
|
||||||
|
# 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:
|
||||||
|
- "5984:5984"
|
||||||
|
|
||||||
|
peer0.org1.example.com:
|
||||||
|
environment:
|
||||||
|
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
|
||||||
|
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984
|
||||||
|
depends_on:
|
||||||
|
- couchdb0
|
||||||
|
|
||||||
|
couchdb1:
|
||||||
|
container_name: couchdb1
|
||||||
|
image: hyperledger/fabric-couchdb
|
||||||
|
# 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:
|
||||||
|
- "6984:5984"
|
||||||
|
|
||||||
|
peer1.org1.example.com:
|
||||||
|
environment:
|
||||||
|
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
|
||||||
|
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984
|
||||||
|
depends_on:
|
||||||
|
- couchdb1
|
||||||
|
|
||||||
|
couchdb2:
|
||||||
|
container_name: couchdb2
|
||||||
|
image: hyperledger/fabric-couchdb
|
||||||
|
# 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:
|
||||||
|
- "7984:5984"
|
||||||
|
|
||||||
|
peer0.org2.example.com:
|
||||||
|
environment:
|
||||||
|
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
|
||||||
|
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb2:5984
|
||||||
|
depends_on:
|
||||||
|
- couchdb2
|
||||||
|
|
||||||
|
couchdb3:
|
||||||
|
container_name: couchdb3
|
||||||
|
image: hyperledger/fabric-couchdb
|
||||||
|
# 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:
|
||||||
|
- "8984:5984"
|
||||||
|
|
||||||
|
peer1.org2.example.com:
|
||||||
|
environment:
|
||||||
|
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
|
||||||
|
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb3:5984
|
||||||
|
depends_on:
|
||||||
|
- couchdb3
|
||||||
67
first-network/docker-compose-e2e-template.yaml
Normal file
67
first-network/docker-compose-e2e-template.yaml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Copyright IBM Corp. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
version: '2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
ca0:
|
||||||
|
image: hyperledger/fabric-ca
|
||||||
|
environment:
|
||||||
|
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
|
||||||
|
- FABRIC_CA_SERVER_CA_NAME=ca-org1
|
||||||
|
- FABRIC_CA_SERVER_TLS_ENABLED=true
|
||||||
|
- FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
|
||||||
|
- FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA1_PRIVATE_KEY
|
||||||
|
ports:
|
||||||
|
- "7054:7054"
|
||||||
|
command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/CA1_PRIVATE_KEY -b admin:adminpw -d'
|
||||||
|
volumes:
|
||||||
|
- ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
|
||||||
|
container_name: ca_peerOrg1
|
||||||
|
|
||||||
|
ca1:
|
||||||
|
image: hyperledger/fabric-ca
|
||||||
|
environment:
|
||||||
|
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
|
||||||
|
- FABRIC_CA_SERVER_CA_NAME=ca-org2
|
||||||
|
- FABRIC_CA_SERVER_TLS_ENABLED=true
|
||||||
|
- FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem
|
||||||
|
- FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA2_PRIVATE_KEY
|
||||||
|
ports:
|
||||||
|
- "8054:7054"
|
||||||
|
command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/CA2_PRIVATE_KEY -b admin:adminpw -d'
|
||||||
|
volumes:
|
||||||
|
- ./crypto-config/peerOrganizations/org2.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
|
||||||
|
container_name: ca_peerOrg2
|
||||||
|
|
||||||
|
orderer.example.com:
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: orderer.example.com
|
||||||
|
container_name: orderer.example.com
|
||||||
|
|
||||||
|
peer0.org1.example.com:
|
||||||
|
container_name: peer0.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer0.org1.example.com
|
||||||
|
|
||||||
|
peer1.org1.example.com:
|
||||||
|
container_name: peer1.org1.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer1.org1.example.com
|
||||||
|
|
||||||
|
peer0.org2.example.com:
|
||||||
|
container_name: peer0.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer0.org2.example.com
|
||||||
|
|
||||||
|
peer1.org2.example.com:
|
||||||
|
container_name: peer1.org2.example.com
|
||||||
|
extends:
|
||||||
|
file: base/docker-compose-base.yaml
|
||||||
|
service: peer1.org2.example.com
|
||||||
240
first-network/scripts/script.sh
Executable file
240
first-network/scripts/script.sh
Executable file
|
|
@ -0,0 +1,240 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo " ____ _____ _ ____ _____ "
|
||||||
|
echo "/ ___| |_ _| / \ | _ \ |_ _|"
|
||||||
|
echo "\___ \ | | / _ \ | |_) | | | "
|
||||||
|
echo " ___) | | | / ___ \ | _ < | | "
|
||||||
|
echo "|____/ |_| /_/ \_\ |_| \_\ |_| "
|
||||||
|
echo
|
||||||
|
echo "Build your first network (BYFN) end-to-end test"
|
||||||
|
echo
|
||||||
|
CHANNEL_NAME="$1"
|
||||||
|
: ${CHANNEL_NAME:="mychannel"}
|
||||||
|
: ${TIMEOUT:="60"}
|
||||||
|
COUNTER=1
|
||||||
|
MAX_RETRY=5
|
||||||
|
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem
|
||||||
|
|
||||||
|
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 () {
|
||||||
|
|
||||||
|
if [ $1 -eq 0 -o $1 -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 [ $1 -eq 0 ]; then
|
||||||
|
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
|
||||||
|
else
|
||||||
|
CORE_PEER_ADDRESS=peer1.org1.example.com:7051
|
||||||
|
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
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 [ $1 -eq 2 ]; then
|
||||||
|
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
|
||||||
|
else
|
||||||
|
CORE_PEER_ADDRESS=peer1.org2.example.com:7051
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
env |grep CORE
|
||||||
|
}
|
||||||
|
|
||||||
|
createChannel() {
|
||||||
|
setGlobals 0
|
||||||
|
|
||||||
|
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
|
||||||
|
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
|
||||||
|
else
|
||||||
|
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt
|
||||||
|
fi
|
||||||
|
res=$?
|
||||||
|
cat log.txt
|
||||||
|
verifyResult $res "Channel creation failed"
|
||||||
|
echo "===================== Channel \"$CHANNEL_NAME\" is created successfully ===================== "
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAnchorPeers() {
|
||||||
|
PEER=$1
|
||||||
|
setGlobals $PEER
|
||||||
|
|
||||||
|
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 ===================== "
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
## Sometimes Join takes time hence RETRY atleast for 5 times
|
||||||
|
joinWithRetry () {
|
||||||
|
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$1 failed to join the channel, Retry after 2 seconds"
|
||||||
|
sleep 2
|
||||||
|
joinWithRetry $1
|
||||||
|
else
|
||||||
|
COUNTER=1
|
||||||
|
fi
|
||||||
|
verifyResult $res "After $MAX_RETRY attempts, PEER$ch has failed to Join the Channel"
|
||||||
|
}
|
||||||
|
|
||||||
|
joinChannel () {
|
||||||
|
for ch in 0 1 2 3; do
|
||||||
|
setGlobals $ch
|
||||||
|
joinWithRetry $ch
|
||||||
|
echo "===================== PEER$ch joined on the channel \"$CHANNEL_NAME\" ===================== "
|
||||||
|
sleep 2
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
installChaincode () {
|
||||||
|
PEER=$1
|
||||||
|
setGlobals $PEER
|
||||||
|
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 >&log.txt
|
||||||
|
res=$?
|
||||||
|
cat log.txt
|
||||||
|
verifyResult $res "Chaincode installation on remote peer PEER$PEER has Failed"
|
||||||
|
echo "===================== Chaincode is installed on remote peer PEER$PEER ===================== "
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
instantiateChaincode () {
|
||||||
|
PEER=$1
|
||||||
|
setGlobals $PEER
|
||||||
|
# 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 -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 -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 on channel '$CHANNEL_NAME' failed"
|
||||||
|
echo "===================== Chaincode Instantiation on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
chaincodeQuery () {
|
||||||
|
PEER=$1
|
||||||
|
echo "===================== Querying on PEER$PEER on channel '$CHANNEL_NAME'... ===================== "
|
||||||
|
setGlobals $PEER
|
||||||
|
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 3
|
||||||
|
echo "Attempting to Query PEER$PEER ...$(($(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" = "$2" && let rc=0
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
cat log.txt
|
||||||
|
if test $rc -eq 0 ; then
|
||||||
|
echo "===================== Query on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
|
||||||
|
else
|
||||||
|
echo "!!!!!!!!!!!!!!! Query result on PEER$PEER is INVALID !!!!!!!!!!!!!!!!"
|
||||||
|
echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
chaincodeInvoke () {
|
||||||
|
PEER=$1
|
||||||
|
setGlobals $PEER
|
||||||
|
# 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 failed "
|
||||||
|
echo "===================== Invoke transaction on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
## Create channel
|
||||||
|
echo "Creating channel..."
|
||||||
|
createChannel
|
||||||
|
|
||||||
|
## Join all the peers to the channel
|
||||||
|
echo "Having all peers join the channel..."
|
||||||
|
joinChannel
|
||||||
|
|
||||||
|
## Set the anchor peers for each org in the channel
|
||||||
|
echo "Updating anchor peers for org1..."
|
||||||
|
updateAnchorPeers 0
|
||||||
|
echo "Updating anchor peers for org2..."
|
||||||
|
updateAnchorPeers 2
|
||||||
|
|
||||||
|
## Install chaincode on Peer0/Org1 and Peer2/Org2
|
||||||
|
echo "Installing chaincode on org1/peer0..."
|
||||||
|
installChaincode 0
|
||||||
|
echo "Install chaincode on org2/peer2..."
|
||||||
|
installChaincode 2
|
||||||
|
|
||||||
|
#Instantiate chaincode on Peer2/Org2
|
||||||
|
echo "Instantiating chaincode on org2/peer2..."
|
||||||
|
instantiateChaincode 2
|
||||||
|
|
||||||
|
#Query on chaincode on Peer0/Org1
|
||||||
|
echo "Querying chaincode on org1/peer0..."
|
||||||
|
chaincodeQuery 0 100
|
||||||
|
|
||||||
|
#Invoke on chaincode on Peer0/Org1
|
||||||
|
echo "Sending invoke transaction on org1/peer0..."
|
||||||
|
chaincodeInvoke 0
|
||||||
|
|
||||||
|
## Install chaincode on Peer3/Org2
|
||||||
|
echo "Installing chaincode on org2/peer3..."
|
||||||
|
installChaincode 3
|
||||||
|
|
||||||
|
#Query on chaincode on Peer3/Org2, check if the result is 90
|
||||||
|
echo "Querying chaincode on org2/peer3..."
|
||||||
|
chaincodeQuery 3 90
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "========= All GOOD, BYFN execution completed =========== "
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo " _____ _ _ ____ "
|
||||||
|
echo "| ____| | \ | | | _ \ "
|
||||||
|
echo "| _| | \| | | | | | "
|
||||||
|
echo "| |___ | |\ | | |_| | "
|
||||||
|
echo "|_____| |_| \_| |____/ "
|
||||||
|
echo
|
||||||
|
|
||||||
|
exit 0
|
||||||
Loading…
Reference in a new issue