Skip to content

Commit

Permalink
Refactor finality helpers to helpers pkg (#8734)
Browse files Browse the repository at this point in the history
Co-authored-by: Victor Farazdagi <simple.square@gmail.com>
  • Loading branch information
terencechain and farazdagi authored Apr 10, 2021
1 parent 1af88b2 commit 19a9b4b
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 75 deletions.
28 changes: 5 additions & 23 deletions beacon-chain/core/epoch/precompute/reward_penalty.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func attestationDelta(pBal *Balance, v *Validator, prevEpoch, finalizedEpoch typ
maxAttesterReward := br - proposerReward
r += maxAttesterReward / uint64(v.InclusionDistance)

if isInInactivityLeak(prevEpoch, finalizedEpoch) {
if helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
Expand All @@ -103,7 +103,7 @@ func attestationDelta(pBal *Balance, v *Validator, prevEpoch, finalizedEpoch typ

// Process target reward / penalty
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
if helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
Expand All @@ -117,7 +117,7 @@ func attestationDelta(pBal *Balance, v *Validator, prevEpoch, finalizedEpoch typ

// Process head reward / penalty
if v.IsPrevEpochHeadAttester && !v.IsSlashed {
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
if helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
Expand All @@ -130,9 +130,9 @@ func attestationDelta(pBal *Balance, v *Validator, prevEpoch, finalizedEpoch typ
}

// Process finality delay penalty
finalityDelay := finalityDelay(prevEpoch, finalizedEpoch)
finalityDelay := helpers.FinalityDelay(prevEpoch, finalizedEpoch)

if isInInactivityLeak(prevEpoch, finalizedEpoch) {
if helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch) {
// If validator is performing optimally, this cancels all rewards for a neutral balance.
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
p += baseRewardsPerEpoch*br - proposerReward
Expand Down Expand Up @@ -177,21 +177,3 @@ func ProposersDelta(state iface.ReadOnlyBeaconState, pBal *Balance, vp []*Valida
}
return rewards, nil
}

// isInInactivityLeak returns true if the state is experiencing inactivity leak.
//
// Spec code:
// def is_in_inactivity_leak(state: BeaconState) -> bool:
// return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
func isInInactivityLeak(prevEpoch, finalizedEpoch types.Epoch) bool {
return finalityDelay(prevEpoch, finalizedEpoch) > params.BeaconConfig().MinEpochsToInactivityPenalty
}

// finalityDelay returns the finality delay using the beacon state.
//
// Spec code:
// def get_finality_delay(state: BeaconState) -> uint64:
// return get_previous_epoch(state) - state.finalized_checkpoint.epoch
func finalityDelay(prevEpoch, finalizedEpoch types.Epoch) types.Epoch {
return prevEpoch - finalizedEpoch
}
52 changes: 0 additions & 52 deletions beacon-chain/core/epoch/precompute/reward_penalty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,55 +350,3 @@ func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, uint64(0), r[proposerIndex], "Unexpected proposer reward for slashed")
}

func TestFinalityDelay(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
beaconState, err := stateV0.InitializeFromProto(base)
require.NoError(t, err)
prevEpoch := types.Epoch(0)
finalizedEpoch := types.Epoch(0)
// Set values for each test case
setVal := func() {
prevEpoch = helpers.PrevEpoch(beaconState)
finalizedEpoch = beaconState.FinalizedCheckpointEpoch()
}
setVal()
d := finalityDelay(prevEpoch, finalizedEpoch)
w := helpers.PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")

require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}))
setVal()
d = finalityDelay(prevEpoch, finalizedEpoch)
w = helpers.PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")

require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}))
setVal()
d = finalityDelay(prevEpoch, finalizedEpoch)
w = helpers.PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")
}

func TestIsInInactivityLeak(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
beaconState, err := stateV0.InitializeFromProto(base)
require.NoError(t, err)
prevEpoch := types.Epoch(0)
finalizedEpoch := types.Epoch(0)
// Set values for each test case
setVal := func() {
prevEpoch = helpers.PrevEpoch(beaconState)
finalizedEpoch = beaconState.FinalizedCheckpointEpoch()
}
setVal()
assert.Equal(t, true, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}))
setVal()
assert.Equal(t, true, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}))
setVal()
assert.Equal(t, false, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak false")
}
18 changes: 18 additions & 0 deletions beacon-chain/core/helpers/rewards_penalties.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,21 @@ func DecreaseBalanceWithVal(currBalance, delta uint64) uint64 {
}
return currBalance - delta
}

// IsInInactivityLeak returns true if the state is experiencing inactivity leak.
//
// Spec code:
// def is_in_inactivity_leak(state: BeaconState) -> bool:
// return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
func IsInInactivityLeak(prevEpoch, finalizedEpoch types.Epoch) bool {
return FinalityDelay(prevEpoch, finalizedEpoch) > params.BeaconConfig().MinEpochsToInactivityPenalty
}

// FinalityDelay returns the finality delay using the beacon state.
//
// Spec code:
// def get_finality_delay(state: BeaconState) -> uint64:
// return get_previous_epoch(state) - state.finalized_checkpoint.epoch
func FinalityDelay(prevEpoch, finalizedEpoch types.Epoch) types.Epoch {
return prevEpoch - finalizedEpoch
}
91 changes: 91 additions & 0 deletions beacon-chain/core/helpers/rewards_penalties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,94 @@ func TestDecreaseBalance_OK(t *testing.T) {
assert.Equal(t, test.eb, state.Balances()[test.i], "Incorrect Validator balance")
}
}

func TestFinalityDelay(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
beaconState, err := stateV0.InitializeFromProto(base)
require.NoError(t, err)
prevEpoch := types.Epoch(0)
finalizedEpoch := types.Epoch(0)
// Set values for each test case
setVal := func() {
prevEpoch = PrevEpoch(beaconState)
finalizedEpoch = beaconState.FinalizedCheckpointEpoch()
}
setVal()
d := FinalityDelay(prevEpoch, finalizedEpoch)
w := PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")

require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}))
setVal()
d = FinalityDelay(prevEpoch, finalizedEpoch)
w = PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")

require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}))
setVal()
d = FinalityDelay(prevEpoch, finalizedEpoch)
w = PrevEpoch(beaconState) - beaconState.FinalizedCheckpointEpoch()
assert.Equal(t, w, d, "Did not get wanted finality delay")
}

func TestIsInInactivityLeak(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
beaconState, err := stateV0.InitializeFromProto(base)
require.NoError(t, err)
prevEpoch := types.Epoch(0)
finalizedEpoch := types.Epoch(0)
// Set values for each test case
setVal := func() {
prevEpoch = PrevEpoch(beaconState)
finalizedEpoch = beaconState.FinalizedCheckpointEpoch()
}
setVal()
assert.Equal(t, true, IsInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}))
setVal()
assert.Equal(t, true, IsInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}))
setVal()
assert.Equal(t, false, IsInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak false")
}

func buildState(slot types.Slot, validatorCount uint64) *pb.BeaconState {
validators := make([]*ethpb.Validator, validatorCount)
for i := 0; i < len(validators); i++ {
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
}
}
validatorBalances := make([]uint64, len(validators))
for i := 0; i < len(validatorBalances); i++ {
validatorBalances[i] = params.BeaconConfig().MaxEffectiveBalance
}
latestActiveIndexRoots := make(
[][]byte,
params.BeaconConfig().EpochsPerHistoricalVector,
)
for i := 0; i < len(latestActiveIndexRoots); i++ {
latestActiveIndexRoots[i] = params.BeaconConfig().ZeroHash[:]
}
latestRandaoMixes := make(
[][]byte,
params.BeaconConfig().EpochsPerHistoricalVector,
)
for i := 0; i < len(latestRandaoMixes); i++ {
latestRandaoMixes[i] = params.BeaconConfig().ZeroHash[:]
}
return &pb.BeaconState{
Slot: slot,
Balances: validatorBalances,
Validators: validators,
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerEpoch*10),
FinalizedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, 32)},
PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, 32)},
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, 32)},
}
}

0 comments on commit 19a9b4b

Please sign in to comment.