Linked with GitHub
# Validator withdrawals meta-spec
"Meta-spec" for beacon chain validator withdrawals to the EVM, following a "push" architecture.
This document outlines a proposal to implement withdrawals of ETH from the beacon chain to the EVM execution layer. Several changes are required across clients and this document serves as one place that specifies the entire set of changes. Refer to links below for more information about detailed changes at each layer of the overall protocol stack.
Validators deposit ETH into the beacon chain and are rewarded additional ETH for the correct validation of the beacon chain. They should be able to move this ETH from the beacon chain back into the EVM. There are a variety of security concerns around *when* staked ETH is eligible for withdrawal and this meta-spec assumes the consensus layer handles these security concerns.
The high-level flow for withdrawn ETH is from the consensus layer through the Engine API to the execution layer. Importantly, data flows one way! Data is not passed from one stage to the other unless it passes uncondtional validation that the operation should be applied.
### Withdrawal flow
The withdrawal flow presented in this meta-spec begins when a validator on the beacon chain can safely withdraw their ETH. There are conditions that can trigger full or partial withdrawals of validator balances, and when these conditions are met a "receipt" of this action is placed into a queue in the beacon state. This receipt contains the necessary details to effect the withdrawal at the execution layer, namely the receipient execution layer address and the amount of ETH withdrawn in Gwei. The receipt also contains a monotonically increasing index that uniquely labels the withdrawal in the set of all withdrawals.
Withdrawals are dequeued from this queue in the beacon state where a consensus layer validation enforces strict rate-limiting so that the execution layer only has to process a fixed (small) amount of withdrawals in any given execution block. This block-level validation removes even more scheduling surface from the execution client, which can simply assume any amount of withdrawals contained in a consensus-valid block are themselves valid and can be executed as provided.
The block producer for a given slot must determine which withdrawals are dequeued in that slot (if any) and provide them (along with the rest of the necessary block inputs) when requesting an execution client to construct an execution payload. At this point in time, the block builder reads the withdrawal receipts from the beacon state and converts them into an execution-layer-friendly format (in particular, converting a little-endian Gwei value into a big-endian Wei value).
The requisite withdrawals are passed via the Engine API as system-level "operations" to the execution client who then incorporates them into the execution block, applying the effects to the EVM state. Importantly, these operations are never gossiped independently or held in any kind of mempool like user-level transactions. They are only serialized outside the Engine API when an execution client is syncing execution blocks from other execution peers who pass the operations in the block body.
These operations have different semantics than user-level transactions. Withdrawals are processed a bit like the coinbase of an execution block, where a balance increase in the amount specified in the receipt is applied to the recipient specified in the receipt. This balance increase is unconditional and must not fail as the execution client cannot receive invalid withdrawals if all of the previous validations hold.
Links to more detailed specifications relevant to each layer of the protocol stack are given here:
### Consensus layer
See this PR for a sketch of how push withdrawals will work at the consensus layer:
### Engine API
See this PR for proposed changes to the Engine API:
### Execution layer
The preferred path for representing withdrawals at the execution layer is currently under active discussion.
The above prose follows the path of [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895) but there is another option leveraging more of the existing transaction infrastructure by including withdrawals as a new [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) transaction type. This approach is specified in [EIP-4863](https://eips.ethereum.org/EIPS/eip-4863).
Update (04/04/2022): the core developers have elected to follow the route of EIP-4895 with *push* withdrawals.
#### Unresolved questions
An unspecified part of the design involves EVM logging of withdrawals. Adding a log for each withdrawal provides much better UX for validators.
If option 1 is pursued, then the EVM logging facility is directly available and can simply slot into the existing commitment schemes, receipt types, etc.
If option 2 is pursued, then [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895) must be extended with an additional operations "receipts" trie that is also committed to in the block header. A similar approach to handling the transactions receipts trie can be used but does mean new code paths that increase surface for potential bugs and implies new tooling must be constructed to consume these logs.
Update (04/04/2022): the current favored route just ignores in-protocol logging in lieu of extra-protocol logging (i.e. just processing the data in a block). this processing is facilitated by the `index` field included in a withdrawal.
#### Option 1
Withdrawals as new transaction type:
Update (04/04/2022): this route is not favored due to complexity
#### Option 2
Withdrawals as new system-level "operation" type:
Update (04/04/2022): this route involves more client development resources but is overall simpler in complexity with fewer moving parts, so it is currently the preferred solution. it is considered "CFI" for Shanghai.