├── example1.png ├── example2.png ├── example3.png ├── README.md └── show-solana-node-info_v2.sh /example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SOFZP/show-solana-node-info_v2/HEAD/example1.png -------------------------------------------------------------------------------- /example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SOFZP/show-solana-node-info_v2/HEAD/example2.png -------------------------------------------------------------------------------- /example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SOFZP/show-solana-node-info_v2/HEAD/example3.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solana Nodes CLI Monitoring Script 2 | #### 💛💙 Stand with Ukraine! 💙💛 3 | ##### ❇️ Say thanks to author (SOL): BrnMNcFz6EzjZsQM8xNbrTsJE88fyXU2X6Crar9QPpsK / cryptovik.sol - or just stake your SOL to my node: CryptoVik 4 | 5 | 6 | ### This is complex CLI script for solana nodes monitoring 7 | 8 | ## UPD: This script is not supported in 2025. We are working on new versions, more modular approach, error tolerance, more all-in-one information. 9 | 10 | ## TL;DR 11 | Script uses **on-chain solana data, API of solana.org, API of Grafana** 12 | 13 | You can see data of **ANY solana validator node** 14 | 15 | This is the tool for monitoring multiple nodes with cli 16 | 17 | Tool has two modes: **full and short** 18 | 19 | If node don't have standart Grafana (telegraf) installed than you cannot see hardware info of it 20 | 21 | All returned parameters are decribed in the end of this readme 22 | 23 | 24 | ## How to use show-solana-node-info_v2.sh: 25 | 26 | 1. Move file `show-solana-node-info_v2.sh` to the server or instance **with installed solana** 27 | 28 | 29 | 2. Install **rust, solana-foundation-delegation-program-cli and jq**: 30 | 31 | `apt-get update && curl https://sh.rustup.rs/ -sSf | sh` 32 | 33 | enter 1 + Enter 34 | 35 | `source $HOME/.cargo/env && rustup update` 36 | 37 | `sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make` 38 | 39 | enter y + Enter 40 | 41 | `cargo install solana-foundation-delegation-program-cli` 42 | 43 | `sudo apt install jq # version 1.6-1ubuntu0.20.04.1` 44 | 45 | 46 | 3. Give permissions to the script: `chmod u+x ./show-solana-node-info_v2.sh` 47 | 48 | 49 | 4. Run it on your node without parameters: `./show-solana-node-info_v2.sh` 50 | 51 | 52 | ### You can use script on any instance with installed solana, 53 | and you can read data of **any node** in solana blockchain: 54 | 55 | `./show-solana-node-info_v2.sh ` 56 | 57 | where 58 | `` - pubkey of any node, 59 | 60 | `` - `-ut` or `-ud` or `-um` or `-ul` for cluster, 61 | 62 | `` - `true` if you want short return and `false` / nothing if you want full return 63 | 64 | 65 | ## Known issues: 66 | 1. **RPC issues**. If PRC is slow or unavailable than you can see RPC errors. Working now to rotate RPC if so happens. 67 | ![RPC error example](/example3.png "RPC error example") 68 | 2. **If --no-voting is set**, than you cannot see node info here. 69 | 3. **If pubkey doesn't belongs to node**, there will be some errors. 70 | 71 | 72 | ## Appreciation 73 | Part of `see schedule block` (shows estimated time of scheduled slots of node) modified from https://github.com/Vahhhh/solana/blob/main/see-schedule.sh - BIG THANKS!!! 74 | 75 | 76 | ## Examples 77 | ### My TDS node FULL return (Testnet cluster restart was active at that moment) 78 | ![My TDS node FULL return](/example1.png "My TDS node FULL return") 79 | ### My MB node SHORT return 80 | ![My MB node SHORT return](/example2.png "My MB node SHORT return") 81 | 82 | 83 | # All script returned data 84 | 85 | 1. *Time now* - counting as time of server. You can change time of server: 86 | 87 | `sudo ln -sf /usr/share/zoneinfo/Europe/Kiev /etc/localtime` 88 | 89 | Check it: 90 | 91 | `date` or `timedatectl` 92 | 93 | 2. *Solana Price*. If Grafana is not set or have its own issues than you can see NULL here 94 | 95 | 3. *Epoch Progress* 96 | 97 | 4. 98 | 99 | 5. 100 | 101 | 6. 102 | 103 | 7. 104 | 105 | . 106 | 107 | . 108 | 109 | ❇️ Say thanks to author (SOL): BrnMNcFz6EzjZsQM8xNbrTsJE88fyXU2X6Crar9QPpsK / cryptovik.sol 110 | ❇️ Or stake your SOL to my node: CryptoVik (https://cryptovik.info/) 111 | -------------------------------------------------------------------------------- /show-solana-node-info_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Solana Nodes CLI Monitoring Script 3 | # 4 | # Documentation & actual releases are here: 5 | # https://github.com/SOFZP/show-solana-node-info_v2 6 | # 7 | # Stand with Ukraine! 8 | # 9 | # ❇️❇️❇️ Say thanks to author (SOL): ❇️❇️❇️ 10 | # BrnMNcFz6EzjZsQM8xNbrTsJE88fyXU2X6Crar9QPpsK / cryptovik.sol 11 | # 12 | 13 | pushd `dirname ${0}` > /dev/null || exit 1 14 | 15 | 16 | # colors 17 | NOCOLOR='\033[0m' 18 | CYAN='\033[0;36m' 19 | RED='\033[0;31m' 20 | GREEN='\033[0;32m' 21 | ORANGE='\033[0;33m' 22 | BLUE='\033[0;34m' 23 | PURPLE='\033[0;35m' 24 | LIGHTGRAY='\033[0;37m' 25 | DARKGRAY='\033[1;30m' 26 | LIGHTRED='\033[1;31m' 27 | LIGHTGREEN='\033[1;32m' 28 | YELLOW='\033[1;33m' 29 | LIGHTBLUE='\033[1;34m' 30 | LIGHTPURPLE='\033[1;35m' 31 | LIGHTCYAN='\033[1;36m' 32 | 33 | UNDERLINE='' #'\033[4m' 34 | 35 | 36 | _work_done=0 37 | 38 | SERVER_TIME_ZONE=`timedatectl | grep "Time zone" | sed 's/ */ /g' | sed 's/ Time zone://g'` 39 | 40 | 41 | 42 | 43 | function getRandomRPC () { 44 | local DEFAULT_CLUSTER1='-ul' 45 | local SOLANA_CLUSTER1=' '${1:-$DEFAULT_CLUSTER1}' ' 46 | 47 | echo $(solana ${SOLANA_CLUSTER1} gossip --output json-compact | jq -r .[].rpcHost | sed 's/null//g' | sed '/^$/d' | shuf -n 1 | awk '{print "--url https://"$1}') 48 | } 49 | 50 | function rotateKnownRPC () { 51 | 52 | local testRPC1=' -ut ' 53 | local testRPC2=' -ut ' 54 | local testRPC3='--url https://testnet.rpcpool.com/' 55 | local testRPC4='--url http://testnet.solana.margus.one/' 56 | local testRPC5='--url https://entrypoint.testnet.solana.sergo.dev' 57 | 58 | local mainRPC1=' -um ' 59 | local mainRPC2='--url https://rpc.ankr.com/solana' 60 | local mainRPC3='--url https://ssc-dao.genesysgo.net/' 61 | local mainRPC4='--url https://solana-mainnet-rpc.allthatnode.com/' 62 | local mainRPC5='--url https://mainnet.rpcpool.com/' 63 | 64 | local fcl="$1" 65 | 66 | if [[ "$fcl" = "$testRPC1" ]]; then 67 | echo "$testRPC2" 68 | elif [[ "$fcl" = "$testRPC2" ]]; then 69 | echo "$testRPC3" 70 | elif [[ "$fcl" = "$testRPC3" ]]; then 71 | echo "$testRPC4" 72 | elif [[ "$fcl" = "$testRPC4" ]]; then 73 | echo "$testRPC1" 74 | fi 75 | 76 | if [[ "$fcl" = "$mainRPC1" ]]; then 77 | echo "$mainRPC2" 78 | elif [[ "$fcl" = "$mainRPC2" ]]; then 79 | echo "$mainRPC3" 80 | elif [[ "$fcl" = "$mainRPC3" ]]; then 81 | echo "$mainRPC4" 82 | elif [[ "$fcl" = "$mainRPC4" ]]; then 83 | echo "$mainRPC1" 84 | fi 85 | } 86 | 87 | 88 | function solana_price() { 89 | 90 | PRICE=`curl -g -s 'https://data.gateapi.io/api2/1/ticker/sol_usdt' --compressed | jq -r @json 2> /dev/null | jq -r '.last' | awk '{printf("%.2f\n",$1)}' 2> /dev/null` 91 | 92 | PERCENT=`curl -g -s 'https://data.gateapi.io/api2/1/ticker/sol_usdt' --compressed | jq -r @json 2> /dev/null | jq -r '.percentChange' | awk '{printf("%.2f\n",$1)}' 2> /dev/null` 93 | 94 | #if [[ $PRICE!="null" ]]; then 95 | echo -e "${PURPLE}${PRICE:-Cannot see price now}$ | ${PERCENT:-}% ${NOCOLOR}" 96 | #else 97 | # echo "" 98 | #fi 99 | 100 | } 101 | 102 | 103 | 104 | function check_key () { 105 | local KEY_TO_CHECK=${1:-} 106 | 107 | local STAKE_NAMES=(SELF_STAKE FOUNDATION TDS_FOUNDATION SECRET_STAKE MARINADE MARINADE2 SOCEAN_POOL JPOOL_POOL EVERSOL_STAKE BLAZESTAKE LIDO_POOL DAOPOOL JITO_POOL LAINE_POOL UNKNOWN_POOL ?ALAMEDA2 ?ALAMEDA3 ?ALAMEDA4 ?ALAMEDA5 ?ALAMEDA6 ?ALAMEDA7 ?ALAMEDA8 ?ALAMEDA9 ?ALAMEDA10 ?ALAMEDA11 ?ALAMEDA12 ?ALAMEDA13 ?ALAMEDA14 ?ALAMEDA15) 108 | local STAKE_WTHDR=($NODE_WITHDRAW_AUTHORITY "4ZJhPQAgUseCsWhKvJLTmmRRUV74fdoTpQLNfKoekbPY" "mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN" "EhYXq3ANp5nAerUpbSgd7VK2RRcxK1zNuSQ755G5Mtxx" "9eG63CdHjsfhHmobHgLtESGC8GabbmRcaSpHAZrtmhco" "4bZ6o3eUUNXhKuqjdCnCoPAoLgWiuLYixKaxoa8PpiKk" "AzZRvyyMHBm8EHEksWxq4ozFL7JxLMydCDMGhqM6BVck" "HbJTxftxnXgpePCshA8FubsRj9MW4kfPscfuUfn44fnt" "C4NeuptywfXuyWB9A7H7g5jHVDE8L6Nj2hS53tA71KPn" "6WecYymEARvjG5ZyqkrVQ6YkhPfujNzWpSPwNKXHCbV2" "W1ZQRwUfSkDKy2oefRBUWph82Vr2zg9txWMA8RQazN5" "BbyX1GwUNsfbcoWwnkZDo8sqGmwNDzs2765RpjyQ1pQb" "6iQKfEyhr3bZMotVkW6beNZz5CPAkiwvgV2CTje9pVSS" "AAbVVaokj2VSZCmSU5Uzmxi6mxrG1n6StW9mnaWwN6cv" "HXdYQ5gixrY2H6Y9gqsD8kPM2JQKSaRiohDQtLbZkRWE" "e6keeZrGmHMiQaFM3TAYvFz8HE3qtTFUSHsyqq5FEw7" "DYG1ooTxkLS5iHDkte2XK4QBrpHziDR6EEZg5VsqNpVo" "EcH12jxhrbhF6qHqRzWpZ8rZU3TjG3sX6F67zP61oDJG" "HKd8LdhjUyhp2z4kYgpJxc4pzKCCKR4yC14EFSLNENtw" "8g3YB8KxpWEAAvcjom5vSqxJAZczZBgB4pEgsssts86K" "2YcwVbKx9L25Jpaj2vfWSXD5UKugZumWjzEe6suBUJi2" "DU5XJS2Cm8ftMmi5eZZJg8nkgx1hnZ3nT5sPU3GzV1fo" "7VMTVroogF6GhVunnUWF9hX8JiXqPHiZoG3VKAe64Ckt" "GunPZHAJc5DH8qARPz8x6UXAsoR3NDadFYs3bxtMZsvg" "7hbKGnBZEFF3Bwd9HFetDkLDHXycjvCATFUnj1nEzV85" "7dPqBYywCgLmjuHmexrEJLTCuoFpEUEf31Mjkjhz15wv" "5LJ93G4SQh9GiewTQJNAu6X9sQ1VVyrpCAgbQsRSgn22" "21uFTR9S5LptdR2tBxVeG1KAsKXB7tESqQVT8KRU7Vnj" "F5U6ac2vLzv3pYsxPVPYhhvxZY7u2WJMQEk81E3keMhX") 109 | 110 | for j in ${!STAKE_WTHDR[@]}; do 111 | if [[ "${KEY_TO_CHECK}" == "${STAKE_WTHDR[$j]}" ]]; then 112 | RETURN_INFO+=${STAKE_NAMES[$j]} 113 | fi 114 | done 115 | 116 | if [[ "$RETURN_INFO" == "" ]]; then 117 | RETURN_INFO="\t" 118 | fi 119 | 120 | echo $RETURN_INFO 121 | } 122 | 123 | 124 | 125 | # start of see schedule block 126 | # modified from https://github.com/Vahhhh/solana/blob/main/see-schedule.sh - BIG THANKS!!! 127 | 128 | #from https://stackoverflow.com/a/58617630OD 129 | function durationToSeconds () { 130 | set -f 131 | normalize () { echo $1 | tr '[:upper:]' '[:lower:]' | tr -d "\"\\\'" | sed 's/years\{0,1\}/y/g; s/months\{0,1\}/m/g; s/days\{0,1\}/d/g; s/hours\{0,1\}/h/g; s/minutes\{0,1\}/m/g; s/min/m/g; s/seconds\{0,1\}/s/g; s/sec/s/g; s/ //g;'; } 132 | local value=$(normalize "$1") 133 | local fallback=$(normalize "$2") 134 | 135 | echo $value | grep -v '^[-+*/0-9ydhms]\{0,30\}$' > /dev/null 2>&1 136 | if [ $? -eq 0 ] 137 | then 138 | >&2 echo Invalid duration pattern \"$value\" 139 | else 140 | if [ "$value" = "" ]; then 141 | [ "$fallback" != "" ] && durationToSeconds "$fallback" 142 | else 143 | sedtmpl () { echo "s/\([0-9]\+\)$1/(0\1 * $2)/g;"; } 144 | local template="$(sedtmpl '\( \|$\)' 1) $(sedtmpl y '365 * 86400') $(sedtmpl d 86400) $(sedtmpl h 3600) $(sedtmpl m 60) $(sedtmpl s 1) s/) *(/) + (/g;" 145 | echo $value | sed "$template" | bc 146 | fi 147 | fi 148 | set +f 149 | } 150 | 151 | function slotDate () { 152 | local SLOT=${1} 153 | local SLOT_DIFF=`echo "${SLOT}-${CURRENT_SLOT}" | bc` 154 | local DELTA=`echo "(${SLOT_LEN_SEC}*${SLOT_DIFF})/1" | bc` 155 | local SLOT_DATE_SEC=`echo "${NOW_SEC} + ${DELTA}" | bc` 156 | local DATE_TEXT=`date +"%F %T" -d @${SLOT_DATE_SEC}` 157 | echo "${DATE_TEXT}" 158 | } 159 | 160 | function slotColor() { 161 | local SLOT=${1} 162 | local COLOR=` 163 | if (( ${SLOT:-0} <= ${CURRENT_SLOT:-0} )); then 164 | echo "${RED}old< " 165 | else 166 | echo "${GREEN}new> " 167 | fi` 168 | echo -e "${COLOR}" 169 | } 170 | 171 | function see_shedule() { 172 | 173 | local DEFAULT_SOLANA_ADRESS1=`echo $(solana address)` 174 | local DEFAULT_CLUSTER1='-ul' 175 | 176 | local THIS_SOLANA_ADRESS1=${1:-$DEFAULT_SOLANA_ADRESS1} 177 | local SOLANA_CLUSTER1=' '${2:-$DEFAULT_CLUSTER1}' ' 178 | 179 | local NOW=`date +"%F %T"` 180 | local NOW_SEC=`date +%s` 181 | local SCHEDULE=`solana ${SOLANA_CLUSTER1} leader-schedule | grep ${THIS_SOLANA_ADRESS1}` 182 | 183 | local FIRST_SLOT=`echo -e "$EPOCH_INFO" | grep "Epoch Slot Range: " | cut -d '[' -f 2 | cut -d '.' -f 1` 184 | local LAST_SLOT=`echo -e "$EPOCH_INFO" | grep "Epoch Slot Range: " | cut -d '[' -f 2 | cut -d '.' -f 3 | cut -d ')' -f 1` 185 | local CURRENT_SLOT=`echo -e "$EPOCH_INFO" | grep "Slot: " | cut -d ':' -f 2 | cut -d ' ' -f 2` 186 | local EPOCH_LEN_TEXT=`echo -e "$EPOCH_INFO" | grep "Completed Time" | cut -d '/' -f 2 | cut -d '(' -f 1` 187 | local EPOCH_LEN_SEC=$(durationToSeconds "${EPOCH_LEN_TEXT}") 188 | local SLOT_LEN_SEC=`echo "scale=10; ${EPOCH_LEN_SEC}/(${LAST_SLOT}-${FIRST_SLOT})" | bc` 189 | local SLOT_PER_SEC=`echo "scale=10; 1.0/${SLOT_LEN_SEC}" | bc` 190 | local COMPLETED_SLOTS=`echo -e "${SCHEDULE}" | awk -v cs="${CURRENT_SLOT:-0}" '{ if ( ! -z "$1" ) if ($1 <= cs) { print }}' | wc -l` 191 | local REMAINING_SLOTS=`echo -e "${SCHEDULE}" | awk -v cs="${CURRENT_SLOT:-0}" '{ if ( ! -z "$1" ) if ($1 > cs) { print }}' | wc -l` 192 | local TOTAL_SLOTS=`echo -e "${SCHEDULE}" | wc -l` 193 | 194 | echo "${NOW}" 195 | echo "Speed: ${SLOT_PER_SEC} slots per second" 196 | echo " Time: ${SLOT_LEN_SEC} seconds per slot" 197 | echo "My Slots ${COMPLETED_SLOTS}/${TOTAL_SLOTS} (${REMAINING_SLOTS} remaining)" 198 | echo 199 | echo "${EPOCH_INFO}" 200 | echo 201 | echo -e "${CYAN}Start: `slotDate ${FIRST_SLOT}`${NOCOLOR}" 202 | echo "${SCHEDULE}" | sed 's/|/ /' | awk '{print $1}' | while read in; do 203 | COLOR=`slotColor ${in}` 204 | echo -e "${COLOR}$in `slotDate ${in}`${NOCOLOR}"; 205 | done 206 | echo -e "${CYAN}End: `slotDate ${LAST_SLOT}`${NOCOLOR}" 207 | } 208 | 209 | # end of see schedule block 210 | 211 | 212 | 213 | function Optimistic_Slot_Now() { 214 | 215 | echo "null" 216 | exit 1 217 | 218 | 219 | sleep ${1:-3} 220 | 221 | local NOW_S=`date +"%s"` 222 | local TMRW_S=`echo "${NOW_S} + 24*60*60" | bc` 223 | local NOW=`date --date @${NOW_S} +"%FT%T.%3NZ"` 224 | local TMRW=`date --date @${TMRW_S} +"%FT%T.%3NZ"` 225 | 226 | NOW_S=$NOW_S'000' 227 | TMRW_S=$TMRW_S'000' 228 | 229 | local CLUSTER_FOR_API=` 230 | if [[ "${CLUSTER_NAME}" == "(TESTNET)" ]]; then 231 | echo "testnet" 232 | elif [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 233 | echo "mainnet-beta" 234 | else 235 | echo "" 236 | fi` 237 | 238 | local REFERER=`echo "https://metrics.solana.com/d/EcFDgFgVk/validator-last-optimistic-slot?orgId=1&refresh=1m&var-bucket="``echo "${CLUSTER_FOR_API}&var-host_id=${THIS_SOLANA_ADRESS}&viewPanel=5"` 239 | 240 | local ALL_RESULT=`curl -s -g 'https://metrics.solana.com/api/ds/query' \ 241 | -H 'Accept-Language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 242 | -H 'Connection: keep-alive' \ 243 | -H 'Cookie: _ga=GA1.2.1085836855.1617899020' \ 244 | -H 'Origin: https://metrics.solana.com' \ 245 | -H 'Referer: $REFERER' \ 246 | -H 'Sec-Fetch-Dest: empty' \ 247 | -H 'Sec-Fetch-Mode: cors' \ 248 | -H 'Sec-Fetch-Site: same-origin' \ 249 | -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 250 | -H 'accept: application/json, text/plain, */*' \ 251 | -H 'content-type: application/json' \ 252 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 253 | -H 'sec-ch-ua-mobile: ?0' \ 254 | -H 'sec-ch-ua-platform: "Windows"' \ 255 | -H 'x-grafana-org-id: 1' \ 256 | --data-raw '{"queries":[{"datasource":{"uid":"cF6_LMfnz","type":"influxdb"},"query":"from(bucket: \"'${CLUSTER_FOR_API}'\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"optimistic_slot\")\n |> filter(fn: (r) => r[\"_field\"] == \"slot\")\n |> filter(fn: (r) => r[\"host_id\"] ==\"'${THIS_SOLANA_ADRESS}'\")\n |> max()\n","refId":"A","datasourceId":8,"intervalMs":1800000,"maxDataPoints":1066}],"range":{"from":"now-1d","to":"now+1d","raw":{"from":"now-1d","to":"now+1d"}},"from":"now-1d","to":"now+1d"}' \ 257 | --compressed 2> /dev/null` 258 | 259 | local OPTIMISTIC_SLOT_RIGHT_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][0]' 2> /dev/null` 260 | local OPTIMISTIC_SLOT_TIME_RIGHT_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[0][0]' 2> /dev/null` 261 | local COLOR_OPT_SLOT=`echo "${NOCOLOR}"` 262 | 263 | if (( $(bc<<<"scale=0;${OPTIMISTIC_SLOT_TIME_RIGHT_NOW:-0} != 0") )); then 264 | OPTIMISTIC_SLOT_TIME_RIGHT_NOW=${OPTIMISTIC_SLOT_TIME_RIGHT_NOW::${#OPTIMISTIC_SLOT_TIME_RIGHT_NOW}-3} 265 | local OPTIMISTIC_SLOT_DATE=" | "`date --date @${OPTIMISTIC_SLOT_TIME_RIGHT_NOW:-0} +"%F %T" 2>&1`"${SERVER_TIME_ZONE:-}" 266 | else 267 | NOW_S=${NOW_S::${#NOW_S}-3} 268 | local OPTIMISTIC_SLOT_DATE=" | "`date --date @${NOW_S:-0} +"%F %T" 2>&1`"${SERVER_TIME_ZONE:-}" 269 | COLOR_OPT_SLOT=`echo "${YELLOW}"` 270 | fi 271 | 272 | #"Optimistic Slot: " 273 | 274 | echo -e ${OPTIMISTIC_SLOT_RIGHT_NOW:-null} #${OPTIMISTIC_SLOT_DATE:-""} 275 | } 276 | 277 | function Optimistic_Slot_Summary() { 278 | 279 | local GL_COLOR_OPT_SLOT=`echo "${RED}"` 280 | local GL_TEXT_OPT_SLOT=`echo "${RED}Optimistic Slot Outdated! Recheck it after 5 minutes, or check your log for correct metrics sharing!${NOCOLOR}"` 281 | local first_elem=`echo "${OPTIMISTIC_ARR[0]}" | awk '{print $1}'` 282 | 283 | for ix in ${!OPTIMISTIC_ARR[*]} 284 | do 285 | local this_elem=`echo "${OPTIMISTIC_ARR[$ix]}" | awk '{print $1}'` 286 | if [[ "${this_elem}" != "null" ]]; 287 | then 288 | if [[ "${this_elem}" != "${first_elem}" ]]; 289 | then 290 | GL_COLOR_OPT_SLOT=`echo "${GREEN}"` 291 | GL_TEXT_OPT_SLOT="" 292 | fi 293 | fi 294 | done 295 | 296 | 297 | if [[ "${OPTIMISTIC_ARR[0]}" != "null" ]]; 298 | then 299 | if [[ "${OPTIMISTIC_ARR[-1]}" != "null" ]]; 300 | then 301 | echo -e "${CYAN}" 302 | echo -e "Metrics Sending Now ${NOCOLOR}" 303 | echo -e "Optimistic Slot 1: ${GL_COLOR_OPT_SLOT}"`printf "%s\n" "${OPTIMISTIC_ARR[0]}"`"${NOCOLOR}" 304 | echo -e "Optimistic Slot 2: ${GL_COLOR_OPT_SLOT}"`printf "%s\n" "${OPTIMISTIC_ARR[-1]}"`"${NOCOLOR}" 305 | echo -e "${GL_TEXT_OPT_SLOT}" | awk 'length > 5' 306 | fi 307 | fi 308 | 309 | } 310 | 311 | 312 | function Graphana_hardware_info() { 313 | 314 | #Disk Space 315 | 316 | #102 disk 317 | #139 swap 318 | #104 cpu 319 | #108 ram 320 | #118 descriptors 321 | 322 | local GRAPHANA_CODE=${1:-102} #"102" 323 | 324 | THIS_SOLANA_VALIDATOR_INFO=`solana ${SOLANA_CLUSTER} validator-info get | awk '$0 ~ sadddddr {do_print=1} do_print==1 {print} NF==0 {do_print=0}' sadddddr=$THIS_SOLANA_ADRESS` 325 | 326 | NODE_NAME=`echo -e "${THIS_SOLANA_VALIDATOR_INFO}" | grep 'Name: ' | sed 's/Name: //g' | sed 's/^[ \t]*//g' | sed 's/[ \t]*$//g'` 327 | 328 | local NOW_S=`date +"%s"` 329 | local PREV_S=`echo "${NOW_S} + 1*60" | bc` 330 | local NOW=`date --date @${NOW_S} +"%FT%T.%3NZ"` 331 | local PREV=`date --date @${PREV_S} +"%FT%T.%3NZ"` 332 | 333 | NOW_S=$NOW_S'000' 334 | PREV_S=$PREV_S'000' 335 | 336 | local CLUSTER_FOR_API=` 337 | if [[ "${CLUSTER_NAME}" == "(TESTNET)" ]]; then 338 | echo "testnet" 339 | elif [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 340 | echo "mainnet-beta" 341 | else 342 | echo "" 343 | fi` 344 | 345 | #echo "Host: "${GRAFANA_HOST_NAME} 346 | 347 | local REFERER=`echo "https://metrics.stakeconomy.com/d/f2b2HcaGz/solana-community-validator-dashboard?var-pubkey="``echo "${THIS_SOLANA_ADRESS}&orgId=1&refresh=1m&viewPanel=${GRAPHANA_CODE}&from=now-5m&to=now&inspect=${GRAPHANA_CODE}"` 348 | 349 | if [[ ${GRAPHANA_CODE} == "102" ]]; then 350 | local ALL_RESULT=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 351 | -H 'authority: metrics.stakeconomy.com' \ 352 | -H 'accept: application/json, text/plain, */*' \ 353 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 354 | -H 'content-type: application/json' \ 355 | -H 'origin: https://metrics.stakeconomy.com' \ 356 | -H 'referer: '${REFERER}'' \ 357 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 358 | -H 'sec-ch-ua-mobile: ?0' \ 359 | -H 'sec-ch-ua-platform: "Windows"' \ 360 | -H 'sec-fetch-dest: empty' \ 361 | -H 'sec-fetch-mode: cors' \ 362 | -H 'sec-fetch-site: same-origin' \ 363 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 364 | -H 'x-grafana-org-id: 1' \ 365 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"disk_used_percent{host =~ \"'$GRAFANA_HOST_NAME'$\", path=\"/\"}","legendFormat":"__auto","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"71A","utcOffsetSec":0,"interval":"","datasourceId":1,"intervalMs":15000,"maxDataPoints":100}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 366 | --compressed 2> /dev/null` 367 | 368 | elif [[ ${GRAPHANA_CODE} == "139" ]]; then 369 | local ALL_RESULT=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 370 | -H 'authority: metrics.stakeconomy.com' \ 371 | -H 'accept: application/json, text/plain, */*' \ 372 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 373 | -H 'content-type: application/json' \ 374 | -H 'origin: https://metrics.stakeconomy.com' \ 375 | -H 'referer: '${REFERER}'' \ 376 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not=A?Brand";v="99"' \ 377 | -H 'sec-ch-ua-mobile: ?0' \ 378 | -H 'sec-ch-ua-platform: "Windows"' \ 379 | -H 'sec-fetch-dest: empty' \ 380 | -H 'sec-fetch-mode: cors' \ 381 | -H 'sec-fetch-site: same-origin' \ 382 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 383 | -H 'x-grafana-org-id: 1' \ 384 | --data-raw '{"queries":[{"alias":"$tag_host: $col","col":"used","datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"dsType":"prometheus","expr":"median(swap_used{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","function":"mean","groupBy":" by (host)","interval":"","legendFormat":"{{host}}: used","measurement":"swap","policy":"default","query":"select mean(used) as used from \"swap\" WHERE host =~ /$server$/ AND $timeFilter GROUP BY time($interval), host ORDER BY asc","rawQuery":true,"refId":"B","resultFormat":"time_series","select":[[{"params":["used"],"type":"mean"}]],"tags":"{host =~ \"$server$\"}","queryType":"timeSeriesQuery","exemplar":false,"requestId":"139B","utcOffsetSec":0,"datasourceId":1,"intervalMs":15000,"maxDataPoints":100},{"alias":"$tag_host: $col","col":"total","datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"dsType":"prometheus","expr":"median(swap_total{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","function":"mean","groupBy":" by (host)","interval":"","legendFormat":"{{host}}: total","measurement":"swap","policy":"default","query":"select mean(total) as total from \"swap\" WHERE host =~ /$server$/ AND $timeFilter GROUP BY time($interval), host ORDER BY asc","rawQuery":true,"refId":"C","resultFormat":"time_series","select":[[{"params":["total"],"type":"mean"}]],"tags":"{host =~ \"$server$\"}","queryType":"timeSeriesQuery","exemplar":false,"requestId":"139C","utcOffsetSec":0,"datasourceId":1,"intervalMs":15000,"maxDataPoints":100}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 385 | --compressed 2> /dev/null` 386 | 387 | elif [[ ${GRAPHANA_CODE} == "73" ]]; then 388 | local ALL_RESULT=`curl 'https://metrics.stakeconomy.com/api/ds/query' \ 389 | -H 'authority: metrics.stakeconomy.com' \ 390 | -H 'accept: application/json, text/plain, */*' \ 391 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 392 | -H 'content-type: application/json' \ 393 | -H 'origin: https://metrics.stakeconomy.com' \ 394 | -H 'referer: '${REFERER}'' \ 395 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not=A?Brand";v="99"' \ 396 | -H 'sec-ch-ua-mobile: ?0' \ 397 | -H 'sec-ch-ua-platform: "Windows"' \ 398 | -H 'sec-fetch-dest: empty' \ 399 | -H 'sec-fetch-mode: cors' \ 400 | -H 'sec-fetch-site: same-origin' \ 401 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 402 | -H 'x-grafana-org-id: 1' \ 403 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"100-cpu_usage_idle{host =~ \"^GwuVgxewTRizBWM622HQeY5qBJ4dcvyQyZ7JnsXnRLRQ$\",cpu = \"cpu-total\"}","legendFormat":"__auto","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"73A","utcOffsetSec":0,"interval":"","datasourceId":1,"intervalMs":20000,"maxDataPoints":100}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 404 | --compressed 2> /dev/null` 405 | 406 | elif [[ ${GRAPHANA_CODE} == "67" ]]; then 407 | local ALL_RESULT=`curl 'https://metrics.stakeconomy.com/api/ds/query' \ 408 | -H 'authority: metrics.stakeconomy.com' \ 409 | -H 'accept: application/json, text/plain, */*' \ 410 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 411 | -H 'content-type: application/json' \ 412 | -H 'origin: https://metrics.stakeconomy.com' \ 413 | -H 'referer: '${REFERER}'' \ 414 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not=A?Brand";v="99"' \ 415 | -H 'sec-ch-ua-mobile: ?0' \ 416 | -H 'sec-ch-ua-platform: "Windows"' \ 417 | -H 'sec-fetch-dest: empty' \ 418 | -H 'sec-fetch-mode: cors' \ 419 | -H 'sec-fetch-site: same-origin' \ 420 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 421 | -H 'x-grafana-org-id: 1' \ 422 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"cpu_usage_iowait{host =~ \"^'$GRAFANA_HOST_NAME'$\",cpu = \"cpu-total\"}","legendFormat":"__auto","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"67A","utcOffsetSec":0,"interval":"","datasourceId":1,"intervalMs":20000,"maxDataPoints":100}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 423 | --compressed 2> /dev/null` 424 | 425 | elif [[ ${GRAPHANA_CODE} == "108" ]]; then 426 | local ALL_RESULT=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 427 | -H 'authority: metrics.stakeconomy.com' \ 428 | -H 'accept: application/json, text/plain, */*' \ 429 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 430 | -H 'content-type: application/json' \ 431 | -H 'origin: https://metrics.stakeconomy.com' \ 432 | -H 'referer: '${REFERER}'' \ 433 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 434 | -H 'sec-ch-ua-mobile: ?0' \ 435 | -H 'sec-ch-ua-platform: "Windows"' \ 436 | -H 'sec-fetch-dest: empty' \ 437 | -H 'sec-fetch-mode: cors' \ 438 | -H 'sec-fetch-site: same-origin' \ 439 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 440 | -H 'x-grafana-org-id: 1' \ 441 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"median(mem_total{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","interval":"1m","legendFormat":"{{host}}: total","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"108A","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057},{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"median(mem_used{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","hide":false,"interval":"1m","legendFormat":"{{host}}: used","range":true,"refId":"B","queryType":"timeSeriesQuery","exemplar":false,"requestId":"108B","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057},{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"median(mem_cached{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","hide":false,"interval":"1m","legendFormat":"{{host}}: cached","range":true,"refId":"C","queryType":"timeSeriesQuery","exemplar":false,"requestId":"108C","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057},{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"median(mem_free{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","hide":false,"interval":"1m","legendFormat":"{{host}}: free","range":true,"refId":"D","queryType":"timeSeriesQuery","exemplar":false,"requestId":"108D","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057},{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"median(mem_buffered{host =~ \"'$GRAFANA_HOST_NAME'$\"}) by (host)","hide":false,"interval":"1m","legendFormat":"{{host}}: buffered","range":true,"refId":"E","queryType":"timeSeriesQuery","exemplar":false,"requestId":"108E","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057}],"range":{"from":"now-2m","to":"now","raw":{"from":"now-2m","to":"now"}},"from":"now-2m","to":"now"}' \ 442 | --compressed 2> /dev/null` 443 | 444 | 445 | 446 | elif [[ ${GRAPHANA_CODE} == "118" ]]; then 447 | local ALL_RESULT=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 448 | -H 'authority: metrics.stakeconomy.com' \ 449 | -H 'accept: application/json, text/plain, */*' \ 450 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 451 | -H 'content-type: application/json' \ 452 | -H 'origin: https://metrics.stakeconomy.com' \ 453 | -H 'referer: '${REFERER}'' \ 454 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 455 | -H 'sec-ch-ua-mobile: ?0' \ 456 | -H 'sec-ch-ua-platform: "Windows"' \ 457 | -H 'sec-fetch-dest: empty' \ 458 | -H 'sec-fetch-mode: cors' \ 459 | -H 'sec-fetch-site: same-origin' \ 460 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 461 | -H 'x-grafana-org-id: 1' \ 462 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"nodemonitor_openFiles{host=\"'$GRAFANA_HOST_NAME'\"}[1m]","legendFormat":"__auto","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"118A","utcOffsetSec":0,"interval":"","datasourceId":1,"intervalMs":60000,"maxDataPoints":1057}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 463 | --compressed 2> /dev/null` 464 | 465 | 466 | 467 | elif [[ ${GRAPHANA_CODE} == "111" ]]; then 468 | local ALL_RESULT=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 469 | -H 'authority: metrics.stakeconomy.com' \ 470 | -H 'accept: application/json, text/plain, */*' \ 471 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 472 | -H 'content-type: application/json' \ 473 | -H 'origin: https://metrics.stakeconomy.com' \ 474 | -H 'referer: '${REFERER}'' \ 475 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 476 | -H 'sec-ch-ua-mobile: ?0' \ 477 | -H 'sec-ch-ua-platform: "Windows"' \ 478 | -H 'sec-fetch-dest: empty' \ 479 | -H 'sec-fetch-mode: cors' \ 480 | -H 'sec-fetch-site: same-origin' \ 481 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 482 | -H 'x-grafana-org-id: 1' \ 483 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","exemplar":false,"expr":"abs(ideriv(median(net_bytes_recv{host =~ \"'$GRAFANA_HOST_NAME'\"}) by (host,interface)))*8","interval":"1m","legendFormat":"{{host}}: {{interface}}: in","range":true,"refId":"A","queryType":"timeSeriesQuery","requestId":"111A","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057},{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"abs(ideriv(median(net_bytes_sent{host =~ \"'$GRAFANA_HOST_NAME'\"}) by (host,interface)))*8","hide":false,"interval":"1m","legendFormat":"{{host}}: {{interface}}: out","range":true,"refId":"B","queryType":"timeSeriesQuery","exemplar":false,"requestId":"111B","utcOffsetSec":0,"datasourceId":1,"intervalMs":60000,"maxDataPoints":1057}],"range":{"from":"now-5m","to":"now","raw":{"from":"now-5m","to":"now"}},"from":"now-5m","to":"now"}' \ 484 | --compressed 2> /dev/null` 485 | 486 | else 487 | local ALL_RESULT="" 488 | fi 489 | 490 | 491 | 492 | local GRAPHANA_DATA_1_NAME=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].schema.name' 2> /dev/null` 493 | local GRAPHANA_DATA_1_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][0]' | awk '{print ($1/(1024*1024*1024))}' 2> /dev/null | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 494 | local GRAPHANA_DATA_1_NOW_TIME_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[0][0]' 2> /dev/null` 495 | 496 | local GRAPHANA_DATA_2_NAME=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.B.frames[0].schema.name' 2> /dev/null` 497 | local GRAPHANA_DATA_2_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.B.frames[0].data.values[1][0]' | awk '{print ($1/(1024*1024*1024))}' 2> /dev/null | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 498 | local GRAPHANA_DATA_2_NOW_TIME_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.B.frames[0].data.values[0][0]' 2> /dev/null` 499 | 500 | 501 | 502 | 503 | 504 | if [[ ${GRAPHANA_CODE} == "102" ]]; then 505 | 506 | #if [[ ${GRAPHANA_DATA_1_NOW:-0} == "0" ]]; then 507 | #GRAPHANA_DATA_1_NOW="1" 508 | #fi 509 | 510 | GRAPHANA_DISK_DATA=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][-1]' 2> /dev/null | awk '{printf("%.2f\n",$1)}' 2> /dev/null | awk '{ if (($1 <= 80.00)) print gr$1"%"nc; else if (($1 <= 87.00)) print ye$1"%"nc; else print rd$1"%"nc; fi }' gr=$GREEN ye=$YELLOW rd=$RED nc=$NOCOLOR` 511 | 512 | echo -e "Disk: "${GRAPHANA_DISK_DATA} 513 | 514 | elif [[ ${GRAPHANA_CODE} == "139" ]]; then 515 | 516 | GRAPHANA_SWAP_DATA_TOTAL=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.C.frames[0].data.values[1][0]' | awk '{print ($1/(1024*1024*1024))}' 2> /dev/null | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 517 | GRAPHANA_SWAP_DATA_USED=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.B.frames[0].data.values[1][0]' | awk '{print ($1/(1024*1024*1024))}' 2> /dev/null | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 518 | 519 | if (( $(bc<<<"scale=2;${GRAPHANA_SWAP_DATA_TOTAL:-0} <= 0.5") )); 520 | then 521 | GRAPHANA_SWAP_DATA_TOTAL="1" 522 | GRAPHANA_SWAP_DATA_TOTAL_SHOW="0" 523 | else 524 | GRAPHANA_SWAP_DATA_TOTAL_SHOW=$GRAPHANA_SWAP_DATA_TOTAL 525 | fi 526 | 527 | GRAPHANA_SWAP_COLOR=` 528 | if (( $(bc<<<"scale=2;100*${GRAPHANA_SWAP_DATA_USED:-0}/${GRAPHANA_SWAP_DATA_TOTAL:-1} >= 95") )); then 529 | echo "${YELLOW}" 530 | elif (( $(bc<<<"scale=2;100*${GRAPHANA_SWAP_DATA_USED:-0}/${GRAPHANA_SWAP_DATA_TOTAL:-1} >= 85") )); then 531 | echo "${RED}" 532 | else 533 | echo "${GREEN}" 534 | fi` 535 | 536 | echo -e "Swap: "${GRAPHANA_SWAP_COLOR}${GRAPHANA_SWAP_DATA_USED:-N/A}"Gb/"${GRAPHANA_SWAP_DATA_TOTAL_SHOW:-N/A}"Gb"${NOCOLOR} 537 | 538 | elif [[ ${GRAPHANA_CODE} == "73" ]]; then 539 | 540 | GRAPHANA_CPU_DATA=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][-1]' 2> /dev/null | awk '{printf("%.2f\n",$1)}' 2> /dev/null | awk '{ if (($1 <= 80.00)) print gr$1"%"nc; else if (($1 <= 90.00)) print ye$1"%"nc; else print rd$1"%"nc; fi }' gr=$GREEN ye=$YELLOW rd=$RED nc=$NOCOLOR` 541 | 542 | echo -e "CPU: "${GRAPHANA_CPU_DATA} 543 | 544 | elif [[ ${GRAPHANA_CODE} == "67" ]]; then 545 | 546 | GRAPHANA_IOWAIT=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][-1]' 2> /dev/null | awk '{printf("%.2f\n",$1)}' 2> /dev/null | awk '{ if (($1 <= 8.00)) print gr$1"%"nc; else if (($1 <= 20.00)) print ye$1"%"nc; else print rd$1"%"nc; fi }' gr=$GREEN ye=$YELLOW rd=$RED nc=$NOCOLOR` 547 | 548 | echo -e "IOWait: "${GRAPHANA_IOWAIT} 549 | 550 | elif [[ ${GRAPHANA_CODE} == "108" ]]; then 551 | 552 | GRAPHANA_RAM_COLOR=` 553 | if (( $(bc<<<"scale=2;100*${GRAPHANA_DATA_2_NOW:-0}/${GRAPHANA_DATA_1_NOW:-1} >= 95") )); then 554 | echo "${YELLOW}" 555 | elif (( $(bc<<<"scale=2;100*${GRAPHANA_DATA_2_NOW:-0}/${GRAPHANA_DATA_1_NOW:-1} >= 85") )); then 556 | echo "${RED}" 557 | else 558 | echo "${GREEN}" 559 | fi` 560 | 561 | echo -e "RAM: "${GRAPHANA_RAM_COLOR}${GRAPHANA_DATA_2_NOW:-N/A}"Gb/"${GRAPHANA_DATA_1_NOW:-N/A}"Gb"${NOCOLOR} 562 | 563 | elif [[ ${GRAPHANA_CODE} == "118" ]]; then 564 | 565 | GRAPHANA_DATA_1_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][-1]' | bc 2> /dev/null` 566 | 567 | GRAPHANA_OFD_COLOR=` 568 | if (( $(bc<<<"scale=2;${GRAPHANA_DATA_1_NOW:-1000001} >= 900000") )); then 569 | echo "${RED}" 570 | elif (( $(bc<<<"scale=2;${GRAPHANA_DATA_1_NOW:-1000001} >= 800000") )); then 571 | echo "${YELLOW}" 572 | else 573 | echo "${GREEN}" 574 | fi` 575 | 576 | echo -e "Descriptors: "${GRAPHANA_OFD_COLOR}${GRAPHANA_DATA_1_NOW:-N/A}${NOCOLOR} 577 | 578 | 579 | elif [[ ${GRAPHANA_CODE} == "111" ]]; then 580 | 581 | GRAPHANA_DATA_1_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].data.values[1][0]' | bc | awk '{print ($1/1024/1024)}' | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 582 | 583 | GRAPHANA_DATA_2_NOW=`echo $ALL_RESULT | jq -r @json 2> /dev/null | jq -r '.results.B.frames[0].data.values[1][0]' | bc | awk '{print ($1/1024/1024)}' | awk '{printf("%.1f\n",$1)}' 2> /dev/null` 584 | 585 | GRAPHANA_N1_COLOR=` 586 | if (( $(bc<<<"scale=2;${GRAPHANA_DATA_1_NOW:-0} >= 500") )); then 587 | echo "${YELLOW}" 588 | elif (( $(bc<<<"scale=2;${GRAPHANA_DATA_1_NOW:-0} >= 800") )); then 589 | echo "${RED}" 590 | else 591 | echo "${GREEN}" 592 | fi` 593 | 594 | GRAPHANA_N2_COLOR=` 595 | if (( $(bc<<<"scale=2;${GRAPHANA_DATA_2_NOW:-0} >= 500") )); then 596 | echo "${YELLOW}" 597 | elif (( $(bc<<<"scale=2;${GRAPHANA_DATA_2_NOW:-0} >= 900") )); then 598 | echo "${RED}" 599 | else 600 | echo "${GREEN}" 601 | fi` 602 | 603 | echo -e "Network: IN "${GRAPHANA_N1_COLOR}${GRAPHANA_DATA_1_NOW:-N/A}"Mb/s"${NOCOLOR}" OUT "${GRAPHANA_N2_COLOR}${GRAPHANA_DATA_2_NOW:-N/A}"Mb/s"${NOCOLOR} 604 | 605 | 606 | 607 | else 608 | echo -e ""${GRAPHANA_DATA_1_NAME}" "${GRAPHANA_DATA_1_NOW:-N/A}" / "${GRAPHANA_DATA_2_NAME}" "${GRAPHANA_DATA_2_NOW:-N/A}" | "${NOCOLOR} 609 | fi 610 | } 611 | 612 | 613 | 614 | 615 | # default info 616 | 617 | DEFAULT_SOLANA_ADRESS=`echo $(solana address)` 618 | DEFAULT_CLUSTER='-ul' 619 | 620 | THIS_SOLANA_ADRESS=${1:-$DEFAULT_SOLANA_ADRESS} 621 | SOLANA_CLUSTER=' '${2:-$DEFAULT_CLUSTER}' ' 622 | FLAG_ONLY_IMPORTANT=${3:-"false"} 623 | STAKE_SHOW_TYPE=${4:-"false"} 624 | 625 | #SOLANA_CLUSTER=`getRandomRPC ${SOLANA_CLUSTER}` 626 | 627 | THIS_CONFIG_RPC=`solana config get | grep "RPC URL:"` 628 | 629 | if [[ "${SOLANA_CLUSTER}" == " -ul " ]]; then 630 | if [[ $THIS_CONFIG_RPC == *"testnet"* ]]; then 631 | SOLANA_CLUSTER=" -ut " 632 | elif [[ $THIS_CONFIG_RPC == *"mainnet"* ]]; then 633 | SOLANA_CLUSTER=" -um " 634 | fi 635 | fi 636 | 637 | CLUSTER_NAME=` 638 | if [[ "${SOLANA_CLUSTER}" == " -ut " ]]; then 639 | echo "(TESTNET)" 640 | elif [[ "${SOLANA_CLUSTER}" == " -um " ]]; then 641 | echo "(Mainnet)" 642 | elif [[ "${SOLANA_CLUSTER}" == " -ul " ]]; then 643 | echo "(Taken from Local)" 644 | else 645 | echo "" 646 | fi` 647 | 648 | OPTIMISTIC_ARR[0]="`Optimistic_Slot_Now`" 649 | 650 | EPOCH_INFO=`solana ${SOLANA_CLUSTER} epoch-info 2> /dev/null` 651 | 652 | LAST_EPOCH=`echo -e "${EPOCH_INFO}" | grep 'Epoch: ' | sed 's/Epoch: //g'` 653 | 654 | #SOLANA_VALIDATORS=`solana ${SOLANA_CLUSTER} validators` 655 | THIS_VALIDATOR_JSON=`solana ${SOLANA_CLUSTER} validators --output json-compact | jq --arg ID ${THIS_SOLANA_ADRESS} '.validators[] | select(.identityPubkey==$ID)'` 656 | 657 | YOUR_VOTE_ACCOUNT=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.voteAccountPubkey'` 658 | #YOUR_VOTE_ACCOUNT=`echo -e "${SOLANA_VALIDATORS}" | grep ${THIS_SOLANA_ADRESS} | sed 's/ */ /g' | cut -d ' ' -f 3` 659 | 660 | SEE_SHEDULE_VAR=`see_shedule ${THIS_SOLANA_ADRESS} ${SOLANA_CLUSTER}` 661 | 662 | 663 | 664 | 665 | 666 | if [[ ${YOUR_VOTE_ACCOUNT} == "" ]]; then 667 | echo -e "${RED}${THIS_SOLANA_ADRESS} - can't find node account!" 668 | echo -e " for it does not exist or --no-voting key is active or RPC error occured!${NOCOLOR}" 669 | exit 1 670 | fi 671 | 672 | 673 | iterator=0 674 | DONE_STOP=0 675 | while [ $DONE_STOP == 0 ] 676 | do 677 | KYC_API_VERCEL_2=`curl -s 'https://api.solana.org/api/validators/details?pk='${THIS_SOLANA_ADRESS}'&epoch='${LAST_EPOCH}` 678 | if [[ "$(echo "${KYC_API_VERCEL_2}" | jq -r '.message')" != "null" ]]; then 679 | LAST_EPOCH=$(echo "$LAST_EPOCH-1" | bc) 680 | else 681 | DONE_STOP=1 682 | fi 683 | iterator=$iterator+1 684 | #echo $iterator 685 | if (( $(bc<<<"scale=0;${iterator:-0} >= 10") )); then 686 | DONE_STOP=1 687 | fi 688 | #echo $LAST_EPOCH 689 | #echo $KYC_API_VERCEL_2 690 | done 691 | 692 | KYC_API_VERCEL_3=`curl -s 'https://api.solana.org/api/validators/'${THIS_SOLANA_ADRESS}` 693 | 694 | 695 | 696 | REFERER000=`echo "https://metrics.stakeconomy.com/d/f2b2HcaGz/solana-community-validator-dashboard?var-pubkey="``echo "${THIS_SOLANA_ADRESS}&orgId=1&refresh=1m"` 697 | 698 | GRAFANA_HOST_NAME=`curl -g -s 'https://metrics.stakeconomy.com/api/ds/query' \ 699 | -H 'authority: metrics.stakeconomy.com' \ 700 | -H 'accept: application/json, text/plain, */*' \ 701 | -H 'accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7' \ 702 | -H 'content-type: application/json' \ 703 | -H 'origin: https://metrics.stakeconomy.com' \ 704 | -H 'referer: '${REFERER000}'' \ 705 | -H 'sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"' \ 706 | -H 'sec-ch-ua-mobile: ?0' \ 707 | -H 'sec-ch-ua-platform: "Windows"' \ 708 | -H 'sec-fetch-dest: empty' \ 709 | -H 'sec-fetch-mode: cors' \ 710 | -H 'sec-fetch-site: same-origin' \ 711 | -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' \ 712 | -H 'x-grafana-org-id: 1' \ 713 | --data-raw '{"queries":[{"datasource":{"uid":"PBFA97CFB590B2093","type":"prometheus"},"editorMode":"code","expr":"nodemonitor_pctEpochElapsed{pubkey=\"'$THIS_SOLANA_ADRESS'\"}[1m]","legendFormat":"__auto","range":true,"refId":"A","queryType":"timeSeriesQuery","exemplar":false,"requestId":"97A","utcOffsetSec":0,"interval":"","datasourceId":1,"intervalMs":600000,"maxDataPoints":81}],"range":{"from":"now-2m","to":"now","raw":{"from":"now-2m","to":"now"}},"from":"now-2m","to":"now"}' \ 714 | --compressed | jq -r @json 2> /dev/null | jq -r '.results.A.frames[0].schema.fields[1].labels.host' | sed 's/ / /g' 2> /dev/null` 715 | 716 | 717 | function Time_Now_1 () { 718 | 719 | TIME_NOW=`echo -e "${SEE_SHEDULE_VAR}" | sed -n -e 1p` 720 | 721 | #echo -ne '\n' 722 | echo -e "${GREEN}" 723 | echo -e "Time now: ${TIME_NOW:-''}${SERVER_TIME_ZONE:-''}${NOCOLOR}" | awk 'length > 30' 724 | } 725 | 726 | function Epoch_Progress_2 () { 727 | 728 | END_OF_EPOCH=`echo -e "${SEE_SHEDULE_VAR}" | tail -n1 | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | sed 's/End: /End of epoch:/g' | tr -s ' '` 729 | 730 | #echo -ne '\n' 731 | echo -e "${CYAN}" 732 | echo -e "Epoch Progress ${CLUSTER_NAME}${NOCOLOR}" 733 | 734 | echo "$EPOCH_INFO" | grep 'Epoch: ' 735 | echo "$EPOCH_INFO" | grep 'Epoch Completed Percent' 736 | echo "$EPOCH_INFO" | grep 'Epoch Completed Time' 737 | echo -e "${NOCOLOR}$END_OF_EPOCH ${NOCOLOR}" 738 | } 739 | 740 | function This_Node_3 () { 741 | 742 | SOLANA_VALIDATORS=`solana ${SOLANA_CLUSTER} validators` 743 | 744 | THIS_SOLANA_VALIDATOR_INFO=`solana ${SOLANA_CLUSTER} validator-info get | awk '$0 ~ sadddddr {do_print=1} do_print==1 {print} NF==0 {do_print=0}' sadddddr=$THIS_SOLANA_ADRESS` 745 | #THIS_SOLANA_VALIDATOR_INFO_JS=`solana -ut validator-info get --output json-compact | jq --arg ID $(solana address) '.[] | select(.identityPubkey==$ID)'` 746 | 747 | NODE_NAME=`echo -e "${THIS_SOLANA_VALIDATOR_INFO}" | grep 'Name: ' | sed 's/Name//g' | tr -s ' '` 748 | #NODE_NAME=`echo -e "${THIS_SOLANA_VALIDATOR_INFO_JS}" | jq -r '.info.name'` 749 | 750 | SOLANA_VERSION=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.version'` 751 | #SOLANA_VERSION=`solana ${SOLANA_CLUSTER} validators --output json-compact | jq --arg ID ${THIS_SOLANA_ADRESS} '.validators[] | select(.identityPubkey==$ID) | .version' | sed 's/\"//g'` 752 | 753 | MAJOR_CLUSTER_VERSION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k6 -nr | sed 1q | awk '{print $1}'` 754 | MAJOR_CLUSTER_VERSION_PERCENT=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k6 -nr | sed 1q | awk '{print $6}'` 755 | 756 | MAJOR_CLUSTER_VERSION_BY_POPULATION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k3 -nr | sed 1q | awk '{print $1}'` 757 | MAJOR_CLUSTER_VERSION_POPULATION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k3 -nr | sed 1q | awk '{print $3}'` 758 | 759 | NODE_COMMISSION=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.commission'` 760 | 761 | NODE_WITHDRAW_AUTHORITY=`solana ${SOLANA_CLUSTER} vote-account ${YOUR_VOTE_ACCOUNT} | grep 'Withdraw' | awk '{print $NF}'` 762 | 763 | IDACC_BALANCE=`solana ${SOLANA_CLUSTER} balance ${THIS_SOLANA_ADRESS} | sed 's/ SOL//g' ` 764 | VOTEACC_BALANCE=`solana ${SOLANA_CLUSTER} balance ${YOUR_VOTE_ACCOUNT}` 765 | WITHDR_BALANCE=`solana ${SOLANA_CLUSTER} balance ${NODE_WITHDRAW_AUTHORITY}` 766 | 767 | IS_DELINKED=`echo -e "${SOLANA_VALIDATORS}" | grep ⚠️ | if (grep ${THIS_SOLANA_ADRESS} -c)>0; then echo -e "WARNING: ${RED}THIS NODE IS DELINKED\n\rconsider to check catchup, network connection and/or messages from your datacenter${NOCOLOR}"; else >/dev/null; fi` 768 | 769 | CONCENTRATION=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.data_center_stake_percent' | awk '{printf("%.2f\n",$1)}'` 770 | 771 | MAX_CONCENTRATION=` 772 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 773 | echo "10.00" 774 | else 775 | echo "25.00" 776 | fi` 777 | DC_COLOR=` 778 | if (( $(bc<<<"scale=2;${CONCENTRATION} < ${MAX_CONCENTRATION}") )); then 779 | echo "${GREEN}" 780 | else 781 | echo "${YELLOW}" 782 | fi` 783 | 784 | CURRENT_DC=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.epoch_data_center.asn'`'-'`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.epoch_data_center.location'`' | '`echo "${DC_COLOR}${CONCENTRATION}"`'%'`echo "${NOCOLOR}"`' concentration' 785 | 786 | #echo -ne '\n' 787 | echo -e "${CYAN}" 788 | echo -e "This Node${NODE_NAME} ${NOCOLOR}" 789 | 790 | echo -e "${IS_DELINKED}" | awk 'length > 5' 791 | 792 | #echo -e "Identity: ${THIS_SOLANA_ADRESS}" 793 | 794 | if (( $(bc<<<"scale=0;${IDACC_BALANCE:-0} >= 1.8") )); then 795 | echo -e "Identity: ${THIS_SOLANA_ADRESS} / ${GREEN}${IDACC_BALANCE:-0} SOL${NOCOLOR}" 796 | else 797 | echo -e "Identity: ${THIS_SOLANA_ADRESS} / ${RED}${IDACC_BALANCE:-0} SOL${NOCOLOR}" 798 | fi 799 | 800 | echo -e "VoteKey: ${YOUR_VOTE_ACCOUNT} / ${VOTEACC_BALANCE}" 801 | #echo -e "VoteKey Balance: ${VOTEACC_BALANCE}" 802 | echo -e "Withdrawer: ${NODE_WITHDRAW_AUTHORITY} / ${WITHDR_BALANCE}" 803 | #echo -e "Withrawer Balance: ${WITHDR_BALANCE}" 804 | 805 | if (( $(bc<<<"scale=0;${NODE_COMMISSION:-100} <= 10.0") )); then 806 | echo -e "Node commission: " | tr -d '\r\n' && echo -e "${GREEN}${NODE_COMMISSION}%${NOCOLOR}" 807 | else 808 | if [[ "${CLUSTER_NAME}" != "(Mainnet)" ]]; then 809 | echo -e "Node commission: " | tr -d '\r\n' && echo -e "${GREEN}${NODE_COMMISSION}%${NOCOLOR}" 810 | else 811 | echo -e "Node commission: " | tr -d '\r\n' && echo -e "${RED}${NODE_COMMISSION}%${NOCOLOR}" 812 | fi 813 | fi 814 | 815 | if [[ "${SOLANA_VERSION}" == "${MAJOR_CLUSTER_VERSION_BY_POPULATION}" ]]; then 816 | echo -e "Solana version: " | tr -d '\r\n' && echo -e "${GREEN}${SOLANA_VERSION}${NOCOLOR} (Majority: ${MAJOR_CLUSTER_VERSION_PERCENT} stake on ${MAJOR_CLUSTER_VERSION} / ${MAJOR_CLUSTER_VERSION_POPULATION} nodes on ${MAJOR_CLUSTER_VERSION_BY_POPULATION}${NOCOLOR})" 817 | else 818 | echo -e "Solana version: " | tr -d '\r\n' && echo -e "${RED}${SOLANA_VERSION}${NOCOLOR} | Recheck discord for right version (Majority: ${MAJOR_CLUSTER_VERSION_PERCENT} stake on ${MAJOR_CLUSTER_VERSION} / ${MAJOR_CLUSTER_VERSION_POPULATION} nodes on ${MAJOR_CLUSTER_VERSION_BY_POPULATION})" 819 | fi 820 | 821 | echo -e "Datacenter: ${CURRENT_DC}" 822 | } 823 | 824 | function Node_Stake_4 () { 825 | 826 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 827 | SOLANA_CLUSTER_local=' -um ' 828 | elif [[ "${CLUSTER_NAME}" == "(TESTNET)" ]]; then 829 | SOLANA_CLUSTER_local=' -ut ' 830 | else 831 | SOLANA_CLUSTER_local=' -ul ' 832 | fi 833 | 834 | SOLANA_STAKES_THIS_NODE=`solana $SOLANA_CLUSTER_local stakes ${YOUR_VOTE_ACCOUNT}` 835 | 836 | TOTAL_ACTIVE_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | awk '{n += $1}; END{print 0+n+0}' | bc` 837 | TOTAL_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | grep '' -c` 838 | 839 | ACTIVATING_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep 'Activating Stake: ' | sed 's/Activating Stake: //g' | sed 's/ SOL//g' | awk '{n += $1}; END{print 0+n+0}' | bc` 840 | ACTIVATING_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep 'Activating Stake: ' | sed 's/Activating Stake: //g' | sed 's/ SOL//g' | grep '' -c` 841 | 842 | DEACTIVATING_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B1 -i 'deactivates' | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | awk '{n += $1}; END{print 0+n+0}' | bc` 843 | DEACTIVATING_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B1 -i 'deactivates' | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | grep '' -c` 844 | 845 | NO_MOVING_STAKE=`echo "${TOTAL_ACTIVE_STAKE:-0} ${DEACTIVATING_STAKE:-0}" | awk '{print $1 - $2}' | bc` 846 | 847 | TOTAL_ACTIVE_STAKE_COUNT=`echo "${TOTAL_STAKE_COUNT:-0} ${ACTIVATING_STAKE_COUNT:-0}" | awk '{print $1 - $2}'` 848 | 849 | BOT_ACTIVE_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "mvines|mpa4abUk" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | awk '{n += $1}; END{print 0+n+0}' | bc` 850 | BOT_ACTIVE_STAKE_CLR=`echo -e "${BOT_ACTIVE_STAKE:-0}" | awk '{if(NR=0) print 0; else print'} | awk '{ if ($1 >= 0.9) print gr$1" SOL"nc; else print rd$1" SOL"nc; fi }' gr=$GREEN rd=$RED nc=$NOCOLOR` 851 | BOT_ACTIVE_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "mvines|mpa4abUk" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | grep '' -c` 852 | 853 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 854 | MINIMUM_SECRET_STAKE=`echo "0.5" | bc` 855 | else 856 | MINIMUM_SECRET_STAKE=0 857 | fi 858 | SECRET_ACTIVE_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "EhYXq3ANp5nAerUpbSgd7VK2RRcxK1zNuSQ755G5Mtxx" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | sed 's/ //g' | awk '{n += $1}; END{print 0+n+0}' | bc` 859 | SECRET_ACTIVE_STAKE_CLR=`echo -e "${SECRET_ACTIVE_STAKE:-0}" | awk '{if(NR=0) print 0; else print'} | awk '{ if (($1 > 0)) print gr$1" SOL"nc; else print rd$1" SOL"nc; fi }' gr=$GREEN rd=$RED nc=$NOCOLOR` 860 | SECRET_ACTIVE_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "EhYXq3ANp5nAerUpbSgd7VK2RRcxK1zNuSQ755G5Mtxx" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | grep '' -c` 861 | SECRET_ACTIVE_TEXT=`echo -e "| Un-known Fund(${SECRET_ACTIVE_STAKE_COUNT:-0}) ${SECRET_ACTIVE_STAKE_CLR} "` 862 | if [[ "${MINIMUM_SECRET_STAKE:-0}" == "0" ]]; then 863 | SECRET_ACTIVE_TEXT="" 864 | fi 865 | 866 | POOL_ACTIVE_TEXT="| " 867 | POOL_ACTIVE_STAKE_SUM=0 868 | POOL_ACTIVE_STAKE_COUNT_SUM=0 869 | STAKE_POOLS_NAMES=(MARINADE SOCEAN JPOOL EVERSOL BLAZESTAKE LIDO DAOPOOL) 870 | STAKE_POOLS_WTHDR=("9eG63CdHjsfhHmobHgLtESGC8GabbmRcaSpHAZrtmhco" "AzZRvyyMHBm8EHEksWxq4ozFL7JxLMydCDMGhqM6BVck" "HbJTxftxnXgpePCshA8FubsRj9MW4kfPscfuUfn44fnt" "C4NeuptywfXuyWB9A7H7g5jHVDE8L6Nj2hS53tA71KPn" "6WecYymEARvjG5ZyqkrVQ6YkhPfujNzWpSPwNKXHCbV2" "W1ZQRwUfSkDKy2oefRBUWph82Vr2zg9txWMA8RQazN5" "BbyX1GwUNsfbcoWwnkZDo8sqGmwNDzs2765RpjyQ1pQb") 871 | for i in ${!STAKE_POOLS_WTHDR[@]}; do 872 | POOL_ACTIVE_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "${STAKE_POOLS_WTHDR[$i]}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | sed 's/ //g' | awk '{n += $1}; END{print 0+n+0}' | bc` 873 | POOL_ACTIVE_STAKE_CLR=`echo -e "${POOL_ACTIVE_STAKE:-0}" | awk '{ if (($1 > 0)) print gr$1" SOL"nc; else print rd$1" SOL"nc; fi }' gr=$GREEN rd=$RED nc=$NOCOLOR` 874 | POOL_ACTIVE_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 -E "${STAKE_POOLS_WTHDR[$i]}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | grep '' -c` 875 | POOL_ACTIVE_TEXT_ADD=`echo -e "| ${STAKE_POOLS_NAMES[$i]}(${POOL_ACTIVE_STAKE_COUNT:-0}) ${POOL_ACTIVE_STAKE_CLR} "` 876 | if [[ "${POOL_ACTIVE_STAKE:-0}" == "0" ]]; then 877 | POOL_ACTIVE_TEXT_ADD="" 878 | fi 879 | POOL_ACTIVE_TEXT=`echo -e "${POOL_ACTIVE_TEXT:-}${POOL_ACTIVE_TEXT_ADD:-}| "` 880 | POOL_ACTIVE_STAKE_SUM=`echo -e "${POOL_ACTIVE_STAKE_SUM:-0} ${POOL_ACTIVE_STAKE:-0}" | awk '{print $1 + $2}'` 881 | POOL_ACTIVE_STAKE_COUNT_SUM=`echo -e "${POOL_ACTIVE_STAKE_COUNT_SUM:-0} ${POOL_ACTIVE_STAKE_COUNT:-0}" | awk '{print $1 + $2}'` 882 | done 883 | 884 | if [[ `echo -e "$POOL_ACTIVE_TEXT" | sed 's/ //g' | sed 's/|//g' ` == "" ]]; then 885 | POOL_ACTIVE_TEXT="" 886 | fi 887 | 888 | POOL_ACTIVE_TEXT=`echo -e ${POOL_ACTIVE_TEXT} | sed 's/| |/|/g'` 889 | 890 | SELF_ACTIVE_STAKE=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 'Withdraw Authority: '${NODE_WITHDRAW_AUTHORITY} | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | awk '{n += $1}; END{print 0+n+0}'` 891 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 892 | MINIMUM_SELF_STAKE=100 893 | else 894 | MINIMUM_SELF_STAKE=0 895 | fi 896 | 897 | SELF_ACTIVE_STAKE_CLR=`echo -e "${SELF_ACTIVE_STAKE:-0}" | awk '{if(NR=0) print 0; else print'} | awk '{ if (($1 >= $MINIMUM_SELF_STAKE)) print gr$1" SOL"nc; else print rd$1" SOL"nc; fi }' gr=$GREEN rd=$RED nc=$NOCOLOR` 898 | SELF_ACTIVE_STAKE_COUNT=`echo -e "${SOLANA_STAKES_THIS_NODE}" | grep -B7 'Withdraw Authority: '${NODE_WITHDRAW_AUTHORITY} | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | grep '' -c` 899 | 900 | OTHER_ACTIVE_STAKE=`echo "${TOTAL_ACTIVE_STAKE:-0} ${BOT_ACTIVE_STAKE:-0} ${SECRET_ACTIVE_STAKE:-0} ${POOL_ACTIVE_STAKE_SUM:-0} ${SELF_ACTIVE_STAKE:-0}" | awk '{print $1 - $2 - $3 - $4 - $5}' | bc` 901 | OTHER_ACTIVE_STAKE_COUNT=`echo "${TOTAL_ACTIVE_STAKE_COUNT:-0} ${BOT_ACTIVE_STAKE_COUNT:-0} ${SECRET_ACTIVE_STAKE_COUNT:-0} ${POOL_ACTIVE_STAKE_COUNT_SUM:-0} ${SELF_ACTIVE_STAKE_COUNT:-0}" | awk '{print $1 - $2 - $3 - $4 - $5}'` 902 | 903 | 904 | CURRENT_STAKE_ACTION=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state_action'` 905 | #| tr '-' '\n | ' 906 | #echo -ne '\n' 907 | 908 | echo -e "${CYAN}" 909 | echo -e "Current Stake ${NOCOLOR}" 910 | 911 | echo -e "${LIGHTPURPLE}Last Bot Stake Action:${NOCOLOR} In epoch ${LAST_EPOCH} ${CURRENT_STAKE_ACTION}${NOCOLOR}" 912 | 913 | echo -e "Stake Total: Active(${TOTAL_ACTIVE_STAKE_COUNT:-0}) ${TOTAL_ACTIVE_STAKE:-0} SOL | From Bot(${BOT_ACTIVE_STAKE_COUNT:-0}) ${BOT_ACTIVE_STAKE_CLR} ${SECRET_ACTIVE_TEXT:-}${POOL_ACTIVE_TEXT:-}| Self-Stake(${SELF_ACTIVE_STAKE_COUNT:-0}) ${SELF_ACTIVE_STAKE_CLR} | Other(${OTHER_ACTIVE_STAKE_COUNT:-0}) ${OTHER_ACTIVE_STAKE} SOL" | sed 's/|\( *|\)*/|/g' 914 | echo -e "Stake Moving: no-moving ${NO_MOVING_STAKE:-0} SOL | activating ${ACTIVATING_STAKE:-0} SOL | deactivating ${DEACTIVATING_STAKE:-0} SOL" 915 | 916 | } 917 | 918 | 919 | function Node_Stake_AllStakers_4 () { 920 | ALL_MY_STAKES=`solana ${SOLANA_CLUSTER} stakes ${YOUR_VOTE_ACCOUNT}` 921 | while [[ $? != 0 ]]; do 922 | ALL_MY_STAKES=`solana ${SOLANA_CLUSTER} stakes ${YOUR_VOTE_ACCOUNT}` 923 | done 924 | 925 | ALL_STAKERS_WITHDRAWERS=`echo "$ALL_MY_STAKES" | grep -E "Withdraw" | sort | uniq | awk -F 'Withdraw Authority: ' '{print $2}'` 926 | 927 | #echo -e "—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————" 928 | 929 | echo -e "${UNDERLINE}${DARKGRAY}All Stakers of Node: \t\t\t\tCount\t${DARKGRAY}${UNDERLINE}Info\t\t${DARKGRAY}${UNDERLINE}Active Stake\t${DARKGRAY}${UNDERLINE}Deactivating\t${DARKGRAY}${UNDERLINE}Activating${NOCOLOR}" 930 | 931 | for i in $ALL_STAKERS_WITHDRAWERS; do 932 | echo -e $i "\t"`echo "$ALL_MY_STAKES" | grep -B7 -E $i | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | wc -l`"\t${NOCOLOR}"`check_key $i`"\t${NOCOLOR}"`echo "$ALL_MY_STAKES" | grep -B7 -E $i | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | awk '{n+=0+$1+0}; END{print 0+n+0}' | sed -r 's/^(.{7}).+$/\1/'`"\t\t${RED}"`echo "$ALL_MY_STAKES" | grep -B7 -E $i | grep -B1 -i 'deactivates' | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | awk '{n-=0+$1+0}; END{print 0+n+0}' | sed -r 's/^(.{7}).+$/\1/'`"\t\t${GREEN}"`echo "$ALL_MY_STAKES" | grep -B7 -E $i | grep 'Activating Stake' | sed 's/Activating Stake: //g' | sed 's/ SOL//g' | bc | awk '{n+=0+$1+0}; END{print 0+n+0}' | sed -r 's/^(.{7}).+$/\1/'`"${NOCOLOR}"; 933 | done 934 | 935 | TOTAL_ACTIVE_STAKE=`echo -e "${ALL_MY_STAKES}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | awk '{n += $1}; END{print 0+n+0}' | bc` 936 | TOTAL_STAKE_COUNT=`echo -e "${ALL_MY_STAKES}" | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | wc -l` 937 | 938 | ACTIVATING_STAKE=`echo -e "${ALL_MY_STAKES}" | grep 'Activating Stake: ' | sed 's/Activating Stake: //g' | sed 's/ SOL//g' | bc | awk '{n += $1}; END{print 0+n+0}' | bc | sed -r 's/^(.{7}).+$/\1/'` 939 | ACTIVATING_STAKE_COUNT=`echo -e "${ALL_MY_STAKES}" | grep 'Activating Stake: ' | sed 's/Activating Stake: //g' | sed 's/ SOL//g' | bc | wc -l` 940 | 941 | DEACTIVATING_STAKE=`echo -e "${ALL_MY_STAKES}" | grep -B1 -i 'deactivates' | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | awk '{n -= $1}; END{print 0+n+0}' | bc | sed -r 's/^(.{7}).+$/\1/'` 942 | DEACTIVATING_STAKE_COUNT=`echo -e "${ALL_MY_STAKES}" | grep -B1 -i 'deactivates' | grep 'Active Stake' | sed 's/Active Stake: //g' | sed 's/ SOL//g' | bc | wc -l` 943 | 944 | TOTAL_ACTIVE_STAKE_COUNT=`echo "${TOTAL_STAKE_COUNT:-0} ${ACTIVATING_STAKE_COUNT:-0}" | awk '{print $1 - $2}' | bc` 945 | 946 | #echo -e "—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————" 947 | echo -e "${UNDERLINE}${NOCOLOR}TOTAL:\t\t\t\t\t\t${TOTAL_ACTIVE_STAKE_COUNT}\t${LIGHTPURPLE}${UNDERLINE}\t\t${CYAN}${UNDERLINE}${TOTAL_ACTIVE_STAKE:-0}\t\t${RED}${UNDERLINE}${DEACTIVATING_STAKE:-0}\t\t${GREEN}${UNDERLINE}${ACTIVATING_STAKE:-0}${NOCOLOR}" 948 | 949 | } 950 | 951 | 952 | function SFDP_5 () { 953 | 954 | KYC_API_VERCEL=`curl -s 'https://api.solana.org/api/validators/list?offset=0&limit=15&order_by=name&order=asc&search_term='${THIS_SOLANA_ADRESS}` 955 | 956 | SFDP_FULL_STATUS=$(solana-foundation-delegation-program status ${THIS_SOLANA_ADRESS} > /dev/null 2>&1) 957 | SFDP_STATUS=`echo -e "${SFDP_FULL_STATUS}" | grep 'State: ' | sed 's/State: //g'` 958 | 959 | if [[ SFDP_STATUS="" ]]; then 960 | SFDP_STATUS=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].state'` 961 | fi 962 | 963 | if [[ SFDP_FULL_STATUS="" ]]; then 964 | SFDP_FULL_STATUS=`echo "Testnet Key:" $(echo "${KYC_API_VERCEL}" | jq -r '.data[0].testnetPubkey') 965 | echo "Mainnet Key:" $(echo "${KYC_API_VERCEL}" | jq -r '.data[0].mainnetBetaPubkey') 966 | echo "Participant Pubkey:" $(echo "${KYC_API_VERCEL_3}" | jq -r '.participantPubkey')` 967 | fi 968 | 969 | KYC_STATUS=`echo "${KYC_API_VERCEL_3}" | jq -r '.kycStatus'` 970 | KYC_REQ_BY=`echo "${KYC_API_VERCEL_3}" | jq -r '.kycRequiredBy'` 971 | 972 | TDS22ENROLLED=`echo "${KYC_API_VERCEL_3}" | jq -r '.tds22Enrolled'` 973 | TDS22SIGNUPDATE=`echo "${KYC_API_VERCEL_3}" | jq -r '.tds22SignupDate'` 974 | 975 | TDS_GROUP=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].tds_onboarding_group'` 976 | 977 | ONBOARDING_NUMBER=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].onboardingNumber'` 978 | ONBOARDING_WEEK=`echo -e "$ONBOARDING_NUMBER" | awk '{print ($1/25.00)}' | awk '{printf("%.1f\n",$1)}'` 979 | 980 | CURRENT_STAKE_STATE=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state'` 981 | CURRENT_STAKE_REASON=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state_reason'` 982 | 983 | METRICS_LAST_EPOCH_TRUE_FALSE=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics.pass'` 984 | METRICS_LAST_EPOCH=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics.reason'` 985 | 986 | METRICS_SUMMARY_TRUE_FALSE=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics_summary.pass'` 987 | METRICS_SUMMARY_RAW=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics_summary.reason'` 988 | COLOR_METRICS=`if [[ "${METRICS_SUMMARY_TRUE_FALSE}" == "true" ]]; 989 | then 990 | if [[ $METRICS_SUMMARY_RAW == *"10/10"* ]]; 991 | then 992 | echo "${GREEN}" 993 | else 994 | echo "${YELLOW}" 995 | fi 996 | else 997 | echo "${RED}" 998 | fi` 999 | 1000 | METRICS_SUMMARY=`echo "${COLOR_METRICS}"``echo "${METRICS_SUMMARY_RAW}"``echo "${NOCOLOR}"` 1001 | 1002 | TESTNET_PERFORMANCE=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].tn_calculated_stats.num_bonus_last_10'` 1003 | 1004 | COLOR_TESTNET_PERFORMANCE=` 1005 | if (( $(bc<<<"scale=0;${TESTNET_PERFORMANCE} >= 8") )); then 1006 | echo "${GREEN}" 1007 | elif (( $(bc<<<"scale=0;${TESTNET_PERFORMANCE} >= 5") )); then 1008 | echo "${YELLOW}" 1009 | else 1010 | echo "${RED}" 1011 | fi` 1012 | 1013 | COLOR_STAKE_STATE=` 1014 | if [[ "${CURRENT_STAKE_STATE}" == "Bonus" ]]; 1015 | then 1016 | echo "${GREEN}" 1017 | elif [[ "${CURRENT_STAKE_STATE}" == "Baseline" ]]; 1018 | then 1019 | echo "${YELLOW}" 1020 | else 1021 | echo "${RED}" 1022 | fi` 1023 | 1024 | COLOR_SFDP_STATUS=` 1025 | if [[ "${SFDP_STATUS}" == "Rejected" ]]; 1026 | then 1027 | echo "${RED}" 1028 | else 1029 | if [[ "${SFDP_STATUS}" == "Approved" ]]; 1030 | then 1031 | echo "${GREEN}" 1032 | else 1033 | echo "${LIGHTPURPLE}" 1034 | fi 1035 | fi` 1036 | SFDP_STATUS_STRING=`echo -e "State: ${COLOR_SFDP_STATUS}${SFDP_STATUS}${NOCOLOR}"` 1037 | SFDP=`echo -e "${SFDP_FULL_STATUS}" | grep -v "State: "` 1038 | 1039 | KYC_REQ_STRING=` 1040 | if [[ "${KYC_STATUS}" == "RE_KYC_REQUIRED" ]]; 1041 | then 1042 | echo " untill" $(date -d "${KYC_REQ_BY}" +"%F %T") ${SERVER_TIME_ZONE:-''} 1043 | fi` 1044 | COLOR_KYC_STATUS=` 1045 | if [[ "${KYC_STATUS}" == "RE_KYC_REQUIRED" ]]; 1046 | then 1047 | echo "${RED}REQUIRED" 1048 | else 1049 | if [[ "${KYC_STATUS}" == "KYC_VALID" ]]; 1050 | then 1051 | echo "${GREEN}VALID" 1052 | else 1053 | echo "${LIGHTPURPLE}${KYC_STATUS}" 1054 | fi 1055 | fi` 1056 | KYC_STATUS_STRING=`echo -e "KYC Status: ${COLOR_KYC_STATUS}${NOCOLOR}${KYC_REQ_STRING}"` 1057 | 1058 | TDS22SIGNUPDATE_STRING=` 1059 | if [[ "${TDS22SIGNUPDATE}" != "null" ]]; 1060 | then 1061 | echo $(date -d "${TDS22SIGNUPDATE}" +"%F %T") ${SERVER_TIME_ZONE:-''} 1062 | fi` 1063 | 1064 | #echo -ne '\n' 1065 | echo -e "${CYAN}" 1066 | echo -e "Foundation Delegation Program ${NOCOLOR}" 1067 | echo -e "${KYC_STATUS_STRING}" 1068 | echo -e "${SFDP_STATUS_STRING}" 1069 | if [[ "${TDS_GROUP}" != "null" ]] ; then 1070 | echo -e "TDS Group: ${TDS_GROUP}" 1071 | fi 1072 | if [[ "${ONBOARDING_NUMBER}" != "null" ]] ; then 1073 | echo -e "Current Onboarding Queue Number: ${LIGHTPURPLE}${ONBOARDING_NUMBER}${NOCOLOR} | ~${ONBOARDING_WEEK} weeks" 1074 | fi 1075 | echo -e "${SFDP}" 1076 | 1077 | if [[ "${TESTNET_PERFORMANCE}" != "null" ]] ; then 1078 | echo -e "Current Testnet Performance: ${COLOR_TESTNET_PERFORMANCE}${TESTNET_PERFORMANCE}/10 ${NOCOLOR}" 1079 | fi 1080 | echo -e "Last Epoch State: ${COLOR_STAKE_STATE}${CURRENT_STAKE_STATE}: ${CURRENT_STAKE_REASON}${NOCOLOR}" 1081 | if [[ "${TDS22ENROLLED}" == "true" ]] ; 1082 | then 1083 | echo -e "TDS22 registration: ${GREEN}TRUE${NOCOLOR} from ${TDS22SIGNUPDATE_STRING}" 1084 | else 1085 | echo -e "TDS22 registration: ${RED}${TDS22ENROLLED}${NOCOLOR}" 1086 | fi 1087 | 1088 | 1089 | #echo -e "Metrics-Last-Epoch-${LAST_EPOCH}: ${METRICS_LAST_EPOCH}" 1090 | 1091 | if [[ "${METRICS_SUMMARY_RAW}" != "null" ]] ; then 1092 | echo -e "Metrics: ${METRICS_SUMMARY}" 1093 | fi 1094 | } 1095 | 1096 | function Vote_Credits_6 () { 1097 | 1098 | YOUR_CREDITS=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.epochCredits'` 1099 | #YOUR_CREDITS=`solana ${SOLANA_CLUSTER} vote-account ${YOUR_VOTE_ACCOUNT} | grep -A 4 History | grep -A 2 epoch | grep credits/slots | cut -d ' ' -f 4 | cut -d '/' -f 1 | bc` 1100 | YOUR_CREDITS_PLACE=`solana validators ${SOLANA_CLUSTER} --sort=credits -r -n | grep ${THIS_SOLANA_ADRESS} | sed 's/⚠️/ /g' | awk '{print ($1)}' | sed 's/[[:blank:]]*$//'` 1101 | ALL_CREDITS_PLACES=`solana validators ${SOLANA_CLUSTER} --sort=credits -r -n | grep -A 999999999 Skip | grep -B 999999999 Skip | grep -v Skip | sed 's/[()⚠️]/ /g' | tr -s ' ' | tac | egrep -m 1 . | awk {'print $1'}` 1102 | #ALL_CLUSTER_CREDITS_LIST=`solana ${SOLANA_CLUSTER} validators | grep -A 999999999 Skip | grep -B 999999999 Skip | grep -v Skip | sed 's/(/ /g'| sed 's/)/ /g' | tr -s ' ' | sed 's/ /\n\r/g' | grep -v % | grep -i -v [a-z⚠️-] | egrep '^.{2,7}$' | grep -v -E '\.+[[:digit:]]\.+[[:digit:]]+$' | grep -v -E '^.{2,3}$'` 1103 | #SUM_CLUSTER_CREDITS=`echo -e "${ALL_CLUSTER_CREDITS_LIST}" | awk '{n += $1}; END{print n}'` 1104 | #COUNT_CLUSTER_VALIDATORS=`echo -e "${ALL_CLUSTER_CREDITS_LIST}" | wc -l | bc` 1105 | #CLUSTER_CREDITS=`echo -e "$SUM_CLUSTER_CREDITS" "$COUNT_CLUSTER_VALIDATORS" | awk '{print ($1/$2)}' ` 1106 | CLUSTER_CREDITS=`solana ${SOLANA_CLUSTER} validators --output json-compact | jq --arg ID ${THIS_SOLANA_ADRESS} '.validators[]' | jq -r .epochCredits | awk '{n += $1; y += 1}; END{print n/y}'` 1107 | 1108 | PERCENT_CREDITS=`echo "${YOUR_CREDITS:-0} ${CLUSTER_CREDITS:-0} ${CLUSTER_CREDITS:-1}" | awk '{print 100 * ($1 - $2) / $3}' | awk '{printf("%.2f\n",$1)}'` 1109 | 1110 | PERCENT_SIGN=` 1111 | if (( $(bc<<<"scale=2;${PERCENT_CREDITS} >= 0.0") )); 1112 | then 1113 | echo "+" 1114 | else 1115 | echo "" 1116 | fi` 1117 | 1118 | #echo -ne '\n' 1119 | echo -e "${CYAN}" 1120 | echo -e "Vote-Credits ${NOCOLOR}" 1121 | 1122 | echo -e "Average cluster credits: ${CLUSTER_CREDITS:-0} (minus grace 35%: $(bc<<<"scale=2;${CLUSTER_CREDITS:-0}*0.65"))" 1123 | 1124 | if (( $(bc<<<"scale=2;${YOUR_CREDITS:-0} >= ${CLUSTER_CREDITS:-0}*0.65"))); then 1125 | echo -e "${GREEN}Your credits: ${YOUR_CREDITS} (Good) | ${PERCENT_SIGN}${PERCENT_CREDITS}% from average${NOCOLOR}" 1126 | else 1127 | echo -e "${RED}Your credits: ${YOUR_CREDITS} (Bad) | ${PERCENT_SIGN}${PERCENT_CREDITS}% from average${NOCOLOR}" 1128 | fi 1129 | echo -e "Your epoch credit rating: # ${YOUR_CREDITS_PLACE} / ${ALL_CREDITS_PLACES} " 1130 | #("${COUNT_CLUSTER_VALIDATORS} with non-zero credits)" 1131 | 1132 | echo -e "Max-Possible Cluster Credits are 432000 (minus grace 35%: $(bc<<<"scale=2;432000*0.65"))" 1133 | 1134 | if (( $(bc<<<"scale=2;${YOUR_CREDITS:-0} >= 432000*0.65") )); then 1135 | echo -e "${GREEN}Your Node fulfilled the maximum plan!${NOCOLOR}" 1136 | else 1137 | echo -e "Your Node not yet fulfilled the maximum plan: $(bc<<<"scale=2;432000*0.65-${YOUR_CREDITS:-0}") | ${YELLOW}$(bc<<<"scale=2;100-100*${YOUR_CREDITS:-0}/(432000*0.65)")% remains${NOCOLOR}" 1138 | fi 1139 | 1140 | } 1141 | 1142 | function Skiprate_7 () { 1143 | 1144 | 1145 | 1146 | CLUSTER_SKIP=`echo -e "$(solana validators ${SOLANA_CLUSTER} --output json-compact | jq .averageStakeWeightedSkipRate)" | awk '{printf("%.2f\n",$1)}'` 1147 | 1148 | CLUSTER_SKIP_AVERAGE=`echo -e "$(solana validators ${SOLANA_CLUSTER} --output json-compact | jq .averageSkipRate)" | awk '{printf("%.2f\n",$1)}'` 1149 | 1150 | 1151 | THIS_BLOCK_PRODUCTION=`solana ${SOLANA_CLUSTER} -v block-production | grep ${THIS_SOLANA_ADRESS}` 1152 | 1153 | ALL_SLOTS=`solana ${SOLANA_CLUSTER} leader-schedule | grep ${THIS_SOLANA_ADRESS} -c | awk '{if ($1==0) print 1; else print $1;}'` 1154 | SKIPPED_COUNT=`echo -e "${THIS_BLOCK_PRODUCTION}" | grep SKIPPED -c` 1155 | NON_SKIPPED_COUNT=`echo -e "${THIS_BLOCK_PRODUCTION}" | grep SKIPPED -v -c | awk '{ if ($1 > 0) print $1-1; else print 0; fi}'` 1156 | 1157 | SCHEDULE1=`solana ${SOLANA_CLUSTER} leader-schedule | grep ${THIS_SOLANA_ADRESS} | tr -s ' ' | cut -d' ' -f2` 1158 | CURRENT_SLOT1=`echo -e "$EPOCH_INFO" | grep "Slot: " | cut -d ':' -f 2 | cut -d ' ' -f 2` 1159 | COMPLETED_SLOTS1=`echo -e "${SCHEDULE1}" | awk -v cs1="${CURRENT_SLOT1:-0}" '{ if ( ! -z "$1" ) if ($1 <= cs1) { print }}' | wc -l` 1160 | REMAINING_SLOTS1=`echo -e "${SCHEDULE1}" | awk -v cs1="${CURRENT_SLOT1:-0}" '{ if ( ! -z "$1" ) if ($1 > cs1) { print }}' | wc -l` 1161 | 1162 | YOUR_SKIPRATE=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.skipRate' | awk '{printf("%.2f\n",$1)}'` 1163 | #YOUR_SKIPRATE=`echo -e "${THIS_BLOCK_PRODUCTION}" | sed -n -e 1p | sed 's/ */ /g' | sed '/^#\|^$\| *#/d' | cut -d ' ' -f 6 | cut -d '%' -f 1 | awk '{print $1}'` 1164 | 1165 | NEAREST_SLOTS=`echo -e "${SEE_SHEDULE_VAR}" | grep -m1 -A11 "new>" | sed -n -e 1p -e 5p -e 9p | sed 's/End: /End of epoch:/g' | sed 's/new> //g' | tr -s ' ' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g'` 1166 | LAST_BLOCK=`echo -e "${SEE_SHEDULE_VAR}" | grep "old<" | tail -n1 | sed 's/old< //g' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g'` 1167 | LAST_BLOCK_STATUS=`echo -e "${THIS_BLOCK_PRODUCTION}" | tail -n2 | tr -s ' ' | sed 's/ /\n\r/g' | sed '/^$/d' | grep -i 'skipped' -c | awk {'if ($1==0) print "DONE"; else print "SKIPPED"'}` 1168 | COLOR_LAST_BLOCK=` 1169 | if [[ "${LAST_BLOCK_STATUS}" == "SKIPPED" ]]; 1170 | then 1171 | echo "${RED}" 1172 | else 1173 | echo "${GREEN}" 1174 | fi` 1175 | 1176 | 1177 | #echo -ne '\n' 1178 | echo -e "${CYAN}" 1179 | echo -e "Skip Rate ${NOCOLOR}" 1180 | 1181 | echo -e "Average cluster skiprate: ${CLUSTER_SKIP}% (plus grace 30%: $(bc<<<"scale=2;${CLUSTER_SKIP:-0}+30")%) | AVG ${CLUSTER_SKIP_AVERAGE}%" 1182 | 1183 | if (( $(bc<<<"scale=2;${YOUR_SKIPRATE:-0} > ${CLUSTER_SKIP:-0}+30"))); then 1184 | echo -e "${RED}Your skiprate: ${YOUR_SKIPRATE:-0}% (Bad) - Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR}" 1185 | elif (( $(bc<<<"scale=2;${YOUR_SKIPRATE:-0} >= ${CLUSTER_SKIP:-0}+20"))); then 1186 | echo -e "${YELLOW}Your skiprate: ${YOUR_SKIPRATE:-0}% (Good) - Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR}" 1187 | else 1188 | echo -e "${GREEN}Your skiprate: ${YOUR_SKIPRATE:-0}% (Good) - Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR}" 1189 | fi 1190 | 1191 | if (("${COMPLETED_SLOTS1:-0}" != '1' && "${ALL_SLOTS:-0}" != '1')); then 1192 | 1193 | echo "Your Slots ${COMPLETED_SLOTS1:-0}/${ALL_SLOTS:-0} (${REMAINING_SLOTS1:-0} remaining)" 1194 | 1195 | 1196 | #min-skip 1197 | if (( $(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1} <= ${CLUSTER_SKIP:-0}+30") )); then 1198 | echo -e "Your Min-Possible Skiprate is ${GREEN}$(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1}")%${NOCOLOR} (if all remaining slots will be done)" 1199 | else 1200 | echo -e "Your Min-Possible Skiprate is ${RED}$(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1}")%${NOCOLOR} (if all remaining slots will be done)" 1201 | fi 1202 | 1203 | #max-skip 1204 | if (( $(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1} <= ${CLUSTER_SKIP:-0}+30") )); then 1205 | echo -e "Your Max-Possible Skiprate is ${GREEN}$(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1}")%${NOCOLOR} (if all remaining slots will be skipped)" 1206 | else 1207 | echo -e "Your Max-Possible Skiprate is ${RED}$(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1}")%${NOCOLOR} (if all remaining slots will be skipped)" 1208 | fi 1209 | 1210 | echo -e "${CYAN}" 1211 | echo -e "Block Production ${NOCOLOR}" 1212 | 1213 | if (( $(bc<<<"scale=2;${COMPLETED_SLOTS1:-0} > 0"))); then 1214 | echo -e "Last Block: ${COLOR_LAST_BLOCK}${LAST_BLOCK} ${LAST_BLOCK_STATUS}${NOCOLOR}" 1215 | else 1216 | echo -e "This node did not produce any blocks yet" 1217 | fi 1218 | 1219 | if (( $(bc<<<"scale=2;${REMAINING_SLOTS1:-0} > 0"))); then 1220 | echo -e "Nearest Slots (4 blocks each):" 1221 | echo -e "${GREEN}${NEAREST_SLOTS}${NOCOLOR}" 1222 | else 1223 | echo -e "This node will not have new blocks in this epoch" 1224 | fi 1225 | 1226 | else 1227 | echo -e "${LIGHTPURPLE}This node don't have blocks in this epoch${NOCOLOR}" 1228 | fi 1229 | } 1230 | 1231 | function Last_Rewards_8 () { 1232 | 1233 | LAST_REWARDS_RAW_JSON=$(solana -um vote-account --with-rewards --num-rewards-epochs 5 --output json ${YOUR_VOTE_ACCOUNT} 2>&1 | jq -r '.epochRewards[]') 1234 | 1235 | LAST_REWARDS_RAW_JSON_EPOCHS=(`echo -e "${LAST_REWARDS_RAW_JSON}" | jq -r '.epoch'`) 1236 | LAST_REWARDS_RAW_JSON_AMOUNT=(`echo -e "${LAST_REWARDS_RAW_JSON}" | jq -r '.amount' | awk '{print ($1/(1000000000))}' | bc`) 1237 | 1238 | for((t=0;t<${#LAST_REWARDS_RAW_JSON_EPOCHS[@]};t++)); do 1239 | LAST_REWARDS_JSON+=`echo -ne "Epoch ${LAST_REWARDS_RAW_JSON_EPOCHS[t]} - ${LAST_REWARDS_RAW_JSON_AMOUNT[t]} "` 1240 | LAST_REWARDS_JSON+="\n" 1241 | done 1242 | 1243 | #LAST_REWARDS_RAW=$(solana -um vote-account --with-rewards --num-rewards-epochs 5 ${YOUR_VOTE_ACCOUNT} 2>&1) 1244 | #LAST_REWARDS=`echo -e "${LAST_REWARDS_RAW}" | grep -A10 'Reward Slot' | sed 's/Reward Slot/Reward_Slot/g' | awk '{print $1"\t"$3}'` 1245 | 1246 | #echo -ne '\n' 1247 | echo -e "${CYAN}" 1248 | echo -e "Last Rewards ${NOCOLOR}" 1249 | #echo -e "${LAST_REWARDS:-${LIGHTPURPLE}No rewards yet ${NOCOLOR}}" 1250 | echo -e "${LAST_REWARDS_JSON:-${LIGHTPURPLE}No rewards yet ${NOCOLOR}}" 1251 | 1252 | #_work_done=1 1253 | } 1254 | 1255 | 1256 | function Only_Important () 1257 | { 1258 | OPTIMISTIC_ARR[1]=`Optimistic_Slot_Now` 1259 | 1260 | EPOCH_NUMBER=`echo "$EPOCH_INFO" | grep 'Epoch: '` 1261 | END_OF_EPOCH=`echo -e "${SEE_SHEDULE_VAR}" | tail -n1 | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | sed 's/End: /End of epoch:/g' | tr -s ' '` 1262 | EPOCH_REMAINS=`echo "$EPOCH_INFO" | grep 'Epoch Completed Time' | sed -n '/.*(/s///p' | sed 's/)//g' 2> /dev/null` 1263 | 1264 | echo -e "" 1265 | echo -e "Solana Price: "`solana_price` 1266 | 1267 | echo -e "${CYAN}$EPOCH_NUMBER | $END_OF_EPOCH$SERVER_TIME_ZONE| $EPOCH_REMAINS ${NOCOLOR}" 1268 | 1269 | KYC_API_VERCEL=`curl -s 'https://api.solana.org/api/validators/list?offset=0&limit=15&order_by=name&order=asc&search_term='${THIS_SOLANA_ADRESS}` 1270 | SFDP_STATUS=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].state'` 1271 | COLOR_SFDP_STATUS=` 1272 | if [[ "${SFDP_STATUS}" == "Rejected" ]]; 1273 | then 1274 | echo "${RED}" 1275 | else 1276 | if [[ "${SFDP_STATUS}" == "Approved" ]]; 1277 | then 1278 | echo "${GREEN}" 1279 | else 1280 | echo "${LIGHTPURPLE}" 1281 | fi 1282 | fi` 1283 | if [[ "${SFDP_STATUS}" == "null" ]]; 1284 | then 1285 | SFDP_STATUS="Not SFDP Node" 1286 | fi 1287 | SFDP_STATUS_STRING=`echo -e ": ${COLOR_SFDP_STATUS}${SFDP_STATUS}${NOCOLOR}"` 1288 | 1289 | THIS_SOLANA_VALIDATOR_INFO=`solana ${SOLANA_CLUSTER} validator-info get | awk '$0 ~ sadddddr {do_print=1} do_print==1 {print} NF==0 {do_print=0}' sadddddr=$THIS_SOLANA_ADRESS` 1290 | 1291 | SOLANA_VALIDATORS=`solana ${SOLANA_CLUSTER} validators` 1292 | 1293 | NODE_NAME=`echo -e "${THIS_SOLANA_VALIDATOR_INFO}" | grep 'Name: ' | sed 's/Name//g' | tr -s ' '` 1294 | 1295 | NODE_COMMISSION=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.commission'` 1296 | if (( $(bc<<<"scale=0;${NODE_COMMISSION:-100} <= 10.0") )); then 1297 | NODE_COMMISSION="${GREEN}${NODE_COMMISSION}%${NOCOLOR}" 1298 | else 1299 | if [[ "${CLUSTER_NAME}" != "(Mainnet)" ]]; then 1300 | NODE_COMMISSION="${GREEN}${NODE_COMMISSION}%${NOCOLOR}" 1301 | else 1302 | NODE_COMMISSION="${RED}${NODE_COMMISSION}%${NOCOLOR}" 1303 | fi 1304 | fi 1305 | 1306 | KYC_STATUS=`echo "${KYC_API_VERCEL_3}" | jq -r '.kycStatus'` 1307 | #KYC_REQ_BY=`echo "${KYC_API_VERCEL_3}" | jq -r '.kycRequiredBy'` 1308 | 1309 | TDS22ENROLLED=`echo "${KYC_API_VERCEL_3}" | jq -r '.tds22Enrolled'` 1310 | #TDS22SIGNUPDATE=`echo "${KYC_API_VERCEL_3}" | jq -r '.tds22SignupDate'` 1311 | 1312 | COLOR_KYC_STATUS=` 1313 | if [[ "${KYC_STATUS}" == "RE_KYC_REQUIRED" ]]; 1314 | then 1315 | echo "${RED}RE-KYC REQUIRED" 1316 | else 1317 | if [[ "${KYC_STATUS}" == "KYC_VALID" ]]; 1318 | then 1319 | echo "${GREEN}KYC VALID" 1320 | else 1321 | echo "${LIGHTPURPLE}${KYC_STATUS}" 1322 | fi 1323 | fi` 1324 | KYC_STATUS_STRING=`echo -e "${COLOR_KYC_STATUS}${NOCOLOR}"` 1325 | 1326 | if [[ "${TDS22ENROLLED}" == "true" ]]; 1327 | then 1328 | TDS22ENROLLED=`echo -e "${GREEN}TDS22 Registered${NOCOLOR}"` 1329 | else 1330 | TDS22ENROLLED=`echo -e "${NOCOLOR}TDS22 no registered${NOCOLOR}"` 1331 | fi 1332 | 1333 | echo -e "${BLUE}This Node${NODE_NAME} ${CLUSTER_NAME} ${NOCOLOR}${SFDP_STATUS_STRING} | ${NODE_COMMISSION} | ${TDS22ENROLLED} | ${KYC_STATUS_STRING}" 1334 | 1335 | IS_DELINKED=`echo -e "${SOLANA_VALIDATORS}" | grep ⚠️ | if (grep ${THIS_SOLANA_ADRESS} -c)>0; then echo -e "WARNING: ${RED}THIS NODE IS DELINKED\n\rconsider to check catchup, network connection and/or messages from your datacenter${NOCOLOR}"; else >/dev/null; fi` 1336 | 1337 | echo -e "${IS_DELINKED}" | awk 'length > 5' 1338 | 1339 | NODE_WITHDRAW_AUTHORITY=`solana ${SOLANA_CLUSTER} vote-account ${YOUR_VOTE_ACCOUNT} | grep 'Withdraw' | awk '{print $NF}'` 1340 | IDACC_BALANCE=`solana ${SOLANA_CLUSTER} balance ${THIS_SOLANA_ADRESS} | sed 's/ SOL//g' ` 1341 | VOTEACC_BALANCE=`solana ${SOLANA_CLUSTER} balance ${YOUR_VOTE_ACCOUNT}` 1342 | WITHDR_BALANCE=`solana ${SOLANA_CLUSTER} balance ${NODE_WITHDRAW_AUTHORITY}` 1343 | 1344 | if (( $(bc<<<"scale=0;${IDACC_BALANCE:-0} >= 1.8") )); then 1345 | echo -e "Identity: ${THIS_SOLANA_ADRESS} | ${GREEN}${IDACC_BALANCE:-0} SOL${NOCOLOR}" 1346 | else 1347 | echo -e "Identity: ${THIS_SOLANA_ADRESS} | ${RED}${IDACC_BALANCE:-0} SOL${NOCOLOR}" 1348 | fi 1349 | echo -e "VoteKey: ${YOUR_VOTE_ACCOUNT} | ${VOTEACC_BALANCE}" 1350 | echo -e "Withdrawer: ${NODE_WITHDRAW_AUTHORITY} | ${WITHDR_BALANCE}" 1351 | 1352 | 1353 | SOLANA_VERSION=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.version'` 1354 | 1355 | MAJOR_CLUSTER_VERSION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k6 -nr | sed 1q | awk '{print $1}'` 1356 | #MAJOR_CLUSTER_VERSION_PERCENT=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k6 -nr | sed 1q | awk '{print $6}'` 1357 | 1358 | MAJOR_CLUSTER_VERSION_BY_POPULATION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k3 -nr | sed 1q | awk '{print $1}'` 1359 | #MAJOR_CLUSTER_VERSION_POPULATION=`echo -e "${SOLANA_VALIDATORS}" | grep -A99 "Stake By Version:" | sed 's/[()]/ /g' | tail -n +2 | sort -k3 -nr | sed 1q | awk '{print $3}'` 1360 | 1361 | if [[ "${SOLANA_VERSION}" == "${MAJOR_CLUSTER_VERSION_BY_POPULATION}" ]]; then 1362 | echo -e "Solana version: " | tr -d '\r\n' && echo -e "${GREEN}${SOLANA_VERSION}${NOCOLOR} (Majority ${MAJOR_CLUSTER_VERSION_BY_POPULATION}${NOCOLOR})" 1363 | else 1364 | echo -e "Solana version: " | tr -d '\r\n' && echo -e "${RED}${SOLANA_VERSION}${NOCOLOR} (Majority ${MAJOR_CLUSTER_VERSION_BY_POPULATION}${NOCOLOR})" 1365 | fi 1366 | 1367 | OPTIMISTIC_ARR[3]=`Optimistic_Slot_Now 5` 1368 | 1369 | 1370 | 1371 | ONBOARDING_NUMBER=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].onboardingNumber'` 1372 | ONBOARDING_WEEK=`echo -e "$ONBOARDING_NUMBER" | awk '{print ($1/25.00)}' | awk '{printf("%.1f\n",$1)}'` 1373 | 1374 | if [[ "${ONBOARDING_NUMBER}" != "null" ]] ; then 1375 | echo -e "Current Onboarding Queue Number: ${LIGHTPURPLE}${ONBOARDING_NUMBER}${NOCOLOR} | ~${ONBOARDING_WEEK} weeks" 1376 | fi 1377 | 1378 | YOUR_CREDITS=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.epochCredits'` 1379 | 1380 | CLUSTER_CREDITS=`solana ${SOLANA_CLUSTER} validators --output json-compact | jq --arg ID ${THIS_SOLANA_ADRESS} '.validators[]' | jq -r .epochCredits | awk '{n += $1; y += 1}; END{print n/y}'` 1381 | 1382 | PERCENT_CREDITS=`echo "${YOUR_CREDITS:-0} ${CLUSTER_CREDITS:-0} ${CLUSTER_CREDITS:-1}" | awk '{print 100 * ($1 - $2) / $3}' | awk '{printf("%.2f\n",$1)}'` 1383 | 1384 | PERCENT_SIGN=` 1385 | if (( $(bc<<<"scale=2;${PERCENT_CREDITS} >= 0.0") )); 1386 | then 1387 | echo "+" 1388 | else 1389 | echo "" 1390 | fi` 1391 | 1392 | VOTE_PLAN=` 1393 | if (( $(bc<<<"scale=2;${YOUR_CREDITS:-0} >= 432000*0.65") )); then 1394 | echo -e "${GREEN} | Maximum plan credits!${NOCOLOR}" 1395 | else 1396 | echo -e "${YELLOW} | $(bc<<<"scale=2;100-100*${YOUR_CREDITS:-0}/(432000*0.65)")% remaining${NOCOLOR}" 1397 | fi` 1398 | 1399 | if (( $(bc<<<"scale=2;${YOUR_CREDITS:-0} >= ${CLUSTER_CREDITS:-0}*0.65"))); then 1400 | echo -e "${GREEN}Your credits: ${YOUR_CREDITS} (Good) | ${PERCENT_SIGN}${PERCENT_CREDITS}% from average${NOCOLOR}${VOTE_PLAN}" 1401 | else 1402 | echo -e "${RED}Your credits: ${YOUR_CREDITS} (Bad) | ${PERCENT_SIGN}${PERCENT_CREDITS}% from average${NOCOLOR}${VOTE_PLAN}" 1403 | fi 1404 | 1405 | OPTIMISTIC_ARR[4]=`Optimistic_Slot_Now` 1406 | 1407 | CLUSTER_SKIP=`echo -e "$(solana validators ${SOLANA_CLUSTER} --output json-compact | jq .averageStakeWeightedSkipRate)" | awk '{printf("%.2f\n",$1)}'` 1408 | 1409 | CLUSTER_SKIP_AVERAGE=`echo -e "$(solana validators ${SOLANA_CLUSTER} --output json-compact | jq .averageSkipRate)" | awk '{printf("%.2f\n",$1)}'` 1410 | 1411 | 1412 | THIS_BLOCK_PRODUCTION=`solana ${SOLANA_CLUSTER} -v block-production | grep ${THIS_SOLANA_ADRESS}` 1413 | 1414 | ALL_SLOTS=`solana ${SOLANA_CLUSTER} leader-schedule | grep ${THIS_SOLANA_ADRESS} -c | awk '{if ($1==0) print 1; else print $1;}'` 1415 | SKIPPED_COUNT=`echo -e "${THIS_BLOCK_PRODUCTION}" | grep SKIPPED -c` 1416 | NON_SKIPPED_COUNT=`echo -e "${THIS_BLOCK_PRODUCTION}" | grep SKIPPED -v -c | awk '{ if ($1 > 0) print $1-1; else print 0; fi}'` 1417 | 1418 | SCHEDULE1=`solana ${SOLANA_CLUSTER} leader-schedule | grep ${THIS_SOLANA_ADRESS} | tr -s ' ' | cut -d' ' -f2` 1419 | CURRENT_SLOT1=`echo -e "$EPOCH_INFO" | grep "Slot: " | cut -d ':' -f 2 | cut -d ' ' -f 2` 1420 | COMPLETED_SLOTS1=`echo -e "${SCHEDULE1}" | awk -v cs1="${CURRENT_SLOT1:-0}" '{ if ( ! -z "$1" ) if ($1 <= cs1) { print }}' | wc -l` 1421 | REMAINING_SLOTS1=`echo -e "${SCHEDULE1}" | awk -v cs1="${CURRENT_SLOT1:-0}" '{ if ( ! -z "$1" ) if ($1 > cs1) { print }}' | wc -l` 1422 | 1423 | YOUR_SKIPRATE=`echo -e "${THIS_VALIDATOR_JSON}" | jq -r '.skipRate' | awk '{printf("%.2f\n",$1)}'` 1424 | 1425 | if (("${COMPLETED_SLOTS1:-0}" != '1' && "${ALL_SLOTS:-0}" != '1')); then 1426 | 1427 | MIN_POS_SKIP=`if (( $(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1} <= ${CLUSTER_SKIP:-0}+30") )); then 1428 | echo -e "${GREEN}min: $(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1}")%${NOCOLOR}" 1429 | else 1430 | echo -e "${RED}min: $(bc<<<"scale=2;${SKIPPED_COUNT:-0}*100/${ALL_SLOTS:-1}")%${NOCOLOR}" 1431 | fi` 1432 | 1433 | MAX_POS_SKIP=`if (( $(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1} <= ${CLUSTER_SKIP:-0}+30") )); then 1434 | echo -e "${GREEN}max: $(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1}")%${NOCOLOR}" 1435 | else 1436 | echo -e "${RED}max: $(bc<<<"scale=2;(${ALL_SLOTS:-0}-${NON_SKIPPED_COUNT:-0})*100/${ALL_SLOTS:-1}")%${NOCOLOR}" 1437 | fi` 1438 | 1439 | COLOR_REMAINING_SLOTS=`if (( $(bc<<<"scale=0;${REMAINING_SLOTS1:-0} == 0") )); then 1440 | echo -e "${GREEN}" 1441 | else 1442 | echo -e "${YELLOW}" 1443 | fi` 1444 | 1445 | SHORT_SKIP_INFO=`echo "${MIN_POS_SKIP} | ${MAX_POS_SKIP} | cluster ${CLUSTER_SKIP}%->$(bc<<<"scale=2;${CLUSTER_SKIP:-0}+30")% grace | ${COLOR_REMAINING_SLOTS}${REMAINING_SLOTS1:-0} remaining${NOCOLOR}"` 1446 | 1447 | else 1448 | SHORT_SKIP_INFO=`echo -e "${LIGHTPURPLE}This node don't have blocks in this epoch${NOCOLOR} | cluster ${CLUSTER_SKIP}%->$(bc<<<"scale=2;${CLUSTER_SKIP:-0}+30")% grace"` 1449 | fi 1450 | 1451 | 1452 | if (( $(bc<<<"scale=2;${YOUR_SKIPRATE:-0} > ${CLUSTER_SKIP:-0}+30"))); then 1453 | echo -e "${RED}Your skiprate: ${YOUR_SKIPRATE:-0}% (Bad) | Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR} | ${SHORT_SKIP_INFO}" 1454 | elif (( $(bc<<<"scale=2;${YOUR_SKIPRATE:-0} >= ${CLUSTER_SKIP:-0}+20"))); then 1455 | echo -e "${YELLOW}Your skiprate: ${YOUR_SKIPRATE:-0}% (Good) | Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR} | ${SHORT_SKIP_INFO}" 1456 | else 1457 | echo -e "${GREEN}Your skiprate: ${YOUR_SKIPRATE:-0}% (Good) | Done: ${NON_SKIPPED_COUNT:-0}, Skipped: ${SKIPPED_COUNT:-0}${NOCOLOR} | ${SHORT_SKIP_INFO}" 1458 | fi 1459 | 1460 | if (( $(bc<<<"scale=2;${COMPLETED_SLOTS1:-0} > 0"))); then 1461 | LAST_BLOCK_TIME=`echo -e "${SEE_SHEDULE_VAR}" | grep "old<" | tail -n1 | sed 's/old< //g' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | awk '{print $2" "$3}'` 1462 | LAST_BLOCK_STATUS=`echo -e "${THIS_BLOCK_PRODUCTION}" | tail -n2 | tr -s ' ' | sed 's/ /\n\r/g' | sed '/^$/d' | grep -i 'skipped' -c | awk {'if ($1==0) print "DONE"; else print "SKIPPED"'}` 1463 | COLOR_LAST_BLOCK=` 1464 | if [[ "${LAST_BLOCK_STATUS}" == "SKIPPED" ]]; 1465 | then 1466 | echo "${RED}" 1467 | else 1468 | echo "${GREEN}" 1469 | fi` 1470 | LAST_BLOCK_INFO="${COLOR_LAST_BLOCK}${LAST_BLOCK_TIME} ${LAST_BLOCK_STATUS}${NOCOLOR} |" 1471 | else 1472 | LAST_BLOCK_INFO="" 1473 | fi 1474 | 1475 | if (( $(bc<<<"scale=2;${REMAINING_SLOTS1:-0} > 0"))); then 1476 | 1477 | NEXT_SLOT=`echo -e "${SEE_SHEDULE_VAR}" | grep -m1 -A11 "new>" | grep -v "End" | sed -n -e 1p | sed 's/new> //g' | tr -s ' ' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | awk '{print $2" "$3}'` 1478 | NEXT_SLOT_2=`echo -e "${SEE_SHEDULE_VAR}" | grep -m1 -A11 "new>" | grep -v "End" | sed -n -e 5p | sed 's/new> //g' | tr -s ' ' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | awk '{print $2" "$3}'` 1479 | NEXT_SLOT_3=`echo -e "${SEE_SHEDULE_VAR}" | grep -m1 -A11 "new>" | grep -v "End" | sed -n -e 9p | sed 's/new> //g' | tr -s ' ' | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | awk '{print $2" "$3}'` 1480 | 1481 | NEXT_SLOT_INFO="${NOCOLOR}next ${NEXT_SLOT} ${NEXT_SLOT_2:-} ${NEXT_SLOT_3:-}${NOCOLOR}" 1482 | else 1483 | NEXT_SLOT_INFO="${GREEN}This node will not have new blocks in this epoch${NOCOLOR}" 1484 | fi 1485 | 1486 | 1487 | echo -e "Block Production: ${LAST_BLOCK_INFO} ${NEXT_SLOT_INFO} ${NOCOLOR}" 1488 | 1489 | 1490 | TESTNET_PERFORMANCE=`echo "${KYC_API_VERCEL}" | jq -r '.data[0].tn_calculated_stats.num_bonus_last_10'` 1491 | COLOR_TESTNET_PERFORMANCE=` 1492 | if (( $(bc<<<"scale=0;${TESTNET_PERFORMANCE:-0} >= 8") )); then 1493 | echo "${GREEN}" 1494 | elif (( $(bc<<<"scale=0;${TESTNET_PERFORMANCE:-0} >= 5") )); then 1495 | echo "${YELLOW}" 1496 | else 1497 | echo "${RED}" 1498 | fi` 1499 | 1500 | if [[ "${TESTNET_PERFORMANCE}" != "null" ]] ; then 1501 | echo -e "Current Testnet Performance: ${COLOR_TESTNET_PERFORMANCE}${TESTNET_PERFORMANCE}/10 ${NOCOLOR}" 1502 | fi 1503 | 1504 | 1505 | METRICS_SUMMARY_TRUE_FALSE=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics_summary.pass'` 1506 | METRICS_SUMMARY_RAW=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.self_reported_metrics_summary.reason'` 1507 | COLOR_METRICS=`if [[ "${METRICS_SUMMARY_TRUE_FALSE}" == "true" ]]; 1508 | then 1509 | if [[ $METRICS_SUMMARY_RAW == *"10/10"* ]]; 1510 | then 1511 | echo "${GREEN}" 1512 | else 1513 | echo "${YELLOW}" 1514 | fi 1515 | else 1516 | echo "${RED}" 1517 | fi` 1518 | METRICS_SUMMARY=`echo "${COLOR_METRICS}"``echo "${METRICS_SUMMARY_RAW}"``echo "${NOCOLOR}"` 1519 | 1520 | if [[ "${METRICS_SUMMARY_RAW}" != "null" ]] ; then 1521 | echo -e "Metrics: ${METRICS_SUMMARY}" 1522 | fi 1523 | 1524 | 1525 | OPTIMISTIC_ARR[6]=`Optimistic_Slot_Now 5` 1526 | 1527 | GL_COLOR_OPT_SLOT=`echo "${RED}"` 1528 | GL_TEXT_OPT_SLOT=`echo "${RED}Optimistic Slot Outdated!${NOCOLOR}"` 1529 | first_elem=`echo "${OPTIMISTIC_ARR[0]}" | awk '{print $1}'` 1530 | last_elem=`echo "${OPTIMISTIC_ARR[-1]}" | awk '{print $1}'` 1531 | 1532 | for ix in ${!OPTIMISTIC_ARR[*]} 1533 | do 1534 | this_elem=`echo "${OPTIMISTIC_ARR[$ix]}" | awk '{print $1}'` 1535 | if [[ "${this_elem}" != "null" ]]; 1536 | then 1537 | if [[ "${this_elem}" != "${first_elem}" ]]; 1538 | then 1539 | GL_COLOR_OPT_SLOT=`echo "${GREEN}"` 1540 | GL_TEXT_OPT_SLOT=`echo "${GREEN}Optimistic Slot OK!${NOCOLOR}"` 1541 | fi 1542 | fi 1543 | done 1544 | 1545 | if [[ "${OPTIMISTIC_ARR[0]}" != "null" ]]; 1546 | then 1547 | if [[ "${OPTIMISTIC_ARR[-1]}" != "null" ]]; 1548 | then 1549 | echo -e "Optimistic Slots: ${GL_COLOR_OPT_SLOT}${first_elem}${NOCOLOR}-${GL_COLOR_OPT_SLOT}${last_elem}${NOCOLOR} | ${GL_TEXT_OPT_SLOT}" 1550 | fi 1551 | fi 1552 | 1553 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 1554 | 1555 | #LAST_REWARDS_RAW=$(solana -um vote-account --with-rewards --num-rewards-epochs 1 ${YOUR_VOTE_ACCOUNT} 2>&1) 1556 | #while [[ $? != 0 ]]; do 1557 | # LAST_REWARDS_RAW=$(solana -um vote-account --with-rewards --num-rewards-epochs 1 ${YOUR_VOTE_ACCOUNT} 2>&1) 1558 | #done 1559 | # 1560 | #LAST_REWARDS=`echo -e "${LAST_REWARDS_RAW}" | grep -m1 -A1 "Reward Slot" | grep -v "Reward" | sed -n -e 1p | awk '{print "Epoch "$1" - "$3}'` 1561 | # 1562 | #echo -e "Last Reward: ${LAST_REWARDS:-${LIGHTPURPLE}Cannot see rewards now ${NOCOLOR}}" 1563 | 1564 | 1565 | LAST_REWARDS_RAW_JSON=$(solana -um vote-account --with-rewards --num-rewards-epochs 1 --output json ${YOUR_VOTE_ACCOUNT} 2>&1 | jq -r '.epochRewards[]') 1566 | while [[ $? != 0 ]]; do 1567 | LAST_REWARDS_RAW_JSON=$(solana -um vote-account --with-rewards --num-rewards-epochs 1 --output json ${YOUR_VOTE_ACCOUNT} 2>&1 | jq -r '.epochRewards[]') 1568 | done 1569 | 1570 | LAST_REWARDS_RAW_JSON_EPOCHS=(`echo -e "${LAST_REWARDS_RAW_JSON}" | jq -r '.epoch'`) 1571 | LAST_REWARDS_RAW_JSON_AMOUNT=(`echo -e "${LAST_REWARDS_RAW_JSON}" | jq -r '.amount' | awk '{print ($1/(1000000000))}' | bc`) 1572 | 1573 | for((t=0;t<${#LAST_REWARDS_RAW_JSON_EPOCHS[@]};t++)); do 1574 | LAST_REWARDS_JSON+=`echo -ne "Epoch ${LAST_REWARDS_RAW_JSON_EPOCHS[t]} - ${LAST_REWARDS_RAW_JSON_AMOUNT[t]} "` 1575 | #LAST_REWARDS_JSON+="\n" 1576 | done 1577 | 1578 | echo -e "Last Reward: ${LAST_REWARDS_JSON:-${LIGHTPURPLE}Cannot see rewards now ${NOCOLOR}}" 1579 | 1580 | fi 1581 | 1582 | 1583 | if [[ ${GRAFANA_HOST_NAME} != "null" ]]; then 1584 | echo -e `Graphana_hardware_info 102`" | "`Graphana_hardware_info 139`" | "`Graphana_hardware_info 73`" | "`Graphana_hardware_info 67`" | "`Graphana_hardware_info 108`" | "`Graphana_hardware_info 118`" | "`Graphana_hardware_info 111` 1585 | fi 1586 | 1587 | 1588 | CONCENTRATION=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.data_center_stake_percent' | awk '{printf("%.2f\n",$1)}'` 1589 | 1590 | MAX_CONCENTRATION=` 1591 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 1592 | echo "10.00" 1593 | else 1594 | echo "25.00" 1595 | fi` 1596 | DC_COLOR=` 1597 | if (( $(bc<<<"scale=2;${CONCENTRATION} < ${MAX_CONCENTRATION}") )); then 1598 | echo "${GREEN}" 1599 | else 1600 | echo "${YELLOW}" 1601 | fi` 1602 | 1603 | CURRENT_DC=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.epoch_data_center.asn'`'-'`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.epoch_data_center.location'`' | '`echo "${DC_COLOR}${CONCENTRATION}"`'%'`echo "${NOCOLOR}"`' concentration' 1604 | 1605 | if [[ "$(echo "${KYC_API_VERCEL_2}" | jq -r '.stats.epoch_data_center.asn')" != "null" ]] ; then 1606 | echo -e "Datacenter: ${CURRENT_DC}" 1607 | fi 1608 | 1609 | 1610 | CURRENT_STAKE_STATE=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state'` 1611 | CURRENT_STAKE_REASON=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state_reason'` 1612 | COLOR_STAKE_STATE=` 1613 | if [[ "${CURRENT_STAKE_STATE}" == "Bonus" ]]; 1614 | then 1615 | echo "${GREEN}" 1616 | elif [[ "${CURRENT_STAKE_STATE}" == "Baseline" ]]; 1617 | then 1618 | echo "${YELLOW}" 1619 | else 1620 | echo "${RED}" 1621 | fi` 1622 | CURRENT_STAKE_ACTION=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state_action'` 1623 | 1624 | if [[ "${CURRENT_STAKE_STATE}" != "null" ]] ; then 1625 | echo -e "Last Epoch State: ${COLOR_STAKE_STATE}${CURRENT_STAKE_STATE}: ${CURRENT_STAKE_REASON}${NOCOLOR}" 1626 | fi 1627 | if [[ "${CURRENT_STAKE_ACTION}" != "null" ]] ; then 1628 | echo -e "Last Bot Stake Action: In epoch ${LAST_EPOCH} ${CURRENT_STAKE_ACTION}${NOCOLOR}" 1629 | fi 1630 | 1631 | if [[ "${STAKE_SHOW_TYPE}" == "false" ]]; then 1632 | Node_Stake_4 | grep -A2 "Stake Total: Active" 1633 | else 1634 | Node_Stake_AllStakers_4 1635 | fi 1636 | 1637 | } 1638 | 1639 | 1640 | if [[ "${FLAG_ONLY_IMPORTANT}" == "false" ]]; then 1641 | 1642 | Time_Now_1 1643 | echo -e "${GREEN}Solana Price: ${NOCOLOR}"`solana_price` 1644 | 1645 | Epoch_Progress_2 1646 | #SOLANA_CLUSTER=$(rotateKnownRPC "${SOLANA_CLUSTER}") 1647 | #SOLANA_CLUSTER=$(rotateKnownRPC "${SOLANA_CLUSTER}") 1648 | OPTIMISTIC_ARR[5]=`Optimistic_Slot_Now` 1649 | This_Node_3 1650 | 1651 | if [[ "${STAKE_SHOW_TYPE}" == "false" ]]; then 1652 | Node_Stake_4 1653 | else 1654 | echo -e "${CYAN}" 1655 | echo -e "Current Stake ${NOCOLOR}" 1656 | CURRENT_STAKE_ACTION=`echo "${KYC_API_VERCEL_2}" | jq -r '.stats.state_action'` 1657 | echo -e "${LIGHTPURPLE}Last Bot Stake Action:${NOCOLOR} In epoch ${LAST_EPOCH} ${CURRENT_STAKE_ACTION}${NOCOLOR}" 1658 | Node_Stake_AllStakers_4 1659 | fi 1660 | 1661 | OPTIMISTIC_ARR[6]=`Optimistic_Slot_Now` 1662 | SFDP_5 1663 | OPTIMISTIC_ARR[7]=`Optimistic_Slot_Now` 1664 | Vote_Credits_6 1665 | Skiprate_7 1666 | OPTIMISTIC_ARR[8]=`Optimistic_Slot_Now` 1667 | Optimistic_Slot_Summary 1668 | if [[ ${GRAFANA_HOST_NAME} != "null" ]]; then 1669 | echo -e "${CYAN}" 1670 | echo -e "Hardware Info: ${NOCOLOR}" 1671 | echo -e `Graphana_hardware_info 102` 1672 | echo -e `Graphana_hardware_info 139` 1673 | echo -e `Graphana_hardware_info 73` 1674 | echo -e `Graphana_hardware_info 67` 1675 | echo -e `Graphana_hardware_info 108` 1676 | echo -e `Graphana_hardware_info 118` 1677 | echo -e `Graphana_hardware_info 111` 1678 | fi 1679 | if [[ "${CLUSTER_NAME}" == "(Mainnet)" ]]; then 1680 | Last_Rewards_8 1681 | fi 1682 | 1683 | else 1684 | 1685 | Time_Now_1 1686 | 1687 | #SOLANA_CLUSTER=$(rotateKnownRPC "${SOLANA_CLUSTER}") 1688 | #SOLANA_CLUSTER=$(rotateKnownRPC "${SOLANA_CLUSTER}") 1689 | 1690 | Only_Important 1691 | 1692 | 1693 | 1694 | fi 1695 | 1696 | echo -e "${NOCOLOR}" 1697 | 1698 | popd > /dev/null || exit 1 1699 | --------------------------------------------------------------------------------