def test_get_matching_head_attestations(genesis_state, config): some_epoch = config.GENESIS_EPOCH + 20 some_slot = ( compute_start_slot_at_epoch(some_epoch, config.SLOTS_PER_EPOCH) + config.SLOTS_PER_EPOCH // 4) some_target_root = b"\x33" * 32 target_attestations = tuple( (PendingAttestation.create(data=AttestationData.create( slot=some_slot - 1, index=0, beacon_block_root=some_target_root, target=Checkpoint.create(epoch=some_epoch - 1), )) for i in range(3))) current_epoch_attestations = target_attestations + tuple( (PendingAttestation.create(data=AttestationData.create( beacon_block_root=b"\x44" * 32, target=Checkpoint.create(epoch=some_epoch - 1), )) for _ in range(3))) state = genesis_state.mset( "slot", some_slot, "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_head_attestations(genesis_state, config): some_epoch = config.GENESIS_EPOCH + 20 some_slot = ( compute_start_slot_of_epoch(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=Checkpoint(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=Checkpoint(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 get_attestation_deltas( state: BeaconState, config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: rewards = tuple(0 for _ in range(len(state.validators))) penalties = tuple(0 for _ in range(len(state.validators))) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH) total_balance = get_total_active_balance(state, config) eligible_validator_indices = tuple( ValidatorIndex(index) for index, v in enumerate(state.validators) if v.is_active(previous_epoch) or ( v.slashed and previous_epoch + 1 < v.withdrawable_epoch)) matching_source_attestations = get_matching_source_attestations( state, previous_epoch, config) matching_target_attestations = get_matching_target_attestations( state, previous_epoch, config) matching_head_attestations = get_matching_head_attestations( state, previous_epoch, config) increment = config.EFFECTIVE_BALANCE_INCREMENT total_balance_in_increment = total_balance // increment for attestations in ( matching_source_attestations, matching_target_attestations, matching_head_attestations, ): unslashed_attesting_indices = get_unslashed_attesting_indices( state, attestations, config) attesting_balance = get_total_balance(state, unslashed_attesting_indices, config) attesting_balance_in_increment = attesting_balance // increment for index in eligible_validator_indices: if index in unslashed_attesting_indices: if is_in_inactivity_leak(state, config): reward = get_base_reward(state, index, config) else: reward = Gwei((get_base_reward(state, index, config) * attesting_balance_in_increment) // total_balance_in_increment) rewards = update_tuple_item_with_fn( rewards, index, lambda balance, delta: balance + delta, reward) else: penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, get_base_reward(state, index, config), ) for index in get_unslashed_attesting_indices(state, matching_source_attestations, config): attestation = min( (a for a in matching_source_attestations if index in get_attesting_indices(state, a.data, a.aggregation_bits, config)), key=lambda a: a.inclusion_delay, ) proposer_reward = get_proposer_reward(state, index, config) rewards = update_tuple_item_with_fn( rewards, attestation.proposer_index, lambda balance, delta: balance + delta, proposer_reward, ) base_reward = get_base_reward(state, index, config) max_attester_reward = base_reward - proposer_reward rewards = update_tuple_item_with_fn( rewards, index, lambda balance, delta: balance + delta, (max_attester_reward // attestation.inclusion_delay), ) if is_in_inactivity_leak(state, config): matching_target_attesting_indices = get_unslashed_attesting_indices( state, matching_target_attestations, config) for index in eligible_validator_indices: base_reward = get_base_reward(state, index, config) penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, BASE_REWARDS_PER_EPOCH * base_reward - get_proposer_reward(state, index, config), ) if index not in matching_target_attesting_indices: effective_balance = state.validators[index].effective_balance penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, effective_balance * get_finality_delay(state, config.SLOTS_PER_EPOCH) // config.INACTIVITY_PENALTY_QUOTIENT, ) return ( tuple(Gwei(reward) for reward in rewards), tuple(Gwei(penalty) for penalty in penalties), )
def get_attestation_deltas(state: BeaconState, config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: committee_config = CommitteeConfig(config) rewards = tuple( 0 for _ in range(len(state.validators)) ) penalties = tuple( 0 for _ in range(len(state.validators)) ) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) total_balance = get_total_active_balance(state, config) eligible_validator_indices = tuple( ValidatorIndex(index) for index, v in enumerate(state.validators) if v.is_active(previous_epoch) or ( v.slashed and previous_epoch + 1 < v.withdrawable_epoch ) ) matching_source_attestations = get_matching_source_attestations( state, previous_epoch, config, ) matching_target_attestations = get_matching_target_attestations( state, previous_epoch, config, ) matching_head_attestations = get_matching_head_attestations( state, previous_epoch, config, ) for attestations in ( matching_source_attestations, matching_target_attestations, matching_head_attestations ): unslashed_attesting_indices = get_unslashed_attesting_indices( state, attestations, committee_config, ) attesting_balance = get_total_balance(state, unslashed_attesting_indices) for index in eligible_validator_indices: if index in unslashed_attesting_indices: rewards = update_tuple_item_with_fn( rewards, index, lambda balance, delta: balance + delta, get_base_reward( state, index, config, ) * attesting_balance // total_balance, ) else: penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, get_base_reward( state, index, config, ), ) for index in get_unslashed_attesting_indices( state, matching_source_attestations, committee_config, ): attestation = min( ( a for a in matching_source_attestations if index in get_attesting_indices( state, a.data, a.aggregation_bitfield, committee_config, ) ), key=lambda a: a.inclusion_delay, ) base_reward = get_base_reward(state, index, config) proposer_reward = base_reward // config.PROPOSER_REWARD_QUOTIENT rewards = update_tuple_item_with_fn( rewards, attestation.proposer_index, lambda balance, delta: balance + delta, proposer_reward, ) max_attester_reward = base_reward - proposer_reward rewards = update_tuple_item_with_fn( rewards, index, lambda balance, delta: balance + delta, ( max_attester_reward * config.MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay ) ) finality_delay = previous_epoch - state.finalized_epoch if finality_delay > config.MIN_EPOCHS_TO_INACTIVITY_PENALTY: matching_target_attesting_indices = get_unslashed_attesting_indices( state, matching_target_attestations, committee_config, ) for index in eligible_validator_indices: penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, BASE_REWARDS_PER_EPOCH * get_base_reward( state, index, config, ), ) if index not in matching_target_attesting_indices: effective_balance = state.validators[index].effective_balance penalties = update_tuple_item_with_fn( penalties, index, lambda balance, delta: balance + delta, effective_balance * finality_delay // config.INACTIVITY_PENALTY_QUOTIENT, ) return tuple( Gwei(reward) for reward in rewards ), tuple( Gwei(penalty) for penalty in penalties )