Exit a validator
Exiting permanently removes a validator from the network. Once the exit is processed, it stops earning rewards, and its whole balance is sent to its withdrawal address. There are two ways to exit:
- With the validator's signing key, using Prysm. It costs nothing. You can submit the exit right away, or sign it now and submit it later. See Submit a voluntary exit and Sign an exit to submit later.
- From the withdrawal address, with a request sent from your wallet. It doesn't need the signing key, for example, when a staking service holds it, but it costs a small fee. See Exit from your withdrawal address.
Once submitted, you can’t cancel an exit, and an exited validator can never validate again. Double-check the public keys you select.
Before you begin
- Check that the validator has a withdrawal address (credentials starting with
0x01or0x02). With0x00credentials, the balance stays locked until you add one. See Convert a0x00validator to0x01. - The validator must have been active for at least 256 epochs (about 27 hours).
- To exit with the signing key: a synced Prysm beacon node (gRPC on
127.0.0.1:4000by default) and the validator's wallet.
Submit a voluntary exit
-
Keep the validator client running. It must keep attesting until the exit takes effect, or it loses balance.
-
Run the exit command:
./prysm.sh prysmctl validator exit \--wallet-dir=<WALLET_DIR> \--wallet-password-file=<WALLET_PASSWORD_FILE> \--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> \--public-keys=<VALIDATOR_PUBKEY>.\prysm.bat prysmctl validator exit `--wallet-dir=<WALLET_DIR> `--wallet-password-file=<WALLET_PASSWORD_FILE> `--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> `--public-keys=<VALIDATOR_PUBKEY>./prysm.sh validator accounts voluntary-exit \--wallet-dir=<WALLET_DIR> \--wallet-password-file=<WALLET_PASSWORD_FILE> \--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> \--public-keys=<VALIDATOR_PUBKEY>.\prysm.bat validator accounts voluntary-exit `--wallet-dir=<WALLET_DIR> `--wallet-password-file=<WALLET_PASSWORD_FILE> `--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> `--public-keys=<VALIDATOR_PUBKEY>Replace
<BEACON_NODE_GRPC_ADDRESS>with your beacon node's gRPC address:127.0.0.1:4000for a beacon node on the same machine with default settings.--public-keystakes a comma-separated list. Leave it out to pick keys from a menu.--exit-allexits every key in the wallet.--public-keystakes a comma-separated list. Leave it out to pick keys from a menu.--exit-allexits every key in the wallet. -
Confirm. Prysm lists the keys and asks:
===============CONFIRMATION NEEDED===============continue with the voluntary exit? (y/n)Type
y. -
Read the result:
INFO accounts: Voluntary exit was successful pubkey=<SHORT_PUBKEY> url=https://beaconcha.in/validator/<VALIDATOR_PUBKEY_WITHOUT_0X>INFO accounts: Voluntary exits were successful count=<NUMBER_OF_EXITS>INFO accounts: Voluntary exit was successful pubkey=<SHORT_PUBKEY> url=https://hoodi.beaconcha.in/validator/<VALIDATOR_PUBKEY_WITHOUT_0X>INFO accounts: Voluntary exits were successful count=<NUMBER_OF_EXITS>There is one
Voluntary exit was successfulline per key. Open itsurlto follow the exit.A key that can't exit logs
Could not perform voluntary exit for account ...with the reason.
Sign an exit to submit later
You can sign an exit now and keep it, without sending it to the network. The validator keeps validating until someone submits the signed exit. Use this to:
- Exit without the keys. Keep the signed exit with your records, so you can exit even if the validator machine or its wallet is lost.
- Hand the exit to someone else. A staking provider can give each staker a signed exit, so the staker can exit without the provider's help and without ever holding the signing key.
-
Sign the exit:
./prysm.sh prysmctl validator exit \--wallet-dir=<WALLET_DIR> \--wallet-password-file=<WALLET_PASSWORD_FILE> \--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> \--public-keys=<VALIDATOR_PUBKEY> \--exit-json-output-dir=<OUTPUT_DIR>.\prysm.bat prysmctl validator exit `--wallet-dir=<WALLET_DIR> `--wallet-password-file=<WALLET_PASSWORD_FILE> `--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> `--public-keys=<VALIDATOR_PUBKEY> `--exit-json-output-dir=<OUTPUT_DIR>./prysm.sh validator accounts voluntary-exit \--wallet-dir=<WALLET_DIR> \--wallet-password-file=<WALLET_PASSWORD_FILE> \--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> \--public-keys=<VALIDATOR_PUBKEY> \--exit-json-output-dir=<OUTPUT_DIR>.\prysm.bat validator accounts voluntary-exit `--wallet-dir=<WALLET_DIR> `--wallet-password-file=<WALLET_PASSWORD_FILE> `--beacon-rpc-provider=<BEACON_NODE_GRPC_ADDRESS> `--public-keys=<VALIDATOR_PUBKEY> `--exit-json-output-dir=<OUTPUT_DIR>--exit-json-output-dirmakes the command write each signed exit to<OUTPUT_DIR>instead of submitting it. Prysm creates the folder if it doesn't exist.--exit-json-output-dirmakes the command write each signed exit to<OUTPUT_DIR>instead of submitting it. Prysm creates the folder if it doesn't exist.The command still needs a synced beacon node: it gets the validator's index from it. The exit is valid from the current epoch.
-
Confirm. Prysm asks the same question as for a normal exit. Type
y. -
Read the result:
INFO accounts: Signed voluntary exit files were written to <OUTPUT_DIR>. No exits were broadcast to the network. The validators listed will NOT exit until these files are submitted to a beacon node.There is one file per key, named
validator-exit-<VALIDATOR_INDEX>.json:{"message":{"epoch":"<EPOCH>","validator_index":"<VALIDATOR_INDEX>"},"signature":"0x..."} -
Store the file somewhere safe and offline, or give it to the person who will submit it.
To exit, submit the file to the Beacon API of any synced beacon node, Prysm or not:
curl -s -X POST \
-H "Content-Type: application/json" \
-d @<OUTPUT_DIR>/validator-exit-<VALIDATOR_INDEX>.json \
http://127.0.0.1:3500/eth/v1/beacon/pool/voluntary_exits
curl.exe -s -X POST `
-H "Content-Type: application/json" `
-d '@<OUTPUT_DIR>\validator-exit-<VALIDATOR_INDEX>.json' `
http://127.0.0.1:3500/eth/v1/beacon/pool/voluntary_exits
An empty 200 response means the beacon node accepted the exit and shares it with the network. From there, it's the same as a normal exit: keep the validator client running until the exit takes effect.
Exit from your withdrawal address
If you don't have the signing key (for example, with a staking service), the withdrawal address of a 0x01 or 0x02 validator can trigger the exit instead. Prysm and your keys are not involved. The request costs a small fee.
The network ignores the request, and doesn't refund the fee if:
- the validator has been active for less than 256 epochs (about 27 hours), or is already exiting;
- a partial withdrawal for this validator is still waiting in the queue.
Open Validator actions on the launchpad (https://launchpad.ethereum.org/en/validator-actions), connect the wallet that controls the withdrawal address, select the validator, and choose Exit validator.
Open the Exit page of the EthStaker console (https://hoodi.console.ethstaker.org/exit), connect the wallet that controls the withdrawal address, then select the validator.
Type the address yourself. Websites that offer to "help" with this step are phishing.
Sync committees
A sync committee is chosen one period (about 27 hours) in advance, from active validators only. A validator chosen before its exit epoch for the current or next period remains a member after the exit, even if it wasn’t on a committee when it exited. It must sign until that period ends, up to about 54 hours after the exit. It’s rewarded for each signature and penalized for every slot it misses. The same applies to a slashed validator.
Before you stop the validator client or delete the keys, check that the validator is in neither the current nor the next sync committee. Every command must print false:
curl -s http://127.0.0.1:3500/eth/v1/beacon/states/head/sync_committees | jq '.data.validators | map(tonumber) | any(. == <VALIDATOR_INDEX>)'
NEXT=$(( $(curl -s http://127.0.0.1:3500/eth/v1/beacon/headers/head | jq -r '.data.header.message.slot') / 32 + 256 ))
curl -s "http://127.0.0.1:3500/eth/v1/beacon/states/head/sync_committees?epoch=$NEXT" | jq '.data.validators | map(tonumber) | any(. == <VALIDATOR_INDEX>)'
curl.exe -s http://127.0.0.1:3500/eth/v1/beacon/states/head/sync_committees | jq '.data.validators | map(tonumber) | any(. == <VALIDATOR_INDEX>)'
$NEXT = [math]::Floor([long](curl.exe -s http://127.0.0.1:3500/eth/v1/beacon/headers/head | jq -r '.data.header.message.slot') / 32) + 256
curl.exe -s "http://127.0.0.1:3500/eth/v1/beacon/states/head/sync_committees?epoch=$NEXT" | jq '.data.validators | map(tonumber) | any(. == <VALIDATOR_INDEX>)'
If one prints true, keep the validator client running and check again after the period ends. Prysm's validator client keeps signing for an exited or slashed key as long as it's in a sync committee.
What happens next
- Exit queue. The validator waits for its exit epoch: a few epochs when the queue is short, longer when many validators are exiting. Keep the validator client running.
- Exited. After the exit epoch, the validator no longer attests or proposes. About 27 hours later (256 epochs) it becomes withdrawable. Before you stop the validator client for these keys, check sync committees.
- Withdrawn. The next automatic withdrawal sweep sends the full balance to the withdrawal address.
Remove the keys from the wallet
Once the validator is withdrawable and in no sync committee (see Sync committees), you can delete its keys from the wallet:
./prysm.sh validator accounts delete \
--wallet-dir=<WALLET_DIR> \
--delete-public-keys=<VALIDATOR_PUBKEY>
.\prysm.bat validator accounts delete `
--wallet-dir=<WALLET_DIR> `
--delete-public-keys=<VALIDATOR_PUBKEY>
Deleting a key from the wallet doesn't exit the validator. Don't do it before the exit: the validator stays active and loses balance while nothing signs for it.
Check that it works
curl -s http://127.0.0.1:3500/eth/v1/beacon/states/head/validators/<VALIDATOR_PUBKEY_OR_INDEX> \
| jq '.data.status'
curl.exe -s http://127.0.0.1:3500/eth/v1/beacon/states/head/validators/<VALIDATOR_PUBKEY_OR_INDEX> |
jq '.data.status'
Right after submitting, the status may stay active_ongoing until a block includes your exit. It then moves through active_exiting, exited_unslashed, withdrawal_possible, and finally withdrawal_done.