Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify justification and finalization accounting logic #826

Merged
merged 6 commits into from
Mar 26, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 24 additions & 73 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -1883,10 +1883,11 @@ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:

```python
def get_inactivity_penalty(state: BeaconState, index: ValidatorIndex, epochs_since_finality: int) -> Gwei:
return (
get_base_reward(state, index) +
get_effective_balance(state, index) * epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT // 2
)
if epochs_since_finality <= 4:
extra_penalty = 0
else:
extra_penalty = get_effective_balance(state, index) * min(epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT // 2
vbuterin marked this conversation as resolved.
Show resolved Hide resolved
return get_base_reward(state, index) + extra_penalty
```

Note: When applying penalties in the following balance recalculations implementers should make sure the `uint64` does not underflow.
Expand All @@ -1896,99 +1897,49 @@ Note: When applying penalties in the following balance recalculations implemente
```python
def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
epochs_since_finality = get_current_epoch(state) + 1 - state.finalized_epoch
if epochs_since_finality <= 4:
return compute_normal_justification_and_finalization_deltas(state)
else:
return compute_inactivity_leak_deltas(state)
```

When blocks are finalizing normally...

```python
def compute_normal_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
# deltas[0] for rewards
# deltas[1] for penalties
deltas = [
[0 for index in range(len(state.validator_registry))],
[0 for index in range(len(state.validator_registry))]
]
rewards = [0 for index in range(len(state.validator_registry))]
penalties = [0 for index in range(len(state.validator_registry))]
# Some helper variables
boundary_attestations = get_previous_epoch_boundary_attestations(state)
boundary_attesting_balance = get_attesting_balance(state, boundary_attestations)
total_balance = get_previous_total_balance(state)
total_attesting_balance = get_attesting_balance(state, state.previous_epoch_attestations)
matching_head_attestations = get_previous_epoch_matching_head_attestations(state)
matching_head_balance = get_attesting_balance(state, matching_head_attestations)
eligible_validators = [
i for i,v in enumerate(state.validator_registry) if is_active_validator(v, get_current_epoch(state)) or
(v.slashed and get_current_epoch(state) < v.withdrawable_epoch)
]
# Process rewards or penalties for all validators
for index in get_active_validator_indices(state.validator_registry, get_previous_epoch(state)):
for index in eligible_validators:
# Expected FFG source
if index in get_attesting_indices(state, state.previous_epoch_attestations):
deltas[0][index] += get_base_reward(state, index) * total_attesting_balance // total_balance
rewards[index] += get_base_reward(state, index) * total_attesting_balance // total_balance
# Inclusion speed bonus
deltas[0][index] += (
rewards[index] += (
get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY //
inclusion_distance(state, index)
)
else:
deltas[1][index] += get_base_reward(state, index)
penalties[index] += get_base_reward(state, index)
# Expected FFG target
if index in get_attesting_indices(state, boundary_attestations):
deltas[0][index] += get_base_reward(state, index) * boundary_attesting_balance // total_balance
rewards[index] += get_base_reward(state, index) * boundary_attesting_balance // total_balance
else:
deltas[1][index] += get_base_reward(state, index)
penalties[index] += get_inactivity_penalty(state, index, epochs_since_finality)
# Expected head
if index in get_attesting_indices(state, matching_head_attestations):
deltas[0][index] += get_base_reward(state, index) * matching_head_balance // total_balance
rewards[index] += get_base_reward(state, index) * matching_head_balance // total_balance
else:
deltas[1][index] += get_base_reward(state, index)
penalties[index] += get_base_reward(state, index)
# Proposer bonus
if index in get_attesting_indices(state, state.previous_epoch_attestations):
proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index))
deltas[0][proposer_index] += get_base_reward(state, index) // ATTESTATION_INCLUSION_REWARD_QUOTIENT
return deltas
```

When blocks are not finalizing normally...

```python
def compute_inactivity_leak_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
# deltas[0] for rewards
# deltas[1] for penalties
deltas = [
[0 for index in range(len(state.validator_registry))],
[0 for index in range(len(state.validator_registry))]
]
boundary_attestations = get_previous_epoch_boundary_attestations(state)
matching_head_attestations = get_previous_epoch_matching_head_attestations(state)
active_validator_indices = get_active_validator_indices(state.validator_registry, get_previous_epoch(state))
epochs_since_finality = get_current_epoch(state) + 1 - state.finalized_epoch
for index in active_validator_indices:
if index not in get_attesting_indices(state, state.previous_epoch_attestations):
deltas[1][index] += get_inactivity_penalty(state, index, epochs_since_finality)
else:
# If a validator did attest, apply a small penalty for getting attestations included late
deltas[0][index] += (
get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY //
inclusion_distance(state, index)
)
deltas[1][index] += get_base_reward(state, index)
if index not in get_attesting_indices(state, boundary_attestations):
deltas[1][index] += get_inactivity_penalty(state, index, epochs_since_finality)
if index not in get_attesting_indices(state, matching_head_attestations):
deltas[1][index] += get_base_reward(state, index)
# Penalize slashed-but-inactive validators as though they were active but offline
for index in range(len(state.validator_registry)):
eligible = (
index not in active_validator_indices and
state.validator_registry[index].slashed and
get_current_epoch(state) < state.validator_registry[index].withdrawable_epoch
)
if eligible:
deltas[1][index] += (
2 * get_inactivity_penalty(state, index, epochs_since_finality) +
get_base_reward(state, index)
)
return deltas
rewards[proposer_index] += get_base_reward(state, index) // ATTESTATION_INCLUSION_REWARD_QUOTIENT
# Take away max rewards if we're not finalizing
if epochs_since_finality > 4:
penalties[index] += get_base_reward(state, index) * 4
return [rewards, penalties]
```

##### Crosslinks
Expand Down