Evaluate usage of attestation/proposal/aggregation duties prediction
Stereum users have no way of predicting duties of their validators. Please evaluate usability of such options.
Example of how prediction can work, courtesy to pk910#1214:
#!/bin/bash
# getduties.sh by pk910.eth
# This script polls validator duties and shows the next scheduled attestation/proposal.
# It's intended to be used to plan restarts of the bn / vc without missing a attestation.
# Use the `watch` command to get a live view of the output.
#
# Usage:
# ./getduties.sh [options] <validator_index> [<validator_index> ...]
#
# Options:
# -h <rpchost> - beacon node RPC host in addr:port format (default: 127.0.0.1:5052)
# -p - check proposer duties (disabled by default for performance)
# -v - verbose (show more per validator details)
# -n - always load duties of next epoch too (combine with -v)
rpchost="127.0.0.1:5052"
proposer="false"
verbose="false"
nextepoch="false"
# parse arguments
# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
usage_error () { echo >&2 "$(basename $0): $1"; exit 2; }
assert_argument () { test "$1" != "$EOL" || usage_error "$2 requires an argument"; }
if [ "$#" != 0 ]; then
EOL=$(printf '\1\3\3\7')
set -- "$@" "$EOL"
while [ "$1" != "$EOL" ]; do
opt="$1"; shift
case "$opt" in
# options
-h|--host) assert_argument "$1" "$opt"; rpchost="$1"; shift;;
-p|--proposer) proposer='true';;
-v|--verbose) verbose='true';;
-n|--nextepoch) nextepoch='true';;
# processing
-|''|[!-]*) set -- "$@" "$opt";;
--*=*) set -- "${opt%%=*}" "${opt#*=}" "$@";;
-[!-]?*) set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@";;
--) while [ "$1" != "$EOL" ]; do set -- "$@" "$1"; shift; done;;
-*) usage_error "unknown option: '$opt'";;
*) usage_error "this should NEVER happen ($opt)";;
esac
done
shift
fi
# helper functions
function join_by {
local d=${1-} f=${2-}
if shift 2; then
printf %s "$f" "${@/#/$d}"
fi
}
function split_by {
local delimiter=${1-}
local str=${2-}
local handler=$3
local s=$str$delimiter
while [[ $s ]]; do
"${handler}" "${s%%"$delimiter"*}"
s=${s#*"$delimiter"};
done;
}
current_time=$(date +%s)
validators=$@
if [ "$validators" = "" ]; then
echo "No validator index specified."
exit
fi
validators_str=$(join_by , $validators)
read -ra validators_arr <<< "$validators"
echo "RPC Host: $rpchost"
echo "Validators: $validators_str"
echo "Current Time: $current_time"
# get genesis time & calculate slot / epoch number
genesis_time=$(curl -s http://$rpchost/eth/v1/beacon/genesis | sed 's/.*"genesis_time":"\{0,1\}\([^,"]*\)"\{0,1\}.*/\1/')
slot_time=12
slot_timeout=$(expr $slot_time - \( \( $current_time - $genesis_time \) % $slot_time \) )
current_slot=$(expr \( $current_time - $genesis_time \) \/ \( $slot_time \) )
current_epoch=$(expr $current_slot \/ 32 )
current_index=$(expr $current_slot \% 32)
next_epoch=$(expr $current_epoch + 1 )
epoch_timeout=$(expr \( \( 32 - $current_index - 1 \) \* $slot_time \) + $slot_timeout)
echo "Genesis Time: $genesis_time"
echo "Current Epoch: $current_epoch"
echo "Current Slot: $current_slot (idx: $current_index)"
echo "Next Epoch in: $epoch_timeout sec"
echo "Next Slot in: $slot_timeout sec"
echo ""
# get duties
current_att=0
current_prop=0
next_att_slot=0
next_prop_slot=0
function handle_attestation_duty {
local vidx=$(echo $1 | sed 's/.*"validator_index":"\{0,1\}\([^,"]*\)"\{0,1\}.*/\1/')
local slot=$(echo $1 | sed 's/.*"slot":"\{0,1\}\([^,"]*\)"\{0,1\}.*/\1/')
if [[ "$vidx" == ?(-)+([[:digit:]]) ]]; then
if [ $verbose = "true" ]; then
local duty_eta=$(expr \( \( $slot - $current_slot - 1 \) \* $slot_time \) + $slot_timeout )
local eta_str=""
if [ $duty_eta -gt 0 ]; then
eta_str=" ETA: $duty_eta sec"
elif [ $duty_eta -gt $(expr 0 - $slot_time) ]; then
eta_str=" ETA: now!"
fi
local slot_idx=$(expr $slot \% 32)
echo "Validator: $vidx Attestation Slot: $slot (idx: $slot_idx) $eta_str"
fi
if [ $slot -gt $current_slot ]; then
if [ $slot -lt $next_att_slot ] || [ $next_att_slot -eq 0 ]; then
next_att_slot=$slot
fi
elif [ $slot -eq $current_slot ]; then
current_att=$vidx
fi
fi
}
function handle_proposer_duty {
local vidx=$(echo $1 | sed 's/.*"validator_index":"\{0,1\}\([^,"]*\)"\{0,1\}.*/\1/')
local slot=$(echo $1 | sed 's/.*"slot":"\{0,1\}\([^,"]*\)"\{0,1\}.*/\1/')
if [[ "$vidx" == ?(-)+([[:digit:]]) ]] && printf '%s\0' "${validators_arr[@]}" | grep -Fxqz -- "$vidx"; then
if [ $verbose = "true" ]; then
local duty_eta=$(expr \( \( $slot - $current_slot - 1 \) \* $slot_time \) + $slot_timeout )
local eta_str=""
if [ $duty_eta -ge 0 ]; then
eta_str=" ETA: $duty_eta sec"
elif [ $duty_eta -gt $(expr 0 - $slot_time) ]; then
eta_str=" ETA: now!"
fi
local slot_idx=$(expr $slot \% 32)
echo "Validator: $vidx Proposal Slot: $slot (idx: $slot_idx) $eta_str"
fi
if [ $slot -gt $current_slot ]; then
if [ $slot -lt $next_prop_slot ] || [ $next_prop_slot -eq 0 ]; then
next_prop_slot=$slot
fi
elif [ $slot -eq $current_slot ]; then
current_prop=$vidx
fi
fi
}
# current epoch duties
if [ $verbose = "true" ]; then
echo "Epoch $current_epoch duties:"
fi
duties_json=$(curl -s -X POST http://$rpchost/eth/v1/validator/duties/attester/$current_epoch -H 'Content-Type: application/json' -d "[$validators_str]")
split_by "},{" "$duties_json" "handle_attestation_duty"
if [ "$proposer" = "true" ]; then
duties_json=$(curl -s http://$rpchost/eth/v1/validator/duties/proposer/$current_epoch)
split_by "},{" "$duties_json" "handle_proposer_duty"
fi
if [ $verbose = "true" ]; then
echo ""
fi
# next epoch duties
if [ $nextepoch = "true" ] || [ $next_att_slot -eq 0 ]; then
if [ $verbose = "true" ]; then
echo "Epoch $next_epoch duties:"
fi
duties_json=$(curl -s -X POST http://$rpchost/eth/v1/validator/duties/attester/$next_epoch -H 'Content-Type: application/json' -d "[$validators_str]")
split_by "},{" "$duties_json" "handle_attestation_duty"
if [ "$proposer" = "true" ]; then
duties_json=$(curl -s http://$rpchost/eth/v1/validator/duties/proposer/$next_epoch)
split_by "},{" "$duties_json" "handle_proposer_duty"
fi
if [ $verbose = "true" ]; then
echo ""
fi
fi
# print summary
if [ "$current_att" -gt 0 ]; then
echo "Attestation scheduled for current slot! (Validator: $current_att)"
fi
echo "Next Attestation Slot: $next_att_slot"
if [ "$proposer" = "true" ]; then
if [ "$current_prop" -gt 0 ]; then
echo "Proposal scheduled for current slot! (Validator: $current_prop)"
fi
echo "Next Proposal Slot: $next_prop_slot"
fi
if [ "$next_prop_slot" -gt 0 ] && [ "$next_prop_slot" -lt "$next_att_slot" ]; then
next_duty_slot=$next_prop_slot
else
next_duty_slot=$next_att_slot
fi
if [ $next_duty_slot -gt 0 ]; then
remianing_slots=$(expr $next_duty_slot - $current_slot - 1)
echo "Remaining Slots: $remianing_slots"
remaining_time=$(expr \( $remianing_slots \* $slot_time \) + $slot_timeout )
echo "Remaining Time: $remaining_time sec"
fi
Heya, Thanks for the credits 😁
Just a few words about the script: I'm not a shell scripter and the script is definitely not production ready. The json "parsing" with regex masks hurts my eyes 😂. It was more a quick and dirty helper script for myself.
Anyway it shows how attestation & proposer duties can be fetched via the beacon node api. It would be nice to have something similar, but with proper JSON parsing and some error handling and stuff...
And it should check for sync committee contributions as well using this api: /eth/v1/validator/duties/sync/{epoch}
@pk910 These has been now open for a while, but we finnaly got around adding this with the next version & we would like to give you a little image credit in there - given that you are fine that?
It will look smth like this:
And be part of the Staking page:
P.S.: If you have another wish, we have a great Japanese artist - who as soon as he has more time, could turn this into something more fun - if you hand us some inspiration :)
Used with Rc.19 # further development tracked in #858