diff --git a/chaincode/abac/abac.go b/chaincode/abac/abac.go
new file mode 100644
index 0000000000..c43448e481
--- /dev/null
+++ b/chaincode/abac/abac.go
@@ -0,0 +1,206 @@
+/*
+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
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/hyperledger/fabric/core/chaincode/shim"
+ "github.com/hyperledger/fabric/core/chaincode/lib/cid"
+ pb "github.com/hyperledger/fabric/protos/peer"
+)
+
+// SimpleChaincode example simple Chaincode implementation
+type SimpleChaincode struct {
+}
+
+// Init initializes the chaincode
+func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
+
+ fmt.Println("abac Init")
+
+ //
+ // Demonstrate the use of Attribute-Based Access Control (ABAC) by checking
+ // to see if the caller has the "abac.init" attribute with a value of true;
+ // if not, return an error.
+ //
+ err := cid.AssertAttributeValue(stub, "abac.init", "true")
+ if err != nil {
+ return shim.Error(err.Error())
+ }
+
+ _, args := stub.GetFunctionAndParameters()
+ var A, B string // Entities
+ var Aval, Bval int // Asset holdings
+
+ 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("abac 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)
+ }
+}
diff --git a/fabric-ca/.env b/fabric-ca/.env
new file mode 100644
index 0000000000..4fd2ee0d73
--- /dev/null
+++ b/fabric-ca/.env
@@ -0,0 +1 @@
+COMPOSE_PROJECT_NAME=net
diff --git a/fabric-ca/.gitignore b/fabric-ca/.gitignore
new file mode 100644
index 0000000000..a5a77b4574
--- /dev/null
+++ b/fabric-ca/.gitignore
@@ -0,0 +1,2 @@
+docker-compose.yml
+data
diff --git a/fabric-ca/README.md b/fabric-ca/README.md
new file mode 100755
index 0000000000..8e9fd3865c
--- /dev/null
+++ b/fabric-ca/README.md
@@ -0,0 +1,88 @@
+# Hyperledger Fabric CA sample
+
+The Hyperledger Fabric CA sample demonstrates the following:
+
+* How to use the Hyperledger Fabric CA client and server to generate all crypto
+ material rather than using cryptogen. The cryptogen tool is not intended for
+ a production environment because it generates all private keys in one location
+ which must then be copied to the appropriate host or container. This sample demonstrates
+ how to generate crypto material for orderers, peers, administrators, and end
+ users so that private keys never leave the host or container in which they are generated.
+
+* How to use Attribute-Based Access Control (ABAC). See fabric-samples/chaincode/abac/abac.go and
+ note the use of the *github.com/hyperledger/fabric/core/chaincode/lib/cid* package to extract
+ attributes from the invoker's identity. Only identities with the *abac.init* attribute value of
+ *true* can successfully call the *Init* function to instantiate the chaincode.
+
+## Running this sample
+
+1. The following images are required to run this sample:
+*hyperledger/fabric-ca-orderer*, *hyperledger/fabric-ca-peer*, and *hyperledger/fabric-ca-tools*.
+These images are new in the v1.1.0 release of the *github.com/hyperledger/fabric-ca*.
+In order to run this sample prior to the v1.1.0 release, you must build these
+images manually as follows:
+a) pull the master branch of the *github.com/hyperledger/fabric* and
+ *github.com/hyperledger/fabric-ca* repositories;
+b) make sure these repositories are on your GOPATH;
+c) run the *build-images.sh* script provided with this sample.
+
+2. To run this sample, simply run the *start.sh* script. You may do this multiple times in a row as needed
+since the *start.sh* script cleans up before starting each time.
+
+3. To stop the containers which are started by the *start.sh* script, you may run the *stop.sh* script.
+
+## Understanding this sample
+
+There are some variables at the top of *fabric-samples/fabric-ca/scripts/env.sh* script which
+define the names and topology of this sample. You may modify these as described in the comments
+of the script in order to customize this sample. By default, there are three organizations.
+The orderer organization is *org0*, and two peer organizations are *org1* and *org2*.
+
+The *start.sh* script first builds the *docker-compose.yml* file (by invoking the
+*makeDocker.sh* script) and then starts the docker containers.
+The *data* directory is a volume mount for all containers.
+This volume mount is not be needed in a real scenario, but it is used by this sample
+for the following reasons:
+ a) so that all containers can write their logs to a common directory
+ (i.e. *the *data/logs* directory) to make debugging easier;
+ b) to synchronize the sequence in which containers start as described below
+ (for example, an intermediate CA in an *ica* container must wait for the
+ corresponding root CA in a *rca* container to write its certificate to
+ the *data* directory);
+ c) to access bootstrap certificates required by clients to connect over TLS.
+
+The containers defined in the *docker-compose.yml* file are started in the
+following sequence.
+
+1. The *rca* (root CA) containers start first, one for each organization.
+An *rca* container runs the fabric-ca-server for the root CA of an
+organization. The root CA certificate is written to the *data* directory
+and is used when an intermediate CA must connect to it over TLS.
+
+2. The *ica* (Intermediate CA) containers start next. An *ica* container
+runs the fabric-ca-server for the intermediate CA of an organization.
+Each of these containers enrolls with a corresponding root CA.
+The intermediate CA certificate is also written to the *data* directory.
+
+3. The *setup* container registers identities with the intermediate CAs,
+generates the genesis block, and other artifacts needed to setup the
+blockchain network. This is performed by the
+*fabric-samples/fabric-ca/scripts/run-fabric.sh* script. Note that the
+admin identity is registered with **abac.init=true:ecert**
+(see the *registerPeerIdentities* function of this script). This causes
+the admin's enrollment certificate (ECert) to have an attribute named "abac.init"
+with a value of "true". Note further that the chaincode used by this sample
+requires this attribute be included in the certificate of the identity that
+invokes its Init function. See the chaincode at *fabric-samples/chaincode/abac/abac.go*).
+For more information on Attribute-Based Access Control (ABAC), see
+https://github.com/hyperledger/fabric/tree/release/core/chaincode/lib/cid/README.md.
+
+4. The orderer and peer containers are started. The naming of these containers
+is straight-forward as is their log files in the *data/logs* directory.
+
+5. The *run* container is started which runs the actual test case. It creates
+a channel, peers join the channel, chaincode is installed and instantiated,
+and the chaincode is queried and invoked. See the *main* function of the
+*fabric-samples/fabric-ca/scripts/run-fabric.sh* script for more details.
+
+
This work is licensed under a Creative Commons Attribution 4.0 International License
diff --git a/fabric-ca/build-images.sh b/fabric-ca/build-images.sh
new file mode 100755
index 0000000000..e49bf4e5e9
--- /dev/null
+++ b/fabric-ca/build-images.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+#
+# This script builds the images required to run this sample.
+#
+
+function assertOnMasterBranch {
+ if [ "`git rev-parse --abbrev-ref HEAD`" != "master" ]; then
+ fatal "You must switch to the master branch in `pwd`"
+ fi
+}
+
+set -e
+
+SDIR=$(dirname "$0")
+source $SDIR/scripts/env.sh
+
+# Delete docker containers
+dockerContainers=$(docker ps -a | awk '$2~/hyperledger/ {print $1}')
+if [ "$dockerContainers" != "" ]; then
+ log "Deleting existing docker containers ..."
+ docker rm -f $dockerContainers > /dev/null
+fi
+
+# Remove chaincode docker images
+chaincodeImages=`docker images | grep "^dev-peer" | awk '{print $3}'`
+if [ "$chaincodeImages" != "" ]; then
+ log "Removing chaincode docker images ..."
+ docker rmi $chaincodeImages > /dev/null
+fi
+
+# Perform docker clean for fabric-ca
+log "Cleaning fabric-ca docker images ..."
+cd $GOPATH/src/github.com/hyperledger/fabric-ca
+assertOnMasterBranch
+make docker-clean
+
+# Perform docker clean for fabric and rebuild
+log "Cleaning and rebuilding fabric docker images ..."
+cd $GOPATH/src/github.com/hyperledger/fabric
+assertOnMasterBranch
+make docker-clean docker
+
+# Perform docker clean for fabric and rebuild against latest fabric images just built
+log "Rebuilding fabric-ca docker images ..."
+cd $GOPATH/src/github.com/hyperledger/fabric-ca
+FABRIC_TAG=latest make docker
+
+log "Setup completed successfully. You may run the tests multiple times by running start.sh."
diff --git a/fabric-ca/makeDocker.sh b/fabric-ca/makeDocker.sh
new file mode 100755
index 0000000000..83244097ea
--- /dev/null
+++ b/fabric-ca/makeDocker.sh
@@ -0,0 +1,261 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+#
+# This script builds the docker compose file needed to run this sample.
+#
+
+SDIR=$(dirname "$0")
+source $SDIR/scripts/env.sh
+
+function main {
+ {
+ writeHeader
+ writeRootFabricCA
+ if $USE_INTERMEDIATE_CA; then
+ writeIntermediateFabricCA
+ fi
+ writeSetupFabric
+ writeStartFabric
+ writeRunFabric
+ } > $SDIR/docker-compose.yml
+ log "Created docker-compose.yml"
+}
+
+# Write services for the root fabric CA servers
+function writeRootFabricCA {
+ for ORG in $ORGS; do
+ initOrgVars $ORG
+ writeRootCA
+ done
+}
+
+# Write services for the intermediate fabric CA servers
+function writeIntermediateFabricCA {
+ for ORG in $ORGS; do
+ initOrgVars $ORG
+ writeIntermediateCA
+ done
+}
+
+# Write a service to setup the fabric artifacts (e.g. genesis block, etc)
+function writeSetupFabric {
+ echo " setup:
+ container_name: setup
+ image: hyperledger/fabric-ca-tools
+ command: /bin/bash -c '/scripts/setup-fabric.sh 2>&1 | tee /$SETUP_LOGFILE; sleep 99999'
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ networks:
+ - $NETWORK
+ depends_on:"
+ for ORG in $ORGS; do
+ initOrgVars $ORG
+ echo " - $CA_NAME"
+ done
+ echo ""
+}
+
+# Write services for fabric orderer and peer containers
+function writeStartFabric {
+ for ORG in $ORDERER_ORGS; do
+ COUNT=1
+ while [[ "$COUNT" -le $NUM_ORDERERS ]]; do
+ initOrdererVars $ORG $COUNT
+ writeOrderer
+ COUNT=$((COUNT+1))
+ done
+ done
+ for ORG in $PEER_ORGS; do
+ COUNT=1
+ while [[ "$COUNT" -le $NUM_PEERS ]]; do
+ initPeerVars $ORG $COUNT
+ writePeer
+ COUNT=$((COUNT+1))
+ done
+ done
+}
+
+# Write a service to run a fabric test including creating a channel,
+# installing chaincode, invoking and querying
+function writeRunFabric {
+ # Set samples directory relative to this script
+ SAMPLES_DIR=$(dirname $(cd ${SDIR} && pwd))
+ # Set fabric directory relative to GOPATH
+ FABRIC_DIR=${GOPATH}/src/github.com/hyperledger/fabric
+ echo " run:
+ container_name: run
+ image: hyperledger/fabric-ca-tools
+ environment:
+ - GOPATH=/opt/gopath
+ command: /bin/bash -c 'sleep 3;/scripts/run-fabric.sh 2>&1 | tee /$RUN_LOGFILE; sleep 99999'
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ - ${SAMPLES_DIR}:/opt/gopath/src/github.com/hyperledger/fabric-samples
+ - ${FABRIC_DIR}:/opt/gopath/src/github.com/hyperledger/fabric
+ networks:
+ - $NETWORK
+ depends_on:"
+ for ORG in $ORDERER_ORGS; do
+ COUNT=1
+ while [[ "$COUNT" -le $NUM_ORDERERS ]]; do
+ initOrdererVars $ORG $COUNT
+ echo " - $ORDERER_NAME"
+ COUNT=$((COUNT+1))
+ done
+ done
+ for ORG in $PEER_ORGS; do
+ COUNT=1
+ while [[ "$COUNT" -le $NUM_PEERS ]]; do
+ initPeerVars $ORG $COUNT
+ echo " - $PEER_NAME"
+ COUNT=$((COUNT+1))
+ done
+ done
+}
+
+function writeRootCA {
+ echo " $ROOT_CA_NAME:
+ container_name: $ROOT_CA_NAME
+ image: hyperledger/fabric-ca
+ command: /bin/bash -c '/scripts/start-root-ca.sh 2>&1 | tee /$ROOT_CA_LOGFILE'
+ environment:
+ - FABRIC_CA_SERVER_HOME=/etc/hyperledger/fabric-ca
+ - FABRIC_CA_SERVER_TLS_ENABLED=true
+ - FABRIC_CA_SERVER_CSR_CN=$ROOT_CA_NAME
+ - FABRIC_CA_SERVER_CSR_HOSTS=$ROOT_CA_HOST
+ - FABRIC_CA_SERVER_DEBUG=true
+ - BOOTSTRAP_USER_PASS=$ROOT_CA_ADMIN_USER_PASS
+ - TARGET_CERTFILE=$ROOT_CA_CERTFILE
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ networks:
+ - $NETWORK
+"
+}
+
+function writeIntermediateCA {
+ echo " $INT_CA_NAME:
+ container_name: $INT_CA_NAME
+ image: hyperledger/fabric-ca
+ command: /bin/bash -c '/scripts/start-intermediate-ca.sh $ORG 2>&1 | tee /$INT_CA_LOGFILE'
+ environment:
+ - FABRIC_CA_SERVER_HOME=/etc/hyperledger/fabric-ca
+ - FABRIC_CA_SERVER_CA_NAME=$INT_CA_NAME
+ - FABRIC_CA_SERVER_INTERMEDIATE_TLS_CERTFILES=$ROOT_CA_CERTFILE
+ - FABRIC_CA_SERVER_CSR_HOSTS=$INT_CA_HOST
+ - FABRIC_CA_SERVER_TLS_ENABLED=true
+ - FABRIC_CA_SERVER_DEBUG=true
+ - BOOTSTRAP_USER_PASS=$INT_CA_ADMIN_USER_PASS
+ - PARENT_URL=https://$ROOT_CA_ADMIN_USER_PASS@$ROOT_CA_HOST:7054
+ - TARGET_CHAINFILE=$INT_CA_CHAINFILE
+ - ORG=$ORG
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ networks:
+ - $NETWORK
+ depends_on:
+ - $ROOT_CA_NAME
+"
+}
+
+function writeOrderer {
+ MYHOME=/etc/hyperledger/orderer
+ echo " $ORDERER_NAME:
+ container_name: $ORDERER_NAME
+ image: hyperledger/fabric-ca-orderer
+ environment:
+ - FABRIC_CA_CLIENT_HOME=$MYHOME
+ - FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ - ENROLLMENT_URL=https://$ORDERER_NAME_PASS@$CA_HOST:7054
+ - ORDERER_HOME=$MYHOME
+ - ORDERER_HOST=$ORDERER_HOST
+ - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
+ - ORDERER_GENERAL_GENESISMETHOD=file
+ - ORDERER_GENERAL_GENESISFILE=$GENESIS_BLOCK_FILE
+ - ORDERER_GENERAL_LOCALMSPID=$ORG_MSP_ID
+ - ORDERER_GENERAL_LOCALMSPDIR=$MYHOME/msp
+ - ORDERER_GENERAL_TLS_ENABLED=true
+ - ORDERER_GENERAL_TLS_PRIVATEKEY=$MYHOME/tls/server.key
+ - ORDERER_GENERAL_TLS_CERTIFICATE=$MYHOME/tls/server.crt
+ - ORDERER_GENERAL_TLS_ROOTCAS=[$CA_CHAINFILE]
+ - ORDERER_GENERAL_LOGLEVEL=debug
+ - ORDERER_DEBUG_BROADCASTTRACEDIR=$LOGDIR
+ - ORG=$ORG
+ - ORG_ADMIN_CERT=$ORG_ADMIN_CERT
+ command: /bin/bash -c '/scripts/start-orderer.sh 2>&1 | tee /$ORDERER_LOGFILE'
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ networks:
+ - $NETWORK
+ depends_on:
+ - setup
+"
+}
+
+function writePeer {
+ MYHOME=/opt/gopath/src/github.com/hyperledger/fabric/peer
+ echo " $PEER_NAME:
+ container_name: $PEER_NAME
+ image: hyperledger/fabric-ca-peer
+ environment:
+ - FABRIC_CA_CLIENT_HOME=$MYHOME
+ - FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ - ENROLLMENT_URL=https://$PEER_NAME_PASS@$CA_HOST:7054
+ - PEER_HOME=$MYHOME
+ - PEER_HOST=$PEER_HOST
+ - PEER_NAME_PASS=$PEER_NAME_PASS
+ - CORE_PEER_ID=$PEER_HOST
+ - CORE_PEER_ADDRESS=$PEER_HOST:7051
+ - CORE_PEER_LOCALMSPID=$ORG_MSP_ID
+ - CORE_PEER_MSPCONFIGPATH=$MYHOME/msp
+ - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
+ - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_${NETWORK}
+ - CORE_LOGGING_LEVEL=DEBUG
+ - CORE_PEER_TLS_ENABLED=true
+ - CORE_PEER_PROFILE_ENABLED=true
+ - CORE_PEER_TLS_CERT_FILE=$MYHOME/tls/server.crt
+ - CORE_PEER_TLS_KEY_FILE=$MYHOME/tls/server.key
+ - CORE_PEER_TLS_ROOTCERT_FILE=$CA_CHAINFILE
+ - CORE_PEER_GOSSIP_USELEADERELECTION=true
+ - CORE_PEER_GOSSIP_ORGLEADER=false
+ - CORE_PEER_GOSSIP_EXTERNALENDPOINT=$PEER_HOST:7051
+ - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
+ - ORG=$ORG
+ - ORG_ADMIN_CERT=$ORG_ADMIN_CERT"
+ if [ $NUM -gt 1 ]; then
+ echo " - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-${ORG}:7051"
+ fi
+ echo " working_dir: $MYHOME
+ command: /bin/bash -c '/scripts/start-peer.sh 2>&1 | tee /$PEER_LOGFILE'
+ volumes:
+ - ./scripts:/scripts
+ - ./$DATA:/$DATA
+ - /var/run:/host/var/run
+ networks:
+ - $NETWORK
+ depends_on:
+ - setup
+"
+}
+
+function writeHeader {
+ echo "version: '2'
+
+networks:
+ $NETWORK:
+
+services:
+"
+}
+
+main
diff --git a/fabric-ca/scripts/env.sh b/fabric-ca/scripts/env.sh
new file mode 100755
index 0000000000..e86f661170
--- /dev/null
+++ b/fabric-ca/scripts/env.sh
@@ -0,0 +1,322 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+#
+# The following variables describe the topology and may be modified to provide
+# different organization names or the number of peers in each peer organization.
+#
+
+# Name of the docker-compose network
+NETWORK=fabric-ca
+
+# Names of the orderer organizations
+ORDERER_ORGS="org0"
+
+# Names of the peer organizations
+PEER_ORGS="org1 org2"
+
+# Number of peers in each peer organization
+NUM_PEERS=2
+
+#
+# The remainder of this file contains variables which typically would not be changed.
+#
+
+# All org names
+ORGS="$ORDERER_ORGS $PEER_ORGS"
+
+# Set to true to populate the "admincerts" folder of MSPs
+ADMINCERTS=true
+
+# Number of orderer nodes
+NUM_ORDERERS=1
+
+# The volume mount to share data between containers
+DATA=data
+
+# The path to the genesis block
+GENESIS_BLOCK_FILE=/$DATA/genesis.block
+
+# The path to a channel transaction
+CHANNEL_TX_FILE=/$DATA/channel.tx
+
+# Name of test channel
+CHANNEL_NAME=mychannel
+
+# Query timeout in seconds
+QUERY_TIMEOUT=15
+
+# Log directory
+LOGDIR=$DATA/logs
+LOGPATH=/$LOGDIR
+
+# Name of a the file to create when setup is successful
+SETUP_SUCCESS_FILE=${LOGDIR}/setup.successful
+# The setup container's log file
+SETUP_LOGFILE=${LOGDIR}/setup.log
+
+# The run container's log file
+RUN_LOGFILE=${LOGDIR}/run.log
+# The run container's summary log file
+RUN_SUMFILE=${LOGDIR}/run.sum
+RUN_SUMPATH=/${RUN_SUMFILE}
+# Run success and failure files
+RUN_SUCCESS_FILE=${LOGDIR}/run.success
+RUN_FAIL_FILE=${LOGDIR}/run.fail
+
+# Affiliation is not used to limit users in this sample, so just put
+# all identities in the same affiliation.
+export FABRIC_CA_CLIENT_ID_AFFILIATION=org1
+
+# Set to true to enable use of intermediate CAs
+USE_INTERMEDIATE_CA=true
+
+# initOrgVars
+function initOrgVars {
+ if [ $# -ne 1 ]; then
+ echo "Usage: initOrgVars "
+ exit 1
+ fi
+ ORG=$1
+ ORG_CONTAINER_NAME=${ORG//./-}
+ ROOT_CA_HOST=rca-${ORG}
+ ROOT_CA_NAME=rca-${ORG}
+ ROOT_CA_LOGFILE=$LOGDIR/${ROOT_CA_NAME}.log
+ INT_CA_HOST=ica-${ORG}
+ INT_CA_NAME=ica-${ORG}
+ INT_CA_LOGFILE=$LOGDIR/${INT_CA_NAME}.log
+
+ # Root CA admin identity
+ ROOT_CA_ADMIN_USER=rca-${ORG}-admin
+ ROOT_CA_ADMIN_PASS=${ROOT_CA_ADMIN_USER}pw
+ ROOT_CA_ADMIN_USER_PASS=${ROOT_CA_ADMIN_USER}:${ROOT_CA_ADMIN_PASS}
+ # Root CA intermediate identity to bootstrap the intermediate CA
+ ROOT_CA_INT_USER=ica-${ORG}
+ ROOT_CA_INT_PASS=${ROOT_CA_INT_USER}pw
+ ROOT_CA_INT_USER_PASS=${ROOT_CA_INT_USER}:${ROOT_CA_INT_PASS}
+ # Intermediate CA admin identity
+ INT_CA_ADMIN_USER=ica-${ORG}-admin
+ INT_CA_ADMIN_PASS=${INT_CA_ADMIN_USER}pw
+ INT_CA_ADMIN_USER_PASS=${INT_CA_ADMIN_USER}:${INT_CA_ADMIN_PASS}
+ # Admin identity for the org
+ ADMIN_NAME=admin-${ORG}
+ ADMIN_PASS=${ADMIN_NAME}pw
+ # Typical user identity for the org
+ USER_NAME=user-${ORG}
+ USER_PASS=${USER_NAME}pw
+
+ ROOT_CA_CERTFILE=/${DATA}/${ORG}-ca-cert.pem
+ INT_CA_CHAINFILE=/${DATA}/${ORG}-ca-chain.pem
+ ANCHOR_TX_FILE=/${DATA}/orgs/${ORG}/anchors.tx
+ ORG_MSP_ID=${ORG}MSP
+ ORG_MSP_DIR=/${DATA}/orgs/${ORG}/msp
+ ORG_ADMIN_CERT=${ORG_MSP_DIR}/admincerts/cert.pem
+ ORG_ADMIN_HOME=/${DATA}/orgs/$ORG/admin
+
+ if $USE_INTERMEDIATE_CA; then
+ CA_NAME=$INT_CA_NAME
+ CA_HOST=$INT_CA_HOST
+ CA_CHAINFILE=$INT_CA_CHAINFILE
+ CA_ADMIN_USER_PASS=$INT_CA_ADMIN_USER_PASS
+ CA_LOGFILE=$INT_CA_LOGFILE
+ else
+ CA_NAME=$ROOT_CA_NAME
+ CA_HOST=$ROOT_CA_HOST
+ CA_CHAINFILE=$ROOT_CA_CERTFILE
+ CA_ADMIN_USER_PASS=$ROOT_CA_ADMIN_USER_PASS
+ CA_LOGFILE=$ROOT_CA_LOGFILE
+ fi
+}
+
+# initOrdererVars
+function initOrdererVars {
+ if [ $# -ne 2 ]; then
+ echo "Usage: initOrdererVars "
+ exit 1
+ fi
+ initOrgVars $1
+ NUM=$2
+ ORDERER_HOST=orderer${NUM}-${ORG}
+ ORDERER_NAME=orderer${NUM}-${ORG}
+ ORDERER_PASS=${ORDERER_NAME}pw
+ ORDERER_NAME_PASS=${ORDERER_NAME}:${ORDERER_PASS}
+ ORDERER_LOGFILE=$LOGDIR/${ORDERER_NAME}.log
+ MYHOME=/etc/hyperledger/orderer
+
+ export FABRIC_CA_CLIENT=$MYHOME
+ export ORDERER_GENERAL_LOGLEVEL=debug
+ export ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
+ export ORDERER_GENERAL_GENESISMETHOD=file
+ export ORDERER_GENERAL_GENESISFILE=$GENESIS_BLOCK_FILE
+ export ORDERER_GENERAL_LOCALMSPID=$ORG_MSP_ID
+ export ORDERER_GENERAL_LOCALMSPDIR=$MYHOME/msp
+ # enabled TLS
+ export ORDERER_GENERAL_TLS_ENABLED=true
+ TLSDIR=$MYHOME/tls
+ export ORDERER_GENERAL_TLS_PRIVATEKEY=$TLSDIR/server.key
+ export ORDERER_GENERAL_TLS_CERTIFICATE=$TLSDIR/server.crt
+ export ORDERER_GENERAL_TLS_ROOTCAS=[$INT_CA_CHAINFILE]
+}
+
+# initPeerVars
+function initPeerVars {
+ if [ $# -ne 2 ]; then
+ echo "Usage: initPeerVars : $*"
+ exit 1
+ fi
+ initOrgVars $1
+ NUM=$2
+ PEER_HOST=peer${NUM}-${ORG}
+ PEER_NAME=peer${NUM}-${ORG}
+ PEER_PASS=${PEER_NAME}pw
+ PEER_NAME_PASS=${PEER_NAME}:${PEER_PASS}
+ PEER_LOGFILE=$LOGDIR/${PEER_NAME}.log
+ MYHOME=/opt/gopath/src/github.com/hyperledger/fabric/peer
+ TLSDIR=$MYHOME/tls
+
+ export FABRIC_CA_CLIENT=$MYHOME
+ export CORE_PEER_ID=$PEER_HOST
+ export CORE_PEER_ADDRESS=$PEER_HOST:7051
+ export CORE_PEER_LOCALMSPID=$ORG_MSP_ID
+ export 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/
+ #export CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_${NETWORK}
+ export CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_${NETWORK}
+ # export CORE_LOGGING_LEVEL=ERROR
+ export CORE_LOGGING_LEVEL=DEBUG
+ export CORE_PEER_TLS_ENABLED=true
+ export CORE_PEER_PROFILE_ENABLED=true
+ export CORE_PEER_TLS_CERT_FILE=$TLSDIR/server.crt
+ export CORE_PEER_TLS_KEY_FILE=$TLSDIR/server.key
+ export CORE_PEER_TLS_ROOTCERT_FILE=$INT_CA_CHAINFILE
+ # gossip variables
+ export CORE_PEER_GOSSIP_USELEADERELECTION=true
+ export CORE_PEER_GOSSIP_ORGLEADER=false
+ export CORE_PEER_GOSSIP_EXTERNALENDPOINT=$PEER_HOST:7051
+ if [ $NUM -gt 1 ]; then
+ # Point the non-anchor peers to the anchor peer, which is always the 1st peer
+ export CORE_PEER_GOSSIP_BOOTSTRAP=peer1-${ORG}:7051
+ fi
+}
+
+# Switch to the current org's admin identity. Enroll if not previously enrolled.
+function switchToAdminIdentity {
+ if [ ! -d $ORG_ADMIN_HOME ]; then
+ dowait "$CA_NAME to start" 10 $CA_LOGFILE $CA_CHAINFILE
+ log "Enrolling admin '$ADMIN_NAME' with $CA_HOST ..."
+ export FABRIC_CA_CLIENT_HOME=$ORG_ADMIN_HOME
+ export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ fabric-ca-client enroll -d -u https://$ADMIN_NAME:$ADMIN_PASS@$CA_HOST:7054
+ # If admincerts are required in the MSP, copy the cert there now and to my local MSP also
+ if [ $ADMINCERTS ]; then
+ mkdir -p $(dirname "${ORG_ADMIN_CERT}")
+ cp $ORG_ADMIN_HOME/msp/signcerts/* $ORG_ADMIN_CERT
+ mkdir $ORG_ADMIN_HOME/msp/admincerts
+ cp $ORG_ADMIN_HOME/msp/signcerts/* $ORG_ADMIN_HOME/msp/admincerts
+ fi
+ fi
+ export CORE_PEER_MSPCONFIGPATH=$ORG_ADMIN_HOME/msp
+}
+
+# Switch to the current org's user identity. Enroll if not previously enrolled.
+function switchToUserIdentity {
+ export FABRIC_CA_CLIENT_HOME=/etc/hyperledger/fabric/orgs/$ORG/user
+ export CORE_PEER_MSPCONFIGPATH=$FABRIC_CA_CLIENT_HOME/msp
+ if [ ! -d $FABRIC_CA_CLIENT_HOME ]; then
+ dowait "$CA_NAME to start" 10 $CA_LOGFILE $CA_CHAINFILE
+ log "Enrolling user for organization $ORG with home directory $FABRIC_CA_CLIENT_HOME ..."
+ export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ fabric-ca-client enroll -d -u https://$USER_NAME:$USER_PASS@$CA_HOST:7054
+ # Set up admincerts directory if required
+ if [ $ADMINCERTS ]; then
+ ACDIR=$CORE_PEER_MSPCONFIGPATH/admincerts
+ mkdir -p $ACDIR
+ cp $ORG_ADMIN_HOME/msp/signcerts/* $ACDIR
+ fi
+ fi
+}
+
+# Copy the org's admin cert into some target MSP directory
+# This is only required if ADMINCERTS is enabled.
+function copyAdminCert {
+ if [ $# -ne 1 ]; then
+ fatal "Usage: copyAdminCert "
+ fi
+ if $ADMINCERTS; then
+ dstDir=$1/admincerts
+ mkdir -p $dstDir
+ dowait "$ORG administator to enroll" 10 $SETUP_LOGFILE $ORG_ADMIN_CERT
+ cp $ORG_ADMIN_CERT $dstDir
+ fi
+}
+
+# Create the TLS directories of the MSP folder if they don't exist.
+# The fabric-ca-client should do this.
+function finishMSPSetup {
+ if [ $# -ne 1 ]; then
+ fatal "Usage: finishMSPSetup "
+ fi
+ if [ ! -d $1/tlscacerts ]; then
+ mkdir $1/tlscacerts
+ cp $1/cacerts/* $1/tlscacerts
+ if [ -d $1/intermediatecerts ]; then
+ mkdir $1/tlsintermediatecerts
+ cp $1/intermediatecerts/* $1/tlsintermediatecerts
+ fi
+ fi
+}
+
+function awaitSetup {
+ dowait "the 'setup' container to finish registering identities, creating the genesis block and other artifacts" $1 $SETUP_LOGFILE /$SETUP_SUCCESS_FILE
+}
+
+# Wait for one or more files to exist
+# Usage: dowait [ ...]
+function dowait {
+ if [ $# -lt 4 ]; then
+ fatal "Usage: dowait: $*"
+ fi
+ local what=$1
+ local secs=$2
+ local logFile=$3
+ shift 3
+ local logit=true
+ local starttime=$(date +%s)
+ for file in $*; do
+ until [ -f $file ]; do
+ if [ "$logit" = true ]; then
+ log -n "Waiting for $what ..."
+ logit=false
+ fi
+ sleep 1
+ if [ "$(($(date +%s)-starttime))" -gt "$secs" ]; then
+ echo ""
+ fatal "Failed waiting for $what ($file not found); see $logFile"
+ fi
+ echo -n "."
+ done
+ done
+ echo ""
+}
+
+# log a message
+function log {
+ if [ "$1" = "-n" ]; then
+ shift
+ echo -n "##### `date '+%Y-%m-%d %H:%M:%S'` $*"
+ else
+ echo "##### `date '+%Y-%m-%d %H:%M:%S'` $*"
+ fi
+}
+
+# fatal a message
+function fatal {
+ log "FATAL: $*"
+ exit 1
+}
diff --git a/fabric-ca/scripts/run-fabric.sh b/fabric-ca/scripts/run-fabric.sh
new file mode 100755
index 0000000000..76c9860fc2
--- /dev/null
+++ b/fabric-ca/scripts/run-fabric.sh
@@ -0,0 +1,191 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -e
+
+source $(dirname "$0")/env.sh
+
+function main {
+
+ done=false
+
+ # Wait for setup to complete and then wait another 5 seconds for the orderer and peers to start
+ awaitSetup 10
+ sleep 5
+
+ trap finish EXIT
+
+ mkdir -p $LOGPATH
+ logr "The docker 'run' container has started"
+
+ # Set ORDERER_PORT_ARGS to the args needed to communicate with the 1st orderer
+ IFS=', ' read -r -a OORGS <<< "$ORDERER_ORGS"
+ initOrdererVars ${OORGS[0]} 1
+ ORDERER_PORT_ARGS="-o $ORDERER_HOST:7050 --tls true --cafile $CA_CHAINFILE"
+
+ # Convert PEER_ORGS to an array named PORGS
+ IFS=', ' read -r -a PORGS <<< "$PEER_ORGS"
+
+ # Create the channel
+ createChannel
+
+ # All peers join the channel
+ for ORG in $PEER_ORGS; do
+ local COUNT=1
+ while [[ "$COUNT" -le $NUM_PEERS ]]; do
+ initPeerVars $ORG $COUNT
+ joinChannel
+ COUNT=$((COUNT+1))
+ done
+ done
+
+ # Update the anchor peers
+ for ORG in $PEER_ORGS; do
+ initPeerVars $ORG 1
+ switchToAdminIdentity
+ logr "Updating anchor peers for $PEER_HOST ..."
+ peer channel update -c $CHANNEL_NAME -f $ANCHOR_TX_FILE $ORDERER_PORT_ARGS
+ done
+
+ # Install chaincode on the 1st peer in each org
+ for ORG in $PEER_ORGS; do
+ initPeerVars $ORG 1
+ installChaincode
+ done
+
+ # Instantiate chaincode on the 1st peer of the 2nd org
+ makePolicy
+ initPeerVars ${PORGS[1]} 1
+ switchToAdminIdentity
+ logr "Instantiating chaincode on $PEER_HOST ..."
+ peer chaincode instantiate -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "$POLICY" $ORDERER_PORT_ARGS
+
+ # Query chaincode from the 1st peer of the 1st org
+ initPeerVars ${PORGS[0]} 1
+ switchToUserIdentity
+ chaincodeQuery 100
+
+ # Invoke chaincode on the 1st peer of the 1st org
+ initPeerVars ${PORGS[0]} 1
+ switchToUserIdentity
+ logr "Sending invoke transaction to $PEER_HOST ..."
+ peer chaincode invoke -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' $ORDERER_PORT_ARGS
+
+ ## Install chaincode on 2nd peer of 2nd org
+ initPeerVars ${PORGS[1]} 2
+ installChaincode
+
+ # Query chaincode on 2nd peer of 2nd org
+ sleep 10
+ initPeerVars ${PORGS[1]} 2
+ switchToUserIdentity
+ chaincodeQuery 90
+
+ logr "Congratulations! The tests ran successfully."
+
+ done=true
+
+}
+
+# Enroll as a peer admin and create the channel
+function createChannel {
+ initPeerVars ${PORGS[0]} 1
+ switchToAdminIdentity
+ logr "Creating channel '$CHANNEL_NAME' on $ORDERER_HOST ..."
+ peer channel create --logging-level=DEBUG -c $CHANNEL_NAME -f $CHANNEL_TX_FILE $ORDERER_PORT_ARGS
+}
+
+# Enroll as a fabric admin and join the channel
+function joinChannel {
+ switchToAdminIdentity
+ set +e
+ local COUNT=1
+ MAX_RETRY=10
+ while true; do
+ logr "Peer $PEER_HOST is attempting to join channel '$CHANNEL_NAME' (attempt #${COUNT}) ..."
+ peer channel join -b $CHANNEL_NAME.block
+ if [ $? -eq 0 ]; then
+ set -e
+ logr "Peer $PEER_HOST successfully joined channel '$CHANNEL_NAME'"
+ return
+ fi
+ if [ $COUNT -gt $MAX_RETRY ]; then
+ fatalr "Peer $PEER_HOST failed to join channel '$CHANNEL_NAME' in $MAX_RETRY retries"
+ fi
+ COUNT=$((COUNT+1))
+ sleep 1
+ done
+}
+
+chaincodeQuery () {
+ if [ $# -ne 1 ]; then
+ fatalr "Usage: chaincodeQuery "
+ fi
+ set +e
+ logr "Querying chaincode in channel '$CHANNEL_NAME' on peer '$PEER_HOST' ..."
+ local rc=1
+ local starttime=$(date +%s)
+ # Continue to poll until we get a successful response or reach QUERY_TIMEOUT
+ while test "$(($(date +%s)-starttime))" -lt "$QUERY_TIMEOUT"; do
+ sleep 1
+ peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >& log.txt
+ VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}')
+ if [ $? -eq 0 -a "$VALUE" = "$1" ]; then
+ logr "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful"
+ set -e
+ return 0
+ fi
+ echo -n "."
+ done
+ cat log.txt
+ cat log.txt >> $RUN_SUMFILE
+ fatalr "Failed to query channel '$CHANNEL_NAME' on peer '$PEER_HOST'; expected value was $1 and found $VALUE"
+}
+
+
+function makePolicy {
+ POLICY="OR("
+ local COUNT=0
+ for ORG in $PEER_ORGS; do
+ if [ $COUNT -ne 0 ]; then
+ POLICY="${POLICY},"
+ fi
+ initOrgVars $ORG
+ POLICY="${POLICY}'${ORG_MSP_ID}.member'"
+ COUNT=$((COUNT+1))
+ done
+ POLICY="${POLICY})"
+ log "policy: $POLICY"
+}
+
+function installChaincode {
+ switchToAdminIdentity
+ logr "Installing chaincode on $PEER_HOST ..."
+ peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac
+}
+
+function finish {
+ if [ "$done" = true ]; then
+ logr "See $RUN_LOGFILE for more details"
+ touch /$RUN_SUCCESS_FILE
+ else
+ logr "Tests did not complete successfully; see $RUN_LOGFILE for more details"
+ touch /$RUN_FAIL_FILE
+ fi
+}
+
+function logr {
+ log $*
+ log $* >> $RUN_SUMPATH
+}
+
+function fatalr {
+ logr "FATAL: $*"
+ exit 1
+}
+
+main
diff --git a/fabric-ca/scripts/setup-fabric.sh b/fabric-ca/scripts/setup-fabric.sh
new file mode 100755
index 0000000000..3837a87d7e
--- /dev/null
+++ b/fabric-ca/scripts/setup-fabric.sh
@@ -0,0 +1,288 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+#
+# This script does the following:
+# 1) registers orderer and peer identities with intermediate fabric-ca-servers
+# 2) Builds the channel artifacts (e.g. genesis block, etc)
+#
+
+function main {
+ sleep 1
+ log "Beginning building channel artifacts ..."
+ registerIdentities
+ getCACerts
+ makeConfigTxYaml
+ generateChannelArtifacts
+ log "Finished building channel artifacts"
+ touch /$SETUP_SUCCESS_FILE
+}
+
+# Enroll as the CA admin
+function enrollCAAdmin {
+ dowait "$CA_NAME to start" 10 $CA_LOGFILE $CA_CHAINFILE
+ log "Enrolling with $CA_NAME as bootstrap identity ..."
+ export FABRIC_CA_CLIENT_HOME=$HOME/cas/$CA_NAME
+ export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ fabric-ca-client enroll -d -u https://$CA_ADMIN_USER_PASS@$CA_HOST:7054
+}
+
+function registerIdentities {
+ log "Registering identities ..."
+ registerOrdererIdentities
+ registerPeerIdentities
+}
+
+# Register any identities associated with the orderer
+function registerOrdererIdentities {
+ for ORG in $ORDERER_ORGS; do
+ initOrgVars $ORG
+ enrollCAAdmin
+ local COUNT=1
+ while [[ "$COUNT" -le $NUM_ORDERERS ]]; do
+ initOrdererVars $ORG $COUNT
+ log "Registering $ORDERER_NAME with $CA_NAME"
+ fabric-ca-client register -d --id.name $ORDERER_NAME --id.secret $ORDERER_PASS
+ COUNT=$((COUNT+1))
+ done
+ log "Registering admin identity with $CA_NAME"
+ # The admin identity has the "hf.admin" attribute which is added to ECert by default
+ fabric-ca-client register -d --id.name $ADMIN_NAME --id.secret $ADMIN_PASS --id.attrs "hf.admin=true:ecert"
+ done
+}
+
+# Register any identities associated with a peer
+function registerPeerIdentities {
+ for ORG in $PEER_ORGS; do
+ initOrgVars $ORG
+ enrollCAAdmin
+ local COUNT=1
+ while [[ "$COUNT" -le $NUM_PEERS ]]; do
+ initPeerVars $ORG $COUNT
+ log "Registering $PEER_NAME with $CA_NAME"
+ fabric-ca-client register -d --id.name $PEER_NAME --id.secret $PEER_PASS
+ COUNT=$((COUNT+1))
+ done
+ log "Registering admin identity with $CA_NAME"
+ # The admin identity has the "hf.admin" attribute which is added to ECert by default
+ fabric-ca-client register -d --id.name $ADMIN_NAME --id.secret $ADMIN_PASS --id.attrs "hf.admin=true:ecert,abac.init=true:ecert"
+ log "Registering user identity with $CA_NAME"
+ fabric-ca-client register -d --id.name $USER_NAME --id.secret $USER_PASS
+ done
+}
+
+function getCACerts {
+ log "Getting CA certificates ..."
+ for ORG in $ORGS; do
+ initOrgVars $ORG
+ log "Getting CA certs for organization $ORG and storing in $ORG_MSP_DIR"
+ export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE
+ fabric-ca-client getcacert -d -u https://$CA_HOST:7054 -M $ORG_MSP_DIR
+ finishMSPSetup $ORG_MSP_DIR
+ # If ADMINCERTS is true, we need to enroll the admin now to populate the admincerts directory
+ if [ $ADMINCERTS ]; then
+ switchToAdminIdentity
+ fi
+ done
+}
+
+# printOrg
+function printOrg {
+ echo "
+ - &$ORG_CONTAINER_NAME
+
+ Name: $ORG
+
+ # ID to load the MSP definition as
+ ID: $ORG_MSP_ID
+
+ # MSPDir is the filesystem path which contains the MSP configuration
+ MSPDir: $ORG_MSP_DIR"
+}
+
+# printOrdererOrg
+function printOrdererOrg {
+ initOrgVars $1
+ printOrg
+}
+
+# printPeerOrg
+function printPeerOrg {
+ initPeerVars $1 $2
+ printOrg
+ echo "
+ 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: $PEER_HOST
+ Port: 7051"
+}
+
+function makeConfigTxYaml {
+ {
+ echo "################################################################################
+#
+# Profile
+#
+# - Different configuration profiles may be encoded here to be specified
+# as parameters to the configtxgen tool
+#
+################################################################################
+Profiles:
+
+ OrgsOrdererGenesis:
+ Orderer:
+ # Orderer Type: The orderer implementation to start
+ # Available types are \"solo\" and \"kafka\"
+ OrdererType: solo
+ Addresses:"
+
+ for ORG in $ORDERER_ORGS; do
+ local COUNT=1
+ while [[ "$COUNT" -le $NUM_ORDERERS ]]; do
+ initOrdererVars $ORG $COUNT
+ echo " - $ORDERER_HOST:7050"
+ COUNT=$((COUNT+1))
+ done
+ done
+
+ echo "
+ # 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:"
+
+ for ORG in $ORDERER_ORGS; do
+ initOrgVars $ORG
+ echo " - *${ORG_CONTAINER_NAME}"
+ done
+
+ echo "
+ Consortiums:
+
+ SampleConsortium:
+
+ Organizations:"
+
+ for ORG in $PEER_ORGS; do
+ initOrgVars $ORG
+ echo " - *${ORG_CONTAINER_NAME}"
+ done
+
+ echo "
+ OrgsChannel:
+ Consortium: SampleConsortium
+ Application:
+ <<: *ApplicationDefaults
+ Organizations:"
+
+ for ORG in $PEER_ORGS; do
+ initOrgVars $ORG
+ echo " - *${ORG_CONTAINER_NAME}"
+ done
+
+ echo "
+################################################################################
+#
+# Section: Organizations
+#
+# - This section defines the different organizational identities which will
+# be referenced later in the configuration.
+#
+################################################################################
+Organizations:"
+
+ for ORG in $ORDERER_ORGS; do
+ printOrdererOrg $ORG
+ done
+
+ for ORG in $PEER_ORGS; do
+ printPeerOrg $ORG 1
+ done
+
+ echo "
+################################################################################
+#
+# 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:
+"
+
+ } > /etc/hyperledger/fabric/configtx.yaml
+ # Copy it to the data directory to make debugging easier
+ cp /etc/hyperledger/fabric/configtx.yaml /$DATA
+}
+
+function generateChannelArtifacts() {
+ which configtxgen
+ if [ "$?" -ne 0 ]; then
+ fatal "configtxgen tool not found. exiting"
+ fi
+
+ log "Generating orderer genesis block at $GENESIS_BLOCK_FILE"
+ # 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 OrgsOrdererGenesis -outputBlock $GENESIS_BLOCK_FILE
+ if [ "$?" -ne 0 ]; then
+ fatal "Failed to generate orderer genesis block"
+ fi
+
+ log "Generating channel configuration transaction at $CHANNEL_TX_FILE"
+ configtxgen -profile OrgsChannel -outputCreateChannelTx $CHANNEL_TX_FILE -channelID $CHANNEL_NAME
+ if [ "$?" -ne 0 ]; then
+ fatal "Failed to generate channel configuration transaction"
+ fi
+
+ for ORG in $PEER_ORGS; do
+ initOrgVars $ORG
+ log "Generating anchor peer update transaction for $ORG at $ANCHOR_TX_FILE"
+ configtxgen -profile OrgsChannel -outputAnchorPeersUpdate $ANCHOR_TX_FILE \
+ -channelID $CHANNEL_NAME -asOrg $ORG
+ if [ "$?" -ne 0 ]; then
+ fatal "Failed to generate anchor peer update for $ORG"
+ fi
+ done
+}
+
+set -e
+
+SDIR=$(dirname "$0")
+source $SDIR/env.sh
+
+main
diff --git a/fabric-ca/scripts/start-intermediate-ca.sh b/fabric-ca/scripts/start-intermediate-ca.sh
new file mode 100755
index 0000000000..d69ec5c163
--- /dev/null
+++ b/fabric-ca/scripts/start-intermediate-ca.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+source $(dirname "$0")/env.sh
+initOrgVars $ORG
+
+set -e
+
+dowait "Root CA certificate file to be created" 10 $ROOT_CA_CERTFILE $ROOT_CA_LOGFILE
+
+sleep 2
+
+# Initialize the intermediate CA
+fabric-ca-server init -b $BOOTSTRAP_USER_PASS -u $PARENT_URL
+
+# Copy the intermediate CA's certificate chain to the data directory to be used by others
+cp $FABRIC_CA_SERVER_HOME/ca-chain.pem $TARGET_CHAINFILE
+
+# Start the intermediate CA
+fabric-ca-server start
diff --git a/fabric-ca/scripts/start-orderer.sh b/fabric-ca/scripts/start-orderer.sh
new file mode 100755
index 0000000000..be12d53883
--- /dev/null
+++ b/fabric-ca/scripts/start-orderer.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -e
+
+source $(dirname "$0")/env.sh
+
+# Wait for setup to complete sucessfully
+awaitSetup 10
+
+# Enroll to get orderer's TLS cert (using the "tls" profile)
+fabric-ca-client enroll -d --enrollment.profile tls -u $ENROLLMENT_URL -M /tmp/tls --csr.hosts $ORDERER_HOST
+
+# Copy the TLS key and cert to the appropriate place
+TLSDIR=$ORDERER_HOME/tls
+mkdir -p $TLSDIR
+cp /tmp/tls/keystore/* $ORDERER_GENERAL_TLS_PRIVATEKEY
+cp /tmp/tls/signcerts/* $ORDERER_GENERAL_TLS_CERTIFICATE
+rm -rf /tmp/tls
+
+# Enroll again to get the orderer's enrollment certificate (default profile)
+fabric-ca-client enroll -d -u $ENROLLMENT_URL -M $ORDERER_GENERAL_LOCALMSPDIR
+
+# Finish setting up the local MSP for the orderer
+finishMSPSetup $ORDERER_GENERAL_LOCALMSPDIR
+copyAdminCert $ORDERER_GENERAL_LOCALMSPDIR
+
+# Wait for the genesis block to be created
+dowait "genesis block to be created" 10 $SETUP_LOGFILE $ORDERER_GENERAL_GENESISFILE
+
+# Start the orderer
+env | grep ORDERER
+orderer
diff --git a/fabric-ca/scripts/start-peer.sh b/fabric-ca/scripts/start-peer.sh
new file mode 100755
index 0000000000..addfd2eef4
--- /dev/null
+++ b/fabric-ca/scripts/start-peer.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -e
+
+source $(dirname "$0")/env.sh
+
+awaitSetup 10
+
+# Enroll the peer to get a TLS cert
+fabric-ca-client enroll -d --enrollment.profile tls -u $ENROLLMENT_URL -M /tmp/tls --csr.hosts $PEER_HOST
+
+# Copy the TLS key and cert to the appropriate place
+TLSDIR=$PEER_HOME/tls
+mkdir -p $TLSDIR
+cp /tmp/tls/signcerts/* $CORE_PEER_TLS_CERT_FILE
+cp /tmp/tls/keystore/* $CORE_PEER_TLS_KEY_FILE
+rm -rf /tmp/tls
+
+# Enroll the peer to get an enrollment certificate and set up the core's local MSP directory
+fabric-ca-client enroll -d -u $ENROLLMENT_URL -M $CORE_PEER_MSPCONFIGPATH
+finishMSPSetup $CORE_PEER_MSPCONFIGPATH
+copyAdminCert $CORE_PEER_MSPCONFIGPATH
+
+# Start the peer
+log "Starting peer '$CORE_PEER_ID' with MSP at '$CORE_PEER_MSPCONFIGPATH'"
+env | grep CORE
+peer node start
diff --git a/fabric-ca/scripts/start-root-ca.sh b/fabric-ca/scripts/start-root-ca.sh
new file mode 100755
index 0000000000..27874ddf60
--- /dev/null
+++ b/fabric-ca/scripts/start-root-ca.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -e
+
+# Initialize the root CA
+fabric-ca-server init -b $BOOTSTRAP_USER_PASS
+
+# Copy the root CA's signing certificate to the data directory to be used by others
+cp $FABRIC_CA_SERVER_HOME/ca-cert.pem $TARGET_CERTFILE
+
+# Start the root CA
+fabric-ca-server start
diff --git a/fabric-ca/start.sh b/fabric-ca/start.sh
new file mode 100755
index 0000000000..5574b343b0
--- /dev/null
+++ b/fabric-ca/start.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+#
+# This script does everything required to run the fabric CA sample.
+#
+
+set -e
+
+SDIR=$(dirname "$0")
+source ${SDIR}/scripts/env.sh
+
+cd ${SDIR}
+
+# Delete docker containers
+dockerContainers=$(docker ps -a | awk '$2~/hyperledger/ {print $1}')
+if [ "$dockerContainers" != "" ]; then
+ log "Deleting existing docker containers ..."
+ docker rm -f $dockerContainers > /dev/null
+fi
+
+# Remove chaincode docker images
+chaincodeImages=`docker images | grep "^dev-peer" | awk '{print $3}'`
+if [ "$chaincodeImages" != "" ]; then
+ log "Removing chaincode docker images ..."
+ docker rmi -f $chaincodeImages > /dev/null
+fi
+
+# Start with a clean data directory
+DDIR=${SDIR}/${DATA}
+if [ -d ${DDIR} ]; then
+ log "Cleaning up the data directory from previous run at $DDIR"
+ rm -rf ${SDIR}/data
+fi
+mkdir -p ${DDIR}/logs
+
+# Create the docker-compose file
+${SDIR}/makeDocker.sh
+
+# Create the docker containers
+log "Creating docker containers ..."
+docker-compose up -d
+
+# Wait for the setup container to complete
+dowait "the 'setup' container to finish registering identities, creating the genesis block and other artifacts" 10 $SDIR/$SETUP_LOGFILE $SDIR/$SETUP_SUCCESS_FILE
+
+# Wait for the run container to start and then tails it's summary log
+dowait "the docker 'run' container to start" 15 ${SDIR}/${SETUP_LOGFILE} ${SDIR}/${RUN_SUMFILE}
+tail -f ${SDIR}/${RUN_SUMFILE}&
+TAIL_PID=$!
+
+# Wait for the run container to complete
+while true; do
+ if [ -f ${SDIR}/${RUN_SUCCESS_FILE} ]; then
+ kill -9 $TAIL_PID
+ exit 0
+ elif [ -f ${SDIR}/${RUN_FAIL_FILE} ]; then
+ kill -9 $TAIL_PID
+ exit 1
+ else
+ sleep 1
+ fi
+done
diff --git a/fabric-ca/stop.sh b/fabric-ca/stop.sh
new file mode 100755
index 0000000000..c350e46faf
--- /dev/null
+++ b/fabric-ca/stop.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. All Rights Reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -e
+SDIR=$(dirname "$0")
+source $SDIR/scripts/env.sh
+
+log "Stopping docker containers ..."
+docker-compose down
+log "Docker containers have been stopped"