-
Notifications
You must be signed in to change notification settings - Fork 997
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
Improve epoch processing within state transition #1043
Comments
This was the original off my one error/kludge in attestation voting. Problem here is that an committee/attester of the last slot in an epoch would have to vote on the justification data of the next epoch |
cc: @arnetheduck |
Trying to wrap my head around the problem 😂 By "vote" I'm assuming you are referring to an In option B, when |
Hmm, I fail to see this -- somehow it feels like semantically the two approaches Justin suggests should be equivalent, it is only a matter of when process_epoch is run? The only difference would be that the "state" object at SLOTS_PER_EPOCH - 1 (mod epoch) would have the epoch processed or not (this might change what a validator has to do to compute blocks. But as the next block would be in the next epoch already, Option B should still seem like the more natural one?) Assuming this is correct, I would agree with Justin that Option B seems a bit more natural and elegant, and also makes the interpretation of state.slot clearer. |
When a validator performs their duty wrt the beacon chain currently, they simply perform the state transition to the post state at the slot they are assigned, pull data from that state, put it in an attestation, and sign it. The semantics here are clear ("attest to the slot" -- perform the state transition to the slot and attest to what the state says) and are currently working very well. To move the epoch transition to the end of the last slot in the epoch rather than the beginning of the first slot in the next epoch, we break this for one slot in each epoch. There are two options if you do this --
Both of these options is inelegant and require exceptional rules in various places, whereas the current method is clean which no exceptions to the simple semantics. I'm pretty against changing this. |
Oh boy, there must be a subtle detail I'm missing! 😂
Let's be super explicit. Let's assume there is a beacon
Assuming the above explicit interpretation is correct, I think validators respect these semantics in option B. Specifically, they are attesting to
Why is aborting early necessary? I'd argue we want the state root corresponding to |
I think the detail you're missing is that the following {
# LMD GHOST vote
'beacon_block_root': 'bytes32',
# FFG vote
'source_epoch': 'uint64',
'source_root': 'bytes32',
'target_epoch': 'uint64',
'target_root': 'bytes32',
} (For the last slot in the epoch) If you change to the method you've described then |
Just to play around with this a bit more, I ran the two options through our state sim - to make what @djrtwo is pointing out more concrete, here's a dump of the state at options a and b at slot 132: Slot 132 is interesting because we can see attestations from slots 126, 127 and 128 - right around the epoch boundary. Slots 126 and 127 belong to epoch 1, while 128 is the start of epoch 2, thus in Under option A (assuming perfect attestation performance), all attestations in The screenshot is from 0.5.1, have fun with Another (very minor) difference is the following: To validate that a block is valid, one must apply it to the state. In option B, we first apply block then do epoch processing meaning that Which is "more" clean is anyone's guess :) One more possible consideration/convenience would be for all slots of an epoch, should the fields that are touched only by epoch processing stay constant? Under this assumption, option A wins - consider for example balances - under option a, I run the state transition to get to the state for a particular slot and the balances change only iff the epoch changes between state and state+1. Under option b, the last slot of the epoch will see adjusted balances. How does this affect talking / reasoning about slashings etc? What does it mean that a validator was slashed in epoch 1? should that validator be marked as slashed in all slots of epoch 1 or just the last one? If we say that someone was slashed during epoch 1, with option a that means that we must advance the state to a state that belongs to epoch 2 to see them as slashed, whereas under option a, they'll already be slashed in state 127 (but not 126, both belonging to the same epoch).. |
Another consideration is the following: if I call the helper function |
Still not groking the tradeoffs but I think this issue can be closed for now, especially post freeze 😂 |
We currently have option A (see #1018):
I suggest option B:
Option B seems to be an improvement over option A. In option B the current epoch is naturally processed at the end of the current epoch (as opposed to the start of the next epoch).
Option B is conceptually cleaner because there's no "mixing" of different epochs (which leads to confusion such as #946). It also means that the state root at the end of an epoch is the one corresponding to the end of that epoch's processing, as opposed to postponing epoch processing to the next epoch and getting frankenstein state roots on both sides of the epoch boundary (one is missing an epoch transition, the other mixes processing from different epochs).
This restructure also means that
state.slot += 1
can be incorporated withinprocess_slot(state)
which reduces moving parts to justprocess_slot
,process_block
andprocess_epoch
. cc @dankrad, @djrtwoThe text was updated successfully, but these errors were encountered: