restore full test coverage for process_rewards_and_penalties (#5407)

* restore full test coverage for process_rewards_and_penalties

* adjust ncli_db to use new iterator
This commit is contained in:
tersec 2023-09-08 16:42:18 +00:00 committed by GitHub
parent 59ccd25d8d
commit cc13e0b7e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 119 additions and 177 deletions

View File

@ -665,63 +665,17 @@ func get_active_increments*(
info: altair.EpochInfo | bellatrix.BeaconState): Gwei = info: altair.EpochInfo | bellatrix.BeaconState): Gwei =
info.balances.current_epoch div EFFECTIVE_BALANCE_INCREMENT info.balances.current_epoch div EFFECTIVE_BALANCE_INCREMENT
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#get_flag_index_deltas
# This version mainly exists for the rewards and state transition epoch
# consensus-spec tests, which check rewards calculations for individual
# TimelyFlags.
iterator get_flag_index_deltas*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
flag_index: TimelyFlag, base_reward_per_increment: Gwei,
info: var altair.EpochInfo, finality_delay: uint64):
(ValidatorIndex, RewardDelta) =
## Return the deltas for a given ``flag_index`` by scanning through the
## participation flags.
let
previous_epoch = get_previous_epoch(state)
weight = PARTICIPATION_FLAG_WEIGHTS[flag_index]
unslashed_participating_increments = get_unslashed_participating_increment(
info, flag_index)
active_increments = get_active_increments(info)
for vidx in state.validators.vindices:
if not is_eligible_validator(info.validators[vidx]):
continue
let base_reward = get_base_reward_increment(state, vidx, base_reward_per_increment)
yield
if is_unslashed_participating_index(
state, flag_index, previous_epoch, vidx):
let pflag = case flag_index
of TIMELY_SOURCE_FLAG_INDEX: ParticipationFlag.timelySourceAttester
of TIMELY_TARGET_FLAG_INDEX: ParticipationFlag.timelyTargetAttester
of TIMELY_HEAD_FLAG_INDEX: ParticipationFlag.timelyHeadAttester
info.validators[vidx].flags.incl pflag
(vidx, RewardDelta(
rewards: get_flag_index_reward(
state, base_reward, active_increments,
unslashed_participating_increments, weight, finality_delay),
penalties: 0.Gwei))
elif flag_index != TIMELY_HEAD_FLAG_INDEX:
(vidx, RewardDelta(
rewards: 0.Gwei,
penalties: base_reward * weight div WEIGHT_DENOMINATOR))
else:
(vidx, RewardDelta(rewards: 0.Gwei, penalties: 0.Gwei))
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#get_flag_index_deltas # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#get_flag_index_deltas
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#modified-get_inactivity_penalty_deltas # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#modified-get_inactivity_penalty_deltas
# Combines get_flag_index_deltas() and get_inactivity_penalty_deltas() # Combines get_flag_index_deltas() and get_inactivity_penalty_deltas()
func update_flag_and_inactivity_deltas( iterator get_flag_and_inactivity_deltas*(
cfg: RuntimeConfig, cfg: RuntimeConfig,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState, deneb.BeaconState,
base_reward_per_increment: Gwei, info: var altair.EpochInfo, base_reward_per_increment: Gwei, info: var altair.EpochInfo,
finality_delay: uint64) = finality_delay: uint64):
(ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) =
## Return the deltas for a given ``flag_index`` by scanning through the ## Return the deltas for a given ``flag_index`` by scanning through the
## participation flags. ## participation flags.
# #
@ -793,60 +747,13 @@ func update_flag_and_inactivity_deltas(
let penalty_numerator = state.validators[vidx].effective_balance * state.inactivity_scores[vidx] let penalty_numerator = state.validators[vidx].effective_balance * state.inactivity_scores[vidx]
penalty_numerator div penalty_denominator penalty_numerator div penalty_denominator
info.validators[vidx].delta.rewards += # Yielding these as a structure with identifiable names rather than
reward(TIMELY_SOURCE_FLAG_INDEX) + reward(TIMELY_TARGET_FLAG_INDEX) + # multiple-return-value style creates spurious nimZeroMem calls.
reward(TIMELY_HEAD_FLAG_INDEX) yield
info.validators[vidx].delta.penalties += (vidx, reward(TIMELY_SOURCE_FLAG_INDEX),
penalty(TIMELY_SOURCE_FLAG_INDEX) + penalty(TIMELY_TARGET_FLAG_INDEX) + reward(TIMELY_TARGET_FLAG_INDEX), reward(TIMELY_HEAD_FLAG_INDEX),
inactivity_penalty penalty(TIMELY_SOURCE_FLAG_INDEX), penalty(TIMELY_TARGET_FLAG_INDEX),
inactivity_penalty)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas
# Exists for consensus-spec tests which probe for specific flag calculations.
iterator get_inactivity_penalty_deltas*(
cfg: RuntimeConfig, state: altair.BeaconState, info: altair.EpochInfo):
(ValidatorIndex, Gwei) =
## Return the inactivity penalty deltas by considering timely target
## participation flags and inactivity scores.
let
penalty_denominator =
cfg.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR
previous_epoch = get_previous_epoch(state)
for vidx in state.validators.vindices:
if not is_eligible_validator(info.validators[vidx]):
continue
if not is_unslashed_participating_index(
state, TIMELY_TARGET_FLAG_INDEX, previous_epoch, vidx):
let
penalty_numerator = state.validators[vidx].effective_balance *
state.inactivity_scores[vidx]
yield (vidx, Gwei(penalty_numerator div penalty_denominator))
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#modified-get_inactivity_penalty_deltas
# Exists for consensus-spec tests which probe for specific flag calculations.
iterator get_inactivity_penalty_deltas*(
cfg: RuntimeConfig,
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState,
info: altair.EpochInfo): (ValidatorIndex, Gwei) =
## Return the inactivity penalty deltas by considering timely target
## participation flags and inactivity scores.
let
# [Modified in Bellatrix]
penalty_denominator =
cfg.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_BELLATRIX
previous_epoch = get_previous_epoch(state)
for vidx in state.validators.vindices:
if not is_eligible_validator(info.validators[vidx]):
continue
if not is_unslashed_participating_index(
state, TIMELY_TARGET_FLAG_INDEX, previous_epoch, vidx):
let
penalty_numerator = state.validators[vidx].effective_balance *
state.inactivity_scores[vidx]
yield (vidx, Gwei(penalty_numerator div penalty_denominator))
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/beacon-chain.md#rewards-and-penalties-1 # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/beacon-chain.md#rewards-and-penalties-1
func process_rewards_and_penalties*( func process_rewards_and_penalties*(
@ -887,8 +794,11 @@ func process_rewards_and_penalties*(
finality_delay = get_finality_delay(state) finality_delay = get_finality_delay(state)
doAssert state.validators.len() == info.validators.len() doAssert state.validators.len() == info.validators.len()
update_flag_and_inactivity_deltas( for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2 in
cfg, state, base_reward_per_increment, info, finality_delay) get_flag_and_inactivity_deltas(
cfg, state, base_reward_per_increment, info, finality_delay):
info.validators[validator_index].delta.rewards += reward0 + reward1 + reward2
info.validators[validator_index].delta.penalties += penalty0 + penalty1 + penalty2
# Here almost all balances are updated (assuming most validators are active) - # Here almost all balances are updated (assuming most validators are active) -
# clearing the cache becomes a bottleneck if done item by item because of the # clearing the cache becomes a bottleneck if done item by item because of the

View File

@ -288,37 +288,37 @@ proc collectEpochRewardsAndPenalties*(
total_active_balance) total_active_balance)
finality_delay = get_finality_delay(state) finality_delay = get_finality_delay(state)
for flag_index in TimelyFlag: for validator_index, reward_source, reward_target, reward_head,
for validator_index, delta in get_flag_index_deltas( penalty_source, penalty_target, penalty_inactivity in
state, flag_index, base_reward_per_increment, info, finality_delay): get_flag_and_inactivity_deltas(
cfg, state, base_reward_per_increment, info, finality_delay):
template rp: untyped = rewardsAndPenalties[validator_index] template rp: untyped = rewardsAndPenalties[validator_index]
let let
base_reward = get_base_reward_increment( base_reward = get_base_reward_increment(
state, validator_index, base_reward_per_increment) state, validator_index, base_reward_per_increment)
active_increments = get_active_increments(info) active_increments = get_active_increments(info)
unslashed_participating_increment =
template unslashed_participating_increment(flag_index: untyped): untyped =
get_unslashed_participating_increment(info, flag_index) get_unslashed_participating_increment(info, flag_index)
max_flag_index_reward = get_flag_index_reward( template max_flag_index_reward(flag_index: untyped): untyped =
get_flag_index_reward(
state, base_reward, active_increments, state, base_reward, active_increments,
unslashed_participating_increment, unslashed_participating_increment(flag_index),
PARTICIPATION_FLAG_WEIGHTS[flag_index], PARTICIPATION_FLAG_WEIGHTS[flag_index], finality_delay)
finality_delay)
case flag_index rp.source_outcome = reward_source.int64 - penalty_source.int64
of TIMELY_SOURCE_FLAG_INDEX: rp.max_source_reward =
rp.source_outcome = delta.getOutcome max_flag_index_reward(TimelyFlag.TIMELY_SOURCE_FLAG_INDEX)
rp.max_source_reward = max_flag_index_reward rp.target_outcome = reward_target.int64 - penalty_target.int64
of TIMELY_TARGET_FLAG_INDEX: rp.max_target_reward =
rp.target_outcome = delta.getOutcome max_flag_index_reward(TimelyFlag.TIMELY_TARGET_FLAG_INDEX)
rp.max_target_reward = max_flag_index_reward rp.head_outcome = reward_head.int64
of TIMELY_HEAD_FLAG_INDEX: rp.max_head_reward =
rp.head_outcome = delta.getOutcome max_flag_index_reward(TimelyFlag.TIMELY_HEAD_FLAG_INDEX)
rp.max_head_reward = max_flag_index_reward
for validator_index, penalty in get_inactivity_penalty_deltas( rewardsAndPenalties[validator_index].inactivity_penalty +=
cfg, state, info): penalty_inactivity
rewardsAndPenalties[validator_index].inactivity_penalty += penalty
rewardsAndPenalties.collectSlashings(state, info.balances.current_epoch) rewardsAndPenalties.collectSlashings(state, info.balances.current_epoch)

View File

@ -56,17 +56,25 @@ proc runTest(rewardsDir, identifier: string) =
let finality_delay = get_finality_delay(state[]) let finality_delay = get_finality_delay(state[])
for flag_index in TimelyFlag: for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2
for validator_index, delta in get_flag_index_deltas( in get_flag_and_inactivity_deltas(
state[], flag_index, base_reward_per_increment, info, finality_delay): defaultRuntimeConfig, state[], base_reward_per_increment, info,
finality_delay):
if not is_eligible_validator(info.validators[validator_index]): if not is_eligible_validator(info.validators[validator_index]):
continue continue
flagDeltas2[flag_index].rewards[validator_index] = delta.rewards flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].rewards[validator_index] =
flagDeltas2[flag_index].penalties[validator_index] = delta.penalties reward0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].rewards[validator_index] =
for validator_index, delta in get_inactivity_penalty_deltas( reward1
defaultRuntimeConfig, state[], info): flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].rewards[validator_index] =
inactivityPenaltyDeltas2.penalties[validator_index] = delta reward2
flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].penalties[validator_index] =
penalty0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] =
penalty1
flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] =
0
inactivityPenaltyDeltas2.penalties[validator_index] = penalty2
check: check:
flagDeltas == flagDeltas2 flagDeltas == flagDeltas2

View File

@ -56,17 +56,25 @@ proc runTest(rewardsDir, identifier: string) =
let finality_delay = get_finality_delay(state[]) let finality_delay = get_finality_delay(state[])
for flag_index in TimelyFlag: for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2
for validator_index, delta in get_flag_index_deltas( in get_flag_and_inactivity_deltas(
state[], flag_index, base_reward_per_increment, info, finality_delay): defaultRuntimeConfig, state[], base_reward_per_increment, info,
finality_delay):
if not is_eligible_validator(info.validators[validator_index]): if not is_eligible_validator(info.validators[validator_index]):
continue continue
flagDeltas2[flag_index].rewards[validator_index] = delta.rewards flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].rewards[validator_index] =
flagDeltas2[flag_index].penalties[validator_index] = delta.penalties reward0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].rewards[validator_index] =
for validator_index, delta in get_inactivity_penalty_deltas( reward1
defaultRuntimeConfig, state[], info): flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].rewards[validator_index] =
inactivityPenaltyDeltas2.penalties[validator_index] = delta reward2
flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].penalties[validator_index] =
penalty0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] =
penalty1
flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] =
0
inactivityPenaltyDeltas2.penalties[validator_index] = penalty2
check: check:
flagDeltas == flagDeltas2 flagDeltas == flagDeltas2

View File

@ -56,17 +56,25 @@ proc runTest(rewardsDir, identifier: string) =
let finality_delay = get_finality_delay(state[]) let finality_delay = get_finality_delay(state[])
for flag_index in TimelyFlag: for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2
for validator_index, delta in get_flag_index_deltas( in get_flag_and_inactivity_deltas(
state[], flag_index, base_reward_per_increment, info, finality_delay): defaultRuntimeConfig, state[], base_reward_per_increment, info,
finality_delay):
if not is_eligible_validator(info.validators[validator_index]): if not is_eligible_validator(info.validators[validator_index]):
continue continue
flagDeltas2[flag_index].rewards[validator_index] = delta.rewards flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].rewards[validator_index] =
flagDeltas2[flag_index].penalties[validator_index] = delta.penalties reward0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].rewards[validator_index] =
for validator_index, delta in get_inactivity_penalty_deltas( reward1
defaultRuntimeConfig, state[], info): flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].rewards[validator_index] =
inactivityPenaltyDeltas2.penalties[validator_index] = delta reward2
flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].penalties[validator_index] =
penalty0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] =
penalty1
flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] =
0
inactivityPenaltyDeltas2.penalties[validator_index] = penalty2
check: check:
flagDeltas == flagDeltas2 flagDeltas == flagDeltas2

View File

@ -56,17 +56,25 @@ proc runTest(rewardsDir, identifier: string) =
let finality_delay = get_finality_delay(state[]) let finality_delay = get_finality_delay(state[])
for flag_index in TimelyFlag: for validator_index, reward0, reward1, reward2, penalty0, penalty1, penalty2
for validator_index, delta in get_flag_index_deltas( in get_flag_and_inactivity_deltas(
state[], flag_index, base_reward_per_increment, info, finality_delay): defaultRuntimeConfig, state[], base_reward_per_increment, info,
finality_delay):
if not is_eligible_validator(info.validators[validator_index]): if not is_eligible_validator(info.validators[validator_index]):
continue continue
flagDeltas2[flag_index].rewards[validator_index] = delta.rewards flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].rewards[validator_index] =
flagDeltas2[flag_index].penalties[validator_index] = delta.penalties reward0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].rewards[validator_index] =
for validator_index, delta in get_inactivity_penalty_deltas( reward1
defaultRuntimeConfig, state[], info): flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].rewards[validator_index] =
inactivityPenaltyDeltas2.penalties[validator_index] = delta reward2
flagDeltas2[TimelyFlag.TIMELY_SOURCE_FLAG_INDEX].penalties[validator_index] =
penalty0
flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] =
penalty1
flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] =
0
inactivityPenaltyDeltas2.penalties[validator_index] = penalty2
check: check:
flagDeltas == flagDeltas2 flagDeltas == flagDeltas2