Add in Balance Safety Check (#9419)

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Nishant Das 2021-09-29 06:19:10 +08:00 committed by GitHub
parent 8f8ccf11e4
commit 393549ad19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 12 deletions

View File

@ -98,7 +98,10 @@ func ProcessInactivityScores(
v.InactivityScore -= 1
}
} else {
v.InactivityScore += bias
v.InactivityScore, err = math.Add64(v.InactivityScore, bias)
if err != nil {
return nil, nil, err
}
}
if !helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch) {
@ -200,7 +203,10 @@ func ProcessRewardsAndPenaltiesPrecompute(
// Compute the post balance of the validator after accounting for the
// attester and proposer rewards and penalties.
balances[i] = helpers.IncreaseBalanceWithVal(balances[i], attsRewards[i])
balances[i], err = helpers.IncreaseBalanceWithVal(balances[i], attsRewards[i])
if err != nil {
return nil, err
}
balances[i] = helpers.DecreaseBalanceWithVal(balances[i], attsPenalties[i])
vals[i].AfterEpochTransitionBalance = balances[i]
@ -230,7 +236,10 @@ func AttestationsDelta(beaconState state.BeaconStateAltair, bal *precompute.Bala
inactivityDenominator := cfg.InactivityScoreBias * cfg.InactivityPenaltyQuotientAltair
for i, v := range vals {
rewards[i], penalties[i] = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)
rewards[i], penalties[i], err = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)
if err != nil {
return nil, nil, err
}
}
return rewards, penalties, nil
@ -240,11 +249,11 @@ func attestationDelta(
bal *precompute.Balance,
val *precompute.Validator,
baseRewardMultiplier, inactivityDenominator uint64,
inactivityLeak bool) (reward, penalty uint64) {
inactivityLeak bool) (reward, penalty uint64, err error) {
eligible := val.IsActivePrevEpoch || (val.IsSlashed && !val.IsWithdrawableCurrentEpoch)
// Per spec `ActiveCurrentEpoch` can't be 0 to process attestation delta.
if !eligible || bal.ActiveCurrentEpoch == 0 {
return 0, 0
return 0, 0, nil
}
cfg := params.BeaconConfig()
@ -289,9 +298,12 @@ func attestationDelta(
// Process finality delay penalty
// Apply an additional penalty to validators that did not vote on the correct target or slashed
if !val.IsPrevEpochTargetAttester || val.IsSlashed {
n := effectiveBalance * val.InactivityScore
n, err := math.Mul64(effectiveBalance, val.InactivityScore)
if err != nil {
return 0, 0, err
}
penalty += n / inactivityDenominator
}
return reward, penalty
return reward, penalty, nil
}

View File

@ -3,6 +3,7 @@ package altair_test
import (
"context"
"fmt"
"math"
"testing"
types "github.com/prysmaticlabs/eth2-types"
@ -181,3 +182,16 @@ func TestProcessSlashings_SlashedLess(t *testing.T) {
})
}
}
func TestProcessSlashings_BadValue(t *testing.T) {
base := &ethpb.BeaconStateAltair{
Slot: 0,
Validators: []*ethpb.Validator{{Slashed: true}},
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
Slashings: []uint64{math.MaxUint64, 1e9},
}
s, err := stateAltair.InitializeFromProto(base)
require.NoError(t, err)
_, err = epoch.ProcessSlashings(s, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
require.ErrorContains(t, "addition overflows", err)
}

View File

@ -180,7 +180,10 @@ func ProcessSlashings(state state.BeaconState, slashingMultiplier uint64) (state
slashings := state.Slashings()
totalSlashing := uint64(0)
for _, slashing := range slashings {
totalSlashing += slashing
totalSlashing, err = math.Add64(totalSlashing, slashing)
if err != nil {
return nil, err
}
}
// a callback is used here to apply the following actions to all validators

View File

@ -3,6 +3,7 @@ package epoch_test
import (
"context"
"fmt"
"math"
"testing"
types "github.com/prysmaticlabs/eth2-types"
@ -440,3 +441,16 @@ func buildState(t testing.TB, slot types.Slot, validatorCount uint64) state.Beac
}
return s
}
func TestProcessSlashings_BadValue(t *testing.T) {
base := &ethpb.BeaconState{
Slot: 0,
Validators: []*ethpb.Validator{{Slashed: true}},
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
Slashings: []uint64{math.MaxUint64, 1e9},
}
s, err := v1.InitializeFromProto(base)
require.NoError(t, err)
_, err = epoch.ProcessSlashings(s, params.BeaconConfig().ProportionalSlashingMultiplier)
require.ErrorContains(t, "addition overflows", err)
}

View File

@ -47,7 +47,10 @@ func ProcessRewardsAndPenaltiesPrecompute(
// Compute the post balance of the validator after accounting for the
// attester and proposer rewards and penalties.
validatorBals[i] = helpers.IncreaseBalanceWithVal(validatorBals[i], attsRewards[i]+proposerRewards[i])
validatorBals[i], err = helpers.IncreaseBalanceWithVal(validatorBals[i], attsRewards[i]+proposerRewards[i])
if err != nil {
return nil, err
}
validatorBals[i] = helpers.DecreaseBalanceWithVal(validatorBals[i], attsPenalties[i])
vp[i].AfterEpochTransitionBalance = validatorBals[i]

View File

@ -8,6 +8,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
mathutil "github.com/prysmaticlabs/prysm/math"
)
var balanceCache = cache.NewEffectiveBalanceCache()
@ -95,7 +96,11 @@ func IncreaseBalance(state state.BeaconState, idx types.ValidatorIndex, delta ui
if err != nil {
return err
}
return state.UpdateBalancesAtIndex(idx, IncreaseBalanceWithVal(balAtIdx, delta))
newBal, err := IncreaseBalanceWithVal(balAtIdx, delta)
if err != nil {
return err
}
return state.UpdateBalancesAtIndex(idx, newBal)
}
// IncreaseBalanceWithVal increases validator with the given 'index' balance by 'delta' in Gwei.
@ -108,8 +113,8 @@ func IncreaseBalance(state state.BeaconState, idx types.ValidatorIndex, delta ui
// Increase the validator balance at index ``index`` by ``delta``.
// """
// state.balances[index] += delta
func IncreaseBalanceWithVal(currBalance, delta uint64) uint64 {
return currBalance + delta
func IncreaseBalanceWithVal(currBalance, delta uint64) (uint64, error) {
return mathutil.Add64(currBalance, delta)
}
// DecreaseBalance decreases validator with the given 'index' balance by 'delta' in Gwei.

View File

@ -1,6 +1,7 @@
package helpers
import (
"math"
"testing"
types "github.com/prysmaticlabs/eth2-types"
@ -238,3 +239,23 @@ func buildState(slot types.Slot, validatorCount uint64) *ethpb.BeaconState {
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, 32)},
}
}
func TestIncreaseBadBalance_NotOK(t *testing.T) {
tests := []struct {
i types.ValidatorIndex
b []uint64
nb uint64
}{
{i: 0, b: []uint64{math.MaxUint64, math.MaxUint64, math.MaxUint64}, nb: 1},
{i: 2, b: []uint64{math.MaxUint64, math.MaxUint64, math.MaxUint64}, nb: 33 * 1e9},
}
for _, test := range tests {
state, err := v1.InitializeFromProto(&ethpb.BeaconState{
Validators: []*ethpb.Validator{
{EffectiveBalance: 4}, {EffectiveBalance: 4}, {EffectiveBalance: 4}},
Balances: test.b,
})
require.NoError(t, err)
require.ErrorContains(t, "addition overflows", IncreaseBalance(state, test.i, test.nb))
}
}

View File

@ -2,6 +2,7 @@ package transition_test
import (
"context"
"math"
"testing"
"github.com/prysmaticlabs/go-bitfield"
@ -207,6 +208,24 @@ func TestExecuteStateTransitionNoVerifyAnySig_PassesProcessingConditions(t *test
require.Equal(t, true, verified, "Could not verify signature set")
}
func TestProcessEpoch_BadBalanceAltair(t *testing.T) {
s, _ := util.DeterministicGenesisStateAltair(t, 100)
assert.NoError(t, s.SetSlot(63))
assert.NoError(t, s.UpdateBalancesAtIndex(0, math.MaxUint64))
participation := byte(0)
participation = altair.AddValidatorFlag(participation, params.BeaconConfig().TimelyHeadFlagIndex)
participation = altair.AddValidatorFlag(participation, params.BeaconConfig().TimelySourceFlagIndex)
participation = altair.AddValidatorFlag(participation, params.BeaconConfig().TimelyTargetFlagIndex)
epochParticipation, err := s.CurrentEpochParticipation()
assert.NoError(t, err)
epochParticipation[0] = participation
assert.NoError(t, s.SetCurrentParticipationBits(epochParticipation))
assert.NoError(t, s.SetPreviousParticipationBits(epochParticipation))
_, err = altair.ProcessEpoch(context.Background(), s)
assert.ErrorContains(t, "addition overflows", err)
}
func createFullAltairBlockWithOperations(t *testing.T) (state.BeaconStateAltair,
*ethpb.SignedBeaconBlockAltair) {
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, 32)