def test_get_block_root(sample_beacon_state_params, current_slot, target_slot, success, slots_per_epoch, slots_per_historical_root, sample_block): blocks, latest_block_roots = generate_mock_latest_historical_roots( sample_block, current_slot, slots_per_epoch, slots_per_historical_root, ) state = BeaconState(**sample_beacon_state_params).copy( slot=current_slot, latest_block_roots=latest_block_roots, ) if success: block_root = get_block_root( state, target_slot, slots_per_historical_root, ) assert block_root == blocks[target_slot].root else: with pytest.raises(ValidationError): get_block_root( state, target_slot, slots_per_historical_root, )
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 _determine_new_finalized_checkpoint(state: BeaconState, justification_bits: Bitfield, config: Eth2Config) -> Checkpoint: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) new_finalized_epoch = _determine_new_finalized_epoch( state.finalized_checkpoint.epoch, state.previous_justified_checkpoint.epoch, state.current_justified_checkpoint.epoch, current_epoch, justification_bits, ) if new_finalized_epoch != state.finalized_checkpoint.epoch: # NOTE: we only want to call ``get_block_root`` # upon some change, not unconditionally # Given the way it reads the block roots, it can cause # validation problems with some configurations, esp. in testing. # This is implicitly happening above for the justified roots. new_finalized_root = get_block_root( state, new_finalized_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ) else: new_finalized_root = state.finalized_checkpoint.root return Checkpoint.create(epoch=new_finalized_epoch, root=new_finalized_root)
def _determine_new_justified_checkpoint_and_bitfield( state: BeaconState, config: Eth2Config) -> Tuple[Checkpoint, Bitfield]: ( new_current_justified_epoch, justification_bits, ) = _determine_new_justified_epoch_and_bitfield( state, config, ) if new_current_justified_epoch != state.current_justified_checkpoint.epoch: new_current_justified_root = get_block_root( state, new_current_justified_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ) else: new_current_justified_root = state.current_justified_checkpoint.root return ( Checkpoint( epoch=new_current_justified_epoch, root=new_current_justified_root, ), justification_bits, )
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 get_previous_epoch_matching_head_attestations( state: 'BeaconState', slots_per_epoch: int, slots_per_historical_root: int) -> Iterable[PendingAttestation]: for attestation in state.previous_epoch_attestations: beacon_block_root = get_block_root( state, attestation.data.slot, slots_per_historical_root, ) if attestation.data.beacon_block_root == beacon_block_root: yield attestation
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 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 _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, )
def _get_epoch_boundary_attesting_indices( state: 'BeaconState', attestations: Sequence[PendingAttestation], epoch: Epoch, config: Eth2Config) -> Tuple[ValidatorIndex, ...]: target_root = get_block_root( state, get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, ) relevant_attestations = (a for a in attestations if a.data.target_root == target_root) return get_attesting_indices( state, relevant_attestations, config, )
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 get_previous_epoch_head_attestations( state: 'BeaconState', slots_per_epoch: int, genesis_epoch: Epoch, latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]: previous_epoch_attestations = get_previous_epoch_attestations( state, slots_per_epoch, genesis_epoch, ) for attestation in previous_epoch_attestations: beacon_block_root = get_block_root( state, attestation.data.slot, latest_block_roots_length, ) if attestation.data.beacon_block_root == beacon_block_root: yield attestation
def get_previous_epoch_boundary_attestations( state: 'BeaconState', slots_per_epoch: int, latest_block_roots_length: int) -> Iterable[PendingAttestation]: if not state.previous_epoch_attestations: return tuple() beacon_block_root = get_block_root( state, get_epoch_start_slot( state.previous_epoch(slots_per_epoch), slots_per_epoch, ), latest_block_roots_length, ) for attestation in state.previous_epoch_attestations: if attestation.data.beacon_block_root == beacon_block_root: yield attestation
def validate_serenity_attestation(state: BeaconState, attestation: Attestation, epoch_length: int, min_attestation_inclusion_delay: int, latest_block_roots_length: int) -> None: """ Validate the given ``attestation``. Raise ``ValidationError`` if it's invalid. """ validate_serenity_attestation_slot( attestation.data, state.slot, epoch_length, min_attestation_inclusion_delay, ) validate_serenity_attestation_justified_slot( attestation.data, state.slot, state.previous_justified_slot, state.justified_slot, epoch_length, ) validate_serenity_attestation_justified_block_root( attestation.data, justified_block_root=get_block_root( state=state, slot=attestation.data.justified_slot, latest_block_roots_length=latest_block_roots_length, ), ) validate_serenity_attestation_latest_crosslink_root( attestation.data, latest_crosslink_root=state.latest_crosslinks[ attestation.data.shard].shard_block_root, ) validate_serenity_attestation_shard_block_root(attestation.data) validate_serenity_attestation_aggregate_signature( state, attestation, epoch_length, )
def _determine_new_justified_checkpoint_and_bitfield( state: BeaconState, config: Eth2Config) -> Tuple[Epoch, Hash32, int]: ( new_current_justified_epoch, justification_bitfield, ) = _determine_new_justified_epoch_and_bitfield( state, config, ) new_current_justified_root = get_block_root( state, new_current_justified_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ) return ( new_current_justified_epoch, new_current_justified_root, justification_bitfield, )
def create_mock_slashable_attestation( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_slot: Slot) -> SlashableAttestation: """ Create `SlashableAttestation` that is signed by one attester. """ attester_index = ValidatorIndex(0) committee = (attester_index, ) shard = Shard(0) # Use genesis block root as `beacon_block_root`, only for tests. beacon_block_root = get_block_root( state, config.GENESIS_SLOT, config.SLOTS_PER_HISTORICAL_ROOT, ) # 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.current_justified_epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, ) 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=source_root, target_root=target_root, shard=shard, previous_crosslink=previous_crosslink, crosslink_data_root=ZERO_HASH32, ) message_hash, voting_committee_indices = _get_mock_message_and_voting_committee_indices( attestation_data, committee, num_voted_attesters=1, ) signature = sign_transaction( message_hash=message_hash, privkey=keymap[state.validator_registry[ voting_committee_indices[0]].pubkey], fork=state.fork, slot=attestation_slot, signature_domain=SignatureDomain.DOMAIN_ATTESTATION, slots_per_epoch=config.SLOTS_PER_EPOCH, ) validator_indices = tuple(committee[i] for i in voting_committee_indices) return SlashableAttestation( validator_indices=sorted(validator_indices), data=attestation_data, custody_bitfield=get_empty_bitfield(len(voting_committee_indices)), aggregate_signature=signature, )
def process_justification(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) current_epoch_justifiable = _is_epoch_justifiable( state, state.current_epoch_attestations, current_epoch, config, ) previous_epoch_justifiable = _is_epoch_justifiable( state, state.previous_epoch_attestations, previous_epoch, config, ) _justification_bitfield = state.justification_bitfield << 1 if previous_epoch_justifiable and current_epoch_justifiable: justification_bitfield = _justification_bitfield | 3 elif previous_epoch_justifiable: justification_bitfield = _justification_bitfield | 2 elif current_epoch_justifiable: justification_bitfield = _justification_bitfield | 1 else: justification_bitfield = _justification_bitfield if current_epoch_justifiable: new_justified_epoch = current_epoch elif previous_epoch_justifiable: new_justified_epoch = previous_epoch else: new_justified_epoch = state.current_justified_epoch new_finalized_epoch, _ = _get_finalized_epoch( justification_bitfield, state.previous_justified_epoch, state.current_justified_epoch, state.finalized_epoch, previous_epoch, ) # Update state state = state.copy( previous_justified_epoch=state.current_justified_epoch, previous_justified_root=state.current_justified_root, justification_bitfield=justification_bitfield, ) if new_justified_epoch != state.current_justified_epoch: state = state.copy( current_justified_epoch=new_justified_epoch, current_justified_root=get_block_root( state, get_epoch_start_slot(new_justified_epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, ), ) if new_finalized_epoch != state.finalized_epoch: state = state.copy(finalized_epoch=new_finalized_epoch, finalized_root=get_block_root( state, get_epoch_start_slot(new_finalized_epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, )) return state
def test_get_attestation_deltas( genesis_state, config, slots_per_epoch, target_committee_size, max_committees_per_slot, min_attestation_inclusion_delay, inactivity_penalty_quotient, finalized_epoch, current_slot, sample_pending_attestation_record_params, sample_attestation_data_params, ): state = genesis_state.mset( "slot", current_slot, "finalized_checkpoint", Checkpoint.create(epoch=finalized_epoch), ) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) has_inactivity_penalty = (previous_epoch - finalized_epoch > config.MIN_EPOCHS_TO_INACTIVITY_PENALTY) indices_to_check = set() prev_epoch_attestations = tuple() for committee, committee_index, slot in iterate_committees_at_epoch( state, previous_epoch, config): participants_bitfield = get_empty_bitfield(len(committee)) for i, index in enumerate(committee): indices_to_check.add(index) participants_bitfield = set_voted(participants_bitfield, i) prev_epoch_attestations += (PendingAttestation.create( **sample_pending_attestation_record_params).mset( "aggregation_bits", participants_bitfield, "inclusion_delay", min_attestation_inclusion_delay, "proposer_index", get_beacon_proposer_index(state.set("slot", slot), CommitteeConfig(config)), "data", AttestationData.create(**sample_attestation_data_params).mset( "slot", slot, "index", committee_index, "beacon_block_root", get_block_root_at_slot(state, slot, config.SLOTS_PER_HISTORICAL_ROOT), "target", Checkpoint.create( epoch=previous_epoch, root=get_block_root( state, previous_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ), ), ), ), ) state = state.set("previous_epoch_attestations", prev_epoch_attestations) rewards_received, penalties_received = get_attestation_deltas( state, config) if has_inactivity_penalty: assert sum(penalties_received) > 0 else: assert sum(penalties_received) == 0 assert all(reward > 0 for reward in rewards_received)
def _process_rewards_and_penalties_for_finality( state: BeaconState, config: BeaconConfig, previous_epoch_active_validator_indices: Set[ValidatorIndex], previous_total_balance: Gwei, previous_epoch_attestations: Sequence[Attestation], previous_epoch_attester_indices: Set[ValidatorIndex], inclusion_infos: Dict[ValidatorIndex, InclusionInfo], effective_balances: Dict[ValidatorIndex, Gwei], base_rewards: Dict[ValidatorIndex, Gwei], old_rewards_received: Dict[ValidatorIndex, SignedGwei] ) -> Dict[ValidatorIndex, SignedGwei]: previous_epoch_boundary_attestations = ( a for a in previous_epoch_attestations if a.data.epoch_boundary_root == get_block_root( state, get_epoch_start_slot( state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), config.SLOTS_PER_EPOCH, ), config.LATEST_BLOCK_ROOTS_LENGTH, )) previous_epoch_boundary_attester_indices = get_attester_indices_from_attesttion( state=state, attestations=previous_epoch_boundary_attestations, committee_config=CommitteeConfig(config), ) previous_epoch_head_attestations = get_previous_epoch_head_attestations( state, config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH, config.LATEST_BLOCK_ROOTS_LENGTH, ) previous_epoch_head_attester_indices = get_attester_indices_from_attesttion( state=state, attestations=previous_epoch_head_attestations, committee_config=CommitteeConfig(config), ) rewards_received = {index: Gwei(0) for index in old_rewards_received} penalties_received = rewards_received.copy() epochs_since_finality = state.next_epoch( config.SLOTS_PER_EPOCH) - state.finalized_epoch if epochs_since_finality <= 4: # 1.1 Expected FFG source: previous_epoch_attesting_balance = get_total_balance_from_effective_balances( effective_balances, previous_epoch_attester_indices, ) # Reward validators in `previous_epoch_attester_indices` # # Punish active validators not in `previous_epoch_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_attester_indices, ) rewards = { index: Gwei(base_rewards[index] * previous_epoch_attesting_balance // previous_total_balance) for index in previous_epoch_attester_indices } penalties = { index: base_rewards[index] for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( rewards=rewards, indices_to_reward=previous_epoch_attester_indices, penalties=penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # 1.2 Expected FFG target: previous_epoch_boundary_attesting_balance = get_total_balance_from_effective_balances( effective_balances, previous_epoch_boundary_attester_indices, ) # Reward validators in `previous_epoch_boundary_attester_indices` # Punish active validators not in `previous_epoch_boundary_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_boundary_attester_indices, ) rewards = { index: Gwei(base_rewards[index] * previous_epoch_boundary_attesting_balance // previous_total_balance) for index in previous_epoch_boundary_attester_indices } penalties = { index: base_rewards[index] for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( rewards=rewards, indices_to_reward=previous_epoch_boundary_attester_indices, penalties=penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # 1.3 Expected beacon chain head: previous_epoch_head_attesting_balance = get_total_balance_from_effective_balances( effective_balances, previous_epoch_head_attester_indices, ) # Reward validators in `previous_epoch_head_attester_indices` # Punish active validators not in `previous_epoch_head_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_head_attester_indices, ) rewards = { index: Gwei(base_rewards[index] * previous_epoch_head_attesting_balance // previous_total_balance) for index in previous_epoch_head_attester_indices } penalties = { index: base_rewards[index] for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( rewards=rewards, indices_to_reward=previous_epoch_head_attester_indices, penalties=penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # 1.4 Inclusion distance: # Reward validators in `previous_epoch_attester_indices` rewards = { index: Gwei(base_rewards[index] * config.MIN_ATTESTATION_INCLUSION_DELAY // inclusion_infos[index].inclusion_distance) for index in previous_epoch_attester_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( rewards=rewards, indices_to_reward=previous_epoch_attester_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # epochs_since_finality > 4 else: # Punish active validators not in `previous_epoch_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_attester_indices, ) inactivity_penalties = { index: base_rewards[index] + (effective_balances[index] * epochs_since_finality // config.INACTIVITY_PENALTY_QUOTIENT // 2) for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( penalties=inactivity_penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # Punish active validators not in `previous_epoch_boundary_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_boundary_attester_indices, ) inactivity_penalties = { index: base_rewards[index] + (effective_balances[index] * epochs_since_finality // config.INACTIVITY_PENALTY_QUOTIENT // 2) for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( penalties=inactivity_penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # Punish active validators not in `previous_epoch_head_attester_indices` excluded_active_validators_indices = previous_epoch_active_validator_indices.difference( previous_epoch_head_attester_indices, ) penalties = { index: base_rewards[index] for index in excluded_active_validators_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( penalties=penalties, indices_to_penalize=excluded_active_validators_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # Punish penalized active validators penalties = { index: 3 * base_rewards[index] + 2 * (effective_balances[index] * epochs_since_finality // config.INACTIVITY_PENALTY_QUOTIENT // 2) for index in previous_epoch_active_validator_indices if state.validator_registry[index].slashed is True } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( penalties=penalties, indices_to_penalize={index for index in penalties}, rewards_received=rewards_received, penalties_received=penalties_received, ), ) # Punish validators in `previous_epoch_attester_indices` penalties = { index: Gwei(base_rewards[index] - (base_rewards[index] * config.MIN_ATTESTATION_INCLUSION_DELAY // inclusion_infos[index].inclusion_distance)) for index in previous_epoch_attester_indices } rewards_received, penalties_received = _apply_rewards_and_penalties( RewardSettlementContext( penalties=penalties, indices_to_penalize=previous_epoch_attester_indices, rewards_received=rewards_received, penalties_received=penalties_received, ), ) historical_rewards_received = old_rewards_received.copy() for index in rewards_received: historical_rewards_received = _update_rewards_or_penalies( index, rewards_received[index] - penalties_received[index], historical_rewards_received, ) return historical_rewards_received
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]