0

I have built a Hyperledger Fabric Network and the network is set up fine. The chaincode has also been deployed. Now, I want to call a function of the chaincode. If I have to do it via terminal, then it goes like:

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"StorePacketData","Args":["a0", "b0", "c0", "d0", "e0"]}'

This works perfectly fine. However, I want to call this function from a shell script where the arguments of the functions would be variables. This shell script file be called by another shell script. Hence, my shell script file looks like this:

#!/bin/bash

invokeCC() {

   arg1=$1
   arg2=$2
   arg3=$3
   arg4=$4
   arg5=$5

   export PATH=${PWD}/../bin:$PATH
   export FABRIC_CFG_PATH=$PWD/../config/
   export CORE_PEER_TLS_ENABLED=true
   export CORE_PEER_LOCALMSPID="Org1MSP"
   export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   export CORE_PEER_ADDRESS=localhost:7051

   peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"StorePacketData","Args":["$arg1", "$arg2", "$arg3", "$arg4", "$arg5"]}'
}

invokeCC $1 $2 $3 $4 $5

It is eveident the term:

'{"function":"StorePacketData","Args":["$arg1", "$arg2", "$arg3", "$arg4", "$arg5"]}'

is taken as a whole string and the variables can't be passed. Therefore, I tried a variant:

#!/bin/bash

invokeCC() {

   arg1=$1
   arg2=$2
   arg3=$3
   arg4=$4
   arg5=$5

   export PATH=${PWD}/../bin:$PATH
   export FABRIC_CFG_PATH=$PWD/../config/
   export CORE_PEER_TLS_ENABLED=true
   export CORE_PEER_LOCALMSPID="Org1MSP"
   export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   export CORE_PEER_ADDRESS=localhost:7051
   QUOTE="'"
   args="{\"function\":\"StorePacketData\",\"Args\":[\"$arg1\", \"$arg2\", \"$arg3\", \"$arg4\", \"$arg5\"]}"

   peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c $QUOTE$args$QUOTE
}

invokeCC $1 $2 $3 $4 $5

This gives error as well which is

Error: chaincode argument error: invalid character '\'' looking for beginning of value

I know that I am going wrong in the second method but I don't know what else can be done.

Please suggest what I should do here to invoke the chaincode. Let me know if I need to provide any other information.

Thanks in advance!

  • Aside: `$1 $2 $3 $4 $5` is better replaced with `"$@"` (including the quotes). Even `"$1" "$2" "$3" "$4" "$5"` would be something of an improvement over what you have now. – Charles Duffy Oct 18 '21 at 18:00
  • More importantly, though: Making JSON out of an argument list is a job for `jq`. It shouldn't be done with string concatenation at all. – Charles Duffy Oct 18 '21 at 18:01

2 Answers2

1

To generate well-formed, syntactically-valid JSON with an arbitrary list of command-line arguments, use jq version 1.6 with $ARGS.positional:

#!/usr/bin/env bash

invokeCC() {
  args=$(jq -n '{"function":"StorePacketData", "Args": $ARGS.positional}' --args "$@")
  peer chaincode invoke ... --args "$args"
}

invokeCC "$@"

One could also achieve the same goal using --arg and $ARGS.named:

invokeCC() {
  local -a jq_args=( )
  local arg idx=0 idx_str
  for arg in "$@"; do
    printf -v idx_str '%04d' "$idx"
    jq_args+=( --arg "arg$idx_str" "$arg" )
    (( ++idx ))
  done
  jq -nc "${jq_args[@]}" '{"function": "StorePacketData", "Args": [$ARGS.named | to_entries | sort_by(.key)[] | .value]}'
}

invokeCC "$@"
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Hi @Charles Duffy. Thanks a lot for your advice. I tried using your method but the code simply halts at the command `args=$(jq '{"function":"StorePacketData", "Args": $ARGS.positional}' --args "$@")`. Your answer appears to be much better. Can you please see again if I have made a mistake [here](https://github.com/smishy05/HFMisc/blob/main/invokeChaincode1.sh). It would be great if you could just verify this once and let me know of my mistake so that I can mark your answer as the correct one. – Shailesh Mishra Oct 19 '21 at 06:13
  • Do you know what version of jq you have? `--args` requires a quite recent one. – Charles Duffy Oct 19 '21 at 11:53
  • I did try the command `jq --version`. It is 1.6. – Shailesh Mishra Oct 19 '21 at 15:06
  • Heh, got it. Missed the `-n` argument to `jq`. It "stops" because it's waiting for stdin. (doesn't happen if you're testing somewhere with stdin coming from `/dev/null`, which I did). – Charles Duffy Oct 19 '21 at 15:26
  • Cool it works now! Thanks! – Shailesh Mishra Oct 19 '21 at 16:16
0

As @Charles Duffy suggested, I used jq for passing the argument. So, I changed my shell script to this:

#!/bin/bash

invokeCC() {

   arg1=$1
   arg2=$2
   arg3=$3
   arg4=$4
   arg5=$5

   export PATH=${PWD}/../bin:$PATH
   export FABRIC_CFG_PATH=$PWD/../config/
   export CORE_PEER_TLS_ENABLED=true
   export CORE_PEER_LOCALMSPID="Org1MSP"
   export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   export CORE_PEER_ADDRESS=localhost:7051

   echo hello

   args=$(jq \
  -n --arg val1 "$arg1" \
  -n --arg val2 "$arg2" \
  -n --arg val3 "$arg3" \
  -n --arg val4 "$arg4" \
  -n --arg val5 "$arg5" \
  '{"function":"StorePacketData", "Args": [$val1, $val2, $val3, $val4, $val5]}'
  )
   echo "$args"

   peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c "$args"
}

invokeCC "$1" "$2" "$3" "$4" "$5"

This worked absolutely fine. However, the solution suggested by @Charles Duffy is a much better one.

  • BTW, `echo "$args"` is more reliable than `echo $args`. See [I just assigned a variable, but `echo $variable` shows something else!](https://stackoverflow.com/questions/29378566/i-just-assigned-a-variable-but-echo-variable-shows-something-else) – Charles Duffy Oct 19 '21 at 15:42
  • Dang. I never learn. Thanks for pointing out again! – Shailesh Mishra Oct 19 '21 at 16:17