def test_validate_attestation_aggregate_signature(genesis_state, slots_per_epoch, random, sample_attestation_data_params, is_valid, target_committee_size, shard_count, keymap, committee_config): state = genesis_state # choose committee slot = 0 crosslink_committee = get_crosslink_committees_at_slot( state=state, slot=slot, committee_config=committee_config, )[0] committee, shard = crosslink_committee committee_size = len(committee) assert committee_size > 0 # randomly select 3/4 participants from committee votes_count = len(committee) * 3 // 4 assert votes_count > 0 attestation_data = AttestationData(**sample_attestation_data_params).copy( slot=slot, shard=shard, ) attestation = create_mock_signed_attestation( state, attestation_data, committee, votes_count, keymap, slots_per_epoch, ) if is_valid: validate_attestation_aggregate_signature( state, attestation, committee_config, ) else: # mess up signature attestation = attestation.copy( aggregate_signature=( attestation.aggregate_signature[0] + 10, attestation.aggregate_signature[1] - 1 ) ) with pytest.raises(ValidationError): validate_attestation_aggregate_signature( state, attestation, committee_config, )
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 _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 create_mock_signed_attestations_at_slot( state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, 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``. """ state_transition = state_machine.state_transition state = state_transition.apply_state_transition_without_block( state, attestation_slot, ) crosslink_committees_at_slot = get_crosslink_committees_at_slot( state, attestation_slot, CommitteeConfig(config), ) # Get `target_root` target_root = _get_target_root(state, config, beacon_block_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.current_justified_epoch, source_root=state.current_justified_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 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 create_mock_signed_attestations_at_slot( state: BeaconState, config: BeaconConfig, attestation_slot: SlotNumber, keymap: Dict[BLSPubkey, int], voted_attesters_ratio: float=1.0) -> Iterable[Attestation]: """ Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``. """ crosslink_committees_at_slot = get_crosslink_committees_at_slot( state.copy( slot=state.slot + 1, ), slot=attestation_slot, genesis_epoch=config.GENESIS_EPOCH, epoch_length=config.EPOCH_LENGTH, target_committee_size=config.TARGET_COMMITTEE_SIZE, shard_count=config.SHARD_COUNT, ) for crosslink_committee in crosslink_committees_at_slot: committee, shard = crosslink_committee num_voted_attesters = int(len(committee) * voted_attesters_ratio) latest_crosslink_root = state.latest_crosslinks[shard].shard_block_root attestation_data = AttestationData( slot=attestation_slot, shard=shard, beacon_block_root=ZERO_HASH32, epoch_boundary_root=ZERO_HASH32, shard_block_root=ZERO_HASH32, latest_crosslink_root=latest_crosslink_root, justified_epoch=state.previous_justified_epoch, justified_block_root=get_block_root( state, get_epoch_start_slot(state.previous_justified_epoch, config.EPOCH_LENGTH), config.LATEST_BLOCK_ROOTS_LENGTH, ), ) yield create_mock_signed_attestation( state, attestation_data, committee, num_voted_attesters, keymap, config.EPOCH_LENGTH, )
def test_get_crosslink_committees_at_slot(n_validators_state, current_slot, slot, epoch_length, target_committee_size, shard_count, genesis_epoch): state = n_validators_state.copy(slot=current_slot, ) crosslink_committees_at_slot = get_crosslink_committees_at_slot( state=state, slot=slot, genesis_epoch=genesis_epoch, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count, ) assert len(crosslink_committees_at_slot) > 0 for crosslink_committee in crosslink_committees_at_slot: committee, shard = crosslink_committee assert len(committee) > 0 assert shard < shard_count
def get_next_epoch_committee_assignment( state: BeaconState, config: BeaconConfig, validator_index: ValidatorIndex, registry_change: bool) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the next 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.EPOCH_LENGTH) next_epoch = current_epoch + 1 next_epoch_start_slot = get_epoch_start_slot(next_epoch, config.EPOCH_LENGTH) for slot in range(next_epoch_start_slot, next_epoch_start_slot + config.EPOCH_LENGTH): crosslink_committees = get_crosslink_committees_at_slot( state, slot, CommitteeConfig(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] first_committee_at_slot = crosslink_committees[0][ 0] # List[ValidatorIndex] is_proposer = first_committee_at_slot[ slot % len(first_committee_at_slot)] == validator_index return CommitteeAssignment(validators, shard, slot, is_proposer) raise NoCommitteeAssignment
def test_get_crosslink_committees_at_slot( monkeypatch, genesis_slot, n_validators_state, current_slot, slot, slots_per_epoch, target_committee_size, shard_count, genesis_epoch, committee_config, registry_change, should_reseed, previous_shuffling_epoch, current_shuffling_epoch, shuffling_epoch): # Mock generate_seed new_seed = b'\x88' * 32 def mock_generate_seed(state, epoch, committee_config): return new_seed monkeypatch.setattr('eth2.beacon.helpers.generate_seed', mock_generate_seed) state = n_validators_state.copy( slot=current_slot, previous_shuffling_epoch=previous_shuffling_epoch, current_shuffling_epoch=current_shuffling_epoch, previous_shuffling_seed=b'\x11' * 32, current_shuffling_seed=b'\x22' * 32, ) crosslink_committees_at_slot = get_crosslink_committees_at_slot( state=state, slot=slot, committee_config=committee_config, registry_change=registry_change, ) assert len(crosslink_committees_at_slot) > 0 for crosslink_committee in crosslink_committees_at_slot: committee, shard = crosslink_committee assert len(committee) > 0 assert shard < shard_count # # Check shuffling_start_shard # offset = slot % slots_per_epoch result_slot_start_shard = crosslink_committees_at_slot[0][1] current_committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=shard_count, slots_per_epoch=slots_per_epoch, target_committee_size=target_committee_size, ) if registry_change: committees_per_epoch = current_committees_per_epoch shuffling_start_shard = (state.current_shuffling_start_shard + current_committees_per_epoch) % shard_count elif should_reseed: committees_per_epoch = get_next_epoch_committee_count( state=state, shard_count=shard_count, slots_per_epoch=slots_per_epoch, target_committee_size=target_committee_size, ) shuffling_start_shard = state.current_shuffling_start_shard else: committees_per_epoch = current_committees_per_epoch shuffling_start_shard = state.current_shuffling_start_shard committees_per_slot = committees_per_epoch // slots_per_epoch assert result_slot_start_shard == ( shuffling_start_shard + committees_per_slot * offset) % shard_count # # Check seed # epoch = slot_to_epoch(slot, slots_per_epoch) current_epoch = state.current_epoch(slots_per_epoch) previous_epoch = state.previous_epoch(slots_per_epoch) next_epoch = current_epoch + 1 if epoch == current_epoch: seed = state.current_shuffling_seed elif epoch == previous_epoch: seed = state.previous_shuffling_seed elif epoch == next_epoch: if registry_change or should_reseed: seed = new_seed else: seed = state.current_shuffling_seed shuffling = get_shuffling( seed=seed, validators=state.validator_registry, epoch=shuffling_epoch, committee_config=committee_config, ) assert shuffling[committees_per_slot * offset] == crosslink_committees_at_slot[0][0]
def process_crosslinks(state: BeaconState, config: BeaconConfig) -> BeaconState: """ Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec: https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks For each shard from the past two epochs, find the shard block root that has been attested to by the most stake. If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard. Return resulting ``state`` """ latest_crosslinks = state.latest_crosslinks previous_epoch_attestations = get_previous_epoch_attestations( state, config.EPOCH_LENGTH, config.GENESIS_EPOCH, ) current_epoch_attestations = get_current_epoch_attestations(state, config.EPOCH_LENGTH) prev_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.EPOCH_LENGTH, config.GENESIS_EPOCH), config.EPOCH_LENGTH, ) next_epoch_start_slot = get_epoch_start_slot( state.next_epoch(config.EPOCH_LENGTH), config.EPOCH_LENGTH, ) for slot in range(prev_epoch_start_slot, next_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: try: winning_root, total_attesting_balance = get_winning_root( state=state, shard=shard, # Use `_filter_attestations_by_shard` to filter out attestations # not attesting to this shard so we don't need to going over # irrelevent attestations over and over again. attestations=_filter_attestations_by_shard( previous_epoch_attestations + current_epoch_attestations, shard, ), max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, committee_config=CommitteeConfig(config), ) except NoWinningRootError: # No winning shard block root found for this shard. pass else: total_balance = sum( get_effective_balance(state.validator_balances, i, config.MAX_DEPOSIT_AMOUNT) for i in crosslink_committee ) if 3 * total_attesting_balance >= 2 * total_balance: latest_crosslinks = update_tuple_item( latest_crosslinks, shard, CrosslinkRecord( epoch=state.current_epoch(config.EPOCH_LENGTH), shard_block_root=winning_root, ), ) else: # Don't update the crosslink of this shard pass state = state.copy( latest_crosslinks=latest_crosslinks, ) return state
def _process_rewards_and_penalties_for_crosslinks( state: BeaconState, config: BeaconConfig, previous_epoch_attestations: Iterable[PendingAttestationRecord], effective_balances: Dict[ValidatorIndex, Gwei], base_rewards: Dict[ValidatorIndex, Gwei], old_rewards_received: Dict[ValidatorIndex, SignedGwei] ) -> Dict[ValidatorIndex, SignedGwei]: rewards_received = old_rewards_received.copy() previous_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), config.SLOTS_PER_EPOCH, ) current_epoch_start_slot = get_epoch_start_slot( state.current_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) # Also need current epoch attestations to compute the winning root. current_epoch_attestations = get_current_epoch_attestations( state, config.SLOTS_PER_EPOCH) 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: filtered_attestations = _filter_attestations_by_shard( previous_epoch_attestations + current_epoch_attestations, shard, ) try: winning_root, total_attesting_balance = get_winning_root( state=state, shard=shard, attestations=filtered_attestations, max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, committee_config=CommitteeConfig(config), ) except NoWinningRootError: # No winning shard block root found for this shard. # Hence no one is counted as attesting validator. attesting_validator_indices: Iterable[ValidatorIndex] = set() else: attesting_validator_indices = get_attester_indices_from_attesttion( state=state, attestations=(a for a in filtered_attestations if a.data.shard == shard and a.data.crosslink_data_root == winning_root), committee_config=CommitteeConfig(config), ) total_balance = get_total_balance_from_effective_balances( effective_balances, crosslink_committee, ) for index in attesting_validator_indices: reward = base_rewards[ index] * total_attesting_balance // total_balance rewards_received[index] = SignedGwei(rewards_received[index] + reward) for index in set(crosslink_committee).difference( attesting_validator_indices): penalty = base_rewards[index] rewards_received[index] = SignedGwei(rewards_received[index] - penalty) return rewards_received
def test_process_rewards_and_penalties_for_crosslinks( random, n_validators_state, config, slots_per_epoch, target_committee_size, shard_count, current_slot, num_attesting_validators, max_deposit_amount, min_attestation_inclusion_delay, sample_attestation_data_params, sample_pending_attestation_record_params): previous_epoch = current_slot // slots_per_epoch - 1 state = n_validators_state.copy( slot=current_slot, ) # Compute previous epoch committees prev_epoch_start_slot = get_epoch_start_slot(previous_epoch, slots_per_epoch) prev_epoch_crosslink_committees = [ get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch) ] # Record which validators attest during each slot for reward collation. each_slot_attestion_validators_list = [] previous_epoch_attestations = [] for i in range(slots_per_epoch): committee, shard = prev_epoch_crosslink_committees[i] # Randomly sample `num_attesting_validators` validators # from the committee to attest in this slot. crosslink_data_root_attesting_validators = random.sample( committee, num_attesting_validators, ) each_slot_attestion_validators_list.append(crosslink_data_root_attesting_validators) participants_bitfield = get_empty_bitfield(target_committee_size) for index in crosslink_data_root_attesting_validators: participants_bitfield = set_voted(participants_bitfield, committee.index(index)) data_slot = i + previous_epoch * slots_per_epoch previous_epoch_attestations.append( PendingAttestationRecord(**sample_pending_attestation_record_params).copy( data=AttestationData(**sample_attestation_data_params).copy( slot=data_slot, shard=shard, ), aggregation_bitfield=participants_bitfield, slot_included=(data_slot + min_attestation_inclusion_delay), ) ) active_validators = set( [ i for i in range(len(state.validator_registry)) ] ) effective_balances = { index: get_effective_balance( state.validator_balances, index, config.MAX_DEPOSIT_AMOUNT, ) for index in active_validators } validator_balance = max_deposit_amount total_active_balance = len(active_validators) * validator_balance _base_reward_quotient = ( integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT ) base_rewards = { index: get_base_reward( state=state, index=index, base_reward_quotient=_base_reward_quotient, max_deposit_amount=max_deposit_amount, ) for index in active_validators } rewards_received = { index: 0 for index in range(len(state.validator_registry)) } rewards_received = _process_rewards_and_penalties_for_crosslinks( state, config, tuple(previous_epoch_attestations), effective_balances, base_rewards, rewards_received, ) expected_rewards_received = { index: 0 for index in range(len(state.validator_registry)) } for i in range(slots_per_epoch): crosslink_committee, shard = prev_epoch_crosslink_committees[i] attesting_validators = each_slot_attestion_validators_list[i] total_attesting_balance = len(attesting_validators) * validator_balance total_committee_balance = len(crosslink_committee) * validator_balance _base_reward_quotient = ( integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT ) for index in attesting_validators: reward = get_base_reward( state=state, index=index, base_reward_quotient=_base_reward_quotient, max_deposit_amount=max_deposit_amount, ) * total_attesting_balance // total_committee_balance expected_rewards_received[index] += reward for index in set(crosslink_committee).difference(attesting_validators): penalty = get_base_reward( state=state, index=index, base_reward_quotient=_base_reward_quotient, max_deposit_amount=max_deposit_amount, ) expected_rewards_received[index] -= penalty # Check the rewards/penalties match for index, reward_received in rewards_received.items(): assert rewards_received[index] == expected_rewards_received[index]
def test_process_rewards_and_penalties_for_finality( n_validators_state, config, slots_per_epoch, target_committee_size, shard_count, min_attestation_inclusion_delay, inactivity_penalty_quotient, finalized_epoch, current_slot, penalized_validator_indices, previous_epoch_active_validator_indices, previous_epoch_attester_indices, previous_epoch_boundary_head_attester_indices, inclusion_distances, effective_balance, base_reward, expected_rewards_received, sample_pending_attestation_record_params, sample_attestation_data_params): validator_registry = n_validators_state.validator_registry for index in penalized_validator_indices: validator_record = validator_registry[index].copy( slashed=True, ) validator_registry = update_tuple_item(validator_registry, index, validator_record) state = n_validators_state.copy( slot=current_slot, finalized_epoch=finalized_epoch, validator_registry=validator_registry, ) previous_total_balance = len(previous_epoch_active_validator_indices) * effective_balance attestation_slot = current_slot - slots_per_epoch inclusion_infos = { index: InclusionInfo( attestation_slot + inclusion_distances[index], attestation_slot, ) for index in previous_epoch_attester_indices } effective_balances = { index: effective_balance for index in previous_epoch_active_validator_indices } base_rewards = { index: base_reward for index in previous_epoch_active_validator_indices } rewards_received = { index: 0 for index in range(len(state.validator_registry)) } prev_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), slots_per_epoch, ) prev_epoch_crosslink_committees = [ get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch) ] prev_epoch_attestations = [] for i in range(slots_per_epoch): committee, shard = prev_epoch_crosslink_committees[i] participants_bitfield = get_empty_bitfield(target_committee_size) for index in previous_epoch_boundary_head_attester_indices: if index in committee: participants_bitfield = set_voted(participants_bitfield, committee.index(index)) prev_epoch_attestations.append( PendingAttestationRecord(**sample_pending_attestation_record_params).copy( data=AttestationData(**sample_attestation_data_params).copy( slot=(prev_epoch_start_slot + i), shard=shard, epoch_boundary_root=get_block_root( state, prev_epoch_start_slot, config.LATEST_BLOCK_ROOTS_LENGTH, ), beacon_block_root=get_block_root( state, (prev_epoch_start_slot + i), config.LATEST_BLOCK_ROOTS_LENGTH, ), ), aggregation_bitfield=participants_bitfield, ) ) state = state.copy( latest_attestations=prev_epoch_attestations, ) rewards_received = _process_rewards_and_penalties_for_finality( state, config, previous_epoch_active_validator_indices, previous_total_balance, prev_epoch_attestations, previous_epoch_attester_indices, inclusion_infos, effective_balances, base_rewards, rewards_received, ) for index, reward_received in rewards_received.items(): assert reward_received == expected_rewards_received[index]
def test_process_crosslinks( random, n_validators_state, config, slots_per_epoch, target_committee_size, shard_count, success_crosslink_in_cur_epoch, sample_attestation_data_params, sample_attestation_params): shard = 1 crosslink_data_root = hash_eth2(b'crosslink_data_root') current_slot = config.SLOTS_PER_EPOCH * 2 - 1 genesis_crosslinks = tuple([ CrosslinkRecord(epoch=config.GENESIS_EPOCH, crosslink_data_root=ZERO_HASH32) for _ in range(shard_count) ]) state = n_validators_state.copy( slot=current_slot, latest_crosslinks=genesis_crosslinks, ) # Generate current epoch attestations cur_epoch_attestations = [] for slot_in_cur_epoch in range(state.slot - config.SLOTS_PER_EPOCH, state.slot): if len(cur_epoch_attestations) > 0: break for committee, _shard in get_crosslink_committees_at_slot( state, slot_in_cur_epoch, CommitteeConfig(config), ): if _shard == shard: # Sample validators attesting to this shard. # Number of attesting validators sampled depends on `success_crosslink_in_cur_epoch` # if True, have >2/3 committee attest if success_crosslink_in_cur_epoch: attesting_validators = random.sample(committee, (2 * len(committee) // 3 + 1)) else: attesting_validators = random.sample(committee, (2 * len(committee) // 3 - 1)) # Generate the bitfield aggregation_bitfield = get_empty_bitfield(len(committee)) for v_index in attesting_validators: aggregation_bitfield = set_voted( aggregation_bitfield, committee.index(v_index)) # Generate the attestation cur_epoch_attestations.append( Attestation(**sample_attestation_params).copy( aggregation_bitfield=aggregation_bitfield, data=AttestationData(**sample_attestation_data_params).copy( slot=slot_in_cur_epoch, shard=shard, crosslink_data_root=crosslink_data_root, ), ) ) state = state.copy( latest_attestations=cur_epoch_attestations, ) assert (state.latest_crosslinks[shard].epoch == config.GENESIS_EPOCH and state.latest_crosslinks[shard].crosslink_data_root == ZERO_HASH32) new_state = process_crosslinks(state, config) crosslink_record = new_state.latest_crosslinks[shard] if success_crosslink_in_cur_epoch: attestation = cur_epoch_attestations[0] assert (crosslink_record.epoch == slot_to_epoch(current_slot, slots_per_epoch) and crosslink_record.crosslink_data_root == attestation.data.crosslink_data_root and attestation.data.crosslink_data_root == crosslink_data_root) else: assert (crosslink_record.epoch == config.GENESIS_EPOCH and crosslink_record.crosslink_data_root == ZERO_HASH32)
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState: """ Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec: https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks For each shard from the past two epochs, find the shard block root that has been attested to by the most stake. If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard. Return resulting ``state`` """ latest_crosslinks = state.latest_crosslinks effective_balances = { ValidatorIndex(index): get_effective_balance( state.validator_balances, ValidatorIndex(index), config.MAX_DEPOSIT_AMOUNT, ) for index in range(len(state.validator_registry)) } previous_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) next_epoch_start_slot = get_epoch_start_slot( state.next_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) for slot in range(previous_epoch_start_slot, next_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), ) if len(attesting_validator_indices) > 0: total_attesting_balance = get_total_balance( state.validator_balances, attesting_validator_indices, config.MAX_DEPOSIT_AMOUNT, ) total_balance = get_total_balance( state.validator_balances, crosslink_committee, config.MAX_DEPOSIT_AMOUNT, ) if 3 * total_attesting_balance >= 2 * total_balance: latest_crosslinks = update_tuple_item( latest_crosslinks, shard, CrosslinkRecord( epoch=slot_to_epoch(Slot(slot), config.SLOTS_PER_EPOCH), crosslink_data_root=winning_root, ), ) state = state.copy(latest_crosslinks=latest_crosslinks, ) return state