# peep-an-eip: validator withdrawals ## draft / outline goal: - resource to explain how validator withdrawals will work and what users/validators need to do to execute them - give some narrative about how we got here ## todo - logging - eth1 analysis - https://notes.ethereum.org/@djrtwo/0x01-payable # outline - what do we mean “validator withdrawals”? - warning: generally assuming post-merge - ethereum is a proof-of-stake network - consensus layer - execution layer - consensus layer: separate layer of the protocol from the EVM execution environment - actors called “validators” form consensus by validating the chain and attesting to its correctness - necessary for consensus security that validators lock up some ETH - the “stake” - some analogy to a “principal” of a loan - currently 32 ETH - if you do a good job validating, then rewards accrue - some analogy to “interest” - how to move ETH back to execution environment? - either bc - you are done validating? - or just want to move your rewards? - designing a solution to this problem: validator withdrawals - how to implement? - first, when is a validator allowed to withdraw? - second, how is that signaled from the consensus layer to execution layer? - (as it originates on CL, need to signal to EL somehow where effects take place) - third, where does the actual ETH come from? - as new ETH is created at the consensus layer - when withdraw? - need some consensus conditions met - ensure validators remain accountable - but assuming a withdraw would still keep incentive for a validator to be honest - can withdraw the extra funds - being generic here, bc you can have “full” or “partial” withdrawals - “all of the stake” - or just “the rewards” - examples: - validator has successfully “exited” the active validator set - both an exit queue *and* some delay to allow for catching “trailing slashing” - they can withdraw all of their balance - validator is active but has some balance over the “consensus stake weight” of 32 ETH - assuming it is *safe* to withdraw a validator’s ETH, just make a note of it in the beacon state - “put a receipt into some list of receipts” - the task then becomes: - how to make EL aware of the receipts in this list? - important aside for validators: - will need to change withdrawal credentials from `0x00` to `0x01` - indicates how withdrawals can be authenticated - move from BLS signature (e.g. cold storage key protecting stake) to any execution address - open pr: https://github.com/ethereum/consensus-specs/pull/2855 - how to signal? - lots of possible designs - big decision point: - “pull” vs. “push” semantics - another decision point: - how to credit the ETH in the EVM state? - analogy: pile of ETH - do you want to “pull” it from the consensus layer into the execution layer - or, do you want to have it “pushed” to you from the consensus layer to the execution layer - intuition here: someone else “does the work” - what does pull look like? - as the execution layer owner (could be a smart contract) of the validator’s funds, I initiate a regular transaction that tells the system: “I would like to consume the i’th withdrawal in the list” - the “system” needs to know what the list is - and also to track which withdrawals in this list have been consumed - otherwise you could double-spend withdrawals and print eth :( - how does the “system” learn? - well, luckily, the beacon state has a cryptographic commitment - Merkle tree structure with SSZ - so can make proofs about receipts in the beacon state, IF this state root is exposed to the EL - this was the intent of https://eips.ethereum.org/EIPS/eip-4788 - as we will see, ended up going the “push” route, so no immediate need for this EIP - although lots of other cool applications becomes possible if the EVM gets the state root, so I’d like to see sooner or later - how does the “system” keep track? - a few options on structure but ultimately, *somewhere* in the EVM keep some state, e.g. a bitfield to track which receipts in the withdrawal list have already been consumed - “stateful precompile” - no prior precedent - how to credit ETH? - assume a stateful precompile: - either pull ETH “out of thin air” - but again, no real precedent other than awarding the block subsidy to coinbase - a “quick and dirty” idea: - the precompile could have `MAX_WEI` eth and just pull down from this “endowment” - just looks like a normal balance transfer from a smart contract, this happens all the time - what would it look like end-to-end? - user: here is the receipt at index `i` that says I am owed X eth from a withdrawal and a proof that it is a valid withdrawal against the latest beacon state root - system (e.g. precompile): let me verify the proof, and make sure this index has not already been redeemed. If it all looks good, then I will send you the ETH (perhaps out of my huge endowment) - ok, so this would work but: - “stateful precompile” - entirely new EVM concept - would complicate testing, etc. - esp if this thing has `MAX_WEI` and or arbitrary “credit” powers - scheduling is on the user - they pay gas and take up block space from other users - so for these reasons, current favored solution is the “push” style semantics - what does push look like? - rather than a simple list in the beacon state, withdrawals are now put into a *queue* - and the consensus layer becomes responsible for *dequeuing* withdrawals at a certain rate and placing them into the execution payload - so now, the execution layer (which already does a lot) - does not have to track which withdrawals have been consumed - can use block space for other transactions - doesn’t need to manage synchronizing the beacon state root into the EVM somehow - doesn’t need some novel “stateful precompile” concept - from the EL perspective, much simpler — just apply the balance increases from the withdrawals - very much like we already do w/ coinbase transactions - to answer the prior key questions for this stage of the process: - how does the system learn? - it just processes the payload (like it already does) - how does the system keep track? - it doesn’t, this logic is now handled by the consensus layer - better division of responsibilites - how to credit ETH? - again, a few options you can imagine but simplest is to just treat like a coinbase “transaction” - what does it look like end-to-end? - user: does nothing - system: when I encounter a withdrawal in the execution payload, I just increase the balance according to the details in the receipt - get us to where we are now: - push-style withdrawals, managed by the CL, processed by the EL - one dangling question: how are withdrawals structured in the execution payload? - the CL will have some structure by definition of the SSZ schema (whatever goes into the beacon state) - the interface to the EL (engine API) can have whatever schema as long as it gets the relevant data across - but, we want the EL to be able to independently process execution payloads w/o having to ask the consensus layer for data - e.g. if the EL is syncing - so need some way to structure the withdrawals - how to structure withdrawals at EL? - again, “quick and dirty” and a much cleaner solution - “quick and dirty” - abuse EIP-2718-style transaction types - just make a new type that has special semantics - this was the approach in https://eips.ethereum.org/EIPS/eip-4863 - “cleaner” solution - new type of object: “operation” - looks like a transaction but is firewalled from EVM concerns - which we want - main problem w/ new txn type is that you now need special logic for processing a common concept, the transaction, but this new type of transaction doesn’t touch the actual virtual machine, unlike all other transaction types to date - also this new transaction type can “credit” ETH, which is also substantially different from existing transaction types - e.g. coinbase is not “written” down as a transaction anywhere - so, instead, prefer the much cleaner idea of “operation” - new type of thing that lives alongside transactions but it fundamentally different - bonus: symmetry to how many rollups structure themselves, so can re-use code/concepts at several layers of the stack - one final feature to look at, now that we have the high-level pipeline in place - partial withdrawals - can "skim off" excess ETH over the "consensus stake weight" of 32 ETH - will happen automatically when it is secure to do so and a given validator has excess balance - rotate over the entire val set to check every N epochs - once some ETH has been identified as withdrawable, it is put into a withdrawal receipt just like a full withdrawal - rest of the process is the same from there - open PR: https://github.com/ethereum/consensus-specs/pull/2862 - still some fine-tuning to do around exact parameters, etc. - tl;dr - CL changes: https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md - EL changes: EIP-4895: Beacon chain push withdrawals as operations - https://eips.ethereum.org/EIPS/eip-4895 - as a user / validator, you don’t need to do anything once you have switched to 0x01 credentials - withdrawn eth will simply appear where you specify, when the requisite conditions are met - e.g. no special “withdraw” operation, on top of your exit - when? - CFI for Shanghai (fork after the Merge) - https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md