From 4e93246532ad637ec497a694c94dc6e7c88ae97d Mon Sep 17 00:00:00 2001 From: michael steiner Date: Tue, 8 Dec 2020 19:26:44 -0800 Subject: [PATCH 1/4] Peer cli assist for client request/response processing Signed-off-by: michael steiner --- ecc/chaincode/ecc.go | 2 +- fabric/bin/peer.sh | 296 ++++++++++++++---- utils/fabric/Makefile | 4 +- .../peer-cli-assist.src/peer-cli-assist.go | 129 +++++++- utils/fabric/peer-cli-assist.src/test.sh | 29 ++ 5 files changed, 390 insertions(+), 70 deletions(-) create mode 100644 utils/fabric/peer-cli-assist.src/test.sh diff --git a/ecc/chaincode/ecc.go b/ecc/chaincode/ecc.go index 97724439e..cfe16c883 100644 --- a/ecc/chaincode/ecc.go +++ b/ecc/chaincode/ecc.go @@ -180,7 +180,7 @@ func (t *EnclaveChaincode) endorse(stub shim.ChaincodeStubInterface) pb.Response return shim.Error(err.Error()) } - return shim.Success(nil) + return shim.Success([]byte("OK")) // make sure we have a non-empty return on success so we can distinguish success from failure in cli ... } func ccParamsMatch(expected, actual *protos.CCParameters) bool { diff --git a/fabric/bin/peer.sh b/fabric/bin/peer.sh index 9b4a9b8a8..0521a839e 100755 --- a/fabric/bin/peer.sh +++ b/fabric/bin/peer.sh @@ -108,7 +108,7 @@ handle_lifecycle_chaincode_package() { echo "" echo "Flags for fpc-c chaincode:" echo " -s, --sgx-mode string SGX-mode to run with" - exit 0 + exit 0 ;; --clientauth) @@ -211,7 +211,7 @@ handle_lifecycle_chaincode_install() { -h|--help) # with help, no point to continue but run it right here .. try $RUN ${FABRIC_BIN_DIR}/peer "${ARGS_EXEC[@]}" - exit 0 + exit 0 ;; --clientauth) @@ -248,7 +248,7 @@ handle_lifecycle_chaincode_install() { # - extract package id PKG_ID via queryinstalled PKG_ID=$(${FABRIC_BIN_DIR}/peer lifecycle chaincode queryinstalled | awk "/Package ID: ${CC_LABEL}:/{print}" | sed -n 's/^Package ID: //; s/, Label:.*$//;p') [ ! -z "${PKG_ID}" ] || die "Could not extract package id" - # - remember this + # - remember this try touch "${FABRIC_STATE_DIR}/is-fpc-c-package.${PKG_ID}" fi @@ -268,7 +268,7 @@ handle_lifecycle_chaincode_approveformyorg() { shift; shift ;; -n|--name) - CC_NAME=$2; + CC_ID=$2; shift; shift ;; -v|--version) @@ -309,7 +309,7 @@ handle_lifecycle_chaincode_approveformyorg() { # - iff it is fpc pkg if [ -f "${FABRIC_STATE_DIR}/is-fpc-c-package.${PKG_ID}" ]; then # remember mapping - try touch "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_NAME}.${CC_VERSION}" + try touch "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_ID}.${CC_VERSION}" fi # - exit (instead of below return, which would re-execute install) exit 0 @@ -322,7 +322,7 @@ handle_lifecycle_chaincode_checkcommitreadiness() { while [[ $# > 0 ]]; do case "$1" in -n|--name) - CC_NAME=$2; + CC_ID=$2; shift; shift ;; -v|--version) @@ -348,7 +348,7 @@ handle_lifecycle_chaincode_checkcommitreadiness() { done # - iff it is fpc pkg - if [ -f "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_NAME}.${CC_VERSION}" ]; then + if [ -f "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_ID}.${CC_VERSION}" ]; then # no endorsement plugin can be specified in FPC [ -z "${ENDORSEMENT_PLUGIN_NAME}" ] || die "Endorsement plugins are disabled for FPC chaincodes" # no validation plugin can be specified in FPC @@ -368,7 +368,7 @@ handle_lifecycle_chaincode_commit() { while [[ $# > 0 ]]; do case "$1" in -n|--name) - CC_NAME=$2; + CC_ID=$2; shift; shift ;; -v|--version) @@ -394,7 +394,7 @@ handle_lifecycle_chaincode_commit() { done # - iff it is fpc pkg - if [ -f "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_NAME}.${CC_VERSION}" ]; then + if [ -f "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_ID}.${CC_VERSION}" ]; then # no endorsement plugin can be specified in FPC [ -z "${ENDORSEMENT_PLUGIN_NAME}" ] || die "Endorsement plugins are disabled for FPC chaincodes" # no validation plugin can be specified in FPC @@ -413,36 +413,61 @@ handle_lifecycle_chaincode_initEnclave() { # - remember variables we might need later while [[ $# > 0 ]]; do case "$1" in + -h|--help) + cat < /dev/null | wc -l) + FILES_NUM=$(ls -1 ${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_ID}.* 2> /dev/null | wc -l) if [ ${FILES_NUM} -eq 0 ]; then - die "initEnclave: $CC_NAME is not written in language 'fpc-c'" + die "initEnclave: $CC_ID is not written in language 'fpc-c'" fi # create host params - HOST_PARAMS="${PEER_ADDRESS}" + PEER_ENDPOINT="${PEER_ADDRESS}" # create init enclave message - INIT_ENCLAVE_PROTO=$( (echo "peer_endpoint: \"${HOST_PARAMS}\""; echo "attestation_params: \"${ATTESTATION_PARAMS}\"") | protoc --encode fpc.InitEnclaveMessage --proto_path=${FPC_PATH}/protos/fpc --proto_path=${FPC_PATH}/protos/fabric ${FPC_PATH}/protos/fpc/fpc.proto | base64 --wrap=0) + INIT_ENCLAVE_PROTO=$( (echo "peer_endpoint: \"${PEER_ENDPOINT}\""; echo "attestation_params: \"${ATTESTATION_PARAMS}\"") | protoc --encode fpc.InitEnclaveMessage --proto_path=${FPC_PATH}/protos/fpc --proto_path=${FPC_PATH}/protos/fabric ${FPC_PATH}/protos/fpc/fpc.proto | base64 --wrap=0) [ -z ${INIT_ENCLAVE_PROTO} ] && die "init enclave proto is empty" # trigger initEnclave - try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} --peerAddresses "${PEER_ADDRESS}" -C ${CHAN_ID} -n ${CC_NAME} -c '{"Args":["__initEnclave", "'${INIT_ENCLAVE_PROTO}'"]}' - B64CREDS=${RESPONSE} - [ -z ${B64CREDS} ] && die "initEnclave failed" - [ -z ${DEBUG+x} ] || say "initEnclave response (b64): ${B64CREDS}" - [ -z ${DEBUG+x} ] || say "initEnclave response (decoded): $(echo "${B64CREDS}" | base64 -d)" + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} --peerAddresses "${PEER_ADDRESS}" -C ${CHAN_ID} -n ${CC_ID} -c '{"Args":["__initEnclave", "'${INIT_ENCLAVE_PROTO}'"]}' + CC_CREDS_B64=${RESPONSE} + [ -z ${CC_CREDS_B64} ] && die "initEnclave failed" + [ -z ${DEBUG+x} ] || say "initEnclave response (b64): ${CC_CREDS_B64}" + [ -z ${DEBUG+x} ] || say "initEnclave response (decoded): $(echo "${CC_CREDS_B64}" | base64 -d)" - say "Convert credentials" - B64CONVCREDS=$(echo "${B64CREDS}" | ${PEER_ASSIST_CMD} attestation2Evidence) || die "could not convert credentials" - [ -z ${DEBUG+x} ] && say "initEnclave converted response (b64): ${B64CONVCREDS}" + echo "Convert credentials" + CC_CREDS_CONV_B64=$(echo "${CC_CREDS_B64}" | ${PEER_ASSIST_CMD} attestation2Evidence) || die "could not convert credentials" + [ -z ${DEBUG+x} ] && say "initEnclave converted response (b64): ${CC_CREDS_CONV_B64}" - say "Registering with Enclave Registry" - try $RUN ${FABRIC_BIN_DIR}/peer chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["RegisterEnclave", "'${B64CONVCREDS}'"]}' --waitForEvent + echo "Registering with Enclave Registry" + try $RUN ${FABRIC_BIN_DIR}/peer chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["RegisterEnclave", "'${CC_CREDS_CONV_B64}'"]}' --waitForEvent # NOTE: the chaincode encryption key is retrieved here for testing purposes - say "Querying Chaincode Encryption Key" - try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["QueryChaincodeEncryptionKey", "'${CC_NAME}'"]}' - B64CCEK="${RESPONSE}" - CCEK=$(echo ${B64CCEK} | base64 -d) - say "Chaincode EK (b64): ${B64CCEK}" - [ -z ${DEBUG+x} ] || say "Chaincode EK: ${CCEK}" + echo "Querying Chaincode Encryption Key" + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["QueryChaincodeEncryptionKey", "'${CC_ID}'"]}' + CC_EK_B64="${RESPONSE}" + CC_EK=$(echo ${CC_EK_B64} | base64 -d) + echo "Chaincode EK (b64): ${CC_EK_B64}" + [ -z ${DEBUG+x} ] || say "Chaincode EK: ${CC_EK}" # - exit (otherwise main function will invoke operation again!) exit 0 @@ -500,13 +527,166 @@ handle_lifecycle_chaincode_initEnclave() { # Chaincode command wrappers #-------------------------------------------- +handle_chaincode_call() { + CMD=$1; shift + + OTHER_ARGS=() + DO_HEX=0 + DO_RAW=0 + DO_WAIT=0 + while [[ $# > 0 ]]; do + case "$1" in + -h|--help) + return + ;; + -C|--channelID) + CHAN_ID=$2; + shift; shift + ;; + --peerAddresses) + PEER_ADDRESS=$2 + EXPLICIT_PEER=1 + shift; shift + ;; + -n|--name) + CC_ID=$2; + shift; shift + ;; + -c|--ctor) + CC_MSG=$2; + shift; shift + ;; + -I|--isInit) + IS_INIT=$2; + shift; shift + ;; + --transient) + TRANSIENT=$2; + shift; shift + ;; + -x|--hex) + DO_HEX=1 + shift + ;; + -r|--raw) + DO_RAW=1 + shift + ;; + --waitForEvent) + DO_WAIT=1 + shift + ;; + --waitForEventTimeout) + DO_WAIT_TIMEOUT=$1 + shift + ;; + *) + # these args we pass to both enclave query and validation invoke + # e.g., --clientauth, --(tls|ca|cert|key)*, --(conn*)*, --order* + OTHER_ARGS+=( "$1" ) + shift + ;; + esac + done + + # - iff it is not a fpc pkg + if [ ! -f "${FABRIC_STATE_DIR}/is-fpc-c-chaincode.${CC_ID}"* ]; then + [ -z ${DEBUG+x} ] || say "non-FPC chaincode" + return + else + [ -z ${DEBUG+x} ] || say "FPC chaincode" + fi + + # - check for unsupported options $IS_INIT, $TRANSIENT + [ ${DO_HEX} ] || die "--hex/-x is not supported for for FPC chaincodes" + [ ${DO_RAW} ] || die "--raw/-r is not supported for for FPC chaincodes" + [ -z "${IS_INIT}" ] || die "--isInit/-I is not supported for for FPC chaincodes" + [ -z "${TRANSIENT}" ] || die "--transient is not supported for for FPC chaincodes" + + # - query ercc.queryChaincodeEncryptionKey for chaincode encryption key + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["QueryChaincodeEncryptionKey", "'${CC_ID}'"]}' + CC_EK_B64="${RESPONSE}" + [ -z ${CC_EK_B64} ] && die "looking up chaincode encryption key failed" + [ -z ${DEBUG+x} ] || say "Chaincode EK (b64): ${CC_EK_B64}" + + # - if no endpoint specified, query ercc.queryChaincodeEndPoints for endpoint + if [ !${EXPLICIT_PEER} ]; then + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${ERCC_ID} -c '{"Args":["QueryChaincodeEndPoints", "'${CC_ID}'"]}' + PEER_ADDRESS="${RESPONSE}" + [ -z ${PEER_ADDRESS} ] && die "looking up peer endpoint failed" + [ -z ${DEBUG+x} ] || say "peer endpoint: ${PEER_ADDRESS}" + fi + + # - start cli assist with input to fd 3 and output from fd 4, a fifo + [ -z ${DEBUG+x} ] || say "starting peer assist .." + result_pipe=$(mktemp -u -t peer_cli_assistXXXX) + mkfifo $result_pipe || die "can't create fifo '${result_pipe}'" + exec 3> >(${PEER_ASSIST_CMD} handleRequestAndResponse "${CC_EK_B64}" "${result_pipe}") + assist_pid=$! + exec 4<${result_pipe} + + # - send clear-text request to assist + [ -z ${DEBUG+x} ] || say "sending cleartext request '${CC_MSG}' to peer assist .." + echo >&3 "${CC_MSG}" + + # - receive encrypted request from assist + read <&4 encrypted_request + [ -z ${encrypted_request} ] && die "peer assist failed to produce encrypted request" + [ -z ${DEBUG+x} ] || say "received encrypted request '${encrypted_request}' from peer assist" + + # - invoke function in enclave (as fabric query) + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode query --peerAddresses ${PEER_ADDRESS} "${OTHER_ARGS[@]}" -C ${CHAN_ID} -n ${CC_ID} -c '{"Args":["__invoke", "'${encrypted_request}'"]}' + encrypted_response="${RESPONSE}" + [ -z ${encrypted_response} ] && die "calling enclave failed" + + # - send encrypted response to assist + [ -z ${DEBUG+x} ] || say "sending encrypted response '${encrypted_response}' to peer assist .." + echo >&3 "${encrypted_response}" + + # - receive decrypted response from assist + read <&4 decrypted_response + [ -z ${decrypted_response} ] && die "peer assist failed to produce decrypted response" + [ -z ${DEBUG+x} ] || say "received decrypted response '${decrypted_response}' from peer assist" + + # - get assist return code + wait ${assist_pid} + rc=$? + [ ${rc} == 0 ] || die "assist could not properly transform requests/responses (rc=${rc})" + + # iff invoke (rather than query), cause endorsement flows + if [ ${CMD} == "invoke" ]; then + # - invoke validation of enclave endorsement + opt_arg="" + if [ ${EXPLICIT_PEER} ]; then + opt_arg="--peerAddresses ${PEER_ADDRESS} ${opt_arg}" + fi + if [ ${DO_WAIT} == 1 ]; then + opt_arg="--waitForEvent ${opt_arg}" + fi + if [ ! -z ${DO_WAIT_TIMEOUT+x} ]; then + opt_arg="--waitForEvent ${opt_arg}" + fi + try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode invoke "${OTHER_ARGS[@]}" ${opt_arg} -C ${CHAN_ID} -n ${CC_ID} -c '{"Args":["__endorse", "'${encrypted_response}'"]}' + endorse_response="${RESPONSE}" + [ ${endorse_response} == "OK" ] || die "endorsement failed: '${endorse_response}'" + [ -z ${DEBUG+x} ] || say "endorsement returned '${endorse_response}'" + fi + # - return decrypted response + # TODO: post-processing once we return proper fabric response objects + # As part of this, might also consider supporting -r/--raw and/or -x/--hex + # (Note that strangely these options exist only for query, not invoke?!) + echo ${decrypted_response} + + exit 0 +} + handle_chaincode_invoke() { - # TODO: eventually add client-side encryption/decryption + handle_chaincode_call "invoke" "$@" return } handle_chaincode_query() { - # TODO: eventually add client-side encryption/decryption + handle_chaincode_call "query" "$@" return } @@ -541,34 +721,34 @@ handle_channel_join() { ERCC_QUERY_INSTALL_LOG=${FABRIC_STATE_DIR}/ercc-query-install.$$.log ERCC_PATH="${FPC_PATH}/ercc" ERCC_TYPE="ercc-type" - say "Installing ercc on channel '${CHAN_ID}' ..." - say "Packaging ${ERCC_ID} ..." + echo "Installing ercc on channel '${CHAN_ID}' ..." + echo "Packaging ${ERCC_ID} ..." handle_lifecycle_ercc_package para sleep 3 - say "Installing ${ERCC_ID} ..." + echo "Installing ${ERCC_ID} ..." try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode install ${ERCC_PACKAGE} para sleep 3 - say "Querying installed chaincodes to find package id.." + echo "Querying installed chaincodes to find package id.." try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode queryinstalled >& ${ERCC_QUERY_INSTALL_LOG} para ERCC_PACKAGE_ID=$(awk "/Package ID: ${ERCC_LABEL}/{print}" ${ERCC_QUERY_INSTALL_LOG} | sed -n 's/^Package ID: //; s/, Label:.*$//;p') [ ! -z "${ERCC_PACKAGE_ID}" ] || die "Could not extract package id" - say "Approve for my org" + echo "Approve for my org" try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode approveformyorg -o ${ORDERER_ADDR} --channelID ${CHAN_ID} --name ${ERCC_ID} --version ${ERCC_VERSION} --package-id ${ERCC_PACKAGE_ID} --sequence ${ERCC_SEQUENCE} para sleep 3 - say "Checking for commit readiness" + echo "Checking for commit readiness" try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode checkcommitreadiness --channelID ${CHAN_ID} --name ${ERCC_ID} --version ${ERCC_VERSION} --sequence ${ERCC_SEQUENCE} --output json para sleep 3 - say "Committing chaincode definition...." + echo "Committing chaincode definition...." try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode commit -o ${ORDERER_ADDR} --channelID ${CHAN_ID} --name ${ERCC_ID} --version ${ERCC_VERSION} --sequence ${ERCC_SEQUENCE} para sleep 3 # Note: Below is not crucial but they do display potentially useful info and the second also is liveness-test for ercc - say "Query commited chaincodes on the channel" + echo "Query commited chaincodes on the channel" try $RUN ${FABRIC_BIN_DIR}/peer lifecycle chaincode querycommitted --channelID ${CHAN_ID} para sleep 3 diff --git a/utils/fabric/Makefile b/utils/fabric/Makefile index 1dfc788cf..d979de196 100644 --- a/utils/fabric/Makefile +++ b/utils/fabric/Makefile @@ -10,9 +10,11 @@ GO_CMDS= get-fabric-container-name peer-cli-assist build: $(GO_CMDS) -$(GO_CMDS): +$(GO_CMDS): FORCE $(GO) build $(GOTAGS) ./$@.src/$@.go +FORCE: + test: build clean: diff --git a/utils/fabric/peer-cli-assist.src/peer-cli-assist.go b/utils/fabric/peer-cli-assist.src/peer-cli-assist.go index 8d57abfc8..416fadab9 100644 --- a/utils/fabric/peer-cli-assist.src/peer-cli-assist.go +++ b/utils/fabric/peer-cli-assist.src/peer-cli-assist.go @@ -7,21 +7,40 @@ package main import ( + "bufio" + "bytes" + "encoding/json" "fmt" "io/ioutil" "os" + "strings" "github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc" + "github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc/crypto" + "github.com/hyperledger/fabric/common/flogging" ) +var logger = flogging.MustGetLogger("peer-cli-assist") + func printHelp() { fmt.Printf( - `Usage: %s [attestation2Evidence | createEncryptRequest | processEncryptedResponse] + `Usage: %s [attestation2Evidence | handleRequestAndResponse ] - attestation2Evidence: convert attestation to evidence in (base64-encoded) Credentials protobuf -- createEncryptRequest: create a (base64-encoded) encrypted fpc chaincode request protobuf -- processEncryptedResponse: decrypt and validate an (base64-encoded) encrypted fpc chaincode response protobuf -Input and outpus are via stdin and stdout, respectively.`, + (Input and outpus are via stdin and stdout, respectively.) +- handleRequestAndResponse: handles the encryption of invocation requests as well as the decryption + of the corresponding responses. + Expects three parameters + - the chaincode encryption key, as returned from ercc.QueryChaincodeEncryptionKey + (i.e., a base64-encoded string) + - a path to an (existing) fifo file through which the results are communicated back + As input, expects two lines + - a (single line!) json string in peer cli format '{"Function": "...", "Args": [...]}' with the invocation params, + after which it returns (as single line) the (base64-encoded) ChaincodeRequestMessage protobuf, and then + - a (base64-encoded) ChaincodeResponseMessage protobuf, after which it will decrypt it and + return a json-encoded fabric response protobuf object +`, os.Args[0]) + // TODO: above we have to fix the response payload format (json?) } func main() { @@ -45,12 +64,13 @@ func main() { os.Exit(1) } fmt.Printf("%s\n", credentialsStringOut) - case "createEncryptRequest": - fmt.Fprintf(os.Stderr, "FATAL: command %s not yet implemented\n", os.Args[1]) - os.Exit(1) - case "processEncryptedResponse": - fmt.Fprintf(os.Stderr, "FATAL: command %s not yet implemented\n", os.Args[1]) - os.Exit(1) + case "handleRequestAndResponse": + if len(os.Args) != 4 { + fmt.Fprintf(os.Stderr, "ERROR: command 'handleRequestAndResponse' needs exactly two arguments\n") + printHelp() + os.Exit(1) + } + handleEncryptedRequestAndResponse(os.Args[2], os.Args[3]) default: fmt.Fprintf(os.Stderr, "ERROR: Illegal command '%s'\n", os.Args[1]) printHelp() @@ -59,3 +79,92 @@ func main() { os.Exit(0) } + +func handleEncryptedRequestAndResponse(chaincodeEncryptionKey string, resultPipeName string) { + reader := bufio.NewReader(os.Stdin) + resultPipeFile, err := os.OpenFile(resultPipeName, os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: couldn't open pipe '%s': %v\n", resultPipeName, err) + os.Exit(1) + } + + // read request + requestJSON, err := reader.ReadString('\n') + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: couldn't read json request: %v\n", err) + os.Exit(1) + } + requestJSON = strings.TrimSpace(requestJSON) + type Request struct { + Function *string `json:"function,omitempty"` + Args *[]string `json:"args,omitempty"` + } + clearRequest := &Request{} + dec := json.NewDecoder(bytes.NewReader([]byte(requestJSON))) + dec.DisallowUnknownFields() + if err := dec.Decode(&clearRequest); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: unexpected json '%s': %v\n", requestJSON, err) + os.Exit(1) + } + // Note fabric has two invocation formats, i.e., missing Function means function is Args[0] + if clearRequest.Args == nil { + clearRequest.Args = &([]string{}) + } + if clearRequest.Function == nil { + if len(*clearRequest.Args) > 0 { + clearRequest.Function = &((*clearRequest.Args)[0]) + remainingArgs := (*clearRequest.Args)[1:] + clearRequest.Args = &remainingArgs + } else { + emptyString := "" + clearRequest.Function = &emptyString + } + } + logger.Debugf("Normalized json args '%s' to function='%s'/args='%v'", requestJSON, *clearRequest.Function, *clearRequest.Args) + + // setup crypto context + ep := &crypto.EncryptionProviderImpl{ + GetCcEncryptionKey: func() ([]byte, error) { + // TODO: might have to do some re-formatting, e.g., de-hex, here? + return []byte(chaincodeEncryptionKey), nil + }} + + ctx, err := ep.NewEncryptionContext() + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not setup crypto context: %v\n", err) + os.Exit(1) + } + logger.Debugf("Setup crypto context based on CC-ek '%v'", chaincodeEncryptionKey) + + // encrypt request ... + encryptedRequest, err := ctx.Conceal(*clearRequest.Function, *clearRequest.Args) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not encrypt request: %v\n", err) + os.Exit(1) + } + // ... and return it + logger.Debugf("Transformed request '%v' to '%v' and write to pipe '%s'", clearRequest, encryptedRequest, resultPipeName) + resultPipeFile.WriteString(fmt.Sprintf("%s\n", encryptedRequest)) + + // read encrypted response ... + encryptedResponse, err := reader.ReadString('\n') + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: couldn't read encrypted response: %v\n", err) + os.Exit(1) + } + encryptedResponse = strings.TrimSuffix(encryptedResponse, "\n") + + // .. decrypt it .. + // TODO: requires fix in Conceal & ecc/mock + // - should be base64 encoded + // - encrypted response should be a proper (serialized) response object, not only a string, and hence conceal should + // return the deserialized response, not a byte array .. + clearResponse, err := ctx.Reveal([]byte(encryptedResponse)) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not decrypt response: %v\n", err) + os.Exit(1) + } + // TODO: create a (single-line) json encoding once we get above a proper response object ... + logger.Debugf("Transformed response '%s' to '%s' and write to pipe '%s'", encryptedResponse, string(clearResponse), resultPipeName) + resultPipeFile.WriteString(fmt.Sprintf("%s\n", clearResponse)) +} diff --git a/utils/fabric/peer-cli-assist.src/test.sh b/utils/fabric/peer-cli-assist.src/test.sh new file mode 100644 index 000000000..c49688a12 --- /dev/null +++ b/utils/fabric/peer-cli-assist.src/test.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Copyright 2020 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +#set -ex + +result_pipe=$(mktemp -u -t testpipeXXXX) +mkfifo $result_pipe + +cc_ek="a-key" +exec 3> >( ../peer-cli-assist handleRequestAndResponse "${cc_ek}" "${result_pipe}") +assist_pid=$! + +exec 4<${result_pipe} + +echo >&3 '{"Function":"init", "Args": ["MyAuctionHouse"]}' + +read <&4 encrypted_request +echo "encrypted_request='$encrypted_request'" + +echo >&3 "I'm supposed to be an base64 encoded serialized ChaincodeResponseMessage" +read <&4 decrypted_response +echo "decrypted_response='$decrypted_response'" + +wait ${assist_pid} +echo "child exit code=$?" + +rm $result_pipe From fde77ef0f94522f07f8f8b138e88c389d7846711 Mon Sep 17 00:00:00 2001 From: michael steiner Date: Wed, 16 Dec 2020 15:10:14 -0800 Subject: [PATCH 2/4] Uniform arg & base64 treatment in ecc/contract Signed-off-by: michael steiner --- client_sdk/go/fpc/crypto/crypto.go | 23 ++++++++++++++++++--- ecc/chaincode/ecc.go | 22 +++++++++++++++++--- ecc/chaincode/enclave/enclave.go | 18 ++++------------- ecc/chaincode/enclave/interface.go | 29 ++++++++++++++++++--------- ecc/chaincode/enclave/mock_enclave.go | 11 ++++++---- 5 files changed, 69 insertions(+), 34 deletions(-) diff --git a/client_sdk/go/fpc/crypto/crypto.go b/client_sdk/go/fpc/crypto/crypto.go index 47628f32b..c78f7927e 100644 --- a/client_sdk/go/fpc/crypto/crypto.go +++ b/client_sdk/go/fpc/crypto/crypto.go @@ -70,14 +70,31 @@ type EncryptionContextImpl struct { chaincodeEncryptionKey []byte } -func (e *EncryptionContextImpl) Reveal(responseBytes []byte) ([]byte, error) { +func (e *EncryptionContextImpl) Reveal(responseBytesB64 []byte) ([]byte, error) { + responseBytes, err := base64.StdEncoding.DecodeString(string(responseBytesB64)) + if err != nil { + return nil, err + } + response := &protos.ChaincodeResponseMessage{} - err := proto.Unmarshal(responseBytes, response) + err = proto.Unmarshal(responseBytes, response) + if err != nil { + return nil, err + } + + clearResponseB64, err := decrypt(response.EncryptedResponse, e.resultEncryptionKey) + if err != nil { + return nil, err + } + // TODO: above should eventually be a (protobuf but not base64 serialized) fabric response object, + // rather than just the (base64-serialized) response string. + // so we also get fpc chaincode return-code/error-message as in for normal fabric + clearResponse, err := base64.StdEncoding.DecodeString(string(clearResponseB64)) if err != nil { return nil, err } - return decrypt(response.EncryptedResponse, e.resultEncryptionKey) + return clearResponse, nil } func (e *EncryptionContextImpl) Conceal(function string, args []string) (string, error) { diff --git a/ecc/chaincode/ecc.go b/ecc/chaincode/ecc.go index cfe16c883..44b721640 100644 --- a/ecc/chaincode/ecc.go +++ b/ecc/chaincode/ecc.go @@ -102,24 +102,40 @@ func (t *EnclaveChaincode) initEnclave(stub shim.ChaincodeStubInterface) pb.Resp func (t *EnclaveChaincode) invoke(stub shim.ChaincodeStubInterface) pb.Response { // call enclave var errMsg string - b64ChaincodeResponseMessage, errInvoke := t.enclave.ChaincodeInvoke(stub) + + // prep chaincode request message as input + _, args := stub.GetFunctionAndParameters() + if len(args) != 1 { + return shim.Error("no chaincodeRequestMessage as argument found") + } + chaincodeRequestMessageB64 := args[0] + chaincodeRequestMessage, err := base64.StdEncoding.DecodeString(chaincodeRequestMessageB64) + if err != nil { + errMsg := fmt.Sprintf("cannot base64 decode ChaincodeRequestMessage ('%s'): %s", chaincodeRequestMessageB64, err.Error()) + return shim.Error(errMsg) + } + + chaincodeResponseMessage, errInvoke := t.enclave.ChaincodeInvoke(stub, chaincodeRequestMessage) if errInvoke != nil { errMsg = fmt.Sprintf("t.enclave.Invoke failed: %s", errInvoke) logger.Errorf(errMsg) // likely a chaincode error, so we still want response go back ... } + chaincodeResponseMessageB64 := []byte(base64.StdEncoding.EncodeToString(chaincodeResponseMessage)) + logger.Debugf("base64-encoded response message: '%s'", chaincodeResponseMessageB64) + var response pb.Response if errInvoke == nil { response = pb.Response{ Status: shim.OK, - Payload: b64ChaincodeResponseMessage, + Payload: chaincodeResponseMessageB64, Message: errMsg, } } else { response = pb.Response{ Status: shim.ERROR, - Payload: b64ChaincodeResponseMessage, + Payload: chaincodeResponseMessageB64, Message: errMsg, } } diff --git a/ecc/chaincode/enclave/enclave.go b/ecc/chaincode/enclave/enclave.go index eb8bde6ca..4be9da431 100644 --- a/ecc/chaincode/enclave/enclave.go +++ b/ecc/chaincode/enclave/enclave.go @@ -12,7 +12,6 @@ package enclave import "C" import ( "context" - "encoding/base64" "fmt" "unsafe" @@ -89,15 +88,15 @@ func (e *EnclaveStub) Init(chaincodeParams, hostParams, attestationParams []byte return C.GoBytes(credentialsBuffer, C.int(credentialsSize)), nil } -func (e *EnclaveStub) GenerateCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) { +func (e *EnclaveStub) GenerateCCKeys() ([]byte, error) { panic("implement me") } -func (e *EnclaveStub) ExportCCKeys(credentials *protos.Credentials) (*protos.SignedExportMessage, error) { +func (e *EnclaveStub) ExportCCKeys(credentials []byte) ([]byte, error) { panic("implement me") } -func (e *EnclaveStub) ImportCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) { +func (e *EnclaveStub) ImportCCKeys() ([]byte, error) { panic("implement me") } @@ -106,7 +105,7 @@ func (e *EnclaveStub) GetEnclaveId() (string, error) { } // ChaincodeInvoke calls the enclave for transaction processing -func (e *EnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface) ([]byte, error) { +func (e *EnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface, crmProtoBytes []byte) ([]byte, error) { if !e.isInitialized { return nil, fmt.Errorf("enclave not yet initialized") } @@ -133,15 +132,6 @@ func (e *EnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface) ([]byte, cresmProtoBytesPtr := C.malloc(maxResponseSize) defer C.free(cresmProtoBytesPtr) - // prep chaincode request message as input - _, args := stub.GetFunctionAndParameters() - if len(args) != 1 { - return nil, fmt.Errorf("no chaincodeRequestMessage as argument found") - } - crmProtoBytes, err := base64.StdEncoding.DecodeString(args[0]) - if err != nil { - return nil, fmt.Errorf("cannot decode ChaincodeRequestMessage: %s", err.Error()) - } crmProtoBytesPtr := C.CBytes(crmProtoBytes) defer C.free(unsafe.Pointer(crmProtoBytesPtr)) diff --git a/ecc/chaincode/enclave/interface.go b/ecc/chaincode/enclave/interface.go index bce0c95ab..a002ec21f 100644 --- a/ecc/chaincode/enclave/interface.go +++ b/ecc/chaincode/enclave/interface.go @@ -8,7 +8,6 @@ SPDX-License-Identifier: Apache-2.0 package enclave import ( - "github.com/hyperledger-labs/fabric-private-chaincode/internal/protos" "github.com/hyperledger/fabric-chaincode-go/shim" "github.com/hyperledger/fabric/common/flogging" ) @@ -17,19 +16,29 @@ var logger = flogging.MustGetLogger("enclave") type StubInterface interface { + // Init initializes the chaincode enclave. + // The input and output parameters are serialized protobufs // triggered by an admin - Init(chaincodeParams, hostParams, attestationParams []byte) ([]byte, error) + Init(chaincodeParams, hostParams, attestationParams []byte) (credentials []byte, err error) - // key generation - GenerateCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) + // GetEnclaveId returns the EnclaveId hosted by the peer + GetEnclaveId() (string, error) // key distribution (Post-MVP Feature) - ExportCCKeys(credentials *protos.Credentials) (*protos.SignedExportMessage, error) - ImportCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) - // returns the EnclaveId hosted by the peer - GetEnclaveId() (string, error) + // GenerateCCKeys, key generation + // The output parameters is a serialized protobuf + GenerateCCKeys() (signedCCKeyRegistrationMessage []byte, err error) + + // ExportCCKeys exports chaincode secrets to enclave with provided credentials + // The input and output parameters are serialized protobufs + ExportCCKeys(credentials []byte) (signedExportMessage []byte, err error) + + // ImportCCKeys imports chaincode secrets + // The output parameters is a serialized protobuf + ImportCCKeys() (signedCCKeyRegistrationMessage []byte, err error) - // chaincode invoke - ChaincodeInvoke(stub shim.ChaincodeStubInterface) ([]byte, error) + // ChaincodeInvoke invokes fpc chaincode inside enclave + // chaincodeRequestMessage and chaincodeResponseMessage are serialized protobuf + ChaincodeInvoke(stub shim.ChaincodeStubInterface, chaincodeRequestMessage []byte) (chaincodeResponseMessage []byte, err error) } diff --git a/ecc/chaincode/enclave/mock_enclave.go b/ecc/chaincode/enclave/mock_enclave.go index 8dded508c..332ac3792 100644 --- a/ecc/chaincode/enclave/mock_enclave.go +++ b/ecc/chaincode/enclave/mock_enclave.go @@ -83,16 +83,19 @@ func (m *MockEnclaveStub) Init(serializedChaincodeParams, serializedHostParamsBy return proto.Marshal(credentials) } -func (m MockEnclaveStub) GenerateCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) { +func (m MockEnclaveStub) GenerateCCKeys() ([]byte, error) { panic("implement me") + // -> *protos.SignedCCKeyRegistrationMessage } -func (m MockEnclaveStub) ExportCCKeys(credentials *protos.Credentials) (*protos.SignedExportMessage, error) { +func (m MockEnclaveStub) ExportCCKeys(credentials []byte) ([]byte, error) { panic("implement me") + // credentials *protos.Credentials -> *protos.SignedExportMessage, } -func (m MockEnclaveStub) ImportCCKeys() (*protos.SignedCCKeyRegistrationMessage, error) { +func (m MockEnclaveStub) ImportCCKeys() ([]byte, error) { panic("implement me") + // -> *protos.SignedCCKeyRegistrationMessage } func (m *MockEnclaveStub) GetEnclaveId() (string, error) { @@ -104,7 +107,7 @@ func (m *MockEnclaveStub) GetEnclaveId() (string, error) { return strings.ToUpper(hex.EncodeToString(hash[:])), nil } -func (m *MockEnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface) ([]byte, error) { +func (m *MockEnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface, chaincodeRequestMessage []byte) ([]byte, error) { logger.Debug("ChaincodeInvoke") signedProposal, err := stub.GetSignedProposal() From 832e5a715ab54e9a506e27bb42b7c5ea948d56d3 Mon Sep 17 00:00:00 2001 From: michael steiner Date: Wed, 16 Dec 2020 19:16:03 -0800 Subject: [PATCH 3/4] Scripting improvement * somewhat more consistenly put debugish info to stderr so we can better script other scripts * fixed test-verification against new output format Signed-off-by: michael steiner --- fabric/bin/lib/common_ledger.sh | 37 ++++++++++++----------- fabric/bin/lib/common_utils.sh | 16 +++++----- fabric/bin/peer.sh | 6 ++-- integration/auction_test.sh | 53 +++++++++++++++++---------------- integration/deployment_test.sh | 20 +++++++------ integration/echo_test.sh | 9 +++--- 6 files changed, 73 insertions(+), 68 deletions(-) diff --git a/fabric/bin/lib/common_ledger.sh b/fabric/bin/lib/common_ledger.sh index 73379ad48..e0f3b739b 100644 --- a/fabric/bin/lib/common_ledger.sh +++ b/fabric/bin/lib/common_ledger.sh @@ -182,28 +182,31 @@ ledger_shutdown() { # Check the chaincode's response (ResponseData) of # peer chaincode invoke/query -# (executed via 'try_r' macro) against expected result. -# In case of failures, tries to increment integer variable FAILURES +# (executed via 'try_r/try_out_r' macro) against expected result. +# In case of failures, tries to increment integer variable NUM_FAILURES. Increment in all cases NUM_TESTS check_result() { - # Parse out the Response Data from the payload - CI_RESPONSE=${RESPONSE} - CI_RESPONSE=${CI_RESPONSE##*payload:\"} - CI_RESPONSE=${CI_RESPONSE%%\"*} - # Convert and de-encrypt it - CI_RESPONSE=$(echo ${CI_RESPONSE} | base64 -d) - say "b64 Decoded response: ${CI_RESPONSE}" - # Test response to expected result + if [ "${RESPONSE_TYPE}" == "out+err" ]; then + CI_RESPONSE=$(parse_invoke_result_from_log "${RESPONSE}") + CONTEXT=" context: '${RESPONSE}'" + else + CI_RESPONSE="${RESPONSE}" + CONTEXT="" + fi + if [[ ${CI_RESPONSE} == "$1" ]]; then gecho "PASSED" else - if [[ ${CI_RESPONSE} == $RESPONSE ]]; then - CONTEXT="" - else - CONTEXT=" context: '${RESPONSE}'" - fi - recho "FAILED (expected '${1}', got '${CI_RESPONSE}' ${CONTEXT})" - export FAILURES=$(($FAILURES+1)) + recho "FAILED (expected '${1}', got '${CI_RESPONSE}'${CONTEXT})" + export NUM_FAILURES=$(($NUM_FAILURES+1)) fi + export NUM_TESTS=$(($NUM_TESTS+1)) +} + +parse_invoke_result_from_log() { + RESPONSE="$1" + RESPONSE=${RESPONSE##*payload:\"} + RESPONSE=${RESPONSE%%\"*} + echo "${RESPONSE}" } diff --git a/fabric/bin/lib/common_utils.sh b/fabric/bin/lib/common_utils.sh index fe6b95815..9742e5213 100644 --- a/fabric/bin/lib/common_utils.sh +++ b/fabric/bin/lib/common_utils.sh @@ -43,9 +43,9 @@ function gecho () { # Common reporting functions: say, yell & die #----------------------------------------- -# say is stdout, yell is stderr +# they all write to stderr. if you want normal progres for stdout, just use echo function say () { - echo "$(basename $0): $*" + echo "$(basename $0): $*" >&2; } function yell () { @@ -72,16 +72,14 @@ try_fail() { (! "$@") || die "rev-test failed: $*" } -# Variant of try which stores commands stdout and stderr in variable RESPONSE +# Variant of try which stores commands stdout and stderr (or only stdout) in variable RESPONSE try_r() { - echo "$@" - export RESPONSE=$("$@" 2>&1) || die "test failed: $*" - echo $RESPONSE + say "$@" + export RESPONSE=$("$@" 2>&1) RESPONSE_TYPE="out+err" || die "test failed: $*" } try_out_r() { - echo "$@" - export RESPONSE=$("$@") || die "test failed: $*" - echo $RESPONSE + say "$@" + export RESPONSE=$("$@") RESPONSE_TYPE="out" || die "test failed: $*" } diff --git a/fabric/bin/peer.sh b/fabric/bin/peer.sh index 0521a839e..096fadea1 100755 --- a/fabric/bin/peer.sh +++ b/fabric/bin/peer.sh @@ -666,9 +666,9 @@ handle_chaincode_call() { if [ ! -z ${DO_WAIT_TIMEOUT+x} ]; then opt_arg="--waitForEvent ${opt_arg}" fi - try_out_r $RUN ${FABRIC_BIN_DIR}/peer chaincode invoke "${OTHER_ARGS[@]}" ${opt_arg} -C ${CHAN_ID} -n ${CC_ID} -c '{"Args":["__endorse", "'${encrypted_response}'"]}' - endorse_response="${RESPONSE}" - [ ${endorse_response} == "OK" ] || die "endorsement failed: '${endorse_response}'" + try_r $RUN ${FABRIC_BIN_DIR}/peer chaincode invoke "${OTHER_ARGS[@]}" ${opt_arg} -C ${CHAN_ID} -n ${CC_ID} -c '{"Args":["__endorse", "'${encrypted_response}'"]}' + endorse_response=$(parse_invoke_result_from_log "${RESPONSE}") + [ "${endorse_response}" == "OK" ] || die "endorsement failed: '${endorse_response}'" [ -z ${DEBUG+x} ] || say "endorsement returned '${endorse_response}'" fi # - return decrypted response diff --git a/integration/auction_test.sh b/integration/auction_test.sh index 46cd25d4a..2552d3f85 100755 --- a/integration/auction_test.sh +++ b/integration/auction_test.sh @@ -22,7 +22,8 @@ CC_EP="OR('SampleOrg.member')" # note that we use .member as NodeOUs is disabled num_rounds=3 num_clients=10 -FAILURES=0 +NUM_FAILURES=0 +NUM_TESTS=0 auction_test() { PKG=/tmp/${CC_ID}.tar.gz @@ -46,78 +47,78 @@ auction_test() { # Scenario 1 becho ">>>> Close and evaluate non existing auction. Response should be AUCTION_NOT_EXISTING" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction"]}' --waitForEvent check_result "AUCTION_NOT_EXISTING" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction0"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction0"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "AUCTION_NOT_EXISTING" # Scenario 2 becho ">>>> Create an auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction1"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction1"]}' --waitForEvent check_result "OK" becho ">>>> Create two equivalent bids. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash0", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash0", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash1", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash1", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "OK" becho ">>>> Close auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction1"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction1"]}' --waitForEvent check_result "OK" becho ">>>> Submit a bid on a closed auction. Response should be AUCTION_ALREADY_CLOSED" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash2", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction1", "JohnnyCash2", "2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "AUCTION_ALREADY_CLOSED"; becho ">>>> Evaluate auction. Response should be DRAW" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction1"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction1"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "DRAW" # Scenario 3 becho ">>>> Create an auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction2"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction2"]}' --waitForEvent check_result "OK" for (( i=0; i<=$num_rounds; i++ )) do becho ">>>> Submit unique bid. Response should be OK" b="$(($i%$num_clients))" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction2", "JohnnyCash'$b'", "'$b'"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"submit", "Args": ["MyAuction2", "JohnnyCash'$b'", "'$b'"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "OK" done becho ">>>> Close auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction2"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction2"]}' --waitForEvent check_result "OK" becho ">>>> Evaluate auction. Auction Result should be printed out" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction2"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result '{"bidder":"JohnnyCash3","value":3}' # Scenario 4 becho ">>>> Create a new auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction3"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction3"]}' --waitForEvent check_result "OK" becho ">>>> Create a duplicate auction. Response should be AUCTION_ALREADY_EXISTING" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction3"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction3"]}' --waitForEvent check_result "AUCTION_ALREADY_EXISTING" becho ">>>> Close auction and evaluate. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction3"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction3"]}' --waitForEvent check_result "OK" becho ">>>> Close an already closed auction. Response should be AUCTION_ALREADY_CLOSED" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction3"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"close", "Args": ["MyAuction3"]}' --waitForEvent check_result "AUCTION_ALREADY_CLOSED" becho ">>>> Evaluate auction. Response should be NO_BIDS" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction3"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"eval", "Args": ["MyAuction3"]}' # Don't do --waitForEvent, so potentially there is some parallelism here .. check_result "NO_BIDS" # Code below is used to test bug in issue #42 becho ">>>> Create a new auction. Response should be OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"init", "Args": ["MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction4"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"create", "Args": ["MyAuction4"]}' --waitForEvent check_result "OK" } @@ -142,10 +143,10 @@ say "- shutdown ledger" ledger_shutdown para -if [[ "$FAILURES" == 0 ]]; then +if [[ "$NUM_FAILURES" == 0 ]]; then yell "Auction test PASSED" else - yell "Auction test had ${FAILURES} failures" + yell "Auction test had ${NUM_FAILURES} failures out of ${NUM_TESTS} tests" exit 1 fi exit 0 diff --git a/integration/deployment_test.sh b/integration/deployment_test.sh index 9db3f2163..b6c84508e 100755 --- a/integration/deployment_test.sh +++ b/integration/deployment_test.sh @@ -17,7 +17,8 @@ FABRIC_SCRIPTDIR="${FPC_PATH}/fabric/bin/" . ${FABRIC_SCRIPTDIR}/lib/common_ledger.sh CC_EP="OR('SampleOrg.member')" # note that we use .member as NodeOUs is disabled with the crypto material used in the integration tests. -FAILURES=0 +NUM_FAILURES=0 +NUM_TESTS=0 run_test() { @@ -51,13 +52,13 @@ run_test() { try ${PEER_CMD} lifecycle chaincode checkcommitreadiness -C ${CHAN_ID} --name marbles02 --version ${CC_VER} --sequence ${CC_SEQ} try ${PEER_CMD} lifecycle chaincode commit -o ${ORDERER_ADDR} -C ${CHAN_ID} --name marbles02 --version ${CC_VER} --sequence ${CC_SEQ} - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["init", "MyAuctionHouse"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["init", "MyAuctionHouse"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["create", "MyAuction"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["create", "MyAuction"]}' --waitForEvent check_result "OK" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n marbles02 -c '{"Args":["initMarble","marble1","blue","35","tom"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n marbles02 -c '{"Args":["initMarble","marble1","blue","35","tom"]}' --waitForEvent # install examples/echo CC_PATH=${FPC_PATH}/examples/echo/_build/lib/ @@ -85,15 +86,15 @@ run_test() { try_fail ${PEER_CMD} lifecycle chaincode initEnclave -o ${ORDERER_ADDR} --peerAddresses "localhost:7051" --name wrong-cc-id try ${PEER_CMD} lifecycle chaincode initEnclave -o ${ORDERER_ADDR} --peerAddresses "localhost:7051" --name echo_test - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n echo_test -c '{"Args": ["moin"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n echo_test -c '{"Args": ["moin"]}' --waitForEvent check_result "moin" - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["submit", "MyAuction", "JohnnyCash0", "0"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n auction_test -c '{"Args":["submit", "MyAuction", "JohnnyCash0", "0"]}' --waitForEvent check_result "OK" try ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n marbles02 -c '{"Args":["readMarble","marble1"]}' --waitForEvent - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n echo_test -c '{"Args": ["bonjour"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n echo_test -c '{"Args": ["bonjour"]}' --waitForEvent check_result "bonjour" } @@ -127,11 +128,12 @@ say "- shutdown ledger" ledger_shutdown para -if [[ "$FAILURES" == 0 ]]; then +if [[ "$NUM_FAILURES" == 0 ]]; then yell "Deployement test PASSED" else - yell "Deployement test had ${FAILURES} failures" + yell "Deployement test had ${NUM_FAILURES} failures out of ${NUM_TESTS} tests" exit 1 fi exit 0 + diff --git a/integration/echo_test.sh b/integration/echo_test.sh index 3b0792a3c..8bd24bada 100755 --- a/integration/echo_test.sh +++ b/integration/echo_test.sh @@ -21,7 +21,8 @@ CC_SEQ="1" CC_EP="OR('SampleOrg.member')" # note that we use .member as NodeOUs is disabled with the crypto material used in the integration tests. num_rounds=10 -FAILURES=0 +NUM_FAILURES=0 +NUM_TESTS=0 echo_test() { PKG=/tmp/${CC_ID}.tar.gz @@ -56,7 +57,7 @@ echo_test() { for (( i=1; i<=$num_rounds; i++ )) do # echos - try_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Args": ["echo-'$i'"]}' --waitForEvent + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Args": ["echo-'$i'"]}' --waitForEvent check_result "echo-$i" done } @@ -83,10 +84,10 @@ say "- shutdown ledger" ledger_shutdown para -if [[ "$FAILURES" == 0 ]]; then +if [[ "$NUM_FAILURES" == 0 ]]; then yell "Echo test PASSED" else - yell "Echo test had ${FAILURES} failures" + yell "Echo test had ${NUM_FAILURES} failures out of ${NUM_TESTS} tests" exit 1 fi exit 0 From d08286cdd16930a32a35808ed1be70b5ca933227 Mon Sep 17 00:00:00 2001 From: michael steiner Date: Wed, 16 Dec 2020 21:02:47 -0800 Subject: [PATCH 4/4] bug fix for test-network Signed-off-by: michael steiner --- integration/test-network/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration/test-network/docker-compose.yml b/integration/test-network/docker-compose.yml index 3ad7ad24f..e7dad69a5 100644 --- a/integration/test-network/docker-compose.yml +++ b/integration/test-network/docker-compose.yml @@ -10,7 +10,7 @@ services: ecc.peer0.org1.example.com: container_name: ${CC_ID}.peer0.org1.example.com hostname: ${CC_ID}.peer0.org1.example.com - image: fpc/fpc-echo${HW_EXTENSION:-} + image: fpc/fpc-${CC_ID}${HW_EXTENSION:-} entrypoint: /usr/local/bin/chaincode environment: - CHAINCODE_SERVER_ADDRESS=${CC_ID}.peer0.org1.example.com:9999 @@ -41,7 +41,7 @@ services: ecc.peer0.org2.example.com: container_name: ${CC_ID}.peer0.org2.example.com hostname: ${CC_ID}.peer0.org2.example.com - image: fpc/fpc-echo${HW_EXTENSION:-} + image: fpc/fpc-${CC_ID}${HW_EXTENSION:-} entrypoint: /usr/local/bin/chaincode environment: - CHAINCODE_SERVER_ADDRESS=${CC_ID}.peer0.org2.example.com:9999