Merge pull request #3308 from saltiniroberto/add_get_boundary_block

Add get_checkpoint_block to the fork choice spec
This commit is contained in:
Hsiao-Wei Wang
2023-05-01 17:16:00 +08:00
committed by GitHub
6 changed files with 94 additions and 31 deletions

View File

@@ -170,7 +170,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert block.slot > finalized_slot
# Check block is a descendant of the finalized block at the checkpoint finalized slot
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
finalized_checkpoint_block = get_checkpoint_block(
store,
block.parent_root,
store.finalized_checkpoint.epoch,
)
assert store.finalized_checkpoint.root == finalized_checkpoint_block
# Check the block is valid and compute the post-state
state = pre_state.copy()

View File

@@ -82,7 +82,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert block.slot > finalized_slot
# Check block is a descendant of the finalized block at the checkpoint finalized slot
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
finalized_checkpoint_block = get_checkpoint_block(
store,
block.parent_root,
store.finalized_checkpoint.epoch,
)
assert store.finalized_checkpoint.root == finalized_checkpoint_block
# [New in Deneb]
# Check if blob data is available

View File

@@ -18,6 +18,7 @@
- [`get_current_slot`](#get_current_slot)
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start)
- [`get_ancestor`](#get_ancestor)
- [`get_checkpoint_block`](#get_checkpoint_block)
- [`get_weight`](#get_weight)
- [`get_voting_source`](#get_voting_source)
- [`filter_block_tree`](#filter_block_tree)
@@ -190,6 +191,17 @@ def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
return root
```
#### `get_checkpoint_block`
```python
def get_checkpoint_block(store: Store, root: Root, epoch: Epoch) -> Root:
"""
Compute the checkpoint block for epoch ``epoch`` in the chain of block ``root``
"""
epoch_first_slot = compute_start_slot_at_epoch(epoch)
return get_ancestor(store, root, epoch_first_slot)
```
#### `get_weight`
```python
@@ -276,10 +288,15 @@ def filter_block_tree(store: Store, block_root: Root, blocks: Dict[Root, BeaconB
voting_source.epoch + 2 >= current_epoch
)
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
finalized_checkpoint_block = get_checkpoint_block(
store,
block_root,
store.finalized_checkpoint.epoch,
)
correct_finalized = (
store.finalized_checkpoint.epoch == GENESIS_EPOCH
or store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
or store.finalized_checkpoint.root == finalized_checkpoint_block
)
# If expected finalized/justified, add to viable block-tree and signal viability to parent.
@@ -440,8 +457,7 @@ def validate_on_attestation(store: Store, attestation: Attestation, is_from_bloc
assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot
# LMD vote must be consistent with FFG vote target
target_slot = compute_start_slot_at_epoch(target.epoch)
assert target.root == get_ancestor(store, attestation.data.beacon_block_root, target_slot)
assert target.root == get_checkpoint_block(store, attestation.data.beacon_block_root, target.epoch)
# Attestations can only affect the fork choice of subsequent slots.
# Delay consideration in the fork choice until their slot is in the past.
@@ -504,7 +520,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert block.slot > finalized_slot
# Check block is a descendant of the finalized block at the checkpoint finalized slot
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
finalized_checkpoint_block = get_checkpoint_block(
store,
block.parent_root,
store.finalized_checkpoint.epoch,
)
assert store.finalized_checkpoint.root == finalized_checkpoint_block
# Check the block is valid and compute the post-state
state = pre_state.copy()

View File

@@ -317,7 +317,7 @@ The following validations MUST pass before forwarding the `signed_beacon_block`
- _[REJECT]_ The block's parent (defined by `block.parent_root`) passes validation.
- _[REJECT]_ The block is from a higher slot than its parent.
- _[REJECT]_ The current `finalized_checkpoint` is an ancestor of `block` -- i.e.
`get_ancestor(store, block.parent_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
`get_checkpoint_block(store, block.parent_root, store.finalized_checkpoint.epoch)
== store.finalized_checkpoint.root`
- _[REJECT]_ The block is proposed by the expected `proposer_index` for the block's slot
in the context of the current shuffling (defined by `parent_root`/`slot`).
@@ -356,7 +356,7 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_
(a client MAY queue aggregates for processing once block is retrieved).
- _[REJECT]_ The block being voted for (`aggregate.data.beacon_block_root`) passes validation.
- _[IGNORE]_ The current `finalized_checkpoint` is an ancestor of the `block` defined by `aggregate.data.beacon_block_root` -- i.e.
`get_ancestor(store, aggregate.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
`get_checkpoint_block(store, aggregate.data.beacon_block_root, finalized_checkpoint.epoch)
== store.finalized_checkpoint.root`
@@ -425,9 +425,9 @@ The following validations MUST pass before forwarding the `attestation` on the s
(a client MAY queue attestations for processing once block is retrieved).
- _[REJECT]_ The block being voted for (`attestation.data.beacon_block_root`) passes validation.
- _[REJECT]_ The attestation's target block is an ancestor of the block named in the LMD vote -- i.e.
`get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(attestation.data.target.epoch)) == attestation.data.target.root`
`get_checkpoint_block(store, attestation.data.beacon_block_root, attestation.data.target.epoch) == attestation.data.target.root`
- _[IGNORE]_ The current `finalized_checkpoint` is an ancestor of the `block` defined by `attestation.data.beacon_block_root` -- i.e.
`get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
`get_checkpoint_block(store, attestation.data.beacon_block_root, store.finalized_checkpoint.epoch)
== store.finalized_checkpoint.root`

View File

@@ -479,7 +479,7 @@ def test_voting_source_within_two_epoch(spec, state):
- store.voting_source[block_root].epoch != store.justified_checkpoint.epoch, and
- store.unrealized_justifications[block_root].epoch >= store.justified_checkpoint.epoch, and
- store.voting_source[block_root].epoch + 2 >= current_epoch, and
- store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
- store.finalized_checkpoint.root == get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
"""
test_steps = []
# Initialization
@@ -536,8 +536,11 @@ def test_voting_source_within_two_epoch(spec, state):
assert store.unrealized_justifications[last_fork_block_root].epoch >= store.justified_checkpoint.epoch
# assert store.voting_source[last_fork_block_root].epoch + 2 >= \
# spec.compute_epoch_at_slot(spec.get_current_slot(store))
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert store.finalized_checkpoint.root == spec.get_ancestor(store, last_fork_block_root, finalized_slot)
assert store.finalized_checkpoint.root == spec.get_checkpoint_block(
store,
last_fork_block_root,
store.finalized_checkpoint.epoch
)
assert spec.get_head(store) == last_fork_block_root
yield 'steps', test_steps
@@ -552,7 +555,7 @@ def test_voting_source_beyond_two_epoch(spec, state):
- store.voting_source[block_root].epoch != store.justified_checkpoint.epoch, and
- store.unrealized_justifications[block_root].epoch >= store.justified_checkpoint.epoch, and
- store.voting_source[block_root].epoch + 2 < current_epoch, and
- store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
- store.finalized_checkpoint.root == get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
"""
test_steps = []
# Initialization
@@ -617,8 +620,11 @@ def test_voting_source_beyond_two_epoch(spec, state):
assert store.unrealized_justifications[last_fork_block_root].epoch >= store.justified_checkpoint.epoch
# assert store.voting_source[last_fork_block_root].epoch + 2 < \
# spec.compute_epoch_at_slot(spec.get_current_slot(store))
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert store.finalized_checkpoint.root == spec.get_ancestor(store, last_fork_block_root, finalized_slot)
assert store.finalized_checkpoint.root == spec.get_checkpoint_block(
store,
last_fork_block_root,
store.finalized_checkpoint.epoch
)
assert spec.get_head(store) == correct_head
yield 'steps', test_steps
@@ -641,7 +647,7 @@ def test_incorrect_finalized(spec, state):
# Check that the store doesn't allow for a head block that has:
# - store.voting_source[block_root].epoch == store.justified_checkpoint.epoch, and
# - store.finalized_checkpoint.epoch != GENESIS_EPOCH, and
# - store.finalized_checkpoint.root != get_ancestor(store, block_root, finalized_slot)
# - store.finalized_checkpoint.root != get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
test_steps = []
# Initialization
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
@@ -718,7 +724,11 @@ def test_incorrect_finalized(spec, state):
assert store.voting_source[last_fork_block_root].epoch == store.justified_checkpoint.epoch
assert store.finalized_checkpoint.epoch != spec.GENESIS_EPOCH
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
assert store.finalized_checkpoint.root != spec.get_ancestor(store, last_fork_block_root, finalized_slot)
assert store.finalized_checkpoint.root != spec.get_checkpoint_block(
store,
block_root,
store.finalized_checkpoint.epoch
)
assert spec.get_head(store) != last_fork_block_root
assert spec.get_head(store) == head_root

View File

@@ -352,8 +352,11 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
# NOTE: Do not call `on_tick` here
yield from add_block(spec, store, block, test_steps)
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
ancestor_at_finalized_slot = spec.get_ancestor(store, pre_store_justified_checkpoint_root, finalized_slot)
ancestor_at_finalized_slot = spec.get_checkpoint_block(
store,
pre_store_justified_checkpoint_root,
store.finalized_checkpoint.epoch
)
assert ancestor_at_finalized_slot != store.finalized_checkpoint.root
assert store.finalized_checkpoint == another_state.finalized_checkpoint
@@ -428,8 +431,11 @@ def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
for block in all_blocks:
yield from tick_and_add_block(spec, store, block, test_steps)
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
ancestor_at_finalized_slot = spec.get_ancestor(store, pre_store_justified_checkpoint_root, finalized_slot)
ancestor_at_finalized_slot = spec.get_checkpoint_block(
store,
pre_store_justified_checkpoint_root,
store.finalized_checkpoint.epoch
)
assert ancestor_at_finalized_slot == store.finalized_checkpoint.root
assert store.finalized_checkpoint == another_state.finalized_checkpoint
@@ -857,10 +863,18 @@ def test_incompatible_justification_update_start_of_epoch(spec, state):
# Now add the blocks & check that justification update was triggered
for signed_block in signed_blocks:
yield from tick_and_add_block(spec, store, signed_block, test_steps)
finalized_slot = spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
assert spec.get_ancestor(store, last_block_root, finalized_slot) == state.finalized_checkpoint.root
justified_slot = spec.compute_start_slot_at_epoch(state.current_justified_checkpoint.epoch)
assert spec.get_ancestor(store, last_block_root, justified_slot) != state.current_justified_checkpoint.root
finalized_checkpoint_block = spec.get_checkpoint_block(
store,
last_block_root,
state.finalized_checkpoint.epoch,
)
assert finalized_checkpoint_block == state.finalized_checkpoint.root
justified_checkpoint_block = spec.get_checkpoint_block(
store,
last_block_root,
state.current_justified_checkpoint.epoch,
)
assert justified_checkpoint_block != state.current_justified_checkpoint.root
assert store.finalized_checkpoint.epoch == 4
assert store.justified_checkpoint.epoch == 6
@@ -934,10 +948,18 @@ def test_incompatible_justification_update_end_of_epoch(spec, state):
# Now add the blocks & check that justification update was triggered
for signed_block in signed_blocks:
yield from tick_and_add_block(spec, store, signed_block, test_steps)
finalized_slot = spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
assert spec.get_ancestor(store, last_block_root, finalized_slot) == state.finalized_checkpoint.root
justified_slot = spec.compute_start_slot_at_epoch(state.current_justified_checkpoint.epoch)
assert spec.get_ancestor(store, last_block_root, justified_slot) != state.current_justified_checkpoint.root
finalized_checkpoint_block = spec.get_checkpoint_block(
store,
last_block_root,
state.finalized_checkpoint.epoch,
)
assert finalized_checkpoint_block == state.finalized_checkpoint.root
justified_checkpoint_block = spec.get_checkpoint_block(
store,
last_block_root,
state.current_justified_checkpoint.epoch,
)
assert justified_checkpoint_block != state.current_justified_checkpoint.root
assert store.finalized_checkpoint.epoch == 4
assert store.justified_checkpoint.epoch == 6