diff --git a/beacon-chain/core/epoch/precompute/reward_penalty.go b/beacon-chain/core/epoch/precompute/reward_penalty.go index 9a95364ba..07868da4f 100644 --- a/beacon-chain/core/epoch/precompute/reward_penalty.go +++ b/beacon-chain/core/epoch/precompute/reward_penalty.go @@ -162,6 +162,10 @@ func ProposersDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient for _, v := range vp { + if v.ProposerIndex > uint64(len(rewards)) { + // This should never happen with a valid state / validator. + return nil, errors.New("proposer index out of range") + } // Only apply inclusion rewards to proposer only if the attested hasn't been slashed. if v.IsPrevEpochAttester && !v.IsSlashed { vBalance := v.CurrentEpochEffectiveBalance diff --git a/beacon-chain/core/epoch/precompute/reward_penalty_test.go b/beacon-chain/core/epoch/precompute/reward_penalty_test.go index 085c3466f..3df1ddddb 100644 --- a/beacon-chain/core/epoch/precompute/reward_penalty_test.go +++ b/beacon-chain/core/epoch/precompute/reward_penalty_test.go @@ -359,6 +359,26 @@ func TestProposerDeltaPrecompute_HappyCase(t *testing.T) { } } +func TestProposerDeltaPrecompute_ValidatorIndexOutOfRange(t *testing.T) { + e := params.BeaconConfig().SlotsPerEpoch + validatorCount := uint64(10) + base := buildState(e, validatorCount) + state, err := state.InitializeFromProto(base) + if err != nil { + t.Fatal(err) + } + + proposerIndex := validatorCount + 1 + b := &Balance{ActiveCurrentEpoch: 1000} + v := []*Validator{ + {IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex}, + } + _, err = ProposersDelta(state, b, v) + if err == nil { + t.Fatal("Expected an error with invalid proposer index") + } +} + func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) { e := params.BeaconConfig().SlotsPerEpoch validatorCount := uint64(10)