Add channel update script

pull/142/head
Baohua Yang 2021-10-22 13:47:48 -07:00
parent d624e64b10
commit cbe0f0010e
5 changed files with 349 additions and 15 deletions

View File

@ -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

View File

@ -61,12 +61,12 @@ fi
main() { main() {
if [ $# -lt 3 ]; then if [ $# -lt 3 ]; then
echo "Not enough argument supplied" echo "Not enough argument supplied"
echo "$(basename $0) mspId channel ordererURL mspPath=${PWD}/msp-mspId" echo "$(basename $0) channel ordererURL mspId mspPath=${PWD}/msp-mspId"
exit 1 exit 1
fi fi
local mspId=$1 local channel=$1
local channel=$2 local ordererURL=$2
local ordererURL=$3 local mspId=$3
local mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the local msp path named as msp-${msp_id} local mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the local msp path named as msp-${msp_id}
export FABRIC_LOGGING_SPEC="debug" export FABRIC_LOGGING_SPEC="debug"

View File

@ -81,7 +81,7 @@ def process(directory):
f_read.close() f_read.close()
f_write.close() f_write.close()
else: else:
print("Ignore non-json file {}".format(f)) print("Ignore non .block.json file {}".format(f))
# Usage python json_flatter.py [path_containing_json_files] # Usage python json_flatter.py [path_containing_json_files]

View File

@ -1044,7 +1044,7 @@ configtxlatorEncode() {
} }
# configtxlator decode pb to json # configtxlator decode pb to json
# Usage: configtxlatorEncode msgType input output # Usage: configtxlatorDecode msgType input output
configtxlatorDecode() { configtxlatorDecode() {
local msgType=$1 local msgType=$1
local input=$2 local input=$2

View File

@ -20,11 +20,11 @@ def decode_if_b64(raw):
except binascii.Error: except binascii.Error:
success = False success = False
# if success: # result_bytes = b'xxxx\xx' #if success: # result_bytes = b'xxxx\xx'
# print('===================Start==================================') #print('===================Start==================================')
# print(raw) #print(raw)
# print(result) #print(result)
# print('=====================End===================================') #print('=====================End===================================')
return success, result return success, result
@ -44,7 +44,7 @@ def check_tree(tree, prefix, f_write):
else: # leaf else: # leaf
result = v result = v
if 'cert' in k or 'id_bytes' in k or 'value' in k and 'hash' not in k: if 'cert' in k or 'id_bytes' in k or 'value' in k and 'hash' not in k:
# print(prefix_path) #print(prefix_path)
success, result = decode_if_b64(v) success, result = decode_if_b64(v)
if success: if success:
result = "b64({})".format(result) result = "b64({})".format(result)
@ -76,13 +76,12 @@ def process(directory):
if f.endswith(".block.json"): if f.endswith(".block.json"):
file_name = os.path.join(json_dir, f) file_name = os.path.join(json_dir, f)
f_read = open(file=file_name, mode="r", encoding='utf-8') f_read = open(file=file_name, mode="r", encoding='utf-8')
f_write = open(file=file_name + "-flat.json", mode="w", f_write = open(file=file_name+"-flat.json", mode="w", encoding='utf-8')
encoding='utf-8')
check_tree(json.load(f_read), "", f_write) check_tree(json.load(f_read), "", f_write)
f_read.close() f_read.close()
f_write.close() f_write.close()
else: else:
print("Ignore non-json file {}".format(f)) print("Ignore non .block.json file {}".format(f))
# Usage python json_flatter.py [path_containing_json_files] # Usage python json_flatter.py [path_containing_json_files]