#!/bin/bash # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. set -e source $(dirname "$0")/env.sh CHAINCODE_NAME=abaccc #this function creates a channel and deploys the abac chaincode (from fabric-samples), then runs a few test cases function main { done=false cloneFabricSamples log "Test network using $CHAINCODE_NAME chaincode" # Set ORDERER_PORT_ARGS to the args needed to communicate with the 1st orderer IFS=', ' read -r -a OORGS <<< "$ORDERER_ORGS" # if we are running this script in an account remote from the main orderer account, make sure we use the # NLB endpoint for the orderer. Otherwise, assume we are running in the same K8s cluster as the orderer and use the local endpoint. if [[ -v $"REMOTE_PEER" ]]; then initOrdererVars ${OORGS[0]} 2 else initOrdererVars ${OORGS[0]} 1 fi export ORDERER_PORT_ARGS="-o $ORDERER_HOST:$ORDERER_PORT --tls --cafile $CA_CHAINFILE --clientauth" # export ORDERER_PORT_ARGS="-o $ORDERER_HOST:7050 --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 updateAnchorPeers 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 instantiateChaincode set +e # Query chaincode from the 1st peer of the 1st org initPeerVars ${PORGS[0]} 1 switchToUserIdentity chaincodeQuery 100 set -e # Invoke chaincode on the 1st peer of the 1st org initPeerVars ${PORGS[0]} 1 switchToUserIdentity chaincodeInvoke ## 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 initPeerVars ${PORGS[0]} 1 switchToUserIdentity # Revoke the user and generate CRL using admin's credentials revokeFabricUserAndGenerateCRL # Fetch config block fetchConfigBlock # Create config update envelope with CRL and update the config block of the channel createConfigUpdatePayloadWithCRL updateConfigBlock # querying the chaincode should fail as the user is revoked switchToUserIdentity queryAsRevokedUser if [ "$?" -ne 0 ]; then log "The revoked user $USER_NAME should have failed to query the $CHAINCODE_NAME chaincode in the channel '$CHANNEL_NAME'" exit 1 fi log "Congratulations! $CHAINCODE_NAME chaincode tests ran successfully." done=true } # git clone fabric-samples. We need this repo for the chaincode function cloneFabricSamples { log "cloneFabricSamples" mkdir -p /opt/gopath/src/github.com/hyperledger cd /opt/gopath/src/github.com/hyperledger git clone https://github.com/hyperledger/fabric-samples.git log "cloned FabricSamples" cd fabric-samples git checkout release-1.1 log "checked out version 1.1 of FabricSamples" log "cloneFabric" mkdir /opt/gopath/src/github.com/hyperledger/fabric } # Enroll as a peer admin and create the channel function createChannel { initPeerVars ${PORGS[0]} 1 switchToAdminIdentity log "Creating channel '$CHANNEL_NAME' with file '$CHANNEL_TX_FILE' on $ORDERER_HOST using connection '$ORDERER_CONN_ARGS'" local CHANNELLIST=`peer channel list | grep -c ${CHANNEL_NAME}` if [ $CHANNELLIST -gt 0 ]; then log "Channel '$CHANNEL_NAME' already exists - creation request ignored" else peer channel create --logging-level=DEBUG -c $CHANNEL_NAME -f $CHANNEL_TX_FILE $ORDERER_CONN_ARGS cp ${CHANNEL_NAME}.block /$DATA fi } # Enroll as a fabric admin and join the channel function joinChannel { switchToAdminIdentity set +e local COUNT=1 MAX_RETRY=10 cd /$DATA local CHANNELLIST=`peer channel list | grep -c ${CHANNEL_NAME}` if [ $CHANNELLIST -gt 0 ]; then log "Peer $PEER_NAME has already joined channel '$CHANNEL_NAME' - channel join request ignored" return fi while true; do log "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 log "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 } function updateAnchorPeers { log "Updating anchor peers for $PEER_HOST ..." peer channel update -c $CHANNEL_NAME -f $ANCHOR_TX_FILE $ORDERER_CONN_ARGS } function installChaincode { switchToAdminIdentity log "Installing $CHAINCODE_NAME chaincode on $PEER_HOST ..." peer chaincode install -n $CHAINCODE_NAME -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/go } function instantiateChaincode { switchToAdminIdentity log "Instantiating $CHAINCODE_NAME chaincode on $PEER_HOST ..." peer chaincode instantiate -C $CHANNEL_NAME -n $CHAINCODE_NAME -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "$POLICY" $ORDERER_CONN_ARGS } function chaincodeInvoke { log "Initialising $CHAINCODE_NAME on $PEER_NAME ..." peer chaincode invoke -C $CHANNEL_NAME -n $CHAINCODE_NAME -c '{"Args":["invoke","a","b","10"]}' $ORDERER_CONN_ARGS } function chaincodeQuery { if [ $# -ne 1 ]; then fatalr "Usage: chaincodeQuery " fi set +e log "Querying chaincode in the channel '$CHANNEL_NAME' on the peer '$PEER_HOST' ..." cd /$DATA 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 $CHAINCODE_NAME -c '{"Args":["query","a"]}' >& log-abac.txt VALUE=$(cat log-abac.txt | awk '/Query Result/ {print $NF}') if [ $? -eq 0 -a "$VALUE" = "$1" ]; then log "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful" set -e return 0 fi echo -n "." done cat log-abac.txt fatalr "Failed to query channel '$CHANNEL_NAME' on peer '$PEER_HOST'; expected value was $1 and found $VALUE" } function queryAsRevokedUser { set +e log "Querying the chaincode in the channel '$CHANNEL_NAME' on the peer '$PEER_HOST' as revoked user '$USER_NAME' ..." cd /$DATA local starttime=$(date +%s) # Continue to poll until we get an expected response or reach QUERY_TIMEOUT while test "$(($(date +%s)-starttime))" -lt "$QUERY_TIMEOUT"; do sleep 1 peer chaincode query -C $CHANNEL_NAME -n $CHAINCODE_NAME -c '{"Args":["query","a"]}' >& log-abac.txt if [ $? -ne 0 ]; then err=$(cat log-abac.txt | grep "access denied") if [ "$err" != "" ]; then log "Expected error occurred when the revoked user '$USER_NAME' queried the chaincode in the channel '$CHANNEL_NAME'" set -e return 0 fi fi echo -n "." done set -e cat log-abac.txt return 1 } 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 fetchConfigBlock { log "Fetching the configuration block of the channel '$CHANNEL_NAME'" peer channel fetch config $CONFIG_BLOCK_FILE -c $CHANNEL_NAME $ORDERER_CONN_ARGS } function updateConfigBlock { log "Updating the configuration block of the channel '$CHANNEL_NAME'" peer channel update -f $CONFIG_UPDATE_ENVELOPE_FILE -c $CHANNEL_NAME $ORDERER_CONN_ARGS } function createConfigUpdatePayloadWithCRL { log "Creating config update payload with the generated CRL for the organization '$ORG'" # Start the configtxlator configtxlator start & configtxlator_pid=$! log "configtxlator_pid:$configtxlator_pid" log "Sleeping 5 seconds for configtxlator to start..." sleep 5 pushd /tmp CTLURL=http://127.0.0.1:7059 # Convert the config block protobuf to JSON curl -X POST --data-binary @$CONFIG_BLOCK_FILE $CTLURL/protolator/decode/common.Block > config_block.json # Extract the config from the config block jq .data.data[0].payload.data.config config_block.json > config.json # Update crl in the config json crl=$(cat $CORE_PEER_MSPCONFIGPATH/crls/crl*.pem | base64 | tr -d '\n') cat config.json | jq '.channel_group.groups.Application.groups.'"${ORG}"'.values.MSP.value.config.revocation_list = ["'"${crl}"'"]' > updated_config.json # Create the config diff protobuf curl -X POST --data-binary @config.json $CTLURL/protolator/encode/common.Config > config.pb curl -X POST --data-binary @updated_config.json $CTLURL/protolator/encode/common.Config > updated_config.pb curl -X POST -F original=@config.pb -F updated=@updated_config.pb $CTLURL/configtxlator/compute/update-from-configs -F channel=$CHANNEL_NAME > config_update.pb # Convert the config diff protobuf to JSON curl -X POST --data-binary @config_update.pb $CTLURL/protolator/decode/common.ConfigUpdate > config_update.json # Create envelope protobuf container config diff to be used in the "peer channel update" command to update the channel configuration block echo '{"payload":{"header":{"channel_header":{"channel_id":"'"${CHANNEL_NAME}"'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' > config_update_as_envelope.json curl -X POST --data-binary @config_update_as_envelope.json $CTLURL/protolator/encode/common.Envelope > $CONFIG_UPDATE_ENVELOPE_FILE # Stop configtxlator kill $configtxlator_pid popd } function fatalr { log "FATAL: $*" exit 1 } main