-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add EIP: Execution layer triggerable exits #7002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
File
|
|
This is massive for liquid staking protocols and DVT setups. We've been very looking forward to this at Diva specifically This EIP would allow to manage risk much better for scenarios like loss of private keys, or scenarios where DVT validators have lost connectivity to a majority of their key shares, which could occur if there's mass censorship or downtime in a popular AWS region for example. I agree with @djrtwo that no solution I've heard of relies on this not being possible, and that a SC is an elegant workaround for any cases which might. |
EIPS/eip-7002.md
Outdated
|
|
||
| #### Exit precompile | ||
|
|
||
| The precompile requires a single `8` byte big-endian `uint64` input, aliased to `validator_index`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most, if not all, staking pools keep track of validator public key not validator_index.
Can it be triggered by the pub key (considering it takes more space)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. And EL does not trustlessly have this info without something like BEACON_ROOT.
The beacon chain does not maintain a mapping of pubkey to validator so would require a full sweep to search for the validator when validating and performing the exit. This full sweep would just be in the spec -- the clients would maintain a pubkey -> index mapping to do so efficiently. This functionality exists in some form in due to pubkey requirements of process_deposit so it's probably okay
I'll ask around about functionality and then make the spec change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely doable by some oracle, just another step pools (and others) will need to add before they can ensure EL withdrawal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to use pubkey if possible. Getting a validator index for pubkey on EL is complex but needed for staking protocols; and extra complexity here only brings gains in form of a few bytes per exit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pubkey would be a strong preference for Rocket Pool.
|
Really useful. Opens up a lot of possibilities, specifically DKG validators running on DVT. |
| ## Motivation | ||
|
|
||
| Validators have two keys -- an active key and a withdrawal credential. The active key takes the form of a BLS key, whereas the withdrawal credential can either be a BLS key (0x00) or a execution layer address (0x01). The active key is "hot", actively signing and performing validator duties, whereas the withdrawal credential can remain "cold", only performing limited operations in relation to withdrawing and ownership of the staked ETH. Due to this security relationship, the withdrawal credential ultimately is the key that owns the staked ETH and any rewards. | ||
|
|
||
| As currently specified, only the active key can initiate a validator exit. This means that in any non-standard custody relationships (i.e. active key is separate entity from withdrawal credentials), that the ultimate owner of the funds -- the possessor of the withdrawal credentials -- cannot independently choose to exit and begin the withdrawal process. This leads to either trust issues (e.g. ETH can be "held hostage" by the active key owner) or insufficient work-arounds such as pre-signed exits. Additionally, in the event that active keys are lost, a user should still be able to recover their funds by using their cold withdrawal credentials. | ||
|
|
||
| To ensure that the withdrawal credentials (owned by both EOAs and smart contracts) can trustlessly control the destiny of the staked ETH, this specification enables exits triggerable by 0x01 withdrawal credentials. | ||
|
|
||
| Note, 0x00 withdrawal credentials can be changed into 0x01 withdrawal credentials with a one-time signed message. Thus any functionality enabled for 0x01 credentials is defacto enabled for 0x00 credentials. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a note to the motivation that withdraw credentials can have complex recovery mechanisms that simultaneously protect users from both loss and theft which are not possible to private keys (e.g., time based recovery, social recovery, survivorship, etc.).
Also worth noting that by making the validator keys unnecessary for exiting, a validator can favor "protection from theft" exclusively with their validator keys without having to concern themselves with "protection from loss". At the moment, validators MUST (game theoretically) prioritize protection from loss over protection from theft and these two are often in direct opposition to each other. This means someone could have their validator keys on disk only on their heavily locked down validator node, and if the node is destroyed they can exit to recover. Right now this would be an absolutely terrible idea.
|
|
||
| The alternative designs are (1) to utilize a precompile or opcode for the functionality and write a separate specified space in the EVM -- e.g. `0xFF..FF` -- or (2) to place the required state into the block and require the previous block header as an input into the state transition function (e.g. like 1559 `base_fee`). | ||
|
|
||
| Alternative design (1) is essentially using a stateful precompile but dissociating the state into a separate address. At first glance, this split appears unnecessarily convoluted when we could store the location of the `CALL` and the associated state in the same address. That said, there might be unexpected engineering constraints around precompiles in existing clients that make this a preferable path. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more consideration here is that it'd be nice to be able to know the current fee in a smart contract, so it'd be nice to have a stateful precompile with view functions for state. That would make it pretty complex for a precompile.
I think a prerompile + separate address for storage and view functions is not a bad option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were discussing having two precompiles:
- A precompile where to perform the exit (reads and writes to (2))
- A precompile with a fee-read that has all of the state utilized by (1)
I think this reasonable. CC: @adietrichs for input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might have been answered before...when precompile vs when opcode?
EIPS/eip-7002.md
Outdated
| Sketch of spec: | ||
|
|
||
| * New operation `ExecutionLayerExit` | ||
| * Will show up in `ExecutionPayload` as a vector bound by length `MAX_EXITS_PER_BLOCK` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"vector" is a special term in SSZ. just to clarify:
| * Will show up in `ExecutionPayload` as a vector bound by length `MAX_EXITS_PER_BLOCK` | |
| * Will show up in `ExecutionPayload` as an SSZ List bound by length `MAX_EXITS_PER_BLOCK` |
EIPS/eip-7002.md
Outdated
|
|
||
| ### Consensus layer | ||
|
|
||
| In progress. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI
[WIP] CL specs side PR: ethereum/consensus-specs#3349
|
The commit d75602c (as a parent of fa0b79a) contains errors. |
|
|
||
| ### Stateful precompile | ||
|
|
||
| This specification utilizes a *stateful* precompile for simplicity and future-proofness. While precompiles are a well-known quantity, none to date have associated EVM state at the address. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be useful to explicitly list what parts of that mechanism will be more future proof (more interface-y) vs which ones are expected to be more malleable (more of an implementation) so that smart contract developers would understand what can be relayed upon.
Similar how to it's clear deposit smart contract is expected to be a staple for a long time or maybe forever, but the exact mechanism to relay deposits to beacon chain is under talks to be simplified a lot, I think implementation details can change here too. There's a decent chance that fee mechanism could change if we find out that in practice it's too high (e.g. we see that making trustless protocol is less efficient than trustful bc they have to pay a lot more for EL triggered exits) or too low (e.g. if we see it is effectively DOS'ed). The plethora of el-cl communication bands might get refactored for simplicity and uniformity as well.
E.g. as far as far as my intuition goes it would be:
More reliable parts:
- withdrawer credential owner can initiate an exit by paying a fee and providing a public key of a validator
- you can read the current fee using fee view precompile
- you provide the fee by making a call with value >= the fee
- excess ether will be returned to the address that makes the call
- there's a limited amount of exits that fit into the block
Malleable parts:
- Fee are calculated using formula ...
- amount of exits per block is ...
- exits are communicated to beacon chain using a particular mechanism ...
EIPS/eip-7002.md
Outdated
| SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) | ||
| + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1)[0:16] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) | |
| + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1)[0:16] | |
| SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 1) + SLOAD(EXIT_PRECOMPILE_ADDRESS, queue_storage_slot + 2)[0:16] |
|
My 2 cents... For sure there are persons that had their withdrawal keys compromised while they are retaining control of their validator keys. At this time, they are at an impasse: their profits can be stolen through the compromised withdrawal keys (it is a race for the first one that moves them out from the compromised withdrawal address) while their 32 ETH are "protected", because the hacker doesn't have the validator key and/or the mnemonic. Clearly this proposal would give the possibility for the hacker to gain access to the 32 ETH (it would be a race for whoever is then able to "extract" first the 32 ETH from the withdrawal address). I think that organizing a CLWP for this particular case BEFORE passing this EIP would be a good idea (and/or thinking about other solutions). |
EIPS/eip-7002.md
Outdated
| ]) | ||
| ``` | ||
|
|
||
| #### Exit precompile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In programming, "Exit" typically conveys a system shutdown. How about renaming "Exit" to "Validator Exit"?
| rlp_encoded_exit = RLP([ | ||
| RLP(source_address), | ||
| RLP(validator_pubkey), | ||
| ]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have learned in the past that the editors' preference is to write this like so:
| rlp_encoded_exit = RLP([ | |
| RLP(source_address), | |
| RLP(validator_pubkey), | |
| ]) | |
| rlp_encoded_exit = RLP([ | |
| source_address, | |
| validator_pubkey, | |
| ]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, only top rlp is prefered
EIPS/eip-7002.md
Outdated
| # Latest block body field before `exits` | ||
| rlp_encoded_field_n, | ||
|
|
||
| RLP([rlp_encoded_exit_0, ..., rlp_encoded_exit_k]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| RLP([rlp_encoded_exit_0, ..., rlp_encoded_exit_k]), | |
| [rlp_encoded_exit_0, ..., rlp_encoded_exit_k], |
|
@g11tech I see you've reviewed this a while back - it'd be nice if we could merge it given the amount of discussion that's happened on the PR |
👍 Will incorporate them wherever they seem straightforward and see if the PR can be merg e |
| 2. The list of exit operations contained in the block body **MUST** be equivalent to list of exits at the head of the exit precompile's exit message queue up to the maximum of `MAX_EXITS_PER_BLOCK`, respecting the order in the queue. This validation **MUST** be run after all transactions in the current block are processed and **MUST** be run before per-block precompile storage calculations (i.e. a call to `update_exit_precompile()`) are performed. To illustrate: | ||
|
|
||
| ```python | ||
| class ValidatorExit(object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have updated to ValidatorExit rather than just exit,
should the field names be update to validatior_exits in block/payload etc. although exits in the block is pretty clear to what is being refereed , so letting it stay
|
have added a bit of TODOs based on the conversations which could be resolved/cleaned when moving post draft stage |
Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com>
g11tech
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gtg for draft 👍
|
bot doesn't seem to working right now, going to go ahead and merge |
|
Waiting for that on @staketogether 👀 |
* add EL exits EIP * update to EIP 7002 * add discussions-to url * fix typo on body name * quick add * lint * Apply suggestions from code review Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> * EIP 7002 feedbacl * add links to referenced EIPs * eip 7002: change validator_index to validator_pubkey * fix rlp encoding * update precompile var reference * fix body rlp * apply corrections * add todos to be addressed post draft stage --------- Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> Co-authored-by: gajinder <develop@g11tech.io>
* add EL exits EIP * update to EIP 7002 * add discussions-to url * fix typo on body name * quick add * lint * Apply suggestions from code review Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> * EIP 7002 feedbacl * add links to referenced EIPs * eip 7002: change validator_index to validator_pubkey * fix rlp encoding * update precompile var reference * fix body rlp * apply corrections * add todos to be addressed post draft stage --------- Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> Co-authored-by: gajinder <develop@g11tech.io>
Gemrav
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scammers fraud alert
* add EL exits EIP * update to EIP 7002 * add discussions-to url * fix typo on body name * quick add * lint * Apply suggestions from code review Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> * EIP 7002 feedbacl * add links to referenced EIPs * eip 7002: change validator_index to validator_pubkey * fix rlp encoding * update precompile var reference * fix body rlp * apply corrections * add todos to be addressed post draft stage --------- Co-authored-by: Hsiao-Wei Wang <hsiaowei.eth@gmail.com> Co-authored-by: gajinder <develop@g11tech.io>
Add a cross-layer method to trigger validator exits from the execution layer.
Note, the consensus layer spec is just a sketch and will be implemented on the CL specs repo soon