# Issue: Add operation for withdrawal credentials change operation ### What? New operation and signed message is proposed for Eth2, `BLSSetWithdrawal`, which could permanently change `withdrawal_credentials`: #### `BLSSetWithdrawal` ```python class BLSSetWithdrawal(Container): bls_withdrawal_pubkey: Bytes32 # Reveal of withdrawal public key withdrawal_credentials: Bytes32 # New withdrawal credentials, shouldn't start with BLS_WITHDRAWAL_PREFIX (0x00) validator_index: ValidatorIndex ``` And `SignedBLSSetWithdrawal` message: #### `SignedBLSSetWithdrawal` ```python class SignedBLSSetWithdrawal(Container): message: BLSSetWithdrawal signature: BLSSignature # Signed by withdrawal BLS key ``` ### Why? It's already confirmed that at least one extra withdrawal target option will be supported with merge of PR #2149 "Eth1 withdrawal credentials (0x01)" by @djrtwo. While new validators could submit deposits using this option, there were already tons of deposits before this PR was merged and some of their owners could be interested in Eth1 withdrawal. Moreover, for some parties it could be a best flow of withdrawal control during validator lifecycle to start with BLS key `0x00` withdrawal credentials and change it's target to Eth1 address later with `0x01` or another options introduced in future. ### How? - we verify that current validator’s `withdrawal_credentials` is started with `BLS_WITHDRAWAL_PREFIX (0x00)` - we verify that new credentials are not started with `BLS_WITHDRAWAL_PREFIX (0x00)` There are several assessments when choosing such behavior of this operation: - Why don’t allow change to another BLS public key? There are 2 most obvious usages for `0x00` to another `0x00` swaps: + Validator's withdrawal key was compromised. For some validators it would mean the validator signing key could be under attack too and the safest way is to withdraw now. Changing credentials to explicit target works in the safest way in this case + Validators could be traded on some market by withdrawal pubkey change. Currently there is no mechanism to change validator's signing key and it's not known whether it will be introduced in future. Also it provides additional load on beacon chain network and block size making this type of message to fight for its place under the sun with `Deposit`, `Attestation` and other more important network message types. - Whether to check that `withdrawal_credentials` is in the currently supported range. The answer should be “no”, as the deposit contract already doesn’t check it. It’s a kind of risk for the minutest number of user errors, but by changing this we could open a way to a number of bugs that could affect all users. Draft implementation: ```python def process_bls_set_withdrawal(state: BeaconState, signed_bls_set_withdrawal: SignedBLSSetWithdrawal) -> None: set_withdrawal = signed_bls_set_withdrawal.message validator = state.validators[set_withdrawal.validator_index] # Verify the validator has BLS pubkey commitment assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX # Verify the validator is active assert is_active_validator(validator, get_current_epoch(state)) # Verify exit has not been initiated assert validator.exit_epoch == FAR_FUTURE_EPOCH # Verify new withdrawal credentials doesn't start with BLS_WITHDRAWAL_PREFIX assert set_withdrawal.withdrawal_credentials[:1] != BLS_WITHDRAWAL_PREFIX # Verify BLS pubkey reveal is correct assert hash(set_withdrawal.withdrawal_pubkey)[1:] == validator.withdrawal_credentials[1:] # Verify signature domain = get_domain(state, DOMAIN_BLS_SET_WITHDRAWAL, get_current_epoch(state)) signing_root = compute_signing_root(set_withdrawal, domain) assert bls.Verify(set_withdrawal.withdrawal_pubkey, signing_root, signed_bls_set_withdrawal.signature) # Update withdrawal credentials validator.withdrawal_credentials = set_withdrawal.withdrawal_credentials ``` ### Some concerns We have two options here, and I'm not sure, which way should we go: - allow change of credentials only for validators that doesn't initiate the exit - allow change of credentials for exited validators Second option requires extra processing of withdrawals after `withdrawal_credentials` are changed for already exited validators. It’s not straightforward and requires thoughtful implementation to avoid bugs. For example, when we have 2 active withdrawal options, we should verify that one was not processed before `withdrawal_credentials` change, though Eth1 withdrawal is planned to be automatically on validator exit without extra messages on Beacon Chain, while BLS key withdrawal will require new message with processing. ### Some important notes - this approach means once `withdrawal_credentials` are changed from `BLS_WITHDRAWAL_PREFIX (0x00)` to any other, withdrawal target could not be changed anymore. But this is already concreted by PR #2149 - `BLSSetWithdrawal` could be added already, as nothing prevents to submit `withdrawal_credentials` to Deposit Contract today with a prefix other than `BLS_WITHDRAWAL_PREFIX (0x00)` ### Links [Simple eth1 withdrawals (beacon-chain centric)](https://ethresear.ch/t/simple-eth1-withdrawals-beacon-chain-centric/8256) with `BLSSetWithdrawalAddress` proposal by @djrtwo inspiring this issue [Eth1 withdrawal credentials (0x01)](https://github.com/ethereum/eth2.0-specs/pull/2149) #2149 by @djrtwo - PR merged in specs [Withdrawal credential rotation from BLS to Eth1](https://ethresear.ch/t/withdrawal-credential-rotation-from-bls-to-eth1/8722) - some alternative approaches of withdrawal credentials change [Allow withdrawal_credentials to point to an eth1 address](https://github.com/ethereum/eth2.0-specs/issues/2040) #2040 by @dapplion - Issue to add eth1 withdrawal prefix