rework process_attestation and work through tests

This commit is contained in:
Danny Ryan 2020-02-06 12:58:21 -06:00
parent aa451778f9
commit d414aac933
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
2 changed files with 114 additions and 36 deletions

View File

@ -575,16 +575,16 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
for_ops(body.proposer_slashings, process_proposer_slashing) for_ops(body.proposer_slashings, process_proposer_slashing)
for_ops(body.attester_slashings, process_attester_slashing) for_ops(body.attester_slashings, process_attester_slashing)
# New attestation processing # New attestation processing
process_attestations(state, body, body.attestations) for_ops(body.attestations, process_attestation)
for_ops(body.deposits, process_deposit) for_ops(body.deposits, process_deposit)
for_ops(body.voluntary_exits, process_voluntary_exit) for_ops(body.voluntary_exits, process_voluntary_exit)
# See custody game spec. # See custody game spec.
process_custody_game_operations(state, body) process_custody_game_operations(state, body)
process_crosslinks(state, body.shard_transitions, body.attestations)
# TODO process_operations(body.shard_receipt_proofs, process_shard_receipt_proofs) # TODO process_operations(body.shard_receipt_proofs, process_shard_receipt_proofs)
``` ```
@ -598,6 +598,7 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
assert data.index < get_committee_count_at_slot(state, data.slot) assert data.index < get_committee_count_at_slot(state, data.slot)
assert data.index < get_active_shard_count(state) assert data.index < get_active_shard_count(state)
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.target.epoch == compute_epoch_at_slot(data.slot)
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
committee = get_beacon_committee(state, data.slot, data.index) committee = get_beacon_committee(state, data.slot, data.index)
@ -740,49 +741,46 @@ def process_crosslink_for_shard(state: BeaconState,
```python ```python
def process_crosslinks(state: BeaconState, def process_crosslinks(state: BeaconState,
block_body: BeaconBlockBody, shard_transitions: Sequence[ShardTransition],
attestations: Sequence[Attestation]) -> Set[Tuple[Shard, Root]]: attestations: Sequence[Attestation]) -> None:
winners: Set[Tuple[Shard, Root]] = set()
committee_count = get_committee_count_at_slot(state, state.slot) committee_count = get_committee_count_at_slot(state, state.slot)
for committee_index in map(CommitteeIndex, range(committee_count)): for committee_index in map(CommitteeIndex, range(committee_count)):
shard = compute_shard_from_committee_index(state, committee_index, state.slot) shard = compute_shard_from_committee_index(state, committee_index, state.slot)
# All attestations in the block for this shard # All attestations in the block for this committee/shard and current slot
shard_attestations = [ shard_attestations = [
attestation for attestation in attestations attestation for attestation in attestations
if get_shard(state, attestation) == shard and attestation.data.slot == state.slot if attestation.data.index == committee_index and attestation.data.slot == state.slot
] ]
shard_transition = block_body.shard_transitions[shard] shard_transition = shard_transitions[shard]
winning_root = process_crosslink_for_shard(state, shard, shard_transition, shard_attestations) winning_root = process_crosslink_for_shard(state, shard, shard_transition, shard_attestations)
if winning_root != Root(): if winning_root != Root():
winners.add((shard, winning_root)) # Mark relevant pending attestations as creating a successful crosslink
return winners for pending_attestation in state.current_epoch_attestations:
if (
pending_attestation.slot == state.slot and pending_attestation
and pending_attestation.data.index == committee_index
and pending_attestation.data.shard_transition_root == winning_root
):
pending_attestation.crosslink_success = True
``` ```
###### `process_attestations` ###### `process_attestation`
```python ```python
def process_attestations(state: BeaconState, block_body: BeaconBlockBody, attestations: Sequence[Attestation]) -> None: def process_attestation(state: BeaconState, attestation: Attestation) -> None:
# Basic validation validate_attestation(state, attestation)
for attestation in attestations: # Store pending attestation for epoch processing
validate_attestation(state, attestation) pending_attestation = PendingAttestation(
aggregation_bits=attestation.aggregation_bits,
# Process crosslinks data=attestation.data,
winners = process_crosslinks(state, block_body, attestations) inclusion_delay=state.slot - attestation.data.slot,
crosslink_success=False, # To be filled in during process_crosslinks
# Store pending attestations for epoch processing proposer_index=get_beacon_proposer_index(state),
for attestation in attestations: )
is_winning_transition = (get_shard(state, attestation), attestation.data.shard_transition_root) in winners if attestation.data.target.epoch == get_current_epoch(state):
pending_attestation = PendingAttestation( state.current_epoch_attestations.append(pending_attestation)
aggregation_bits=attestation.aggregation_bits, else:
data=attestation.data, state.previous_epoch_attestations.append(pending_attestation)
inclusion_delay=state.slot - attestation.data.slot,
crosslink_success=is_winning_transition and attestation.data.slot == state.slot,
proposer_index=get_beacon_proposer_index(state),
)
if attestation.data.target.epoch == get_current_epoch(state):
state.current_epoch_attestations.append(pending_attestation)
else:
state.previous_epoch_attestations.append(pending_attestation)
``` ```
##### New Attester slashing processing ##### New Attester slashing processing

View File

@ -0,0 +1,80 @@
from eth2spec.test.context import (
with_all_phases_except,
expect_assertion_error,
spec_state_test,
always_bls,
)
from eth2spec.test.helpers.attestations import (
get_valid_attestation,
sign_attestation,
)
from eth2spec.utils.ssz.ssz_typing import Bitlist
def run_attestation_processing(spec, state, attestation, valid=True):
"""
Run ``process_attestation``, yielding:
- pre-state ('pre')
- attestation ('attestation')
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
# yield pre-state
yield 'pre', state
yield 'attestation', attestation
# If the attestation is invalid, processing is aborted, and there is no post-state.
if not valid:
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
yield 'post', None
return
current_epoch_count = len(state.current_epoch_attestations)
previous_epoch_count = len(state.previous_epoch_attestations)
# process attestation
spec.process_attestation(state, attestation)
# Make sure the attestation has been processed
if attestation.data.target.epoch == spec.get_current_epoch(state):
assert len(state.current_epoch_attestations) == current_epoch_count + 1
else:
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
# yield post-state
yield 'post', state
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_success_empty_custody_bits_blocks(spec, state):
attestation = get_valid_attestation(spec, state)
attestation.custody_bits_blocks = []
sign_attestation(spec, state, attestation)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
yield from run_attestation_processing(spec, state, attestation)
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_fail_custody_bits_blocks_incorrect_slot(spec, state):
attestation = get_valid_attestation(spec, state)
committee = spec.get_beacon_committee(
state,
attestation.data.slot,
attestation.data.index,
)
bitlist = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in range(len(committee))])
bitlist[0] = 1
attestation.custody_bits_blocks = [bitlist]
sign_attestation(spec, state, attestation)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
yield from run_attestation_processing(spec, state, attestation)