Conversation
specs/gloas/beacon-chain.md
Outdated
| # [New in Gloas:EIP7732] | ||
| payload_expected_withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] | ||
| # [New in Gloas:EIP7732] | ||
| ptc_lookbehind: Vector[Vector[ValidatorIndex, PTC_SIZE], 2] |
There was a problem hiding this comment.
Could be previous_ptc, current_ptc which is ugly as well, but more like previous forks structures.
There was a problem hiding this comment.
I've just made this change. I prefer this.
specs/gloas/beacon-chain.md
Outdated
| process_epoch(state) | ||
| state.slot = Slot(state.slot + 1) | ||
| # [New in Gloas:EIP7732] | ||
| state.ptc_lookbehind = [state.ptc_lookbehind[1], compute_ptc(state)] |
There was a problem hiding this comment.
Could be moved to process_slot but it's uglier.
|
Personally prefer this over #4979 . It's a balance between state size and spec simplicity. |
specs/gloas/fork.md
Outdated
| # [New in Gloas:EIP7732] | ||
| onboard_builders_from_pending_deposits(post) | ||
| # [New in Gloas:EIP7732] | ||
| ptc_lookbehind[1] = compute_ptc(post) |
There was a problem hiding this comment.
Added outside because compute_ptc should only make sense on Gloas states.
| given slot. To check for PTC assignments, use | ||
| `get_ptc_assignment(state, epoch, validator_index)` where `epoch <= next_epoch`, | ||
| as PTC committee selection is only stable within the context of the current and | ||
| next epoch. |
There was a problem hiding this comment.
This sentence was factually wrong which is what started this issue. Removed the helper entirely since there is no need to specify it.
I wouldn't be so certain, the PR that adds the full lookahead has a single point where this computation is carried and no synchronization with process slots that happens at time on wall clock. The total data added per state is 0.08% (that's 0.0008) of a current beacon state in mainnet. |
| next epoch. | ||
|
|
||
| ```python | ||
| def get_ptc_assignment( |
There was a problem hiding this comment.
Leaving a note that get_ptc_assignment is still being used in three sections below.
| current slot by checking if their validator index is in `get_ptc(state)`. PTC | ||
| committee selection is only stable within the context of the current epoch. | ||
|
|
||
| ### Lookahead |
There was a problem hiding this comment.
This doesn't seem to hold anymore.
There was a problem hiding this comment.
Right above it says:
PTC committee selection is only stable within the context of the current epoch.
which means there is no 1 epoch lookahead.
There was a problem hiding this comment.
The committee selection is stable within the context of the current epoch, it doesn't mean that the epoch needs to be cached in the state. It means that any validator that wants to check if it has PTC duties in the current epoch, can do so at the beginning of the epoch. Clients will most likely implement this and cache it no matter which lookahead/lookbehind system we implement in-state.
There was a problem hiding this comment.
Lookahead section states that PTC is stable for next epoch.
There was a problem hiding this comment.
which section? I'm replying only to your comment that is based on the sentence:
current slot by checking if their validator index is in `get_ptc(state)`. PTC
committee selection is only stable within the context of the current epoch.
There was a problem hiding this comment.
Lookahead section states that PTC is stable for next epoch.
Lookahead section. I left this comment on Lookahead section.
There was a problem hiding this comment.
Ah, yeah what Github shows is confusing.
There was a problem hiding this comment.
L77-L78:
get_ptc_assignmentshould be called at the start of each epoch to get the
assignment for the next epoch (current_epoch + 1). A validator should plan for
There was a problem hiding this comment.
oh yeah that's definitely wrong.
| return compute_balance_weighted_selection( | ||
| state, indices, seed, size=PTC_SIZE, shuffle_indices=False | ||
| ) | ||
| assert slot == state.slot or slot + 1 == state.slot |
There was a problem hiding this comment.
I think this change makes get_ptc to be too restrictive on the range of slot it accepts. Validator's PTC assignment should still be determined ahead on a per-epoch basis instead of per-slot basis.
I think we should accept slot [previous slot, end slot of state's current epoch]. Maybe something like
def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]:
epoch = get_current_epoch(state)
epoch_start_slot = compute_start_slot_at_epoch(epoch)
epoch_end_slot = epoch_state_slot + SLOTS_PER_EPOCH
assert slot >= state.slot - 1 and slot < epoch_end_slot
if slot == state.slot:
return state.current_ptc
if slot + 1 == state.slot:
return state.previous_ptc
return compute_ptc(state, slot) So get_ptc_assignment can still take advantage of this.
There was a problem hiding this comment.
clients are free to simply pass the slot to conpute_ptc for caching purposes. Why should we have these off-protocol elements leaking in the spec?
OTOH one think that should be considered IMO is that if clients will anyway cache them, then most likely having the full cache in the spec is more efficient than keeping it in an ad-hoc in-memory cache that needs to be in-sync with the head state.
|
Grandine has a similar cache implemented already, so we would need to remove our cache implementation and switch to this. But my question is why do we need such a cache in the state (and specification)? Clients have a lot of other caches that are part of the client (not specification). So why is this time different? |
Because the state is flawed currently: PTC attestations are cast in slot 31, validation of gossip uses |
you can handle that with separate caches in the client but one problem is that if you load a state you can't compute the previous PTC as you'd need the effective balances of the previous epoch, having the |
Alternative to ethereum#4992 that addresses ethereum#4979's epoch-boundary PTC bug with minimal state changes: - Add single `previous_ptc` field to BeaconState (~4KB vs 8KB/ethereum#4992, 256KB/ethereum#4979) - New `compute_ptc(state, slot)` extracted from `get_ptc` for on-demand computation - New `process_ptc_update` at START of `process_epoch` (before balance updates) - Modified `get_ptc` returns cached `previous_ptc` for epoch boundary case - No per-slot rotation in `process_slots` (unlike ethereum#4992) - Preserves `get_ptc_assignment` validator duties API (unlike ethereum#4992) - Tightened `get_ptc_assignment` assert to `current_epoch <= epoch <= next_epoch` Key insight: only the PTC for the last slot of the previous epoch needs caching because `process_payload_attestation` enforces `data.slot + 1 == state.slot` and effective balances only change at epoch boundaries. Co-authored-by: Nico Flaig <nflaig@users.noreply.github.com>
Alternative to ethereum#4992 that addresses ethereum#4979's epoch-boundary PTC bug with minimal state changes: - Add single `previous_ptc` field to BeaconState (~4KB vs 8KB/ethereum#4992, 256KB/ethereum#4979) - New `compute_ptc(state, slot)` extracted from `get_ptc` for on-demand computation - New `process_ptc_update` at START of `process_epoch` (before balance updates) - Modified `get_ptc` returns cached `previous_ptc` for epoch boundary case - No per-slot rotation in `process_slots` (unlike ethereum#4992) - Preserves `get_ptc_assignment` validator duties API (unlike ethereum#4992) - Tightened `get_ptc_assignment` assert to `current_epoch <= epoch <= next_epoch` Key insight: only the PTC for the last slot of the previous epoch needs caching because `process_payload_attestation` enforces `data.slot + 1 == state.slot` and effective balances only change at epoch boundaries. Co-authored-by: Nico Flaig <nflaig@users.noreply.github.com>
|
Closing in lieu of #4979. |
Alternative to #4979 that only keeps track of 2 committees (8KB per state)