Skip to content

Commit

Permalink
Add signing exit messages (eth-educators#1304)
Browse files Browse the repository at this point in the history
  • Loading branch information
yorickdowne authored Apr 15, 2023
1 parent 71ad3c5 commit db84c47
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 46 deletions.
6 changes: 0 additions & 6 deletions .eth/ethdo/create-withdrawal-change.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ while true; do
echo "The mnemonic needs to be 24 or 12 words. You can try again or hit Ctrl-C to abort."
continue
fi
read -rp "Please verify your validator mnemonic : " __mnemonic2
if [[ "${__mnemonic}" = "${__mnemonic2}" ]]; then
break
else
echo "Mnemonic did not match. You can try again or hit Ctrl-C to abort."
fi
done
echo "You may have used a 25th word for the mnemonic. This is not the passphrase for the"
echo "validator signing keys. When in doubt, say no to the next question."
Expand Down
226 changes: 189 additions & 37 deletions ethd
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,79 @@ prep-keyimport() {
done
}

__i_haz_ethdo() {
var="COMPOSE_FILE"
value=$(sed -n -e "s/^${var}=\(.*\)/\1/p" ".env" || true)
# Literal match intended
# shellcheck disable=SC2076
if [[ ! "${value}" =~ "ethdo.yml" ]]; then
echo "Please edit the .env file and make sure \":ethdo.yml\" is added to the \"COMPOSE_FILE\" line"
echo "For example, \"nano .env\" will open the nano text editor with the \".env\" file loaded."
echo "Without it, this step cannot be run"
echo
read -rp "Do you want me to make this change for you? (n/y)" yn
case $yn in
[Yy] );;
* ) exit 1;;
esac
COMPOSE_FILE="${value}:ethdo.yml"
set_value_in_env
echo "Your COMPOSE_FILE now reads ${COMPOSE_FILE}"
fi
}


__keys_usage() {
echo "Call keymanager with an ACTION, one of:"
echo " list"
echo " Lists the public keys of all validators currently loaded into your validator client"
echo " import"
echo " Import all keystore*.json in .eth/validator_keys while loading slashing protection data"
echo " in slashing_protection*.json files that match the public key(s) of the imported validator(s)"
echo " delete 0xPUBKEY | all"
echo " Deletes the validator with public key 0xPUBKEY from the validator client, and exports its"
echo " slashing protection database. \"all\" deletes all detected validators instead"
echo
echo " get-recipient 0xPUBKEY"
echo " List fee recipient set for the validator with public key 0xPUBKEY"
echo " Validators will use FEE_RECIPIENT in .env by default, if not set individually"
echo " set-recipient 0xPUBKEY 0xADDRESS"
echo " Set individual fee recipient for the validator with public key 0xPUBKEY"
echo " delete-recipient 0xPUBKEY"
echo " Delete individual fee recipient for the validator with public key 0xPUBKEY"
echo
echo " get-gas 0xPUBKEY"
echo " List execution gas limit set for the validator with public key 0xPUBKEY"
echo " Validators will use the client's default, if not set individually"
echo " set-gas 0xPUBKEY amount"
echo " Set individual execution gas limit for the validator with public key 0xPUBKEY"
echo " delete-gas 0xPUBKEY"
echo " Delete individual execution gas limit for the validator with public key 0xPUBKEY"
echo
echo " get-api-token"
echo " Print the token for the keymanager API running on port ${KEY_API_PORT:-7500}."
echo " This is also the token for the Prysm Web UI"
echo
echo " create-prysm-wallet"
echo " Create a new Prysm wallet to store keys in"
echo " get-prysm-wallet"
echo " Print Prysm's wallet password"
echo
echo " prepare-address-change"
echo " Create an offline-preparation.json with ethdo"
echo " send-address-change"
echo " Send a change-operations.json with ethdo, setting the withdrawal address"
echo
echo " sign-exit from-keystore [--offline]"
echo " Create pre-signed exit messages with ethdo, from keystore files in ./.eth/validator_keys"
}

keys() {
if [[ "$#" -eq 0 || "$1" == "help" || "$1" == "-h" || "$1" == "--help" ]]; then
__keys_usage
return
fi

__owner_uid=$(id -u "${OWNER}")
if [ "${1:-}" = "import" ]; then
shift
Expand All @@ -1209,25 +1281,7 @@ keys() {
docompose rm --force validator
up
elif [ "${1:-}" = "prepare-address-change" ]; then
var="COMPOSE_FILE"
value=$(sed -n -e "s/^${var}=\(.*\)/\1/p" ".env" || true)
# Literal match intended
# shellcheck disable=SC2076
if [[ ! "${value}" =~ "ethdo.yml" ]]; then
echo "Please edit the .env file and make sure \":ethdo.yml\" is added to the \"COMPOSE_FILE\" line"
echo "For example, \"nano .env\" will open the nano text editor with the \".env\" file loaded."
echo "Without it, this step cannot be run"
echo
read -rp "Do you want me to make this change for you? (n/y)" yn
case $yn in
[Yy] );;
* ) exit 1;;
esac
COMPOSE_FILE="${value}:ethdo.yml"
set_value_in_env
echo "Your COMPOSE_FILE now reads ${COMPOSE_FILE}"
fi
# We need things up so we can query
__i_haz_ethdo
up
echo "Generating offline prep file"
docompose run --rm ethdo validator credentials set --prepare-offline
Expand Down Expand Up @@ -1261,27 +1315,125 @@ keys() {
echo "Copy the contents of ./.eth/ethdo to a USB drive, and prepare a Linux Live USB to safely enter your mnemonic."
echo "Please see https://eth-docker.net/Support/ChangingWithdrawalCredentials for details"
elif [ "${1:-}" = "send-address-change" ]; then
var="COMPOSE_FILE"
value=$(sed -n -e "s/^${var}=\(.*\)/\1/p" ".env" || true)
# Literal match intended
# shellcheck disable=SC2076
if [[ ! "${value}" =~ "ethdo.yml" ]]; then
echo "Please edit the .env file and make sure \":ethdo.yml\" is added to the \"COMPOSE_FILE\" line"
echo "For example, \"nano .env\" will open the nano text editor with the \".env\" file loaded."
echo "Without it, this step cannot be run"
echo
read -rp "Do you want me to make this change for you? (n/y)" yn
case $yn in
[Yy] );;
* ) exit 1;;
esac
COMPOSE_FILE="${value}:ethdo.yml"
set_value_in_env
echo "Your COMPOSE_FILE now reads ${COMPOSE_FILE}"
fi
__i_haz_ethdo
# We need things up so we can query
up
docompose run --rm ethdo validator credentials set
elif [ "${1:-}" = "sign-exit" ] && [ "${2:-}" = "from-keystore" ]; then
__i_haz_ethdo
# We need things up so we can query
up

__offline=""
if echo "$@" | grep -q '.*--offline.*' 2>/dev/null ; then
__offline="--offline"
fi

__non_interactive=0
if echo "$@" | grep -q '.*--non-interactive.*' 2>/dev/null ; then
__non_interactive=1
fi

if [ ${__non_interactive} = 1 ]; then
__password="${KEYSTORE_PASSWORD}"
__justone=1
else
__num_files=$(find .eth/validator_keys -maxdepth 1 -type f -name 'keystore*.json' | wc -l)
if [ "$__num_files" -eq 0 ]; then
echo "No keystore*.json files found in .eth/validator_keys/"
echo "Nothing to do"
exit 0
fi

if [ "$__num_files" -gt 1 ]; then
while true; do
read -rp "Do all validator keys have the same password? (y/n) " yn
case $yn in
[Yy]* ) __justone=1; break;;
[Nn]* ) __justone=0; break;;
* ) echo "Please answer yes or no.";;
esac
done
else
__justone=1
fi
if [ "${__justone}" -eq 1 ]; then
while true; do
read -srp "Please enter the password for your validator key(s): " __password
echo
read -srp "Please re-enter the password: " __password2
echo
if [ "${__password}" == "${__password2}" ]; then
break
else
echo "The two entered passwords do not match, please try again."
echo
fi
done
echo
fi
fi

docompose run --rm ethdo --base-dir /app/wallet wallet delete --wallet=exits >/dev/null 2>&1
docompose run --rm ethdo --base-dir /app/wallet wallet create --wallet=exits

i=1
created=0
failed=0
mkdir -p .eth/exit_messages
for __keyfile in .eth/validator_keys/keystore-*.json; do
[ -f "${__keyfile}" ] || continue # Should always evaluate true - just in case
if [ "${__justone}" -eq 0 ]; then
while true; do
read -srp "Please enter the password for your validator key stored in ${__keyfile}: " __password
echo
read -srp "Please re-enter the password: " __password2
echo
if [ "${__password}" == "${__password2}" ]; then
break
else
echo "The two entered passwords do not match, please try again."
echo
fi
echo
done
fi

__pubkey=$(docompose run --rm ethdo account import --base-dir /app/wallet --account exits/"${i}" --keystore "/app/.eth/validator_keys/$(basename "${__keyfile}")" --keystore-passphrase "${__password}" --passphrase "${__password}" --allow-weak-passphrases --verbose)
exitstatus=$?
if [ "${exitstatus}" -ne 0 ]; then
echo "Importing ${__keyfile} failed"
echo "Was the supplied password correct?"
(( i++ ))
continue
fi
__json=$(docompose run --rm ethdo validator exit --base-dir /app/wallet --validator exits/"${i}" --json --timeout 2m --passphrase "${__password}" ${__offline})
exitstatus=$?
if [ "${exitstatus}" -eq 0 ]; then
echo "${__json}" >".eth/exit_messages/${__pubkey}-exit.json"
exitstatus=$?
if [ "${exitstatus}" -eq 0 ]; then
echo "Creating an exit message for validator ${__pubkey} into file ./.eth/exit_messages/${__pubkey}-exit.json succeeded"
(( created++ ))
else
echo "Error writing exit json to file ./.eth/exit_messages/${__pubkey}-exit.json"
(( failed++ ))
fi
else
echo "Creating an exit message for validator ${__pubkey} from file ${__keyfile} failed"
(( failed++ ))
fi
(( i++ ))
done
docompose run --rm ethdo --base-dir /app/wallet wallet delete --wallet=exits
echo
echo "Created pre-signed exit messages for ${created} validators"
if [ "${created}" -gt 0 ]; then
echo "You can find them in ./.eth/exit_messages"
fi
if [ "${failed}" -gt 0 ]; then
echo "Failed for ${failed} validators"
fi
else
# We need things up so we can query
up
Expand Down
4 changes: 4 additions & 0 deletions ethdo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ services:
image: ethdo:local
volumes:
- ./.eth:/app/.eth
- ethdo-wallet:/app/wallet
environment:
- NETWORK=${NETWORK}
- CL_NODE=${CL_NODE:-http://consensus:5052}
entrypoint:
- docker-entrypoint.sh
- /app/ethdo
- --allow-insecure-connections

volumes:
ethdo-wallet:
1 change: 1 addition & 0 deletions ethdo/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN adduser \

RUN apt-get update && apt-get install -y gosu jq

RUN mkdir -p /app/wallet
RUN chown -R ${USER}:${USER} /app

COPY ./docker-entrypoint.sh /usr/local/bin/
Expand Down
17 changes: 14 additions & 3 deletions ethdo/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,19 @@ if [[ "$*" =~ "validator credentials set" ]] && [[ ! "$*" =~ "--prepare-offline"
fi
fi

# Get just the first CL_NODE
ARGS=( "${ARGS[@]:0:1}" "--connection" "$(cut -d, -f1 <<<"${CL_NODE}")" "${ARGS[@]:1}" )
if [[ "$*" =~ "--offline" ]]; then
if [ ! -f "/app/.eth/ethdo/offline-preparation.json" ]; then
echo "Offline preparation file ./.eth/ethdo/offline-preparation.json not found"
echo "Please create it, for example with ./ethd keys prepare-address-change, and try again"
exit 1
else
cp /app/.eth/ethdo/offline-preparation.json /app
chown ethdo:ethdo /app/offline-preparation.json
fi
else
# Get just the first CL_NODE
ARGS=( "${ARGS[@]:0:1}" "--connection" "$(cut -d, -f1 <<<"${CL_NODE}")" "${ARGS[@]:1}" )
fi

gosu ethdo "${ARGS[@]}"
__result=$?
Expand All @@ -92,7 +103,7 @@ if [[ "$*" =~ "--prepare-offline" ]]; then
else
__butta="https://${NETWORK}.beaconcha.in"
fi
cp -rp /app/offline-preparation.json /app/.eth/ethdo/
cp -p /app/offline-preparation.json /app/.eth/ethdo/
chown "$uid":"$uid" /app/.eth/ethdo/offline-preparation.json
echo "The preparation file has been copied to ./.eth/ethdo/offline-preparation.json"
echo "It contains $(jq .validators[].index </app/.eth/ethdo/offline-preparation.json | wc -l) validators."
Expand Down
3 changes: 3 additions & 0 deletions vc-utils/keymanager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ usage() {
echo " Create an offline-preparation.json with ethdo"
echo " send-address-change"
echo " Send a change-operations.json with ethdo, setting the withdrawal address"
echo
echo " sign-exit from-keystore [--offline]"
echo " Create pre-signed exit messages with ethdo, from keystore files in ./.eth/validator_keys"
}

set -e
Expand Down

0 comments on commit db84c47

Please sign in to comment.