diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go index a30fdbf5cdb2..6ca9791e616e 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go @@ -518,8 +518,8 @@ func (bs *Server) GetValidatorParticipation( } var v []*precompute.Validator var b *precompute.Balance - switch beaconState.Version() { - case version.Phase0: + + if beaconState.Version() == version.Phase0 { v, b, err = precompute.New(ctx, beaconState) if err != nil { return nil, status.Errorf(codes.Internal, "Could not set up pre compute instance: %v", err) @@ -528,7 +528,7 @@ func (bs *Server) GetValidatorParticipation( if err != nil { return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) } - case version.Altair, version.Bellatrix: + } else if beaconState.Version() >= version.Altair { v, b, err = altair.InitializePrecomputeValidators(ctx, beaconState) if err != nil { return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err) @@ -537,9 +537,10 @@ func (bs *Server) GetValidatorParticipation( if err != nil { return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) } - default: + } else { return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", beaconState.Version()) } + cp := bs.FinalizationFetcher.FinalizedCheckpt() p := ðpb.ValidatorParticipationResponse{ Epoch: requestedEpoch, @@ -678,8 +679,7 @@ func (bs *Server) GetValidatorPerformance( } } var validatorSummary []*precompute.Validator - switch headState.Version() { - case version.Phase0: + if headState.Version() == version.Phase0 { vp, bp, err := precompute.New(ctx, headState) if err != nil { return nil, err @@ -693,7 +693,7 @@ func (bs *Server) GetValidatorPerformance( return nil, err } validatorSummary = vp - case version.Altair, version.Bellatrix: + } else if headState.Version() >= version.Altair { vp, bp, err := altair.InitializePrecomputeValidators(ctx, headState) if err != nil { return nil, err @@ -711,6 +711,8 @@ func (bs *Server) GetValidatorPerformance( return nil, err } validatorSummary = vp + } else { + return nil, status.Errorf(codes.Internal, "Head state version %d not supported", headState.Version()) } responseCap := len(req.Indices) + len(req.PublicKeys) @@ -855,8 +857,7 @@ func (bs *Server) GetIndividualVotes( var v []*precompute.Validator var bal *precompute.Balance - switch st.Version() { - case version.Phase0: + if st.Version() == version.Phase0 { v, bal, err = precompute.New(ctx, st) if err != nil { return nil, status.Errorf(codes.Internal, "Could not set up pre compute instance: %v", err) @@ -865,7 +866,7 @@ func (bs *Server) GetIndividualVotes( if err != nil { return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) } - case version.Altair, version.Bellatrix: + } else if st.Version() >= version.Altair { v, bal, err = altair.InitializePrecomputeValidators(ctx, st) if err != nil { return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err) @@ -874,7 +875,7 @@ func (bs *Server) GetIndividualVotes( if err != nil { return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) } - default: + } else { return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", st.Version()) } diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go index 31dee7dd3dd1..c88b585b68fa 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go @@ -1704,6 +1704,24 @@ func TestServer_GetValidatorParticipation_CurrentAndPrevEpochWithBits(t *testing assert.NoError(t, err) runGetValidatorParticipationCurrentAndPrevEpoch(t, genState, gb) }) + + t.Run("capella", func(t *testing.T) { + validatorCount := uint64(32) + genState, _ := util.DeterministicGenesisStateCapella(t, validatorCount) + c, err := altair.NextSyncCommittee(context.Background(), genState) + require.NoError(t, err) + require.NoError(t, genState.SetCurrentSyncCommittee(c)) + + bits := make([]byte, validatorCount) + for i := range bits { + bits[i] = 0xff + } + require.NoError(t, genState.SetCurrentParticipationBits(bits)) + require.NoError(t, genState.SetPreviousParticipationBits(bits)) + gb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella()) + assert.NoError(t, err) + runGetValidatorParticipationCurrentAndPrevEpoch(t, genState, gb) + }) } func runGetValidatorParticipationCurrentAndPrevEpoch(t *testing.T, genState state.BeaconState, gb interfaces.SignedBeaconBlock) { @@ -2141,6 +2159,74 @@ func TestGetValidatorPerformanceBellatrix_OK(t *testing.T) { } } +func TestGetValidatorPerformanceCapella_OK(t *testing.T) { + helpers.ClearCache() + params.SetupTestConfigCleanup(t) + params.OverrideBeaconConfig(params.MinimalSpecConfig()) + + ctx := context.Background() + epoch := types.Epoch(1) + headState, _ := util.DeterministicGenesisStateCapella(t, 32) + require.NoError(t, headState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch+1)))) + + defaultBal := params.BeaconConfig().MaxEffectiveBalance + extraBal := params.BeaconConfig().MaxEffectiveBalance + params.BeaconConfig().GweiPerEth + balances := []uint64{defaultBal, extraBal, extraBal + params.BeaconConfig().GweiPerEth} + require.NoError(t, headState.SetBalances(balances)) + publicKey1 := bytesutil.ToBytes48([]byte{1}) + publicKey2 := bytesutil.ToBytes48([]byte{2}) + publicKey3 := bytesutil.ToBytes48([]byte{3}) + validators := []*ethpb.Validator{ + { + PublicKey: publicKey1[:], + ActivationEpoch: 5, + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { + PublicKey: publicKey2[:], + EffectiveBalance: defaultBal, + ActivationEpoch: 0, + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { + PublicKey: publicKey3[:], + EffectiveBalance: defaultBal, + ActivationEpoch: 0, + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + } + require.NoError(t, headState.SetValidators(validators)) + require.NoError(t, headState.SetInactivityScores([]uint64{0, 0, 0})) + require.NoError(t, headState.SetBalances([]uint64{100, 101, 102})) + offset := int64(headState.Slot().Mul(params.BeaconConfig().SecondsPerSlot)) + bs := &Server{ + HeadFetcher: &mock.ChainService{ + State: headState, + }, + GenesisTimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, + SyncChecker: &mockSync.Sync{IsSyncing: false}, + } + want := ðpb.ValidatorPerformanceResponse{ + PublicKeys: [][]byte{publicKey2[:], publicKey3[:]}, + CurrentEffectiveBalances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, + CorrectlyVotedSource: []bool{false, false}, + CorrectlyVotedTarget: []bool{false, false}, + CorrectlyVotedHead: []bool{false, false}, + BalancesBeforeEpochTransition: []uint64{101, 102}, + BalancesAfterEpochTransition: []uint64{0, 0}, + MissingValidators: [][]byte{publicKey1[:]}, + InactivityScores: []uint64{0, 0}, + } + + res, err := bs.GetValidatorPerformance(ctx, ðpb.ValidatorPerformanceRequest{ + PublicKeys: [][]byte{publicKey1[:], publicKey3[:], publicKey2[:]}, + }) + require.NoError(t, err) + if !proto.Equal(want, res) { + t.Errorf("Wanted %v\nReceived %v", want, res) + } +} + func BenchmarkListValidatorBalances(b *testing.B) { b.StopTimer() beaconDB := dbTest.SetupDB(b) @@ -2592,6 +2678,94 @@ func TestServer_GetIndividualVotes_BellatrixEndOfEpoch(t *testing.T) { assert.DeepEqual(t, wanted, res, "Unexpected response") } +func TestServer_GetIndividualVotes_CapellaEndOfEpoch(t *testing.T) { + helpers.ClearCache() + params.SetupTestConfigCleanup(t) + params.OverrideBeaconConfig(params.BeaconConfig()) + beaconDB := dbTest.SetupDB(t) + ctx := context.Background() + + validators := uint64(32) + beaconState, _ := util.DeterministicGenesisStateCapella(t, validators) + startSlot, err := slots.EpochStart(1) + assert.NoError(t, err) + require.NoError(t, beaconState.SetSlot(startSlot)) + + b := util.NewBeaconBlock() + b.Block.Slot = startSlot + util.SaveBlock(t, ctx, beaconDB, b) + gRoot, err := b.Block.HashTreeRoot() + require.NoError(t, err) + gen := stategen.New(beaconDB, doublylinkedtree.New()) + require.NoError(t, gen.SaveState(ctx, gRoot, beaconState)) + require.NoError(t, beaconDB.SaveState(ctx, beaconState, gRoot)) + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) + // Save State at the end of the epoch: + endSlot, err := slots.EpochEnd(1) + assert.NoError(t, err) + + beaconState, _ = util.DeterministicGenesisStateCapella(t, validators) + require.NoError(t, beaconState.SetSlot(endSlot)) + + pb, err := beaconState.CurrentEpochParticipation() + require.NoError(t, err) + for i := range pb { + pb[i] = 0xff + } + require.NoError(t, beaconState.SetCurrentParticipationBits(pb)) + require.NoError(t, beaconState.SetPreviousParticipationBits(pb)) + + b.Block.Slot = endSlot + util.SaveBlock(t, ctx, beaconDB, b) + gRoot, err = b.Block.HashTreeRoot() + require.NoError(t, err) + + require.NoError(t, gen.SaveState(ctx, gRoot, beaconState)) + require.NoError(t, beaconDB.SaveState(ctx, beaconState, gRoot)) + bs := &Server{ + StateGen: gen, + GenesisTimeFetcher: &mock.ChainService{}, + } + addDefaultReplayerBuilder(bs, beaconDB) + + res, err := bs.GetIndividualVotes(ctx, ðpb.IndividualVotesRequest{ + Indices: []types.ValidatorIndex{0, 1}, + Epoch: 1, + }) + require.NoError(t, err) + wanted := ðpb.IndividualVotesRespond{ + IndividualVotes: []*ethpb.IndividualVotesRespond_IndividualVote{ + { + ValidatorIndex: 0, + PublicKey: beaconState.Validators()[0].PublicKey, + IsActiveInCurrentEpoch: true, + IsActiveInPreviousEpoch: true, + IsCurrentEpochTargetAttester: true, + IsCurrentEpochAttester: true, + IsPreviousEpochAttester: true, + IsPreviousEpochHeadAttester: true, + IsPreviousEpochTargetAttester: true, + CurrentEpochEffectiveBalanceGwei: params.BeaconConfig().MaxEffectiveBalance, + Epoch: 1, + }, + { + ValidatorIndex: 1, + PublicKey: beaconState.Validators()[1].PublicKey, + IsActiveInCurrentEpoch: true, + IsActiveInPreviousEpoch: true, + IsCurrentEpochTargetAttester: true, + IsCurrentEpochAttester: true, + IsPreviousEpochAttester: true, + IsPreviousEpochHeadAttester: true, + IsPreviousEpochTargetAttester: true, + CurrentEpochEffectiveBalanceGwei: params.BeaconConfig().MaxEffectiveBalance, + Epoch: 1, + }, + }, + } + assert.DeepEqual(t, wanted, res, "Unexpected response") +} + func Test_validatorStatus(t *testing.T) { tests := []struct { name string