diff --git a/beacon-chain/rpc/beacon/validators.go b/beacon-chain/rpc/beacon/validators.go index cd41b3a3eb69..1c28f2b933ed 100644 --- a/beacon-chain/rpc/beacon/validators.go +++ b/beacon-chain/rpc/beacon/validators.go @@ -360,60 +360,18 @@ func (bs *Server) GetValidator( func (bs *Server) GetValidatorActiveSetChanges( ctx context.Context, req *ethpb.GetValidatorActiveSetChangesRequest, ) (*ethpb.ActiveSetChanges, error) { - headState, err := bs.HeadFetcher.HeadState(ctx) - if err != nil { - return nil, status.Error(codes.Internal, "Could not get head state") - } - currentEpoch := helpers.CurrentEpoch(headState) - requestedEpoch := currentEpoch - requestingGenesis := false + currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + var requestedEpoch uint64 switch q := req.QueryFilter.(type) { case *ethpb.GetValidatorActiveSetChangesRequest_Genesis: - requestingGenesis = q.Genesis requestedEpoch = 0 case *ethpb.GetValidatorActiveSetChangesRequest_Epoch: requestedEpoch = q.Epoch + default: + requestedEpoch = currentEpoch } - - activatedIndices := make([]uint64, 0) - exitedIndices := make([]uint64, 0) - slashedIndices := make([]uint64, 0) - ejectedIndices := make([]uint64, 0) - if requestingGenesis || requestedEpoch < currentEpoch { - archivedChanges, err := bs.BeaconDB.ArchivedActiveValidatorChanges(ctx, requestedEpoch) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not fetch archived active validator changes: %v", err) - } - if archivedChanges == nil { - return nil, status.Errorf( - codes.NotFound, - "Did not find any data for epoch %d - perhaps no active set changed occurred during the epoch", - requestedEpoch, - ) - } - activatedIndices = archivedChanges.Activated - exitedIndices = archivedChanges.Exited - slashedIndices = archivedChanges.Slashed - ejectedIndices = archivedChanges.Ejected - } else if requestedEpoch == currentEpoch { - activeValidatorCount, err := helpers.ActiveValidatorCount(headState, helpers.PrevEpoch(headState)) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err) - } - vals := headState.Validators() - activatedIndices = validators.ActivatedValidatorIndices(helpers.PrevEpoch(headState), vals) - exitedIndices, err = validators.ExitedValidatorIndices(helpers.PrevEpoch(headState), vals, activeValidatorCount) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not determine exited validator indices: %v", err) - } - slashedIndices = validators.SlashedValidatorIndices(helpers.PrevEpoch(headState), vals) - ejectedIndices, err = validators.EjectedValidatorIndices(helpers.PrevEpoch(headState), vals, activeValidatorCount) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not determine ejected validator indices: %v", err) - } - } else { - // We are requesting data from the future and we return an error. + if requestedEpoch > currentEpoch { return nil, status.Errorf( codes.InvalidArgument, "Cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", @@ -422,25 +380,51 @@ func (bs *Server) GetValidatorActiveSetChanges( ) } - // We retrieve the public keys for the indices. + activatedIndices := make([]uint64, 0) + exitedIndices := make([]uint64, 0) + slashedIndices := make([]uint64, 0) + ejectedIndices := make([]uint64, 0) + + requestedState, err := bs.StateGen.StateBySlot(ctx, helpers.StartSlot(requestedEpoch)) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) + } + + activeValidatorCount, err := helpers.ActiveValidatorCount(requestedState, helpers.CurrentEpoch(requestedState)) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err) + } + vs := requestedState.Validators() + activatedIndices = validators.ActivatedValidatorIndices(helpers.CurrentEpoch(requestedState), vs) + exitedIndices, err = validators.ExitedValidatorIndices(helpers.CurrentEpoch(requestedState), vs, activeValidatorCount) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not determine exited validator indices: %v", err) + } + slashedIndices = validators.SlashedValidatorIndices(helpers.CurrentEpoch(requestedState), vs) + ejectedIndices, err = validators.EjectedValidatorIndices(helpers.CurrentEpoch(requestedState), vs, activeValidatorCount) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not determine ejected validator indices: %v", err) + } + + // Retrieve public keys for the indices. activatedKeys := make([][]byte, len(activatedIndices)) exitedKeys := make([][]byte, len(exitedIndices)) slashedKeys := make([][]byte, len(slashedIndices)) ejectedKeys := make([][]byte, len(ejectedIndices)) for i, idx := range activatedIndices { - pubkey := headState.PubkeyAtIndex(idx) + pubkey := requestedState.PubkeyAtIndex(idx) activatedKeys[i] = pubkey[:] } for i, idx := range exitedIndices { - pubkey := headState.PubkeyAtIndex(idx) + pubkey := requestedState.PubkeyAtIndex(idx) exitedKeys[i] = pubkey[:] } for i, idx := range slashedIndices { - pubkey := headState.PubkeyAtIndex(idx) + pubkey := requestedState.PubkeyAtIndex(idx) slashedKeys[i] = pubkey[:] } for i, idx := range ejectedIndices { - pubkey := headState.PubkeyAtIndex(idx) + pubkey := requestedState.PubkeyAtIndex(idx) ejectedKeys[i] = pubkey[:] } return ðpb.ActiveSetChanges{ diff --git a/beacon-chain/rpc/beacon/validators_test.go b/beacon-chain/rpc/beacon/validators_test.go index 773b475057fc..0fd3834439b8 100644 --- a/beacon-chain/rpc/beacon/validators_test.go +++ b/beacon-chain/rpc/beacon/validators_test.go @@ -1123,27 +1123,19 @@ func TestServer_GetValidator(t *testing.T) { } func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing.T) { - db := dbTest.SetupDB(t) - defer dbTest.TeardownDB(t, db) - ctx := context.Background() st := testutil.NewBeaconState() if err := st.SetSlot(0); err != nil { t.Fatal(err) } - bs := &Server{ - BeaconDB: db, - HeadFetcher: &mock.ChainService{ - State: st, - }, - } + bs := &Server{GenesisTimeFetcher: &mock.ChainService{}} wanted := "Cannot retrieve information about an epoch in the future" if _, err := bs.GetValidatorActiveSetChanges( ctx, ðpb.GetValidatorActiveSetChangesRequest{ QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Epoch{ - Epoch: 1, + Epoch: helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1, }, }, ); err != nil && !strings.Contains(err.Error(), wanted) { @@ -1152,6 +1144,9 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing } func TestServer_GetValidatorActiveSetChanges(t *testing.T) { + db := dbTest.SetupDB(t) + defer dbTest.TeardownDB(t, db) + ctx := context.Background() validators := make([]*ethpb.Validator, 8) headState := testutil.NewBeaconState() @@ -1196,110 +1191,28 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) { t.Fatal(err) } } - bs := &Server{ - HeadFetcher: &mock.ChainService{ - State: headState, - }, - FinalizationFetcher: &mock.ChainService{ - FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0}, - }, - } - res, err := bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{}) - if err != nil { + b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}} + if err := db.SaveBlock(ctx, b); err != nil { t.Fatal(err) } - wantedActive := [][]byte{ - pubKey(0), - pubKey(2), - pubKey(4), - pubKey(6), - } - wantedActiveIndices := []uint64{0, 2, 4, 6} - wantedExited := [][]byte{ - pubKey(5), - } - wantedExitedIndices := []uint64{5} - wantedSlashed := [][]byte{ - pubKey(3), - } - wantedSlashedIndices := []uint64{3} - wantedEjected := [][]byte{ - pubKey(7), - } - wantedEjectedIndices := []uint64{7} - wanted := ðpb.ActiveSetChanges{ - Epoch: 0, - ActivatedPublicKeys: wantedActive, - ActivatedIndices: wantedActiveIndices, - ExitedPublicKeys: wantedExited, - ExitedIndices: wantedExitedIndices, - SlashedPublicKeys: wantedSlashed, - SlashedIndices: wantedSlashedIndices, - EjectedPublicKeys: wantedEjected, - EjectedIndices: wantedEjectedIndices, - } - if !proto.Equal(wanted, res) { - t.Errorf("Wanted \n%v, received \n%v", wanted, res) - } -} -func TestServer_GetValidatorActiveSetChanges_FromArchive(t *testing.T) { - db := dbTest.SetupDB(t) - defer dbTest.TeardownDB(t, db) - ctx := context.Background() - validators := make([]*ethpb.Validator, 8) - headState := testutil.NewBeaconState() - if err := headState.SetSlot(helpers.StartSlot(100)); err != nil { - t.Fatal(err) - } - if err := headState.SetValidators(validators); err != nil { + gRoot, err := ssz.HashTreeRoot(b.Block) + if err != nil { t.Fatal(err) } - activatedIndices := make([]uint64, 0) - exitedIndices := make([]uint64, 0) - slashedIndices := make([]uint64, 0) - ejectedIndices := make([]uint64, 0) - for i := 0; i < len(validators); i++ { - // Mark indices divisible by two as activated. - if i%2 == 0 { - activatedIndices = append(activatedIndices, uint64(i)) - } else if i%3 == 0 { - // Mark indices divisible by 3 as slashed. - slashedIndices = append(slashedIndices, uint64(i)) - } else if i%5 == 0 { - // Mark indices divisible by 5 as exited. - exitedIndices = append(exitedIndices, uint64(i)) - } else if i%7 == 0 { - // Mark indices divisible by 7 as ejected. - ejectedIndices = append(ejectedIndices, uint64(i)) - } - key := make([]byte, 48) - copy(key, strconv.Itoa(i)) - if err := headState.UpdateValidatorAtIndex(uint64(i), ðpb.Validator{ - PublicKey: key, - }); err != nil { - t.Fatal(err) - } - } - archivedChanges := &pbp2p.ArchivedActiveSetChanges{ - Activated: activatedIndices, - Exited: exitedIndices, - Slashed: slashedIndices, - Ejected: ejectedIndices, - } - // We store the changes during the genesis epoch. - if err := db.SaveArchivedActiveValidatorChanges(ctx, 0, archivedChanges); err != nil { + if err := db.SaveGenesisBlockRoot(ctx, gRoot); err != nil { t.Fatal(err) } - // We store the same changes during epoch 5 for further testing. - if err := db.SaveArchivedActiveValidatorChanges(ctx, 5, archivedChanges); err != nil { + if err := db.SaveState(ctx, headState, gRoot); err != nil { t.Fatal(err) } + bs := &Server{ - BeaconDB: db, - HeadFetcher: &mock.ChainService{ - State: headState, + FinalizationFetcher: &mock.ChainService{ + FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0}, }, + GenesisTimeFetcher: &mock.ChainService{}, + StateGen: stategen.New(db, cache.NewStateSummaryCache()), } res, err := bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{ QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Genesis{Genesis: true}, @@ -1307,29 +1220,23 @@ func TestServer_GetValidatorActiveSetChanges_FromArchive(t *testing.T) { if err != nil { t.Fatal(err) } - wantedKeys := make([][]byte, 8) - for i := 0; i < len(wantedKeys); i++ { - k := make([]byte, 48) - copy(k, strconv.Itoa(i)) - wantedKeys[i] = k - } wantedActive := [][]byte{ - wantedKeys[0], - wantedKeys[2], - wantedKeys[4], - wantedKeys[6], + pubKey(0), + pubKey(2), + pubKey(4), + pubKey(6), } wantedActiveIndices := []uint64{0, 2, 4, 6} wantedExited := [][]byte{ - wantedKeys[5], + pubKey(5), } wantedExitedIndices := []uint64{5} wantedSlashed := [][]byte{ - wantedKeys[3], + pubKey(3), } wantedSlashedIndices := []uint64{3} wantedEjected := [][]byte{ - wantedKeys[7], + pubKey(7), } wantedEjectedIndices := []uint64{7} wanted := ðpb.ActiveSetChanges{ @@ -1346,16 +1253,6 @@ func TestServer_GetValidatorActiveSetChanges_FromArchive(t *testing.T) { if !proto.Equal(wanted, res) { t.Errorf("Wanted \n%v, received \n%v", wanted, res) } - res, err = bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{ - QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Epoch{Epoch: 5}, - }) - if err != nil { - t.Fatal(err) - } - wanted.Epoch = 5 - if !proto.Equal(wanted, res) { - t.Errorf("Wanted \n%v, received \n%v", wanted, res) - } } func TestServer_GetValidatorQueue_PendingActivation(t *testing.T) {