Esempio n. 1
0
def test_duplicate_attester_slashing(spec, state):
    if spec.MAX_ATTESTER_SLASHINGS < 2:
        return dump_skipping_message(
            "Skip test if config cannot handle multiple AttesterSlashings per block"
        )

    attester_slashing = get_valid_attester_slashing(spec,
                                                    state,
                                                    signed_1=True,
                                                    signed_2=True)
    attester_slashings = [attester_slashing, attester_slashing.copy()]
    slashed_indices = get_indexed_attestation_participants(
        spec, attester_slashing.attestation_1)

    assert not any(state.validators[i].slashed for i in slashed_indices)

    yield 'pre', state

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(spec, state)
    block.body.attester_slashings = attester_slashings

    signed_block = state_transition_and_sign_block(spec,
                                                   state,
                                                   block,
                                                   expect_fail=True)

    yield 'blocks', [signed_block]
    yield 'post', None
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]
Esempio n. 3
0
def test_attester_slashing(spec, state):
    # copy for later balance lookups.
    pre_state = deepcopy(state)

    attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
    validator_index = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)[0]

    assert not state.validators[validator_index].slashed

    yield 'pre', state

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(spec, state)
    block.body.attester_slashings.append(attester_slashing)

    signed_block = state_transition_and_sign_block(spec, state, block)

    yield 'blocks', [signed_block]
    yield 'post', state

    slashed_validator = state.validators[validator_index]
    assert slashed_validator.slashed
    assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
    assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
    # lost whistleblower reward
    assert get_balance(state, validator_index) < get_balance(pre_state, validator_index)

    proposer_index = spec.get_beacon_proposer_index(state)
    # gained whistleblower reward
    assert (
        get_balance(state, proposer_index) >
        get_balance(pre_state, proposer_index)
    )
Esempio n. 4
0
def test_attester_slashing(spec, state):
    # copy for later balance lookups.
    pre_state = state.copy()

    attester_slashing = get_valid_attester_slashing(spec,
                                                    state,
                                                    signed_1=True,
                                                    signed_2=True)
    slashed_indices = get_indexed_attestation_participants(
        spec, attester_slashing.attestation_1)

    assert not any(state.validators[i].slashed for i in slashed_indices)

    yield 'pre', state

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(spec, state)
    block.body.attester_slashings.append(attester_slashing)

    signed_block = state_transition_and_sign_block(spec, state, block)

    yield 'blocks', [signed_block]
    yield 'post', state

    check_attester_slashing_effect(spec, pre_state, state, slashed_indices)
Esempio n. 5
0
def test_success_already_exited_recent(spec, state):
    attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
    slashed_indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)
    for index in slashed_indices:
        spec.initiate_validator_exit(state, index)

    yield from run_attester_slashing_processing(spec, state, attester_slashing)
Esempio n. 6
0
def test_success_already_exited_long_ago(spec, state):
    attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
    slashed_indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)
    for index in slashed_indices:
        spec.initiate_validator_exit(state, index)
        state.validators[index].withdrawable_epoch = spec.get_current_epoch(state) + 2

    yield from run_attester_slashing_processing(spec, state, attester_slashing)
Esempio n. 7
0
def test_participants_already_slashed(spec, state):
    attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)

    # set all indices to slashed
    validator_indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)
    for index in validator_indices:
        state.validators[index].slashed = True

    yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
Esempio n. 8
0
def test_att1_bad_extra_index(spec, state):
    attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)

    indices = get_indexed_attestation_participants(spec, attester_slashing.attestation_1)
    options = list(set(range(len(state.validators))) - set(indices))
    indices.append(options[len(options) // 2])  # add random index, not previously in attestation.
    attester_slashing.attestation_1.attesting_indices = sorted(indices)
    # Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not),
    # see if the bad extra index is spotted, and slashing is aborted.

    yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
Esempio n. 9
0
def test_att2_high_index(spec, state):
    attester_slashing = get_valid_attester_slashing(spec,
                                                    state,
                                                    signed_1=True,
                                                    signed_2=True)

    indices = get_indexed_attestation_participants(
        spec, attester_slashing.attestation_2)
    indices.append(spec.ValidatorIndex(len(state.validators)))  # off by 1
    attester_slashing.attestation_2.attesting_indices = indices

    yield from run_attester_slashing_processing(spec, state, attester_slashing,
                                                False)
def test_duplicate_participants_different_attestation_3(spec, state):
    """
    Same attesters get two different attestations on chain for *different* 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],
                              inclusion_slot)
    add_attestations_to_state(spec, dup_state, [correct_attestation],
                              inclusion_slot + 1)

    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]
Esempio n. 11
0
def run_attester_slashing_processing(spec,
                                     state,
                                     attester_slashing,
                                     valid=True):
    """
    Run ``process_attester_slashing``, yielding:
      - pre-state ('pre')
      - attester_slashing ('attester_slashing')
      - post-state ('post').
    If ``valid == False``, run expecting ``AssertionError``
    """

    yield 'pre', state
    yield 'attester_slashing', attester_slashing

    if not valid:
        expect_assertion_error(
            lambda: spec.process_attester_slashing(state, attester_slashing))
        yield 'post', None
        return

    slashed_indices = get_indexed_attestation_participants(
        spec, attester_slashing.attestation_1)

    proposer_index = spec.get_beacon_proposer_index(state)
    pre_proposer_balance = get_balance(state, proposer_index)
    pre_slashing_balances = {
        slashed_index: get_balance(state, slashed_index)
        for slashed_index in slashed_indices
    }
    pre_slashing_effectives = {
        slashed_index: state.validators[slashed_index].effective_balance
        for slashed_index in slashed_indices
    }
    pre_withdrawalable_epochs = {
        slashed_index: state.validators[slashed_index].withdrawable_epoch
        for slashed_index in slashed_indices
    }

    total_proposer_rewards = sum(
        effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT
        for effective_balance in pre_slashing_effectives.values())

    # Process slashing
    spec.process_attester_slashing(state, attester_slashing)

    for slashed_index in slashed_indices:
        pre_withdrawalable_epoch = pre_withdrawalable_epochs[slashed_index]
        slashed_validator = state.validators[slashed_index]

        # Check slashing
        assert slashed_validator.slashed
        assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
        if pre_withdrawalable_epoch < spec.FAR_FUTURE_EPOCH:
            expected_withdrawable_epoch = max(
                pre_withdrawalable_epoch,
                spec.get_current_epoch(state) +
                spec.EPOCHS_PER_SLASHINGS_VECTOR)
            assert slashed_validator.withdrawable_epoch == expected_withdrawable_epoch
        else:
            assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
        assert get_balance(
            state, slashed_index) < pre_slashing_balances[slashed_index]

    if proposer_index not in slashed_indices:
        # gained whistleblower reward
        assert get_balance(
            state,
            proposer_index) == pre_proposer_balance + total_proposer_rewards
    else:
        # gained rewards for all slashings, which may include others. And only lost that of themselves.
        expected_balance = (pre_proposer_balance + total_proposer_rewards -
                            pre_slashing_effectives[proposer_index] //
                            get_min_slashing_penalty_quotient(spec))

        assert get_balance(state, proposer_index) == expected_balance

    yield 'post', state