From dc1b9ecb4a5f603dc32f3a1459141811fa12a29f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 4 Mar 2019 19:27:02 +0800 Subject: [PATCH] Sync with ethereum/eth2.0-specs#694: enhance `get_beacon_proposer_index` (#333) * Sync with ethereum/eth2.0-specs#694 * Fix mypy check * Update tests/eth2/beacon/test_beacon_validation.py Co-Authored-By: hwwhww --- eth2/beacon/committee_helpers.py | 22 ++++++--- eth2/beacon/tools/builder/validator.py | 31 ++++++------ eth2/beacon/validation.py | 22 ++++----- tests/eth2/beacon/test_beacon_validation.py | 48 ++++++++++++------- tests/eth2/beacon/test_committee_helpers.py | 18 ++++++- .../beacon/test_epoch_processing_helpers.py | 12 +++-- .../beacon/test_validator_status_helpers.py | 6 ++- 7 files changed, 99 insertions(+), 60 deletions(-) diff --git a/eth2/beacon/committee_helpers.py b/eth2/beacon/committee_helpers.py index bc0845e183..a2f761ccc6 100644 --- a/eth2/beacon/committee_helpers.py +++ b/eth2/beacon/committee_helpers.py @@ -42,7 +42,7 @@ ) from eth2.beacon.validation import ( validate_bitfield, - validate_epoch_for_current_epoch, + validate_epoch_within_previous_and_next, ) if TYPE_CHECKING: @@ -180,11 +180,7 @@ def get_crosslink_committees_at_slot( previous_epoch = state.previous_epoch(slots_per_epoch, genesis_epoch) next_epoch = state.next_epoch(slots_per_epoch) - validate_epoch_for_current_epoch( - current_epoch=current_epoch, - given_epoch=epoch, - genesis_epoch=genesis_epoch, - ) + validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) if epoch == current_epoch: committees_per_epoch = get_current_epoch_committee_count( @@ -281,14 +277,26 @@ def get_crosslink_committees_at_slot( def get_beacon_proposer_index(state: 'BeaconState', slot: Slot, - committee_config: CommitteeConfig) -> ValidatorIndex: + committee_config: CommitteeConfig, + registry_change: bool=False) -> ValidatorIndex: """ Return the beacon proposer index for the ``slot``. """ + epoch = slot_to_epoch(slot, committee_config.SLOTS_PER_EPOCH) + current_epoch = state.current_epoch(committee_config.SLOTS_PER_EPOCH) + previous_epoch = state.previous_epoch( + committee_config.SLOTS_PER_EPOCH, + committee_config.GENESIS_EPOCH, + ) + next_epoch = Epoch(current_epoch + 1) + + validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) + crosslink_committees_at_slot = get_crosslink_committees_at_slot( state=state, slot=slot, committee_config=committee_config, + registry_change=registry_change, ) try: first_crosslink_committee = crosslink_committees_at_slot[0] diff --git a/eth2/beacon/tools/builder/validator.py b/eth2/beacon/tools/builder/validator.py index 54d0249580..5f6a8bd454 100644 --- a/eth2/beacon/tools/builder/validator.py +++ b/eth2/beacon/tools/builder/validator.py @@ -16,7 +16,6 @@ ) from eth_utils import ( to_tuple, - ValidationError, ) from eth.constants import ( @@ -32,6 +31,7 @@ SignatureDomain, ) from eth2.beacon.committee_helpers import ( + get_beacon_proposer_index, get_crosslink_committees_at_slot, ) from eth2.beacon.configs import ( @@ -70,6 +70,9 @@ Slot, ValidatorIndex, ) +from eth2.beacon.validation import ( + validate_epoch_within_previous_and_next, +) from .committee_assignment import ( CommitteeAssignment, @@ -572,25 +575,19 @@ def get_committee_assignment( """ current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) - next_epoch = current_epoch + 1 + next_epoch = Epoch(current_epoch + 1) - if previous_epoch > epoch: - raise ValidationError( - f"The given epoch ({epoch}) is less than previous epoch ({previous_epoch})" - ) - - if epoch > next_epoch: - raise ValidationError( - f"The given epoch ({epoch}) is greater than next epoch ({previous_epoch})" - ) + validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH) + committee_config = CommitteeConfig(config) + for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH): crosslink_committees = get_crosslink_committees_at_slot( state, slot, - CommitteeConfig(config), + committee_config, registry_change=registry_change, ) selected_committees = [ @@ -601,10 +598,12 @@ def get_committee_assignment( if len(selected_committees) > 0: validators = selected_committees[0][0] shard = selected_committees[0][1] - first_committee_at_slot = crosslink_committees[0][0] # List[ValidatorIndex] - is_proposer = first_committee_at_slot[ - slot % len(first_committee_at_slot) - ] == validator_index + is_proposer = validator_index == get_beacon_proposer_index( + state, + Slot(slot), + committee_config, + registry_change=registry_change, + ) return CommitteeAssignment(validators, shard, Slot(slot), is_proposer) diff --git a/eth2/beacon/validation.py b/eth2/beacon/validation.py index 9e344719ac..5a6aa04f74 100644 --- a/eth2/beacon/validation.py +++ b/eth2/beacon/validation.py @@ -24,22 +24,22 @@ def validate_slot(slot: int, title: str="Slot") -> None: validate_lte(slot, 2**64 - 1, title) -def validate_epoch_for_current_epoch( - current_epoch: Epoch, - given_epoch: Epoch, - genesis_epoch: Epoch) -> None: - previous_epoch = current_epoch - 1 if current_epoch > genesis_epoch else current_epoch - next_epoch = current_epoch + 1 - - if given_epoch < previous_epoch: +def validate_epoch_within_previous_and_next( + epoch: Epoch, + previous_epoch: Epoch, + next_epoch: Epoch) -> None: + """ + Validate that ``previous_epoch <= epoch <= next_epoch``. + """ + if epoch < previous_epoch: raise ValidationError( f"previous_epoch ({previous_epoch}) should be less than " - f"or equal to given_epoch ({given_epoch})" + f"or equal to given_epoch ({epoch})" ) - if given_epoch > next_epoch: + if epoch > next_epoch: raise ValidationError( - f"given_epoch ({given_epoch}) should be less than next_epoch ({next_epoch})" + f"given_epoch ({epoch}) should be less than or equal to next_epoch ({next_epoch})" ) diff --git a/tests/eth2/beacon/test_beacon_validation.py b/tests/eth2/beacon/test_beacon_validation.py index cbb023f690..3e68aba445 100644 --- a/tests/eth2/beacon/test_beacon_validation.py +++ b/tests/eth2/beacon/test_beacon_validation.py @@ -17,7 +17,7 @@ from eth2.beacon.validation import ( validate_bitfield, validate_slot, - validate_epoch_for_current_epoch, + validate_epoch_within_previous_and_next, ) @@ -46,47 +46,59 @@ def test_validate_slot(slot, is_valid): @pytest.mark.parametrize( ( - 'current_epoch, epoch, success' + 'genesis_epoch' + ), + [ + (0), + ] +) +@pytest.mark.parametrize( + ( + 'epoch', + 'previous_epoch', + 'next_epoch', + 'success' ), [ ( - 0, 0, True, + 0, 0, 1, True, ), ( - 1, 0, True, + 0, 0, 2, True, ), ( - 2, 0, False, # epoch < previous_epoch + 0, 1, 3, False, # epoch < previous_epoch ), ( - 2, 2, True, + 2, 1, 3, True, ), ( - 2, 3, True, # next_epoch == epoch + 3, 1, 3, True, # next_epoch == epoch ), ( - 2, 4, False, # next_epoch < epoch + 4, 1, 3, False, # next_epoch < epoch ), ] ) -def test_validate_epoch_for_current_epoch( - current_epoch, +def test_validate_epoch_within_previous_and_next( epoch, + previous_epoch, + next_epoch, success, slots_per_epoch, genesis_epoch): if success: - validate_epoch_for_current_epoch( - current_epoch=current_epoch, - given_epoch=epoch, - genesis_epoch=genesis_epoch, + validate_epoch_within_previous_and_next( + epoch, + previous_epoch, + next_epoch, ) else: with pytest.raises(ValidationError): - validate_epoch_for_current_epoch( - current_epoch=current_epoch, - given_epoch=epoch, - genesis_epoch=genesis_epoch, + validate_epoch_within_previous_and_next( + epoch, + previous_epoch, + next_epoch, ) diff --git a/tests/eth2/beacon/test_committee_helpers.py b/tests/eth2/beacon/test_committee_helpers.py index 2a9523f69e..46a70ac41a 100644 --- a/tests/eth2/beacon/test_committee_helpers.py +++ b/tests/eth2/beacon/test_committee_helpers.py @@ -407,6 +407,15 @@ def mock_generate_seed(state, assert shuffling[committees_per_slot * offset] == crosslink_committees_at_slot[0][0] +@pytest.mark.parametrize( + ( + 'registry_change' + ), + [ + (True), + (False) + ] +) @pytest.mark.parametrize( ( 'num_validators,' @@ -438,6 +447,7 @@ def test_get_beacon_proposer_index( slots_per_epoch, committee, slot, + registry_change, success, sample_state, genesis_epoch, @@ -449,7 +459,8 @@ def test_get_beacon_proposer_index( def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, 1,), ) @@ -464,6 +475,7 @@ def mock_get_crosslink_committees_at_slot(state, sample_state, slot, committee_config, + registry_change=registry_change, ) assert proposer_index == committee[slot % len(committee)] else: @@ -472,6 +484,7 @@ def mock_get_crosslink_committees_at_slot(state, sample_state, slot, committee_config, + registry_change=registry_change, ) @@ -533,7 +546,8 @@ def test_get_attestation_participants( def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, shard,), ) diff --git a/tests/eth2/beacon/test_epoch_processing_helpers.py b/tests/eth2/beacon/test_epoch_processing_helpers.py index 00d5544c7a..ee6bbef757 100644 --- a/tests/eth2/beacon/test_epoch_processing_helpers.py +++ b/tests/eth2/beacon/test_epoch_processing_helpers.py @@ -244,7 +244,8 @@ def test_get_winning_root( def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, shard,), ) @@ -341,7 +342,8 @@ def test_get_epoch_boundary_attester_indices(monkeypatch, def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, sample_attestation_data_params['shard'],), ) @@ -456,7 +458,8 @@ def test_get_epoch_boundary_attesting_balances( def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, sample_attestation_data_params['shard'],), ) @@ -591,7 +594,8 @@ def test_get_inclusion_infos( def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, shard,), ) diff --git a/tests/eth2/beacon/test_validator_status_helpers.py b/tests/eth2/beacon/test_validator_status_helpers.py index 710f020609..38da3906aa 100644 --- a/tests/eth2/beacon/test_validator_status_helpers.py +++ b/tests/eth2/beacon/test_validator_status_helpers.py @@ -187,7 +187,8 @@ def test_settle_penality_to_validator_and_whistleblower(monkeypatch, def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, 1,), ) @@ -269,7 +270,8 @@ def test_slash_validator(monkeypatch, def mock_get_crosslink_committees_at_slot(state, slot, - committee_config): + committee_config, + registry_change=False): return ( (committee, 1,), )