-
Notifications
You must be signed in to change notification settings - Fork 998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new Altair transition tests #2664
Conversation
Thanks a lot! perhaps it may be worth adding the case that the slashed validator is assigned to a sync committee? Since in this case the penalties are active and the implementations may differ in how to add a slashing validator from phase 0? |
The approach looks good! Question -- what do the |
… at the fork block
@potuz # ensure that some of the current sync committee members are the slashed
slashed_pubkeys = [state.validators[index].pubkey for index in slashed_indices]
assert any(set(slashed_pubkeys).intersection(list(state.current_sync_committee.pubkeys))) I updated it in the new commits. Thank you!
|
@@ -0,0 +1,134 @@ | |||
import random |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the increasing diff. 😅
This file is mainly copied from test_transition.py
.
p.s. decided to name it fork_transition.py
rather than transition.py
because the most important "transition" helpers are in state.py
.
- sanity check: deposit operation is independent of spec fork versions - refactoring - add comments
91f63bb
to
67da1ba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
The tests are a bit verbose. Some might be able to be modularized in helper functions.. Not critical but consider if you see some opportunity.
We also might consider some of these tests to be done in both a leaking and non-leaking context. Maybe we do a mixed-use test (combination of all types here -- slashed, exited, queued, etc) and do a non-leaking and leaking form.
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
operation_dict = {'voluntary_exits': signed_exits} | ||
|
||
# irregular state transition to handle fork: | ||
state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this exit happens at the 0th block immediately after the fork transition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to also do one at the N-1 block to the fork?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, it seems that this exit is valid starting in the prior epoch (fork_epoch
- 1) and included in the "fork block", i.e. the first block after the fork transition occurs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could include an exit at the N-1 block but that kind of raises the question of the scope of this PR -- we could include operations at each N-1 block and N block (if the "fork block" is N) but then we have to ask if doing this by hand is the best way to test it...
there is also the question of operations in the N+1 block, but we could argue those cases are already covered by existing tests that just start in an Altair fork...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. Doing some random-operation fork-span tests might be the right way to capture more funcitonality beyond the hand written tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworked these tests into transition/test_operations.py
(3a242a1).
- use a
run_transition_with_operation
function to handle all types of operations- it could be done with some factories and cleaner, but I think it probably doesn't worth it for these tests. 😅
- added
fork slot-1
cases
we could argue those cases are already covered by existing tests that just start in an Altair fork...
I think the difference is that we use pre_spec
to create the operations here. Is this kind of tests already covered?
And indeed random-operation fork-span would cover more! Maybe in later PRs?
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_slashing.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great!
thanks to @potuz for raising the original issue and thanks @hwwhww for writing these tests!
overall the direction is good and these tests cover the cases we are concerned about. i left some minor feedback across the PR of various things to tighten/clean up before we merge.
one point that runs across the PR: you use transition_to_next_epoch_and_append_blocks
to generate an epoch's worth of blocks after the fork; in most (all?) of the tests, it isn't relevant to the thing we are testing to have a full epoch of blocks. to keep testing load smaller, i'd consider only making a handful of blocks after the fork (maybe even just 1 block).
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
operation_dict = {'voluntary_exits': signed_exits} | ||
|
||
# irregular state transition to handle fork: | ||
state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, it seems that this exit is valid starting in the prior epoch (fork_epoch
- 1) and included in the "fork block", i.e. the first block after the fork transition occurs.
operation_dict = {'voluntary_exits': signed_exits} | ||
|
||
# irregular state transition to handle fork: | ||
state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could include an exit at the N-1 block but that kind of raises the question of the scope of this PR -- we could include operations at each N-1 block and N block (if the "fork block" is N) but then we have to ask if doing this by hand is the best way to test it...
there is also the question of operations in the N+1 block, but we could argue those cases are already covered by existing tests that just start in an Altair fork...
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
|
||
yield "blocks", blocks | ||
yield "post", state | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if we should inflate this PR further, but following the symmetry of exits, there is a test case where a validator is de-queued for activation at the fork epoch...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good suggestion. I think transition/test_operation.py::test_transition_with_deposit_right_before_fork
now covers it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not just making a deposit but the case where a validator is already deposited and their activation_epoch == FORK_EPOCH
... not sure it is worth blocking this PR on this case though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added test_transition_with_activation_at_fork_epoch
!
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py
Outdated
Show resolved
Hide resolved
b861207
to
5081895
Compare
5081895
to
49bf78d
Compare
@djrtwo @ralexstokes I think I addressed or replied to the suggestions. I'm running |
I'm okay to release right after @ralexstokes puts his eyes on it one more time |
tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_inactivity_updates.py
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activations_and_exits.py
Outdated
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activations_and_exits.py
Show resolved
Hide resolved
tests/core/pyspec/eth2spec/test/altair/transition/test_activations_and_exits.py
Outdated
Show resolved
Hide resolved
# | ||
|
||
@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2) | ||
@with_presets([MINIMAL], reason="only test with non-full committee") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how do you mean "non-full"? like duplicates vs none in the sync committee?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated reason description: "only test with enough validators such that at least one exited index is not in sync committee"
It is when (almost) all validator indices are in sync committee, we may get False on
any(set(slashed_pubkeys).difference(list(state.current_sync_committee.pubkeys)))
check.
yield "pre", state | ||
|
||
# irregular state transition to handle fork: | ||
state, _ = do_altair_fork(state, spec, post_spec, fork_epoch, with_block=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we not want the block here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because slash_random_validators
may select the next block proposer. I didn't want to change slash_random_validators
too much. Do you feel strongly that we should add an avoid_next_proposer
flag to slash_random_validators
helper?
spec, state, slashed_index=selected_validator_index, signed_1=True, signed_2=True) | ||
operation_dict = {'proposer_slashings': [proposer_slashing]} | ||
elif operation_type == OperetionType.ATTESTER_SLASHING: | ||
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could also slash the proposer here, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes...!
Good catch! I updated state_transition_across_slots_with_ignoring_proposers
helper to avoid such cases. (162711e)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice updates! i left a few more comments on minor things about updating some code and/or formatting
@@ -53,7 +53,7 @@ def exit_random_validators(spec, state, rng, fraction=0.5, exit_epoch=None, with | |||
""" | |||
if from_epoch is None: | |||
from_epoch = spec.MAX_SEED_LOOKAHEAD + 1 | |||
epoch_diff = from_epoch - spec.get_current_epoch(state) | |||
epoch_diff = int(from_epoch) - int(spec.get_current_epoch(state)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, right we can't do signed arith here... whoops!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great! thanks for this and incorporating all the feedback :)
Fix #2662
Thank @potuz for the ideas. ✨
test_transition_with_one_fourth_slashed_active_validators_pre_fork
test_transition_with_one_fourth_exiting_validators_exit_post_fork
test_transition_with_one_fourth_exiting_validators_exit_at_fork
test_transition_with_leaking_pre_fork
test_transition_with_leaking_at_fork
test_transition_with_leaking_post_fork
test_transition_with_non_empty_activation_queue
Operations at the fork block:
test_transition_with_proposer_slashing_right_after_fork
test_transition_with_proposer_slashing_right_before_fork
test_transition_with_attester_slashing_right_after_fork
test_transition_with_attester_slashing_right_before_fork
test_transition_with_deposit_right_after_fork
test_transition_with_deposit_right_before_fork
test_transition_with_voluntary_exit_right_after_fork
test_transition_with_voluntary_exit_right_before_fork
TODO