From d126162ca8e687e0a687754b8e389f9cf68955b8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 10 Dec 2019 11:25:55 -0700 Subject: [PATCH 01/11] fix activation queue efficiency --- specs/core/0_beacon-chain.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9c7248c56..4caf8a862 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1311,17 +1311,16 @@ def process_registry_updates(state: BeaconState) -> None: if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: initiate_validator_exit(state, ValidatorIndex(index)) - # Queue validators eligible for activation and not dequeued for activation prior to finalized epoch + # Queue validators eligible for activation and not yet dequeued for activation prior activation_queue = sorted([ index for index, validator in enumerate(state.validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH - and validator.activation_epoch >= compute_activation_exit_epoch(state.finalized_checkpoint.epoch) + and validator.activation_epoch == FAR_FUTURE_EPOCH ], key=lambda index: state.validators[index].activation_eligibility_epoch) - # Dequeued validators for activation up to churn limit (without resetting activation epoch) + # Dequeued validators for activation up to churn limit for index in activation_queue[:get_validator_churn_limit(state)]: validator = state.validators[index] - if validator.activation_epoch == FAR_FUTURE_EPOCH: - validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) + validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) ``` #### Slashings From e4d710590a1b9421b4701eb0626f892fc8679e21 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 10 Dec 2019 11:49:26 -0700 Subject: [PATCH 02/11] add test for queue efficiency --- specs/core/0_beacon-chain.md | 2 +- .../test_process_registry_updates.py | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4caf8a862..35fd439c1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1311,7 +1311,7 @@ def process_registry_updates(state: BeaconState) -> None: if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: initiate_validator_exit(state, ValidatorIndex(index)) - # Queue validators eligible for activation and not yet dequeued for activation prior + # Queue validators eligible for activation and not yet dequeued for activation activation_queue = sorted([ index for index, validator in enumerate(state.validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index bfd992ffa..26eb26104 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -63,6 +63,34 @@ def test_activation_queue_sorting(spec, state): assert state.validators[churn_limit - 2].activation_epoch != spec.FAR_FUTURE_EPOCH +@with_all_phases +@spec_state_test +def test_activation_queue_efficiency(spec, state): + churn_limit = spec.get_validator_churn_limit(state) + mock_activations = churn_limit * 2 + + epoch = spec.get_current_epoch(state) + for i in range(mock_activations): + mock_deposit(spec, state, i) + state.validators[i].activation_eligibility_epoch = epoch + 1 + + # Run first registry update. Do not yield test vectors + for _ in run_process_registry_updates(spec, state): + pass + + # Half should churn in first run of registry update + for i in range(mock_activations): + if i < mock_activations // 2: + assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH + else: + assert state.validators[i].activation_epoch == spec.FAR_FUTURE_EPOCH + + # Second half should churn in second run of registry update + yield from run_process_registry_updates(spec, state) + for i in range(mock_activations): + assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH + + @with_all_phases @spec_state_test def test_ejection(spec, state): From 6610aeea2fabea028180b2123e8b93ed800554d9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Dec 2019 16:00:46 -0700 Subject: [PATCH 03/11] fix activation queue to finality --- specs/core/0_beacon-chain.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 35fd439c1..5f8b84376 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -601,6 +601,21 @@ def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch) ``` +#### `is_eligible_for_activation` + +```python +def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool: + """ + Check if ``validator`` is eligible for activation. + """ + return ( + # Was placed in activation queue prior to most recent finalized epoch + validator.activation_eligibility_epoch < state.finalized_checkpoint.epoch + # Has not yet been activated + and validator.activation_epoch == FAR_FUTURE_EPOCH + ) +``` + #### `is_slashable_attestation_data` ```python @@ -1314,8 +1329,7 @@ def process_registry_updates(state: BeaconState) -> None: # Queue validators eligible for activation and not yet dequeued for activation activation_queue = sorted([ index for index, validator in enumerate(state.validators) - if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH - and validator.activation_epoch == FAR_FUTURE_EPOCH + if is_eligible_for_activation(state, validator) ], key=lambda index: state.validators[index].activation_eligibility_epoch) # Dequeued validators for activation up to churn limit for index in activation_queue[:get_validator_churn_limit(state)]: From e117b58ae2269afc56d2ce2dce397cfbe21f8954 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Dec 2019 16:10:18 -0700 Subject: [PATCH 04/11] add queue eligibility helper --- specs/core/0_beacon-chain.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5f8b84376..210e1797f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -601,6 +601,20 @@ def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch) ``` +#### `is_eligible_for_activation_queue` + +```python +def is_eligible_for_activation_queue(validator: Validator) -> bool: + """ + Check if ``validator`` is eligible to be placed into the activation queue. + """ + return ( + validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH + and validator.effective_balance == MAX_EFFECTIVE_BALANCE + ) +``` + + #### `is_eligible_for_activation` ```python @@ -1317,10 +1331,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None: def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections for index, validator in enumerate(state.validators): - if ( - validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH - and validator.effective_balance == MAX_EFFECTIVE_BALANCE - ): + if is_eligible_for_activation_queue(validator): validator.activation_eligibility_epoch = get_current_epoch(state) if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: From e8d079b366ed4d1a81b9a5e5c9d503338d1d8721 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Dec 2019 17:06:14 -0700 Subject: [PATCH 05/11] fix and add tests for activation queue --- .../test_process_registry_updates.py | 80 ++++++++++++++++--- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index 26eb26104..b6bd47204 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -1,4 +1,7 @@ -from eth2spec.test.helpers.state import next_epoch +from eth2spec.test.helpers.state import ( + next_epoch, + next_epoch_with_attestations, +) from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with @@ -17,18 +20,71 @@ def mock_deposit(spec, state, index): @with_all_phases @spec_state_test -def test_activation(spec, state): +def test_add_to_activation_queue(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + index = 0 mock_deposit(spec, state, index) - for _ in range(spec.MAX_SEED_LOOKAHEAD + 1): - next_epoch(spec, state) + yield from run_process_registry_updates(spec, state) + + # validator moved into queue + assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH + assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + + +@with_all_phases +@spec_state_test +def test_activation_queue_to_activated_if_finalized(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 0 + mock_deposit(spec, state, index) + + # mock validator as having been in queue since before latest finalized + state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 + state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch - 1 + + assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) yield from run_process_registry_updates(spec, state) + # validator activated for future epoch assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH - assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + assert spec.is_active_validator( + state.validators[index], + spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + ) + + +@with_all_phases +@spec_state_test +def test_activation_queue_no_activation_no_finality(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 0 + mock_deposit(spec, state, index) + + # mock validator as having been in queue only since latest finalized (not before) + state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 + state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch + + assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + + yield from run_process_registry_updates(spec, state) + + # validator not activated + assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH @with_all_phases @@ -44,6 +100,10 @@ def test_activation_queue_sorting(spec, state): # give the last priority over the others state.validators[mock_activations - 1].activation_eligibility_epoch = epoch + # move state forward and finalize to allow for activations + state.slot += spec.SLOTS_PER_EPOCH * 3 + state.finalized_checkpoint.epoch = epoch + 2 + # make sure we are hitting the churn churn_limit = spec.get_validator_churn_limit(state) assert mock_activations > churn_limit @@ -74,6 +134,10 @@ def test_activation_queue_efficiency(spec, state): mock_deposit(spec, state, i) state.validators[i].activation_eligibility_epoch = epoch + 1 + # move state forward and finalize to allow for activations + state.slot += spec.SLOTS_PER_EPOCH * 3 + state.finalized_checkpoint.epoch = epoch + 2 + # Run first registry update. Do not yield test vectors for _ in run_process_registry_updates(spec, state): pass @@ -101,13 +165,11 @@ def test_ejection(spec, state): # Mock an ejection state.validators[index].effective_balance = spec.EJECTION_BALANCE - for _ in range(spec.MAX_SEED_LOOKAHEAD + 1): - next_epoch(spec, state) - yield from run_process_registry_updates(spec, state) assert state.validators[index].exit_epoch != spec.FAR_FUTURE_EPOCH + assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) assert not spec.is_active_validator( state.validators[index], - spec.get_current_epoch(state), + spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) ) From b6d7cd93e9706702490d87cdf2d9dd202c392a45 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Dec 2019 17:20:35 -0700 Subject: [PATCH 06/11] Add ejection/exit queue test --- .../test_process_registry_updates.py | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index b6bd47204..26a1a5a94 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -1,7 +1,4 @@ -from eth2spec.test.helpers.state import ( - next_epoch, - next_epoch_with_attestations, -) +from eth2spec.test.helpers.state import next_epoch from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with @@ -90,7 +87,10 @@ def test_activation_queue_no_activation_no_finality(spec, state): @with_all_phases @spec_state_test def test_activation_queue_sorting(spec, state): - mock_activations = 10 + churn_limit = spec.get_validator_churn_limit(state) + + # try to activate more than the per-epoch churn linmit + mock_activations = churn_limit * 2 epoch = spec.get_current_epoch(state) for i in range(mock_activations): @@ -104,10 +104,6 @@ def test_activation_queue_sorting(spec, state): state.slot += spec.SLOTS_PER_EPOCH * 3 state.finalized_checkpoint.epoch = epoch + 2 - # make sure we are hitting the churn - churn_limit = spec.get_validator_churn_limit(state) - assert mock_activations > churn_limit - yield from run_process_registry_updates(spec, state) # the first got in as second @@ -173,3 +169,30 @@ def test_ejection(spec, state): state.validators[index], spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) ) + + +@with_all_phases +@spec_state_test +def test_ejection_past_churn_limit(spec, state): + churn_limit = spec.get_validator_churn_limit(state) + + # try to eject more than per-epoch churn limit + mock_ejections = churn_limit * 3 + + for i in range(mock_ejections): + state.validators[i].effective_balance = spec.EJECTION_BALANCE + + expected_ejection_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + + yield from run_process_registry_updates(spec, state) + + for i in range(mock_ejections): + # first third ejected in normal speed + if i < mock_ejections // 3: + assert state.validators[i].exit_epoch == expected_ejection_epoch + # second thirdgets delayed by 1 epoch + elif mock_ejections // 3 <= i < mock_ejections * 2 // 3: + assert state.validators[i].exit_epoch == expected_ejection_epoch + 1 + # second thirdgets delayed by 2 epochs + else: + assert state.validators[i].exit_epoch == expected_ejection_epoch + 2 From 45620e345d1daf6146efa39d212869e9acb9db1e Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Dec 2019 17:31:05 -0700 Subject: [PATCH 07/11] add test for activation_queue, activation, and ejection all in one --- .../test_process_registry_updates.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index 26a1a5a94..a4655b33e 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -196,3 +196,52 @@ def test_ejection_past_churn_limit(spec, state): # second thirdgets delayed by 2 epochs else: assert state.validators[i].exit_epoch == expected_ejection_epoch + 2 + + +@with_all_phases +@spec_state_test +def test_activation_queue_activation_and_ejection(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + # ready for entrance into activation queue + activation_queue_index = 0 + mock_deposit(spec, state, activation_queue_index) + + # ready for activation + activation_index = 1 + mock_deposit(spec, state, activation_index) + state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 + state.validators[activation_index].activation_eligibility_epoch = state.finalized_checkpoint.epoch - 1 + + # ready for ejection + ejection_index = 2 + state.validators[ejection_index].effective_balance = spec.EJECTION_BALANCE + + yield from run_process_registry_updates(spec, state) + + # validator moved into activation queue + validator = state.validators[activation_queue_index] + assert validator.activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert validator.activation_epoch == spec.FAR_FUTURE_EPOCH + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + + # validator activated for future epoch + validator = state.validators[activation_index] + assert validator.activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert validator.activation_epoch != spec.FAR_FUTURE_EPOCH + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + assert spec.is_active_validator( + validator, + spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + ) + + # validator ejected for future epoch + validator = state.validators[ejection_index] + assert validator.exit_epoch != spec.FAR_FUTURE_EPOCH + assert spec.is_active_validator(validator, spec.get_current_epoch(state)) + assert not spec.is_active_validator( + validator, + spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + ) From 19ec01e4e919252108876168b116f3e511784854 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 12 Dec 2019 06:43:37 -0700 Subject: [PATCH 08/11] add comment about activation queue sort order Co-Authored-By: Hsiao-Wei Wang --- specs/core/0_beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 210e1797f..ff0d42634 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1341,7 +1341,8 @@ def process_registry_updates(state: BeaconState) -> None: activation_queue = sorted([ index for index, validator in enumerate(state.validators) if is_eligible_for_activation(state, validator) - ], key=lambda index: state.validators[index].activation_eligibility_epoch) + # Order by the sequence of activation_eligibility_epoch setting and then index. + ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) # Dequeued validators for activation up to churn limit for index in activation_queue[:get_validator_churn_limit(state)]: validator = state.validators[index] From 86fb3acd59a51be40c04e7a56e50d3ea51c43d71 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 12 Dec 2019 06:53:56 -0700 Subject: [PATCH 09/11] minor changes to finality in activation queue --- specs/core/0_beacon-chain.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ff0d42634..f9a726ff4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -623,8 +623,8 @@ def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool Check if ``validator`` is eligible for activation. """ return ( - # Was placed in activation queue prior to most recent finalized epoch - validator.activation_eligibility_epoch < state.finalized_checkpoint.epoch + # Placement in queue is finalized + validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch # Has not yet been activated and validator.activation_epoch == FAR_FUTURE_EPOCH ) @@ -1332,7 +1332,7 @@ def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections for index, validator in enumerate(state.validators): if is_eligible_for_activation_queue(validator): - validator.activation_eligibility_epoch = get_current_epoch(state) + validator.activation_eligibility_epoch = get_current_epoch(state) + 1 if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: initiate_validator_exit(state, ValidatorIndex(index)) @@ -1341,7 +1341,7 @@ def process_registry_updates(state: BeaconState) -> None: activation_queue = sorted([ index for index, validator in enumerate(state.validators) if is_eligible_for_activation(state, validator) - # Order by the sequence of activation_eligibility_epoch setting and then index. + # Order by the sequence of activation_eligibility_epoch setting and then index ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) # Dequeued validators for activation up to churn limit for index in activation_queue[:get_validator_churn_limit(state)]: From 199933cb2664061e0ebff273ef9bf0c5f4b024a8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 12 Dec 2019 06:57:11 -0700 Subject: [PATCH 10/11] fix tocs --- specs/core/0_beacon-chain.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f9a726ff4..b74a29e9d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -61,6 +61,8 @@ - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) - [Predicates](#predicates) - [`is_active_validator`](#is_active_validator) + - [`is_eligible_for_activation_queue`](#is_eligible_for_activation_queue) + - [`is_eligible_for_activation`](#is_eligible_for_activation) - [`is_slashable_validator`](#is_slashable_validator) - [`is_slashable_attestation_data`](#is_slashable_attestation_data) - [`is_valid_indexed_attestation`](#is_valid_indexed_attestation) @@ -591,16 +593,6 @@ def is_active_validator(validator: Validator, epoch: Epoch) -> bool: return validator.activation_epoch <= epoch < validator.exit_epoch ``` -#### `is_slashable_validator` - -```python -def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: - """ - Check if ``validator`` is slashable. - """ - return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch) -``` - #### `is_eligible_for_activation_queue` ```python @@ -614,7 +606,6 @@ def is_eligible_for_activation_queue(validator: Validator) -> bool: ) ``` - #### `is_eligible_for_activation` ```python @@ -630,6 +621,16 @@ def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool ) ``` +#### `is_slashable_validator` + +```python +def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: + """ + Check if ``validator`` is slashable. + """ + return (not validator.slashed) and (validator.activation_epoch <= epoch < validator.withdrawable_epoch) +``` + #### `is_slashable_attestation_data` ```python From ba8a67ccd89fa068dd4ba4d88ac788d095deba21 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 12 Dec 2019 07:31:51 -0700 Subject: [PATCH 11/11] update registry tests to modified finality condition --- .../test_process_registry_updates.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index a4655b33e..526aba277 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -43,9 +43,9 @@ def test_activation_queue_to_activated_if_finalized(spec, state): index = 0 mock_deposit(spec, state, index) - # mock validator as having been in queue since before latest finalized + # mock validator as having been in queue since latest finalized state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 - state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch - 1 + state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) @@ -71,9 +71,9 @@ def test_activation_queue_no_activation_no_finality(spec, state): index = 0 mock_deposit(spec, state, index) - # mock validator as having been in queue only since latest finalized (not before) + # mock validator as having been in queue only after latest finalized state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 - state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch + state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch + 1 assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) @@ -102,7 +102,7 @@ def test_activation_queue_sorting(spec, state): # move state forward and finalize to allow for activations state.slot += spec.SLOTS_PER_EPOCH * 3 - state.finalized_checkpoint.epoch = epoch + 2 + state.finalized_checkpoint.epoch = epoch + 1 yield from run_process_registry_updates(spec, state) @@ -132,7 +132,7 @@ def test_activation_queue_efficiency(spec, state): # move state forward and finalize to allow for activations state.slot += spec.SLOTS_PER_EPOCH * 3 - state.finalized_checkpoint.epoch = epoch + 2 + state.finalized_checkpoint.epoch = epoch + 1 # Run first registry update. Do not yield test vectors for _ in run_process_registry_updates(spec, state): @@ -213,7 +213,7 @@ def test_activation_queue_activation_and_ejection(spec, state): activation_index = 1 mock_deposit(spec, state, activation_index) state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 - state.validators[activation_index].activation_eligibility_epoch = state.finalized_checkpoint.epoch - 1 + state.validators[activation_index].activation_eligibility_epoch = state.finalized_checkpoint.epoch # ready for ejection ejection_index = 2