diff --git a/eth2/beacon/committee_helpers.py b/eth2/beacon/committee_helpers.py index 87723f7094..d3a28fa3ce 100644 --- a/eth2/beacon/committee_helpers.py +++ b/eth2/beacon/committee_helpers.py @@ -289,13 +289,12 @@ def get_crosslink_committees_at_slot( """ Return the list of ``(committee, shard)`` tuples for the ``slot``. """ - genesis_epoch = committee_config.GENESIS_EPOCH shard_count = committee_config.SHARD_COUNT slots_per_epoch = committee_config.SLOTS_PER_EPOCH epoch = slot_to_epoch(slot, slots_per_epoch) current_epoch = state.current_epoch(slots_per_epoch) - previous_epoch = state.previous_epoch(slots_per_epoch, genesis_epoch) + previous_epoch = state.previous_epoch(slots_per_epoch) next_epoch = state.next_epoch(slots_per_epoch) validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) @@ -358,12 +357,8 @@ def get_beacon_proposer_index(state: 'BeaconState', 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) + previous_epoch = state.previous_epoch(committee_config.SLOTS_PER_EPOCH) + next_epoch = state.next_epoch(committee_config.SLOTS_PER_EPOCH) validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) diff --git a/eth2/beacon/epoch_processing_helpers.py b/eth2/beacon/epoch_processing_helpers.py index 27a1bab170..b8aa0a5994 100644 --- a/eth2/beacon/epoch_processing_helpers.py +++ b/eth2/beacon/epoch_processing_helpers.py @@ -56,12 +56,11 @@ def get_previous_epoch_boundary_attestations( state: 'BeaconState', slots_per_epoch: int, - genesis_epoch: Epoch, latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]: beacon_block_root = get_block_root( state, get_epoch_start_slot( - state.previous_epoch(slots_per_epoch, genesis_epoch), + state.previous_epoch(slots_per_epoch), slots_per_epoch, ), latest_block_roots_length, @@ -75,7 +74,6 @@ def get_previous_epoch_boundary_attestations( def get_previous_epoch_matching_head_attestations( state: 'BeaconState', slots_per_epoch: int, - genesis_epoch: Epoch, latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]: for attestation in state.previous_epoch_attestations: beacon_block_root = get_block_root( @@ -162,12 +160,79 @@ def get_epoch_boundary_attester_indices( ) +@to_tuple +def get_attesting_indices(state: 'BeaconState', + attestations: Sequence[PendingAttestationRecord], + config: CommitteeConfig) -> Iterable[ValidatorIndex]: + output: Set[ValidatorIndex] = set() + for a in attestations: + participants = get_attestation_participants(state, a.data, a.aggregation_bitfield, config) + output = output.union(participants) + for result in sorted(output): + yield result + + +def get_attesting_balance(state: 'BeaconState', + attestations: Sequence[PendingAttestationRecord], + config: 'BeaconConfig') -> Gwei: + return get_total_balance( + state.validator_balances, + get_attesting_indices(state, attestations, CommitteeConfig(config)), + config.MAX_DEPOSIT_AMOUNT, + ) + + +@to_tuple +def _get_boundary_attestations_in_epoch( + *, + state: 'BeaconState', + attestations: Sequence[PendingAttestationRecord], + epoch: Epoch, + config: 'BeaconConfig') -> Iterable[PendingAttestationRecord]: + slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH) + for a in attestations: + block_root = get_block_root( + state, + slot, + config.LATEST_BLOCK_ROOTS_LENGTH + ) + if a.data.epoch_boundary_root == block_root: + yield a + + +def _get_current_epoch_boundary_attestations( + state: 'BeaconState', + config: 'BeaconConfig') -> Tuple[PendingAttestationRecord]: + current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) + current_epoch_attestations = state.current_epoch_attestations + + return _get_boundary_attestations_in_epoch( + state=state, + attestations=current_epoch_attestations, + epoch=current_epoch, + config=config, + ) + + +def _get_previous_epoch_boundary_attestations( + state: 'BeaconState', + config: 'BeaconConfig') -> Tuple[PendingAttestationRecord]: + previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) + previous_epoch_attestations = state.previous_epoch_attestations + + return _get_boundary_attestations_in_epoch( + state=state, + attestations=previous_epoch_attestations, + epoch=previous_epoch, + config=config, + ) + + def get_epoch_boundary_attesting_balances( current_epoch: Epoch, previous_epoch: Epoch, state: 'BeaconState', config: 'BeaconConfig') -> Tuple[Gwei, Gwei]: - previous_epoch_boundary_root = get_block_root( state, get_epoch_start_slot(previous_epoch, config.SLOTS_PER_EPOCH), diff --git a/eth2/beacon/state_machines/forks/serenity/epoch_processing.py b/eth2/beacon/state_machines/forks/serenity/epoch_processing.py index 524aa58db2..f6da47754d 100644 --- a/eth2/beacon/state_machines/forks/serenity/epoch_processing.py +++ b/eth2/beacon/state_machines/forks/serenity/epoch_processing.py @@ -210,7 +210,7 @@ def _get_finalized_epoch( def process_justification(state: BeaconState, config: BeaconConfig) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) - previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) + previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) current_epoch_justifiable, previous_epoch_justifiable = _current_previous_epochs_justifiable( state, @@ -275,7 +275,7 @@ def process_crosslinks(state: BeaconState, config: BeaconConfig) -> BeaconState: for index in range(len(state.validator_registry)) } previous_epoch_start_slot = get_epoch_start_slot( - state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), + state.previous_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) next_epoch_start_slot = get_epoch_start_slot( @@ -523,7 +523,6 @@ def _process_rewards_and_penalties_for_finality( previous_epoch_boundary_attestations = get_previous_epoch_boundary_attestations( state, config.SLOTS_PER_EPOCH, - config.GENESIS_EPOCH, config.LATEST_BLOCK_ROOTS_LENGTH, ) previous_epoch_boundary_attester_indices = get_attester_indices_from_attestations( @@ -535,7 +534,6 @@ def _process_rewards_and_penalties_for_finality( previous_epoch_head_attestations = get_previous_epoch_matching_head_attestations( state, config.SLOTS_PER_EPOCH, - config.GENESIS_EPOCH, config.LATEST_BLOCK_ROOTS_LENGTH, ) previous_epoch_head_attester_indices = get_attester_indices_from_attestations( @@ -582,7 +580,7 @@ def _process_rewards_and_penalties_for_crosslinks( effective_balances: Dict[ValidatorIndex, Gwei], base_rewards: Dict[ValidatorIndex, Gwei]) -> Tuple[Dict[ValidatorIndex, Gwei], Dict[ValidatorIndex, Gwei]]: # noqa: E501 previous_epoch_start_slot = get_epoch_start_slot( - state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), + state.previous_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) current_epoch_start_slot = get_epoch_start_slot( @@ -637,9 +635,14 @@ def process_rewards_and_penalties(state: BeaconState, config: BeaconConfig) -> B previous_epoch_active_validator_indices = set( get_active_validator_indices( state.validator_registry, - state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) + state.previous_epoch(config.SLOTS_PER_EPOCH) ) ) + + # do not proceed if there are no validators in the previous epoch + if not previous_epoch_active_validator_indices: + return state + previous_total_balance: Gwei = get_total_balance( state.validator_balances, tuple(previous_epoch_active_validator_indices), diff --git a/eth2/beacon/state_machines/forks/serenity/operation_processing.py b/eth2/beacon/state_machines/forks/serenity/operation_processing.py index 19c680eec5..2d8d5f86bb 100644 --- a/eth2/beacon/state_machines/forks/serenity/operation_processing.py +++ b/eth2/beacon/state_machines/forks/serenity/operation_processing.py @@ -139,7 +139,7 @@ def process_attestations(state: BeaconState, ) # update attestations - previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) + previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) new_previous_epoch_pending_attestations = [] new_current_epoch_pending_attestations = [] diff --git a/eth2/beacon/tools/builder/validator.py b/eth2/beacon/tools/builder/validator.py index 74596dea1d..51a945f956 100644 --- a/eth2/beacon/tools/builder/validator.py +++ b/eth2/beacon/tools/builder/validator.py @@ -635,9 +635,8 @@ def get_committee_assignment( ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to propose a beacon block at the assigned slot. """ - current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) - previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) - next_epoch = Epoch(current_epoch + 1) + previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) + next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) diff --git a/eth2/beacon/types/states.py b/eth2/beacon/types/states.py index f1e7e3b118..8af1c10d23 100644 --- a/eth2/beacon/types/states.py +++ b/eth2/beacon/types/states.py @@ -303,8 +303,8 @@ def update_validator(self, def current_epoch(self, slots_per_epoch: int) -> Epoch: return slot_to_epoch(self.slot, slots_per_epoch) - def previous_epoch(self, slots_per_epoch: int, genesis_epoch: int) -> Epoch: - return Epoch(max(self.current_epoch(slots_per_epoch) - 1, genesis_epoch)) + def previous_epoch(self, slots_per_epoch: int) -> Epoch: + return Epoch(self.current_epoch(slots_per_epoch) - 1) def next_epoch(self, slots_per_epoch: int) -> Epoch: return Epoch(self.current_epoch(slots_per_epoch) + 1) diff --git a/tests/eth2/beacon/state_machines/forks/test_serenity_epoch_processing.py b/tests/eth2/beacon/state_machines/forks/test_serenity_epoch_processing.py index 664335ec4f..6c1364a24a 100644 --- a/tests/eth2/beacon/state_machines/forks/test_serenity_epoch_processing.py +++ b/tests/eth2/beacon/state_machines/forks/test_serenity_epoch_processing.py @@ -740,7 +740,7 @@ def mock_get_beacon_proposer_index(state, } prev_epoch_start_slot = get_epoch_start_slot( - state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), slots_per_epoch, + state.previous_epoch(config.SLOTS_PER_EPOCH), slots_per_epoch, ) prev_epoch_crosslink_committees = [ get_crosslink_committees_at_slot( diff --git a/tests/eth2/beacon/state_machines/test_state_transition.py b/tests/eth2/beacon/state_machines/test_state_transition.py index 33108dd5db..3248b4aff5 100644 --- a/tests/eth2/beacon/state_machines/test_state_transition.py +++ b/tests/eth2/beacon/state_machines/test_state_transition.py @@ -16,7 +16,8 @@ 'genesis_slot,' ), [ - (0), + # start high enough so that we do not end up with negative numbers + (104), ] ) @pytest.mark.parametrize( @@ -54,6 +55,8 @@ def test_per_slot_transition(base_db, config, state_slot, keymap): + state_slot += config.GENESIS_SLOT + chaindb = BeaconChainDB(base_db) chaindb.persist_block(genesis_block, SerenityBeaconBlock) chaindb.persist_state(genesis_state) diff --git a/tests/eth2/beacon/test_committee_helpers.py b/tests/eth2/beacon/test_committee_helpers.py index 6d78fb9b58..c67de0b5ba 100644 --- a/tests/eth2/beacon/test_committee_helpers.py +++ b/tests/eth2/beacon/test_committee_helpers.py @@ -326,10 +326,9 @@ def mock_get_epoch_committee_count( @pytest.mark.parametrize( ( 'genesis_slot,' - 'genesis_epoch,' ), [ - (0, 0), + 0, ], ) @pytest.mark.parametrize( @@ -387,7 +386,6 @@ def test_get_crosslink_committees_at_slot( slots_per_epoch, target_committee_size, shard_count, - genesis_epoch, committee_config, registry_change, should_reseed, @@ -473,8 +471,8 @@ def mock_generate_seed(state, # epoch = slot_to_epoch(slot, slots_per_epoch) current_epoch = state.current_epoch(slots_per_epoch) - previous_epoch = state.previous_epoch(slots_per_epoch, genesis_epoch) - next_epoch = current_epoch + 1 + previous_epoch = state.previous_epoch(slots_per_epoch) + next_epoch = state.next_epoch(slots_per_epoch) if epoch == current_epoch: seed = state.current_shuffling_seed @@ -507,10 +505,9 @@ def mock_generate_seed(state, @pytest.mark.parametrize( ( 'genesis_slot,' - 'genesis_epoch,' ), [ - (0, 0), + 0, ], ) @pytest.mark.parametrize( @@ -547,7 +544,6 @@ def test_get_beacon_proposer_index( registry_change, success, sample_state, - genesis_epoch, target_committee_size, shard_count, committee_config): @@ -632,7 +628,6 @@ def test_get_attestation_participants( aggregation_bitfield, expected, sample_state, - genesis_epoch, target_committee_size, shard_count, committee_config, diff --git a/tests/eth2/beacon/test_epoch_processing_helpers.py b/tests/eth2/beacon/test_epoch_processing_helpers.py index eeb605ab7a..ee508ec1db 100644 --- a/tests/eth2/beacon/test_epoch_processing_helpers.py +++ b/tests/eth2/beacon/test_epoch_processing_helpers.py @@ -21,7 +21,6 @@ ) from eth2.beacon.configs import CommitteeConfig from eth2.beacon.epoch_processing_helpers import ( - get_epoch_boundary_attester_indices, get_epoch_boundary_attesting_balances, get_inclusion_infos, get_previous_epoch_matching_head_attestations, @@ -77,7 +76,6 @@ def get_aggregation_bitfield(attestation_participants, target_committee_size): ) def test_get_current_and_previous_epoch_attestations(random, sample_state, - genesis_epoch, slots_per_epoch, sample_attestation_data_params, sample_attestation_params): @@ -135,7 +133,6 @@ def test_get_current_and_previous_epoch_attestations(random, def test_get_previous_epoch_matching_head_attestations( random, sample_state, - genesis_epoch, slots_per_epoch, latest_block_roots_length, sample_attestation_data_params, @@ -196,7 +193,6 @@ def test_get_previous_epoch_matching_head_attestations( result = get_previous_epoch_matching_head_attestations( state, slots_per_epoch, - genesis_epoch, latest_block_roots_length, ) assert set(previous_epoch_head_attestations) == set(result) @@ -338,109 +334,6 @@ def mock_get_crosslink_committees_at_slot(state, assert set(attesting_validator_indices) == set(block_root_1_participants) -@settings(max_examples=1) -@given(random=st.randoms()) -def test_get_epoch_boundary_attester_indices(monkeypatch, - random, - sample_attestation_params, - sample_attestation_data_params, - sample_state, - committee_config): - target_committee_size = 16 - committee = tuple([i for i in range(target_committee_size)]) - - from eth2.beacon import committee_helpers - - def mock_get_crosslink_committees_at_slot(state, - slot, - committee_config, - registry_change=False): - return ( - (committee, sample_attestation_data_params['shard'],), - ) - - monkeypatch.setattr( - committee_helpers, - 'get_crosslink_committees_at_slot', - mock_get_crosslink_committees_at_slot - ) - - block_root_1 = hash_eth2(b'block_root_1') - block_root_2 = hash_eth2(b'block_root_2') - - ( - attestation_participants_1, - attestation_participants_2, - not_attestation_participants_1, - ) = sampling_attestation_participants(random, committee, target_committee_size) - - # Generate bitfield of each participants set - aggregation_bitfield_1 = get_aggregation_bitfield( - attestation_participants_1, - target_committee_size, - ) - aggregation_bitfield_2 = get_aggregation_bitfield( - attestation_participants_2, - target_committee_size, - ) - not_aggregation_bitfield_1 = get_aggregation_bitfield( - not_attestation_participants_1, - target_committee_size, - ) - # `attestions` contains attestation to different block root by different set of participants - attestations = [ - # Attestation to `block_root_1` by `attestation_participants_1` - Attestation(**sample_attestation_params).copy( - aggregation_bitfield=aggregation_bitfield_1, - data=AttestationData(**sample_attestation_data_params).copy( - justified_epoch=1, - epoch_boundary_root=block_root_1, - ), - ), - # Attestation to `block_root_1` by `attestation_participants_2` - Attestation(**sample_attestation_params).copy( - aggregation_bitfield=aggregation_bitfield_2, - data=AttestationData(**sample_attestation_data_params).copy( - justified_epoch=1, - epoch_boundary_root=block_root_1, - ), - ), - # Attestation to `block_root_2` by `not_attestation_participants_1` - Attestation(**sample_attestation_params).copy( - aggregation_bitfield=not_aggregation_bitfield_1, - data=AttestationData(**sample_attestation_data_params).copy( - justified_epoch=2, - epoch_boundary_root=block_root_2, - ), - ), - ] - - block_root_1_attesting_validator = get_epoch_boundary_attester_indices( - state=sample_state, - attestations=attestations, - epoch=1, - root=block_root_1, - committee_config=committee_config, - ) - # Check that result is the union of two participants set - # `attestation_participants_1` and `attestation_participants_2` - assert set(block_root_1_attesting_validator) == set( - attestation_participants_1 + attestation_participants_2) - assert len(block_root_1_attesting_validator) == len( - set(attestation_participants_1 + attestation_participants_2)) - - block_root_2_attesting_validator = get_epoch_boundary_attester_indices( - state=sample_state, - attestations=attestations, - epoch=2, - root=block_root_2, - committee_config=committee_config, - ) - # Check that result is the `not_attestation_participants_1` set - assert set(block_root_2_attesting_validator) == set(not_attestation_participants_1) - assert len(block_root_2_attesting_validator) == len(not_attestation_participants_1) - - @settings(max_examples=1) @given(random=st.randoms()) @pytest.mark.parametrize(