Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions specs/phase0/fast-confirmation.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,9 @@ def is_confirmed_chain_safe(fcr_store: FastConfirmationStore, confirmed_root: Ro
starting from current_epoch_observed_justified_checkpoint are LMD-GHOST safe.
"""
store = fcr_store.store
# Check if the confirmed_root is descendant of current_epoch_observed_justified_checkpoint
if not is_ancestor(
store,
get_node_for_root(confirmed_root),
get_node_for_root(fcr_store.current_epoch_observed_justified_checkpoint.root),
# Check if the confirmed_root has current_epoch_observed_justified_checkpoint in its chain
if fcr_store.current_epoch_observed_justified_checkpoint != get_checkpoint_for_block(
store, confirmed_root, fcr_store.current_epoch_observed_justified_checkpoint.epoch
):
return False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,73 @@ def test_reconfirmation_passes_with_empty_slots_prior_first_block(spec, state):
assert fcr_store.confirmed_root == fcr.head_root()

yield from fcr.get_test_artefacts()


@only_generator("too slow")
@with_all_phases_from_to(ALTAIR, GLOAS)
@with_presets([MINIMAL], reason="too slow")
@with_custom_state(
balances_fn=(lambda spec: default_balances(spec, num_validators=64)),
threshold_fn=default_activation_threshold,
)
@spec_test
@single_phase
def test_reconfirmation_fails_for_block_without_uj_checkpoint_in_chain(spec, state):
fcr = FCRTest(spec, seed=1)
store, fcr_store = fcr.initialize(state)

S = spec.SLOTS_PER_EPOCH

# Run until the last slot of epoch 2
fcr.run_slots_with_blocks_and_fast_confirmation(3 * S - 1, participation_rate=100)

# Pivot at the end of epoch 2
pivot_root = fcr.next_slot_with_block_and_fast_confirmation(
participation_rate=100, graffiti="pivot"
)

# Run till the penultimate slot of epoch 3
fcr.run_slots_with_blocks_and_fast_confirmation(S - 2, participation_rate=100)

# Create a conflicting block that justifies a checkpoint not in the chain of confirmed block
# while the block of that checkpoint is in the chain of confirmed block
pivot_attestations = []
for s in range(3 * S, fcr.current_slot()):
pivot_attestations.extend(
fcr.attest(
block_root=pivot_root, participation_rate=100, slot=s, pool_and_disseminate=False
)
)
fcr.add_and_apply_block(
parent_root=pivot_root,
graffiti="conflicting",
attestations=pivot_attestations,
release_att_pool=False,
include_atts=False,
)

# Fast confirm one block
fcr.next_slot_with_block_and_fast_confirmation(participation_rate=100)

# Create the last confirmed block in an epoch and move to the next slot
confirmed_root = fcr.next_slot_with_block(participation_rate=100, graffiti="confirmed")

# Check preconditions over confirmed_root
# From fresh epoch
assert spec.get_block_epoch(store, confirmed_root) + 1 >= fcr.current_epoch()
# Belongs to canonical chain
assert spec.is_ancestor(store, fcr.head(), confirmed_root)
# Ancestor of the previous_epoch_greatest_unrealized_checkpoint block
assert spec.is_ancestor(
store, confirmed_root, fcr_store.previous_epoch_greatest_unrealized_checkpoint.root
)
# Does not have a previous_epoch_greatest_unrealized_checkpoint in its chain
assert fcr_store.previous_epoch_greatest_unrealized_checkpoint != spec.get_checkpoint_for_block(
store, confirmed_root, fcr_store.previous_epoch_greatest_unrealized_checkpoint.epoch
)

# Run fast confirmation and ensure fall back to finality
fcr.run_fast_confirmation()
assert fcr_store.confirmed_root == store.finalized_checkpoint.root
Comment thread
mkalinin marked this conversation as resolved.

yield from fcr.get_test_artefacts()