def test_get_committee_assignment(genesis_state, slots_per_epoch, shard_count, config, num_validators, state_epoch, epoch, registry_change): state_slot = get_epoch_start_slot(state_epoch, slots_per_epoch) state = genesis_state.copy(slot=state_slot, ) proposer_count = 0 shard_validator_count = [0 for _ in range(shard_count)] slots = [] epoch_start_slot = get_epoch_start_slot(epoch, slots_per_epoch) for validator_index in range(num_validators): assignment = get_committee_assignment( state, config, epoch, validator_index, registry_change, ) assert assignment.slot >= epoch_start_slot assert assignment.slot < epoch_start_slot + slots_per_epoch if assignment.is_proposer: proposer_count += 1 shard_validator_count[assignment.shard] += 1 slots.append(assignment.slot) assert proposer_count == slots_per_epoch assert sum(shard_validator_count) == num_validators
def test_get_previous_epoch_matching_head_attestations( random, sample_state, genesis_epoch, slots_per_epoch, slots_per_historical_root, sample_attestation_data_params, sample_attestation_params): previous_epoch = 9 current_epoch = previous_epoch + 1 current_slot = get_epoch_start_slot(current_epoch + 1, slots_per_epoch) - 1 latest_block_roots = [ hash_eth2(b'block_root' + i.to_bytes(1, 'little')) for i in range(slots_per_historical_root) ] num_previous_epoch_attestation = random.sample(range(slots_per_epoch), 1)[0] previous_epoch_attestion_slots = random.sample( range( get_epoch_start_slot(previous_epoch, slots_per_epoch), get_epoch_start_slot(current_epoch, slots_per_epoch), ), num_previous_epoch_attestation, ) num_previous_epoch_head_attestation = random.sample( range(num_previous_epoch_attestation), 1)[0] previous_epoch_head_attestion_slots = random.sample( previous_epoch_attestion_slots, num_previous_epoch_head_attestation, ) previous_epoch_not_head_attestion_slots = set( previous_epoch_attestion_slots).difference( set(previous_epoch_head_attestion_slots)) previous_epoch_head_attestations = [] for slot in previous_epoch_head_attestion_slots: previous_epoch_head_attestations.append( Attestation(**sample_attestation_params).copy( data=AttestationData(**sample_attestation_data_params).copy( slot=slot, beacon_block_root=latest_block_roots[ slot % slots_per_historical_root], ), )) previous_epoch_not_head_attestations = [] for slot in previous_epoch_not_head_attestion_slots: previous_epoch_not_head_attestations.append( Attestation(**sample_attestation_params).copy(data=AttestationData( **sample_attestation_data_params).copy(slot=slot, ), )) state = sample_state.copy( slot=current_slot, latest_block_roots=latest_block_roots, previous_epoch_attestations=(previous_epoch_head_attestations + previous_epoch_not_head_attestations), ) result = get_previous_epoch_matching_head_attestations( state, slots_per_epoch, genesis_epoch, slots_per_historical_root, ) assert set(previous_epoch_head_attestations) == set(result)
def _process_rewards_and_penalties_for_crosslinks( state: BeaconState, config: Eth2Config, 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.SLOTS_PER_EPOCH, ) current_epoch_start_slot = get_epoch_start_slot( state.current_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) rewards_received = { ValidatorIndex(index): Gwei(0) for index in range(len(state.validator_registry)) } penalties_received = rewards_received.copy() for slot in range(previous_epoch_start_slot, current_epoch_start_slot): crosslink_committees_at_slot = get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), ) for crosslink_committee, shard in crosslink_committees_at_slot: winning_root, attesting_validator_indices = get_winning_root_and_participants( state=state, shard=shard, effective_balances=effective_balances, committee_config=CommitteeConfig(config), ) total_attesting_balance = get_total_balance( state.validator_balances, attesting_validator_indices, config.MAX_DEPOSIT_AMOUNT, ) total_balance = get_total_balance_from_effective_balances( effective_balances, crosslink_committee, ) for index in attesting_validator_indices: rewards_received = _update_rewards_or_penalies( index, base_rewards[index] * total_attesting_balance // total_balance, rewards_received, ) for index in set(crosslink_committee).difference( attesting_validator_indices): penalties_received = _update_rewards_or_penalies( index, base_rewards[index], penalties_received, ) return (rewards_received, penalties_received)
def get_epoch_boundary_attesting_balances( current_epoch: Epoch, previous_epoch: Epoch, state: 'BeaconState', config: 'BeaconConfig') -> Tuple[Gwei, Gwei]: current_epoch_attestations = get_current_epoch_attestations( state, config.SLOTS_PER_EPOCH) previous_epoch_attestations = get_previous_epoch_attestations( state, config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH, ) previous_epoch_boundary_root = get_block_root( state, get_epoch_start_slot(previous_epoch, config.SLOTS_PER_EPOCH), config.LATEST_BLOCK_ROOTS_LENGTH, ) previous_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices( state, current_epoch_attestations + previous_epoch_attestations, state.previous_justified_epoch, previous_epoch_boundary_root, CommitteeConfig(config), ) previous_epoch_boundary_attesting_balance = get_total_balance( state.validator_balances, previous_epoch_boundary_attester_indices, config.MAX_DEPOSIT_AMOUNT, ) current_epoch_boundary_root = get_block_root( state, get_epoch_start_slot(current_epoch, config.SLOTS_PER_EPOCH), config.LATEST_BLOCK_ROOTS_LENGTH, ) current_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices( state, current_epoch_attestations, state.justified_epoch, current_epoch_boundary_root, CommitteeConfig(config), ) current_epoch_boundary_attesting_balance = get_total_balance( state.validator_balances, current_epoch_boundary_attester_indices, config.MAX_DEPOSIT_AMOUNT, ) return previous_epoch_boundary_attesting_balance, current_epoch_boundary_attesting_balance
def test_process_ejections(genesis_state, config, activation_exit_delay): current_epoch = 8 state = genesis_state.copy( slot=get_epoch_start_slot(current_epoch, config.SLOTS_PER_EPOCH), ) delayed_activation_exit_epoch = get_delayed_activation_exit_epoch( current_epoch, activation_exit_delay, ) ejecting_validator_index = 0 validator = state.validator_registry[ejecting_validator_index] assert validator.is_active(current_epoch) assert validator.exit_epoch > delayed_activation_exit_epoch state = state.update_validator_balance( validator_index=ejecting_validator_index, balance=config.EJECTION_BALANCE - 1, ) result_state = process_ejections(state, config) result_validator = result_state.validator_registry[ejecting_validator_index] assert result_validator.is_active(current_epoch) assert result_validator.exit_epoch == delayed_activation_exit_epoch # The ejecting validator will be inactive at the exit_epoch assert not result_validator.is_active(result_validator.exit_epoch) # Other validators are not ejected assert ( result_state.validator_registry[ejecting_validator_index + 1].exit_epoch == FAR_FUTURE_EPOCH )
def test_process_exit_queue_eligible(genesis_state, config, current_epoch, min_validator_withdrawability_delay, withdrawable_epoch, exit_epoch, is_eligible): state = genesis_state.copy( slot=get_epoch_start_slot(current_epoch, config.SLOTS_PER_EPOCH) ) validator_index = 0 # Set eligible validators state = state.update_validator_registry( validator_index, state.validator_registry[validator_index].copy( withdrawable_epoch=withdrawable_epoch, exit_epoch=exit_epoch, ) ) result_state = process_exit_queue(state, config) if is_eligible: # Check if they got prepared for withdrawal assert ( result_state.validator_registry[validator_index].withdrawable_epoch == current_epoch + min_validator_withdrawability_delay ) else: assert ( result_state.validator_registry[validator_index].withdrawable_epoch == state.validator_registry[validator_index].withdrawable_epoch )
def test_validate_voluntary_validator_exit_epoch(genesis_state, current_epoch, validator_exit_epoch, slots_per_epoch, activation_exit_delay, success): state = genesis_state.copy(slot=get_epoch_start_slot( current_epoch, slots_per_epoch), ) validator_index = 0 validator = state.validator_registry[validator_index].copy( exit_epoch=validator_exit_epoch, ) if success: validate_voluntary_exit_validator_exit_epoch( state, validator, current_epoch, slots_per_epoch, activation_exit_delay, ) else: with pytest.raises(ValidationError): validate_voluntary_exit_validator_exit_epoch( state, validator, current_epoch, slots_per_epoch, activation_exit_delay, )
def test_get_attesting_indices(genesis_state, config): state = genesis_state.copy( slot=get_epoch_start_slot(3, config.SLOTS_PER_EPOCH)) target_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) target_shard = (state.start_shard + 3) % config.SHARD_COUNT some_committee = get_crosslink_committee( state, target_epoch, target_shard, CommitteeConfig(config), ) data = AttestationData( target_epoch=target_epoch, crosslink=Crosslink(shard=target_shard, ), ) some_subset_count = random.randint(1, len(some_committee) // 2) some_subset = random.sample(some_committee, some_subset_count) bitfield = get_empty_bitfield(len(some_committee)) for i, index in enumerate(some_committee): if index in some_subset: bitfield = set_voted(bitfield, i) indices = get_attesting_indices( state, data, bitfield, CommitteeConfig(config), ) assert set(indices) == set(some_subset) assert len(indices) == len(some_subset)
def test_get_matching_head_attestations(genesis_state, config): some_epoch = config.GENESIS_EPOCH + 20 some_slot = get_epoch_start_slot( some_epoch, config.SLOTS_PER_EPOCH) + config.SLOTS_PER_EPOCH // 4 some_target_root = b'\x33' * 32 target_attestations = tuple((PendingAttestation(data=AttestationData( beacon_block_root=some_target_root, target_epoch=some_epoch - 1, crosslink=Crosslink(shard=i, )), ) for i in range(3))) current_epoch_attestations = target_attestations + tuple( (PendingAttestation(data=AttestationData( beacon_block_root=b'\x44' * 32, target_epoch=some_epoch - 1, ), ) for _ in range(3))) state = genesis_state.copy( slot=some_slot - 1, block_roots=tuple(some_target_root for _ in range(config.SLOTS_PER_HISTORICAL_ROOT)), current_epoch_attestations=current_epoch_attestations, ) attestations = get_matching_head_attestations( state, some_epoch, config, ) assert attestations == target_attestations
def test_get_matching_target_attestations(genesis_state, config): some_epoch = config.GENESIS_EPOCH + 20 some_slot = get_epoch_start_slot(some_epoch, config.SLOTS_PER_EPOCH) some_target_root = b'\x33' * 32 target_attestations = tuple((PendingAttestation(data=AttestationData( target_root=some_target_root, ), ) for _ in range(3))) current_epoch_attestations = target_attestations + tuple( (PendingAttestation(data=AttestationData(target_root=b'\x44' * 32, ), ) for _ in range(3))) state = genesis_state.copy( slot=some_slot + 1, block_roots=update_tuple_item( genesis_state.block_roots, some_slot % config.SLOTS_PER_HISTORICAL_ROOT, some_target_root, ), current_epoch_attestations=current_epoch_attestations, ) attestations = get_matching_target_attestations( state, some_epoch, config, ) assert attestations == target_attestations
def test_get_matching_source_attestations(genesis_state, current_epoch, target_epoch, success, config): state = genesis_state.copy( slot=get_epoch_start_slot(current_epoch, config.SLOTS_PER_EPOCH), current_epoch_attestations=tuple( PendingAttestation(data=AttestationData( beacon_block_root=current_epoch.to_bytes(32, "little"), ))), previous_epoch_attestations=tuple( PendingAttestation(data=AttestationData(beacon_block_root=( current_epoch - 1).to_bytes(32, "little"), )))) if success: attestations = get_matching_source_attestations( state, target_epoch, config, ) else: with pytest.raises(InvalidEpochError): get_matching_source_attestations( state, target_epoch, config, ) return if current_epoch == target_epoch: assert attestations == state.current_epoch_attestations else: assert attestations == state.previous_epoch_attestations
def test_get_next_epoch_committee_assignment(genesis_state, epoch_length, shard_count, config, num_validators, registry_change): state = genesis_state proposer_count = 0 shard_validator_count = [0 for _ in range(shard_count)] slots = [] next_epoch_start = get_epoch_start_slot( state.current_epoch(epoch_length) + 1, epoch_length) for validator_index in range(num_validators): assignment = get_next_epoch_committee_assignment( state, config, validator_index, registry_change, ) assert assignment.slot >= next_epoch_start assert assignment.slot < next_epoch_start + epoch_length if assignment.is_proposer: proposer_count += 1 shard_validator_count[assignment.shard] += 1 slots.append(assignment.slot) assert proposer_count == epoch_length assert sum(shard_validator_count) == num_validators
def validate_attestation_justified_epoch(attestation_data: AttestationData, current_epoch: EpochNumber, previous_justified_epoch: EpochNumber, justified_epoch: EpochNumber, epoch_length: int) -> None: """ Validate ``justified_epoch`` field of ``attestation_data``. Raise ``ValidationError`` if it's invalid. """ if attestation_data.slot >= get_epoch_start_slot(current_epoch, epoch_length): if attestation_data.justified_epoch != justified_epoch: raise ValidationError( "Attestation ``slot`` is after recent epoch transition but attestation" "``justified_epoch`` is not targeting the ``justified_epoch``:\n" "\tFound: %s, Expected %s" % (attestation_data.justified_epoch, justified_epoch) ) else: if attestation_data.justified_epoch != previous_justified_epoch: raise ValidationError( "Attestation ``slot`` is before recent epoch transition but attestation" "``justified_epoch`` is not targeting the ``previous_justified_epoch:\n" "\tFound: %s, Expected %s" % (attestation_data.justified_epoch, previous_justified_epoch) )
def create_mock_attester_slashing_is_surround_vote( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_epoch: Epoch) -> AttesterSlashing: # target_epoch_2 < target_epoch_1 attestation_slot_2 = get_epoch_start_slot(attestation_epoch, config.SLOTS_PER_EPOCH) attestation_slot_1 = Slot(attestation_slot_2 + config.SLOTS_PER_EPOCH) slashable_attestation_1 = create_mock_slashable_attestation( state.copy( slot=attestation_slot_1, current_justified_epoch=config.GENESIS_EPOCH, ), config, keymap, attestation_slot_1, ) slashable_attestation_2 = create_mock_slashable_attestation( state.copy( slot=attestation_slot_1, current_justified_epoch=config.GENESIS_EPOCH + 1, # source_epoch_1 < source_epoch_2 ), config, keymap, attestation_slot_2, ) return AttesterSlashing( attestation_1=slashable_attestation_1, attestation_2=slashable_attestation_2, )
def create_mock_attester_slashing_is_double_vote( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_epoch: Epoch) -> AttesterSlashing: attestation_slot_1 = get_epoch_start_slot(attestation_epoch, config.SLOTS_PER_EPOCH) attestation_slot_2 = Slot(attestation_slot_1 + 1) slashable_attestation_1 = create_mock_slashable_attestation( state, config, keymap, attestation_slot_1, ) slashable_attestation_2 = create_mock_slashable_attestation( state, config, keymap, attestation_slot_2, ) return AttesterSlashing( slashable_attestation_1=slashable_attestation_1, slashable_attestation_2=slashable_attestation_2, )
def test_validate_validator_minimum_lifespan(genesis_state, keymap, current_epoch, activation_epoch, slots_per_epoch, persistent_committee_period, success): state = genesis_state.copy(slot=get_epoch_start_slot( current_epoch, slots_per_epoch), ) validator_index = 0 validator = state.validators[validator_index].copy( activation_epoch=activation_epoch, ) state = state.update_validator(validator_index, validator) if success: _validate_validator_minimum_lifespan( validator, state.current_epoch(slots_per_epoch), persistent_committee_period, ) else: with pytest.raises(ValidationError): _validate_validator_minimum_lifespan( validator, state.current_epoch(slots_per_epoch), persistent_committee_period, )
def test_validate_eligible_exit_epoch(genesis_state, keymap, current_epoch, voluntary_exit_epoch, slots_per_epoch, config, success): state = genesis_state.copy(slot=get_epoch_start_slot( current_epoch, slots_per_epoch), ) validator_index = 0 voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, exit_epoch=voluntary_exit_epoch, ) if success: _validate_eligible_exit_epoch( voluntary_exit.epoch, state.current_epoch(slots_per_epoch), ) else: with pytest.raises(ValidationError): _validate_eligible_exit_epoch( voluntary_exit.epoch, state.current_epoch(slots_per_epoch), )
def test_validate_attestation_source_epoch_and_root( genesis_state, sample_attestation_data_params, attestation_slot, attestation_source_epoch, attestation_source_root, current_epoch, previous_justified_epoch, current_justified_epoch, previous_justified_root, current_justified_root, slots_per_epoch, is_valid): state = genesis_state.copy( slot=get_epoch_start_slot(current_epoch, slots_per_epoch), previous_justified_epoch=previous_justified_epoch, current_justified_epoch=current_justified_epoch, previous_justified_root=previous_justified_root, current_justified_root=current_justified_root, ) attestation_data = AttestationData(**sample_attestation_data_params).copy( slot=attestation_slot, source_epoch=attestation_source_epoch, source_root=attestation_source_root, ) if is_valid: validate_attestation_source_epoch_and_root( state, attestation_data, current_epoch, slots_per_epoch, ) else: with pytest.raises(ValidationError): validate_attestation_source_epoch_and_root( state, attestation_data, current_epoch, slots_per_epoch, )
def test_validate_voluntary_exit_persistent(genesis_state, keymap, current_epoch, activation_epoch, slots_per_epoch, persistent_committee_period, success): state = genesis_state.copy(slot=get_epoch_start_slot( current_epoch, slots_per_epoch), ) validator_index = 0 validator = state.validator_registry[validator_index].copy( activation_epoch=activation_epoch, ) state = state.update_validator_registry(validator_index, validator) if success: validate_voluntary_exit_persistent( validator, state.current_epoch(slots_per_epoch), persistent_committee_period, ) else: with pytest.raises(ValidationError): validate_voluntary_exit_persistent( validator, state.current_epoch(slots_per_epoch), persistent_committee_period, )
def test_generate_seed(genesis_state, committee_config, slots_per_epoch, min_seed_lookahead, activation_exit_delay, epochs_per_historical_vector): def mock_get_randao_mix(state, epoch, slots_per_epoch, epochs_per_historical_vector, perform_validation=False): return hash_eth2( state.root + epoch.to_bytes(32, byteorder='little') + epochs_per_historical_vector.to_bytes(32, byteorder='little') ) def mock_get_active_index_root(state, epoch, slots_per_epoch, activation_exit_delay, epochs_per_historical_vector): return hash_eth2( state.root + epoch.to_bytes(32, byteorder='little') + slots_per_epoch.to_bytes(32, byteorder='little') + epochs_per_historical_vector.to_bytes(32, byteorder='little') ) state = genesis_state epoch = 1 state = state.copy( slot=get_epoch_start_slot(epoch, committee_config.SLOTS_PER_EPOCH), ) epoch_as_bytes = epoch.to_bytes(32, 'little') seed = _generate_seed( state=state, epoch=epoch, randao_provider=mock_get_randao_mix, active_index_root_provider=mock_get_active_index_root, epoch_provider=lambda *_: epoch_as_bytes, committee_config=committee_config, ) assert seed == hash_eth2( mock_get_randao_mix( state=state, epoch=(epoch + epochs_per_historical_vector - min_seed_lookahead), slots_per_epoch=slots_per_epoch, epochs_per_historical_vector=epochs_per_historical_vector, ) + mock_get_active_index_root( state=state, epoch=epoch, slots_per_epoch=slots_per_epoch, activation_exit_delay=activation_exit_delay, epochs_per_historical_vector=epochs_per_historical_vector, ) + epoch_as_bytes )
def _validate_withdrawable_epoch(state_slot: Slot, validator_withdrawable_epoch: Epoch, slots_per_epoch: int) -> None: if state_slot >= get_epoch_start_slot(validator_withdrawable_epoch, slots_per_epoch): raise ValidationError( f"state.slot ({state_slot}) should be less than " f"validator.withdrawable_epoch ({validator_withdrawable_epoch})")
def create_mock_signed_attestations_at_slot( state: BeaconState, config: Eth2Config, attestation_slot: Slot, beacon_block_root: Hash32, keymap: Dict[BLSPubkey, int], voted_attesters_ratio: float=1.0) -> Iterable[Attestation]: """ Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``. """ slots_per_epoch = config.SLOTS_PER_EPOCH crosslink_committees_at_slot = get_crosslink_committees_at_slot( # To avoid the epoch boundary cases state.copy( slot=state.slot + 1, ), attestation_slot, CommitteeConfig(config), ) # Get `target_root` target_root = _get_target_root(state, config, beacon_block_root) # Get `source_root` source_root = get_block_root( state, get_epoch_start_slot(state.justified_epoch, slots_per_epoch), config.SLOTS_PER_HISTORICAL_ROOT, ) for crosslink_committee in crosslink_committees_at_slot: committee, shard = crosslink_committee num_voted_attesters = int(len(committee) * voted_attesters_ratio) previous_crosslink = state.latest_crosslinks[shard] attestation_data = AttestationData( slot=attestation_slot, beacon_block_root=beacon_block_root, source_epoch=state.justified_epoch, source_root=source_root, target_root=target_root, shard=shard, previous_crosslink=previous_crosslink, crosslink_data_root=ZERO_HASH32, ) num_voted_attesters = int(len(committee) * voted_attesters_ratio) yield create_mock_signed_attestation( state, attestation_data, committee, num_voted_attesters, keymap, config.SLOTS_PER_EPOCH, )
def test_process_voluntary_exits(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, success): state = genesis_state.copy(slot=get_epoch_start_slot( config.GENESIS_EPOCH + config.PERSISTENT_COMMITTEE_PERIOD, config.SLOTS_PER_EPOCH, ), ) validator_index = 0 validator = state.validators[validator_index].copy( activation_epoch=config.GENESIS_EPOCH, ) state = state.update_validator(validator_index, validator) valid_voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(valid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) new_state = process_voluntary_exits( state, block, config, ) updated_validator = new_state.validators[validator_index] assert updated_validator.exit_epoch != FAR_FUTURE_EPOCH assert updated_validator.exit_epoch > state.current_epoch( config.SLOTS_PER_EPOCH) assert updated_validator.withdrawable_epoch == ( updated_validator.exit_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY) else: invalid_voluntary_exit = valid_voluntary_exit.copy( signature=b'\x12' * 96, # Put wrong signature ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(invalid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_voluntary_exits( state, block, config, )
def get_committee_assignment( state: BeaconState, config: BeaconConfig, epoch: Epoch, validator_index: ValidatorIndex, registry_change: bool = False) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index`` and ``registry_change``. ``CommitteeAssignment.committee`` is the tuple array of validators in the committee ``CommitteeAssignment.shard`` is the shard to which the committee is assigned ``CommitteeAssignment.slot`` is the slot at which the committee is assigned ``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) 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, committee_config, registry_change=registry_change, ) selected_committees = [ committee for committee in crosslink_committees if validator_index in committee[0] ] if len(selected_committees) > 0: validators = selected_committees[0][0] shard = selected_committees[0][1] 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) raise NoCommitteeAssignment
def validate_attestation(state: BeaconState, attestation: Attestation, genesis_epoch: EpochNumber, epoch_length: int, min_attestation_inclusion_delay: int, latest_block_roots_length: int, target_committee_size: int, shard_count: int) -> None: """ Validate the given ``attestation``. Raise ``ValidationError`` if it's invalid. """ validate_attestation_slot( attestation.data, state.slot, epoch_length, min_attestation_inclusion_delay, ) validate_attestation_justified_epoch( attestation.data, state.current_epoch(epoch_length), state.previous_justified_epoch, state.justified_epoch, epoch_length, ) validate_attestation_justified_block_root( attestation.data, justified_block_root=get_block_root( state=state, slot=get_epoch_start_slot(attestation.data.justified_epoch, epoch_length), latest_block_roots_length=latest_block_roots_length, ), ) validate_attestation_latest_crosslink_root( attestation.data, latest_crosslink_root=state.latest_crosslinks[attestation.data.shard].shard_block_root, ) validate_attestation_shard_block_root(attestation.data) validate_attestation_aggregate_signature( state, attestation, genesis_epoch, epoch_length, target_committee_size, shard_count, )
def validate_attestation(state: BeaconState, attestation: Attestation, min_attestation_inclusion_delay: int, slots_per_historical_root: int, committee_config: CommitteeConfig) -> None: """ Validate the given ``attestation``. Raise ``ValidationError`` if it's invalid. """ slots_per_epoch = committee_config.SLOTS_PER_EPOCH validate_attestation_slot( attestation.data, state.slot, slots_per_epoch, min_attestation_inclusion_delay, committee_config.GENESIS_SLOT, ) validate_attestation_source_epoch( attestation.data, state.current_epoch(slots_per_epoch), state.previous_justified_epoch, state.justified_epoch, slots_per_epoch, ) validate_attestation_source_root( attestation.data, justified_epoch=get_block_root( state=state, slot=get_epoch_start_slot( attestation.data.source_epoch, slots_per_epoch, ), slots_per_historical_root=slots_per_historical_root, ), ) validate_attestation_previous_crosslink_or_root( attestation_data=attestation.data, state_latest_crosslink=state.latest_crosslinks[attestation.data.shard], slots_per_epoch=slots_per_epoch, ) validate_attestation_crosslink_data_root(attestation.data) validate_attestation_aggregate_signature( state, attestation, committee_config, )
def _get_target_root(state: BeaconState, config: Eth2Config, beacon_block_root: Hash32) -> Hash32: epoch_start_slot = get_epoch_start_slot( slot_to_epoch(state.slot, config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) if epoch_start_slot == state.slot: return beacon_block_root else: return get_block_root( state, epoch_start_slot, config.SLOTS_PER_HISTORICAL_ROOT, )
def validate_attestation(state: BeaconState, attestation: Attestation, min_attestation_inclusion_delay: int, latest_block_roots_length: int, committee_config: CommitteeConfig) -> None: """ Validate the given ``attestation``. Raise ``ValidationError`` if it's invalid. """ epoch_length = committee_config.EPOCH_LENGTH validate_attestation_slot( attestation.data, state.slot, epoch_length, min_attestation_inclusion_delay, ) validate_attestation_justified_epoch( attestation.data, state.current_epoch(epoch_length), state.previous_justified_epoch, state.justified_epoch, epoch_length, ) validate_attestation_justified_block_root( attestation.data, justified_block_root=get_block_root( state=state, slot=get_epoch_start_slot( attestation.data.justified_epoch, epoch_length, ), latest_block_roots_length=latest_block_roots_length, ), ) validate_attestation_latest_crosslink_root( attestation.data, latest_crosslink_root=state.latest_crosslinks[ attestation.data.shard].shard_block_root, ) validate_attestation_shard_block_root(attestation.data) validate_attestation_aggregate_signature( state, attestation, committee_config, )
def test_process_voluntary_exits(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, success): state = genesis_state.copy(slot=get_epoch_start_slot( config.GENESIS_EPOCH + config.PERSISTENT_COMMITTEE_PERIOD, config.SLOTS_PER_EPOCH, ), ) validator_index = 0 validator = state.validator_registry[validator_index].copy( activation_epoch=config.GENESIS_EPOCH, ) state = state.update_validator_registry(validator_index, validator) valid_voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(valid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) new_state = process_voluntary_exits( state, block, config, ) # Check if initiated exit assert (new_state.validator_registry[validator_index].initiated_exit) else: invalid_voluntary_exit = valid_voluntary_exit.copy( signature=b'\x12' * 96, # Put wrong signature ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(invalid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_voluntary_exits( state, block, config, )
def _get_epoch_boundary_root(state: BeaconState, config: BeaconConfig, beacon_block_root: Hash32) -> Hash32: epoch_start_slot = get_epoch_start_slot( slot_to_epoch(state.slot, config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) if epoch_start_slot == state.slot: return beacon_block_root else: return get_block_root( state, epoch_start_slot, config.LATEST_BLOCK_ROOTS_LENGTH, )