Fix rewards testing for empty/weird participation cases, adding more as well
This commit is contained in:
parent
09cae4b3cc
commit
47ed5b6500
|
@ -113,8 +113,8 @@ def get_valid_late_attestation(spec, state, slot=None, index=None, signed=False)
|
|||
return get_valid_attestation(spec, state, slot=slot, index=index, signed=signed, on_time=False)
|
||||
|
||||
|
||||
def get_valid_attestation(spec, state, slot=None, index=None, empty=False, signed=False, on_time=True):
|
||||
# If empty is true, the attestation has 0 participants, and will not be signed.
|
||||
def get_valid_attestation(spec, state, slot=None, index=None, filter_participant_set=None, signed=False, on_time=True):
|
||||
# If filter_participant_set is filters everything, the attestation has 0 participants, and cannot be signed.
|
||||
# Thus strictly speaking invalid when no participant is added later.
|
||||
|
||||
if slot is None:
|
||||
|
@ -136,10 +136,8 @@ def get_valid_attestation(spec, state, slot=None, index=None, empty=False, signe
|
|||
aggregation_bits=aggregation_bits,
|
||||
data=attestation_data,
|
||||
)
|
||||
if not empty:
|
||||
fill_aggregate_attestation(spec, state, attestation)
|
||||
if signed:
|
||||
sign_attestation(spec, state, attestation)
|
||||
# fill the attestation with (optionally filtered) participants, and optionally sign it
|
||||
fill_aggregate_attestation(spec, state, attestation, signed=signed, filter_participant_set=filter_participant_set)
|
||||
|
||||
if spec.fork == 'phase1' and on_time:
|
||||
attestation = convert_to_valid_on_time_attestation(spec, state, attestation, signed)
|
||||
|
@ -232,16 +230,25 @@ def get_attestation_signature(spec, state, attestation_data, privkey):
|
|||
return bls.Sign(privkey, signing_root)
|
||||
|
||||
|
||||
def fill_aggregate_attestation(spec, state, attestation, signed=False):
|
||||
def fill_aggregate_attestation(spec, state, attestation, signed=False, filter_participant_set=None):
|
||||
"""
|
||||
`signed`: Signing is optional.
|
||||
`filter_participant_set`: Optional, filters the full committee indices set (default) to a subset that participates
|
||||
"""
|
||||
beacon_committee = spec.get_beacon_committee(
|
||||
state,
|
||||
attestation.data.slot,
|
||||
attestation.data.index,
|
||||
)
|
||||
# By default, have everyone participate
|
||||
participants = set(beacon_committee)
|
||||
# But optionally filter the participants to a smaller amount
|
||||
if filter_participant_set is not None:
|
||||
participants = filter_participant_set(participants)
|
||||
for i in range(len(beacon_committee)):
|
||||
attestation.aggregation_bits[i] = True
|
||||
attestation.aggregation_bits[i] = beacon_committee[i] in participants
|
||||
|
||||
if signed:
|
||||
if signed and len(participants) > 0:
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ from eth2spec.test.helpers.attestations import (
|
|||
sign_attestation,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
next_slot,
|
||||
next_slots,
|
||||
next_epoch,
|
||||
transition_to,
|
||||
|
@ -68,7 +67,7 @@ def test_invalid_attestation_signature(spec, state):
|
|||
@spec_state_test
|
||||
@always_bls
|
||||
def test_empty_participants_zeroes_sig(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, empty=True)
|
||||
attestation = get_valid_attestation(spec, state, filter_participant_set=lambda comm: []) # 0 participants
|
||||
attestation.signature = spec.BLSSignature(b'\x00' * 96)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
|
@ -79,7 +78,7 @@ def test_empty_participants_zeroes_sig(spec, state):
|
|||
@spec_state_test
|
||||
@always_bls
|
||||
def test_empty_participants_seemingly_valid_sig(spec, state):
|
||||
attestation = get_valid_attestation(spec, state, empty=True)
|
||||
attestation = get_valid_attestation(spec, state, filter_participant_set=lambda comm: []) # 0 participants
|
||||
# Special BLS value, valid for zero pubkeys on some (but not all) BLS implementations.
|
||||
attestation.signature = spec.BLSSignature(b'\xc0' + b'\x00' * 95)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
@ -283,19 +282,6 @@ def test_bad_source_root(spec, state):
|
|||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_empty_aggregation_bits(spec, state):
|
||||
next_slot(spec, state)
|
||||
attestation = get_valid_attestation(spec, state, empty=True)
|
||||
next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
assert attestation.aggregation_bits == Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](
|
||||
*([0b0] * len(attestation.aggregation_bits)))
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_too_many_aggregation_bits(spec, state):
|
||||
|
|
|
@ -15,15 +15,15 @@ from eth2spec.test.helpers.attestations import (
|
|||
)
|
||||
from eth2spec.test.helpers.attester_slashings import get_indexed_attestation_participants
|
||||
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
|
||||
from random import Random
|
||||
|
||||
|
||||
def run_process_rewards_and_penalties(spec, state):
|
||||
yield from run_epoch_processing_with(spec, state, 'process_rewards_and_penalties')
|
||||
|
||||
|
||||
def prepare_state_with_full_attestations(spec, state, empty=False):
|
||||
# If empty is true, attestations have 0 participants, and are not signed.
|
||||
# Thus strictly speaking invalid when no participant is added later.
|
||||
def prepare_state_with_full_attestations(spec, state, participation_fn=None):
|
||||
# participation_fn: (slot, committee_index, committee_indices_set) -> participants_indices_set
|
||||
|
||||
# Go to start of next epoch to ensure can have full participation
|
||||
next_epoch(spec, state)
|
||||
|
@ -36,8 +36,15 @@ def prepare_state_with_full_attestations(spec, state, empty=False):
|
|||
# create an attestation for each index in each slot in epoch
|
||||
if state.slot < next_epoch_start_slot:
|
||||
for committee_index in range(spec.get_committee_count_at_slot(state, state.slot)):
|
||||
attestation = get_valid_attestation(spec, state, index=committee_index, empty=empty, signed=True)
|
||||
attestations.append(attestation)
|
||||
def temp_participants_filter(comm):
|
||||
if participation_fn is None:
|
||||
return comm
|
||||
else:
|
||||
return participation_fn(state.slot, committee_index, comm)
|
||||
attestation = get_valid_attestation(spec, state, index=committee_index,
|
||||
filter_participant_set=temp_participants_filter, signed=True)
|
||||
if any(attestation.aggregation_bits): # Only if there is at least 1 participant.
|
||||
attestations.append(attestation)
|
||||
# fill each created slot in state after inclusion delay
|
||||
if state.slot >= start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY:
|
||||
inclusion_slot = state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY
|
||||
|
@ -192,20 +199,55 @@ def test_no_attestations_all_penalties(spec, state):
|
|||
assert state.balances[index] < pre_state.balances[index]
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_empty_attestations(spec, state):
|
||||
attestations = prepare_state_with_full_attestations(spec, state, empty=True)
|
||||
def run_with_participation(spec, state, participation_fn):
|
||||
participated = set()
|
||||
|
||||
def participation_tracker(slot, comm_index, comm):
|
||||
att_participants = participation_fn(slot, comm_index, comm)
|
||||
participated.update(att_participants)
|
||||
return att_participants
|
||||
|
||||
attestations = prepare_state_with_full_attestations(spec, state, participation_fn=participation_tracker)
|
||||
|
||||
pre_state = state.copy()
|
||||
|
||||
yield from run_process_rewards_and_penalties(spec, state)
|
||||
|
||||
attesting_indices = spec.get_unslashed_attesting_indices(state, attestations)
|
||||
assert len(attesting_indices) == 0
|
||||
assert len(attesting_indices) == len(participated)
|
||||
|
||||
for index in range(len(pre_state.validators)):
|
||||
assert state.balances[index] < pre_state.balances[index]
|
||||
if index in participated:
|
||||
assert state.balances[index] > pre_state.balances[index]
|
||||
else:
|
||||
assert state.balances[index] < pre_state.balances[index]
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_almost_empty_attestations(spec, state):
|
||||
rng = Random(1234)
|
||||
yield from run_with_participation(spec, state, lambda slot, comm_index, comm: rng.sample(comm, 1))
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_random_fill_attestations(spec, state):
|
||||
rng = Random(4567)
|
||||
yield from run_with_participation(spec, state, lambda slot, comm_index, comm: rng.sample(comm, len(comm) // 3))
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_almost_full_attestations(spec, state):
|
||||
rng = Random(8901)
|
||||
yield from run_with_participation(spec, state, lambda slot, comm_index, comm: rng.sample(comm, len(comm) - 1))
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_full_attestation_participation(spec, state):
|
||||
yield from run_with_participation(spec, state, lambda slot, comm_index, comm: comm)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
|
|
Loading…
Reference in New Issue