From 67809e76e163bebb136f833ecd97f0d24a539eea Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 2 Jun 2021 01:21:03 +0800 Subject: [PATCH] Fix tests --- .../test_process_sync_committee.py | 44 ++++--------------- .../test/helpers/proposer_slashings.py | 39 ++++++++++++++-- .../eth2spec/test/helpers/sync_committee.py | 41 +++++++++++++++++ .../test/phase0/sanity/test_blocks.py | 29 ++++++++++-- 4 files changed, 109 insertions(+), 44 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py index 5da8b65fd..b0a294c85 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py @@ -1,4 +1,3 @@ -from collections import Counter import random from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, @@ -13,6 +12,9 @@ from eth2spec.test.helpers.constants import ( ) from eth2spec.test.helpers.sync_committee import ( compute_aggregate_sync_committee_signature, + compute_sync_committee_participant_reward_and_penalty, + compute_sync_committee_proposer_reward, + compute_committee_indices, ) from eth2spec.test.context import ( expect_assertion_error, @@ -61,15 +63,6 @@ def get_committee_indices(spec, state, duplicates=False): state.randao_mixes[randao_index] = hash(state.randao_mixes[randao_index]) -def compute_committee_indices(spec, state, committee): - """ - Given a ``committee``, calculate and return the related indices - """ - all_pubkeys = [v.pubkey for v in state.validators] - committee_indices = [all_pubkeys.index(pubkey) for pubkey in committee.pubkeys] - return committee_indices - - @with_altair_and_later @spec_state_test @always_bls @@ -115,41 +108,20 @@ def test_invalid_signature_extra_participant(spec, state): yield from run_sync_committee_processing(spec, state, block, expect_exception=True) -def compute_sync_committee_inclusion_reward(spec, state): - total_active_increments = spec.get_total_active_balance(state) // spec.EFFECTIVE_BALANCE_INCREMENT - total_base_rewards = spec.Gwei(spec.get_base_reward_per_increment(state) * total_active_increments) - max_participant_rewards = spec.Gwei(total_base_rewards * spec.SYNC_REWARD_WEIGHT // - spec.WEIGHT_DENOMINATOR // spec.SLOTS_PER_EPOCH) - return spec.Gwei(max_participant_rewards // spec.SYNC_COMMITTEE_SIZE) - - -def compute_sync_committee_participant_reward(spec, state, participant_index, committee_indices, committee_bits): - included_indices = [index for index, bit in zip(committee_indices, committee_bits) if bit] - multiplicities = Counter(included_indices) - - inclusion_reward = compute_sync_committee_inclusion_reward(spec, state) - return spec.Gwei(inclusion_reward * multiplicities[participant_index]) - - -def compute_sync_committee_proposer_reward(spec, state, committee_indices, committee_bits): - proposer_reward_denominator = spec.WEIGHT_DENOMINATOR - spec.PROPOSER_WEIGHT - inclusion_reward = compute_sync_committee_inclusion_reward(spec, state) - participant_number = committee_bits.count(True) - participant_reward = inclusion_reward * spec.PROPOSER_WEIGHT // proposer_reward_denominator - return spec.Gwei(participant_reward * participant_number) - - def validate_sync_committee_rewards(spec, pre_state, post_state, committee_indices, committee_bits, proposer_index): for index in range(len(post_state.validators)): reward = 0 + penalty = 0 if index in committee_indices: - reward += compute_sync_committee_participant_reward( + _reward, _penalty = compute_sync_committee_participant_reward_and_penalty( spec, pre_state, index, committee_indices, committee_bits, ) + reward += _reward + penalty += _penalty if proposer_index == index: reward += compute_sync_committee_proposer_reward( @@ -159,7 +131,7 @@ def validate_sync_committee_rewards(spec, pre_state, post_state, committee_indic committee_bits, ) - assert post_state.balances[index] == pre_state.balances[index] + reward + assert post_state.balances[index] == pre_state.balances[index] + reward - penalty def run_successful_sync_committee_test(spec, state, committee_indices, committee_bits): diff --git a/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py b/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py index d3520e580..a783d2517 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -2,6 +2,10 @@ from eth2spec.test.context import is_post_altair from eth2spec.test.helpers.block_header import sign_block_header from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.state import get_balance +from eth2spec.test.helpers.sync_committee import ( + compute_committee_indices, + compute_sync_committee_participant_reward_and_penalty, +) def get_min_slashing_penalty_quotient(spec): @@ -11,7 +15,7 @@ def get_min_slashing_penalty_quotient(spec): return spec.MIN_SLASHING_PENALTY_QUOTIENT -def check_proposer_slashing_effect(spec, pre_state, state, slashed_index): +def check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block=None): slashed_validator = state.validators[slashed_index] assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH @@ -20,24 +24,51 @@ def check_proposer_slashing_effect(spec, pre_state, state, slashed_index): proposer_index = spec.get_beacon_proposer_index(state) slash_penalty = state.validators[slashed_index].effective_balance // get_min_slashing_penalty_quotient(spec) whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT + + # Altair introduces sync committee (SC) reward and penalty + sc_reward_for_slashed = sc_penalty_for_slashed = sc_reward_for_proposer = sc_penalty_for_proposer = 0 + if is_post_altair(spec) and block is not None: + committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) + committee_bits = block.body.sync_aggregate.sync_committee_bits + sc_reward_for_slashed, sc_penalty_for_slashed = compute_sync_committee_participant_reward_and_penalty( + spec, + pre_state, + slashed_index, + committee_indices, + committee_bits, + ) + sc_reward_for_proposer, sc_penalty_for_proposer = compute_sync_committee_participant_reward_and_penalty( + spec, + pre_state, + proposer_index, + committee_indices, + committee_bits, + ) + if proposer_index != slashed_index: # slashed validator lost initial slash penalty assert ( get_balance(state, slashed_index) - == get_balance(pre_state, slashed_index) - slash_penalty + == get_balance(pre_state, slashed_index) - slash_penalty + sc_reward_for_slashed - sc_penalty_for_slashed ) # block proposer gained whistleblower reward # >= because proposer could have reported multiple assert ( get_balance(state, proposer_index) - >= get_balance(pre_state, proposer_index) + whistleblower_reward + >= ( + get_balance(pre_state, proposer_index) + whistleblower_reward + + sc_reward_for_proposer - sc_penalty_for_proposer + ) ) else: # proposer reported themself so get penalty and reward # >= because proposer could have reported multiple assert ( get_balance(state, slashed_index) - >= get_balance(pre_state, slashed_index) - slash_penalty + whistleblower_reward + >= ( + get_balance(pre_state, slashed_index) - slash_penalty + whistleblower_reward + + sc_reward_for_slashed - sc_penalty_for_slashed + ) ) diff --git a/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py b/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py index da85fad60..fa753db52 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py @@ -1,3 +1,5 @@ +from collections import Counter + from eth2spec.test.helpers.keys import privkeys from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, @@ -33,3 +35,42 @@ def compute_aggregate_sync_committee_signature(spec, state, slot, participants, ) ) return bls.Aggregate(signatures) + + +def compute_sync_committee_inclusion_reward(spec, state): + total_active_increments = spec.get_total_active_balance(state) // spec.EFFECTIVE_BALANCE_INCREMENT + total_base_rewards = spec.get_base_reward_per_increment(state) * total_active_increments + max_participant_rewards = (total_base_rewards * spec.SYNC_REWARD_WEIGHT + // spec.WEIGHT_DENOMINATOR // spec.SLOTS_PER_EPOCH) + return max_participant_rewards // spec.SYNC_COMMITTEE_SIZE + + +def compute_sync_committee_participant_reward_and_penalty( + spec, state, participant_index, committee_indices, committee_bits): + inclusion_reward = compute_sync_committee_inclusion_reward(spec, state) + + included_indices = [index for index, bit in zip(committee_indices, committee_bits) if bit] + not_included_indices = [index for index, bit in zip(committee_indices, committee_bits) if not bit] + included_multiplicities = Counter(included_indices) + not_included_multiplicities = Counter(not_included_indices) + return ( + spec.Gwei(inclusion_reward * included_multiplicities[participant_index]), + spec.Gwei(inclusion_reward * not_included_multiplicities[participant_index]) + ) + + +def compute_sync_committee_proposer_reward(spec, state, committee_indices, committee_bits): + proposer_reward_denominator = spec.WEIGHT_DENOMINATOR - spec.PROPOSER_WEIGHT + inclusion_reward = compute_sync_committee_inclusion_reward(spec, state) + participant_number = committee_bits.count(True) + participant_reward = inclusion_reward * spec.PROPOSER_WEIGHT // proposer_reward_denominator + return spec.Gwei(participant_reward * participant_number) + + +def compute_committee_indices(spec, state, committee): + """ + Given a ``committee``, calculate and return the related indices + """ + all_pubkeys = [v.pubkey for v in state.validators] + committee_indices = [all_pubkeys.index(pubkey) for pubkey in committee.pubkeys] + return committee_indices diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index dba623855..33e9854b2 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -24,6 +24,10 @@ from eth2spec.test.helpers.multi_operations import ( run_slash_and_exit, run_test_full_random_operations, ) +from eth2spec.test.helpers.sync_committee import ( + compute_committee_indices, + compute_sync_committee_participant_reward_and_penalty, +) from eth2spec.test.helpers.constants import PHASE0, MINIMAL from eth2spec.test.context import ( spec_test, spec_state_test, dump_skipping_message, @@ -416,7 +420,7 @@ def test_proposer_slashing(spec, state): yield 'blocks', [signed_block] yield 'post', state - check_proposer_slashing_effect(spec, pre_state, state, slashed_index) + check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block) @with_all_phases @@ -491,7 +495,7 @@ def test_multiple_different_proposer_slashings_same_block(spec, state): for proposer_slashing in proposer_slashings: slashed_index = proposer_slashing.signed_header_1.message.proposer_index - check_proposer_slashing_effect(spec, pre_state, state, slashed_index) + check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block) def check_attester_slashing_effect(spec, pre_state, state, slashed_indices): @@ -743,7 +747,8 @@ def test_deposit_top_up(spec, state): initial_balances_len = len(state.balances) validator_pre_balance = get_balance(state, validator_index) - yield 'pre', state + pre_state = state.copy() + yield 'pre', pre_state block = build_empty_block_for_next_slot(spec, state) block.body.deposits.append(deposit) @@ -755,7 +760,23 @@ def test_deposit_top_up(spec, state): assert len(state.validators) == initial_registry_len assert len(state.balances) == initial_balances_len - assert get_balance(state, validator_index) == validator_pre_balance + amount + + # Altair introduces sync committee (sm) reward and penalty + sync_committee_reward = sync_committee_penalty = 0 + if is_post_altair(spec): + committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) + committee_bits = block.body.sync_aggregate.sync_committee_bits + sync_committee_reward, sync_committee_penalty = compute_sync_committee_participant_reward_and_penalty( + spec, + pre_state, + validator_index, + committee_indices, + committee_bits, + ) + + assert get_balance(state, validator_index) == ( + validator_pre_balance + amount + sync_committee_reward - sync_committee_penalty + ) @with_all_phases