extend inactivity updates tests
This commit is contained in:
parent
153e1b34dd
commit
48382ce09c
|
@ -1,26 +1,20 @@
|
|||
from random import Random
|
||||
|
||||
from eth2spec.test.context import spec_state_test, with_altair_and_later
|
||||
from eth2spec.test.helpers.inactivity_scores import randomize_inactivity_scores
|
||||
from eth2spec.test.helpers.inactivity_scores import randomize_inactivity_scores, zero_inactivity_scores
|
||||
from eth2spec.test.helpers.state import (
|
||||
next_epoch_via_block,
|
||||
set_full_participation, set_full_participation_previous_epoch,
|
||||
set_empty_participation,
|
||||
)
|
||||
from eth2spec.test.helpers.epoch_processing import (
|
||||
run_epoch_processing_with
|
||||
)
|
||||
from eth2spec.test.helpers.random import (
|
||||
randomize_attestation_participation,
|
||||
randomize_previous_epoch_participation,
|
||||
)
|
||||
|
||||
|
||||
def set_full_participation(spec, state):
|
||||
full_flags = spec.ParticipationFlags(0)
|
||||
for flag_index in range(len(spec.PARTICIPATION_FLAG_WEIGHTS)):
|
||||
full_flags = spec.add_flag(full_flags, flag_index)
|
||||
|
||||
for index in range(len(state.validators)):
|
||||
state.current_epoch_participation[index] = full_flags
|
||||
state.previous_epoch_participation[index] = full_flags
|
||||
from eth2spec.test.helpers.rewards import leaking
|
||||
|
||||
|
||||
def run_process_inactivity_updates(spec, state):
|
||||
|
@ -33,58 +27,169 @@ def test_genesis(spec, state):
|
|||
yield from run_process_inactivity_updates(spec, state)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_genesis_random_scores(spec, state):
|
||||
rng = Random(10102)
|
||||
state.inactivity_scores = [rng.randint(0, 100) for _ in state.inactivity_scores]
|
||||
pre_scores = state.inactivity_scores.copy()
|
||||
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
|
||||
assert state.inactivity_scores == pre_scores
|
||||
|
||||
|
||||
#
|
||||
# Genesis epoch processing is skipped
|
||||
# Thus all of following tests all go past genesis epoch to test core functionality
|
||||
#
|
||||
|
||||
def run_inactivity_scores_test(spec, state, participation_fn=None, inactivity_scores_fn=None, rng=Random(10101)):
|
||||
next_epoch_via_block(spec, state)
|
||||
if participation_fn is not None:
|
||||
participation_fn(spec, state, rng=rng)
|
||||
if inactivity_scores_fn is not None:
|
||||
inactivity_scores_fn(spec, state, rng=rng)
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_all_zero_inactivity_scores_empty_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
state.inactivity_scores = [0] * len(state.validators)
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(spec, state, set_empty_participation, zero_inactivity_scores)
|
||||
assert set(state.inactivity_scores) == set([0])
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_all_zero_inactivity_scores_empty_participation_leaking(spec, state):
|
||||
yield from run_inactivity_scores_test(spec, state, set_empty_participation, zero_inactivity_scores)
|
||||
|
||||
# Should still in be leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
for score in state.inactivity_scores:
|
||||
assert score > 0
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_all_zero_inactivity_scores_random_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
state.inactivity_scores = [0] * len(state.validators)
|
||||
randomize_attestation_participation(spec, state, rng=Random(5555))
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
randomize_attestation_participation, zero_inactivity_scores, rng=Random(5555),
|
||||
)
|
||||
assert set(state.inactivity_scores) == set([0])
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_all_zero_inactivity_scores_random_participation_leaking(spec, state):
|
||||
# Only randompize participation in previous epoch to remain in leak
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
randomize_previous_epoch_participation, zero_inactivity_scores, rng=Random(5555),
|
||||
)
|
||||
|
||||
# Check still in leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
assert 0 in state.inactivity_scores
|
||||
assert len(set(state.inactivity_scores)) > 1
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_all_zero_inactivity_scores_full_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
set_full_participation(spec, state)
|
||||
state.inactivity_scores = [0] * len(state.validators)
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_full_participation, zero_inactivity_scores,
|
||||
)
|
||||
|
||||
assert set(state.inactivity_scores) == set([0])
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_all_zero_inactivity_scores_full_participation_leaking(spec, state):
|
||||
# Only set full participation in previous epoch to remain in leak
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_full_participation_previous_epoch, zero_inactivity_scores,
|
||||
)
|
||||
|
||||
# Check still in leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
assert set(state.inactivity_scores) == set([0])
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_random_inactivity_scores_empty_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
randomize_inactivity_scores(spec, state, rng=Random(9999))
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_empty_participation, randomize_inactivity_scores, Random(9999),
|
||||
)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_random_inactivity_scores_empty_participation_leaking(spec, state):
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_empty_participation, randomize_inactivity_scores, Random(9999),
|
||||
)
|
||||
|
||||
# Check still in leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_random_inactivity_scores_random_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
randomize_attestation_participation(spec, state, rng=Random(22222))
|
||||
randomize_inactivity_scores(spec, state, rng=Random(22222))
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
randomize_attestation_participation, randomize_inactivity_scores, Random(22222),
|
||||
)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_random_inactivity_scores_random_participation_leaking(spec, state):
|
||||
# Only randompize participation in previous epoch to remain in leak
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
randomize_previous_epoch_participation, randomize_inactivity_scores, Random(22222),
|
||||
)
|
||||
|
||||
# Check still in leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_random_inactivity_scores_full_participation(spec, state):
|
||||
next_epoch_via_block(spec, state)
|
||||
set_full_participation(spec, state)
|
||||
randomize_inactivity_scores(spec, state, rng=Random(33333))
|
||||
yield from run_process_inactivity_updates(spec, state)
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_full_participation, randomize_inactivity_scores, Random(33333),
|
||||
)
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_random_inactivity_scores_full_participation_leaking(spec, state):
|
||||
# Only set full participation in previous epoch to remain in leak
|
||||
yield from run_inactivity_scores_test(
|
||||
spec, state,
|
||||
set_full_participation_previous_epoch, randomize_inactivity_scores, Random(33333),
|
||||
)
|
||||
|
||||
# Check still in leak
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
|
|
@ -112,7 +112,7 @@ def test_random_high_inactivity_scores_leaking(spec, state):
|
|||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking(epochs=5)
|
||||
def test_random_high_inactivity_scores_leaking_5_epochs(spec, state):
|
||||
@leaking(epochs=8)
|
||||
def test_random_high_inactivity_scores_leaking_8_epochs(spec, state):
|
||||
randomize_inactivity_scores(spec, state, minimum=500000, maximum=5000000, rng=Random(9998))
|
||||
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(9998))
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import random
|
||||
from random import Random
|
||||
|
||||
from eth2spec.test.helpers.state import (
|
||||
state_transition_and_sign_block,
|
||||
next_epoch,
|
||||
next_epoch_via_block,
|
||||
set_full_participation_previous_epoch,
|
||||
)
|
||||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
|
@ -15,12 +16,14 @@ from eth2spec.test.context import (
|
|||
with_altair_and_later,
|
||||
spec_state_test,
|
||||
)
|
||||
from eth2spec.test.helpers.rewards import leaking
|
||||
from eth2spec.test.helpers.inactivity_scores import randomize_inactivity_scores
|
||||
|
||||
|
||||
def run_sync_committee_sanity_test(spec, state, fraction_full=1.0):
|
||||
def run_sync_committee_sanity_test(spec, state, fraction_full=1.0, rng=Random(454545)):
|
||||
all_pubkeys = [v.pubkey for v in state.validators]
|
||||
committee = [all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys]
|
||||
participants = random.sample(committee, int(len(committee) * fraction_full))
|
||||
participants = rng.sample(committee, int(len(committee) * fraction_full))
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
|
@ -51,7 +54,7 @@ def test_full_sync_committee_committee(spec, state):
|
|||
@spec_state_test
|
||||
def test_half_sync_committee_committee(spec, state):
|
||||
next_epoch(spec, state)
|
||||
yield from run_sync_committee_sanity_test(spec, state, fraction_full=0.5)
|
||||
yield from run_sync_committee_sanity_test(spec, state, fraction_full=0.5, rng=Random(1212))
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
|
@ -70,7 +73,7 @@ def test_full_sync_committee_committee_genesis(spec, state):
|
|||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_half_sync_committee_committee_genesis(spec, state):
|
||||
yield from run_sync_committee_sanity_test(spec, state, fraction_full=0.5)
|
||||
yield from run_sync_committee_sanity_test(spec, state, fraction_full=0.5, rng=Random(2323))
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
|
@ -81,11 +84,13 @@ def test_empty_sync_committee_committee_genesis(spec, state):
|
|||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
def test_inactivity_scores(spec, state):
|
||||
for _ in range(spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2):
|
||||
next_epoch_via_block(spec, state)
|
||||
|
||||
@leaking()
|
||||
def test_inactivity_scores_leaking(spec, state):
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
randomize_inactivity_scores(spec, state, rng=Random(5252))
|
||||
assert len(set(state.inactivity_scores)) > 1
|
||||
|
||||
previous_inactivity_scores = state.inactivity_scores.copy()
|
||||
|
||||
yield 'pre', state
|
||||
|
@ -97,5 +102,36 @@ def test_inactivity_scores(spec, state):
|
|||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
# No particiaption during a leak so all scores should increase
|
||||
for pre, post in zip(previous_inactivity_scores, state.inactivity_scores):
|
||||
assert post == pre + spec.config.INACTIVITY_SCORE_BIAS
|
||||
|
||||
|
||||
@with_altair_and_later
|
||||
@spec_state_test
|
||||
@leaking()
|
||||
def test_inactivity_scores_full_participation_leaking(spec, state):
|
||||
randomize_inactivity_scores(spec, state, rng=Random(5252))
|
||||
assert len(set(state.inactivity_scores)) > 1
|
||||
|
||||
# Only set full participation for previous epoch to remain in leak
|
||||
set_full_participation_previous_epoch(spec, state)
|
||||
|
||||
previous_inactivity_scores = state.inactivity_scores.copy()
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
# Block transition to next epoch
|
||||
block = build_empty_block(spec, state, slot=state.slot + spec.SLOTS_PER_EPOCH)
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
assert spec.is_in_inactivity_leak(state)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
# Full particiaption during a leak so all scores should decrease by 1
|
||||
print(previous_inactivity_scores)
|
||||
print(state.inactivity_scores)
|
||||
for pre, post in zip(previous_inactivity_scores, state.inactivity_scores):
|
||||
assert post == pre - 1
|
||||
|
|
|
@ -3,3 +3,7 @@ from random import Random
|
|||
|
||||
def randomize_inactivity_scores(spec, state, minimum=0, maximum=50000, rng=Random(4242)):
|
||||
state.inactivity_scores = [rng.randint(minimum, maximum) for _ in range(len(state.validators))]
|
||||
|
||||
|
||||
def zero_inactivity_scores(spec, state, rng=None):
|
||||
state.inactivity_scores = [0] * len(state.validators)
|
||||
|
|
|
@ -100,6 +100,13 @@ def randomize_epoch_participation(spec, state, epoch, rng):
|
|||
epoch_participation[index] = flags
|
||||
|
||||
|
||||
def randomize_previous_epoch_participation(spec, state, rng=Random(8020)):
|
||||
cached_prepare_state_with_attestations(spec, state)
|
||||
randomize_epoch_participation(spec, state, spec.get_previous_epoch(state), rng)
|
||||
if not is_post_altair(spec):
|
||||
state.current_epoch_attestations = []
|
||||
|
||||
|
||||
def randomize_attestation_participation(spec, state, rng=Random(8020)):
|
||||
cached_prepare_state_with_attestations(spec, state)
|
||||
randomize_epoch_participation(spec, state, spec.get_previous_epoch(state), rng)
|
||||
|
|
|
@ -260,9 +260,9 @@ def run_get_inactivity_penalty_deltas(spec, state):
|
|||
|
||||
def transition_state_to_leak(spec, state, epochs=None):
|
||||
if epochs is None:
|
||||
# +1 to trigger inactivity_score transitions
|
||||
epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 1
|
||||
assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
||||
# +2 because finality delay is based on previous_epoch and must be more than `MIN_EPOCHS_TO_INACTIVITY_PENALTY`
|
||||
epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2
|
||||
assert epochs > spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
||||
|
||||
for _ in range(epochs):
|
||||
next_epoch(spec, state)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from eth2spec.test.context import expect_assertion_error
|
||||
from eth2spec.test.context import expect_assertion_error, is_post_altair
|
||||
from eth2spec.test.helpers.block import apply_empty_block, sign_block, transition_unsigned_block
|
||||
|
||||
|
||||
|
@ -92,3 +92,44 @@ def state_transition_and_sign_block(spec, state, block, expect_fail=False):
|
|||
transition_unsigned_block(spec, state, block)
|
||||
block.state_root = state.hash_tree_root()
|
||||
return sign_block(spec, state, block)
|
||||
|
||||
|
||||
#
|
||||
# WARNING: The following functions can only be used post-altair due to the manipulation of participation flags directly
|
||||
#
|
||||
|
||||
|
||||
def _set_full_participation(spec, state, current=True, previous=True):
|
||||
assert is_post_altair(spec)
|
||||
|
||||
full_flags = spec.ParticipationFlags(0)
|
||||
for flag_index in range(len(spec.PARTICIPATION_FLAG_WEIGHTS)):
|
||||
full_flags = spec.add_flag(full_flags, flag_index)
|
||||
|
||||
for index in range(len(state.validators)):
|
||||
if current:
|
||||
state.current_epoch_participation[index] = full_flags.copy()
|
||||
if previous:
|
||||
state.previous_epoch_participation[index] = full_flags.copy()
|
||||
|
||||
|
||||
def set_full_participation(spec, state, rng=None):
|
||||
_set_full_participation(spec, state)
|
||||
|
||||
|
||||
def set_full_participation_previous_epoch(spec, state, rng=None):
|
||||
_set_full_participation(spec, state, current=False, previous=True)
|
||||
|
||||
|
||||
def _set_empty_participation(spec, state, current=True, previous=True):
|
||||
assert is_post_altair(spec)
|
||||
|
||||
for index in range(len(state.validators)):
|
||||
if current:
|
||||
state.current_epoch_participation[index] = spec.ParticipationFlags(0)
|
||||
if previous:
|
||||
state.previous_epoch_participation[index] = spec.ParticipationFlags(0)
|
||||
|
||||
|
||||
def set_empty_participation(spec, state, rng=None):
|
||||
_set_empty_participation(spec, state)
|
||||
|
|
Loading…
Reference in New Issue