rework process_attestation and work through tests
This commit is contained in:
parent
aa451778f9
commit
d414aac933
|
@ -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,43 +741,40 @@ 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
|
|
||||||
for attestation in attestations:
|
|
||||||
validate_attestation(state, attestation)
|
validate_attestation(state, attestation)
|
||||||
|
# Store pending attestation for epoch processing
|
||||||
# Process crosslinks
|
|
||||||
winners = process_crosslinks(state, block_body, attestations)
|
|
||||||
|
|
||||||
# Store pending attestations for epoch processing
|
|
||||||
for attestation in attestations:
|
|
||||||
is_winning_transition = (get_shard(state, attestation), attestation.data.shard_transition_root) in winners
|
|
||||||
pending_attestation = PendingAttestation(
|
pending_attestation = PendingAttestation(
|
||||||
aggregation_bits=attestation.aggregation_bits,
|
aggregation_bits=attestation.aggregation_bits,
|
||||||
data=attestation.data,
|
data=attestation.data,
|
||||||
inclusion_delay=state.slot - attestation.data.slot,
|
inclusion_delay=state.slot - attestation.data.slot,
|
||||||
crosslink_success=is_winning_transition and attestation.data.slot == state.slot,
|
crosslink_success=False, # To be filled in during process_crosslinks
|
||||||
proposer_index=get_beacon_proposer_index(state),
|
proposer_index=get_beacon_proposer_index(state),
|
||||||
)
|
)
|
||||||
if attestation.data.target.epoch == get_current_epoch(state):
|
if attestation.data.target.epoch == get_current_epoch(state):
|
||||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue