|
|
|
@ -0,0 +1,335 @@
|
|
|
|
|
#!/usr/bin/env sh
|
|
|
|
|
|
|
|
|
|
# Fetch a config block and update it. The new channel cfg section will be generated by $CAL_NEW_CFG_PY
|
|
|
|
|
|
|
|
|
|
# Usage: ./script channelListFile ordererURL mspId mspPath
|
|
|
|
|
# For testing a single channel, can use as: ./script channel ordererURL mspId mspPath
|
|
|
|
|
|
|
|
|
|
SYS_CHANNEL_NAME="testchainid" # default system channel name
|
|
|
|
|
CAL_NEW_CFG_PY="calc-new-channel-cfg.py" # script to calculate the new channel cfg section
|
|
|
|
|
|
|
|
|
|
# use configtxlator to decode pb to json
|
|
|
|
|
# Usage: configtxlatorDecode msgType input output
|
|
|
|
|
configtxlatorDecode() {
|
|
|
|
|
msgType=$1
|
|
|
|
|
input=$2
|
|
|
|
|
output=$3
|
|
|
|
|
|
|
|
|
|
if [ ! -f "$input" ]; then
|
|
|
|
|
echo "configDecode: input file not found"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! command -v configtxlator >/dev/null 2>&1; then
|
|
|
|
|
echo "configtxlator could not be found, please install it first"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "Decode $input --> $output using type $msgType"
|
|
|
|
|
configtxlator proto_decode \
|
|
|
|
|
--type="${msgType}" \
|
|
|
|
|
--input="${input}" \
|
|
|
|
|
--output="${output}"
|
|
|
|
|
|
|
|
|
|
[ $? -ne 0 ] && echo "Failed to decode config section from pb"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# use configtxlator to encode json to pb
|
|
|
|
|
# Usage: configtxlatorEncode msgType input output
|
|
|
|
|
configtxlatorEncode() {
|
|
|
|
|
msgType=$1
|
|
|
|
|
input=$2
|
|
|
|
|
output=$3
|
|
|
|
|
|
|
|
|
|
if [ ! -f "$input" ]; then
|
|
|
|
|
echo "configEncode: input file not found"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! command -v configtxlator >/dev/null 2>&1; then
|
|
|
|
|
echo "configtxlator could not be found, please install it first"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "Config Encode $input --> $output using type $msgType"
|
|
|
|
|
configtxlator proto_encode \
|
|
|
|
|
--type="${msgType}" \
|
|
|
|
|
--input="${input}" \
|
|
|
|
|
--output="${output}"
|
|
|
|
|
|
|
|
|
|
[ $? -eq 0 ] || echo "Failed to encode config section to pb"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# compute diff between two pb
|
|
|
|
|
# Usage: configtxlatorCompare channel origin_pb updated_pb output_pb
|
|
|
|
|
configtxlatorCompare() {
|
|
|
|
|
channel=$1
|
|
|
|
|
origin=$2
|
|
|
|
|
updated=$3
|
|
|
|
|
output=$4
|
|
|
|
|
|
|
|
|
|
echo "Config Compare $origin vs $updated > ${output} in channel $channel"
|
|
|
|
|
if [ ! -f "$origin" ] || [ ! -f "$updated" ]; then
|
|
|
|
|
echo "input file not found"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
configtxlator compute_update \
|
|
|
|
|
--original="${origin}" \
|
|
|
|
|
--updated="${updated}" \
|
|
|
|
|
--channel_id="${channel}" \
|
|
|
|
|
--output="${output}"
|
|
|
|
|
|
|
|
|
|
[ $? -eq 0 ] || echo "Failed to compute config update"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# fetchConfigBlock fetch the latest config block, and parse the config section into channelCfgJson
|
|
|
|
|
# Usage: fetchConfigBlock channel mspId mspPath ordererURL ordererTLSRoot channelCfgJson
|
|
|
|
|
fetchConfigBlock() {
|
|
|
|
|
if [ $# -lt 6 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channel channel_config_block_cfg.json update_tx.pb"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
channel=$1
|
|
|
|
|
mspId=$2
|
|
|
|
|
mspPath=$3
|
|
|
|
|
ordererURL=$4
|
|
|
|
|
ordererTLSRoot=$5
|
|
|
|
|
channelCfgJson=$6
|
|
|
|
|
config_block=${channel}_config.block
|
|
|
|
|
PAYLOAD_CFG_PATH=".data.data[0].payload.data.config"
|
|
|
|
|
|
|
|
|
|
export CORE_PEER_LOCALMSPID=${mspId}
|
|
|
|
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
|
|
|
|
export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
|
|
|
|
|
|
|
|
|
peer channel fetch config "${config_block}" \
|
|
|
|
|
-c "${channel}" \
|
|
|
|
|
-o "${ordererURL}" \
|
|
|
|
|
--tls \
|
|
|
|
|
--cafile "${ordererTLSRoot}"
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Decode config block into ${channel}_config.block.json"
|
|
|
|
|
configtxlatorDecode "common.Block" "${channel}_config.block" "${channel}_config_block.json"
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Export the config section ${PAYLOAD_CFG_PATH} from ${channel}_config_block.json into ${channelCfgJson}"
|
|
|
|
|
jq "${PAYLOAD_CFG_PATH}" "${channel}_config_block.json" >"${channelCfgJson}"
|
|
|
|
|
jq . "${channelCfgJson}" >/dev/null
|
|
|
|
|
[ $? -ne 0 ] && {
|
|
|
|
|
echo "${channel}_config_block_cfg.json is invalid"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Generate a new config section json from old config section, including the channel cfg updates
|
|
|
|
|
# Usage genNewCfgSection channel old_config_json new_config_json
|
|
|
|
|
calcNewCfgSection() {
|
|
|
|
|
if [ $# -lt 3 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channel channel_config_block_cfg.json channel_config_block_cfg_new.json"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
channel=$1
|
|
|
|
|
oldCfgJson=$2 # ${channel}_config_block_cfg.json
|
|
|
|
|
newCfgJson=$3 # ${channel}_config_block_cfg_new.json
|
|
|
|
|
|
|
|
|
|
# TODO: here we calculate the new channel cfg json using python
|
|
|
|
|
if [ "${channel}" = "${SYS_CHANNEL_NAME}" ]; then
|
|
|
|
|
python3 $CAL_NEW_CFG_PY --sys --input $oldCfgJson --output $newCfgJson
|
|
|
|
|
else
|
|
|
|
|
python3 $CAL_NEW_CFG_PY --input $oldCfgJson --output $newCfgJson
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
jq . "${newCfgJson}" >/dev/null
|
|
|
|
|
[ $? -ne 0 ] && {
|
|
|
|
|
echo "${newCfgJson} is invalid"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Generate a channel update transaction based on existing config block
|
|
|
|
|
# Usage genUpdateTx channel old_config_json update_tx_pb
|
|
|
|
|
genUpdateTx() {
|
|
|
|
|
if [ $# -lt 3 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channel channel_config_block_cfg.json update_tx.pb"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
channel=$1
|
|
|
|
|
oldCfgJson=$2 # ${channel}_config_block_cfg.json
|
|
|
|
|
oldCfgPb=${channel}_config_block_cfg.pb
|
|
|
|
|
newCfgJson=${channel}_config_block_cfg_new.json
|
|
|
|
|
newCfgPb=${channel}_config_block_cfg_new.pb
|
|
|
|
|
deltaCfgPb=${channel}_config_block_cfg_delta.pb
|
|
|
|
|
deltaCfgJson=${channel}_config_block_cfg_delta.json
|
|
|
|
|
deltaCfgEnvJson=${channel}_config_block_cfg_delta_env.json
|
|
|
|
|
deltaCfgEnvPb=${3:-${channel}_config_block_cfg_delta_env.pb}
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Start generating a channel update tx..."
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Modify channel cfg section: ${oldCfgJson}-->${newCfgJson}"
|
|
|
|
|
calcNewCfgSection "${channel}" "${oldCfgJson}" "${newCfgJson}"
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Convert channel cfg section json into pb files ..."
|
|
|
|
|
configtxlatorEncode "common.Config" "${oldCfgJson}" "${oldCfgPb}"
|
|
|
|
|
configtxlatorEncode "common.Config" "${newCfgJson}" "${newCfgPb}"
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Calculate the config delta between pb files: ${oldCfgPb}+${newCfgPb}-->${deltaCfgPb}"
|
|
|
|
|
configtxlatorCompare "${channel}" "${oldCfgPb}" "${newCfgPb}" "${deltaCfgPb}"
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Decode the config delta pb into json: ${deltaCfgPb}-->${deltaCfgJson}"
|
|
|
|
|
configtxlatorDecode "common.ConfigUpdate" "${deltaCfgPb}" "${deltaCfgJson}"
|
|
|
|
|
jq . "${deltaCfgJson}" >/dev/null
|
|
|
|
|
[ $? -ne 0 ] && {
|
|
|
|
|
echo "${deltaCfgJson} is invalid"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Wrap the delta config section as an envelope: ${deltaCfgJson}-->${deltaCfgEnvJson}"
|
|
|
|
|
echo '{"payload":{"header":{"channel_header":{"channel_id":"'"$channel"'", "type":2}},"data":{"config_update":'$(cat ${deltaCfgJson})'}}}' | jq . >"${deltaCfgEnvJson}"
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Encode the delta config update envelope into pb: ${deltaCfgEnvJson}-->${deltaCfgPb}"
|
|
|
|
|
configtxlatorEncode "common.Envelope" "${deltaCfgEnvJson}" "${deltaCfgEnvPb}"
|
|
|
|
|
|
|
|
|
|
echo "[$channel] Channel update tx is generated as ${deltaCfgPb}, now ready to sign and send the channel update tx"
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Sign a channel update transaction
|
|
|
|
|
# Usage: signUpdateTx mspId mspPath tx
|
|
|
|
|
signUpdateTx() {
|
|
|
|
|
if [ $# -lt 3 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) mspId mspPath tx"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
mspId=$1
|
|
|
|
|
mspPath=$2
|
|
|
|
|
tx=$3
|
|
|
|
|
|
|
|
|
|
echo "Sign channel config tx $tx by $mspId"
|
|
|
|
|
[ -f "${tx}" ] || {
|
|
|
|
|
echo "${tx} not exist"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export CORE_PEER_LOCALMSPID=${mspId}
|
|
|
|
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
|
|
|
|
|
|
|
|
|
peer channel signconfigtx -f "${tx}" >log.txt 2>&1
|
|
|
|
|
rc=$?
|
|
|
|
|
[ $rc -ne 0 ] && cat log.txt
|
|
|
|
|
if [ $rc -ne 0 ]; then
|
|
|
|
|
echo "Sign channel config tx $tx by $mspId failed"
|
|
|
|
|
else
|
|
|
|
|
echo "Sign channel config tx $tx by $mspId is successful"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Send a channel update transaction
|
|
|
|
|
# Usage: sendUpdateTx "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "${updateTx}"
|
|
|
|
|
sendUpdateTx() {
|
|
|
|
|
if [ $# -lt 6 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channel mspId mspPath ordererURL ordererTLSRoot updateTx"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
channel=$1
|
|
|
|
|
mspId=$2
|
|
|
|
|
mspPath=$3
|
|
|
|
|
ordererURL=$4
|
|
|
|
|
ordererTLSRoot=$5
|
|
|
|
|
tx=$6
|
|
|
|
|
|
|
|
|
|
export CORE_PEER_LOCALMSPID=${mspId}
|
|
|
|
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
|
|
|
|
export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Send the channel update tx by $mspId $mspPath to $ordererURL"
|
|
|
|
|
peer channel update \
|
|
|
|
|
-c "${channel}" \
|
|
|
|
|
-o "${ordererURL}" \
|
|
|
|
|
-f "${tx}" \
|
|
|
|
|
--tls \
|
|
|
|
|
--cafile "${ordererTLSRoot}" \
|
|
|
|
|
>log.txt 2>&1
|
|
|
|
|
|
|
|
|
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to send channel update tx to OSN" && cat log.txt; }
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Entrance function, will call other functions
|
|
|
|
|
# Update a single channel's config, need to be founder's admin
|
|
|
|
|
# Usage: updateChannel channel, ordererURL, mspId, mspPath
|
|
|
|
|
UpdateChannel() {
|
|
|
|
|
if [ $# -lt 3 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channel ordererURL mspId mspPath=${PWD}/msp-mspId"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
channel=$1
|
|
|
|
|
ordererURL=$2
|
|
|
|
|
mspId=$3
|
|
|
|
|
mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the msp path named as msp-${msp_id}
|
|
|
|
|
ordererTLSRoot=${mspPath}/tlscacerts/tlsca.cert
|
|
|
|
|
channelCfgJson=${channel}_config_block_cfg.json
|
|
|
|
|
updateTx="${channel}_config_block_cfg_delta_env.pb"
|
|
|
|
|
|
|
|
|
|
export FABRIC_LOGGING_SPEC="debug"
|
|
|
|
|
#export CORE_PEER_LOCALMSPID=${mspId}
|
|
|
|
|
#export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
|
|
|
|
#export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
|
|
|
|
#export CORE_PEER_TLS_ENABLED=true # Let client use TLS connection when connecting to peer
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Fetch config block from ${ordererURL} and decode the cfg section into ${channelCfgJson}"
|
|
|
|
|
fetchConfigBlock "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "$channelCfgJson"
|
|
|
|
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to fetch latest config from OSN" && exit 1; }
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Generate the channel update tx"
|
|
|
|
|
genUpdateTx "${channel}" "${channelCfgJson}" "${updateTx}"
|
|
|
|
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to generate new channel config" && exit 1; }
|
|
|
|
|
|
|
|
|
|
# TODO: do we support multiple msps?
|
|
|
|
|
echo "[${channel}] Sign the channel update tx ${updateTx} by $mspId $mspPath"
|
|
|
|
|
signUpdateTx "${mspId}" "${mspPath}" "${updateTx}"
|
|
|
|
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to sign the channel config update tx" && exit 1; }
|
|
|
|
|
|
|
|
|
|
echo "[${channel}] Send the channel update tx ${updateTx} by $mspId $mspPath to ${ordererTLSRoot}"
|
|
|
|
|
sendUpdateTx "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "${updateTx}"
|
|
|
|
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to send the channel update tx to ${ordererURL}" && exit 1; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if [ $# -lt 4 ]; then
|
|
|
|
|
echo "Not enough argument supplied"
|
|
|
|
|
echo "$(basename $0) channelListFile ordererURL mspId mspPath"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
channelListFile=$1
|
|
|
|
|
ordererURL=$2
|
|
|
|
|
mspId=$3
|
|
|
|
|
mspPath=$4 # the msp path
|
|
|
|
|
|
|
|
|
|
if [ -f ${channelListFile} ]; then
|
|
|
|
|
i=0
|
|
|
|
|
while read channel; do
|
|
|
|
|
((i++))
|
|
|
|
|
echo "Will process channel[$i]=$channel"
|
|
|
|
|
if [[ $channel =~ ^#.* ]]; then
|
|
|
|
|
echo "channel[$i]=$channel is ignored"
|
|
|
|
|
else
|
|
|
|
|
UpdateChannel "$channel" "${@:2}"
|
|
|
|
|
fi
|
|
|
|
|
done <${channelListFile}
|
|
|
|
|
else
|
|
|
|
|
# for test purpose only
|
|
|
|
|
UpdateChannel "$@" # channel, ordererURL, mspid, mspPath
|
|
|
|
|
fi
|