-
Notifications
You must be signed in to change notification settings - Fork 961
Description
I have thought for a while on how ePBS affects existing Lighthouse components in non-obvious ways that are not part of the spec diff. I may be missing some, this is hopefully food for thought for other Lighthouse devs.
State advance
An advanced pre-state for the first slot of epoch N is different depending on:
- last block of epoch N-1 is full
- last block of epoch N-1 is empty
So the state advance must choose correctly if to build on top of full / empty otherwise the advanced state is useless.
- TODO: During state advance we prime the attester cache, look into it
At the end of state avdance we store the state
beacon_chain.store.put_state(&advanced_state_root, &state)?;An advance state where last block of epoch is block_root was represented by the unique tuple (block_root, start_slot(epoch + 1))
API
- Q: When a user calls into the API and gets
/state/100do they get the state post payload or pre-payload?- A: whichever is canonical (use the state root iterator: linear roots for freezer, state summary DAG or fork choice for hot).
- Q: If the node has received the block but not the payload yet do they return the block_state or the execution_payload_state?
- A: block state, if it is canonical.
- Q: Is there going to be a way in the API to request one or the other?
- A:
state_rootis possible, we might want to add another query param to be used withslot? (probably not necessary)
- A:
Attester cache
TODO
Doesn't matter, to be deleted with #8469
State cache
The state cache is data structure is indexed by state_root which remains unique between empty / full. However it uses a BlockMap which is a map from block_root -> slot -> state_root.
Has this function
pub fn get_by_block_root(&mut self, block_root: Hash256, slot: Slot)Used by get_advanced_hot_state_from_cache used by
BeaconChain::get_state_for_re_orgasget_advanced_hot_state_from_cache(re_org_parent_block, slot)HotColdDB::get_advanced_hot_state
For michael
- Q: Why is
HotColdDB::get_advanced_hot_stateused in so many places? Why are so many components aware that this state exists?- A: it is useful in many places and efficient if DB can provide it (no need to recompute)
Pruning
TODO: Prunning assumes one state per tuple (block_root, slot)
There's a single canonical full / empty status per slot. When migrating we should only keep the summaries of the finalized chain. In the hot DB
finalized_and_descendant_state_roots_of_finalized_checkpoint
newly_finalized_state_roots computed from state_summaries_dag.ancestors_of(new_finalized_state_root) which just follows the previous_state_root chain.
Block
- Post block state
Execution payload
- Post execution payload
State {
block_root: Hash256,
slot: Slot,
is_full: bool,
}Consider that block with block_root has slot slot. The post state of that block is State(block_root, slot, false), the post state of that block's execution payload is State(block_root, slot, true). If there's a child of that block that consider the execution payload to be full, then its pre-state is State(block_root, slot + 1, true). If it considers the payload to be empty State(block_root, slot + 1, false).
State(block_root, slot, false): Post execution payload stateState(block_root, slot, true): Post block stateState(block_root, slot + 1, false): Pre-state of the child if empty payloadState(block_root, slot + 1, true): Pre-state of the child if full payloadState(parent(block_root), slot + 1, true): Pre-state of the next slot ifblock_rootis missed
HDiff back pointers
Finalized DB
required_finalized_diff_state_slots for pruning is computed based on slots, so not affected
Hot DB
May be necessary to add a bool in the summary to track empty / full. However, the summaries are unique because the summary of state root 2 has state root 1 as previous state root.
State iterators
Now the state.state_roots vector contains mixed roots -> we can just use this to access canonical states.
Additionally, we should probably delete these iterators:
Fork-choice
TODO