add test case for active/exited difference for sync rewards processing

This commit is contained in:
Alex Stokes
2021-09-01 15:47:05 -07:00
parent df89763777
commit ad076697f4
3 changed files with 67 additions and 42 deletions

View File

@@ -12,7 +12,6 @@ from eth2spec.test.helpers.constants import (
from eth2spec.test.helpers.sync_committee import (
compute_aggregate_sync_committee_signature,
compute_committee_indices,
get_committee_indices,
run_sync_committee_processing,
run_successful_sync_committee_test,
)
@@ -28,7 +27,7 @@ from eth2spec.test.context import (
@spec_state_test
@always_bls
def test_invalid_signature_bad_domain(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
block = build_empty_block_for_next_slot(spec, state)
block.body.sync_aggregate = spec.SyncAggregate(
@@ -48,7 +47,7 @@ def test_invalid_signature_bad_domain(spec, state):
@spec_state_test
@always_bls
def test_invalid_signature_missing_participant(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
rng = random.Random(2020)
random_participant = rng.choice(committee_indices)
@@ -111,7 +110,7 @@ def test_invalid_signature_infinite_signature_with_single_participant(spec, stat
@spec_state_test
@always_bls
def test_invalid_signature_extra_participant(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
rng = random.Random(3030)
random_participant = rng.choice(committee_indices)
@@ -134,7 +133,7 @@ def test_invalid_signature_extra_participant(spec, state):
@with_presets([MINIMAL], reason="to create nonduplicate committee")
@spec_state_test
def test_sync_committee_rewards_nonduplicate_committee(spec, state):
committee_indices = get_committee_indices(spec, state, duplicates=False)
committee_indices = compute_committee_indices(spec, state)
committee_size = len(committee_indices)
committee_bits = [True] * committee_size
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
@@ -150,7 +149,7 @@ def test_sync_committee_rewards_nonduplicate_committee(spec, state):
@with_presets([MAINNET], reason="to create duplicate committee")
@spec_state_test
def test_sync_committee_rewards_duplicate_committee_no_participation(spec, state):
committee_indices = get_committee_indices(spec, state, duplicates=True)
committee_indices = compute_committee_indices(spec, state)
committee_size = len(committee_indices)
committee_bits = [False] * committee_size
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
@@ -166,7 +165,7 @@ def test_sync_committee_rewards_duplicate_committee_no_participation(spec, state
@with_presets([MAINNET], reason="to create duplicate committee")
@spec_state_test
def test_sync_committee_rewards_duplicate_committee_half_participation(spec, state):
committee_indices = get_committee_indices(spec, state, duplicates=True)
committee_indices = compute_committee_indices(spec, state)
committee_size = len(committee_indices)
committee_bits = [True] * (committee_size // 2) + [False] * (committee_size // 2)
assert len(committee_bits) == committee_size
@@ -183,7 +182,7 @@ def test_sync_committee_rewards_duplicate_committee_half_participation(spec, sta
@with_presets([MAINNET], reason="to create duplicate committee")
@spec_state_test
def test_sync_committee_rewards_duplicate_committee_full_participation(spec, state):
committee_indices = get_committee_indices(spec, state, duplicates=True)
committee_indices = compute_committee_indices(spec, state)
committee_size = len(committee_indices)
committee_bits = [True] * committee_size
active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state)))
@@ -199,7 +198,7 @@ def test_sync_committee_rewards_duplicate_committee_full_participation(spec, sta
@spec_state_test
@always_bls
def test_sync_committee_rewards_not_full_participants(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
rng = random.Random(1010)
committee_bits = [rng.choice([True, False]) for _ in committee_indices]
@@ -210,7 +209,7 @@ def test_sync_committee_rewards_not_full_participants(spec, state):
@spec_state_test
@always_bls
def test_sync_committee_rewards_empty_participants(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
committee_bits = [False for _ in committee_indices]
yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
@@ -220,7 +219,7 @@ def test_sync_committee_rewards_empty_participants(spec, state):
@spec_state_test
@always_bls
def test_invalid_signature_past_block(spec, state):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
committee_indices = compute_committee_indices(spec, state)
for _ in range(2):
# NOTE: need to transition twice to move beyond the degenerate case at genesis

View File

@@ -2,10 +2,19 @@ import random
from eth2spec.test.helpers.constants import (
MAINNET, MINIMAL,
)
from eth2spec.test.helpers.random import (
randomize_state
)
from eth2spec.test.helpers.state import (
has_active_balance_differential,
)
from eth2spec.test.helpers.sync_committee import (
get_committee_indices,
compute_committee_indices,
run_successful_sync_committee_test,
)
from eth2spec.test.helpers.voluntary_exits import (
get_unslashed_exited_validators,
)
from eth2spec.test.context import (
with_altair_and_later,
spec_state_test,
@@ -18,8 +27,8 @@ from eth2spec.test.context import (
)
def _test_harness_for_randomized_test_case(spec, state, duplicates=False, participation_fn=None):
committee_indices = get_committee_indices(spec, state, duplicates=duplicates)
def _test_harness_for_randomized_test_case(spec, state, expect_duplicates=False, participation_fn=None):
committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
if participation_fn:
participating_indices = participation_fn(committee_indices)
@@ -28,7 +37,7 @@ def _test_harness_for_randomized_test_case(spec, state, duplicates=False, partic
committee_bits = [index in participating_indices for index in committee_indices]
committee_size = len(committee_indices)
if duplicates:
if expect_duplicates:
assert committee_size > len(set(committee_indices))
else:
assert committee_size == len(set(committee_indices))
@@ -44,7 +53,7 @@ def test_random_only_one_participant_with_duplicates(spec, state):
yield from _test_harness_for_randomized_test_case(
spec,
state,
duplicates=True,
expect_duplicates=True,
participation_fn=lambda comm: [rng.choice(comm)],
)
@@ -57,7 +66,7 @@ def test_random_low_participation_with_duplicates(spec, state):
yield from _test_harness_for_randomized_test_case(
spec,
state,
duplicates=True,
expect_duplicates=True,
participation_fn=lambda comm: rng.sample(comm, int(len(comm) * 0.25)),
)
@@ -70,7 +79,7 @@ def test_random_high_participation_with_duplicates(spec, state):
yield from _test_harness_for_randomized_test_case(
spec,
state,
duplicates=True,
expect_duplicates=True,
participation_fn=lambda comm: rng.sample(comm, int(len(comm) * 0.75)),
)
@@ -83,7 +92,7 @@ def test_random_all_but_one_participating_with_duplicates(spec, state):
yield from _test_harness_for_randomized_test_case(
spec,
state,
duplicates=True,
expect_duplicates=True,
participation_fn=lambda comm: rng.sample(comm, len(comm) - 1),
)
@@ -98,7 +107,25 @@ def test_random_misc_balances_and_half_participation_with_duplicates(spec, state
yield from _test_harness_for_randomized_test_case(
spec,
state,
duplicates=True,
expect_duplicates=True,
participation_fn=lambda comm: rng.sample(comm, len(comm) // 2),
)
@with_altair_and_later
@with_presets([MAINNET], reason="to create duplicate committee")
@spec_state_test
@single_phase
def test_random_with_exits_with_duplicates(spec, state):
rng = random.Random(1402)
randomize_state(spec, state, rng=rng, exit_fraction=0.1, slash_fraction=0.0)
target_validators = get_unslashed_exited_validators(spec, state)
assert len(target_validators) != 0
assert has_active_balance_differential(spec, state)
yield from _test_harness_for_randomized_test_case(
spec,
state,
expect_duplicates=True,
participation_fn=lambda comm: rng.sample(comm, len(comm) // 2),
)
@@ -163,3 +190,20 @@ def test_random_misc_balances_and_half_participation_without_duplicates(spec, st
state,
participation_fn=lambda comm: rng.sample(comm, len(comm) // 2),
)
@with_altair_and_later
@with_presets([MINIMAL], reason="to create nonduplicate committee")
@spec_state_test
@single_phase
def test_random_with_exits_without_duplicates(spec, state):
rng = random.Random(1502)
randomize_state(spec, state, rng=rng, exit_fraction=0.1, slash_fraction=0.0)
target_validators = get_unslashed_exited_validators(spec, state)
assert len(target_validators) != 0
assert has_active_balance_differential(spec, state)
yield from _test_harness_for_randomized_test_case(
spec,
state,
participation_fn=lambda comm: rng.sample(comm, len(comm) // 2),
)

View File

@@ -9,7 +9,6 @@ from eth2spec.test.helpers.block import (
)
from eth2spec.test.helpers.block_processing import run_block_processing_to
from eth2spec.utils import bls
from eth2spec.utils.hash_function import hash
def compute_sync_committee_signature(spec, state, slot, privkey, block_root=None, domain_type=None):
@@ -75,10 +74,12 @@ def compute_sync_committee_proposer_reward(spec, state, committee_indices, commi
return spec.Gwei(participant_reward * participant_number)
def compute_committee_indices(spec, state, committee):
def compute_committee_indices(spec, state, committee=None):
"""
Given a ``committee``, calculate and return the related indices
"""
if committee is None:
committee = state.current_sync_committee
all_pubkeys = [v.pubkey for v in state.validators]
return [all_pubkeys.index(pubkey) for pubkey in committee.pubkeys]
@@ -153,6 +154,7 @@ def _build_block_for_next_slot_with_sync_participation(spec, state, committee_in
state,
block.slot - 1,
[index for index, bit in zip(committee_indices, committee_bits) if bit],
block_root=block.parent_root,
)
)
return block
@@ -161,23 +163,3 @@ def _build_block_for_next_slot_with_sync_participation(spec, state, committee_in
def run_successful_sync_committee_test(spec, state, committee_indices, committee_bits):
block = _build_block_for_next_slot_with_sync_participation(spec, state, committee_indices, committee_bits)
yield from run_sync_committee_processing(spec, state, block)
def get_committee_indices(spec, state, duplicates=False):
"""
This utility function allows the caller to ensure there are or are not
duplicate validator indices in the returned committee based on
the boolean ``duplicates``.
"""
state = state.copy()
current_epoch = spec.get_current_epoch(state)
randao_index = (current_epoch + 1) % spec.EPOCHS_PER_HISTORICAL_VECTOR
while True:
committee = spec.get_next_sync_committee_indices(state)
if duplicates:
if len(committee) != len(set(committee)):
return committee
else:
if len(committee) == len(set(committee)):
return committee
state.randao_mixes[randao_index] = hash(state.randao_mixes[randao_index])