Skip to content

ePBS side-effects on Lighthouse #8630

@dapplion

Description

@dapplion

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/100 do 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_root is possible, we might want to add another query param to be used with slot? (probably not necessary)

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_org as get_advanced_hot_state_from_cache(re_org_parent_block, slot)
  • HotColdDB::get_advanced_hot_state

For michael

  • Q: Why is HotColdDB::get_advanced_hot_state used 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 state
  • State(block_root, slot, true): Post block state
  • State(block_root, slot + 1, false): Pre-state of the child if empty payload
  • State(block_root, slot + 1, true): Pre-state of the child if full payload
  • State(parent(block_root), slot + 1, true): Pre-state of the next slot if block_root is 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.

Image

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions