-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[WIP] Withdrawals pull. #2759
[WIP] Withdrawals pull. #2759
Conversation
minor Merge and forkchoice updates release
I don't know if this is the right issue for it, but we should make some estimations on:
|
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.
An option with a ring-buffer plus historical_roots
accumulator also worth considering, IMO
Right @mkalinin, I was also considering a double batched merkle accumulator (like historic roots). One reason I would like to try this other method first (commitmnt container) is that the claim process/logic will likely be much simpler because it will just look like a merkle tree, constantly growing. Additionally, it's not immediately clear when to do the batching, but that can be solved relatively easily. |
Co-authored-by: Mikhail Kalinin <[email protected]>
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.
Great work!
I haven't started to review the content yet. Just want to remind you of the CI setting earlier.
Actually, user may utilize historical batches to build a persistent proof with the merkle tree solution:
|
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.
some nitpicking.
the logic looks good to me with bare-eye review atm. need to add more test cases to verify it.
specs/capella/beacon-chain.md
Outdated
|
||
| Name | Value | Unit | Duration | | ||
| - | - | :-: | :-: | | ||
| `WITHDRAWAL_RECEIPT_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | withdrawal receipts| |
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.
Need to be added to preset files.
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.
| `WITHDRAWAL_RECEIPT_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | withdrawal receipts| | |
| `WITHDRAWAL_RECEIPT_LIMIT` | `uint64(2**40)` (= 1,099,511,627,776) | withdrawal receipts | |
| Name | Value | Unit | Duration | | ||
| - | - | :-: | :-: | |
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.
| Name | Value | Unit | Duration | | |
| - | - | :-: | :-: | | |
| Name | Value | Unit | | |
| - | - | :-: | |
If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == CAPELLA_FORK_EPOCH`, | ||
an irregular state change is made to upgrade to Capella. | ||
|
||
The upgrade occurs after the completion of the inner loop of `process_slots` that sets `state.slot` equal to `CAPELLA_FORK_EPOCH * SLOTS_PER_EPOCH`. | ||
Care must be taken when transitioning through the fork boundary as implementations will need a modified [state transition function](../phase0/beacon-chain.md#beacon-chain-state-transition-function) that deviates from the Phase 0 document. | ||
In particular, the outer `state_transition` function defined in the Phase 0 document will not expose the precise fork slot to execute the upgrade in the presence of skipped slots at the fork boundary. Instead the logic must be within `process_slots`. |
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.
These words seem from Altair specs. I think seeing Phase 0 here could be a little confusing. In Merge specs, we've changed the wording.
|
||
## Introduction | ||
|
||
Capella is a consensus-layer upgrade containin a number of features related |
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.
Capella is a consensus-layer upgrade containin a number of features related | |
Capella is a consensus-layer upgrade containing a number of features related |
Regarding partial withdrawals: there has been a fair amount of discussion on how this could be achieved with minimal additional complexity on the beacon chain. For ease of reading I'll refer to the partial withdrawal of funds above 32 Ether in a validator as "skimming". Any early discussion regarding skimming was to allow a validator to skim at the same time they proposed a block. Although simple, it has several downsides. Most importantly, it provides no assurance as to when skimming for any given validator will take place: due to the random nature of proposer duties, one validator may skim twice in a month, whereas another may have to wait half a year. Another downside is that it requires the block to be proposed: if the validator misses the block proposal for any reason (or the block is proposed but fails to make it on-chain) then the opportunity for skimming is lost. These downsides are exacerbated with higher numbers of active validators. Given this, it seems that a more reliable method of generating withdrawals would be nice. Manual operations to carry out skimming may appear attractive, however this requires a new operation, new p2p channels, additional block space etc. so should be avoided if possible. One option is to have a regular, controlled skim of all eligible* validators on a periodic basis. For example, if the period was 1024 epochs then at the end of each epoch in the period 1/1024 of the validators would be processed, with each eligible validator in the set having a withdrawal receipt generated and made available to the execution layer for processing. This removes the requirement for a new operation and all of the additional complexity and weight that goes with it, and maintains a regular schedule for rewards to be skimmed. Additional load on the beacon node should be minimal due to the small number of validators processed per epoch, and if this is a concern then the period could be increased accordingly. Having a system for partial withdrawals is important to avoid validators churning through the exit and activation queues to retrieve rewards, but adding to complexity and weight of the beacon chain any more than necessary is not desired and the proposed mechanism achieves the former whilst avoiding the latter. *For a validator to be eligible it would need to be |
release v1.1.7
activation_epoch: Epoch | ||
exit_epoch: Epoch | ||
withdrawable_epoch: Epoch # When validator can withdraw funds | ||
withdrawn_epoch: Epoch # [New in Capella] |
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.
Why do this, instead of just zeroing out the validator once it's withdrawn?
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.
It may be useful to later reuse the validator index. (Oh just realized it's in the PR description)
@djrtwo @ralexstokes To clarify the remaining TODO, you're looking for an implementation:
I think that can be done, I can give it a try maybe tomorrow. |
CommitmentContainer was not the right fit here since we need to commit to all state contents, including the merkle stack contents. Simply caching the root works fine in this case. Mirrored the deposit contract merkle-stack approach:
Extra: since we don't have to gas-golf as much: after processing all withdrawals, cache the new latest withdrawal-tree root in the BeaconState (so light-clients can proof it easily, and everyone can access it without re-computing) Not sure if we can carry over formal verification easily, but it's the same thing. Besides testing the merkle-updates (or formal verification) we'll need some integration tests (e.g. produce the proof for a withdrawal) |
```python | ||
class WithdrawalReceipt(Container): | ||
index: WithdrawalReceiptIndex | ||
address: ExecutionAddress |
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 wonder if it would make sense making this Bytes32
preparing for the possibility of "address space extension"?
It has some downsides:
- The receipt is now packed, given 64 + 160 + 256 bits of values.
- The deposit mechanism is still locked in to 160-bit addresses anyway, and likely many other places on the beacon chain too.
capella: impl withdrawal tree like deposit tree
closing in favor of the Push method #2836 |
First of the withdrawal features to be specified. Feature metatracking issue here -- #2758
Fork has code-name -- Capella. I'm assuming Merge will have a B-star-name so putting a C-star-name placeholder for now. "Withdrawals" is too confusing of a placeholder name.
During the epoch transition, if a validator has 0x01 withdrawal credentials and is withdrawable, fully withdraw the validator -- i.e. create a withdrawal receipt and add it to the state, and zero out the validator balance
Some details to note:
withdrawal_receipts
(e.g. the root) to be exposed in EL for normal EL TX to consume to move the ETH into the end accountindex
(always increasing) included inWithdrawalReceipt
so that a simple bitfield (of lengthmax_successful_withdrawal_receipt_index
) can be used to track consumed receipts in ELwithdraw
function but not use entire balance (to be developed in subsequent PR)todo:
withdrawn_epoch
toValidator
. This will be useful for any sort of validator index reuse (e.g. safe to be reused after 50k epochs)