# Gloas ePBS breaks dependant root?
Before Gloas there's a unique post-state per tuple `(block_root, slot)`. After Gloas there are two possible post-states, one if the slot is `Full` and one if it's `Empty`.
Now the outcome of `process_epoch` depends on wether the payload of the last block is Full or not.
After Gloas, the first block in epoch N may choose to:
- build on top of the last block of the previous epoch + empty
- build on top of the last block of the previous epoch + full
Is `dependant_root` capable of specifying those two cases?
dependant root usage in the Beacon API is specified [here](https://github.com/ethereum/beacon-APIs/blob/339eea96b41c787dad47765fc781303fb40aa886/apis/eventstream/index.yaml#L51-L55)
```json
data: {
"slot": "10",
"block": "0x9a2fefd2fdb57f74993c7780ea5b9030d2897b615b89f808011ca5aebed54eaf",
"state": "0x600e852a08c1200654ddf11025f1ceacb3c2e74bdd5c630cde0838b2591b69f9",
"epoch_transition": false,
"previous_duty_dependent_root": "0x5e0043f107cb57913498fbf2f99ff55e730bf1e151f02f221e977c91a90a0e91",
"current_duty_dependent_root": "0x5e0043f107cb57913498fbf2f99ff55e730bf1e151f02f221e977c91a90a0e91",
"execution_optimistic": false
}
```
```py
previous_duty_dependent_root = get_block_root_at_slot(
state,
compute_start_slot_at_epoch(epoch - 1) - 1
)
```
```py
current_duty_dependent_root = get_block_root_at_slot(
state,
compute_start_slot_at_epoch(epoch) - 1
)
```
Just setting `*_dependent_root` is now insufficient to specify a unique `process_epoch` outcome. Let's define the post state of a block advanced to a certain slot considering if its payload is present or not as `post_state(block_root, slot, payload_present)`. We can assert that in all cases:
```
post_state(block_root, slot, true) != post_state(block_root, slot, false)
```
Now let's define `compute_current_shuffling(state)` and `compute_next_shuffling` as functions that output the attester shufflings for the state's current and next epoch.
Do the shufflings change based on the payload status of the block?
```
compute_current_shuffling(post_state(block_root, slot, true))
?=
compute_current_shuffling(post_state(block_root, slot, false))
```
```
compute_next_shuffling(post_state(block_root, slot, true))
?=
compute_next_shuffling(post_state(block_root, slot, false))
```
## Does payload status actually change the shufflings?
Processing the execution payload changes the state slightly: specifically
```py
state.latest_block_header.state_root = previous_state_root
..
for_ops(requests.deposits, process_deposit_request)
for_ops(requests.withdrawals, process_withdrawal_request)
for_ops(requests.consolidations, process_consolidation_request)
..
state.builder_pending_withdrawals.append(payment.withdrawal)
state.builder_pending_payments[SLOTS_PER_EPOCH + state.slot % SLOTS_PER_EPOCH] = BuilderPendingPayment()
..
state.execution_payload_availability[state.slot % SLOTS_PER_HISTORICAL_ROOT] = 0b1
state.latest_block_hash = payload.block_hash
```
```py
def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
state.pending_deposits.append(PendingDeposit(..))
```
```py
def process_withdrawal_request(state: BeaconState, withdrawal_request: WithdrawalRequest) -> None:
if is_full_exit_request and pending_balance_to_withdraw == 0:
# exit_epoch is at least 1 + MAX_SEED_LOOKAHEAD into the future
exit_queue_epoch = compute_exit_epoch_and_update_churn(state, validator.effective_balance)
initiate_validator_exit(state, index)
else:
withdrawable_epoch = Epoch(exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
state.pending_partial_withdrawals.append(
PendingPartialWithdrawal(.., withdrawable_epoch=withdrawable_epoch)
)
```
```py
def process_consolidation_request(state: BeaconState, consolidation_request: ConsolidationRequest):
if is_valid_switch_to_compounding_request(state, consolidation_request):
switch_to_compounding_validator(state, source_index)
return
else:
source_validator.exit_epoch = compute_consolidation_epoch_and_update_churn(..)
source_validator.withdrawable_epoch = Epoch(source_validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
state.pending_consolidations.append(PendingConsolidation(..))
```
Does that affect `process_epoch`?
```py
# Deposits need to be finalized, so they can't be executed in the very next epoch
process_pending_deposits(state)
# No, the consolidation does not get executed until `source.withdrawable_epoch > next_epoch`
# which can't happen in the very next epoch
process_pending_consolidations(state)
# No, the payment gets processed in the next epoch, does not affect now
process_builder_pending_payments(state)
```
After Fulu the proposers get computed in process_epoch and written in the state
```py
def process_proposer_lookahead(state: BeaconState) -> None:
last_epoch_start = len(state.proposer_lookahead) - SLOTS_PER_EPOCH
# Shift out proposers in the first epoch
state.proposer_lookahead[:last_epoch_start] = state.proposer_lookahead[SLOTS_PER_EPOCH:]
# Fill in the last epoch with new proposer indices
last_epoch_proposers = get_beacon_proposer_indices(
state, Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD + 1)
)
state.proposer_lookahead[last_epoch_start:] = last_epoch_proposers
```
At the end of epoch N, we compute proposers for epoch N + 2. The list of active incides depends on the activation status of validators at epoch N + 2, and the effective balance at the end of `process_epoch` of the end of epoch N.
```py
def get_beacon_proposer_indices(
state: BeaconState, epoch: Epoch
) -> Vector[ValidatorIndex, SLOTS_PER_EPOCH]:
"""
Return the proposer indices for the given ``epoch``.
"""
indices = get_active_validator_indices(state, epoch)
seed = get_seed(state, epoch, DOMAIN_BEACON_PROPOSER)
return compute_proposer_indices(state, epoch, seed, indices)
```
Processing the execution payload can't change the balance of any validator in that epoch. Nor it can change the active status before `1 + MIN_SEED_LOOKAHEAD`, so the shuffling remains stable.
On a preliminary look it seems that the shufflings are stable, so we can say that:
```
compute_current_shuffling(post_state(block_root, slot, true))
==
compute_current_shuffling(post_state(block_root, slot, false))
```
```
compute_next_shuffling(post_state(block_root, slot, true))
==
compute_next_shuffling(post_state(block_root, slot, false))
```
but I would appreciate more eyes on the topic.