diff --git a/docs/Scripts/cntools-changelog.md b/docs/Scripts/cntools-changelog.md index 64ae68d38..f20edda68 100644 --- a/docs/Scripts/cntools-changelog.md +++ b/docs/Scripts/cntools-changelog.md @@ -6,6 +6,18 @@ All notable changes to this tool will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [13.3.0] - 2024-11-21 +#### Added +- Own votes cast (SPO|DRep|CC) shown in proposal list. +#### Changed +- Protocol version 10 check on withdrawal if not vote delegated to show informative error if needed. +- Only transform transaction for HW when a HW wallet is used as source. +- Remove deprecated CIP-0094 vote command from CNTools pool menu. +- Adoptions for Koios v1.3.0 queries (DRep status) +#### Fixed +- Wallet DRep delegation status to pre-defined types +- Proposal list vote summary didn't show correct data for all types + ## [13.2.3] - 2024-10-16 #### Fixed - Edge case fix for pool registration when cardano-hw-cli is present diff --git a/files/configs/guild/config.json b/files/configs/guild/config.json index 1adfc299b..b2ada33fe 100644 --- a/files/configs/guild/config.json +++ b/files/configs/guild/config.json @@ -6,7 +6,7 @@ "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": 3, "LastKnownBlockVersion-Minor": 1, - "MinNodeVersion": "9.0.0", + "MinNodeVersion": "10.0.0", "PeerSharing": true, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresMagic", diff --git a/files/configs/guild/db-sync-config.json b/files/configs/guild/db-sync-config.json index 4ca1b32ae..7c015ceb3 100644 --- a/files/configs/guild/db-sync-config.json +++ b/files/configs/guild/db-sync-config.json @@ -17,7 +17,8 @@ ], "insert_options": { "tx_out": { - "value": "consumed" + "value": "consumed", + "use_address_table": true }, "ledger": "enable", "shelley": { @@ -36,7 +37,6 @@ "json_type": "text", "offchain_pool_data": "enable", "pool_stat": "enable", - "pool_stats": "enable", "tx_cbor": "enable" }, "minSeverity": "Info", diff --git a/files/configs/mainnet/config.json b/files/configs/mainnet/config.json index 6518a24d9..bbd7817c3 100644 --- a/files/configs/mainnet/config.json +++ b/files/configs/mainnet/config.json @@ -7,7 +7,7 @@ "LastKnownBlockVersion-Major": 3, "LastKnownBlockVersion-Minor": 0, "MaxKnownMajorProtocolVersion": 2, - "MinNodeVersion": "9.0.0", + "MinNodeVersion": "10.0.0", "PeerSharing": false, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresNoMagic", diff --git a/files/configs/mainnet/db-sync-config.json b/files/configs/mainnet/db-sync-config.json index 9193d6bc6..f023d424c 100644 --- a/files/configs/mainnet/db-sync-config.json +++ b/files/configs/mainnet/db-sync-config.json @@ -17,7 +17,8 @@ ], "insert_options": { "tx_out": { - "value": "consumed" + "value": "consumed", + "use_address_table": true }, "ledger": "enable", "shelley": { @@ -36,7 +37,6 @@ "json_type": "text", "offchain_pool_data": "enable", "pool_stat": "enable", - "pool_stats": "enable", "tx_cbor": "enable" }, "minSeverity": "Info", diff --git a/files/configs/preprod/config.json b/files/configs/preprod/config.json index cecb74bc8..5c693cf40 100644 --- a/files/configs/preprod/config.json +++ b/files/configs/preprod/config.json @@ -6,7 +6,7 @@ "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": 2, "LastKnownBlockVersion-Minor": 0, - "MinNodeVersion": "9.0.0", + "MinNodeVersion": "10.0.0", "PeerSharing": false, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresMagic", diff --git a/files/configs/preprod/db-sync-config.json b/files/configs/preprod/db-sync-config.json index e018289a4..ebd31458d 100644 --- a/files/configs/preprod/db-sync-config.json +++ b/files/configs/preprod/db-sync-config.json @@ -17,7 +17,8 @@ ], "insert_options": { "tx_out": { - "value": "consumed" + "value": "consumed", + "use_address_table": true }, "ledger": "enable", "shelley": { @@ -36,7 +37,6 @@ "json_type": "text", "offchain_pool_data": "enable", "pool_stat": "enable", - "pool_stats": "enable", "tx_cbor": "enable" }, "minSeverity": "Info", diff --git a/files/configs/preview/config.json b/files/configs/preview/config.json index e5b3950eb..48d793ac0 100644 --- a/files/configs/preview/config.json +++ b/files/configs/preview/config.json @@ -8,7 +8,7 @@ "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": 3, "LastKnownBlockVersion-Minor": 1, - "MinNodeVersion": "9.0.0", + "MinNodeVersion": "10.0.0", "PeerSharing": false, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresMagic", diff --git a/files/configs/preview/db-sync-config.json b/files/configs/preview/db-sync-config.json index 51d0ab3ff..fdbc51d75 100644 --- a/files/configs/preview/db-sync-config.json +++ b/files/configs/preview/db-sync-config.json @@ -17,7 +17,8 @@ ], "insert_options": { "tx_out": { - "value": "consumed" + "value": "consumed", + "use_address_table": true }, "ledger": "enable", "shelley": { @@ -36,7 +37,6 @@ "json_type": "text", "offchain_pool_data": "enable", "pool_stat": "enable", - "pool_stats": "enable", "tx_cbor": "enable" }, "minSeverity": "Info", diff --git a/files/configs/sanchonet/config.json b/files/configs/sanchonet/config.json index b0b14483f..f6324e19d 100644 --- a/files/configs/sanchonet/config.json +++ b/files/configs/sanchonet/config.json @@ -8,7 +8,7 @@ "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": 3, "LastKnownBlockVersion-Minor": 1, - "MinNodeVersion": "9.0.0", + "MinNodeVersion": "10.0.0", "PeerSharing": false, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresMagic", diff --git a/files/configs/sanchonet/conway-genesis.json b/files/configs/sanchonet/conway-genesis.json index 61598cba8..bfda1c67f 100644 --- a/files/configs/sanchonet/conway-genesis.json +++ b/files/configs/sanchonet/conway-genesis.json @@ -1,15 +1,15 @@ { "poolVotingThresholds": { - "committeeNormal": 0.65, - "committeeNoConfidence": 0.65, + "committeeNormal": 0.51, + "committeeNoConfidence": 0.51, "hardForkInitiation": 0.51, - "motionNoConfidence": 0.6, - "ppSecurityGroup": 0.6 + "motionNoConfidence": 0.51, + "ppSecurityGroup": 0.51 }, "dRepVotingThresholds": { "motionNoConfidence": 0.67, "committeeNormal": 0.67, - "committeeNoConfidence": 0.65, + "committeeNoConfidence": 0.6, "updateToConstitution": 0.75, "hardForkInitiation": 0.6, "ppNetworkGroup": 0.67, @@ -18,9 +18,9 @@ "ppGovGroup": 0.75, "treasuryWithdrawal": 0.67 }, - "committeeMinSize": 5, - "committeeMaxTermLength": 146, - "govActionLifetime": 14, + "committeeMinSize": 0, + "committeeMaxTermLength": 1000, + "govActionLifetime": 60, "govActionDeposit": 100000000000, "dRepDeposit": 500000000, "dRepActivity": 20, @@ -280,19 +280,18 @@ ], "constitution": { "anchor": { - "url": "ipfs://QmQq5hWDNzvDR1ForEktAHrdCQmfSL2u5yctNpzDwoSBu4", - "dataHash": "23b43bebac48a4acc39e578715aa06635d6d900fa3ea7441dfffd6e43b914f7b" + "dataHash": "ca41a91f399259bcefe57f9858e91f6d00e1a38d6d9c63d4052914ea7bd70cb2", + "url": "ipfs://bafkreifnwj6zpu3ixa4siz2lndqybyc5wnnt3jkwyutci4e2tmbnj3xrdm" }, - "script": "edcd84c10e36ae810dc50847477083069db796219b39ccde790484e0" + "script": "fa24fb305126805cf2164c161d852a0e7330cf988f1fe558cf7d4a64" }, "committee": { "members": { - "scriptHash-7ceede7d6a89e006408e6b7c6acb3dd094b3f6817e43b4a36d01535b": 500, - "scriptHash-6095e643ea6f1cccb6e463ec34349026b3a48621aac5d512655ab1bf": 500, - "scriptHash-27999ed757d6dac217471ae61d69b1b067b8b240d9e3ff36eb66b5d0": 500, - "scriptHash-87f867a31c0f81360d4d7dcddb6b025ba8383db9bf77a2af7797799d": 500, - "scriptHash-a19a7ba1caede8f3ab3e5e2a928b3798d7d011af18fbd577f7aeb0ec": 500 + "keyHash-77c0a65f9302bccab35b44adc1823cb66c88a66c97cf3de8236dd718": 1000 }, - "threshold": 0.67 + "threshold": { + "numerator": 2, + "denominator": 3 + } } } \ No newline at end of file diff --git a/files/configs/sanchonet/db-sync-config.json b/files/configs/sanchonet/db-sync-config.json index ad5d76ea5..2ac04c2cd 100644 --- a/files/configs/sanchonet/db-sync-config.json +++ b/files/configs/sanchonet/db-sync-config.json @@ -17,7 +17,8 @@ ], "insert_options": { "tx_out": { - "value": "consumed" + "value": "consumed", + "use_address_table": true }, "ledger": "enable", "shelley": { @@ -36,7 +37,6 @@ "json_type": "text", "offchain_pool_data": "enable", "pool_stat": "enable", - "pool_stats": "enable", "tx_cbor": "enable" }, "minSeverity": "Info", diff --git a/files/docker/node/release-versions/cardano-cli-latest.txt b/files/docker/node/release-versions/cardano-cli-latest.txt new file mode 100644 index 000000000..b5640a978 --- /dev/null +++ b/files/docker/node/release-versions/cardano-cli-latest.txt @@ -0,0 +1 @@ +10.1.1.0 \ No newline at end of file diff --git a/files/docker/node/release-versions/cardano-node-latest.txt b/files/docker/node/release-versions/cardano-node-latest.txt index 4ae7a7206..6aeecf6e1 100644 --- a/files/docker/node/release-versions/cardano-node-latest.txt +++ b/files/docker/node/release-versions/cardano-node-latest.txt @@ -1 +1 @@ -9.2.1 \ No newline at end of file +10.1.2 \ No newline at end of file diff --git a/scripts/cnode-helper-scripts/cntools.library b/scripts/cnode-helper-scripts/cntools.library index 14f8f89c1..665061024 100644 --- a/scripts/cnode-helper-scripts/cntools.library +++ b/scripts/cnode-helper-scripts/cntools.library @@ -13,9 +13,9 @@ # Major: Any considerable change in the code base, big feature, workflow or breaking change from previous version CNTOOLS_MAJOR_VERSION=13 # Minor: Changes and features of minor character that can be applied without breaking existing functionality or workflow -CNTOOLS_MINOR_VERSION=2 +CNTOOLS_MINOR_VERSION=3 # Patch: Backwards compatible bug fixes. No additional functionality or major changes -CNTOOLS_PATCH_VERSION=3 +CNTOOLS_PATCH_VERSION=0 CNTOOLS_VERSION="${CNTOOLS_MAJOR_VERSION}.${CNTOOLS_MINOR_VERSION}.${CNTOOLS_PATCH_VERSION}" DUMMYFEE=20000 @@ -1213,8 +1213,8 @@ getDRepStatus() { [[ ${hash_type} = keyHash ]] && _param=$(bech32 drep <<< "22${2}") || _param=$(bech32 drep <<< "23${2}") fi HEADERS=("${KOIOS_API_HEADERS[@]}" -H "Content-Type: application/json" -H "accept: text/csv") - println ACTION "curl -sSL -f -X POST ${HEADERS[*]} -d '{\"_drep_ids\":[\"${_param}\"]}' ${KOIOS_API}/drep_info?select=registered,deposit,active,expires_epoch_no,amount,url,hash" - ! drep_info_list=$(curl -sSL -f -X POST "${HEADERS[@]}" -d '{"_drep_ids":["'${_param}'"]}' "${KOIOS_API}/drep_info?select=registered,deposit,active,expires_epoch_no,amount,url,hash" 2>&1) && println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${drep_info_list}\n" && return 1 # print error and return + println ACTION "curl -sSL -f -X POST ${HEADERS[*]} -d '{\"_drep_ids\":[\"${_param}\"]}' ${KOIOS_API}/drep_info?select=registered,deposit,active,expires_epoch_no,amount,meta_url,meta_hash" + ! drep_info_list=$(curl -sSL -f -X POST "${HEADERS[@]}" -d '{"_drep_ids":["'${_param}'"]}' "${KOIOS_API}/drep_info?select=registered,deposit,active,expires_epoch_no,amount,meta_url,meta_hash" 2>&1) && println "ERROR" "\n${FG_RED}KOIOS_API ERROR${NC}: ${drep_info_list}\n" && return 1 # print error and return [[ -z ${drep_info_list} ]] && return 1 while IFS=',' read -r _registered _deposit _active _expires_epoch_no _amount _url _hash; do [[ ${_registered} != t ]] && return 1 @@ -1359,7 +1359,7 @@ getGovAction() { # Command : getAllGovActions # Return : csv array of governance actions with different data depending on LIGHT VS LOCAL mode getAllGovActions() { - unset vote_action_list _vote_action_list _vote_action_votes + unset vote_action_list _vote_action_list _vote_action_summary _vote_action_votes own_drep_votes own_spo_votes own_cc_votes if [[ ${CNTOOLS_MODE} = "LIGHT" ]]; then getCurrentCommittee; getParameterThresholds # to fetch thresholds HEADERS=("${KOIOS_API_HEADERS[@]}" -H "accept: text/csv") @@ -1368,8 +1368,8 @@ getAllGovActions() { vote_action_list=() while IFS=',' read -r _block_time _ratified_epoch _enacted_epoch _dropped_epoch _expired_epoch _proposal_id _proposal_tx_hash _proposal_index _proposal_type _proposed_epoch _expiration _meta_url _param_proposal; do println ACTION "curl -sSL -f -X GET ${HEADERS[*]} ${KOIOS_API}/proposal_voting_summary?_proposal_id=${_proposal_id}&select=drep_yes_votes_cast,drep_yes_vote_power,drep_yes_pct,drep_no_votes_cast,drep_no_vote_power,drep_no_pct,pool_yes_votes_cast,pool_yes_vote_power,pool_yes_pct,pool_no_votes_cast,pool_no_vote_power,pool_no_pct,committee_yes_votes_cast,committee_yes_pct,committee_no_votes_cast,committee_no_pct" - _vote_action_votes=$(curl -sSL -f -X GET "${HEADERS[@]}" "${KOIOS_API}/proposal_voting_summary?_proposal_id=${_proposal_id}&select=drep_yes_votes_cast,drep_yes_vote_power,drep_yes_pct,drep_no_votes_cast,drep_no_vote_power,drep_no_pct,pool_yes_votes_cast,pool_yes_vote_power,pool_yes_pct,pool_no_votes_cast,pool_no_vote_power,pool_no_pct,committee_yes_votes_cast,committee_yes_pct,committee_no_votes_cast,committee_no_pct" 2>&1) || continue - IFS=',' read -r drep_yes_votes_cast drep_yes_vote_power drep_yes_pct drep_no_votes_cast drep_no_vote_power drep_no_pct pool_yes_votes_cast pool_yes_vote_power pool_yes_pct pool_no_votes_cast pool_no_vote_power pool_no_pct committee_yes_votes_cast committee_yes_pct committee_no_votes_cast committee_no_pct <<< "$(tail -n +2 <<< ${_vote_action_votes})" + _vote_action_summary=$(curl -sSL -f -X GET "${HEADERS[@]}" "${KOIOS_API}/proposal_voting_summary?_proposal_id=${_proposal_id}&select=drep_yes_votes_cast,drep_yes_vote_power,drep_yes_pct,drep_no_votes_cast,drep_no_vote_power,drep_no_pct,pool_yes_votes_cast,pool_yes_vote_power,pool_yes_pct,pool_no_votes_cast,pool_no_vote_power,pool_no_pct,committee_yes_votes_cast,committee_yes_pct,committee_no_votes_cast,committee_no_pct" 2>&1) || continue + IFS=',' read -r drep_yes_votes_cast drep_yes_vote_power drep_yes_pct drep_no_votes_cast drep_no_vote_power drep_no_pct pool_yes_votes_cast pool_yes_vote_power pool_yes_pct pool_no_votes_cast pool_no_vote_power pool_no_pct committee_yes_votes_cast committee_yes_pct committee_no_votes_cast committee_no_pct <<< "$(tail -n +2 <<< ${_vote_action_summary})" drep_yes_pct=$(printf '%.2f' "${drep_yes_pct}" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') drep_no_pct=$(printf '%.2f' "${drep_no_pct}" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') pool_yes_pct=$(printf '%.2f' "${pool_yes_pct}" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') @@ -1384,6 +1384,25 @@ getAllGovActions() { getParameterChangeGroups fi getVoteThreshold ${_proposal_type} + println ACTION "curl -sSL -f -X GET ${HEADERS[*]} ${KOIOS_API}/proposal_votes?_proposal_id=${_proposal_id}&select=voter_role,voter_hex,vote" + _vote_action_votes=$(curl -sSL -f -X GET "${HEADERS[@]}" "${KOIOS_API}/proposal_votes?_proposal_id=${_proposal_id}&select=voter_role,voter_hex,vote" 2>&1) || continue + while IFS= read -r -d '' wallet; do + wallet_name=$(basename ${wallet}) + getGovKeyInfo ${wallet_name} + while IFS= read -r vote; do + IFS=',' read -ra vote_arr <<< "${vote}" + [[ ${vote_arr[0]} = DRep && ${vote_arr[1]} = "${drep_hash}" ]] && own_drep_votes+=( "${_proposal_tx_hash}#${_proposal_index};${wallet_name};${vote_arr[2]}" ) + [[ ${vote_arr[0]} = ConstitutionalCommittee && ${vote_arr[1]} = "${cc_hot_hash}" ]] && own_cc_votes+=( "${_proposal_tx_hash}#${_proposal_index};${wallet_name};${vote_arr[2]}" ) + done <<< "${_vote_action_votes}" + done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + while IFS= read -r -d '' pool; do + pool_name=$(basename ${pool}) + getPoolID ${pool_name} || continue + while IFS= read -r vote; do + IFS=',' read -ra vote_arr <<< "${vote}" + [[ ${vote_arr[0]} = SPO && ${vote_arr[1]} = "${pool_id}" ]] && own_spo_votes+=( "${_proposal_tx_hash}#${_proposal_index};${pool_name};${vote_arr[2]}" ) && continue 2 + done <<< "${_vote_action_votes}" + done < <(find "${POOL_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) vote_action_list+=( "${_proposal_tx_hash}#${_proposal_index},${_proposal_type},${_proposed_epoch},$((_expiration-1)),${_meta_url},${drep_yes_votes_cast},${drep_yes_vote_power},${drep_yes_pct},${drep_no_votes_cast},${drep_no_vote_power},${drep_no_pct},${pool_yes_votes_cast},${pool_yes_vote_power},${pool_yes_pct},${pool_no_votes_cast},${pool_no_vote_power},${pool_no_pct},${committee_yes_votes_cast},${committee_yes_pct},${committee_no_votes_cast},${committee_no_pct},${drep_vt},${spo_vt},${cc_vt},${isParameterSecurityGroup}" ) done <<< "$(tail -n +2 <<< ${_vote_action_list})" elif [[ ${CNTOOLS_MODE} = "LOCAL" ]]; then @@ -1393,13 +1412,11 @@ getAllGovActions() { all_drep_vote_power=$(${CCLI} conway query drep-stake-distribution --all-dreps ${NETWORK_IDENTIFIER}) # sum of all drep stake distribution entries without the alwaysAbstain and alwaysNoConfidence drep_power_total_no_abstain=$(jq -r '[.[] | select(.[0] == "drep-alwaysAbstain" | not) | .[1]] | add //0' <<< "${all_drep_vote_power}" 2>/dev/null) - # get current Pool distribution (available from cardano-cli 9.3.0.0) + # get current Pool distribution unset all_spo_vote_power spo_power_total - if versionCheckNode "9.3.0.0" "${cli_version}"; then - println ACTION "${CCLI} conway query spo-stake-distribution --all-spos ${NETWORK_IDENTIFIER}" - all_spo_vote_power=$(${CCLI} conway query spo-stake-distribution --all-spos ${NETWORK_IDENTIFIER}) - spo_power_total=$(jq -r '[.[][1]] | add' <<< "${all_spo_vote_power}" 2>/dev/null) - fi + println ACTION "${CCLI} conway query spo-stake-distribution --all-spos ${NETWORK_IDENTIFIER}" + all_spo_vote_power=$(${CCLI} conway query spo-stake-distribution --all-spos ${NETWORK_IDENTIFIER}) + spo_power_total=$(jq -r '[.[][1]] | add' <<< "${all_spo_vote_power}" 2>/dev/null) # get committee vote power (sum of authorized committee members) cc_power_authorized=$(jq -r 'reduce(select(.committee[].hotCredsAuthStatus.tag|strings=="MemberAuthorized")) as $_ (0; .+1)' <<< "${committee_info}") vote_action_list=(); _vote_action_list=() @@ -1412,6 +1429,7 @@ getAllGovActions() { getParameterChangeGroups fi getVoteThreshold "$(jq -r '.proposalProcedure.govAction.tag' <<< "$(base64 -d <<< "${vote_action}")")" + # get list of drep voters based on vote drep_yes_voters="$(jq '[.dRepVotes | to_entries[] | select(.value=="VoteYes") | ("drep-" + .key)]' <<< "$(base64 -d <<< "${vote_action}")")" drep_no_voters="$(jq '[.dRepVotes | to_entries[] | select(.value=="VoteNo") | ("drep-" + .key)]' <<< "$(base64 -d <<< "${vote_action}")")" @@ -1431,27 +1449,54 @@ getAllGovActions() { # calculate percentages drep_yes_pct=$(printf '%.2f' "$(bc -l <<< "(${drep_yes_vote_power}/${drep_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') drep_no_pct=$(printf '%.2f' "$(bc -l <<< "(${drep_no_vote_power_total}/${drep_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') - if [[ -n ${spo_power_total} ]]; then - # get list of spo voters based on vote - spo_yes_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="VoteYes") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" - spo_no_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="VoteNo") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" - spo_abstain_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="Abstain") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" - # get sum of vote power for each type - spo_yes_vote_power="$(jq -r --argjson v "${spo_yes_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" - spo_no_vote_power="$(jq -r --argjson v "${spo_no_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" - spo_abstain_vote_power="$(jq -r --argjson v "${spo_abstain_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" - spo_power_total=$(( spo_power_total - spo_abstain_vote_power )) - spo_no_vote_power_total=$(( spo_power_total - spo_yes_vote_power )) # total spo power - proposal abstain - proposal yes - # calculate percentages - spo_yes_pct=$(printf '%.2f' "$(bc -l <<< "(${spo_yes_vote_power}/${spo_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') - spo_no_pct=$(printf '%.2f' "$(bc -l <<< "(${spo_no_vote_power_total}/${spo_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') - else - unset spo_yes_vote_power spo_no_vote_power spo_yes_pct spo_no_pct - fi + # find votes by own DReps + while IFS= read -r -d '' wallet; do + wallet_name=$(basename ${wallet}) + getGovKeyInfo ${wallet_name} + [[ -z ${drep_hash} ]] && continue + for drep in ${drep_yes_voters[@]}; do + [[ ${drep} = *"${hash_type}-${drep_hash}"* ]] && own_drep_votes+=( "${proposal_id};${wallet_name};Yes" ) && continue 2 + done + for drep in ${drep_no_voters[@]}; do + [[ ${drep} = *"${hash_type}-${drep_hash}"* ]] && own_drep_votes+=( "${proposal_id};${wallet_name};No" ) && continue 2 + done + for drep in ${drep_abstain_voters[@]}; do + [[ ${drep} = *"${hash_type}-${drep_hash}"* ]] && own_drep_votes+=( "${proposal_id};${wallet_name};Abstain" ) && continue 2 + done + done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + + # get list of spo voters based on vote + spo_yes_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="VoteYes") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" + spo_no_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="VoteNo") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" + spo_abstain_voters="$(jq '[.stakePoolVotes | to_entries[] | select(.value=="Abstain") | .key]' <<< "$(base64 -d <<< "${vote_action}")")" + # get sum of vote power for each type + spo_yes_vote_power="$(jq -r --argjson v "${spo_yes_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" + spo_no_vote_power="$(jq -r --argjson v "${spo_no_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" + spo_abstain_vote_power="$(jq -r --argjson v "${spo_abstain_voters}" '[.[] | select(.[0] | IN($v[])) | .[1]] | add //0' <<< "${all_spo_vote_power}")" + spo_power_total=$(( spo_power_total - spo_abstain_vote_power )) + spo_no_vote_power_total=$(( spo_power_total - spo_yes_vote_power )) # total spo power - proposal abstain - proposal yes + # calculate percentages + spo_yes_pct=$(printf '%.2f' "$(bc -l <<< "(${spo_yes_vote_power}/${spo_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') + spo_no_pct=$(printf '%.2f' "$(bc -l <<< "(${spo_no_vote_power_total}/${spo_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') + # find votes by own pools + while IFS= read -r -d '' pool; do + pool_name=$(basename ${pool}) + getPoolID ${pool_name} || continue + for spo in ${spo_yes_voters[@]}; do + [[ ${spo} = *"${pool_id}"* ]] && own_spo_votes+=( "${proposal_id};${pool_name};Yes" ) && continue 2 + done + for spo in ${spo_no_voters[@]}; do + [[ ${spo} = *"${pool_id}"* ]] && own_spo_votes+=( "${proposal_id};${pool_name};No" ) && continue 2 + done + for spo in ${spo_abstain_voters[@]}; do + [[ ${spo} = *"${pool_id}"* ]] && own_spo_votes+=( "${proposal_id};${pool_name};Abstain" ) && continue 2 + done + done < <(find "${POOL_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + # get list of cc voters based on vote cc_yes_voters="$(jq '[.committeeVotes | to_entries[] | select(.value=="VoteYes")] | length' <<< "$(base64 -d <<< "${vote_action}")")" - cc_no_voters="$(jq '[.committeeVotes | to_entries[] | select(.value=="VoteYes")] | length' <<< "$(base64 -d <<< "${vote_action}")")" - cc_abstain_voters="$(jq '[.committeeVotes | to_entries[] | select(.value=="VoteYes")] | length' <<< "$(base64 -d <<< "${vote_action}")")" + cc_no_voters="$(jq '[.committeeVotes | to_entries[] | select(.value=="VoteNo")] | length' <<< "$(base64 -d <<< "${vote_action}")")" + cc_abstain_voters="$(jq '[.committeeVotes | to_entries[] | select(.value=="Abstain")] | length' <<< "$(base64 -d <<< "${vote_action}")")" cc_power_total=$(( cc_power_authorized - cc_abstain_voters )) cc_no_voters_total=$(( cc_power_total - cc_yes_voters )) # total cc power - proposal abstain - proposal yes # calculate percentages @@ -1462,6 +1507,21 @@ getAllGovActions() { cc_yes_pct=$(printf '%.2f' "$(bc -l <<< "(${cc_yes_voters}/${cc_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') cc_no_pct=$(printf '%.2f' "$(bc -l <<< "(${cc_no_voters_total}/${cc_power_total})*100")" | sed '/\./ s/\.\{0,1\}0\{1,\}$//') fi + while IFS= read -r -d '' wallet; do + wallet_name=$(basename ${wallet}) + getGovKeyInfo ${wallet_name} + [[ -z ${cc_hot_hash} ]] && continue + for cc_hot in ${cc_yes_voters[@]}; do + [[ ${cc_hot} = *"${cc_hot_hash}"* ]] && own_cc_votes+=( "${proposal_id};${wallet_name};Yes" ) && continue 2 + done + for cc_hot in ${cc_no_voters[@]}; do + [[ ${cc_hot} = *"${cc_hot_hash}"* ]] && own_cc_votes+=( "${proposal_id};${wallet_name};No" ) && continue 2 + done + for cc_hot in ${cc_abstain_voters[@]}; do + [[ ${cc_hot} = *"${cc_hot_hash}"* ]] && own_cc_votes+=( "${proposal_id};${wallet_name};Abstain" ) && continue 2 + done + done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + _vote_action_list+=( "${proposal_id},${proposal_type},${proposed_epoch},${expiration:=0},${meta_url},${drep_yes_votes_cast},${drep_yes_vote_power},${drep_yes_pct},${drep_no_votes_cast},${drep_no_vote_power_total},${drep_no_pct},${spo_yes_votes_cast},${spo_yes_vote_power},${spo_yes_pct},${spo_no_votes_cast},${spo_no_vote_power_total},${spo_no_pct},${cc_yes_votes_cast},${cc_yes_pct},${cc_no_votes_cast},${cc_no_pct},${drep_vt},${spo_vt},${cc_vt},${isParameterSecurityGroup}" ) done # reverse order @@ -2117,6 +2177,11 @@ getRewardInfoKoios() { rewards_available["${stake_address}"]="${rewards_available}" [[ -n ${delegated_pool} ]] && pool_delegations["${stake_address}"]="${delegated_pool}" if [[ -n ${delegated_drep} ]]; then + if [[ ${delegated_drep} = always_abstain ]]; then + vote_delegations["${stake_address}"]="alwaysAbstain"; return + elif [[ ${delegated_drep} = always_no_confidence ]]; then + vote_delegations["${stake_address}"]="alwaysNoConfidence"; return + fi # convert to cli format - vote_delegation_raw=$(bech32 <<< "${delegated_drep}") if [[ ${vote_delegation_raw:0:2} = '22' ]]; then @@ -2690,7 +2755,7 @@ registerStakeWallet() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -2721,7 +2786,11 @@ registerStakeWallet() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet Registration"; then return 1; fi @@ -2824,7 +2893,7 @@ deregisterStakeWallet() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -2855,7 +2924,11 @@ deregisterStakeWallet() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet De-Registration"; then return 1; fi @@ -2956,7 +3029,7 @@ sendAssets() { build_args+=( --tx-out "${s_addr}+${assets_left[lovelace]}${assets_tx_out_s}" --tx-out "${d_addr}+${assets_to_send[lovelace]}${assets_tx_out_d}" ) fi - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} ${outCount} ${witness_cnt} || return 1 @@ -3006,7 +3079,11 @@ sendAssets() { fi fi - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Payment"; then return 1; fi @@ -3104,7 +3181,7 @@ delegate() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3135,7 +3212,11 @@ delegate() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet Delegation"; then return 1; fi @@ -3223,7 +3304,7 @@ withdrawRewards() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3254,7 +3335,11 @@ withdrawRewards() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet Rewards Withdrawal"; then return 1; fi @@ -3350,7 +3435,7 @@ registerPool() { ) [[ -n ${owner_delegation_cert} ]] && build_args+=( --certificate-file "${owner_delegation_cert}" ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3496,7 +3581,7 @@ modifyPool() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3527,7 +3612,11 @@ modifyPool() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Pool Update"; then return 1; fi @@ -3635,7 +3724,7 @@ deRegisterPool() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3666,7 +3755,11 @@ deRegisterPool() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Pool De-Registration"; then return 1; fi @@ -3865,7 +3958,7 @@ sendMetadata() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -3896,7 +3989,11 @@ sendMetadata() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Metadata"; then return 1; fi @@ -3989,7 +4086,7 @@ mintAsset() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4022,7 +4119,11 @@ mintAsset() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Asset Minting"; then return 1; fi @@ -4122,7 +4223,7 @@ burnAsset() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4155,7 +4256,11 @@ burnAsset() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Asset Burning"; then return 1; fi @@ -4260,7 +4365,7 @@ voteDelegation() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4291,7 +4396,11 @@ voteDelegation() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet Vote Delegation"; then return 1; fi @@ -4380,7 +4489,7 @@ registerDRep() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4418,7 +4527,11 @@ registerDRep() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet DRep Registration"; then return 1; fi @@ -4499,7 +4612,7 @@ retireDRep() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4531,7 +4644,11 @@ retireDRep() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet DRep Retire"; then return 1; fi @@ -4610,7 +4727,7 @@ governanceVote() { --out-file "${TMP_DIR}"/tx0.tmp ) - if ! buildTx; then return 1; fi + buildTx || return 1 calcMinFee "${TMP_DIR}"/tx0.tmp ${utxo_cnt} 1 ${witness_cnt} || return 1 @@ -4641,7 +4758,11 @@ governanceVote() { --out-file "${TMP_DIR}"/tx.raw ) - if ! buildTx "${TMP_DIR}/tx.raw"; then return 1; fi + if [[ ${wallet_type} -eq 0 ]]; then + buildTx "${TMP_DIR}/tx.raw" || return 1 + else + buildTx || return 1 + fi if [[ ${op_mode} = "hybrid" ]]; then if ! buildOfflineJSON "Wallet Governance Vote"; then return 1; fi @@ -4912,7 +5033,7 @@ submitTxKoiosOgmios() { jq -r . <<< "${ogmios_error}" println LOG "$(jq -rc . <<< ${ogmios_error})" else - println ERROR "Submit API error: ${stdout}" + println ERROR "Ogmios API error: ${stdout}" fi return 1 fi diff --git a/scripts/cnode-helper-scripts/cntools.sh b/scripts/cnode-helper-scripts/cntools.sh index 0ae165def..878e3ca86 100755 --- a/scripts/cnode-helper-scripts/cntools.sh +++ b/scripts/cnode-helper-scripts/cntools.sh @@ -1122,50 +1122,65 @@ function main { if getWalletVoteDelegation ${wallet_name}; then unset vote_delegation_hash vote_delegation_type="${vote_delegation%-*}" - if [[ ${vote_delegation} = *-* ]]; then - vote_delegation_hash="${vote_delegation#*-}" - while IFS= read -r -d '' _wallet; do - getGovKeyInfo "$(basename ${_wallet})" - if [[ "${drep_hash}" = "${vote_delegation_hash}" ]]; then - walletName="$(basename ${_wallet})" && break - fi - done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) - fi - getDRepIds ${vote_delegation_type} ${vote_delegation_hash} - println "Delegation : CIP-105 => ${FG_LGRAY}${drep_id}${NC}" - println " : CIP-129 => ${FG_LGRAY}${drep_id_cip129}${NC}" - if [[ -n ${walletName} ]]; then - println " : Wallet => ${FG_GREEN}${walletName}${NC}" - fi if [[ ${vote_delegation} = always* ]]; then - : # do nothing - elif getDRepStatus ${vote_delegation_type} ${vote_delegation_hash}; then - [[ $(getEpoch) -lt ${drep_expiry} ]] && expire_status="${FG_GREEN}active${NC}" || expire_status="${FG_RED}inactive${NC} (vote power does not count)" - println "DRep expiry : epoch ${FG_LBLUE}${drep_expiry}${NC} - ${expire_status}" - if [[ -n ${drep_anchor_url} ]]; then - println "DRep anchor url : ${FG_LGRAY}${drep_anchor_url}${NC}" - getDRepAnchor "${drep_anchor_url}" "${drep_anchor_hash}" - case $? in - 0) println "DRep anchor data :\n${FG_LGRAY}" - jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" - println DEBUG "${NC}" - ;; - 1) println "DRep anchor data : ${FG_YELLOW}Invalid URL or currently not available${NC}" ;; - 2) println "DRep anchor data :\n${FG_LGRAY}" - jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" - println "${NC}DRep anchor hash : ${FG_YELLOW}mismatch${NC}" - println " registered : ${FG_LGRAY}${drep_anchor_hash}${NC}" - println " actual : ${FG_LGRAY}${drep_anchor_real_hash}${NC}" - ;; - esac + if [[ ${vote_delegation} = alwaysAbstain ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Delegation" "Always abstain")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Delegation" "Always no confidence")" fi else - println "Status : ${FG_RED}Unable to get DRep status, retired?${NC}" + if [[ ${vote_delegation} = *-* ]]; then + vote_delegation_hash="${vote_delegation#*-}" + while IFS= read -r -d '' _wallet; do + getGovKeyInfo "$(basename ${_wallet})" + if [[ "${drep_hash}" = "${vote_delegation_hash}" ]]; then + walletName="$(basename ${_wallet})" && break + fi + done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + fi + getDRepIds ${vote_delegation_type} ${vote_delegation_hash} + println "$(printf "%-20s ${FG_DGRAY}: CIP-105 =>${NC} ${FG_LGRAY}%s${NC}" "Delegation" "${drep_id}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-129 =>${NC} ${FG_LGRAY}%s${NC}" "" "${drep_id_cip129}")" + if [[ -n ${walletName} ]]; then + println "$(printf "%-20s ${FG_DGRAY}: Wallet =>${NC} ${FG_GREEN}%s${NC}" "" "${walletName}")" + fi + if [[ ${vote_delegation_type} = keyHash ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "Key")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "MultiSig")" + fi + if getDRepStatus ${vote_delegation_type} ${vote_delegation_hash}; then + [[ $(getEpoch) -lt ${drep_expiry} ]] && expire_status="${FG_GREEN}active${NC}" || expire_status="${FG_RED}inactive${NC} (vote power does not count)" + println "$(printf "%-20s ${FG_DGRAY}:${NC} epoch ${FG_LBLUE}%s${NC} - %s" "DRep expiry" "${drep_expiry}" "${expire_status}")" + if [[ -n ${drep_anchor_url} ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep anchor url" "${drep_anchor_url}")" + getDRepAnchor "${drep_anchor_url}" "${drep_anchor_hash}" + case $? in + 0) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" + jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" + println DEBUG "${NC}" + ;; + 1) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor data" "Invalid URL or currently not available")" ;; + 2) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" + jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor hash" "mismatch")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " registered" "${drep_anchor_hash}")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " actual" "${drep_anchor_real_hash}")" + ;; + esac + fi + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_RED}%s${NC}" "Status" "Unable to get DRep status, retired?")" + fi fi getDRepVotePower ${vote_delegation_type} ${vote_delegation_hash} - println "Active Vote power : ${FG_LBLUE}$(formatLovelace ${vote_power:=0})${NC} ADA (${FG_LBLUE}${vote_power_pct:=0} %${NC})" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA (${FG_LBLUE}%s${NC} %%)" "Active Vote power" "$(formatLovelace ${vote_power:=0})" "${vote_power_pct:=0}")" else - println "Delegation : ${FG_YELLOW}undelegated${NC} - please note that reward withdrawals will not work in the future until wallet is vote delegated" + if versionCheck "10.0" "${PROT_VERSION}"; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC} - %s" "Delegation" "undelegated" "please note that reward withdrawals will not work until wallet is vote delegated")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "Delegation" "undelegated")" + fi fi fi waitToProceed && continue @@ -1809,6 +1824,10 @@ function main { fi println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Base Funds" "$(formatLovelace ${base_lovelace})")" println DEBUG "$(printf "%s\t${FG_LBLUE}%s${NC} ADA" "Rewards" "$(formatLovelace ${reward_lovelace})")" + if versionCheck "10.0" "${PROT_VERSION}" && ! getWalletVoteDelegation ${wallet_name}; then + println ERROR "Reward withdrawal is blocked until wallet is vote delegated to a DRep or one of the predefined roles." + waitToProceed && continue + fi if ! withdrawRewards; then waitToProceed && continue fi @@ -1840,10 +1859,9 @@ function main { " ) Rotate - rotate pool KES keys"\ " ) Decrypt - remove write protection and decrypt pool"\ " ) Encrypt - encrypt pool cold keys and make all files immutable"\ - " ) Vote - cast a CIP-0094 Poll ballot"\ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" println DEBUG " Select Pool Operation\n" - select_opt "[n] New" "[i] Import" "[r] Register" "[m] Modify" "[x] Retire" "[l] List" "[s] Show" "[o] Rotate" "[d] Decrypt" "[e] Encrypt" "[v] Vote" "[h] Home" + select_opt "[n] New" "[i] Import" "[r] Register" "[m] Modify" "[x] Retire" "[l] List" "[s] Show" "[o] Rotate" "[d] Decrypt" "[e] Encrypt" "[h] Home" case $? in 0) SUBCOMMAND="new" ;; 1) SUBCOMMAND="import" ;; @@ -1855,8 +1873,7 @@ function main { 7) SUBCOMMAND="rotate" ;; 8) SUBCOMMAND="decrypt" ;; 9) SUBCOMMAND="encrypt" ;; - 10) SUBCOMMAND="vote" ;; - 11) break ;; + 10) break ;; esac case $SUBCOMMAND in new) @@ -3871,99 +3888,114 @@ function main { if getWalletVoteDelegation ${wallet_name}; then unset vote_delegation_hash vote_delegation_type="${vote_delegation%-*}" - if [[ ${vote_delegation} = *-* ]]; then - vote_delegation_hash="${vote_delegation#*-}" - while IFS= read -r -d '' _wallet; do - getGovKeyInfo "$(basename ${_wallet})" - if [[ ${drep_hash} = "${vote_delegation_hash}" ]]; then - walletName="$(basename ${_wallet})" && break - fi - done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) - fi - getDRepIds ${vote_delegation_type} ${vote_delegation_hash} - println "Delegation : CIP-105 => ${FG_LGRAY}${drep_id}${NC}" - println " : CIP-129 => ${FG_LGRAY}${drep_id_cip129}${NC}" - if [[ -n ${walletName} ]]; then - println " : Wallet => ${FG_GREEN}${walletName}${NC}" - fi if [[ ${vote_delegation} = always* ]]; then - : # do nothing - elif getDRepStatus ${vote_delegation_type} ${vote_delegation_hash}; then - [[ ${current_epoch} -lt ${drep_expiry} ]] && expire_status="${FG_GREEN}active${NC}" || expire_status="${FG_RED}inactive${NC} (vote power does not count)" - println "DRep expiry : epoch ${FG_LBLUE}${drep_expiry}${NC} - ${expire_status}" - if [[ -n ${drep_anchor_url} ]]; then - println "DRep anchor url : ${FG_LGRAY}${drep_anchor_url}${NC}" - getDRepAnchor "${drep_anchor_url}" "${drep_anchor_hash}" - case $? in - 0) println "DRep anchor data :\n${FG_LGRAY}" - jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" - println DEBUG "${NC}" - ;; - 1) println "DRep anchor data : ${FG_YELLOW}Invalid URL or currently not available${NC}" ;; - 2) println "DRep anchor data :\n${FG_LGRAY}" - jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" - println "${NC}DRep anchor hash : ${FG_YELLOW}mismatch${NC}" - println " registered : ${FG_LGRAY}${drep_anchor_hash}${NC}" - println " actual : ${FG_LGRAY}${drep_anchor_real_hash}${NC}" - ;; - esac + if [[ ${vote_delegation} = alwaysAbstain ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Delegation" "Always abstain")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "Delegation" "Always no confidence")" fi else - println "Status : ${FG_RED}Unable to get DRep status, retired?${NC}" + if [[ ${vote_delegation} = *-* ]]; then + vote_delegation_hash="${vote_delegation#*-}" + while IFS= read -r -d '' _wallet; do + getGovKeyInfo "$(basename ${_wallet})" + if [[ ${drep_hash} = "${vote_delegation_hash}" ]]; then + walletName="$(basename ${_wallet})" && break + fi + done < <(find "${WALLET_FOLDER}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + fi + getDRepIds ${vote_delegation_type} ${vote_delegation_hash} + println "$(printf "%-20s ${FG_DGRAY}: CIP-105 =>${NC} ${FG_LGRAY}%s${NC}" "Delegation" "${drep_id}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-129 =>${NC} ${FG_LGRAY}%s${NC}" "" "${drep_id_cip129}")" + if [[ -n ${walletName} ]]; then + println "$(printf "%-20s ${FG_DGRAY}: Wallet =>${NC} ${FG_GREEN}%s${NC}" "" "${walletName}")" + fi + if [[ ${vote_delegation_type} = keyHash ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "Key")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "MultiSig")" + fi + if getDRepStatus ${vote_delegation_type} ${vote_delegation_hash}; then + [[ ${current_epoch} -lt ${drep_expiry} ]] && expire_status="${FG_GREEN}active${NC}" || expire_status="${FG_RED}inactive${NC} (vote power does not count)" + println "$(printf "%-20s ${FG_DGRAY}:${NC} epoch ${FG_LBLUE}%s${NC} - %s" "DRep expiry" "${drep_expiry}" "${expire_status}")" + if [[ -n ${drep_anchor_url} ]]; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep anchor url" "${drep_anchor_url}")" + getDRepAnchor "${drep_anchor_url}" "${drep_anchor_hash}" + case $? in + 0) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" + jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" + println DEBUG "${NC}" + ;; + 1) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor data" "Invalid URL or currently not available")" ;; + 2) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" + jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor hash" "mismatch")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " registered" "${drep_anchor_hash}")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " actual" "${drep_anchor_real_hash}")" + ;; + esac + fi + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_RED}%s${NC}" "Status" "Unable to get DRep status, retired?")" + fi fi getDRepVotePower ${vote_delegation_type} ${vote_delegation_hash} - println "Active Vote power : ${FG_LBLUE}$(formatLovelace ${vote_power:=0})${NC} ADA (${FG_LBLUE}${vote_power_pct:=0} %${NC})" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA (${FG_LBLUE}%s${NC} %%)" "Active Vote power" "$(formatLovelace ${vote_power:=0})" "${vote_power_pct:=0}")" else - println "Delegation : ${FG_YELLOW}undelegated${NC} - please note that reward withdrawals will not work in the future until wallet is vote delegated" + if versionCheck "10.0" "${PROT_VERSION}"; then + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC} - %s" "Delegation" "undelegated" "please note that reward withdrawals will not work until wallet is vote delegated")" + else + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "Delegation" "undelegated")" + fi fi fi getGovKeyInfo ${wallet_name} println "DEBUG" "\nOwn DRep Status" if [[ -z ${drep_id} ]]; then - println "Status : ${FG_YELLOW}Governance keys missing, please derive them if needed${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "Status" "Governance keys missing, please derive them if needed")" waitToProceed && continue fi - println "DRep ID : CIP-105 => ${FG_LGRAY}${drep_id}${NC}" - println " : CIP-129 => ${FG_LGRAY}${drep_id_cip129}${NC}" - println "DRep Hash : ${FG_LGRAY}${drep_hash}${NC}" + println "$(printf "%-20s ${FG_DGRAY}: CIP-105 =>${NC} ${FG_LGRAY}%s${NC}" "DRep ID" "${drep_id}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-129 =>${NC} ${FG_LGRAY}%s${NC}" "" "${drep_id_cip129}")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Hash" "${drep_hash}")" if [[ ${hash_type} = keyHash ]]; then - println "DRep Type : ${FG_LGRAY}Key${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "Key")" else - println "DRep Type : ${FG_LGRAY}MultiSig${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep Type" "MultiSig")" fi if [[ ${CNTOOLS_MODE} != "OFFLINE" ]]; then if getDRepStatus ${hash_type} ${drep_hash}; then [[ ${current_epoch} -lt ${drep_expiry} ]] && expire_status="${FG_GREEN}active${NC}" || expire_status="${FG_RED}inactive${NC} (vote power does not count)" - println "DRep expiry : epoch ${FG_LBLUE}${drep_expiry}${NC} - ${expire_status}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} epoch ${FG_LBLUE}%s${NC} - %s" "DRep expiry" "${drep_expiry}" "${expire_status}")" if [[ -n ${drep_anchor_url} ]]; then - println "DRep anchor url : ${FG_LGRAY}${drep_anchor_url}${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" "DRep anchor url" "${drep_anchor_url}")" getDRepAnchor "${drep_anchor_url}" "${drep_anchor_hash}" case $? in - 0) println "DRep anchor data :\n${FG_LGRAY}" + 0) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" println DEBUG "${NC}" ;; - 1) println "DRep anchor data : ${FG_YELLOW}Invalid URL or currently not available${NC}" ;; - 2) println "DRep anchor data :\n${FG_LGRAY}" + 1) println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor data" "Invalid URL or currently not available")" ;; + 2) println "$(printf "%-20s ${FG_DGRAY}:${NC}\n${FG_LGRAY}" "DRep anchor data")" jq -er "${drep_anchor_file}" 2>/dev/null || cat "${drep_anchor_file}" - println "${NC}DRep anchor hash : ${FG_YELLOW}mismatch${NC}" - println " registered : ${FG_LGRAY}${drep_anchor_hash}${NC}" - println " actual : ${FG_LGRAY}${drep_anchor_real_hash}${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "DRep anchor hash" "mismatch")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " registered" "${drep_anchor_hash}")" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LGRAY}%s${NC}" " actual" "${drep_anchor_real_hash}")" ;; esac fi getDRepVotePower ${hash_type} ${drep_hash} - println "Active Vote power : ${FG_LBLUE}$(formatLovelace ${vote_power:=0})${NC} ADA (${FG_LBLUE}${vote_power_pct:=0} %${NC})" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_LBLUE}%s${NC} ADA (${FG_LBLUE}%s${NC} %%)" "Active Vote power" "$(formatLovelace ${vote_power:=0})" "${vote_power_pct:=0}")" else - println "Status : ${FG_YELLOW}DRep key not registered${NC}" + println "$(printf "%-20s ${FG_DGRAY}:${NC} ${FG_YELLOW}%s${NC}" "Status" "DRep key not registered")" fi fi if [[ -n ${cc_cold_id} ]]; then echo - println "Committee Cold ID : CIP-105 => ${FG_LGRAY}${cc_cold_id}${NC}" - println " : CIP-129 => ${FG_LGRAY}${cc_cold_id_cip129}${NC}" - println "Committee Hot ID : CIP-105 => ${FG_LGRAY}${cc_hot_id}${NC}" - println " : CIP-129 => ${FG_LGRAY}${cc_hot_id_cip129}${NC}" + println "$(printf "%-20s ${FG_DGRAY}: CIP-105 =>${NC} ${FG_LGRAY}%s${NC}" "Committee Cold ID" "${cc_cold_id}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-129 =>${NC} ${FG_LGRAY}%s${NC}" "" "${cc_cold_id_cip129}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-105 =>${NC} ${FG_LGRAY}%s${NC}" "Committee Hot ID" "${cc_hot_id}")" + println "$(printf "%-20s ${FG_DGRAY}: CIP-129 =>${NC} ${FG_LGRAY}%s${NC}" "" "${cc_hot_id_cip129}")" fi waitToProceed && continue ;; ################################################################### @@ -4101,10 +4133,10 @@ function main { println "${FG_YELLOW}No active proposals to vote on!${NC}" waitToProceed && continue fi - if [[ ${action_cnt} -gt 5 ]]; then - getAnswerAnyCust page_entries "${action_cnt} proposals found. Enter number of actions to display per page (enter for 4)" + if [[ ${action_cnt} -gt 3 ]]; then + getAnswerAnyCust page_entries "${action_cnt} proposals found. Enter number of actions to display per page (enter for 3)" fi - page_entries=${page_entries:=4} + page_entries=${page_entries:=3} if ! isNumber ${page_entries} || [[ ${page_entries} -lt 1 ]]; then println ERROR "${FG_RED}ERROR${NC}: invalid number" waitToProceed && continue @@ -4143,19 +4175,13 @@ function main { start_idx=$(( (page * page_entries) - page_entries )) # loop current page to find max length of entries max_len=70 # assume action id in CIP-129 format (70) - for vote_action in "${vote_action_list[@]:${start_idx}:${page_entries}}"; do - IFS=',' read -r -a vote_action_arr <<< "${vote_action}" - [[ ${#vote_action_arr[0]} -gt ${max_len} ]] && max_len=${#vote_action_arr[0]} - [[ ${#vote_action_arr[4]} -gt ${max_len} ]] && max_len=${#vote_action_arr[4]} - done total_len=$(( max_len + 13 + 5 )) border_line="|$(printf "%${total_len}s" "" | tr " " "=")|" # max value length + longest title (13) + spacing (5) println DEBUG "Current epoch : ${FG_LBLUE}$(getEpoch)${NC}" println DEBUG "Proposals : ${FG_LBLUE}${action_cnt}${NC}" - println DEBUG "\n${border_line}" idx=1 for vote_action in "${vote_action_list[@]:${start_idx}:${page_entries}}"; do - [[ $idx -ne 1 ]] && printf "|$(printf "%${total_len}s" "" | tr " " "-")|\n" + println DEBUG "\n${border_line}" # calculate length of strings IFS=',' read -r action_id action_type proposed_in expires_after anchor_url drep_yes drep_yes_power drep_yes_pct drep_no drep_no_power drep_no_pct spo_yes spo_yes_power spo_yes_pct spo_no spo_no_power spo_no_pct cc_yes cc_yes_pct cc_no cc_no_pct drep_vt spo_vt cc_vt isParameterSecurityGroup <<< "${vote_action}" max_yes_len=${#drep_yes} @@ -4177,6 +4203,14 @@ function main { max_vt_len=${#drep_vt} [[ ${#spo_vt} -gt ${max_vt_len} ]] && max_vt_len=${#spo_vt} [[ ${#cc_vt} -gt ${max_vt_len} ]] && max_vt_len=${#cc_vt} + anchor_url_arr=() + anchor_url_start=0 + while true; do + anchor_url_chunk=${anchor_url:${anchor_url_start}:${max_len}} + [[ -z ${anchor_url_chunk} ]] && break + anchor_url_arr+=( ${anchor_url_chunk} ) + anchor_url_start=$(( anchor_url_start + max_len )) + done # print data IFS='#' read -r proposal_tx_id proposal_index <<< "${action_id}" getGovActionId ${proposal_tx_id} ${proposal_index} @@ -4189,13 +4223,16 @@ function main { else printf "| %-13s : ${FG_LGRAY}epoch${NC} ${FG_LBLUE}%-$(( max_len - 6 ))s${NC} |\n" "Expires After" "${expires_after}" fi - printf "| %-13s : ${FG_LGRAY}%-${max_len}s${NC} |\n" "Anchor URL" "${anchor_url}" + for i in "${!anchor_url_arr[@]}"; do + [[ $i -eq 0 ]] && anchor_label="Anchor URL" || anchor_label="" + printf "| %-13s : ${FG_LGRAY}%-${max_len}s${NC} |\n" "${anchor_label}" "${anchor_url_arr[$i]}" + done three_col_width=$(( max_len / 3 )) three_col_start=18 three_col_2_start=$(( three_col_start + three_col_width )) three_col_3_start=$(( three_col_2_start + three_col_width )) # Header - printf "|${FG_LGRAY}$(printf "%17s" "" | tr " " "-")${NC}${FG_BLACK}\e[42mYES${NC}${FG_LGRAY}$(printf "%$((three_col_width-3))s" " " | tr "" "-")${NC}${FG_BLACK}\e[41mNO${NC}${FG_LGRAY}$(printf "%$((three_col_width-2))s" "" | tr " " "-")${NC}${FG_BLACK}\e[47mSTATUS${NC}${FG_LGRAY}$(printf "%$(((max_len-(2*three_col_width))-5))s" "" | tr " " "-")${NC}|\n" + printf "|${FG_LGRAY}$(printf "%17s" "" | tr " " "-")${NC}${FG_BLACK}\e[42mYES${NC}${FG_LGRAY}$(printf "%$((three_col_width-3))s" " " | tr " " "-")${NC}${FG_BLACK}\e[41mNO${NC}${FG_LGRAY}$(printf "%$((three_col_width-2))s" "" | tr " " "-")${NC}${FG_BLACK}\e[47mSTATUS${NC}${FG_LGRAY}$(printf "%$(((max_len-(2*three_col_width))-5))s" "" | tr " " "-")${NC}|\n" tput sc if isAllowedToVote "drep" "${action_type}" "${isParameterSecurityGroup:=N}"; then # DRep YES @@ -4212,7 +4249,7 @@ function main { fi printf "${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_yes_pct_len-${#drep_yes_pct}+1))s${NC}" "${drep_yes_pct}" "%" if [[ -n ${drep_vt} ]]; then - printf " ${FG_LGRAY}of${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#drep_vt}+1))s${NC}" "${drep_vt}" "%" + printf " ${FG_LGRAY}VT:${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#drep_vt}+1))s${NC}" "${drep_vt}" "%" fi # move to end and close line tput rc && tput cuf ${total_len} && printf " |\n" @@ -4241,7 +4278,7 @@ function main { fi printf "${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_yes_pct_len-${#spo_yes_pct}+1))s${NC}" "${spo_yes_pct}" "%" if [[ -n ${spo_vt} ]]; then - printf " ${FG_LGRAY}of${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#spo_vt}+1))s${NC}" "${spo_vt}" "%" + printf " ${FG_LGRAY}VT:${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#spo_vt}+1))s${NC}" "${spo_vt}" "%" fi # move to end and close line tput rc && tput cuf ${total_len} && printf " |\n" @@ -4270,7 +4307,7 @@ function main { fi printf "${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_yes_pct_len-${#cc_yes_pct}+1))s${NC}" "${cc_yes_pct}" "%" if [[ -n ${cc_vt} ]]; then - printf " ${FG_LGRAY}of${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#cc_vt}+1))s${NC}" "${cc_vt}" "%" + printf " ${FG_LGRAY}VT:${NC} ${FG_LBLUE}%s${NC} ${FG_LGRAY}%-$((max_vt_len-${#cc_vt}+1))s${NC}" "${cc_vt}" "%" fi # move to end and close line tput rc && tput cuf ${total_len} && printf " |\n" @@ -4283,9 +4320,39 @@ function main { # move to end and close line tput rc && tput cuf ${total_len} && printf " |\n" fi - ((idx++)) + unset printed_own + for own_vote in ${own_spo_votes}; do + if [[ ${own_vote} = "${action_id}"* ]]; then + IFS=';' read -ra own_vote_arr <<< "${own_vote}" + [[ -z ${printed_own} ]] && printf "|$(printf "%${total_len}s" "" | tr " " "-")|\n" && printed_own=Y + if [[ ${own_vote_arr[2]} = Yes ]]; then vote_color="${FG_GREEN}"; elif [[ ${own_vote_arr[2]} = No ]]; then vote_color="${FG_RED}"; else vote_color="${FG_DGRAY}"; fi + tput sc + printf "| You voted ${vote_color}%s${NC} with pool ${FG_GREEN}%s${NC}" "${own_vote_arr[2]}" "${own_vote_arr[1]}" + tput rc && tput cuf ${total_len} && printf " |\n" + fi + done + for own_vote in ${own_drep_votes}; do + if [[ ${own_vote} = "${action_id}"* ]]; then + IFS=';' read -ra own_vote_arr <<< "${own_vote}" + [[ -z ${printed_own} ]] && printf "|$(printf "%${total_len}s" "" | tr " " "-")|\n" && printed_own=Y + if [[ ${own_vote_arr[2]} = Yes ]]; then vote_color="${FG_GREEN}"; elif [[ ${own_vote_arr[2]} = No ]]; then vote_color="${FG_RED}"; else vote_color="${FG_DGRAY}"; fi + tput sc + printf "| You voted ${vote_color}%s${NC} with DRep wallet ${FG_GREEN}%s${NC}" "${own_vote_arr[2]}" "${own_vote_arr[1]}" + tput rc && tput cuf ${total_len} && printf " |\n" + fi + done + for own_vote in ${own_cc_votes}; do + if [[ ${own_vote} = "${action_id}"* ]]; then + IFS=';' read -ra own_vote_arr <<< "${own_vote}" + [[ -z ${printed_own} ]] && printf "|$(printf "%${total_len}s" "" | tr " " "-")|\n" && printed_own=Y + if [[ ${own_vote_arr[2]} = Yes ]]; then vote_color="${FG_GREEN}"; elif [[ ${own_vote_arr[2]} = No ]]; then vote_color="${FG_RED}"; else vote_color="${FG_DGRAY}"; fi + tput sc + printf "| You voted ${vote_color}%s${NC} with committee wallet ${FG_GREEN}%s${NC}" "${own_vote_arr[2]}" "${own_vote_arr[1]}" + tput rc && tput cuf ${total_len} && printf " |\n" + fi + done + println DEBUG "${border_line}" done - println DEBUG "${border_line}" println DEBUG "\n${FG_GREEN}YES${NC} = Total power of 'yes' votes." println DEBUG "${FG_RED}NO${NC} = Total power of 'no' votes, including buckets of 'no vote cast' and 'always no confidence'." println DEBUG " ${FG_LGRAY}For motion of no confidence, 'always no confidence' power is switched to yes bucket.${NC}" diff --git a/scripts/cnode-helper-scripts/deploy-as-systemd.sh b/scripts/cnode-helper-scripts/deploy-as-systemd.sh index 36ab9dd95..9db99d114 100755 --- a/scripts/cnode-helper-scripts/deploy-as-systemd.sh +++ b/scripts/cnode-helper-scripts/deploy-as-systemd.sh @@ -12,56 +12,39 @@ PARENT="$(dirname "$0")" vname="${CNODE_VNAME}" -echo -e "\e[32m~~ Cardano Node ~~\e[0m" -echo "launches the main cnode.sh script to deploy cardano-node" -echo -./cnode.sh -d +removeService() { + [[ -z $1 || ! -f "/etc/systemd/system/$1" ]] && return + sudo systemctl disable "$1" >/dev/null + sudo rm -f "/etc/systemd/system/$1" >/dev/null +} + +echo -e "\n${FG_GREEN}~~ Cardano Node ~~${NC}\n" +getAnswer "Deploy service?" && ./cnode.sh -d if grep -q "^PGPASSFILE=" "${CNODE_HOME}/scripts/dbsync.sh" 2> /dev/null || [[ -f "${CNODE_HOME}/priv/.pgpass" ]]; then - echo -e "\e[32m~~ Cardano DB Sync ~~\e[0m" - echo "launches the dbsync.sh script to deploy cardano-db-sync" - echo - ./dbsync.sh -d + echo -e "\n${FG_GREEN}~~ Cardano DB Sync ~~${NC}\n" + getAnswer "Deploy service?" && ./dbsync.sh -d || removeService "${vname}-dbsync.service" fi -echo -e "\e[32m~~ Cardano Submit API ~~\e[0m" -echo "Deploy Cardano Submit API as systemd service? [y|n]" -echo -read -rsn1 yn -if [[ ${yn} = [Yy]* ]]; then - ./submitapi.sh -d -fi +echo -e "\n${FG_GREEN}~~ Cardano Submit API ~~${NC}\n" +getAnswer "Deploy service?" && ./submitapi.sh -d || removeService "${vname}-submitapi.service" -if command -v mithril-signer >/dev/null 2>&1 ; then - echo -e "\e[32m~~ Mithril Signer ~~\e[0m" - echo "Deploy Mithril Signer as a systemd service? [y|n]" - read -rsn1 yn - if [[ ${yn} = [Yy]* ]]; then - ./mithril-signer.sh -d - else - if [[ -f /etc/systemd/system/${vname}-mithril-signer.service ]]; then - sudo systemctl disable ${vname}-mithril-signer.service - sudo rm -f /etc/systemd/system/${vname}-mithril-signer.service - fi - fi +if command -v mithril-signer >/dev/null 2>&1; then + echo -e "\n${FG_GREEN}~~ Mithril Signer ~~${NC}\n" + getAnswer "Deploy service?" && ./mithril-signer.sh -d || removeService "${vname}-mithril-signer.service" fi -if command -v ogmios >/dev/null 2>&1 ; then - echo -e "\e32m~~ Cardano Ogmios Server ~~\e[0m" - echo "launches the ogmios.sh script to deploy ogmios" - echo - ./ogmios.sh -d +if command -v ogmios >/dev/null 2>&1; then + echo -e "\n${FG_GREEN}~~ Cardano Ogmios Server ~~${NC}\n" + getAnswer "Deploy service?" && ./ogmios.sh -d || removeService "${vname}-ogmios.service" fi -echo -echo -e "\e[32m~~ Topology Updater ~~\e[0m" +echo -e "\n${FG_GREEN}~~ Topology Updater ~~${NC}" echo "An intermediate centralized solution for relay nodes to handle the static topology files until P2P network module is implemented on protocol level." echo "A service file is deployed that once every 60 min send a message to API. After 4 consecutive successful requests (3 hours) the relay is accepted and available for others to fetch. If the node is turned off, it’s automatically delisted after 3 hours." echo "For more info, visit https://cardano-community.github.io/guild-operators/Scripts/topologyupdater" echo -echo "Deploy Topology Updater as systemd services? (only for relay nodes) [y|n]" -read -rsn1 yn -if [[ ${yn} = [Yy]* ]]; then +if getAnswer "Deploy services? (only for relay nodes)"; then sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-tu-push.service [Unit] Description=Cardano Node - Topology Updater - node alive push @@ -130,40 +113,22 @@ AccuracySec=1s WantedBy=timers.target ${vname}.service EOF" else - if [[ -f /etc/systemd/system/${vname}-tu-fetch.service ]]; then - sudo systemctl disable ${vname}-tu-fetch.service - sudo rm -f /etc/systemd/system/${vname}-tu-fetch.service - fi - if [[ -f /etc/systemd/system/${vname}-tu-push.timer ]]; then - sudo systemctl disable ${vname}-tu-push.timer - sudo rm -f /etc/systemd/system/${vname}-tu-push.timer - fi - if [[ -f /etc/systemd/system/${vname}-tu-push.service ]]; then - sudo rm -f /etc/systemd/system/${vname}-tu-push.service - fi - if [[ -f /etc/systemd/system/${vname}-tu-restart.timer ]]; then - sudo systemctl disable ${vname}-tu-restart.timer - sudo rm -f /etc/systemd/system/${vname}-tu-restart.timer - fi - if [[ -f /etc/systemd/system/${vname}-tu-restart.service ]]; then - sudo rm -f /etc/systemd/system/${vname}-tu-restart.service - fi + removeService ${vname}-tu-fetch.service + removeService ${vname}-tu-push.timer + removeService ${vname}-tu-push.service + removeService ${vname}-tu-restart.timer + removeService ${vname}-tu-restart.service fi -echo -echo -e "\e[32m~~ Leaderlog / PoolTool SendSlots ~~\e[0m" -echo "A collection of services that together creates a blocklog of current and upcoming blocks" -echo "Dependant on ${vname}.service and when started|stopped|restarted all these companion services will apply the same action" -echo "${vname}-cncli-sync : Start CNCLI chainsync process that connects to cardano-node to sync blocks stored in SQLite DB" -echo "${vname}-cncli-leaderlog : Loops through all slots in current epoch to calculate leader schedule" -echo "${vname}-cncli-validate : Confirms that the block made actually was accepted and adopted by chain" -echo -e "${vname}-cncli-ptsendslots : Securely sends PoolTool the number of slots you have assigned for an epoch and validates the correctness of your past epochs (\e[36moptional\e[0m)" -echo -e "${vname}-logmonitor : Parses JSON log of cardano-node for traces of interest to give instant adopted status and invalid status (\e[36moptional\e[0m)" -echo -if command -v "${CNCLI}" >/dev/null; then - echo "Deploy Blocklog as systemd services? [y|n]" - read -rsn1 yn - if [[ ${yn} = [Yy]* ]]; then +if command -v cncli >/dev/null 2>&1; then + echo -e "${FG_GREEN}~~ CNCLI ~~${NC}" + echo "A collection of services that together creates a blocklog of current and upcoming blocks" + echo "Dependant on ${vname}.service and when started|stopped|restarted all these companion services will apply the same action" + echo "${vname}-cncli-sync : Start CNCLI chainsync process that connects to cardano-node to sync blocks stored in SQLite DB" + echo "${vname}-cncli-leaderlog : Loops through all slots in current epoch to calculate leader schedule" + echo "${vname}-cncli-validate : Confirms that the block made actually was accepted and adopted by chain" + echo + if getAnswer "Deploy services?"; then sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-cncli-sync.service [Unit] Description=Cardano Node - CNCLI Sync @@ -228,15 +193,11 @@ KillMode=mixed [Install] WantedBy=${vname}-cncli-sync.service EOF" - echo - echo -e "\e[32m~~ PoolTool SendSlots ~~\e[0m" + echo -e "\n${FG_GREEN}~~ PoolTool SendSlots ~~${NC}" echo "Securely sends pooltool the number of slots you have assigned for an epoch and validates the correctness of your past epochs" echo - if command -v "${CNCLI}" >/dev/null; then - echo "Deploy PoolTool SendSlots as systemd services? [y|n]" - read -rsn1 yn - if [[ ${yn} = [Yy]* ]]; then - sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-cncli-ptsendslots.service + if getAnswer "Deploy service?"; then + sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-cncli-ptsendslots.service [Unit] Description=Cardano Node - CNCLI PoolTool SendSlots BindsTo=${vname}-cncli-sync.service @@ -259,139 +220,87 @@ KillMode=mixed [Install] WantedBy=${vname}-cncli-sync.service EOF" - else - if [[ -f /etc/systemd/system/${vname}-cncli-ptsendslots.service ]]; then - sudo systemctl disable ${vname}-cncli-ptsendslots.service - sudo rm -f /etc/systemd/system/${vname}-cncli-ptsendslots.service - fi - fi else - echo "cncli executable not found... skipping!" + removeService ${vname}-cncli-ptsendslots.service fi - echo - echo -e "\e[32m~~ Log Monitor ~~\e[0m" - echo "Parses JSON log of cardano-node for traces of interest to give instant adopted status and invalid status" - echo "Optional to use, blocklog will function but without above mentioned features" - echo - echo "Deploy Log Monitor as systemd services? [y|n]" - read -rsn1 yn - if [[ ${yn} = [Yy]* ]]; then - sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-logmonitor.service + else + removeService ${vname}-cncli-sync.service + removeService ${vname}-cncli-leaderlog.service + removeService ${vname}-cncli-validate.service + removeService ${vname}-cncli-ptsendslots.service + fi + echo -e "\n${FG_GREEN}~~ PoolTool SendTip ~~${NC}" + echo "Countinously sends node tip to PoolTool for network analysis and to show that your node is alive and well with a green badge" + echo "Dependant on ${vname}.service and when started|stopped|restarted ptsendtip services will apply the same action" + echo + if getAnswer "Deploy service?"; then + sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-cncli-ptsendtip.service [Unit] -Description=Cardano Node - Log Monitor +Description=Cardano Node - CNCLI PoolTool SendTip BindsTo=${vname}.service After=${vname}.service [Service] Type=simple Restart=on-failure -RestartSec=1 +RestartSec=20 User=$USER WorkingDirectory=${CNODE_HOME}/scripts -ExecStart=/bin/bash -l -c \"exec ${CNODE_HOME}/scripts/logMonitor.sh\" -ExecStop=/bin/bash -l -c \"exec kill -2 \$(ps -ef | grep -m1 ${CNODE_HOME}/scripts/logMonitor.sh | tr -s ' ' | cut -d ' ' -f2) &>/dev/null\" +ExecStart=/bin/bash -l -c \"exec ${CNODE_HOME}/scripts/cncli.sh ptsendtip\" +ExecStop=/bin/bash -l -c \"exec kill -2 \$(ps -ef | grep [c]ncli.sendtip.*.${vname}-pooltool.json | tr -s ' ' | cut -d ' ' -f2) &>/dev/null\" KillSignal=SIGINT SuccessExitStatus=143 -SyslogIdentifier=${vname}-logmonitor +SyslogIdentifier=${vname}-cncli-ptsendtip TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=${vname}.service EOF" - else - if [[ -f /etc/systemd/system/${vname}-logmonitor.service ]]; then - sudo systemctl disable ${vname}-logmonitor.service - sudo rm -f /etc/systemd/system/${vname}-logmonitor.service - fi - fi else - if [[ -f /etc/systemd/system/${vname}-cncli-sync.service ]]; then - sudo systemctl disable ${vname}-cncli-sync.service - sudo rm -f /etc/systemd/system/${vname}-cncli-sync.service - fi - if [[ -f /etc/systemd/system/${vname}-cncli-leaderlog.service ]]; then - sudo systemctl disable ${vname}-cncli-leaderlog.service - sudo rm -f /etc/systemd/system/${vname}-cncli-leaderlog.service - fi - if [[ -f /etc/systemd/system/${vname}-cncli-validate.service ]]; then - sudo systemctl disable ${vname}-cncli-validate.service - sudo rm -f /etc/systemd/system/${vname}-cncli-validate.service - fi - if [[ -f /etc/systemd/system/${vname}-cncli-ptsendslots.service ]]; then - sudo systemctl disable ${vname}-cncli-ptsendslots.service - sudo rm -f /etc/systemd/system/${vname}-cncli-ptsendslots.service - fi - if [[ -f /etc/systemd/system/${vname}-logmonitor.service ]]; then - sudo systemctl disable ${vname}-logmonitor.service - sudo rm -f /etc/systemd/system/${vname}-logmonitor.service - fi + removeService ${vname}-cncli-ptsendtip.service fi -else - echo "cncli executable not found... skipping!" fi - -echo -echo -e "\e[32m~~ PoolTool SendTip ~~\e[0m" -echo "Countinously sends node tip to PoolTool for network analysis and to show that your node is alive and well with a green badge" -echo "Dependant on ${vname}.service and when started|stopped|restarted ptsendtip services will apply the same action" +echo -e "\n${FG_GREEN}~~ Log Monitor ~~${NC}" +echo "Parses JSON log of cardano-node for traces of interest to give instant adopted status and invalid status" +echo "Optional to use, often used as a complement to CNCLI services but functions on its own" echo -if command -v "${CNCLI}" >/dev/null; then - echo "Deploy PoolTool SendTip as systemd services? [y|n]" - read -rsn1 yn - if [[ ${yn} = [Yy]* ]]; then - sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-cncli-ptsendtip.service +if getAnswer "Deploy service?"; then + sudo bash -c "cat << 'EOF' > /etc/systemd/system/${vname}-logmonitor.service [Unit] -Description=Cardano Node - CNCLI PoolTool SendTip +Description=Cardano Node - Log Monitor BindsTo=${vname}.service After=${vname}.service [Service] Type=simple Restart=on-failure -RestartSec=20 +RestartSec=1 User=$USER WorkingDirectory=${CNODE_HOME}/scripts -ExecStart=/bin/bash -l -c \"exec ${CNODE_HOME}/scripts/cncli.sh ptsendtip\" -ExecStop=/bin/bash -l -c \"exec kill -2 \$(ps -ef | grep [c]ncli.sendtip.*.${vname}-pooltool.json | tr -s ' ' | cut -d ' ' -f2) &>/dev/null\" +ExecStart=/bin/bash -l -c \"exec ${CNODE_HOME}/scripts/logMonitor.sh\" +ExecStop=/bin/bash -l -c \"exec kill -2 \$(ps -ef | grep -m1 ${CNODE_HOME}/scripts/logMonitor.sh | tr -s ' ' | cut -d ' ' -f2) &>/dev/null\" KillSignal=SIGINT SuccessExitStatus=143 -SyslogIdentifier=${vname}-cncli-ptsendtip +SyslogIdentifier=${vname}-logmonitor TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=${vname}.service EOF" - else - if [[ -f /etc/systemd/system/${vname}-cncli-ptsendtip.service ]]; then - sudo systemctl disable ${vname}-cncli-ptsendtip.service - sudo rm -f /etc/systemd/system/${vname}-cncli-ptsendtip.service - fi - fi else - echo "cncli executable not found... skipping!" + removeService ${vname}-logmonitor.service fi -echo -echo -e "\e[32m~~ BlockPerf / Propagation performance ~~\e[0m" +echo -e "\n${FG_GREEN}~~ BlockPerf / Propagation performance ~~${NC}" echo "A service parsing the node block propagation times from announced header to adopted block" echo "sends block propagation time data to TopologyUpdater for common network analysis and performance comparison" echo "${vname}-tu-blockperf : Parses JSON log of cardano-node for block network propagation times" echo -echo "Deploy BlockPerf as systemd services? [y|n]" -read -rsn1 yn -if [[ ${yn} = [Yy]* ]]; then - ./blockPerf.sh -d -else - if [[ -f /etc/systemd/system/${vname}-tu-blockperf.service ]]; then - sudo systemctl disable ${vname}-tu-blockperf.service - sudo rm -f /etc/systemd/system/${vname}-tu-blockperf.service - fi -fi +getAnswer "Deploy service?" && ./blockPerf.sh -d || removeService "${vname}-tu-blockperf.service" -echo sudo systemctl daemon-reload [[ -f /etc/systemd/system/${vname}-logmonitor.service ]] && sudo systemctl enable ${vname}-logmonitor.service [[ -f /etc/systemd/system/${vname}-tu-fetch.service ]] && sudo systemctl enable ${vname}-tu-fetch.service @@ -405,10 +314,9 @@ sudo systemctl daemon-reload [[ -f /etc/systemd/system/${vname}-cncli-ptsendslots.service ]] && sudo systemctl enable ${vname}-cncli-ptsendslots.service [[ -f /etc/systemd/system/${vname}-mithril-signer.service ]] && sudo systemctl enable ${vname}-mithril-signer.service - echo echo "If not done already, update 'User Variables' section in relevant script in ${CNODE_HOME}/scripts/ folder" -echo -e "E.g \e[36menv\e[0m, \e[36mcnode.sh\e[0m, \e[36mcncli.sh\e[0m, \e[36mgLiveView.sh\e[0m, \e[36mtopologyUpdater.sh\e[0m" -echo -e "You can then start/restart the node with \e[32msudo systemctl restart ${vname}\e[0m" +echo -e "E.g ${FG_CYAN}env${NC}, ${FG_CYAN}cnode.sh${NC}, ${FG_CYAN}cncli.sh${NC}, ${FG_CYAN}gLiveView.sh${NC}, ${FG_CYAN}topologyUpdater.sh${NC}" +echo -e "You can then start/restart the node with ${FG_GREEN}sudo systemctl restart ${vname}${NC}" echo "This will automatically start all installed companion services due to service dependency" echo diff --git a/scripts/cnode-helper-scripts/env b/scripts/cnode-helper-scripts/env index 9b74a9cf9..104e1823d 100644 --- a/scripts/cnode-helper-scripts/env +++ b/scripts/cnode-helper-scripts/env @@ -163,7 +163,7 @@ err_exit() { # Description : Query user for yes or no answer getAnswer() { - getAnswerAny answer "$* (yes/no)" + getAnswerAny answer "$* ([y]es / [n]o)" while : ; do case $answer in [Yy]*) return 0 ;; @@ -1110,8 +1110,8 @@ fi node_version="$(${CNODEBIN} version | head -1 | cut -d' ' -f2)" cli_version="$(${CCLI} version | head -1 | cut -d' ' -f2)" -if ! versionCheckNode "9.1.1" "${node_version}" || ! versionCheckNode "9.2.1.0" "${cli_version}"; then - echo -e "\nKoios scripts have now been upgraded to support cardano-node 9.1.x ('${node_version}' found) / cardano-cli 9.2.x.x ('${cli_version}' found).\nPlease update cardano-node binaries (ensure to read release notes and update various configs using guild-deploy (use appropriate options to download/install/overwrite parts you need) or use tagged branches for older node version (eg: ./