mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Add REST implementation for MultipleValidatorStatus
(#11786)
* Add REST implementation for `MultipleValidatorStatus` * Fix PR comments * Address PR comments Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
This commit is contained in:
parent
51601716dc
commit
e1408deb40
@ -69,11 +69,12 @@ goimports -w "$mock_path/."
|
||||
gofmt -s -w "$mock_path/."
|
||||
|
||||
# github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api
|
||||
# --------------------------------------------------------
|
||||
# -------------------------------------------------------------
|
||||
beacon_api_mock_path="validator/client/beacon-api/mock"
|
||||
beacon_api_mocks=(
|
||||
"$beacon_api_mock_path/genesis_mock.go genesis.go"
|
||||
"$beacon_api_mock_path/json_rest_handler_mock.go json_rest_handler.go"
|
||||
"$beacon_api_mock_path/state_validators_mock.go state_validators.go"
|
||||
)
|
||||
|
||||
for ((i = 0; i < ${#beacon_api_mocks[@]}; i++)); do
|
||||
|
@ -69,7 +69,7 @@ func (c *waitForActivationClient) Recv() (*ethpb.ValidatorActivationResponse, er
|
||||
stringTargetPubKeys[index] = stringPubKey
|
||||
}
|
||||
|
||||
stateValidators, err := c.beaconApiValidatorClient.getStateValidators(stringTargetPubKeys, nil)
|
||||
stateValidators, err := c.stateValidatorsProvider.GetStateValidators(stringTargetPubKeys, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get state validators")
|
||||
}
|
||||
|
@ -147,7 +147,11 @@ func TestActivation_Nominal(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
@ -245,7 +249,11 @@ func TestActivation_InvalidData(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
waitForActivation, err := validatorClient.WaitForActivation(
|
||||
context.Background(),
|
||||
@ -274,7 +282,11 @@ func TestActivation_JsonResponseError(t *testing.T) {
|
||||
errors.New("some specific json error"),
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
waitForActivation, err := validatorClient.WaitForActivation(
|
||||
context.Background(),
|
||||
|
@ -14,9 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type beaconApiValidatorClient struct {
|
||||
genesisProvider genesisProvider
|
||||
jsonRestHandler jsonRestHandler
|
||||
fallbackClient iface.ValidatorClient
|
||||
genesisProvider genesisProvider
|
||||
stateValidatorsProvider stateValidatorsProvider
|
||||
jsonRestHandler jsonRestHandler
|
||||
fallbackClient iface.ValidatorClient
|
||||
}
|
||||
|
||||
func NewBeaconApiValidatorClient(host string, timeout time.Duration) iface.ValidatorClient {
|
||||
@ -30,9 +31,10 @@ func NewBeaconApiValidatorClientWithFallback(host string, timeout time.Duration,
|
||||
}
|
||||
|
||||
return &beaconApiValidatorClient{
|
||||
genesisProvider: beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
genesisProvider: beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{jsonRestHandler: jsonRestHandler},
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,13 +113,8 @@ func (c *beaconApiValidatorClient) GetSyncSubcommitteeIndex(ctx context.Context,
|
||||
panic("beaconApiValidatorClient.GetSyncSubcommitteeIndex is not implemented. To use a fallback client, create this validator with NewBeaconApiValidatorClientWithFallback instead.")
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) MultipleValidatorStatus(ctx context.Context, in *ethpb.MultipleValidatorStatusRequest) (*ethpb.MultipleValidatorStatusResponse, error) {
|
||||
if c.fallbackClient != nil {
|
||||
return c.fallbackClient.MultipleValidatorStatus(ctx, in)
|
||||
}
|
||||
|
||||
// TODO: Implement me
|
||||
panic("beaconApiValidatorClient.MultipleValidatorStatus is not implemented. To use a fallback client, create this validator with NewBeaconApiValidatorClientWithFallback instead.")
|
||||
func (c *beaconApiValidatorClient) MultipleValidatorStatus(_ context.Context, in *ethpb.MultipleValidatorStatusRequest) (*ethpb.MultipleValidatorStatusResponse, error) {
|
||||
return c.multipleValidatorStatus(in)
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) PrepareBeaconProposer(_ context.Context, in *ethpb.PrepareBeaconProposerRequest) (*empty.Empty, error) {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
func (c beaconApiValidatorClient) validatorIndex(in *ethpb.ValidatorIndexRequest) (*ethpb.ValidatorIndexResponse, error) {
|
||||
stringPubKey := hexutil.Encode(in.PublicKey)
|
||||
|
||||
stateValidator, err := c.getStateValidators([]string{stringPubKey}, nil)
|
||||
stateValidator, err := c.stateValidatorsProvider.GetStateValidators([]string{stringPubKey}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get state validator")
|
||||
}
|
||||
|
@ -58,7 +58,11 @@ func TestIndex_Nominal(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
validatorIndex, err := validatorClient.ValidatorIndex(
|
||||
context.Background(),
|
||||
@ -93,7 +97,11 @@ func TestIndex_UnexistingValidator(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := validatorClient.ValidatorIndex(
|
||||
context.Background(),
|
||||
@ -136,7 +144,11 @@ func TestIndex_BadIndexError(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := validatorClient.ValidatorIndex(
|
||||
context.Background(),
|
||||
@ -165,7 +177,11 @@ func TestIndex_JsonResponseError(t *testing.T) {
|
||||
errors.New("some specific json error"),
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{
|
||||
stateValidatorsProvider: beaconApiStateValidatorsProvider{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := validatorClient.ValidatorIndex(
|
||||
context.Background(),
|
||||
|
@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"genesis_mock.go",
|
||||
"json_rest_handler_mock.go",
|
||||
"state_validators_mock.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock",
|
||||
visibility = ["//visibility:public"],
|
||||
|
50
validator/client/beacon-api/mock/state_validators_mock.go
generated
Normal file
50
validator/client/beacon-api/mock/state_validators_mock.go
generated
Normal file
@ -0,0 +1,50 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: validator/client/beacon-api/state_validators.go
|
||||
|
||||
// Package mock is a generated GoMock package.
|
||||
package mock
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
apimiddleware "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
)
|
||||
|
||||
// MockstateValidatorsProvider is a mock of stateValidatorsProvider interface.
|
||||
type MockstateValidatorsProvider struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockstateValidatorsProviderMockRecorder
|
||||
}
|
||||
|
||||
// MockstateValidatorsProviderMockRecorder is the mock recorder for MockstateValidatorsProvider.
|
||||
type MockstateValidatorsProviderMockRecorder struct {
|
||||
mock *MockstateValidatorsProvider
|
||||
}
|
||||
|
||||
// NewMockstateValidatorsProvider creates a new mock instance.
|
||||
func NewMockstateValidatorsProvider(ctrl *gomock.Controller) *MockstateValidatorsProvider {
|
||||
mock := &MockstateValidatorsProvider{ctrl: ctrl}
|
||||
mock.recorder = &MockstateValidatorsProviderMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockstateValidatorsProvider) EXPECT() *MockstateValidatorsProviderMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetStateValidators mocks base method.
|
||||
func (m *MockstateValidatorsProvider) GetStateValidators(arg0 []string, arg1 []int64, arg2 []string) (*apimiddleware.StateValidatorsResponseJson, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetStateValidators", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*apimiddleware.StateValidatorsResponseJson)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetStateValidators indicates an expected call of GetStateValidators.
|
||||
func (mr *MockstateValidatorsProviderMockRecorder) GetStateValidators(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStateValidators", reflect.TypeOf((*MockstateValidatorsProvider)(nil).GetStateValidators), arg0, arg1, arg2)
|
||||
}
|
@ -2,19 +2,42 @@ package beacon_api
|
||||
|
||||
import (
|
||||
neturl "net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
rpcmiddleware "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
)
|
||||
|
||||
func (c *beaconApiValidatorClient) getStateValidators(
|
||||
type stateValidatorsProvider interface {
|
||||
GetStateValidators([]string, []int64, []string) (*rpcmiddleware.StateValidatorsResponseJson, error)
|
||||
}
|
||||
|
||||
type beaconApiStateValidatorsProvider struct {
|
||||
jsonRestHandler jsonRestHandler
|
||||
}
|
||||
|
||||
func (c beaconApiStateValidatorsProvider) GetStateValidators(
|
||||
stringPubkeys []string,
|
||||
indexes []int64,
|
||||
statuses []string,
|
||||
) (*rpcmiddleware.StateValidatorsResponseJson, error) {
|
||||
params := neturl.Values{}
|
||||
|
||||
stringPubKeysSet := make(map[string]struct{}, len(stringPubkeys))
|
||||
indexesSet := make(map[int64]struct{}, len(indexes))
|
||||
|
||||
for _, stringPubkey := range stringPubkeys {
|
||||
params.Add("id", stringPubkey)
|
||||
if _, ok := stringPubKeysSet[stringPubkey]; !ok {
|
||||
stringPubKeysSet[stringPubkey] = struct{}{}
|
||||
params.Add("id", stringPubkey)
|
||||
}
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
if _, ok := indexesSet[index]; !ok {
|
||||
indexesSet[index] = struct{}{}
|
||||
params.Add("id", strconv.FormatInt(index, 10))
|
||||
}
|
||||
}
|
||||
|
||||
for _, status := range statuses {
|
||||
@ -30,11 +53,11 @@ func (c *beaconApiValidatorClient) getStateValidators(
|
||||
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(url, stateValidatorsJson)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get json response")
|
||||
return &rpcmiddleware.StateValidatorsResponseJson{}, errors.Wrap(err, "failed to get json response")
|
||||
}
|
||||
|
||||
if stateValidatorsJson.Data == nil {
|
||||
return nil, errors.New("stateValidatorsJson.Data is nil")
|
||||
return &rpcmiddleware.StateValidatorsResponseJson{}, errors.New("stateValidatorsJson.Data is nil")
|
||||
}
|
||||
|
||||
return stateValidatorsJson, nil
|
||||
|
@ -22,6 +22,7 @@ func TestGetStateValidators_Nominal(t *testing.T) {
|
||||
"id=0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526&", // active_exiting
|
||||
"id=0x424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242&", // does not exist
|
||||
"id=0x800015473bdc3a7f45ef8eb8abc598bc20021e55ad6e6ad1d745aaef9730dd2c28ec08bf42df18451de94dd4a6d24ec5&", // exited_slashed
|
||||
"id=12345&", // active_ongoing
|
||||
"status=active_ongoing&status=active_exiting&status=exited_slashed&status=exited_unslashed",
|
||||
}, "")
|
||||
|
||||
@ -29,6 +30,13 @@ func TestGetStateValidators_Nominal(t *testing.T) {
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
|
||||
wanted := []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be19",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "55293",
|
||||
Status: "active_ongoing",
|
||||
@ -65,13 +73,18 @@ func TestGetStateValidators_Nominal(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
actual, err := validatorClient.getStateValidators([]string{
|
||||
stateValidatorsProvider := beaconApiStateValidatorsProvider{jsonRestHandler: jsonRestHandler}
|
||||
actual, err := stateValidatorsProvider.GetStateValidators([]string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // active_ongoing
|
||||
"0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526", // active_exiting
|
||||
"0x424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", // does not exist
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // active_ongoing - duplicate
|
||||
"0x800015473bdc3a7f45ef8eb8abc598bc20021e55ad6e6ad1d745aaef9730dd2c28ec08bf42df18451de94dd4a6d24ec5", // exited_slashed
|
||||
},
|
||||
[]int64{
|
||||
12345, // active_ongoing
|
||||
12345, // active_ongoing - duplicate
|
||||
},
|
||||
[]string{"active_ongoing", "active_exiting", "exited_slashed", "exited_unslashed"},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@ -95,11 +108,12 @@ func TestGetStateValidators_GetRestJsonResponseOnError(t *testing.T) {
|
||||
errors.New("an error"),
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.getStateValidators([]string{
|
||||
stateValidatorsProvider := beaconApiStateValidatorsProvider{jsonRestHandler: jsonRestHandler}
|
||||
_, err := stateValidatorsProvider.GetStateValidators([]string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // active_ongoing
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
assert.ErrorContains(t, "an error", err)
|
||||
assert.ErrorContains(t, "failed to get json response", err)
|
||||
@ -127,11 +141,12 @@ func TestGetStateValidators_DataIsNil(t *testing.T) {
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.getStateValidators([]string{
|
||||
stateValidatorsProvider := beaconApiStateValidatorsProvider{jsonRestHandler: jsonRestHandler}
|
||||
_, err := stateValidatorsProvider.GetStateValidators([]string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // active_ongoing
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
assert.ErrorContains(t, "stateValidatorsJson.Data is nil", err)
|
||||
}
|
||||
|
@ -11,69 +11,158 @@ import (
|
||||
)
|
||||
|
||||
func (c *beaconApiValidatorClient) validatorStatus(in *ethpb.ValidatorStatusRequest) (*ethpb.ValidatorStatusResponse, error) {
|
||||
stringPubKey := hexutil.Encode(in.PublicKey)
|
||||
|
||||
resp := ðpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
|
||||
stateValidator, err := c.getStateValidators([]string{stringPubKey}, nil)
|
||||
_, _, validatorsStatusResponse, err := c.getValidatorsStatusResponse([][]byte{in.PublicKey}, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get state validator")
|
||||
return nil, errors.Wrap(err, "failed to get validator status response")
|
||||
}
|
||||
|
||||
// If no data, the validator is in unknown status
|
||||
if len(stateValidator.Data) == 0 {
|
||||
return resp, nil
|
||||
if len(validatorsStatusResponse) != 1 {
|
||||
return nil, errors.New("number of validator status response not expected")
|
||||
}
|
||||
|
||||
validatorContainer := stateValidator.Data[0]
|
||||
validatorStatusResponse := validatorsStatusResponse[0]
|
||||
|
||||
// Set Status
|
||||
status, ok := beaconAPITogRPCValidatorStatus[validatorContainer.Status]
|
||||
if !ok {
|
||||
return nil, errors.New("invalid validator status: " + validatorContainer.Status)
|
||||
}
|
||||
return validatorStatusResponse, nil
|
||||
}
|
||||
|
||||
resp.Status = status
|
||||
|
||||
// Set activation epoch
|
||||
activationEpoch, err := strconv.ParseInt(validatorContainer.Validator.ActivationEpoch, 10, 64)
|
||||
func (c *beaconApiValidatorClient) multipleValidatorStatus(in *ethpb.MultipleValidatorStatusRequest) (*ethpb.MultipleValidatorStatusResponse, error) {
|
||||
publicKeys, indices, statuses, err := c.getValidatorsStatusResponse(in.PublicKeys, in.Indices)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse activation epoch")
|
||||
return nil, errors.Wrap(err, "failed to get validators status response")
|
||||
}
|
||||
|
||||
resp.ActivationEpoch = types.Epoch(activationEpoch)
|
||||
return ðpb.MultipleValidatorStatusResponse{
|
||||
PublicKeys: publicKeys,
|
||||
Indices: indices,
|
||||
Statuses: statuses,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Set PositionInActivationQueue
|
||||
switch status {
|
||||
case ethpb.ValidatorStatus_DEPOSITED, ethpb.ValidatorStatus_PENDING, ethpb.ValidatorStatus_PARTIALLY_DEPOSITED:
|
||||
validatorIndex, err := strconv.ParseUint(validatorContainer.Index, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse validator index")
|
||||
}
|
||||
func (c *beaconApiValidatorClient) getValidatorsStatusResponse(inPubKeys [][]byte, inIndexes []int64) (
|
||||
[][]byte,
|
||||
[]types.ValidatorIndex,
|
||||
[]*ethpb.ValidatorStatusResponse,
|
||||
error,
|
||||
) {
|
||||
// Represents the target set of keys
|
||||
stringTargetPubKeysToPubKeys := make(map[string][]byte, len(inPubKeys))
|
||||
stringTargetPubKeys := make([]string, len(inPubKeys))
|
||||
|
||||
activeStateValidators, err := c.getStateValidators(nil, []string{"active"})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get state validators")
|
||||
}
|
||||
// Represents the set of keys actually returned by the beacon node
|
||||
stringRetrievedPubKeys := make(map[string]struct{})
|
||||
|
||||
data := activeStateValidators.Data
|
||||
// Contains all keys in targetPubKeys but not in retrievedPubKeys
|
||||
missingPubKeys := [][]byte{}
|
||||
|
||||
var lastActivatedValidatorIndex uint64 = 0
|
||||
totalLen := len(inPubKeys) + len(inIndexes)
|
||||
|
||||
if nbActiveValidators := len(data); nbActiveValidators != 0 {
|
||||
lastValidator := data[nbActiveValidators-1]
|
||||
outPubKeys := make([][]byte, totalLen)
|
||||
outIndexes := make([]types.ValidatorIndex, totalLen)
|
||||
outValidatorsStatuses := make([]*ethpb.ValidatorStatusResponse, totalLen)
|
||||
|
||||
lastActivatedValidatorIndex, err = strconv.ParseUint(lastValidator.Index, 10, 64)
|
||||
for index, publicKey := range inPubKeys {
|
||||
stringPubKey := hexutil.Encode(publicKey)
|
||||
stringTargetPubKeysToPubKeys[stringPubKey] = publicKey
|
||||
stringTargetPubKeys[index] = stringPubKey
|
||||
}
|
||||
|
||||
// Get state for the current validator
|
||||
stateValidatorsResponse, err := c.stateValidatorsProvider.GetStateValidators(stringTargetPubKeys, inIndexes, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "failed to get state validators")
|
||||
}
|
||||
|
||||
isLastActivatedValidatorIndexRetrieved := false
|
||||
var lastActivatedValidatorIndex uint64 = 0
|
||||
|
||||
for i, validatorContainer := range stateValidatorsResponse.Data {
|
||||
stringPubKey := validatorContainer.Validator.PublicKey
|
||||
|
||||
stringRetrievedPubKeys[stringPubKey] = struct{}{}
|
||||
|
||||
pubKey, ok := stringTargetPubKeysToPubKeys[stringPubKey]
|
||||
if !ok {
|
||||
// string pub key is not already known because the index was used for this validator
|
||||
pubKey, err = hexutil.Decode(stringPubKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse last validator index")
|
||||
return nil, nil, nil, errors.Wrapf(err, "failed to parse validator public key %s", stringPubKey)
|
||||
}
|
||||
}
|
||||
|
||||
resp.PositionInActivationQueue = validatorIndex - lastActivatedValidatorIndex
|
||||
validatorIndex, err := strconv.ParseUint(validatorContainer.Index, 10, 64)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrapf(err, "failed to parse validator index %s", validatorContainer.Index)
|
||||
}
|
||||
|
||||
outPubKeys[i] = pubKey
|
||||
outIndexes[i] = types.ValidatorIndex(validatorIndex)
|
||||
|
||||
validatorStatus := ðpb.ValidatorStatusResponse{}
|
||||
|
||||
// Set Status
|
||||
status, ok := beaconAPITogRPCValidatorStatus[validatorContainer.Status]
|
||||
if !ok {
|
||||
return nil, nil, nil, errors.New("invalid validator status " + validatorContainer.Status)
|
||||
}
|
||||
|
||||
validatorStatus.Status = status
|
||||
|
||||
// Set activation epoch
|
||||
activationEpoch, err := strconv.ParseUint(validatorContainer.Validator.ActivationEpoch, 10, 64)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrapf(err, "failed to parse activation epoch %s", validatorContainer.Validator.ActivationEpoch)
|
||||
}
|
||||
|
||||
validatorStatus.ActivationEpoch = types.Epoch(activationEpoch)
|
||||
|
||||
// Set PositionInActivationQueue
|
||||
switch status {
|
||||
case ethpb.ValidatorStatus_PENDING, ethpb.ValidatorStatus_PARTIALLY_DEPOSITED, ethpb.ValidatorStatus_DEPOSITED:
|
||||
if !isLastActivatedValidatorIndexRetrieved {
|
||||
isLastActivatedValidatorIndexRetrieved = true
|
||||
|
||||
activeStateValidators, err := c.stateValidatorsProvider.GetStateValidators(nil, nil, []string{"active"})
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "failed to get state validators")
|
||||
}
|
||||
|
||||
data := activeStateValidators.Data
|
||||
|
||||
if nbActiveValidators := len(data); nbActiveValidators != 0 {
|
||||
lastValidator := data[nbActiveValidators-1]
|
||||
|
||||
lastActivatedValidatorIndex, err = strconv.ParseUint(lastValidator.Index, 10, 64)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrapf(err, "failed to parse last validator index %s", lastValidator.Index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validatorStatus.PositionInActivationQueue = validatorIndex - lastActivatedValidatorIndex
|
||||
}
|
||||
|
||||
outValidatorsStatuses[i] = validatorStatus
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
for _, stringTargetPubKey := range stringTargetPubKeys {
|
||||
if _, ok := stringRetrievedPubKeys[stringTargetPubKey]; !ok {
|
||||
targetPubKey := stringTargetPubKeysToPubKeys[stringTargetPubKey]
|
||||
missingPubKeys = append(missingPubKeys, targetPubKey)
|
||||
}
|
||||
}
|
||||
|
||||
nbStringRetrievedPubKeys := len(stringRetrievedPubKeys)
|
||||
|
||||
for i, missingPubKey := range missingPubKeys {
|
||||
outPubKeys[nbStringRetrievedPubKeys+i] = missingPubKey
|
||||
outIndexes[nbStringRetrievedPubKeys+i] = types.ValidatorIndex(^uint64(0))
|
||||
|
||||
outValidatorsStatuses[nbStringRetrievedPubKeys+i] = ðpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
outLen := len(stateValidatorsResponse.Data) + len(missingPubKeys)
|
||||
return outPubKeys[:outLen], outIndexes[:outLen], outValidatorsStatuses[:outLen], nil
|
||||
}
|
||||
|
@ -2,346 +2,698 @@ package beacon_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/pkg/errors"
|
||||
rpcmiddleware "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
|
||||
)
|
||||
|
||||
const defaultStringPubKey = "0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13"
|
||||
|
||||
type urlAndData struct {
|
||||
Url string
|
||||
Data []*rpcmiddleware.ValidatorContainerJson
|
||||
}
|
||||
|
||||
func TestValidatorsStatus_Nominal(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
urlsAndData []urlAndData
|
||||
wanted *ethpb.ValidatorStatusResponse
|
||||
}{
|
||||
{
|
||||
name: "Some active validators",
|
||||
urlsAndData: []urlAndData{
|
||||
{
|
||||
Url: fmt.Sprintf("/eth/v1/beacon/states/head/validators?id=%s", stringPubKey),
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "55300",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Url: "/eth/v1/beacon/states/head/validators?status=active",
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "55293",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{},
|
||||
},
|
||||
{
|
||||
Index: "55294",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wanted: ðpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_PENDING,
|
||||
ActivationEpoch: 100,
|
||||
PositionInActivationQueue: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No active validators",
|
||||
urlsAndData: []urlAndData{
|
||||
{
|
||||
Url: fmt.Sprintf("/eth/v1/beacon/states/head/validators?id=%s", stringPubKey),
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "55300",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Url: "/eth/v1/beacon/states/head/validators?status=active",
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{},
|
||||
},
|
||||
},
|
||||
wanted: ðpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_PENDING,
|
||||
ActivationEpoch: 100,
|
||||
PositionInActivationQueue: 55300,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Unknown status",
|
||||
urlsAndData: []urlAndData{
|
||||
{
|
||||
Url: fmt.Sprintf("/eth/v1/beacon/states/head/validators?id=%s", stringPubKey),
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{},
|
||||
},
|
||||
},
|
||||
wanted: ðpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pubKey, err := hexutil.Decode(defaultStringPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name,
|
||||
func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
|
||||
for _, urlAndData := range testCase.urlsAndData {
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
urlAndData.Url,
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil,
|
||||
nil,
|
||||
).SetArg(
|
||||
1,
|
||||
rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: urlAndData.Data,
|
||||
},
|
||||
).Times(1)
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
|
||||
actual, err := validatorClient.validatorStatus(
|
||||
ðpb.ValidatorStatusRequest{
|
||||
PublicKey: pubKey,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, testCase.wanted, actual)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorStatus_InvalidData(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
data []*rpcmiddleware.ValidatorContainerJson
|
||||
expectedErrorMessage string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "bad validator status",
|
||||
data: []*rpcmiddleware.ValidatorContainerJson{},
|
||||
expectedErrorMessage: "failed to get state validator",
|
||||
err: errors.New("some specific json error"),
|
||||
},
|
||||
{
|
||||
name: "bad validator status",
|
||||
data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "NotAStatus",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedErrorMessage: "invalid validator status: NotAStatus",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "bad activation epoch",
|
||||
data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "NotAnEpoch",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedErrorMessage: "failed to parse activation epoch",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "bad validator index",
|
||||
data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "12345",
|
||||
},
|
||||
Index: "NotAnIndex",
|
||||
},
|
||||
},
|
||||
expectedErrorMessage: "failed to parse validator index",
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name,
|
||||
func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil,
|
||||
testCase.err,
|
||||
).SetArg(
|
||||
1,
|
||||
rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: testCase.data,
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
|
||||
_, err := validatorClient.ValidatorStatus(
|
||||
context.Background(),
|
||||
ðpb.ValidatorStatusRequest{},
|
||||
)
|
||||
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorStatus_InvalidValidatorsState(t *testing.T) {
|
||||
pubKey, err := hexutil.Decode(defaultStringPubKey)
|
||||
func TestValidatorStatus_Nominal(t *testing.T) {
|
||||
const stringValidatorPubKey = "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463"
|
||||
validatorPubKey, err := hexutil.Decode(stringValidatorPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stateValidatorsResponseJson := rpcmiddleware.StateValidatorsResponseJson{}
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
gomock.Any(),
|
||||
&stateValidatorsResponseJson,
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
[]string{stringValidatorPubKey},
|
||||
nil,
|
||||
nil,
|
||||
).Return(
|
||||
nil,
|
||||
nil,
|
||||
).SetArg(
|
||||
1,
|
||||
rpcmiddleware.StateValidatorsResponseJson{
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "55300",
|
||||
Status: "pending_queued",
|
||||
Index: "35000",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "100",
|
||||
PublicKey: stringValidatorPubKey,
|
||||
ActivationEpoch: "56",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
"/eth/v1/beacon/states/head/validators?status=active",
|
||||
&stateValidatorsResponseJson,
|
||||
).Return(
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
|
||||
actualValidatorStatusResponse, err := validatorClient.ValidatorStatus(
|
||||
context.Background(),
|
||||
ðpb.ValidatorStatusRequest{
|
||||
PublicKey: validatorPubKey,
|
||||
},
|
||||
)
|
||||
|
||||
expectedValidatorStatusResponse := ethpb.ValidatorStatusResponse{
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: 56,
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, &expectedValidatorStatusResponse, actualValidatorStatusResponse)
|
||||
}
|
||||
|
||||
func TestValidatorStatus_Error(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
gomock.Any(),
|
||||
nil,
|
||||
nil,
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{},
|
||||
errors.New("a specific error"),
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
|
||||
_, err = validatorClient.validatorStatus(
|
||||
_, err := validatorClient.ValidatorStatus(
|
||||
context.Background(),
|
||||
ðpb.ValidatorStatusRequest{
|
||||
PublicKey: pubKey,
|
||||
PublicKey: []byte{},
|
||||
},
|
||||
)
|
||||
require.ErrorContains(t, "failed to get state validators", err)
|
||||
|
||||
require.ErrorContains(t, "failed to get validator status response", err)
|
||||
}
|
||||
|
||||
func TestValidatorStatus_InvalidLastValidatorIndex(t *testing.T) {
|
||||
pubKey, err := hexutil.Decode(defaultStringPubKey)
|
||||
require.NoError(t, err)
|
||||
func TestMultipleValidatorStatus_Nominal(t *testing.T) {
|
||||
stringValidatorsPubKey := []string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // existing
|
||||
"0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463", // existing
|
||||
}
|
||||
|
||||
validatorsPubKey := make([][]byte, len(stringValidatorsPubKey))
|
||||
|
||||
for i, stringValidatorPubKey := range stringValidatorsPubKey {
|
||||
validatorPubKey, err := hexutil.Decode(stringValidatorPubKey)
|
||||
require.NoError(t, err)
|
||||
validatorsPubKey[i] = validatorPubKey
|
||||
}
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stateValidatorsResponseJson := rpcmiddleware.StateValidatorsResponseJson{}
|
||||
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
gomock.Any(),
|
||||
&stateValidatorsResponseJson,
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
stringValidatorsPubKey,
|
||||
nil,
|
||||
nil,
|
||||
).Return(
|
||||
nil,
|
||||
nil,
|
||||
).SetArg(
|
||||
1,
|
||||
rpcmiddleware.StateValidatorsResponseJson{
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "55300",
|
||||
Status: "pending_queued",
|
||||
Index: "11111",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
ActivationEpoch: "100",
|
||||
PublicKey: "0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13",
|
||||
ActivationEpoch: "12",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "22222",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463",
|
||||
ActivationEpoch: "34",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
"/eth/v1/beacon/states/head/validators?status=active",
|
||||
&stateValidatorsResponseJson,
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
|
||||
expectedValidatorStatusResponse := ethpb.MultipleValidatorStatusResponse{
|
||||
PublicKeys: validatorsPubKey,
|
||||
Indices: []types.ValidatorIndex{
|
||||
11111,
|
||||
22222,
|
||||
},
|
||||
Statuses: []*ethpb.ValidatorStatusResponse{
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: 12,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: 34,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actualValidatorStatusResponse, err := validatorClient.MultipleValidatorStatus(
|
||||
context.Background(),
|
||||
ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: validatorsPubKey,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, &expectedValidatorStatusResponse, actualValidatorStatusResponse)
|
||||
}
|
||||
|
||||
func TestMultipleValidatorStatus_Error(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
gomock.Any(),
|
||||
nil,
|
||||
nil,
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{},
|
||||
errors.New("a specific error"),
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
|
||||
_, err := validatorClient.MultipleValidatorStatus(
|
||||
context.Background(),
|
||||
ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: [][]byte{},
|
||||
},
|
||||
)
|
||||
require.ErrorContains(t, "failed to get validators status response", err)
|
||||
}
|
||||
|
||||
func TestGetValidatorsStatusResponse_Nominal_SomeActiveValidators(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stringValidatorsPubKey := []string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // existing
|
||||
"0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463", // existing
|
||||
"0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526", // NOT existing
|
||||
"0x8000ab56b051f9d8f31c687528c6e91c9b98e4c3a241e752f9ccfbea7c5a7fbbd272bdf2c0a7e52ce7e0b57693df364c", // existing
|
||||
"0x8000b3e51de7e2e319b23a42d468dc8e63cd61daa5c4609cf2d800026d92706d1240414e155057bdc35e0574bba3ad80", // NOT existing
|
||||
"0x800010c20716ef4264a6d93b3873a008ece58fb9312ac2cc3b0ccc40aedb050f2038281e6a92242a35476af9903c7919", // existing
|
||||
}
|
||||
|
||||
validatorsPubKey := make([][]byte, len(stringValidatorsPubKey))
|
||||
|
||||
for i, stringValidatorPubKey := range stringValidatorsPubKey {
|
||||
validatorPubKey, err := hexutil.Decode(stringValidatorPubKey)
|
||||
require.NoError(t, err)
|
||||
validatorsPubKey[i] = validatorPubKey
|
||||
}
|
||||
|
||||
validatorsIndex := []int64{
|
||||
12345, // NOT existing
|
||||
33333, // existing
|
||||
}
|
||||
|
||||
extraStringValidatorKey := "0x80003eb1e78ffdea6c878026b7074f84aaa16536c8e1960a652e817c848e7ccb051087f837b7d2bb6773cd9705601ede"
|
||||
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
stringValidatorsPubKey,
|
||||
validatorsIndex,
|
||||
nil,
|
||||
nil,
|
||||
).SetArg(
|
||||
1,
|
||||
rpcmiddleware.StateValidatorsResponseJson{
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "NotAnIndex",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{},
|
||||
Index: "11111",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13",
|
||||
ActivationEpoch: "12",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "22222",
|
||||
Status: "active_exiting",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x800010c20716ef4264a6d93b3873a008ece58fb9312ac2cc3b0ccc40aedb050f2038281e6a92242a35476af9903c7919",
|
||||
ActivationEpoch: "34",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "33333",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: extraStringValidatorKey,
|
||||
ActivationEpoch: "56",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "40000",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463",
|
||||
ActivationEpoch: fmt.Sprintf("%d", params.BeaconConfig().FarFutureEpoch),
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "50000",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000ab56b051f9d8f31c687528c6e91c9b98e4c3a241e752f9ccfbea7c5a7fbbd272bdf2c0a7e52ce7e0b57693df364c",
|
||||
ActivationEpoch: fmt.Sprintf("%d", params.BeaconConfig().FarFutureEpoch),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
|
||||
_, err = validatorClient.validatorStatus(
|
||||
ðpb.ValidatorStatusRequest{
|
||||
PublicKey: pubKey,
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
nil,
|
||||
nil,
|
||||
[]string{"active"},
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "35000",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000ab56b051f9d8f31c687528c6e91c9b98e4c3a241e752f9ccfbea7c5a7fbbd272bdf2c0a7e52ce7e0b57693df364d",
|
||||
ActivationEpoch: "56",
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: "39000",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000ab56b051f9d8f31c687528c6e91c9b98e4c3a241e752f9ccfbea7c5a7fbbd272bdf2c0a7e52ce7e0b57693df364e",
|
||||
ActivationEpoch: "56",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
require.ErrorContains(t, "failed to parse last validator index", err)
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
wantedStringValidatorsPubkey := []string{
|
||||
"0x8000091c2ae64ee414a54c1cc1fc67dec663408bc636cb86756e0200e41a75c8f86603f104f02c856983d2783116be13", // existing
|
||||
"0x800010c20716ef4264a6d93b3873a008ece58fb9312ac2cc3b0ccc40aedb050f2038281e6a92242a35476af9903c7919", // existing,
|
||||
extraStringValidatorKey, // existing,
|
||||
"0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463", // existing,
|
||||
"0x8000ab56b051f9d8f31c687528c6e91c9b98e4c3a241e752f9ccfbea7c5a7fbbd272bdf2c0a7e52ce7e0b57693df364c", // existing
|
||||
"0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526", // NOT existing
|
||||
"0x8000b3e51de7e2e319b23a42d468dc8e63cd61daa5c4609cf2d800026d92706d1240414e155057bdc35e0574bba3ad80", // NOT existing
|
||||
}
|
||||
|
||||
wantedValidatorsPubKey := make([][]byte, len(wantedStringValidatorsPubkey))
|
||||
for i, stringValidatorPubKey := range wantedStringValidatorsPubkey {
|
||||
validatorPubKey, err := hexutil.Decode(stringValidatorPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
wantedValidatorsPubKey[i] = validatorPubKey
|
||||
}
|
||||
|
||||
wantedValidatorsIndex := []types.ValidatorIndex{
|
||||
11111,
|
||||
22222,
|
||||
33333,
|
||||
40000,
|
||||
50000,
|
||||
types.ValidatorIndex(^uint64(0)),
|
||||
types.ValidatorIndex(^uint64(0)),
|
||||
}
|
||||
|
||||
wantedValidatorsStatusResponse := []*ethpb.ValidatorStatusResponse{
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: 12,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_EXITING,
|
||||
ActivationEpoch: 34,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ActivationEpoch: 56,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_PENDING,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PositionInActivationQueue: 1000,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_PENDING,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PositionInActivationQueue: 11000,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
actualValidatorsPubKey, actualValidatorsIndex, actualValidatorsStatusResponse, err := validatorClient.getValidatorsStatusResponse(validatorsPubKey, validatorsIndex)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, wantedValidatorsPubKey, actualValidatorsPubKey)
|
||||
assert.DeepEqual(t, wantedValidatorsIndex, actualValidatorsIndex)
|
||||
assert.DeepEqual(t, wantedValidatorsStatusResponse, actualValidatorsStatusResponse)
|
||||
}
|
||||
|
||||
func TestGetValidatorsStatusResponse_Nominal_NoActiveValidators(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
const stringValidatorPubKey = "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463"
|
||||
validatorPubKey, err := hexutil.Decode(stringValidatorPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
[]string{stringValidatorPubKey},
|
||||
nil,
|
||||
nil,
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "40000",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463",
|
||||
ActivationEpoch: fmt.Sprintf("%d", params.BeaconConfig().FarFutureEpoch),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
nil,
|
||||
nil,
|
||||
[]string{"active"},
|
||||
).Return(
|
||||
&rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
wantedValidatorsPubKey := [][]byte{validatorPubKey}
|
||||
wantedValidatorsIndex := []types.ValidatorIndex{40000}
|
||||
wantedValidatorsStatusResponse := []*ethpb.ValidatorStatusResponse{
|
||||
{
|
||||
Status: ethpb.ValidatorStatus_PENDING,
|
||||
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PositionInActivationQueue: 40000,
|
||||
},
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
actualValidatorsPubKey, actualValidatorsIndex, actualValidatorsStatusResponse, err := validatorClient.getValidatorsStatusResponse(wantedValidatorsPubKey, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, wantedValidatorsPubKey, actualValidatorsPubKey)
|
||||
assert.DeepEqual(t, wantedValidatorsIndex, actualValidatorsIndex)
|
||||
assert.DeepEqual(t, wantedValidatorsStatusResponse, actualValidatorsStatusResponse)
|
||||
}
|
||||
|
||||
type getStateValidatorsInterface struct {
|
||||
// Inputs
|
||||
inputStringPubKeys []string
|
||||
inputIndexes []int64
|
||||
inputStatuses []string
|
||||
|
||||
// Outputs
|
||||
outputStateValidatorsResponseJson *rpcmiddleware.StateValidatorsResponseJson
|
||||
outputErr error
|
||||
}
|
||||
|
||||
func TestValidatorStatusResponse_InvalidData(t *testing.T) {
|
||||
stringPubKey := "0x8000a6c975761b488bdb0dfba4ed37c0d97d6e6b968562ef5c84aa9a5dfb92d8e309195004e97709077723739bf04463"
|
||||
pubKey, err := hexutil.Decode(stringPubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
// Inputs
|
||||
inputPubKeys [][]byte
|
||||
inputIndexes []int64
|
||||
inputGetStateValidatorsInterfaces []getStateValidatorsInterface
|
||||
|
||||
// Outputs
|
||||
outputErrMessage string
|
||||
}{
|
||||
{
|
||||
name: "failed getStateValidators",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{},
|
||||
outputErr: errors.New("a specific error"),
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to get state validators",
|
||||
},
|
||||
{
|
||||
name: "failed to parse validator public key NotAPublicKey",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: "NotAPublicKey",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to parse validator public key",
|
||||
},
|
||||
{
|
||||
name: "failed to parse validator index NotAnIndex",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "NotAnIndex",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to parse validator index",
|
||||
},
|
||||
{
|
||||
name: "invalid validator status",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "NotAStatus",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
},
|
||||
outputErrMessage: "invalid validator status NotAStatus",
|
||||
},
|
||||
{
|
||||
name: "failed to parse activation epoch",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "active_ongoing",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
ActivationEpoch: "NotAnEpoch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to parse activation epoch NotAnEpoch",
|
||||
},
|
||||
{
|
||||
name: "failed to get state validators",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
ActivationEpoch: "10",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
{
|
||||
inputStringPubKeys: nil,
|
||||
inputIndexes: nil,
|
||||
inputStatuses: []string{"active"},
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{},
|
||||
outputErr: errors.New("a specific error"),
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to get state validators",
|
||||
},
|
||||
{
|
||||
name: "failed to parse last validator index",
|
||||
|
||||
inputPubKeys: [][]byte{pubKey},
|
||||
inputIndexes: nil,
|
||||
inputGetStateValidatorsInterfaces: []getStateValidatorsInterface{
|
||||
{
|
||||
inputStringPubKeys: []string{stringPubKey},
|
||||
inputIndexes: nil,
|
||||
inputStatuses: nil,
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "12345",
|
||||
Status: "pending_queued",
|
||||
Validator: &rpcmiddleware.ValidatorJson{
|
||||
PublicKey: stringPubKey,
|
||||
ActivationEpoch: "10",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
{
|
||||
inputStringPubKeys: nil,
|
||||
inputIndexes: nil,
|
||||
inputStatuses: []string{"active"},
|
||||
|
||||
outputStateValidatorsResponseJson: &rpcmiddleware.StateValidatorsResponseJson{
|
||||
Data: []*rpcmiddleware.ValidatorContainerJson{
|
||||
{
|
||||
Index: "NotAnIndex",
|
||||
},
|
||||
},
|
||||
},
|
||||
outputErr: nil,
|
||||
},
|
||||
},
|
||||
outputErrMessage: "failed to parse last validator index NotAnIndex",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name,
|
||||
func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
||||
|
||||
for _, aa := range testCase.inputGetStateValidatorsInterfaces {
|
||||
stateValidatorsProvider.EXPECT().GetStateValidators(
|
||||
aa.inputStringPubKeys,
|
||||
aa.inputIndexes,
|
||||
aa.inputStatuses,
|
||||
).Return(
|
||||
aa.outputStateValidatorsResponseJson,
|
||||
aa.outputErr,
|
||||
).Times(1)
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
|
||||
|
||||
_, _, _, err := validatorClient.getValidatorsStatusResponse(
|
||||
testCase.inputPubKeys,
|
||||
testCase.inputIndexes,
|
||||
)
|
||||
|
||||
assert.ErrorContains(t, testCase.outputErrMessage, err)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user