Check correct fork version in LC sync protocol
- Sync committee is determined by signature_slot - Signature fork version is determined by max(signature_slot, 1) - 1 - Attested block fork version can be anything < signature_slot Old logic incorrectly derived signature fork version from signature_slot and did not subtract a slot. Extended tests to check this edge case.
This commit is contained in:
parent
ccfe576dcc
commit
43e714e60f
|
@ -387,7 +387,8 @@ def validate_light_client_update(store: LightClientStore,
|
||||||
pubkey for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys)
|
pubkey for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys)
|
||||||
if bit
|
if bit
|
||||||
]
|
]
|
||||||
fork_version = compute_fork_version(compute_epoch_at_slot(update.signature_slot))
|
fork_version_slot = max(update.signature_slot, 1) - 1
|
||||||
|
fork_version = compute_fork_version(compute_epoch_at_slot(fork_version_slot))
|
||||||
domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
|
domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
|
||||||
signing_root = compute_signing_root(update.attested_header.beacon, domain)
|
signing_root = compute_signing_root(update.attested_header.beacon, domain)
|
||||||
assert bls.FastAggregateVerify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature)
|
assert bls.FastAggregateVerify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature)
|
||||||
|
|
|
@ -668,10 +668,9 @@ def run_test_single_fork(spec, phases, state, fork):
|
||||||
# Upgrade to post-fork spec, attested block is still before the fork
|
# Upgrade to post-fork spec, attested block is still before the fork
|
||||||
attested_block = block.copy()
|
attested_block = block.copy()
|
||||||
attested_state = state.copy()
|
attested_state = state.copy()
|
||||||
state, _ = do_fork(state, spec, phases[fork], fork_epoch, with_block=False)
|
sync_aggregate, _ = get_sync_aggregate(phases[fork], state)
|
||||||
|
state, block = do_fork(state, spec, phases[fork], fork_epoch, sync_aggregate=sync_aggregate)
|
||||||
spec = phases[fork]
|
spec = phases[fork]
|
||||||
sync_aggregate, _ = get_sync_aggregate(spec, state)
|
|
||||||
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
|
|
||||||
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
|
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
|
||||||
assert test.store.finalized_header.beacon.slot == finalized_state.slot
|
assert test.store.finalized_header.beacon.slot == finalized_state.slot
|
||||||
assert test.store.next_sync_committee == finalized_state.next_sync_committee
|
assert test.store.next_sync_committee == finalized_state.next_sync_committee
|
||||||
|
@ -755,18 +754,16 @@ def run_test_multi_fork(spec, phases, state, fork_1, fork_2):
|
||||||
# ..., attested is from `fork_1`, ...
|
# ..., attested is from `fork_1`, ...
|
||||||
fork_1_epoch = getattr(phases[fork_1].config, fork_1.upper() + '_FORK_EPOCH')
|
fork_1_epoch = getattr(phases[fork_1].config, fork_1.upper() + '_FORK_EPOCH')
|
||||||
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_1_epoch) - 1)
|
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_1_epoch) - 1)
|
||||||
state, _ = do_fork(state, spec, phases[fork_1], fork_1_epoch, with_block=False)
|
state, attested_block = do_fork(state, spec, phases[fork_1], fork_1_epoch)
|
||||||
spec = phases[fork_1]
|
spec = phases[fork_1]
|
||||||
attested_block = state_transition_with_full_block(spec, state, True, True)
|
|
||||||
attested_state = state.copy()
|
attested_state = state.copy()
|
||||||
|
|
||||||
# ..., and signature is from `fork_2`
|
# ..., and signature is from `fork_2`
|
||||||
fork_2_epoch = getattr(phases[fork_2].config, fork_2.upper() + '_FORK_EPOCH')
|
fork_2_epoch = getattr(phases[fork_2].config, fork_2.upper() + '_FORK_EPOCH')
|
||||||
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_2_epoch) - 1)
|
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_2_epoch) - 1)
|
||||||
state, _ = do_fork(state, spec, phases[fork_2], fork_2_epoch, with_block=False)
|
sync_aggregate, _ = get_sync_aggregate(phases[fork_2], state)
|
||||||
|
state, block = do_fork(state, spec, phases[fork_2], fork_2_epoch, sync_aggregate=sync_aggregate)
|
||||||
spec = phases[fork_2]
|
spec = phases[fork_2]
|
||||||
sync_aggregate, _ = get_sync_aggregate(spec, state)
|
|
||||||
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
|
|
||||||
|
|
||||||
# Check that update applies
|
# Check that update applies
|
||||||
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
|
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
|
||||||
|
|
|
@ -47,6 +47,7 @@ def _set_operations_by_dict(block, operation_dict):
|
||||||
|
|
||||||
def _state_transition_and_sign_block_at_slot(spec,
|
def _state_transition_and_sign_block_at_slot(spec,
|
||||||
state,
|
state,
|
||||||
|
sync_aggregate=None,
|
||||||
operation_dict=None):
|
operation_dict=None):
|
||||||
"""
|
"""
|
||||||
Cribbed from ``transition_unsigned_block`` helper
|
Cribbed from ``transition_unsigned_block`` helper
|
||||||
|
@ -61,6 +62,8 @@ def _state_transition_and_sign_block_at_slot(spec,
|
||||||
Thus use dict to pass operations.
|
Thus use dict to pass operations.
|
||||||
"""
|
"""
|
||||||
block = build_empty_block(spec, state)
|
block = build_empty_block(spec, state)
|
||||||
|
if sync_aggregate is not None:
|
||||||
|
block.body.sync_aggregate = sync_aggregate
|
||||||
|
|
||||||
if operation_dict:
|
if operation_dict:
|
||||||
_set_operations_by_dict(block, operation_dict)
|
_set_operations_by_dict(block, operation_dict)
|
||||||
|
@ -141,7 +144,7 @@ def state_transition_across_slots_with_ignoring_proposers(spec,
|
||||||
next_slot(spec, state)
|
next_slot(spec, state)
|
||||||
|
|
||||||
|
|
||||||
def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict=None):
|
def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=None, operation_dict=None):
|
||||||
spec.process_slots(state, state.slot + 1)
|
spec.process_slots(state, state.slot + 1)
|
||||||
|
|
||||||
assert state.slot % spec.SLOTS_PER_EPOCH == 0
|
assert state.slot % spec.SLOTS_PER_EPOCH == 0
|
||||||
|
@ -172,7 +175,12 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict=
|
||||||
assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION
|
assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION
|
||||||
|
|
||||||
if with_block:
|
if with_block:
|
||||||
return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict)
|
return state, _state_transition_and_sign_block_at_slot(
|
||||||
|
post_spec,
|
||||||
|
state,
|
||||||
|
sync_aggregate=sync_aggregate,
|
||||||
|
operation_dict=operation_dict,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return state, None
|
return state, None
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None):
|
||||||
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
||||||
spec,
|
spec,
|
||||||
signature_state,
|
signature_state,
|
||||||
signature_slot,
|
max(signature_slot, 1) - 1,
|
||||||
committee_indices[:num_participants],
|
committee_indices[:num_participants],
|
||||||
)
|
)
|
||||||
sync_aggregate = spec.SyncAggregate(
|
sync_aggregate = spec.SyncAggregate(
|
||||||
|
|
Loading…
Reference in New Issue