def test_duplicate_attestation(spec, state): """ Although duplicate attestations can be included on-chain, they should only be rewarded for once. This test addresses this issue found at Interop https://github.com/djrtwo/interop-test-cases/tree/master/tests/prysm_16_duplicate_attestation_rewards """ attestation = get_valid_attestation(spec, state, signed=True) indexed_attestation = spec.get_indexed_attestation(state, attestation) participants = get_indexed_attestation_participants(spec, indexed_attestation) assert len(participants) > 0 single_state = state.copy() dup_state = state.copy() inclusion_slot = state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY add_attestations_to_state(spec, single_state, [attestation], inclusion_slot) add_attestations_to_state(spec, dup_state, [attestation, attestation], inclusion_slot) next_epoch(spec, single_state) next_epoch(spec, dup_state) # Run non-duplicate inclusion rewards for comparison. Do not yield test vectors for _ in run_process_rewards_and_penalties(spec, single_state): pass # Output duplicate inclusion to test vectors yield from run_process_rewards_and_penalties(spec, dup_state) for index in participants: assert state.balances[index] < single_state.balances[index] assert single_state.balances[index] == dup_state.balances[index]
def test_attestations_some_slashed(spec, state): attestations = [] for slot in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY): # create an attestation for each slot in epoch if slot < spec.SLOTS_PER_EPOCH: attestation = get_valid_attestation(spec, state, signed=True) attestations.append(attestation) # fill each created slot in state after inclusion delay if slot - spec.MIN_ATTESTATION_INCLUSION_DELAY >= 0: include_att = attestations[slot - spec.MIN_ATTESTATION_INCLUSION_DELAY] add_attestations_to_state(spec, state, [include_att], state.slot) next_slot(spec, state) attesting_indices_before_slashings = list(spec.get_unslashed_attesting_indices(state, attestations)) # Slash maximum amount of validators allowed per epoch. for i in range(spec.MIN_PER_EPOCH_CHURN_LIMIT): spec.slash_validator(state, attesting_indices_before_slashings[i]) assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1 assert len(state.previous_epoch_attestations) == spec.SLOTS_PER_EPOCH pre_state = deepcopy(state) 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_before_slashings) - len(attesting_indices) == spec.MIN_PER_EPOCH_CHURN_LIMIT for index in range(len(pre_state.validators)): if index in attesting_indices: assert state.balances[index] > pre_state.balances[index] else: assert state.balances[index] < pre_state.balances[index]
def prepare_state_with_full_attestations(spec, state, empty=False): # Go to start of next epoch to ensure can have full participation next_epoch(spec, state) start_slot = state.slot start_epoch = spec.get_current_epoch(state) next_epoch_start_slot = spec.compute_start_slot_at_epoch(start_epoch + 1) attestations = [] for _ in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY): # 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) # 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 include_attestations = [ att for att in attestations if att.data.slot == inclusion_slot ] add_attestations_to_state(spec, state, include_attestations, state.slot) next_slot(spec, state) assert state.slot == next_epoch_start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY assert len(state.previous_epoch_attestations) == len(attestations) return attestations
def prepare_state_with_full_attestations(spec, state): attestations = [] for slot in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY): # create an attestation for each slot in epoch if slot < spec.SLOTS_PER_EPOCH: attestation = get_valid_attestation(spec, state, signed=True) attestations.append(attestation) # fill each created slot in state after inclusion delay if slot - spec.MIN_ATTESTATION_INCLUSION_DELAY >= 0: include_att = attestations[slot - spec.MIN_ATTESTATION_INCLUSION_DELAY] add_attestations_to_state(spec, state, [include_att], state.slot) next_slot(spec, state) assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1 assert len(state.previous_epoch_attestations) == spec.SLOTS_PER_EPOCH return attestations
def test_duplicate_participants_different_attestation_2(spec, state): """ Same attesters get two different attestations on chain for the same inclusion delay Earlier attestation (by list order) has incorrect head, later is correct Note: although these are slashable, they can validly be included """ correct_attestation = get_valid_attestation(spec, state, signed=True) incorrect_attestation = correct_attestation.copy() incorrect_attestation.data.beacon_block_root = b'\x42' * 32 sign_attestation(spec, state, incorrect_attestation) indexed_attestation = spec.get_indexed_attestation(state, correct_attestation) participants = get_indexed_attestation_participants( spec, indexed_attestation) assert len(participants) > 0 single_correct_state = state.copy() dup_state = state.copy() inclusion_slot = state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY add_attestations_to_state(spec, single_correct_state, [correct_attestation], inclusion_slot) add_attestations_to_state(spec, dup_state, [incorrect_attestation, correct_attestation], inclusion_slot) next_epoch(spec, single_correct_state) next_epoch(spec, dup_state) # Run non-duplicate inclusion rewards for comparison. Do not yield test vectors for _ in run_process_rewards_and_penalties(spec, single_correct_state): pass # Output duplicate inclusion to test vectors yield from run_process_rewards_and_penalties(spec, dup_state) for index in participants: assert state.balances[index] < single_correct_state.balances[index] # Inclusion delay does not take into account correctness so equal reward assert single_correct_state.balances[index] == dup_state.balances[ index]
def test_genesis_epoch_full_attestations_no_rewards(spec, state): attestations = [] for slot in range(spec.SLOTS_PER_EPOCH - 1): # create an attestation for each slot if slot < spec.SLOTS_PER_EPOCH: attestation = get_valid_attestation(spec, state, signed=True) attestations.append(attestation) # fill each created slot in state after inclusion delay if slot >= spec.MIN_ATTESTATION_INCLUSION_DELAY: include_att = attestations[slot - spec.MIN_ATTESTATION_INCLUSION_DELAY] add_attestations_to_state(spec, state, [include_att], state.slot) next_slot(spec, state) # ensure has not cross the epoch boundary assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH pre_state = state.copy() yield from run_process_rewards_and_penalties(spec, state) for index in range(len(pre_state.validators)): assert state.balances[index] == pre_state.balances[index]