diff --git a/cardano/mainnet/00_common.sh b/cardano/mainnet/00_common.sh index c2b7332..9ee5cf0 100755 --- a/cardano/mainnet/00_common.sh +++ b/cardano/mainnet/00_common.sh @@ -1534,6 +1534,143 @@ queryLight_UTXO() { #${1} = address to query unset utxoRet response responseCode responseJSON addr error errorcnt } +# Return authoritative reference-script sizes for an exact JSON array of transaction inputs. +queryReferenceScriptSizes() { + local requested="${1}" + local ids id result="{}" response responseJSON responseCode size sizeJSON rows + local -a queryArgs + + if ! ids=$(jq -ce 'if type != "array" or any(.[]; type != "string" or (test("^[0-9a-fA-F]{64}#[0-9]+$") | not)) or length != (unique | length) then error("invalid input list") else . end' <<< "${requested}" 2>/dev/null); then + echo "ERROR - Invalid reference-script input list." >&2 + return 1 + fi + if [[ "$(jq length <<< "${ids}")" -eq 0 ]]; then printf '{}'; return 0; fi + + case ${workMode} in + "online") + queryArgs=() + while IFS= read -r id; do queryArgs+=(--tx-in "${id}"); done < <(jq -r '.[]' <<< "${ids}") + response=$(${cardanocli} ${cliEra} query utxo --output-json "${queryArgs[@]}" 2>&1) + if [[ $? -ne 0 ]] || ! jq -e --argjson ids "${ids}" ' + . as $utxos | type == "object" and + (keys | sort) == ($ids | sort) and + all($ids[]; . as $id | $utxos[$id] | type == "object" and has("referenceScript")) + ' >/dev/null 2>&1 <<< "${response}"; then + echo "ERROR - Could not obtain complete reference-script information from cardano-cli." >&2 + return 1 + fi + while IFS= read -r id; do + if [[ "$(jq -r --arg id "${id}" '.[$id].referenceScript == null' <<< "${response}")" == "true" ]]; then + result=$(jq -c --arg id "${id}" '. + {($id): null}' <<< "${result}") + else + size=$(${cardanocli} ${cliEra} query ref-script-size --output-json --tx-in "${id}" 2>&1) + if [[ $? -ne 0 ]] || ! size=$(jq -er '.refInputScriptSize | select(type == "number" and . >= 0 and floor == .)' <<< "${size}" 2>/dev/null); then + echo "ERROR - Could not determine the reference-script size for '${id}'." >&2 + return 1 + fi + result=$(jq -c --arg id "${id}" --argjson size "${size}" '. + {($id): $size}' <<< "${result}") + fi + done < <(jq -r '.[]' <<< "${ids}") + ;; + + "light") + local errorcnt=0 error=-1 + while [[ ${errorcnt} -lt 5 && ${error} -ne 0 ]]; do + error=0 + response=$(curl -sL -m 120 -X POST -w "---spo-scripts---%{http_code}" "${koiosAPI}/utxo_info?select=tx_hash,tx_index,is_spent,reference_script->hash,reference_script->size" -H "${koiosAuthorizationHeader}" -H "Accept: application/json" -H "Content-Type: application/json" -d "$(jq -cn --argjson ids "${ids}" '{_utxo_refs:$ids,_extended:true}')" 2>/dev/null) + if [[ $? -ne 0 ]]; then error=1; fi + errorcnt=$((errorcnt + 1)) + done + if [[ ${error} -ne 0 || ! "${response}" =~ (.*)---spo-scripts---([0-9]+)$ ]]; then + echo "ERROR - Query of the Koios-API via curl failed." >&2 + return 1 + fi + responseJSON="${BASH_REMATCH[1]}"; responseCode="${BASH_REMATCH[2]}" + if [[ "${responseCode}" != "200" ]]; then echo "ERROR - Koios HTTP response code: ${responseCode}" >&2; return 1; fi + if ! rows=$(jq -ce --argjson ids "${ids}" ' + if type != "array" then error("not an array") else + map(. + {id:(.tx_hash + "#" + (.tx_index | tostring))}) | + if length != ($ids | length) or (map(.id) | sort) != ($ids | sort) or (map(.id) | unique | length) != length or + any(.[]; .is_spent != false or (has("hash") | not) or (has("size") | not) or + (((.hash == null and .size == null) or + ((.hash | type) == "string" and (.hash | test("^[0-9a-fA-F]{56}$")) and + (.size | type) == "number" and .size >= 0 and (.size | floor) == .size)) | not)) + then error("incomplete response") else . end + end + ' <<< "${responseJSON}" 2>/dev/null); then + echo "ERROR - Koios returned incomplete or invalid reference-script information." >&2 + return 1 + fi + result=$(jq -c 'map({key:.id, value:(if .hash == null then null else .size end)}) | from_entries' <<< "${rows}") + ;; + + "offline") + if ! jq -e 'type == "object"' >/dev/null 2>&1 <<< "${offlineJSON:-}"; then readOfflineFile; fi + while IFS= read -r id; do + if ! sizeJSON=$(jq -ce --arg id "${id}" ' + [.address[]? | select((.utxoJSON | type) == "object" and (.utxoJSON | has($id))) | + if (.referenceScriptSizes | type) == "object" and (.referenceScriptSizes | has($id)) + then .referenceScriptSizes[$id] else "__missing__" end] as $matches | + if ($matches | length) != 1 or $matches[0] == "__missing__" or + (($matches[0] == null) | not) and (($matches[0] | type) != "number" or $matches[0] < 0 or ($matches[0] | floor) != $matches[0]) + then error("missing or conflicting metadata") else [$matches[0]] end + ' <<< "${offlineJSON}" 2>/dev/null); then + echo "Reference-script information is missing; refresh the payment address with 01_workOffline.sh add on the online/light machine and transfer the capture again." >&2 + return 1 + fi + size=$(jq -c '.[0]' <<< "${sizeJSON}") + result=$(jq -c --arg id "${id}" --argjson size "${size}" '. + {($id): $size}' <<< "${result}") + done < <(jq -r '.[]' <<< "${ids}") + ;; + + *) echo "ERROR - Unknown workMode '${workMode}'." >&2; return 1;; + esac + + printf '%s' "${result}" +} + +# Inspect the real transaction body, set referenceScriptSize, and warn about script-bearing inputs. +prepareReferenceScriptSpend() { + local txFile="${1}" view ids sizes feeIds spending collateralOnly + unset referenceScriptSize + + view=$(${cardanocli} debug transaction view --output-json --tx-file "${txFile}" 2>&1) + if [[ $? -ne 0 ]] || ! jq -e ' + type == "object" and + has("inputs") and has("reference inputs") and has("collateral inputs") and + ([.inputs, ."reference inputs", ."collateral inputs"] | all(.[]; type == "array" and all(.[]; type == "string"))) + ' >/dev/null 2>&1 <<< "${view}"; then + echo "ERROR - Could not inspect transaction inputs in '${txFile}'." >&2 + return 1 + fi + + ids=$(jq -c '[.inputs[], ."reference inputs"[], ."collateral inputs"[]] | unique' <<< "${view}") + sizes=$(queryReferenceScriptSizes "${ids}") || return 1 + feeIds=$(jq -c '[.inputs[], ."reference inputs"[]] | unique' <<< "${view}") + if ! referenceScriptSize=$(jq -er --argjson ids "${feeIds}" --argjson sizes "${sizes}" '$ids | map($sizes[.] // 0) | add // 0 | select(type == "number" and . >= 0 and floor == .)' <<< '{}'); then + unset referenceScriptSize + echo "ERROR - Invalid reference-script fee total." >&2 + return 1 + fi + + spending=$(jq -r --argjson sizes "${sizes}" '.inputs[] | select($sizes[.] != null) | "\(.) (\($sizes[.]) bytes)"' <<< "${view}") + if [[ -n "${spending}" ]]; then + echo "WARNING: This transaction spends reference-script UTxOs. Their existing reference locations will disappear; sending ADA back does not preserve the scripts. Applications using these UTxOs may stop working." >&2 + while IFS= read -r id; do echo " ${id}" >&2; done <<< "${spending}" + fi + + collateralOnly=$(jq -r --argjson sizes "${sizes}" ' + ([.inputs[], ."reference inputs"[]] | unique) as $fee | + ."collateral inputs"[] as $id | select(($fee | index($id)) == null and $sizes[$id] != null) | + "\($id) (\($sizes[$id]) bytes)" + ' <<< "${view}") + if [[ -n "${collateralOnly}" ]]; then + echo "WARNING: These collateral reference-script UTxOs may be consumed if phase-2 validation fails:" >&2 + while IFS= read -r id; do echo " ${id}" >&2; done <<< "${collateralOnly}" + fi + return 0 +} + #------------------------------------------------------- diff --git a/cardano/mainnet/01_claimRewards.sh b/cardano/mainnet/01_claimRewards.sh index c4bf923..514f3ff 100755 --- a/cardano/mainnet/01_claimRewards.sh +++ b/cardano/mainnet/01_claimRewards.sh @@ -616,8 +616,10 @@ if [[ ${rxcnt} == 1 ]]; then checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -756,6 +758,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed rewards withdrawal from '${stakeAddr}' to '${toAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -763,7 +766,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/01_sendAssets.sh b/cardano/mainnet/01_sendAssets.sh index 194b5a5..2a618e7 100755 --- a/cardano/mainnet/01_sendAssets.sh +++ b/cardano/mainnet/01_sendAssets.sh @@ -676,8 +676,10 @@ dummyReturnAmount=$(( ${totalLovelaces} - ${lovelacesToSend} )) ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${lovelacesToSend}${assetsSendString}" --tx-out "${sendFromAddr}+${dummyReturnAmount}${assetsReturnString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -814,6 +816,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"generated and signed utxo-token-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -821,7 +824,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/01_sendLovelaces.sh b/cardano/mainnet/01_sendLovelaces.sh index 1c6d262..1d0b60e 100755 --- a/cardano/mainnet/01_sendLovelaces.sh +++ b/cardano/mainnet/01_sendLovelaces.sh @@ -473,8 +473,10 @@ if [[ ${rxcnt} == 1 ]]; then #Sending ALLFUNDS or sending ALL lovelaces and no checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -685,6 +687,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -692,7 +695,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/01_workOffline.sh b/cardano/mainnet/01_workOffline.sh index 328a598..f90eb21 100755 --- a/cardano/mainnet/01_workOffline.sh +++ b/cardano/mainnet/01_workOffline.sh @@ -300,6 +300,8 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad utxoEntryCnt=$(jq length <<< ${utxoJSON}) if [[ ${utxoEntryCnt} == 0 ]]; then echo -e "\e[35mNo funds on the Address!\e[0m\n"; exit 1; else echo -e "\e[32m${utxoEntryCnt} UTXOs\e[0m found on the Address!"; fi + referenceScriptSizes=$(queryReferenceScriptSizes "$(jq -c 'keys' <<< "${utxoJSON}")") + if [[ $? -ne 0 ]]; then exit 1; fi echo totalLovelaces=0; #Init for the Sum @@ -429,6 +431,7 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad offlineJSON=$( jq ".address.\"${checkAddr}\" += {used: \"no\" }" <<< ${offlineJSON}) offlineJSON=$( jq ".address.\"${checkAddr}\" += {type: \"${typeOfAddr}\" }" <<< ${offlineJSON}) offlineJSON=$( jq ".address.\"${checkAddr}\" += {utxoJSON: ${utxoJSON} }" <<< ${offlineJSON}) + offlineJSON=$( jq ".address.\"${checkAddr}\".referenceScriptSizes = ${referenceScriptSizes}" <<< ${offlineJSON}) offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"added utxo-info for '${addrName}'\" } ]" <<< ${offlineJSON}) @@ -437,8 +440,10 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad #Readback the content and compare it to the current one utxoJSON=$(jq . <<< ${utxoJSON}) # bring it into the same format - readback=$(cat ${offlineFile} | jq -r ".address.\"${checkAddr}\".utxoJSON") - if [[ "${utxoJSON}" == "${readback}" ]]; then + referenceScriptSizes=$(jq . <<< ${referenceScriptSizes}) + readback=$(jq -r ".address.\"${checkAddr}\".utxoJSON" < "${offlineFile}") + readbackReferenceScriptSizes=$(jq -r ".address.\"${checkAddr}\".referenceScriptSizes" < "${offlineFile}") + if [[ "${utxoJSON}" == "${readback}" && "${referenceScriptSizes}" == "${readbackReferenceScriptSizes}" ]]; then showOfflineFileInfo; echo -e "\e[33mLatest Information about this address was added to the '$(basename ${offlineFile})'.\nYou can now transfer it to your offline machine to work with it, or you can\nadd another address information to the file by re-running this script.\e[0m\n"; else @@ -669,8 +674,19 @@ transactionTxJSON=$(jq -r ".transactions[${transactionIdx}].txJSON" <<< ${offlin #Write out the TxJSON to a temporary file txFile="${tempDir}/$(basename ${transactionFromName}).tmp.txfile" rm ${txFile} 2> /dev/null #delete an old one if present + echo "${transactionTxJSON}" > ${txFile}; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +# Re-resolve fee-critical input metadata before any queued transaction can be submitted. +prepareReferenceScriptSpend "$txFile" || exit 1 +recordedReferenceScriptSize=$(jq -c ".transactions[${transactionIdx}] | if has(\"referenceScriptSize\") then .referenceScriptSize else \"missing\" end" <<< "${offlineJSON}") +if ! jq -e --argjson resolved "${referenceScriptSize}" ' + (type == "number" and . >= 0 and floor == . and . == $resolved) or + (. == "missing" and $resolved == 0) +' >/dev/null 2>&1 <<< "${recordedReferenceScriptSize}"; then + echo -e "\e[35mReference-script fee information is missing or mismatched; rebuild and re-sign this transaction with the updated scripts.\e[0m" >&2 + exit 1 +fi case ${transactionType} in diff --git a/cardano/mainnet/03b_regStakingAddrCert.sh b/cardano/mainnet/03b_regStakingAddrCert.sh index f94ae4c..057e48f 100755 --- a/cardano/mainnet/03b_regStakingAddrCert.sh +++ b/cardano/mainnet/03b_regStakingAddrCert.sh @@ -552,8 +552,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${stakeAddr}.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -695,6 +697,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed staking key registration transaction for '${stakeAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -702,7 +705,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/05c_regStakepoolCert.sh b/cardano/mainnet/05c_regStakepoolCert.sh index 941c7c3..cae48d3 100755 --- a/cardano/mainnet/05c_regStakepoolCert.sh +++ b/cardano/mainnet/05c_regStakepoolCert.sh @@ -175,10 +175,12 @@ poolJSON=$(cat ${poolFile}.pool.json) #Read PoolJSON File into poolJSON variable #Check if there is already an opened witness in the poolJSON, if not create a new one with the current utctime in seconds as id regWitnessID=$(jq -r .regWitness.id <<< ${poolJSON} 2> /dev/null); if [[ "${regWitnessID}" == null || "${regWitnessID}" == 0 ]]; then #Opening up a new witness in the poolJSON + newWitnessCollection=true regWitnessID=""; #used later to determine if it is a new witnesscollection or an existing one poolJSON=$(jq ".regWitness = { id: $(date +%s), type: \"\", ttl: 0, regPayName: \"\", txBody: {}, witnesses: {} }" <<< ${poolJSON}) #Write the opened Witness only if the txBody was created successfully else + newWitnessCollection=false regWitnessDate=$(date --date="@${regWitnessID}") #Get date of the already existing witnesscollection fi @@ -658,8 +660,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${registrationCerts} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count ${witnessCount} --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count ${witnessCount} --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -724,6 +728,7 @@ echo poolJSON=$(jq ".regWitness.ttl = ${ttl}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.txBody = $(cat ${txBodyFile})" <<< ${poolJSON}) +poolJSON=$(jq ".regWitness.referenceScriptSize = ${referenceScriptSize}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayName = \"${regPayName}\"" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayAmount = ${minRegistrationFees}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayReturn = ${lovelacesToSend}" <<< ${poolJSON}) @@ -848,6 +853,19 @@ regWitnessID=$(jq -r ".regWitness.id" <<< ${poolJSON}) regWitnessDate=$(date --date="@${regWitnessID}" -R) regWitnessType=$(jq -r ".regWitness.type" <<< ${poolJSON}) regWitnessTxBody=$(jq -r ".regWitness.txBody" <<< ${poolJSON}) +txBodyFile="${tempDir}/$(basename ${poolName}).txbody" +echo "${regWitnessTxBody}" > "${txBodyFile}" +if ! ${newWitnessCollection}; then + prepareReferenceScriptSpend "${txBodyFile}" || exit 1 + storedReferenceScriptSize=$(jq -c '.regWitness | if has("referenceScriptSize") then .referenceScriptSize else "missing" end' <<< "${poolJSON}") + if ! jq -e --argjson resolved "${referenceScriptSize}" ' + (type == "number" and . >= 0 and floor == . and . == $resolved) or + (. == "missing" and $resolved == 0) + ' >/dev/null 2>&1 <<< "${storedReferenceScriptSize}"; then + echo -e "\e[35mReference-script fee information is missing or mismatched. Run 05d_poolWitness.sh clear ${poolFile} and rebuild this transaction.\e[0m" >&2 + exit 1 + fi +fi regWitnessHardwareWalletIncluded=$(jq -r ".regWitness.hardwareWalletIncluded" <<< ${poolJSON}) regWitnessPayAmount=$(jq -r ".regWitness.regPayAmount" <<< ${poolJSON}) regWitnessPayReturn=$(jq -r ".regWitness.regPayReturn" <<< ${poolJSON}) @@ -933,8 +951,6 @@ fi # txFile="${tempDir}/$(basename ${poolName}).tx" -txBodyFile="${tempDir}/$(basename ${poolName}).txbody" -echo "${regWitnessTxBody}" > ${txBodyFile} echo -e "\e[0mAssemble the Transaction with the payment \e[32m${regPayName}.skey\e[0m, node\e[32m ${poolName}.node.skey/hwsfile\e[0m and all PoolOwner Witnesses: \e[32m ${txFile} \e[90m" echo @@ -1079,6 +1095,7 @@ if ask "\e[33mDoes this look good for you? Do you have enough pledge in your own regProtectionKey: \"${regProtectionKey}\", poolMetaUrl: \"${poolMetaUrl}\", poolMetaHash: \"${poolMetaHash}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed pool registration transaction for '${poolMetaTicker}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -1107,7 +1124,8 @@ if ask "\e[33mDoes this look good for you? Do you have enough pledge in your own echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then echo echo -e "\e[0mStakepool Info JSON:\e[32m ${poolFile}.pool.json \e[90m" cat ${poolFile}.pool.json diff --git a/cardano/mainnet/05d_poolWitness.sh b/cardano/mainnet/05d_poolWitness.sh index 934b05a..78b69c2 100755 --- a/cardano/mainnet/05d_poolWitness.sh +++ b/cardano/mainnet/05d_poolWitness.sh @@ -403,6 +403,7 @@ case ${action} in rm ${tmpWitnessTxBody} 2> /dev/null rm ${tmpWitnessFile} 2> /dev/null echo "${witnessTxBody}" > ${tmpWitnessTxBody} + prepareReferenceScriptSpend "${tmpWitnessTxBody}" || exit 1 #Sign via normal cli skey or hardware key, depends on the content of the vkey description diff --git a/cardano/mainnet/06_regDelegationCert.sh b/cardano/mainnet/06_regDelegationCert.sh index c59f930..7737d08 100755 --- a/cardano/mainnet/06_regDelegationCert.sh +++ b/cardano/mainnet/06_regDelegationCert.sh @@ -550,8 +550,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${delegName}.deleg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -687,6 +689,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed delegation cert registration transaction for '${delegName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -694,7 +697,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/07b_deregStakepoolCert.sh b/cardano/mainnet/07b_deregStakepoolCert.sh index 0da680c..7b0aac0 100755 --- a/cardano/mainnet/07b_deregStakepoolCert.sh +++ b/cardano/mainnet/07b_deregStakepoolCert.sh @@ -402,8 +402,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${deregCertFile} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -564,6 +566,7 @@ if ask "\e[33mDoes this look good for you? Continue ?" N; then toAddr: \"${deregPayName}\", sendToAddr: \"${sendToAddr}\", poolMetaTicker: \"${poolMetaTicker}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed pool retirement transaction for '${poolMetaTicker}', payment via '${deregPayName}'\" } ]" <<< ${offlineJSON}) @@ -571,7 +574,8 @@ if ask "\e[33mDoes this look good for you? Continue ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then file_unlock ${poolFile}.pool.json newJSON=$(cat ${poolFile}.pool.json | jq ". += {deregSubmitted: \"$(date -R) (only offline, no proof)\"}") echo "${newJSON}" > ${poolFile}.pool.json diff --git a/cardano/mainnet/08b_deregStakingAddrCert.sh b/cardano/mainnet/08b_deregStakingAddrCert.sh index 8da2d90..e717549 100755 --- a/cardano/mainnet/08b_deregStakingAddrCert.sh +++ b/cardano/mainnet/08b_deregStakingAddrCert.sh @@ -536,8 +536,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${stakeAddr}.dereg-cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -684,6 +686,7 @@ if ask "\e[33mDoes this look good for you, continue ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed staking key deregistration transaction for '${stakeAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -691,7 +694,8 @@ if ask "\e[33mDoes this look good for you, continue ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/11a_mintAsset.sh b/cardano/mainnet/11a_mintAsset.sh index f7a388b..520bddc 100755 --- a/cardano/mainnet/11a_mintAsset.sh +++ b/cardano/mainnet/11a_mintAsset.sh @@ -400,8 +400,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --mint "${assetMintAmount} ${policyID}${point}${assetMintName}" --minting-script-file ${policyName}.policy.script --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -646,6 +648,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"minted ${assetMintAmount} '${assetMintInputName}' on '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -653,7 +656,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then #Updating the ${policyName}.${assetMintInputName}.asset json assetFileName="${policyName}.${assetMintInputName}.asset" diff --git a/cardano/mainnet/11b_burnAsset.sh b/cardano/mainnet/11b_burnAsset.sh index 0831e72..6472d7a 100755 --- a/cardano/mainnet/11b_burnAsset.sh +++ b/cardano/mainnet/11b_burnAsset.sh @@ -397,8 +397,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --mint "-${assetBurnAmount} ${policyID}${point}${assetBurnName}" --minting-script-file ${policyName}.policy.script --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -648,6 +650,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\e[33mDoes this look good for you, sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"burned ${assetBurnAmount} '${assetBurnInputName}' on '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -655,7 +658,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\e[33mDoes this look good for you, echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then #Updating the ${policyName}.${assetBurnName}.asset json diff --git a/cardano/mainnet/21b_regDRepCert.sh b/cardano/mainnet/21b_regDRepCert.sh index e79cf4a..ab9abbf 100755 --- a/cardano/mainnet/21b_regDRepCert.sh +++ b/cardano/mainnet/21b_regDRepCert.sh @@ -570,8 +570,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${drepName}.drep-reg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -718,6 +720,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed drep-id registration transaction for '${drepName}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -725,7 +728,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/21d_retDRepCert.sh b/cardano/mainnet/21d_retDRepCert.sh index 7eaf81d..4c03006 100755 --- a/cardano/mainnet/21d_retDRepCert.sh +++ b/cardano/mainnet/21d_retDRepCert.sh @@ -448,8 +448,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${drepName}.drep-ret.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -596,6 +598,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed drep-id retirement transaction for '${drepName}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -603,7 +606,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/22b_regVoteDelegCert.sh b/cardano/mainnet/22b_regVoteDelegCert.sh index 21556e8..50a2e78 100755 --- a/cardano/mainnet/22b_regVoteDelegCert.sh +++ b/cardano/mainnet/22b_regVoteDelegCert.sh @@ -546,8 +546,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${delegName}.vote-deleg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -689,6 +691,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed vote-delegation cert registration transaction for '${delegName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -696,7 +699,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/23c_regComAuthCert.sh b/cardano/mainnet/23c_regComAuthCert.sh index fab5797..4ba3a44 100755 --- a/cardano/mainnet/23c_regComAuthCert.sh +++ b/cardano/mainnet/23c_regComAuthCert.sh @@ -493,8 +493,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${comHotName}.cc-hot.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -642,6 +644,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed committee authorization cert registration transaction for '${comColdName}/${comHotName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -649,7 +652,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/23e_retComColdKeys.sh b/cardano/mainnet/23e_retComColdKeys.sh index 6e8411d..a0ad7a8 100755 --- a/cardano/mainnet/23e_retComColdKeys.sh +++ b/cardano/mainnet/23e_retComColdKeys.sh @@ -554,8 +554,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${comColdName}.cc-cold-ret.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -702,6 +704,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${retPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed committee authorization cert registration transaction for '${comColdName}/${comHotName}', payment via '${retPayName}'\" } ]" <<< ${offlineJSON}) @@ -709,7 +712,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/24b_regVote.sh b/cardano/mainnet/24b_regVote.sh index 05aa678..87345b2 100755 --- a/cardano/mainnet/24b_regVote.sh +++ b/cardano/mainnet/24b_regVote.sh @@ -544,8 +544,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${votefileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -730,6 +732,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -737,7 +740,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/25b_regAction.sh b/cardano/mainnet/25b_regAction.sh index 6ee0dbf..8af4cc3 100755 --- a/cardano/mainnet/25b_regAction.sh +++ b/cardano/mainnet/25b_regAction.sh @@ -745,12 +745,14 @@ case "${voteActionTag,,}" in --fee 200000 ${metafileParameter} ${actionfileParameter} --out-file ${txBodyFile} 2> /dev/stdout checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi + prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text \ --tx-body-file ${txBodyFile} \ --protocol-params-file <(echo ${protocolParametersJSON}) \ --witness-count 2 \ - --reference-script-size 0 2> /dev/stdout) + --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi @@ -763,8 +765,9 @@ case "${voteActionTag,,}" in #Generate Dummy-TxBody file for fee calculation ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${actionfileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi + prepareReferenceScriptSpend "$txBodyFile" || exit 1 #calculate the transaction fee. new parameters since cardano-cli 8.21.0 - fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) + fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' echo -e "\e[0mMimimum transfer Fee for ${txcnt}x TxIn & ${rxcnt}x TxOut: \e[32m $(convertToADA ${fee}) ADA / ${fee} lovelaces \e[90m" @@ -958,6 +961,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -965,7 +969,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/mainnet/README.md b/cardano/mainnet/README.md index b47bad3..668a3e5 100644 --- a/cardano/mainnet/README.md +++ b/cardano/mainnet/README.md @@ -291,6 +291,10 @@ Checkout the configuration parameters in your 00_common.sh Main-Configuration fi The scripts uses per default (configurable) the file **offlineTransfer.json** to store the data in between the Machines. +Offline address captures include reference-script sizes used for fee calculation. Refresh each payment address with `./01_workOffline.sh add ` before building or signing if the capture was created by an older script version. + +Transactions that spend UTxOs carrying reference scripts print a warning. Sending the ADA back to the same address does not recreate those scripts; applications using the spent reference locations may stop working. +  
diff --git a/cardano/testnet/00_common.sh b/cardano/testnet/00_common.sh index 4b31622..4d7df77 100755 --- a/cardano/testnet/00_common.sh +++ b/cardano/testnet/00_common.sh @@ -1534,6 +1534,142 @@ queryLight_UTXO() { #${1} = address to query unset utxoRet response responseCode responseJSON addr error errorcnt } +# Return authoritative reference-script sizes for an exact JSON array of transaction inputs. +queryReferenceScriptSizes() { + local requested="${1}" + local ids id result="{}" response responseJSON responseCode size sizeJSON rows + local -a queryArgs + + if ! ids=$(jq -ce 'if type != "array" or any(.[]; type != "string" or (test("^[0-9a-fA-F]{64}#[0-9]+$") | not)) or length != (unique | length) then error("invalid input list") else . end' <<< "${requested}" 2>/dev/null); then + echo "ERROR - Invalid reference-script input list." >&2 + return 1 + fi + if [[ "$(jq length <<< "${ids}")" -eq 0 ]]; then printf '{}'; return 0; fi + + case ${workMode} in + "online") + queryArgs=() + while IFS= read -r id; do queryArgs+=(--tx-in "${id}"); done < <(jq -r '.[]' <<< "${ids}") + response=$(${cardanocli} ${cliEra} query utxo --output-json "${queryArgs[@]}" 2>&1) + if [[ $? -ne 0 ]] || ! jq -e --argjson ids "${ids}" ' + . as $utxos | type == "object" and + (keys | sort) == ($ids | sort) and + all($ids[]; . as $id | $utxos[$id] | type == "object" and has("referenceScript")) + ' >/dev/null 2>&1 <<< "${response}"; then + echo "ERROR - Could not obtain complete reference-script information from cardano-cli." >&2 + return 1 + fi + while IFS= read -r id; do + if [[ "$(jq -r --arg id "${id}" '.[$id].referenceScript == null' <<< "${response}")" == "true" ]]; then + result=$(jq -c --arg id "${id}" '. + {($id): null}' <<< "${result}") + else + size=$(${cardanocli} ${cliEra} query ref-script-size --output-json --tx-in "${id}" 2>&1) + if [[ $? -ne 0 ]] || ! size=$(jq -er '.refInputScriptSize | select(type == "number" and . >= 0 and floor == .)' <<< "${size}" 2>/dev/null); then + echo "ERROR - Could not determine the reference-script size for '${id}'." >&2 + return 1 + fi + result=$(jq -c --arg id "${id}" --argjson size "${size}" '. + {($id): $size}' <<< "${result}") + fi + done < <(jq -r '.[]' <<< "${ids}") + ;; + + "light") + local errorcnt=0 error=-1 + while [[ ${errorcnt} -lt 5 && ${error} -ne 0 ]]; do + error=0 + response=$(curl -sL -m 120 -X POST -w "---spo-scripts---%{http_code}" "${koiosAPI}/utxo_info?select=tx_hash,tx_index,is_spent,reference_script->hash,reference_script->size" -H "${koiosAuthorizationHeader}" -H "Accept: application/json" -H "Content-Type: application/json" -d "$(jq -cn --argjson ids "${ids}" '{_utxo_refs:$ids,_extended:true}')" 2>/dev/null) + if [[ $? -ne 0 ]]; then error=1; fi + errorcnt=$((errorcnt + 1)) + done + if [[ ${error} -ne 0 || ! "${response}" =~ (.*)---spo-scripts---([0-9]+)$ ]]; then + echo "ERROR - Query of the Koios-API via curl failed." >&2 + return 1 + fi + responseJSON="${BASH_REMATCH[1]}"; responseCode="${BASH_REMATCH[2]}" + if [[ "${responseCode}" != "200" ]]; then echo "ERROR - Koios HTTP response code: ${responseCode}" >&2; return 1; fi + if ! rows=$(jq -ce --argjson ids "${ids}" ' + if type != "array" then error("not an array") else + map(. + {id:(.tx_hash + "#" + (.tx_index | tostring))}) | + if length != ($ids | length) or (map(.id) | sort) != ($ids | sort) or (map(.id) | unique | length) != length or + any(.[]; .is_spent != false or (has("hash") | not) or (has("size") | not) or + (((.hash == null and .size == null) or + ((.hash | type) == "string" and (.hash | test("^[0-9a-fA-F]{56}$")) and + (.size | type) == "number" and .size >= 0 and (.size | floor) == .size)) | not)) + then error("incomplete response") else . end + end + ' <<< "${responseJSON}" 2>/dev/null); then + echo "ERROR - Koios returned incomplete or invalid reference-script information." >&2 + return 1 + fi + result=$(jq -c 'map({key:.id, value:(if .hash == null then null else .size end)}) | from_entries' <<< "${rows}") + ;; + + "offline") + if ! jq -e 'type == "object"' >/dev/null 2>&1 <<< "${offlineJSON:-}"; then readOfflineFile; fi + while IFS= read -r id; do + if ! sizeJSON=$(jq -ce --arg id "${id}" ' + [.address[]? | select((.utxoJSON | type) == "object" and (.utxoJSON | has($id))) | + if (.referenceScriptSizes | type) == "object" and (.referenceScriptSizes | has($id)) + then .referenceScriptSizes[$id] else "__missing__" end] as $matches | + if ($matches | length) != 1 or $matches[0] == "__missing__" or + (($matches[0] == null) | not) and (($matches[0] | type) != "number" or $matches[0] < 0 or ($matches[0] | floor) != $matches[0]) + then error("missing or conflicting metadata") else [$matches[0]] end + ' <<< "${offlineJSON}" 2>/dev/null); then + echo "Reference-script information is missing; refresh the payment address with 01_workOffline.sh add on the online/light machine and transfer the capture again." >&2 + return 1 + fi + size=$(jq -c '.[0]' <<< "${sizeJSON}") + result=$(jq -c --arg id "${id}" --argjson size "${size}" '. + {($id): $size}' <<< "${result}") + done < <(jq -r '.[]' <<< "${ids}") + ;; + + *) echo "ERROR - Unknown workMode '${workMode}'." >&2; return 1;; + esac + + printf '%s' "${result}" +} + +# Inspect the real transaction body, set referenceScriptSize, and warn about script-bearing inputs. +prepareReferenceScriptSpend() { + local txFile="${1}" view ids sizes feeIds spending collateralOnly + unset referenceScriptSize + + view=$(${cardanocli} debug transaction view --output-json --tx-file "${txFile}" 2>&1) + if [[ $? -ne 0 ]] || ! jq -e ' + type == "object" and + has("inputs") and has("reference inputs") and has("collateral inputs") and + ([.inputs, ."reference inputs", ."collateral inputs"] | all(.[]; type == "array" and all(.[]; type == "string"))) + ' >/dev/null 2>&1 <<< "${view}"; then + echo "ERROR - Could not inspect transaction inputs in '${txFile}'." >&2 + return 1 + fi + + ids=$(jq -c '[.inputs[], ."reference inputs"[], ."collateral inputs"[]] | unique' <<< "${view}") + sizes=$(queryReferenceScriptSizes "${ids}") || return 1 + feeIds=$(jq -c '[.inputs[], ."reference inputs"[]] | unique' <<< "${view}") + if ! referenceScriptSize=$(jq -er --argjson ids "${feeIds}" --argjson sizes "${sizes}" '$ids | map($sizes[.] // 0) | add // 0 | select(type == "number" and . >= 0 and floor == .)' <<< '{}'); then + unset referenceScriptSize + echo "ERROR - Invalid reference-script fee total." >&2 + return 1 + fi + + spending=$(jq -r --argjson sizes "${sizes}" '.inputs[] | select($sizes[.] != null) | "\(.) (\($sizes[.]) bytes)"' <<< "${view}") + if [[ -n "${spending}" ]]; then + echo "WARNING: This transaction spends reference-script UTxOs. Their existing reference locations will disappear; sending ADA back does not preserve the scripts. Applications using these UTxOs may stop working." >&2 + while IFS= read -r id; do echo " ${id}" >&2; done <<< "${spending}" + fi + + collateralOnly=$(jq -r --argjson sizes "${sizes}" ' + ([.inputs[], ."reference inputs"[]] | unique) as $fee | + ."collateral inputs"[] as $id | select(($fee | index($id)) == null and $sizes[$id] != null) | + "\($id) (\($sizes[$id]) bytes)" + ' <<< "${view}") + if [[ -n "${collateralOnly}" ]]; then + echo "WARNING: These collateral reference-script UTxOs may be consumed if phase-2 validation fails:" >&2 + while IFS= read -r id; do echo " ${id}" >&2; done <<< "${collateralOnly}" + fi + return 0 +} #------------------------------------------------------- diff --git a/cardano/testnet/01_claimRewards.sh b/cardano/testnet/01_claimRewards.sh index e0cf837..3ea4cc0 100755 --- a/cardano/testnet/01_claimRewards.sh +++ b/cardano/testnet/01_claimRewards.sh @@ -616,8 +616,10 @@ if [[ ${rxcnt} == 1 ]]; then checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -766,6 +768,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed rewards withdrawal from '${stakeAddr}' to '${toAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -773,7 +776,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/01_sendAssets.sh b/cardano/testnet/01_sendAssets.sh index 42d5115..041a6fd 100755 --- a/cardano/testnet/01_sendAssets.sh +++ b/cardano/testnet/01_sendAssets.sh @@ -676,8 +676,10 @@ dummyReturnAmount=$(( ${totalLovelaces} - ${lovelacesToSend} )) ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${lovelacesToSend}${assetsSendString}" --tx-out "${sendFromAddr}+${dummyReturnAmount}${assetsReturnString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -824,6 +826,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"generated and signed utxo-token-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -831,7 +834,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/01_sendLovelaces.sh b/cardano/testnet/01_sendLovelaces.sh index 8f4df2a..93c5d97 100755 --- a/cardano/testnet/01_sendLovelaces.sh +++ b/cardano/testnet/01_sendLovelaces.sh @@ -473,8 +473,10 @@ if [[ ${rxcnt} == 1 ]]; then #Sending ALLFUNDS or sending ALL lovelaces and no checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -691,6 +693,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -698,7 +701,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/01_workOffline.sh b/cardano/testnet/01_workOffline.sh index 328a598..864df25 100755 --- a/cardano/testnet/01_workOffline.sh +++ b/cardano/testnet/01_workOffline.sh @@ -300,6 +300,8 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad utxoEntryCnt=$(jq length <<< ${utxoJSON}) if [[ ${utxoEntryCnt} == 0 ]]; then echo -e "\e[35mNo funds on the Address!\e[0m\n"; exit 1; else echo -e "\e[32m${utxoEntryCnt} UTXOs\e[0m found on the Address!"; fi + referenceScriptSizes=$(queryReferenceScriptSizes "$(jq -c 'keys' <<< "${utxoJSON}")") + if [[ $? -ne 0 ]]; then exit 1; fi echo totalLovelaces=0; #Init for the Sum @@ -429,6 +431,7 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad offlineJSON=$( jq ".address.\"${checkAddr}\" += {used: \"no\" }" <<< ${offlineJSON}) offlineJSON=$( jq ".address.\"${checkAddr}\" += {type: \"${typeOfAddr}\" }" <<< ${offlineJSON}) offlineJSON=$( jq ".address.\"${checkAddr}\" += {utxoJSON: ${utxoJSON} }" <<< ${offlineJSON}) + offlineJSON=$( jq ".address.\"${checkAddr}\".referenceScriptSizes = ${referenceScriptSizes}" <<< ${offlineJSON}) offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"added utxo-info for '${addrName}'\" } ]" <<< ${offlineJSON}) @@ -437,8 +440,10 @@ if [[ ${typeOfAddr} == ${addrTypePayment} ]]; then #Enterprise and Base UTXO ad #Readback the content and compare it to the current one utxoJSON=$(jq . <<< ${utxoJSON}) # bring it into the same format - readback=$(cat ${offlineFile} | jq -r ".address.\"${checkAddr}\".utxoJSON") - if [[ "${utxoJSON}" == "${readback}" ]]; then + referenceScriptSizes=$(jq . <<< ${referenceScriptSizes}) + readback=$(jq -r ".address.\"${checkAddr}\".utxoJSON" < "${offlineFile}") + readbackReferenceScriptSizes=$(jq -r ".address.\"${checkAddr}\".referenceScriptSizes" < "${offlineFile}") + if [[ "${utxoJSON}" == "${readback}" && "${referenceScriptSizes}" == "${readbackReferenceScriptSizes}" ]]; then showOfflineFileInfo; echo -e "\e[33mLatest Information about this address was added to the '$(basename ${offlineFile})'.\nYou can now transfer it to your offline machine to work with it, or you can\nadd another address information to the file by re-running this script.\e[0m\n"; else @@ -671,6 +676,16 @@ txFile="${tempDir}/$(basename ${transactionFromName}).tmp.txfile" rm ${txFile} 2> /dev/null #delete an old one if present echo "${transactionTxJSON}" > ${txFile}; checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +# Re-resolve fee-critical input metadata before any queued transaction can be submitted. +prepareReferenceScriptSpend "$txFile" || exit 1 +recordedReferenceScriptSize=$(jq -c ".transactions[${transactionIdx}] | if has(\"referenceScriptSize\") then .referenceScriptSize else \"missing\" end" <<< "${offlineJSON}") +if ! jq -e --argjson resolved "${referenceScriptSize}" ' + (type == "number" and . >= 0 and floor == . and . == $resolved) or + (. == "missing" and $resolved == 0) +' >/dev/null 2>&1 <<< "${recordedReferenceScriptSize}"; then + echo -e "\e[35mReference-script fee information is missing or mismatched; rebuild and re-sign this transaction with the updated scripts.\e[0m" >&2 + exit 1 +fi case ${transactionType} in diff --git a/cardano/testnet/03b_regStakingAddrCert.sh b/cardano/testnet/03b_regStakingAddrCert.sh index b5ebbac..8bf1419 100755 --- a/cardano/testnet/03b_regStakingAddrCert.sh +++ b/cardano/testnet/03b_regStakingAddrCert.sh @@ -552,8 +552,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${stakeAddr}.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -705,6 +707,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed staking key registration transaction for '${stakeAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -712,7 +715,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/05c_regStakepoolCert.sh b/cardano/testnet/05c_regStakepoolCert.sh index 072e911..77589c9 100755 --- a/cardano/testnet/05c_regStakepoolCert.sh +++ b/cardano/testnet/05c_regStakepoolCert.sh @@ -175,10 +175,12 @@ poolJSON=$(cat ${poolFile}.pool.json) #Read PoolJSON File into poolJSON variable #Check if there is already an opened witness in the poolJSON, if not create a new one with the current utctime in seconds as id regWitnessID=$(jq -r .regWitness.id <<< ${poolJSON} 2> /dev/null); if [[ "${regWitnessID}" == null || "${regWitnessID}" == 0 ]]; then #Opening up a new witness in the poolJSON + newWitnessCollection=true regWitnessID=""; #used later to determine if it is a new witnesscollection or an existing one poolJSON=$(jq ".regWitness = { id: $(date +%s), type: \"\", ttl: 0, regPayName: \"\", txBody: {}, witnesses: {} }" <<< ${poolJSON}) #Write the opened Witness only if the txBody was created successfully else + newWitnessCollection=false regWitnessDate=$(date --date="@${regWitnessID}") #Get date of the already existing witnesscollection fi @@ -658,8 +660,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${registrationCerts} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count ${witnessCount} --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count ${witnessCount} --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -724,6 +728,7 @@ echo poolJSON=$(jq ".regWitness.ttl = ${ttl}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.txBody = $(cat ${txBodyFile})" <<< ${poolJSON}) +poolJSON=$(jq ".regWitness.referenceScriptSize = ${referenceScriptSize}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayName = \"${regPayName}\"" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayAmount = ${minRegistrationFees}" <<< ${poolJSON}) poolJSON=$(jq ".regWitness.regPayReturn = ${lovelacesToSend}" <<< ${poolJSON}) @@ -901,6 +906,19 @@ regWitnessID=$(jq -r ".regWitness.id" <<< ${poolJSON}) regWitnessDate=$(date --date="@${regWitnessID}" -R) regWitnessType=$(jq -r ".regWitness.type" <<< ${poolJSON}) regWitnessTxBody=$(jq -r ".regWitness.txBody" <<< ${poolJSON}) +txBodyFile="${tempDir}/$(basename ${poolName}).txbody" +echo "${regWitnessTxBody}" > "${txBodyFile}" +if ! ${newWitnessCollection}; then + prepareReferenceScriptSpend "${txBodyFile}" || exit 1 + storedReferenceScriptSize=$(jq -c '.regWitness | if has("referenceScriptSize") then .referenceScriptSize else "missing" end' <<< "${poolJSON}") + if ! jq -e --argjson resolved "${referenceScriptSize}" ' + (type == "number" and . >= 0 and floor == . and . == $resolved) or + (. == "missing" and $resolved == 0) + ' >/dev/null 2>&1 <<< "${storedReferenceScriptSize}"; then + echo -e "\e[35mReference-script fee information is missing or mismatched. Run 05d_poolWitness.sh clear ${poolFile} and rebuild this transaction.\e[0m" >&2 + exit 1 + fi +fi regWitnessHardwareWalletIncluded=$(jq -r ".regWitness.hardwareWalletIncluded" <<< ${poolJSON}) regWitnessPayAmount=$(jq -r ".regWitness.regPayAmount" <<< ${poolJSON}) regWitnessPayReturn=$(jq -r ".regWitness.regPayReturn" <<< ${poolJSON}) @@ -986,8 +1004,6 @@ fi # txFile="${tempDir}/$(basename ${poolName}).tx" -txBodyFile="${tempDir}/$(basename ${poolName}).txbody" -echo "${regWitnessTxBody}" > ${txBodyFile} echo -e "\e[0mAssemble the Transaction with the payment \e[32m${regPayName}.skey\e[0m, node\e[32m ${poolName}.node.skey/hwsfile\e[0m and all PoolOwner Witnesses: \e[32m ${txFile} \e[90m" echo @@ -1132,6 +1148,7 @@ if ask "\e[33mDoes this look good for you? Do you have enough pledge in your own regProtectionKey: \"${regProtectionKey}\", poolMetaUrl: \"${poolMetaUrl}\", poolMetaHash: \"${poolMetaHash}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed pool registration transaction for '${poolMetaTicker}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -1160,7 +1177,8 @@ if ask "\e[33mDoes this look good for you? Do you have enough pledge in your own echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then echo echo -e "\e[0mStakepool Info JSON:\e[32m ${poolFile}.pool.json \e[90m" cat ${poolFile}.pool.json diff --git a/cardano/testnet/05d_poolWitness.sh b/cardano/testnet/05d_poolWitness.sh index 2df93a9..03f364b 100755 --- a/cardano/testnet/05d_poolWitness.sh +++ b/cardano/testnet/05d_poolWitness.sh @@ -403,6 +403,7 @@ case ${action} in rm ${tmpWitnessTxBody} 2> /dev/null rm ${tmpWitnessFile} 2> /dev/null echo "${witnessTxBody}" > ${tmpWitnessTxBody} + prepareReferenceScriptSpend "${tmpWitnessTxBody}" || exit 1 #Sign via normal cli skey or hardware key, depends on the content of the vkey description diff --git a/cardano/testnet/06_regDelegationCert.sh b/cardano/testnet/06_regDelegationCert.sh index 1349741..ac8d82b 100755 --- a/cardano/testnet/06_regDelegationCert.sh +++ b/cardano/testnet/06_regDelegationCert.sh @@ -550,8 +550,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${delegName}.deleg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -697,6 +699,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed delegation cert registration transaction for '${delegName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -704,7 +707,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/07b_deregStakepoolCert.sh b/cardano/testnet/07b_deregStakepoolCert.sh index ac68fba..9073b4b 100755 --- a/cardano/testnet/07b_deregStakepoolCert.sh +++ b/cardano/testnet/07b_deregStakepoolCert.sh @@ -402,8 +402,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${deregCertFile} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -570,6 +572,7 @@ if ask "\e[33mDoes this look good for you? Continue ?" N; then toAddr: \"${deregPayName}\", sendToAddr: \"${sendToAddr}\", poolMetaTicker: \"${poolMetaTicker}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed pool retirement transaction for '${poolMetaTicker}', payment via '${deregPayName}'\" } ]" <<< ${offlineJSON}) @@ -577,7 +580,8 @@ if ask "\e[33mDoes this look good for you? Continue ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then file_unlock ${poolFile}.pool.json newJSON=$(cat ${poolFile}.pool.json | jq ". += {deregSubmitted: \"$(date -R) (only offline, no proof)\"}") echo "${newJSON}" > ${poolFile}.pool.json diff --git a/cardano/testnet/08b_deregStakingAddrCert.sh b/cardano/testnet/08b_deregStakingAddrCert.sh index 834aa8a..ffda588 100755 --- a/cardano/testnet/08b_deregStakingAddrCert.sh +++ b/cardano/testnet/08b_deregStakingAddrCert.sh @@ -536,8 +536,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${stakeAddr}.dereg-cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -691,6 +693,7 @@ if ask "\e[33mDoes this look good for you, continue ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed staking key deregistration transaction for '${stakeAddr}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -698,7 +701,8 @@ if ask "\e[33mDoes this look good for you, continue ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/11a_mintAsset.sh b/cardano/testnet/11a_mintAsset.sh index 2b7dee5..c432548 100755 --- a/cardano/testnet/11a_mintAsset.sh +++ b/cardano/testnet/11a_mintAsset.sh @@ -400,8 +400,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --mint "${assetMintAmount} ${policyID}${point}${assetMintName}" --minting-script-file ${policyName}.policy.script --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -666,6 +668,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"minted ${assetMintAmount} '${assetMintInputName}' on '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -673,7 +676,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then #Updating the ${policyName}.${assetMintInputName}.asset json assetFileName="${policyName}.${assetMintInputName}.asset" diff --git a/cardano/testnet/11b_burnAsset.sh b/cardano/testnet/11b_burnAsset.sh index c90a640..edce97b 100755 --- a/cardano/testnet/11b_burnAsset.sh +++ b/cardano/testnet/11b_burnAsset.sh @@ -397,8 +397,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --mint "-${assetBurnAmount} ${policyID}${point}${assetBurnName}" --minting-script-file ${policyName}.policy.script --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -667,6 +669,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\e[33mDoes this look good for you, sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"burned ${assetBurnAmount} '${assetBurnInputName}' on '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -674,7 +677,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\e[33mDoes this look good for you, echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then #Updating the ${policyName}.${assetBurnName}.asset json diff --git a/cardano/testnet/13b_sendSpoPoll.sh b/cardano/testnet/13b_sendSpoPoll.sh index 5d66966..f7e04aa 100755 --- a/cardano/testnet/13b_sendSpoPoll.sh +++ b/cardano/testnet/13b_sendSpoPoll.sh @@ -483,9 +483,12 @@ if [[ ${rxcnt} == 1 ]]; then #Sending ALLFUNDS or sending ALL lovelaces and no checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #cardano-cli with new few calculation since cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 | awk '{ print $1 }') -checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) +if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi +fee=${fee%% *} echo -e "\e[0mMinimum Transaction Fee for ${txcnt}x TxIn & ${rxcnt}x TxOut: \e[32m $(convertToADA ${fee}) ADA / ${fee} lovelaces \e[90m" echo @@ -697,6 +700,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${toAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -704,7 +708,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/21b_regDRepCert.sh b/cardano/testnet/21b_regDRepCert.sh index 7fcab96..2b0547a 100755 --- a/cardano/testnet/21b_regDRepCert.sh +++ b/cardano/testnet/21b_regDRepCert.sh @@ -570,8 +570,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${drepName}.drep-reg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -821,6 +823,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed drep-id registration transaction for '${drepName}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -828,7 +831,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/21d_retDRepCert.sh b/cardano/testnet/21d_retDRepCert.sh index 2d00620..a6d2a87 100755 --- a/cardano/testnet/21d_retDRepCert.sh +++ b/cardano/testnet/21d_retDRepCert.sh @@ -448,8 +448,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${drepName}.drep-ret.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -698,6 +700,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed drep-id retirement transaction for '${drepName}', payment via '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -705,7 +708,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/22b_regVoteDelegCert.sh b/cardano/testnet/22b_regVoteDelegCert.sh index fa84a57..920d619 100755 --- a/cardano/testnet/22b_regVoteDelegCert.sh +++ b/cardano/testnet/22b_regVoteDelegCert.sh @@ -546,8 +546,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${delegName}.vote-deleg.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -694,6 +696,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed vote-delegation cert registration transaction for '${delegName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -701,7 +704,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/23c_regComAuthCert.sh b/cardano/testnet/23c_regComAuthCert.sh index f6caf85..cbca4fb 100755 --- a/cardano/testnet/23c_regComAuthCert.sh +++ b/cardano/testnet/23c_regComAuthCert.sh @@ -493,8 +493,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${comHotName}.cc-hot.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -647,6 +649,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${regPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed committee authorization cert registration transaction for '${comColdName}/${comHotName}', payment via '${regPayName}'\" } ]" <<< ${offlineJSON}) @@ -654,7 +657,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/23e_retComColdKeys.sh b/cardano/testnet/23e_retComColdKeys.sh index 46f5b95..60eb043 100755 --- a/cardano/testnet/23e_retComColdKeys.sh +++ b/cardano/testnet/23e_retComColdKeys.sh @@ -554,8 +554,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} --certificate ${comColdName}.cc-cold-ret.cert --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -707,6 +709,7 @@ if ask "\e[33mDoes this look good for you ?" N; then sendFromAddr: \"${sendFromAddr}\", toAddr: \"${retPayName}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed committee authorization cert registration transaction for '${comColdName}/${comHotName}', payment via '${retPayName}'\" } ]" <<< ${offlineJSON}) @@ -714,7 +717,8 @@ if ask "\e[33mDoes this look good for you ?" N; then echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/24b_regVote.sh b/cardano/testnet/24b_regVote.sh index 6bdfe80..9a5d987 100755 --- a/cardano/testnet/24b_regVote.sh +++ b/cardano/testnet/24b_regVote.sh @@ -549,8 +549,10 @@ rm ${txBodyFile} 2> /dev/null ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${votefileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi +prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 -fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size 0 2> /dev/stdout) +fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 2 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' @@ -763,6 +765,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${toAddr}'\" } ]" <<< ${offlineJSON}) @@ -770,7 +773,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/25b_regAction.sh b/cardano/testnet/25b_regAction.sh index 6ee0dbf..8af4cc3 100755 --- a/cardano/testnet/25b_regAction.sh +++ b/cardano/testnet/25b_regAction.sh @@ -745,12 +745,14 @@ case "${voteActionTag,,}" in --fee 200000 ${metafileParameter} ${actionfileParameter} --out-file ${txBodyFile} 2> /dev/stdout checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi + prepareReferenceScriptSpend "$txBodyFile" || exit 1 + #calculate the transaction fee. new parameters since cardano-cli 8.21.0 fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text \ --tx-body-file ${txBodyFile} \ --protocol-params-file <(echo ${protocolParametersJSON}) \ --witness-count 2 \ - --reference-script-size 0 2> /dev/stdout) + --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi @@ -763,8 +765,9 @@ case "${voteActionTag,,}" in #Generate Dummy-TxBody file for fee calculation ${cardanocli} ${cliEra} transaction build-raw ${txInString} --tx-out "${sendToAddr}+${totalLovelaces}${assetsOutString}" --invalid-hereafter ${ttl} --fee 200000 ${metafileParameter} ${actionfileParameter} --out-file ${txBodyFile} checkError "$?"; if [ $? -ne 0 ]; then exit $?; fi + prepareReferenceScriptSpend "$txBodyFile" || exit 1 #calculate the transaction fee. new parameters since cardano-cli 8.21.0 - fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size 0 2> /dev/stdout) + fee=$(${cardanocli} ${cliEra} transaction calculate-min-fee --output-text --tx-body-file ${txBodyFile} --protocol-params-file <(echo ${protocolParametersJSON}) --witness-count 1 --reference-script-size "${referenceScriptSize}" 2> /dev/stdout) if [ $? -ne 0 ]; then echo -e "\n\e[35m${fee}\e[0m\n"; exit 1; fi fee=${fee%% *} #only get the first part of 'xxxxxx Lovelaces' echo -e "\e[0mMimimum transfer Fee for ${txcnt}x TxIn & ${rxcnt}x TxOut: \e[32m $(convertToADA ${fee}) ADA / ${fee} lovelaces \e[90m" @@ -958,6 +961,7 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you sendFromAddr: \"${sendFromAddr}\", toAddr: \"${fromAddr}\", sendToAddr: \"${sendToAddr}\", + referenceScriptSize: ${referenceScriptSize}, txJSON: ${txFileJSON} } ]" <<< ${offlineJSON}) #Write the new offileFile content offlineJSON=$( jq ".history += [ { date: \"$(date -R)\", action: \"signed utxo-transaction from '${fromAddr}' to '${fromAddr}'\" } ]" <<< ${offlineJSON}) @@ -965,7 +969,8 @@ if [ "${ENV_SKIP_PROMPT}" == "YES" ] || ask "\n\e[33mDoes this look good for you echo "${offlineJSON}" > ${offlineFile} #Readback the tx content and compare it to the current one readback=$(cat ${offlineFile} | jq -r ".transactions[-1].txJSON") - if [[ "${txFileJSON}" == "${readback}" ]]; then + readbackReferenceScriptSize=$(cat ${offlineFile} | jq -r ".transactions[-1].referenceScriptSize") + if [[ "${txFileJSON}" == "${readback}" && "${referenceScriptSize}" == "${readbackReferenceScriptSize}" ]]; then showOfflineFileInfo; echo -e "\e[33mTransaction txJSON has been stored in the '$(basename ${offlineFile})'.\nYou can now transfer it to your online machine for execution.\e[0m\n"; else diff --git a/cardano/testnet/README.md b/cardano/testnet/README.md index be63531..3caa9fd 100644 --- a/cardano/testnet/README.md +++ b/cardano/testnet/README.md @@ -291,6 +291,10 @@ Checkout the configuration parameters in your 00_common.sh Main-Configuration fi The scripts uses per default (configurable) the file **offlineTransfer.json** to store the data in between the Machines. +Offline address captures include reference-script sizes used for fee calculation. Refresh each payment address with `./01_workOffline.sh add ` before building or signing if the capture was created by an older script version. + +Transactions that spend UTxOs carrying reference scripts print a warning. Sending the ADA back to the same address does not recreate those scripts; applications using the spent reference locations may stop working. +