Skip to content

Commit

Permalink
Add validatorStates filter to Validators
Browse files Browse the repository at this point in the history
  • Loading branch information
cihati committed Sep 30, 2023
1 parent aa7c91d commit 6aa422c
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 12 deletions.
21 changes: 17 additions & 4 deletions http/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"strings"

api "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 22 in http/validators.go

View workflow job for this annotation

GitHub Actions / lint

ST1019: package "github.com/attestantio/go-eth2-client/api/v1" is being imported more than once (stylecheck)
v1 "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 23 in http/validators.go

View workflow job for this annotation

GitHub Actions / lint

ST1019(related information): other import of "github.com/attestantio/go-eth2-client/api/v1" (stylecheck)
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -70,7 +71,8 @@ func (s *Service) indexChunkSize(ctx context.Context) int {
// Validators provides the validators, with their balance and status, for a given state.
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
// validatorIndices is a list of validators to restrict the returned values. If no validators are supplied no filter will be applied.
func (s *Service) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex) (map[phase0.ValidatorIndex]*api.Validator, error) {
// validatorStates is a list of validator states to restrict the returned values. If no states are supplied no filter will be applied.
func (s *Service) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex, validatorStates []v1.ValidatorState) (map[phase0.ValidatorIndex]*api.Validator, error) {
if stateID == "" {
return nil, errors.New("no state ID specified")
}
Expand All @@ -80,7 +82,7 @@ func (s *Service) Validators(ctx context.Context, stateID string, validatorIndic
}

if len(validatorIndices) > s.indexChunkSize(ctx) {
return s.chunkedValidators(ctx, stateID, validatorIndices)
return s.chunkedValidators(ctx, stateID, validatorIndices, validatorStates)
}

url := fmt.Sprintf("/eth/v1/beacon/states/%s/validators", stateID)
Expand All @@ -91,6 +93,17 @@ func (s *Service) Validators(ctx context.Context, stateID string, validatorIndic
}
url = fmt.Sprintf("%s?id=%s", url, strings.Join(ids, ","))
}
if len(validatorStates) != 0 {
states := make([]string, len(validatorStates))
for i := range validatorStates {
states[i] = fmt.Sprintf("%s", validatorStates[i])

Check failure on line 99 in http/validators.go

View workflow job for this annotation

GitHub Actions / lint

S1025: should use String() instead of fmt.Sprintf (gosimple)
}
if len(validatorIndices) != 0 {
url = fmt.Sprintf("%s&status=%s", url, strings.Join(states, ","))
} else {
url = fmt.Sprintf("%s?status=%s", url, strings.Join(states, ","))
}
}

respBodyReader, err := s.get(ctx, url)
if err != nil {
Expand Down Expand Up @@ -168,7 +181,7 @@ func (s *Service) validatorsFromState(ctx context.Context, stateID string) (map[
}

// chunkedValidators obtains the validators a chunk at a time.
func (s *Service) chunkedValidators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex) (map[phase0.ValidatorIndex]*api.Validator, error) {
func (s *Service) chunkedValidators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex, validatorStates []v1.ValidatorState) (map[phase0.ValidatorIndex]*api.Validator, error) {
res := make(map[phase0.ValidatorIndex]*api.Validator)
indexChunkSize := s.indexChunkSize(ctx)
for i := 0; i < len(validatorIndices); i += indexChunkSize {
Expand All @@ -178,7 +191,7 @@ func (s *Service) chunkedValidators(ctx context.Context, stateID string, validat
chunkEnd = len(validatorIndices)
}
chunk := validatorIndices[chunkStart:chunkEnd]
chunkRes, err := s.Validators(ctx, stateID, chunk)
chunkRes, err := s.Validators(ctx, stateID, chunk, validatorStates)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain chunk")
}
Expand Down
12 changes: 11 additions & 1 deletion http/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"

client "github.com/attestantio/go-eth2-client"
v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/http"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/stretchr/testify/require"
Expand All @@ -34,6 +35,7 @@ func TestValidators(t *testing.T) {
stateID string
expectedErrorCode int
validatorIndices []phase0.ValidatorIndex
validatorStates []v1.ValidatorState
}{
{
name: "Invalid",
Expand Down Expand Up @@ -61,6 +63,14 @@ func TestValidators(t *testing.T) {
name: "Justified",
stateID: "justified",
},
{
name: "SomeStates",
stateID: "head",
validatorStates: []v1.ValidatorState{
v1.ValidatorStateActiveOngoing,
v1.ValidatorStateExitedSlashed,
},
},
{
name: "ManyValidators",
stateID: "head",
Expand All @@ -78,7 +88,7 @@ func TestValidators(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
validators, err := service.(client.ValidatorsProvider).Validators(ctx, test.stateID, test.validatorIndices)
validators, err := service.(client.ValidatorsProvider).Validators(ctx, test.stateID, test.validatorIndices, test.validatorStates)
if test.expectedErrorCode != 0 {
require.Contains(t, err.Error(), fmt.Sprintf("%d", test.expectedErrorCode))
} else {
Expand Down
6 changes: 5 additions & 1 deletion multi/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@ import (

consensusclient "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 20 in multi/validators.go

View workflow job for this annotation

GitHub Actions / lint

ST1019: package "github.com/attestantio/go-eth2-client/api/v1" is being imported more than once (stylecheck)
v1 "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 21 in multi/validators.go

View workflow job for this annotation

GitHub Actions / lint

ST1019(related information): other import of "github.com/attestantio/go-eth2-client/api/v1" (stylecheck)
"github.com/attestantio/go-eth2-client/spec/phase0"
)

// Validators provides the validators, with their balance and status, for a given state.
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
// validatorIndices is a list of validators to restrict the returned values. If no validators are supplied no filter will be applied.
// validatorStates is a list of validator states to restrict the returned values. If no validators states are supplied no filter
// will be applied.
func (s *Service) Validators(ctx context.Context,
stateID string,
validatorIndices []phase0.ValidatorIndex,
validatorStates []v1.ValidatorState,
) (
map[phase0.ValidatorIndex]*api.Validator,
error,
) {
res, err := s.doCall(ctx, func(ctx context.Context, client consensusclient.Service) (interface{}, error) {
block, err := client.(consensusclient.ValidatorsProvider).Validators(ctx, stateID, validatorIndices)
block, err := client.(consensusclient.ValidatorsProvider).Validators(ctx, stateID, validatorIndices, validatorStates)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion multi/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"testing"

consensusclient "github.com/attestantio/go-eth2-client"
v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/mock"
"github.com/attestantio/go-eth2-client/multi"
"github.com/attestantio/go-eth2-client/spec/phase0"
Expand Down Expand Up @@ -51,7 +52,7 @@ func TestValidators(t *testing.T) {
require.NoError(t, err)

for i := 0; i < 128; i++ {
res, err := multiClient.(consensusclient.ValidatorsProvider).Validators(ctx, "1", []phase0.ValidatorIndex{})
res, err := multiClient.(consensusclient.ValidatorsProvider).Validators(ctx, "1", []phase0.ValidatorIndex{}, []v1.ValidatorState{})
require.NoError(t, err)
require.NotNil(t, res)
}
Expand Down
5 changes: 4 additions & 1 deletion service.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

api "github.com/attestantio/go-eth2-client/api"
apiv1 "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 21 in service.go

View workflow job for this annotation

GitHub Actions / lint

ST1019: package "github.com/attestantio/go-eth2-client/api/v1" is being imported more than once (stylecheck)
v1 "github.com/attestantio/go-eth2-client/api/v1"

Check failure on line 22 in service.go

View workflow job for this annotation

GitHub Actions / lint

ST1019(related information): other import of "github.com/attestantio/go-eth2-client/api/v1" (stylecheck)
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/altair"
"github.com/attestantio/go-eth2-client/spec/capella"
Expand Down Expand Up @@ -368,7 +369,9 @@ type ValidatorsProvider interface {
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
// validatorIndices is a list of validator indices to restrict the returned values. If no validators IDs are supplied no filter
// will be applied.
Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex) (map[phase0.ValidatorIndex]*apiv1.Validator, error)
// validatorStates is a list of validator states to restrict the returned values. If no validators states are supplied no filter
// will be applied.
Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex, validatorStates []v1.ValidatorState) (map[phase0.ValidatorIndex]*apiv1.Validator, error)

// ValidatorsByPubKey provides the validators, with their balance and status, for a given state.
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
Expand Down
7 changes: 5 additions & 2 deletions testclients/erroring.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
consensusclient "github.com/attestantio/go-eth2-client"
"github.com/attestantio/go-eth2-client/api"
apiv1 "github.com/attestantio/go-eth2-client/api/v1"
v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/altair"
"github.com/attestantio/go-eth2-client/spec/deneb"
Expand Down Expand Up @@ -580,15 +581,17 @@ func (s *Erroring) ValidatorBalances(ctx context.Context, stateID string, valida
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
// validatorIndices is a list of validator indices to restrict the returned values. If no validators IDs are supplied no filter
// will be applied.
func (s *Erroring) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex) (map[phase0.ValidatorIndex]*apiv1.Validator, error) {
// validatorStates is a list of validator states to restrict the returned values. If no validators states are supplied no filter
// will be applied.
func (s *Erroring) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex, validatorStates []v1.ValidatorState) (map[phase0.ValidatorIndex]*apiv1.Validator, error) {
if err := s.maybeError(ctx); err != nil {
return nil, err
}
next, isNext := s.next.(consensusclient.ValidatorsProvider)
if !isNext {
return nil, fmt.Errorf("%s@%s does not support this call", s.next.Name(), s.next.Address())
}
return next.Validators(ctx, stateID, validatorIndices)
return next.Validators(ctx, stateID, validatorIndices, validatorStates)
}

// ValidatorsByPubKey provides the validators, with their balance and status, for a given state.
Expand Down
7 changes: 5 additions & 2 deletions testclients/sleepy.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
consensusclient "github.com/attestantio/go-eth2-client"
"github.com/attestantio/go-eth2-client/api"
apiv1 "github.com/attestantio/go-eth2-client/api/v1"
v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/deneb"
"github.com/attestantio/go-eth2-client/spec/phase0"
Expand Down Expand Up @@ -395,13 +396,15 @@ func (s *Sleepy) ValidatorBalances(ctx context.Context, stateID string, validato
// stateID can be a slot number or state root, or one of the special values "genesis", "head", "justified" or "finalized".
// validatorIndices is a list of validator indices to restrict the returned values. If no validators IDs are supplied no filter
// will be applied.
func (s *Sleepy) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex) (map[phase0.ValidatorIndex]*apiv1.Validator, error) {
// validatorStates is a list of validator states to restrict the returned values. If no validators states are supplied no filter
// will be applied.
func (s *Sleepy) Validators(ctx context.Context, stateID string, validatorIndices []phase0.ValidatorIndex, validatorStates []v1.ValidatorState) (map[phase0.ValidatorIndex]*apiv1.Validator, error) {
s.sleep(ctx)
next, isNext := s.next.(consensusclient.ValidatorsProvider)
if !isNext {
return nil, errors.New("next does not support this call")
}
return next.Validators(ctx, stateID, validatorIndices)
return next.Validators(ctx, stateID, validatorIndices, validatorStates)
}

// ValidatorsByPubKey provides the validators, with their balance and status, for a given state.
Expand Down

0 comments on commit 6aa422c

Please sign in to comment.