diff --git a/tests/core/pyspec/eth2spec/test/helpers/rewards.py b/tests/core/pyspec/eth2spec/test/helpers/rewards.py index e8cd950ce..09c99c3ac 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/rewards.py +++ b/tests/core/pyspec/eth2spec/test/helpers/rewards.py @@ -32,7 +32,13 @@ def run_attestation_component_deltas(spec, state, component_delta_fn, matching_a matching_attestations = matching_att_fn(state, spec.get_previous_epoch(state)) matching_indices = spec.get_unslashed_attesting_indices(state, matching_attestations) - for index in spec.get_eligible_validator_indices(state): + eligible_indices = spec.get_eligible_validator_indices(state) + for index in range(len(state.validators)): + if index not in eligible_indices: + assert rewards[index] == 0 + assert penalties[index] == 0 + continue + validator = state.validators[index] enough_for_reward = has_enough_for_reward(spec, state, index) if index in matching_indices and not validator.slashed: @@ -117,7 +123,7 @@ def test_some_very_low_effective_balances_that_attested(spec, state, runner): yield from runner(spec, state) -def test_some_zero_effective_balances_that_did_not_attest(spec, state, runner): +def test_some_very_low_effective_balances_that_did_not_attest(spec, state, runner): prepare_state_with_full_attestations(spec, state) # Remove attestation @@ -125,8 +131,8 @@ def test_some_zero_effective_balances_that_did_not_attest(spec, state, runner): state.previous_epoch_attestations = state.previous_epoch_attestations[1:] # Set removed indices effective balance to zero indices = spec.get_unslashed_attesting_indices(state, [attestation]) - for index in indices: - state.validators[index].effective_balance = 0 + for i, index in enumerate(indices): + state.validators[index].effective_balance = i yield from runner(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_head_deltas.py b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_head_deltas.py index b9aab92cb..237920732 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_head_deltas.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_head_deltas.py @@ -37,6 +37,12 @@ def test_half_full(spec, state): yield from rewards_helpers.test_half_full(spec, state, run_get_head_deltas) +@with_all_phases +@spec_state_test +def test_full_but_partial_participation(spec, state): + yield from rewards_helpers.test_full_but_partial_participation(spec, state, run_get_head_deltas) + + @with_all_phases @spec_state_test def test_one_attestation_one_correct(spec, state): @@ -57,8 +63,12 @@ def test_some_very_low_effective_balances_that_attested(spec, state): @with_all_phases @spec_state_test -def test_some_zero_effective_balances_that_did_not_attest(spec, state): - yield from rewards_helpers.test_some_zero_effective_balances_that_did_not_attest(spec, state, run_get_head_deltas) +def test_some_very_low_effective_balances_that_did_not_attest(spec, state): + yield from rewards_helpers.test_some_very_low_effective_balances_that_did_not_attest( + spec, + state, + run_get_head_deltas, + ) @with_all_phases diff --git a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_inactivity_penalty_deltas.py b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_inactivity_penalty_deltas.py new file mode 100644 index 000000000..a81451e38 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_inactivity_penalty_deltas.py @@ -0,0 +1,204 @@ +from eth2spec.test.context import with_all_phases, spec_state_test +from eth2spec.test.helpers.rewards import has_enough_for_reward +from eth2spec.test.helpers.state import next_epoch +import eth2spec.test.helpers.rewards as rewards_helpers +from eth2spec.utils.ssz.ssz_typing import Container, uint64, List + + +# HACK to get the generators outputting correctly +class Deltas(Container): + delta_list: List[uint64, 2**30] + + +def run_get_inactivity_penalty_deltas(spec, state): + """ + Run ``get_inactivity_penalty_deltas``, yielding: + - pre-state ('pre') + - rewards ('rewards') + - penalties ('penalties') + """ + + yield 'pre', state + + rewards, penalties = spec.get_inactivity_penalty_deltas(state) + + yield 'rewards', Deltas(delta_list=rewards) + yield 'penalties', Deltas(delta_list=penalties) + + matching_attestations = spec.get_matching_target_attestations(state, spec.get_previous_epoch(state)) + matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations) + + finality_delay = spec.get_previous_epoch(state) - state.finalized_checkpoint.epoch + eligible_indices = spec.get_eligible_validator_indices(state) + for index in range(len(state.validators)): + assert rewards[index] == 0 + if index not in eligible_indices: + assert penalties[index] == 0 + continue + + if finality_delay > spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY: + base_penalty = spec.BASE_REWARDS_PER_EPOCH * spec.get_base_reward(state, index) + if not has_enough_for_reward(spec, state, index): + assert penalties[index] == 0 + elif index in matching_attesting_indices: + assert penalties[index] == base_penalty + else: + assert penalties[index] > base_penalty + else: + assert penalties[index] == 0 + + +def transition_state_to_leak(spec, state, epochs=None): + if epochs is None: + epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + + for _ in range(epochs): + next_epoch(spec, state) + + +@with_all_phases +@spec_state_test +def test_empty_no_leak(spec, state): + yield from rewards_helpers.test_empty(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_empty_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_empty(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_no_leak(spec, state): + yield from rewards_helpers.test_full_all_correct(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_full_all_correct(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_half_full_no_leak(spec, state): + yield from rewards_helpers.test_half_full(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_half_full_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_half_full(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_quarter_full_no_leak(spec, state): + yield from rewards_helpers.test_partial(spec, state, 0.25, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_quarter_full_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_partial(spec, state, 0.25, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_but_partial_participation_no_leak(spec, state): + yield from rewards_helpers.test_full_but_partial_participation(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_but_partial_participation_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_full_but_partial_participation(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_with_slashed_validators_no_leak(spec, state): + yield from rewards_helpers.test_with_slashed_validators(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_with_slashed_validators_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_with_slashed_validators(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_some_very_low_effective_balances_that_attested_no_leak(spec, state): + yield from rewards_helpers.test_some_very_low_effective_balances_that_attested( + spec, + state, + run_get_inactivity_penalty_deltas, + ) + + +@with_all_phases +@spec_state_test +def test_some_very_low_effective_balances_that_attested_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_some_very_low_effective_balances_that_attested( + spec, + state, + run_get_inactivity_penalty_deltas, + ) + + +@with_all_phases +@spec_state_test +def test_some_very_low_effective_balances_that_did_not_attest_no_leak(spec, state): + yield from rewards_helpers.test_some_very_low_effective_balances_that_did_not_attest( + spec, + state, + run_get_inactivity_penalty_deltas, + ) + + +@with_all_phases +@spec_state_test +def test_some_very_low_effective_balances_that_did_not_attest_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_some_very_low_effective_balances_that_did_not_attest( + spec, + state, + run_get_inactivity_penalty_deltas, + ) + + +@with_all_phases +@spec_state_test +def test_full_random_no_leak(spec, state): + yield from rewards_helpers.test_full_random(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_random_leak(spec, state): + transition_state_to_leak(spec, state) + yield from rewards_helpers.test_full_random(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_random_five_epoch_leak(spec, state): + transition_state_to_leak(spec, state, epochs=5) + yield from rewards_helpers.test_full_random(spec, state, run_get_inactivity_penalty_deltas) + + +@with_all_phases +@spec_state_test +def test_full_random_ten_epoch_leak(spec, state): + transition_state_to_leak(spec, state, epochs=10) + yield from rewards_helpers.test_full_random(spec, state, run_get_inactivity_penalty_deltas) diff --git a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_source_deltas.py b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_source_deltas.py index 9063abfc6..842728db8 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_source_deltas.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_source_deltas.py @@ -63,8 +63,12 @@ def test_some_very_low_effective_balances_that_attested(spec, state): @with_all_phases @spec_state_test -def test_some_zero_effective_balances_that_did_not_attest(spec, state): - yield from rewards_helpers.test_some_zero_effective_balances_that_did_not_attest(spec, state, run_get_source_deltas) +def test_some_very_low_effective_balances_that_did_not_attest(spec, state): + yield from rewards_helpers.test_some_very_low_effective_balances_that_did_not_attest( + spec, + state, + run_get_source_deltas, + ) # diff --git a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_target_deltas.py b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_target_deltas.py index ff20014c8..ad2a65d2a 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_target_deltas.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/rewards/test_get_target_deltas.py @@ -63,8 +63,12 @@ def test_some_very_low_effective_balances_that_attested(spec, state): @with_all_phases @spec_state_test -def test_some_zero_effective_balances_that_did_not_attest(spec, state): - yield from rewards_helpers.test_some_zero_effective_balances_that_did_not_attest(spec, state, run_get_target_deltas) +def test_some_very_low_effective_balances_that_did_not_attest(spec, state): + yield from rewards_helpers.test_some_very_low_effective_balances_that_did_not_attest( + spec, + state, + run_get_target_deltas, + ) @with_all_phases diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index caffc3bd1..fd95dcfaa 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -6,6 +6,8 @@ from eth2spec.test.phase_0.rewards import ( test_get_source_deltas, test_get_target_deltas, test_get_head_deltas, + test_get_inclusion_delay_deltas, + test_get_inactivity_penalty_deltas, ) from gen_base import gen_runner, gen_typing from gen_from_tests.gen import generate_from_tests @@ -41,4 +43,8 @@ if __name__ == "__main__": create_provider('get_target_deltas', test_get_target_deltas, 'mainnet'), create_provider('get_head_deltas', test_get_head_deltas, 'minimal'), create_provider('get_head_deltas', test_get_head_deltas, 'mainnet'), + create_provider('get_inclusion_delay_deltas', test_get_inclusion_delay_deltas, 'minimal'), + create_provider('get_inclusion_delay_deltas', test_get_inclusion_delay_deltas, 'mainnet'), + create_provider('get_inactivity_penalty_deltas', test_get_inactivity_penalty_deltas, 'minimal'), + create_provider('get_inactivity_penalty_deltas', test_get_inactivity_penalty_deltas, 'mainnet'), ])