From d673dbebb3b2f9fb3b023a9cb725f0f4e27a07d7 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Thu, 25 Jul 2024 16:58:54 +0100 Subject: [PATCH 1/8] add GetValidatorActiveSetChanges --- api/server/structs/endpoints_validator.go | 12 ++ beacon-chain/rpc/core/BUILD.bazel | 2 + beacon-chain/rpc/core/service.go | 3 + beacon-chain/rpc/core/validator.go | 91 ++++++++++ beacon-chain/rpc/endpoints.go | 10 + beacon-chain/rpc/endpoints_test.go | 5 +- .../rpc/prysm/v1alpha1/beacon/BUILD.bazel | 1 - .../rpc/prysm/v1alpha1/beacon/validators.go | 69 +------ .../prysm/v1alpha1/beacon/validators_test.go | 20 +- beacon-chain/rpc/prysm/validator/BUILD.bazel | 16 +- beacon-chain/rpc/prysm/validator/handlers.go | 85 +++++++++ .../rpc/prysm/validator/handlers_test.go | 171 ++++++++++++++++++ 12 files changed, 408 insertions(+), 77 deletions(-) create mode 100644 beacon-chain/rpc/prysm/validator/handlers.go create mode 100644 beacon-chain/rpc/prysm/validator/handlers_test.go diff --git a/api/server/structs/endpoints_validator.go b/api/server/structs/endpoints_validator.go index 960033375f28..1baf0f4a246f 100644 --- a/api/server/structs/endpoints_validator.go +++ b/api/server/structs/endpoints_validator.go @@ -118,3 +118,15 @@ type GetValidatorPerformanceResponse struct { MissingValidators [][]byte `json:"missing_validators,omitempty"` InactivityScores []uint64 `json:"inactivity_scores,omitempty"` } + +type ActiveSetChanges struct { + Epoch string `json:"epoch"` + ActivatedPublicKeys []string `json:"activated_public_keys"` + ActivatedIndices []string `json:"activated_indices"` + ExitedPublicKeys []string `json:"exited_public_keys"` + ExitedIndices []string `json:"exited_indices"` + SlashedPublicKeys []string `json:"slashed_public_keys"` + SlashedIndices []string `json:"slashed_indices"` + EjectedPublicKeys []string `json:"ejected_public_keys"` + EjectedIndices []string `json:"ejected_indices"` +} diff --git a/beacon-chain/rpc/core/BUILD.bazel b/beacon-chain/rpc/core/BUILD.bazel index 4cfff1e05453..b11456558213 100644 --- a/beacon-chain/rpc/core/BUILD.bazel +++ b/beacon-chain/rpc/core/BUILD.bazel @@ -20,6 +20,8 @@ go_library( "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/time:go_default_library", "//beacon-chain/core/transition:go_default_library", + "//beacon-chain/core/validators:go_default_library", + "//beacon-chain/db:go_default_library", "//beacon-chain/forkchoice/types:go_default_library", "//beacon-chain/operations/synccommittee:go_default_library", "//beacon-chain/p2p:go_default_library", diff --git a/beacon-chain/rpc/core/service.go b/beacon-chain/rpc/core/service.go index d407c881f4cd..3b1639d2eca8 100644 --- a/beacon-chain/rpc/core/service.go +++ b/beacon-chain/rpc/core/service.go @@ -4,6 +4,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache" opfeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/db" "github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/synccommittee" "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen" @@ -11,6 +12,8 @@ import ( ) type Service struct { + BeaconDB db.ReadOnlyDatabase + ChainInfoFetcher blockchain.ChainInfoFetcher HeadFetcher blockchain.HeadFetcher FinalizedFetcher blockchain.FinalizationFetcher GenesisTimeFetcher blockchain.TimeFetcher diff --git a/beacon-chain/rpc/core/validator.go b/beacon-chain/rpc/core/validator.go index 251e29ca68e1..9d186fc63ea6 100644 --- a/beacon-chain/rpc/core/validator.go +++ b/beacon-chain/rpc/core/validator.go @@ -16,6 +16,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" coreTime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators" forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types" beaconState "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" @@ -752,3 +753,93 @@ func subnetsFromCommittee(pubkey []byte, comm *ethpb.SyncCommittee) []uint64 { } return positions } + +// ValidatorActiveSetChanges retrieves the active set changes for a given epoch. +// +// This data includes any activations, voluntary exits, and involuntary +// ejections. +func (s *Service) ValidatorActiveSetChanges( + ctx context.Context, + requestedEpoch primitives.Epoch, +) ( + *ethpb.ActiveSetChanges, + *RpcError, +) { + currentEpoch := slots.ToEpoch(s.GenesisTimeFetcher.CurrentSlot()) + if requestedEpoch > currentEpoch { + return nil, &RpcError{ + Err: fmt.Errorf("cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", currentEpoch, requestedEpoch), + Reason: BadRequest, + } + } + + slot, err := slots.EpochStart(requestedEpoch) + if err != nil { + return nil, &RpcError{Err: err, Reason: BadRequest} + } + requestedState, err := s.ReplayerBuilder.ReplayerForSlot(slot).ReplayBlocks(ctx) + if err != nil { + return nil, &RpcError{ + Err: fmt.Errorf("error replaying blocks for state at slot %d: %v", slot, err), + Reason: Internal, + } + } + + activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, requestedState, coreTime.CurrentEpoch(requestedState)) + if err != nil { + return nil, &RpcError{ + Err: fmt.Errorf("could not get active validator count: %v", err), + Reason: Internal, + } + } + vs := requestedState.Validators() + activatedIndices := validators.ActivatedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs) + exitedIndices, err := validators.ExitedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) + if err != nil { + return nil, &RpcError{ + Err: fmt.Errorf("could not determine exited validator indices: %v", err), + Reason: Internal, + } + } + slashedIndices := validators.SlashedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs) + ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) + if err != nil { + return nil, &RpcError{ + Err: fmt.Errorf("could not determine ejected validator indices: %v", err), + Reason: Internal, + } + } + + // 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 := requestedState.PubkeyAtIndex(idx) + activatedKeys[i] = pubkey[:] + } + for i, idx := range exitedIndices { + pubkey := requestedState.PubkeyAtIndex(idx) + exitedKeys[i] = pubkey[:] + } + for i, idx := range slashedIndices { + pubkey := requestedState.PubkeyAtIndex(idx) + slashedKeys[i] = pubkey[:] + } + for i, idx := range ejectedIndices { + pubkey := requestedState.PubkeyAtIndex(idx) + ejectedKeys[i] = pubkey[:] + } + return ðpb.ActiveSetChanges{ + Epoch: requestedEpoch, + ActivatedPublicKeys: activatedKeys, + ActivatedIndices: activatedIndices, + ExitedPublicKeys: exitedKeys, + ExitedIndices: exitedIndices, + SlashedPublicKeys: slashedKeys, + SlashedIndices: slashedIndices, + EjectedPublicKeys: ejectedKeys, + EjectedIndices: ejectedIndices, + }, nil +} diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index c8a15a3b4e09..ce06bcacf98d 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -1087,5 +1087,15 @@ func (*Service) prysmValidatorEndpoints(coreService *core.Service) []endpoint { handler: server.GetValidatorPerformance, methods: []string{http.MethodPost}, }, + { + template: "/prysm/v1/validators/active_set_changes", + name: namespace + ".GetValidatorActiveSetChanges", + middleware: []mux.MiddlewareFunc{ + middleware.ContentTypeHandler([]string{api.JsonMediaType}), + middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), + }, + handler: server.GetValidatorActiveSetChanges, + methods: []string{http.MethodGet}, + }, } } diff --git a/beacon-chain/rpc/endpoints_test.go b/beacon-chain/rpc/endpoints_test.go index e3d8d753b114..4b507facd254 100644 --- a/beacon-chain/rpc/endpoints_test.go +++ b/beacon-chain/rpc/endpoints_test.go @@ -124,8 +124,9 @@ func Test_endpoints(t *testing.T) { } prysmValidatorRoutes := map[string][]string{ - "/prysm/validators/performance": {http.MethodPost}, - "/prysm/v1/validators/performance": {http.MethodPost}, + "/prysm/validators/performance": {http.MethodPost}, + "/prysm/v1/validators/performance": {http.MethodPost}, + "/prysm/v1/validators/active_set_changes": {http.MethodGet}, } s := &Service{cfg: &Config{}} diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/BUILD.bazel b/beacon-chain/rpc/prysm/v1alpha1/beacon/BUILD.bazel index e9ee37d4291c..961177984793 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/BUILD.bazel +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/BUILD.bazel @@ -27,7 +27,6 @@ go_library( "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/time:go_default_library", "//beacon-chain/core/transition:go_default_library", - "//beacon-chain/core/validators:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/db/filters:go_default_library", "//beacon-chain/execution:go_default_library", diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go index 4b4e59b04802..743a2a1570a3 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go @@ -12,7 +12,6 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" coreTime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition" - "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/cmd" @@ -392,7 +391,7 @@ func (bs *Server) GetValidator( func (bs *Server) GetValidatorActiveSetChanges( ctx context.Context, req *ethpb.GetValidatorActiveSetChangesRequest, ) (*ethpb.ActiveSetChanges, error) { - currentEpoch := slots.ToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + currentEpoch := slots.ToEpoch(bs.CoreService.GenesisTimeFetcher.CurrentSlot()) var requestedEpoch primitives.Epoch switch q := req.QueryFilter.(type) { @@ -403,72 +402,12 @@ func (bs *Server) GetValidatorActiveSetChanges( default: requestedEpoch = currentEpoch } - if requestedEpoch > currentEpoch { - return nil, status.Errorf( - codes.InvalidArgument, - errEpoch, - currentEpoch, - requestedEpoch, - ) - } - s, err := slots.EpochStart(requestedEpoch) + as, err := bs.CoreService.ValidatorActiveSetChanges(ctx, requestedEpoch) if err != nil { - return nil, err + return nil, status.Errorf(core.ErrorReasonToGRPC(err.Reason), "Could not retrieve validator active set changes: %v", err.Err) } - requestedState, err := bs.ReplayerBuilder.ReplayerForSlot(s).ReplayBlocks(ctx) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error replaying blocks for state at slot %d: %v", s, err)) - } - - activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, requestedState, coreTime.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(coreTime.CurrentEpoch(requestedState), vs) - exitedIndices, err := validators.ExitedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not determine exited validator indices: %v", err) - } - slashedIndices := validators.SlashedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs) - ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.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 := requestedState.PubkeyAtIndex(idx) - activatedKeys[i] = pubkey[:] - } - for i, idx := range exitedIndices { - pubkey := requestedState.PubkeyAtIndex(idx) - exitedKeys[i] = pubkey[:] - } - for i, idx := range slashedIndices { - pubkey := requestedState.PubkeyAtIndex(idx) - slashedKeys[i] = pubkey[:] - } - for i, idx := range ejectedIndices { - pubkey := requestedState.PubkeyAtIndex(idx) - ejectedKeys[i] = pubkey[:] - } - return ðpb.ActiveSetChanges{ - Epoch: requestedEpoch, - ActivatedPublicKeys: activatedKeys, - ActivatedIndices: activatedIndices, - ExitedPublicKeys: exitedKeys, - ExitedIndices: exitedIndices, - SlashedPublicKeys: slashedKeys, - SlashedIndices: slashedIndices, - EjectedPublicKeys: ejectedKeys, - EjectedIndices: ejectedIndices, - }, nil + return as, nil } // GetValidatorParticipation retrieves the validator participation information for a given epoch, diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go index 83abeb5ae372..06d071cd197f 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go @@ -54,11 +54,13 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing require.NoError(t, err) require.NoError(t, st.SetSlot(0)) bs := &Server{ - GenesisTimeFetcher: &mock.ChainService{}, - HeadFetcher: &mock.ChainService{ - State: st, + CoreService: &core.Service{ + BeaconDB: beaconDB, + GenesisTimeFetcher: &mock.ChainService{}, + HeadFetcher: &mock.ChainService{ + State: st, + }, }, - BeaconDB: beaconDB, } wanted := errNoEpochInfoError @@ -66,7 +68,7 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing ctx, ðpb.GetValidatorActiveSetChangesRequest{ QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Epoch{ - Epoch: slots.ToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1, + Epoch: slots.ToEpoch(bs.CoreService.GenesisTimeFetcher.CurrentSlot()) + 1, }, }, ) @@ -1283,10 +1285,12 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) { require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) bs := &Server{ - FinalizationFetcher: &mock.ChainService{ - FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)}, + CoreService: &core.Service{ + FinalizedFetcher: &mock.ChainService{ + FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)}, + }, + GenesisTimeFetcher: &mock.ChainService{}, }, - GenesisTimeFetcher: &mock.ChainService{}, } addDefaultReplayerBuilder(bs, beaconDB) res, err := bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{ diff --git a/beacon-chain/rpc/prysm/validator/BUILD.bazel b/beacon-chain/rpc/prysm/validator/BUILD.bazel index 1c0e4f9368cb..ecca930645a8 100644 --- a/beacon-chain/rpc/prysm/validator/BUILD.bazel +++ b/beacon-chain/rpc/prysm/validator/BUILD.bazel @@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "handlers.go", "server.go", "validator_performance.go", ], @@ -11,8 +12,12 @@ go_library( deps = [ "//api/server/structs:go_default_library", "//beacon-chain/rpc/core:go_default_library", + "//beacon-chain/rpc/eth/shared:go_default_library", + "//consensus-types/primitives:go_default_library", "//network/httputil:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//time/slots:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_pkg_errors//:go_default_library", "@io_opencensus_go//trace:go_default_library", ], @@ -20,16 +25,23 @@ go_library( go_test( name = "go_default_test", - srcs = ["validator_performance_test.go"], + srcs = [ + "handlers_test.go", + "validator_performance_test.go", + ], embed = [":go_default_library"], deps = [ "//api/server/structs:go_default_library", "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/core/epoch/precompute:go_default_library", "//beacon-chain/core/helpers:go_default_library", + "//beacon-chain/db/testing:go_default_library", "//beacon-chain/rpc/core:go_default_library", "//beacon-chain/state:go_default_library", + "//beacon-chain/state/stategen:go_default_library", + "//beacon-chain/state/stategen/mock:go_default_library", "//beacon-chain/sync/initial-sync/testing:go_default_library", + "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", @@ -37,6 +49,8 @@ go_test( "//runtime/version:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "//time/slots:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", ], ) diff --git a/beacon-chain/rpc/prysm/validator/handlers.go b/beacon-chain/rpc/prysm/validator/handlers.go new file mode 100644 index 000000000000..e08dbef42c1f --- /dev/null +++ b/beacon-chain/rpc/prysm/validator/handlers.go @@ -0,0 +1,85 @@ +package validator + +import ( + "fmt" + "net/http" + "strings" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/prysmaticlabs/prysm/v5/api/server/structs" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/network/httputil" + "github.com/prysmaticlabs/prysm/v5/time/slots" + "go.opencensus.io/trace" +) + +// GetValidatorActiveSetChanges retrieves the active set changes for a given epoch. +// +// This data includes any activations, voluntary exits, and involuntary +// ejections. +func (s *Server) GetValidatorActiveSetChanges(w http.ResponseWriter, r *http.Request) { + ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorActiveSetChanges") + defer span.End() + + stateId := strings.ReplaceAll(r.URL.Query().Get("state_id"), " ", "") + var epoch uint64 + switch stateId { + case "head": + e, err := s.CoreService.ChainInfoFetcher.ReceivedBlocksLastEpoch() + if err != nil { + httputil.HandleError(w, "Could not retrieve head root: "+err.Error(), http.StatusInternalServerError) + return + } + epoch = e + case "finalized": + finalized := s.CoreService.ChainInfoFetcher.FinalizedCheckpt() + epoch = uint64(finalized.Epoch) + case "genesis": + epoch = 0 + default: + _, e, ok := shared.UintFromQuery(w, r, "epoch", true) + if !ok { + currentSlot := s.CoreService.GenesisTimeFetcher.CurrentSlot() + currentEpoch := slots.ToEpoch(currentSlot) + epoch = uint64(currentEpoch) + } else { + epoch = e + } + } + as, err := s.CoreService.ValidatorActiveSetChanges(ctx, primitives.Epoch(epoch)) + if err != nil { + httputil.HandleError(w, err.Err.Error(), core.ErrorReasonToHTTP(err.Reason)) + return + } + + response := &structs.ActiveSetChanges{ + Epoch: fmt.Sprintf("%d", as.Epoch), + ActivatedPublicKeys: byteArrayToString(as.ActivatedPublicKeys), + ActivatedIndices: uint64ArrayToString(as.ActivatedIndices), + ExitedPublicKeys: byteArrayToString(as.ExitedPublicKeys), + ExitedIndices: uint64ArrayToString(as.ExitedIndices), + SlashedPublicKeys: byteArrayToString(as.SlashedPublicKeys), + SlashedIndices: uint64ArrayToString(as.SlashedIndices), + EjectedPublicKeys: byteArrayToString(as.EjectedPublicKeys), + EjectedIndices: uint64ArrayToString(as.EjectedIndices), + } + httputil.WriteJson(w, response) +} + +func byteArrayToString(byteArrays [][]byte) []string { + s := make([]string, len(byteArrays)) + for i, b := range byteArrays { + s[i] = hexutil.Encode(b) + } + return s +} + +func uint64ArrayToString(indices []primitives.ValidatorIndex) []string { + s := make([]string, len(indices)) + for i, u := range indices { + s[i] = fmt.Sprintf("%d", u) + } + return s +} diff --git a/beacon-chain/rpc/prysm/validator/handlers_test.go b/beacon-chain/rpc/prysm/validator/handlers_test.go new file mode 100644 index 000000000000..e50f5f5b040c --- /dev/null +++ b/beacon-chain/rpc/prysm/validator/handlers_test.go @@ -0,0 +1,171 @@ +package validator + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/json" + "fmt" + "math" + "net/http" + "net/http/httptest" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/prysmaticlabs/prysm/v5/api/server/structs" + mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing" + dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen" + mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util" + "github.com/prysmaticlabs/prysm/v5/time/slots" +) + +func addDefaultReplayerBuilder(s *Server, h stategen.HistoryAccessor) { + cc := &mockstategen.CanonicalChecker{Is: true, Err: nil} + cs := &mockstategen.CurrentSlotter{Slot: math.MaxUint64 - 1} + s.CoreService.ReplayerBuilder = stategen.NewCanonicalHistory(h, cc, cs) +} + +func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing.T) { + beaconDB := dbTest.SetupDB(t) + st, err := util.NewBeaconState() + require.NoError(t, err) + require.NoError(t, st.SetSlot(0)) + s := &Server{ + CoreService: &core.Service{ + BeaconDB: beaconDB, + GenesisTimeFetcher: &mock.ChainService{}, + HeadFetcher: &mock.ChainService{ + State: st, + }, + }, + } + + url := "http://example.com?epoch=0" + fmt.Sprintf("%d", slots.ToEpoch(s.CoreService.GenesisTimeFetcher.CurrentSlot())+1) + request := httptest.NewRequest(http.MethodGet, url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetValidatorActiveSetChanges(writer, request) + require.Equal(t, http.StatusBadRequest, writer.Code) + require.StringContains(t, "cannot retrieve information about an epoch in the future", writer.Body.String()) +} + +func TestServer_GetValidatorActiveSetChanges(t *testing.T) { + beaconDB := dbTest.SetupDB(t) + + ctx := context.Background() + validators := make([]*ethpb.Validator, 8) + headState, err := util.NewBeaconState() + require.NoError(t, err) + require.NoError(t, headState.SetSlot(0)) + require.NoError(t, headState.SetValidators(validators)) + for i := 0; i < len(validators); i++ { + activationEpoch := params.BeaconConfig().FarFutureEpoch + withdrawableEpoch := params.BeaconConfig().FarFutureEpoch + exitEpoch := params.BeaconConfig().FarFutureEpoch + slashed := false + balance := params.BeaconConfig().MaxEffectiveBalance + // Mark indices divisible by two as activated. + if i%2 == 0 { + activationEpoch = 0 + } else if i%3 == 0 { + // Mark indices divisible by 3 as slashed. + withdrawableEpoch = params.BeaconConfig().EpochsPerSlashingsVector + slashed = true + } else if i%5 == 0 { + // Mark indices divisible by 5 as exited. + exitEpoch = 0 + withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay + } else if i%7 == 0 { + // Mark indices divisible by 7 as ejected. + exitEpoch = 0 + withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay + balance = params.BeaconConfig().EjectionBalance + } + err := headState.UpdateValidatorAtIndex(primitives.ValidatorIndex(i), ðpb.Validator{ + ActivationEpoch: activationEpoch, + PublicKey: pubKey(uint64(i)), + EffectiveBalance: balance, + WithdrawalCredentials: make([]byte, 32), + WithdrawableEpoch: withdrawableEpoch, + Slashed: slashed, + ExitEpoch: exitEpoch, + }) + require.NoError(t, err) + } + b := util.NewBeaconBlock() + util.SaveBlock(t, ctx, beaconDB, b) + + gRoot, err := b.Block.HashTreeRoot() + require.NoError(t, err) + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) + require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) + + s := &Server{ + CoreService: &core.Service{ + FinalizedFetcher: &mock.ChainService{ + FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)}, + }, + GenesisTimeFetcher: &mock.ChainService{}, + }, + } + addDefaultReplayerBuilder(s, beaconDB) + + url := "http://example.com?state_id=genesis" + request := httptest.NewRequest(http.MethodGet, url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetValidatorActiveSetChanges(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + + wantedActive := []string{ + hexutil.Encode(pubKey(0)), + hexutil.Encode(pubKey(2)), + hexutil.Encode(pubKey(4)), + hexutil.Encode(pubKey(6)), + } + wantedActiveIndices := []string{"0", "2", "4", "6"} + wantedExited := []string{ + hexutil.Encode(pubKey(5)), + } + wantedExitedIndices := []string{"5"} + wantedSlashed := []string{ + hexutil.Encode(pubKey(3)), + } + wantedSlashedIndices := []string{"3"} + wantedEjected := []string{ + hexutil.Encode(pubKey(7)), + } + wantedEjectedIndices := []string{"7"} + want := &structs.ActiveSetChanges{ + Epoch: "0", + ActivatedPublicKeys: wantedActive, + ActivatedIndices: wantedActiveIndices, + ExitedPublicKeys: wantedExited, + ExitedIndices: wantedExitedIndices, + SlashedPublicKeys: wantedSlashed, + SlashedIndices: wantedSlashedIndices, + EjectedPublicKeys: wantedEjected, + EjectedIndices: wantedEjectedIndices, + } + + var as *structs.ActiveSetChanges + err = json.NewDecoder(writer.Body).Decode(&as) + require.NoError(t, err) + require.DeepEqual(t, *want, *as) +} + +func pubKey(i uint64) []byte { + pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength) + binary.LittleEndian.PutUint64(pubKey, i) + return pubKey +} From 20aa6d64b21b2e3369b97afc12fcb8c9a570ba00 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Thu, 25 Jul 2024 17:34:28 +0100 Subject: [PATCH 2/8] fix linter --- beacon-chain/rpc/core/validator.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/beacon-chain/rpc/core/validator.go b/beacon-chain/rpc/core/validator.go index 9d186fc63ea6..b6e7e15d6a22 100644 --- a/beacon-chain/rpc/core/validator.go +++ b/beacon-chain/rpc/core/validator.go @@ -768,7 +768,7 @@ func (s *Service) ValidatorActiveSetChanges( currentEpoch := slots.ToEpoch(s.GenesisTimeFetcher.CurrentSlot()) if requestedEpoch > currentEpoch { return nil, &RpcError{ - Err: fmt.Errorf("cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", currentEpoch, requestedEpoch), + Err: errors.Errorf("cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", currentEpoch, requestedEpoch), Reason: BadRequest, } } @@ -780,7 +780,7 @@ func (s *Service) ValidatorActiveSetChanges( requestedState, err := s.ReplayerBuilder.ReplayerForSlot(slot).ReplayBlocks(ctx) if err != nil { return nil, &RpcError{ - Err: fmt.Errorf("error replaying blocks for state at slot %d: %v", slot, err), + Err: errors.Wrapf(err, "error replaying blocks for state at slot %d: %v", slot), Reason: Internal, } } @@ -788,7 +788,7 @@ func (s *Service) ValidatorActiveSetChanges( activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, requestedState, coreTime.CurrentEpoch(requestedState)) if err != nil { return nil, &RpcError{ - Err: fmt.Errorf("could not get active validator count: %v", err), + Err: errors.Wrap(err, "could not get active validator count"), Reason: Internal, } } @@ -797,7 +797,7 @@ func (s *Service) ValidatorActiveSetChanges( exitedIndices, err := validators.ExitedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) if err != nil { return nil, &RpcError{ - Err: fmt.Errorf("could not determine exited validator indices: %v", err), + Err: errors.Wrap(err, "could not determine exited validator indices"), Reason: Internal, } } @@ -805,7 +805,7 @@ func (s *Service) ValidatorActiveSetChanges( ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) if err != nil { return nil, &RpcError{ - Err: fmt.Errorf("could not determine ejected validator indices: %v", err), + Err: errors.Wrap(err, "could not determine ejected validator indices: %v"), Reason: Internal, } } From eb3cb83fd951385dbc5eb32158e1a20ce7b789fd Mon Sep 17 00:00:00 2001 From: Saolyn Date: Thu, 25 Jul 2024 17:49:01 +0100 Subject: [PATCH 3/8] fix errors --- beacon-chain/rpc/core/validator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon-chain/rpc/core/validator.go b/beacon-chain/rpc/core/validator.go index b6e7e15d6a22..b04b2cd53029 100644 --- a/beacon-chain/rpc/core/validator.go +++ b/beacon-chain/rpc/core/validator.go @@ -780,7 +780,7 @@ func (s *Service) ValidatorActiveSetChanges( requestedState, err := s.ReplayerBuilder.ReplayerForSlot(slot).ReplayBlocks(ctx) if err != nil { return nil, &RpcError{ - Err: errors.Wrapf(err, "error replaying blocks for state at slot %d: %v", slot), + Err: errors.Wrapf(err, "error replaying blocks for state at slot %d", slot), Reason: Internal, } } @@ -805,7 +805,7 @@ func (s *Service) ValidatorActiveSetChanges( ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount) if err != nil { return nil, &RpcError{ - Err: errors.Wrap(err, "could not determine ejected validator indices: %v"), + Err: errors.Wrap(err, "could not determine ejected validator indices"), Reason: Internal, } } From 4e13d82b78deb411e1639fe5b0f12fd883d2f1f0 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Fri, 2 Aug 2024 12:01:58 +0100 Subject: [PATCH 4/8] James' review --- beacon-chain/rpc/endpoints.go | 1 - 1 file changed, 1 deletion(-) diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index ce06bcacf98d..4324fa0f3f90 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -1091,7 +1091,6 @@ func (*Service) prysmValidatorEndpoints(coreService *core.Service) []endpoint { template: "/prysm/v1/validators/active_set_changes", name: namespace + ".GetValidatorActiveSetChanges", middleware: []mux.MiddlewareFunc{ - middleware.ContentTypeHandler([]string{api.JsonMediaType}), middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, handler: server.GetValidatorActiveSetChanges, From 1203c9c25b110d49655be0095b2932f8c2e60fc3 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Fri, 2 Aug 2024 12:25:11 +0100 Subject: [PATCH 5/8] use stater --- beacon-chain/rpc/endpoints.go | 5 ++- beacon-chain/rpc/prysm/validator/BUILD.bazel | 4 ++ beacon-chain/rpc/prysm/validator/handlers.go | 42 +++++++------------ .../rpc/prysm/validator/handlers_test.go | 27 ++++++++---- beacon-chain/rpc/prysm/validator/server.go | 2 + 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index 4324fa0f3f90..370d08075f76 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -70,7 +70,7 @@ func (s *Service) endpoints( endpoints = append(endpoints, s.eventsEndpoints()...) endpoints = append(endpoints, s.prysmBeaconEndpoints(ch, stater, coreService)...) endpoints = append(endpoints, s.prysmNodeEndpoints()...) - endpoints = append(endpoints, s.prysmValidatorEndpoints(coreService)...) + endpoints = append(endpoints, s.prysmValidatorEndpoints(stater, coreService)...) if enableDebug { endpoints = append(endpoints, s.debugEndpoints(stater)...) } @@ -1060,8 +1060,9 @@ func (s *Service) prysmNodeEndpoints() []endpoint { } } -func (*Service) prysmValidatorEndpoints(coreService *core.Service) []endpoint { +func (*Service) prysmValidatorEndpoints(stater lookup.Stater, coreService *core.Service) []endpoint { server := &validatorprysm.Server{ + Stater: stater, CoreService: coreService, } diff --git a/beacon-chain/rpc/prysm/validator/BUILD.bazel b/beacon-chain/rpc/prysm/validator/BUILD.bazel index ecca930645a8..6d84d1911caf 100644 --- a/beacon-chain/rpc/prysm/validator/BUILD.bazel +++ b/beacon-chain/rpc/prysm/validator/BUILD.bazel @@ -13,11 +13,13 @@ go_library( "//api/server/structs:go_default_library", "//beacon-chain/rpc/core:go_default_library", "//beacon-chain/rpc/eth/shared:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//consensus-types/primitives:go_default_library", "//network/httputil:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//time/slots:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_pkg_errors//:go_default_library", "@io_opencensus_go//trace:go_default_library", ], @@ -37,6 +39,7 @@ go_test( "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/db/testing:go_default_library", "//beacon-chain/rpc/core:go_default_library", + "//beacon-chain/rpc/testutil:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen/mock:go_default_library", @@ -51,6 +54,7 @@ go_test( "//testing/util:go_default_library", "//time/slots:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", ], ) diff --git a/beacon-chain/rpc/prysm/validator/handlers.go b/beacon-chain/rpc/prysm/validator/handlers.go index e08dbef42c1f..d018137742ae 100644 --- a/beacon-chain/rpc/prysm/validator/handlers.go +++ b/beacon-chain/rpc/prysm/validator/handlers.go @@ -3,9 +3,9 @@ package validator import ( "fmt" "net/http" - "strings" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/gorilla/mux" "github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared" @@ -23,34 +23,22 @@ func (s *Server) GetValidatorActiveSetChanges(w http.ResponseWriter, r *http.Req ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorActiveSetChanges") defer span.End() - stateId := strings.ReplaceAll(r.URL.Query().Get("state_id"), " ", "") - var epoch uint64 - switch stateId { - case "head": - e, err := s.CoreService.ChainInfoFetcher.ReceivedBlocksLastEpoch() - if err != nil { - httputil.HandleError(w, "Could not retrieve head root: "+err.Error(), http.StatusInternalServerError) - return - } - epoch = e - case "finalized": - finalized := s.CoreService.ChainInfoFetcher.FinalizedCheckpt() - epoch = uint64(finalized.Epoch) - case "genesis": - epoch = 0 - default: - _, e, ok := shared.UintFromQuery(w, r, "epoch", true) - if !ok { - currentSlot := s.CoreService.GenesisTimeFetcher.CurrentSlot() - currentEpoch := slots.ToEpoch(currentSlot) - epoch = uint64(currentEpoch) - } else { - epoch = e - } + stateId := mux.Vars(r)["state_id"] + if stateId == "" { + httputil.HandleError(w, "state_id is required in URL params", http.StatusBadRequest) + return } - as, err := s.CoreService.ValidatorActiveSetChanges(ctx, primitives.Epoch(epoch)) + + st, err := s.Stater.State(ctx, []byte(stateId)) if err != nil { - httputil.HandleError(w, err.Err.Error(), core.ErrorReasonToHTTP(err.Reason)) + shared.WriteStateFetchError(w, err) + return + } + stEpoch := slots.ToEpoch(st.Slot()) + + as, rpcError := s.CoreService.ValidatorActiveSetChanges(ctx, stEpoch) + if rpcError != nil { + httputil.HandleError(w, rpcError.Err.Error(), core.ErrorReasonToHTTP(rpcError.Reason)) return } diff --git a/beacon-chain/rpc/prysm/validator/handlers_test.go b/beacon-chain/rpc/prysm/validator/handlers_test.go index e50f5f5b040c..73b1f3275167 100644 --- a/beacon-chain/rpc/prysm/validator/handlers_test.go +++ b/beacon-chain/rpc/prysm/validator/handlers_test.go @@ -12,10 +12,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/gorilla/mux" "github.com/prysmaticlabs/prysm/v5/api/server/structs" mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing" dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/testutil" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen" mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" @@ -33,12 +36,15 @@ func addDefaultReplayerBuilder(s *Server, h stategen.HistoryAccessor) { s.CoreService.ReplayerBuilder = stategen.NewCanonicalHistory(h, cc, cs) } -func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing.T) { +func TestServer_GetValidatorActiveSetChanges_NoState(t *testing.T) { beaconDB := dbTest.SetupDB(t) - st, err := util.NewBeaconState() - require.NoError(t, err) - require.NoError(t, st.SetSlot(0)) + var st state.BeaconState + st, _ = util.DeterministicGenesisState(t, 4) + s := &Server{ + Stater: &testutil.MockStater{ + BeaconState: st, + }, CoreService: &core.Service{ BeaconDB: beaconDB, GenesisTimeFetcher: &mock.ChainService{}, @@ -48,14 +54,15 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing }, } - url := "http://example.com?epoch=0" + fmt.Sprintf("%d", slots.ToEpoch(s.CoreService.GenesisTimeFetcher.CurrentSlot())+1) + url := "http://example.com" + fmt.Sprintf("%d", slots.ToEpoch(s.CoreService.GenesisTimeFetcher.CurrentSlot())+1) request := httptest.NewRequest(http.MethodGet, url, nil) + request = mux.SetURLVars(request, map[string]string{"state_id": ""}) writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} s.GetValidatorActiveSetChanges(writer, request) require.Equal(t, http.StatusBadRequest, writer.Code) - require.StringContains(t, "cannot retrieve information about an epoch in the future", writer.Body.String()) + require.StringContains(t, "state_id is required in URL params", writer.Body.String()) } func TestServer_GetValidatorActiveSetChanges(t *testing.T) { @@ -109,7 +116,12 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) { require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) + var st state.BeaconState + st, _ = util.DeterministicGenesisState(t, 4) s := &Server{ + Stater: &testutil.MockStater{ + BeaconState: st, + }, CoreService: &core.Service{ FinalizedFetcher: &mock.ChainService{ FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)}, @@ -119,8 +131,9 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) { } addDefaultReplayerBuilder(s, beaconDB) - url := "http://example.com?state_id=genesis" + url := "http://example.com" request := httptest.NewRequest(http.MethodGet, url, nil) + request = mux.SetURLVars(request, map[string]string{"state_id": "genesis"}) writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} diff --git a/beacon-chain/rpc/prysm/validator/server.go b/beacon-chain/rpc/prysm/validator/server.go index f8729417aab2..67e943c6f9f2 100644 --- a/beacon-chain/rpc/prysm/validator/server.go +++ b/beacon-chain/rpc/prysm/validator/server.go @@ -2,8 +2,10 @@ package validator import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/lookup" ) type Server struct { + Stater lookup.Stater CoreService *core.Service } From 30eafa93f7c48a8143a68f250fcd4847107219f2 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Mon, 5 Aug 2024 12:54:21 +0200 Subject: [PATCH 6/8] fix merge conflict errors --- beacon-chain/rpc/endpoints.go | 8 ++++---- beacon-chain/rpc/endpoints_test.go | 8 ++++---- beacon-chain/rpc/prysm/validator/handlers.go | 4 ++-- beacon-chain/rpc/prysm/validator/handlers_test.go | 5 ++++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index cc8360620c1c..d928dc0e4cca 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -1098,7 +1098,7 @@ func (s *Service) prysmValidatorEndpoints(stater lookup.Stater, coreService *cor handler: server.GetValidatorPerformance, methods: []string{http.MethodPost}, }, - { + { template: "/prysm/v1/validators/participation", name: namespace + ".GetValidatorParticipation", middleware: []mux.MiddlewareFunc{ @@ -1107,14 +1107,14 @@ func (s *Service) prysmValidatorEndpoints(stater lookup.Stater, coreService *cor handler: server.GetValidatorParticipation, methods: []string{http.MethodGet}, }, - { + { template: "/prysm/v1/validators/active_set_changes", name: namespace + ".GetValidatorActiveSetChanges", middleware: []mux.MiddlewareFunc{ middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, handler: server.GetValidatorActiveSetChanges, - methods: []string{http.MethodGet}, - }, + methods: []string{http.MethodGet}, + }, } } diff --git a/beacon-chain/rpc/endpoints_test.go b/beacon-chain/rpc/endpoints_test.go index 841bffe0ff05..6b7799303f31 100644 --- a/beacon-chain/rpc/endpoints_test.go +++ b/beacon-chain/rpc/endpoints_test.go @@ -125,10 +125,10 @@ func Test_endpoints(t *testing.T) { } prysmValidatorRoutes := map[string][]string{ - "/prysm/validators/performance": {http.MethodPost}, - "/prysm/v1/validators/performance": {http.MethodPost}, - "/prysm/v1/validators/participation": {http.MethodGet}, - "/prysm/v1/validators/active_set_changes": {http.MethodGet}, + "/prysm/validators/performance": {http.MethodPost}, + "/prysm/v1/validators/performance": {http.MethodPost}, + "/prysm/v1/validators/participation": {http.MethodGet}, + "/prysm/v1/validators/active_set_changes": {http.MethodGet}, } s := &Service{cfg: &Config{}} diff --git a/beacon-chain/rpc/prysm/validator/handlers.go b/beacon-chain/rpc/prysm/validator/handlers.go index 4e0ce15d5390..8e54bc47248e 100644 --- a/beacon-chain/rpc/prysm/validator/handlers.go +++ b/beacon-chain/rpc/prysm/validator/handlers.go @@ -4,12 +4,12 @@ import ( "fmt" "net/http" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/gorilla/mux" "github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared" - "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/network/httputil" "github.com/prysmaticlabs/prysm/v5/time/slots" "go.opencensus.io/trace" diff --git a/beacon-chain/rpc/prysm/validator/handlers_test.go b/beacon-chain/rpc/prysm/validator/handlers_test.go index 132a075500ee..10934e6dbcee 100644 --- a/beacon-chain/rpc/prysm/validator/handlers_test.go +++ b/beacon-chain/rpc/prysm/validator/handlers_test.go @@ -3,6 +3,7 @@ package validator import ( "bytes" "context" + "encoding/binary" "encoding/json" "fmt" "math" @@ -11,6 +12,7 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/gorilla/mux" "github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/prysm/v5/api/server/structs" @@ -25,10 +27,12 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen" mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" blocktest "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks/testing" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/testing/assert" @@ -552,4 +556,3 @@ func pubKey(i uint64) []byte { binary.LittleEndian.PutUint64(pubKey, i) return pubKey } - From 505b230f74c385cb9b81a1df57b3471ba5a4e9d9 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Mon, 5 Aug 2024 13:04:29 +0200 Subject: [PATCH 7/8] remove validator from func names --- beacon-chain/rpc/endpoints.go | 16 ++++++++-------- beacon-chain/rpc/prysm/validator/handlers.go | 12 ++++++------ .../rpc/prysm/validator/handlers_test.go | 12 ++++++------ .../rpc/prysm/validator/validator_performance.go | 6 +++--- .../validator/validator_performance_test.go | 14 +++++++------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index d928dc0e4cca..9a67d2d8f38c 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -1080,40 +1080,40 @@ func (s *Service) prysmValidatorEndpoints(stater lookup.Stater, coreService *cor return []endpoint{ { template: "/prysm/validators/performance", - name: namespace + ".GetValidatorPerformance", + name: namespace + ".GetPerformance", middleware: []mux.MiddlewareFunc{ middleware.ContentTypeHandler([]string{api.JsonMediaType}), middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, - handler: server.GetValidatorPerformance, + handler: server.GetPerformance, methods: []string{http.MethodPost}, }, { template: "/prysm/v1/validators/performance", - name: namespace + ".GetValidatorPerformance", + name: namespace + ".GetPerformance", middleware: []mux.MiddlewareFunc{ middleware.ContentTypeHandler([]string{api.JsonMediaType}), middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, - handler: server.GetValidatorPerformance, + handler: server.GetPerformance, methods: []string{http.MethodPost}, }, { template: "/prysm/v1/validators/participation", - name: namespace + ".GetValidatorParticipation", + name: namespace + ".GetParticipation", middleware: []mux.MiddlewareFunc{ middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, - handler: server.GetValidatorParticipation, + handler: server.GetParticipation, methods: []string{http.MethodGet}, }, { template: "/prysm/v1/validators/active_set_changes", - name: namespace + ".GetValidatorActiveSetChanges", + name: namespace + ".GetActiveSetChanges", middleware: []mux.MiddlewareFunc{ middleware.AcceptHeaderHandler([]string{api.JsonMediaType}), }, - handler: server.GetValidatorActiveSetChanges, + handler: server.GetActiveSetChanges, methods: []string{http.MethodGet}, }, } diff --git a/beacon-chain/rpc/prysm/validator/handlers.go b/beacon-chain/rpc/prysm/validator/handlers.go index 8e54bc47248e..95f162e40413 100644 --- a/beacon-chain/rpc/prysm/validator/handlers.go +++ b/beacon-chain/rpc/prysm/validator/handlers.go @@ -15,11 +15,11 @@ import ( "go.opencensus.io/trace" ) -// GetValidatorParticipation retrieves the validator participation information for a given epoch, +// GetParticipation retrieves the validator participation information for a given epoch, // it returns the information about validator's participation rate in voting on the proof of stake // rules based on their balance compared to the total active validator balance. -func (s *Server) GetValidatorParticipation(w http.ResponseWriter, r *http.Request) { - ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorParticipation") +func (s *Server) GetParticipation(w http.ResponseWriter, r *http.Request) { + ctx, span := trace.StartSpan(r.Context(), "validator.GetParticipation") defer span.End() stateId := mux.Vars(r)["state_id"] @@ -59,12 +59,12 @@ func (s *Server) GetValidatorParticipation(w http.ResponseWriter, r *http.Reques httputil.WriteJson(w, response) } -// GetValidatorActiveSetChanges retrieves the active set changes for a given epoch. +// GetActiveSetChanges retrieves the active set changes for a given epoch. // // This data includes any activations, voluntary exits, and involuntary // ejections. -func (s *Server) GetValidatorActiveSetChanges(w http.ResponseWriter, r *http.Request) { - ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorActiveSetChanges") +func (s *Server) GetActiveSetChanges(w http.ResponseWriter, r *http.Request) { + ctx, span := trace.StartSpan(r.Context(), "validator.GetActiveSetChanges") defer span.End() stateId := mux.Vars(r)["state_id"] diff --git a/beacon-chain/rpc/prysm/validator/handlers_test.go b/beacon-chain/rpc/prysm/validator/handlers_test.go index 10934e6dbcee..9956926e54e9 100644 --- a/beacon-chain/rpc/prysm/validator/handlers_test.go +++ b/beacon-chain/rpc/prysm/validator/handlers_test.go @@ -73,7 +73,7 @@ func TestServer_GetValidatorParticipation_NoState(t *testing.T) { writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorParticipation(writer, request) + s.GetParticipation(writer, request) require.Equal(t, http.StatusBadRequest, writer.Code) require.StringContains(t, "state_id is required in URL params", writer.Body.String()) } @@ -154,7 +154,7 @@ func TestServer_GetValidatorParticipation_CurrentAndPrevEpoch(t *testing.T) { writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorParticipation(writer, request) + s.GetParticipation(writer, request) assert.Equal(t, http.StatusOK, writer.Code) want := &structs.GetValidatorParticipationResponse{ @@ -254,7 +254,7 @@ func TestServer_GetValidatorParticipation_OrphanedUntilGenesis(t *testing.T) { writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorParticipation(writer, request) + s.GetParticipation(writer, request) assert.Equal(t, http.StatusOK, writer.Code) want := &structs.GetValidatorParticipationResponse{ @@ -384,7 +384,7 @@ func runGetValidatorParticipationCurrentEpoch(t *testing.T, genState state.Beaco writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorParticipation(writer, request) + s.GetParticipation(writer, request) assert.Equal(t, http.StatusOK, writer.Code) want := &structs.GetValidatorParticipationResponse{ @@ -434,7 +434,7 @@ func TestServer_GetValidatorActiveSetChanges_NoState(t *testing.T) { writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorActiveSetChanges(writer, request) + s.GetActiveSetChanges(writer, request) require.Equal(t, http.StatusBadRequest, writer.Code) require.StringContains(t, "state_id is required in URL params", writer.Body.String()) } @@ -511,7 +511,7 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) { writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} - s.GetValidatorActiveSetChanges(writer, request) + s.GetActiveSetChanges(writer, request) require.Equal(t, http.StatusOK, writer.Code) wantedActive := []string{ diff --git a/beacon-chain/rpc/prysm/validator/validator_performance.go b/beacon-chain/rpc/prysm/validator/validator_performance.go index 2af8d00414e1..faa8325a78b9 100644 --- a/beacon-chain/rpc/prysm/validator/validator_performance.go +++ b/beacon-chain/rpc/prysm/validator/validator_performance.go @@ -13,9 +13,9 @@ import ( "go.opencensus.io/trace" ) -// GetValidatorPerformance is an HTTP handler for GetValidatorPerformance. -func (s *Server) GetValidatorPerformance(w http.ResponseWriter, r *http.Request) { - ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorPerformance") +// GetPerformance is an HTTP handler for GetPerformance. +func (s *Server) GetPerformance(w http.ResponseWriter, r *http.Request) { + ctx, span := trace.StartSpan(r.Context(), "validator.GetPerformance") defer span.End() var req structs.GetValidatorPerformanceRequest diff --git a/beacon-chain/rpc/prysm/validator/validator_performance_test.go b/beacon-chain/rpc/prysm/validator/validator_performance_test.go index 379f5669a9d0..903734e4af5c 100644 --- a/beacon-chain/rpc/prysm/validator/validator_performance_test.go +++ b/beacon-chain/rpc/prysm/validator/validator_performance_test.go @@ -35,7 +35,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { }, } - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", nil) client := &http.Client{} @@ -86,7 +86,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err = json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) @@ -151,7 +151,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err = json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) @@ -216,7 +216,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err = json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) @@ -278,7 +278,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err := json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) @@ -340,7 +340,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err := json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) @@ -402,7 +402,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) { err := json.NewEncoder(&buf).Encode(request) require.NoError(t, err) - srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance)) + srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance)) req := httptest.NewRequest("POST", "/foo", &buf) client := &http.Client{} rawResp, err := client.Post(srv.URL, "application/json", req.Body) From b7cbaa9c2c8b14cd864488329c884b9db0cea901 Mon Sep 17 00:00:00 2001 From: Saolyn Date: Mon, 5 Aug 2024 13:07:14 +0200 Subject: [PATCH 8/8] rename util funcs --- beacon-chain/rpc/prysm/validator/handlers.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/beacon-chain/rpc/prysm/validator/handlers.go b/beacon-chain/rpc/prysm/validator/handlers.go index 95f162e40413..4c48a8708876 100644 --- a/beacon-chain/rpc/prysm/validator/handlers.go +++ b/beacon-chain/rpc/prysm/validator/handlers.go @@ -88,19 +88,19 @@ func (s *Server) GetActiveSetChanges(w http.ResponseWriter, r *http.Request) { response := &structs.ActiveSetChanges{ Epoch: fmt.Sprintf("%d", as.Epoch), - ActivatedPublicKeys: byteArrayToString(as.ActivatedPublicKeys), - ActivatedIndices: uint64ArrayToString(as.ActivatedIndices), - ExitedPublicKeys: byteArrayToString(as.ExitedPublicKeys), - ExitedIndices: uint64ArrayToString(as.ExitedIndices), - SlashedPublicKeys: byteArrayToString(as.SlashedPublicKeys), - SlashedIndices: uint64ArrayToString(as.SlashedIndices), - EjectedPublicKeys: byteArrayToString(as.EjectedPublicKeys), - EjectedIndices: uint64ArrayToString(as.EjectedIndices), + ActivatedPublicKeys: byteSlice2dToStringSlice(as.ActivatedPublicKeys), + ActivatedIndices: uint64SliceToStringSlice(as.ActivatedIndices), + ExitedPublicKeys: byteSlice2dToStringSlice(as.ExitedPublicKeys), + ExitedIndices: uint64SliceToStringSlice(as.ExitedIndices), + SlashedPublicKeys: byteSlice2dToStringSlice(as.SlashedPublicKeys), + SlashedIndices: uint64SliceToStringSlice(as.SlashedIndices), + EjectedPublicKeys: byteSlice2dToStringSlice(as.EjectedPublicKeys), + EjectedIndices: uint64SliceToStringSlice(as.EjectedIndices), } httputil.WriteJson(w, response) } -func byteArrayToString(byteArrays [][]byte) []string { +func byteSlice2dToStringSlice(byteArrays [][]byte) []string { s := make([]string, len(byteArrays)) for i, b := range byteArrays { s[i] = hexutil.Encode(b) @@ -108,7 +108,7 @@ func byteArrayToString(byteArrays [][]byte) []string { return s } -func uint64ArrayToString(indices []primitives.ValidatorIndex) []string { +func uint64SliceToStringSlice(indices []primitives.ValidatorIndex) []string { s := make([]string, len(indices)) for i, u := range indices { s[i] = fmt.Sprintf("%d", u)