github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/eth/v1/beacon/validator_test.go (about)

     1  package beacon
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  
    10  	types "github.com/prysmaticlabs/eth2-types"
    11  	chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/statefetcher"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/testutil"
    15  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    16  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1"
    17  	ethpb_alpha "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    18  	"github.com/prysmaticlabs/prysm/shared/params"
    19  	sharedtestutil "github.com/prysmaticlabs/prysm/shared/testutil"
    20  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    21  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    22  )
    23  
    24  func TestGetValidator(t *testing.T) {
    25  	ctx := context.Background()
    26  
    27  	var state iface.BeaconState
    28  	state, _ = sharedtestutil.DeterministicGenesisState(t, 8192)
    29  
    30  	t.Run("Head Get Validator by index", func(t *testing.T) {
    31  		s := Server{
    32  			StateFetcher: &testutil.MockFetcher{
    33  				BeaconState: state,
    34  			},
    35  		}
    36  
    37  		resp, err := s.GetValidator(ctx, &ethpb.StateValidatorRequest{
    38  			StateId:     []byte("head"),
    39  			ValidatorId: []byte("15"),
    40  		})
    41  		require.NoError(t, err)
    42  		assert.Equal(t, types.ValidatorIndex(15), resp.Data.Index)
    43  	})
    44  
    45  	t.Run("Head Get Validator by pubkey", func(t *testing.T) {
    46  		s := Server{
    47  			StateFetcher: &testutil.MockFetcher{
    48  				BeaconState: state,
    49  			},
    50  		}
    51  
    52  		pubKey := state.PubkeyAtIndex(types.ValidatorIndex(20))
    53  		resp, err := s.GetValidator(ctx, &ethpb.StateValidatorRequest{
    54  			StateId:     []byte("head"),
    55  			ValidatorId: pubKey[:],
    56  		})
    57  		require.NoError(t, err)
    58  		assert.Equal(t, types.ValidatorIndex(20), resp.Data.Index)
    59  		assert.Equal(t, true, bytes.Equal(pubKey[:], resp.Data.Validator.Pubkey))
    60  	})
    61  
    62  	t.Run("Validator ID required", func(t *testing.T) {
    63  		s := Server{
    64  			StateFetcher: &testutil.MockFetcher{
    65  				BeaconState: state,
    66  			},
    67  		}
    68  		_, err := s.GetValidator(ctx, &ethpb.StateValidatorRequest{
    69  			StateId: []byte("head"),
    70  		})
    71  		require.ErrorContains(t, "Validator ID is required", err)
    72  	})
    73  }
    74  
    75  func TestListValidators(t *testing.T) {
    76  	ctx := context.Background()
    77  
    78  	var state iface.BeaconState
    79  	state, _ = sharedtestutil.DeterministicGenesisState(t, 8192)
    80  
    81  	t.Run("Head List All Validators", func(t *testing.T) {
    82  		s := Server{
    83  			StateFetcher: &testutil.MockFetcher{
    84  				BeaconState: state,
    85  			},
    86  		}
    87  
    88  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
    89  			StateId: []byte("head"),
    90  		})
    91  		require.NoError(t, err)
    92  		assert.Equal(t, len(resp.Data), 8192)
    93  		for _, val := range resp.Data {
    94  			assert.Equal(t, ethpb.ValidatorStatus_ACTIVE_ONGOING, val.Status)
    95  		}
    96  	})
    97  
    98  	t.Run("Head List Validators by index", func(t *testing.T) {
    99  		s := Server{
   100  			StateFetcher: &testutil.MockFetcher{
   101  				BeaconState: state,
   102  			},
   103  		}
   104  
   105  		ids := [][]byte{[]byte("15"), []byte("26"), []byte("400")}
   106  		idNums := []types.ValidatorIndex{15, 26, 400}
   107  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   108  			StateId: []byte("head"),
   109  			Id:      ids,
   110  		})
   111  		require.NoError(t, err)
   112  		for i, val := range resp.Data {
   113  			assert.Equal(t, idNums[i], val.Index)
   114  			assert.Equal(t, ethpb.ValidatorStatus_ACTIVE_ONGOING, val.Status)
   115  		}
   116  	})
   117  
   118  	t.Run("Head List Validators by pubkey", func(t *testing.T) {
   119  		s := Server{
   120  			StateFetcher: &testutil.MockFetcher{
   121  				BeaconState: state,
   122  			},
   123  		}
   124  		idNums := []types.ValidatorIndex{20, 66, 90, 100}
   125  		pubkey1 := state.PubkeyAtIndex(types.ValidatorIndex(20))
   126  		pubkey2 := state.PubkeyAtIndex(types.ValidatorIndex(66))
   127  		pubkey3 := state.PubkeyAtIndex(types.ValidatorIndex(90))
   128  		pubkey4 := state.PubkeyAtIndex(types.ValidatorIndex(100))
   129  		pubKeys := [][]byte{pubkey1[:], pubkey2[:], pubkey3[:], pubkey4[:]}
   130  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   131  			StateId: []byte("head"),
   132  			Id:      pubKeys,
   133  		})
   134  		require.NoError(t, err)
   135  		for i, val := range resp.Data {
   136  			assert.Equal(t, idNums[i], val.Index)
   137  			assert.Equal(t, true, bytes.Equal(pubKeys[i], val.Validator.Pubkey))
   138  			assert.Equal(t, ethpb.ValidatorStatus_ACTIVE_ONGOING, val.Status)
   139  		}
   140  	})
   141  
   142  	t.Run("Head List Validators by both index and pubkey", func(t *testing.T) {
   143  		s := Server{
   144  			StateFetcher: &testutil.MockFetcher{
   145  				BeaconState: state,
   146  			},
   147  		}
   148  
   149  		idNums := []types.ValidatorIndex{20, 90, 170, 129}
   150  		pubkey1 := state.PubkeyAtIndex(types.ValidatorIndex(20))
   151  		pubkey2 := state.PubkeyAtIndex(types.ValidatorIndex(90))
   152  		pubkey3 := state.PubkeyAtIndex(types.ValidatorIndex(170))
   153  		pubkey4 := state.PubkeyAtIndex(types.ValidatorIndex(129))
   154  		pubkeys := [][]byte{pubkey1[:], pubkey2[:], pubkey3[:], pubkey4[:]}
   155  		ids := [][]byte{pubkey1[:], []byte("90"), pubkey3[:], []byte("129")}
   156  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   157  			StateId: []byte("head"),
   158  			Id:      ids,
   159  		})
   160  		require.NoError(t, err)
   161  		for i, val := range resp.Data {
   162  			assert.Equal(t, idNums[i], val.Index)
   163  			assert.Equal(t, true, bytes.Equal(pubkeys[i], val.Validator.Pubkey))
   164  			assert.Equal(t, ethpb.ValidatorStatus_ACTIVE_ONGOING, val.Status)
   165  		}
   166  	})
   167  
   168  	t.Run("Unknown public key is ignored", func(t *testing.T) {
   169  		s := Server{
   170  			StateFetcher: &testutil.MockFetcher{
   171  				BeaconState: state,
   172  			},
   173  		}
   174  
   175  		existingKey := state.PubkeyAtIndex(types.ValidatorIndex(1))
   176  		pubkeys := [][]byte{existingKey[:], []byte(strings.Repeat("f", 48))}
   177  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   178  			StateId: []byte("head"),
   179  			Id:      pubkeys,
   180  		})
   181  		require.NoError(t, err)
   182  		require.Equal(t, 1, len(resp.Data))
   183  		assert.Equal(t, types.ValidatorIndex(1), resp.Data[0].Index)
   184  	})
   185  
   186  	t.Run("Unknown index is ignored", func(t *testing.T) {
   187  		s := Server{
   188  			StateFetcher: &testutil.MockFetcher{
   189  				BeaconState: state,
   190  			},
   191  		}
   192  
   193  		ids := [][]byte{[]byte("1"), []byte("99999")}
   194  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   195  			StateId: []byte("head"),
   196  			Id:      ids,
   197  		})
   198  		require.NoError(t, err)
   199  		require.Equal(t, 1, len(resp.Data))
   200  		assert.Equal(t, types.ValidatorIndex(1), resp.Data[0].Index)
   201  	})
   202  }
   203  
   204  func TestListValidators_Status(t *testing.T) {
   205  	ctx := context.Background()
   206  
   207  	var state iface.BeaconState
   208  	state, _ = sharedtestutil.DeterministicGenesisState(t, 8192)
   209  
   210  	farFutureEpoch := params.BeaconConfig().FarFutureEpoch
   211  	validators := []*ethpb_alpha.Validator{
   212  		// Pending initialized.
   213  		{
   214  			ActivationEpoch:            farFutureEpoch,
   215  			ActivationEligibilityEpoch: farFutureEpoch,
   216  		},
   217  		// Pending queued.
   218  		{
   219  			ActivationEpoch:            10,
   220  			ActivationEligibilityEpoch: 4,
   221  		},
   222  		// Active ongoing.
   223  		{
   224  			ActivationEpoch: 0,
   225  			ExitEpoch:       farFutureEpoch,
   226  		},
   227  		// Active slashed.
   228  		{
   229  			ActivationEpoch: 0,
   230  			ExitEpoch:       30,
   231  			Slashed:         true,
   232  		},
   233  		// Active exiting.
   234  		{
   235  			ActivationEpoch: 3,
   236  			ExitEpoch:       30,
   237  			Slashed:         false,
   238  		},
   239  		// Exit slashed (at epoch 35).
   240  		{
   241  			ActivationEpoch:   3,
   242  			ExitEpoch:         30,
   243  			WithdrawableEpoch: 40,
   244  			Slashed:           true,
   245  		},
   246  		// Exit unslashed (at epoch 35).
   247  		{
   248  			ActivationEpoch:   3,
   249  			ExitEpoch:         30,
   250  			WithdrawableEpoch: 40,
   251  			Slashed:           false,
   252  		},
   253  		// Withdrawable (at epoch 45).
   254  		{
   255  			ActivationEpoch:   3,
   256  			ExitEpoch:         30,
   257  			WithdrawableEpoch: 40,
   258  			EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   259  			Slashed:           false,
   260  		},
   261  		// Withdrawal done (at epoch 45).
   262  		{
   263  			ActivationEpoch:   3,
   264  			ExitEpoch:         30,
   265  			WithdrawableEpoch: 40,
   266  			EffectiveBalance:  0,
   267  			Slashed:           false,
   268  		},
   269  	}
   270  	for _, validator := range validators {
   271  		require.NoError(t, state.AppendValidator(validator))
   272  		require.NoError(t, state.AppendBalance(params.BeaconConfig().MaxEffectiveBalance))
   273  	}
   274  
   275  	t.Run("Head List All ACTIVE Validators", func(t *testing.T) {
   276  		s := Server{
   277  			StateFetcher: &statefetcher.StateProvider{
   278  				ChainInfoFetcher: &chainMock.ChainService{State: state},
   279  			},
   280  		}
   281  
   282  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   283  			StateId: []byte("head"),
   284  			Status:  []ethpb.ValidatorStatus{ethpb.ValidatorStatus_ACTIVE},
   285  		})
   286  		require.NoError(t, err)
   287  		assert.Equal(t, len(resp.Data), 8192+2 /* 2 active */)
   288  		for _, datum := range resp.Data {
   289  			status, err := validatorStatus(datum.Validator, 0)
   290  			require.NoError(t, err)
   291  			require.Equal(
   292  				t,
   293  				true,
   294  				status == ethpb.ValidatorStatus_ACTIVE,
   295  			)
   296  			require.Equal(
   297  				t,
   298  				true,
   299  				datum.Status == ethpb.ValidatorStatus_ACTIVE_ONGOING ||
   300  					datum.Status == ethpb.ValidatorStatus_ACTIVE_EXITING ||
   301  					datum.Status == ethpb.ValidatorStatus_ACTIVE_SLASHED,
   302  			)
   303  		}
   304  	})
   305  
   306  	t.Run("Head List All ACTIVE_ONGOING Validators", func(t *testing.T) {
   307  		s := Server{
   308  			StateFetcher: &statefetcher.StateProvider{
   309  				ChainInfoFetcher: &chainMock.ChainService{State: state},
   310  			},
   311  		}
   312  
   313  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   314  			StateId: []byte("head"),
   315  			Status:  []ethpb.ValidatorStatus{ethpb.ValidatorStatus_ACTIVE_ONGOING},
   316  		})
   317  		require.NoError(t, err)
   318  		assert.Equal(t, len(resp.Data), 8192+1 /* 1 active_ongoing */)
   319  		for _, datum := range resp.Data {
   320  			status, err := validatorSubStatus(datum.Validator, 0)
   321  			require.NoError(t, err)
   322  			require.Equal(
   323  				t,
   324  				true,
   325  				status == ethpb.ValidatorStatus_ACTIVE_ONGOING,
   326  			)
   327  			require.Equal(
   328  				t,
   329  				true,
   330  				datum.Status == ethpb.ValidatorStatus_ACTIVE_ONGOING,
   331  			)
   332  		}
   333  	})
   334  
   335  	require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch*35))
   336  	t.Run("Head List All EXITED Validators", func(t *testing.T) {
   337  		s := Server{
   338  			StateFetcher: &statefetcher.StateProvider{
   339  				ChainInfoFetcher: &chainMock.ChainService{State: state},
   340  			},
   341  		}
   342  
   343  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   344  			StateId: []byte("head"),
   345  			Status:  []ethpb.ValidatorStatus{ethpb.ValidatorStatus_EXITED},
   346  		})
   347  		require.NoError(t, err)
   348  		assert.Equal(t, 4 /* 4 exited */, len(resp.Data))
   349  		for _, datum := range resp.Data {
   350  			status, err := validatorStatus(datum.Validator, 35)
   351  			require.NoError(t, err)
   352  			require.Equal(
   353  				t,
   354  				true,
   355  				status == ethpb.ValidatorStatus_EXITED,
   356  			)
   357  			require.Equal(
   358  				t,
   359  				true,
   360  				datum.Status == ethpb.ValidatorStatus_EXITED_UNSLASHED || datum.Status == ethpb.ValidatorStatus_EXITED_SLASHED,
   361  			)
   362  		}
   363  	})
   364  
   365  	t.Run("Head List All PENDING_INITIALIZED and EXITED_UNSLASHED Validators", func(t *testing.T) {
   366  		s := Server{
   367  			StateFetcher: &statefetcher.StateProvider{
   368  				ChainInfoFetcher: &chainMock.ChainService{State: state},
   369  			},
   370  		}
   371  
   372  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   373  			StateId: []byte("head"),
   374  			Status:  []ethpb.ValidatorStatus{ethpb.ValidatorStatus_PENDING_INITIALIZED, ethpb.ValidatorStatus_EXITED_UNSLASHED},
   375  		})
   376  		require.NoError(t, err)
   377  		assert.Equal(t, 4 /* 4 exited */, len(resp.Data))
   378  		for _, datum := range resp.Data {
   379  			status, err := validatorSubStatus(datum.Validator, 35)
   380  			require.NoError(t, err)
   381  			require.Equal(
   382  				t,
   383  				true,
   384  				status == ethpb.ValidatorStatus_PENDING_INITIALIZED || status == ethpb.ValidatorStatus_EXITED_UNSLASHED,
   385  			)
   386  			require.Equal(
   387  				t,
   388  				true,
   389  				datum.Status == ethpb.ValidatorStatus_PENDING_INITIALIZED || datum.Status == ethpb.ValidatorStatus_EXITED_UNSLASHED,
   390  			)
   391  		}
   392  	})
   393  
   394  	t.Run("Head List All PENDING and EXITED Validators", func(t *testing.T) {
   395  		s := Server{
   396  			StateFetcher: &statefetcher.StateProvider{
   397  				ChainInfoFetcher: &chainMock.ChainService{State: state},
   398  			},
   399  		}
   400  
   401  		resp, err := s.ListValidators(ctx, &ethpb.StateValidatorsRequest{
   402  			StateId: []byte("head"),
   403  			Status:  []ethpb.ValidatorStatus{ethpb.ValidatorStatus_PENDING, ethpb.ValidatorStatus_EXITED_SLASHED},
   404  		})
   405  		require.NoError(t, err)
   406  		assert.Equal(t, 2 /* 1 pending, 1 exited */, len(resp.Data))
   407  		for _, datum := range resp.Data {
   408  			status, err := validatorStatus(datum.Validator, 35)
   409  			require.NoError(t, err)
   410  			subStatus, err := validatorSubStatus(datum.Validator, 35)
   411  			require.NoError(t, err)
   412  			require.Equal(
   413  				t,
   414  				true,
   415  				status == ethpb.ValidatorStatus_PENDING || subStatus == ethpb.ValidatorStatus_EXITED_SLASHED,
   416  			)
   417  			require.Equal(
   418  				t,
   419  				true,
   420  				datum.Status == ethpb.ValidatorStatus_PENDING_INITIALIZED || datum.Status == ethpb.ValidatorStatus_EXITED_SLASHED,
   421  			)
   422  		}
   423  	})
   424  }
   425  func TestListValidatorBalances(t *testing.T) {
   426  	ctx := context.Background()
   427  
   428  	var state iface.BeaconState
   429  	state, _ = sharedtestutil.DeterministicGenesisState(t, 8192)
   430  
   431  	t.Run("Head List Validators Balance by index", func(t *testing.T) {
   432  		s := Server{
   433  			StateFetcher: &testutil.MockFetcher{
   434  				BeaconState: state,
   435  			},
   436  		}
   437  
   438  		ids := [][]byte{[]byte("15"), []byte("26"), []byte("400")}
   439  		idNums := []types.ValidatorIndex{15, 26, 400}
   440  		resp, err := s.ListValidatorBalances(ctx, &ethpb.ValidatorBalancesRequest{
   441  			StateId: []byte("head"),
   442  			Id:      ids,
   443  		})
   444  		require.NoError(t, err)
   445  		for i, val := range resp.Data {
   446  			assert.Equal(t, idNums[i], val.Index)
   447  			assert.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.Balance)
   448  		}
   449  	})
   450  
   451  	t.Run("Head List Validators Balance by pubkey", func(t *testing.T) {
   452  		s := Server{
   453  			StateFetcher: &testutil.MockFetcher{
   454  				BeaconState: state,
   455  			},
   456  		}
   457  		idNums := []types.ValidatorIndex{20, 66, 90, 100}
   458  		pubkey1 := state.PubkeyAtIndex(types.ValidatorIndex(20))
   459  		pubkey2 := state.PubkeyAtIndex(types.ValidatorIndex(66))
   460  		pubkey3 := state.PubkeyAtIndex(types.ValidatorIndex(90))
   461  		pubkey4 := state.PubkeyAtIndex(types.ValidatorIndex(100))
   462  		pubKeys := [][]byte{pubkey1[:], pubkey2[:], pubkey3[:], pubkey4[:]}
   463  		resp, err := s.ListValidatorBalances(ctx, &ethpb.ValidatorBalancesRequest{
   464  			StateId: []byte("head"),
   465  			Id:      pubKeys,
   466  		})
   467  		require.NoError(t, err)
   468  		for i, val := range resp.Data {
   469  			assert.Equal(t, idNums[i], val.Index)
   470  			assert.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.Balance)
   471  		}
   472  	})
   473  
   474  	t.Run("Head List Validators Balance by both index and pubkey", func(t *testing.T) {
   475  		s := Server{
   476  			StateFetcher: &testutil.MockFetcher{
   477  				BeaconState: state,
   478  			},
   479  		}
   480  
   481  		idNums := []types.ValidatorIndex{20, 90, 170, 129}
   482  		pubkey1 := state.PubkeyAtIndex(types.ValidatorIndex(20))
   483  		pubkey3 := state.PubkeyAtIndex(types.ValidatorIndex(170))
   484  		ids := [][]byte{pubkey1[:], []byte("90"), pubkey3[:], []byte("129")}
   485  		resp, err := s.ListValidatorBalances(ctx, &ethpb.ValidatorBalancesRequest{
   486  			StateId: []byte("head"),
   487  			Id:      ids,
   488  		})
   489  		require.NoError(t, err)
   490  		for i, val := range resp.Data {
   491  			assert.Equal(t, idNums[i], val.Index)
   492  			assert.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.Balance)
   493  		}
   494  	})
   495  }
   496  
   497  func TestListCommittees(t *testing.T) {
   498  	ctx := context.Background()
   499  
   500  	var state iface.BeaconState
   501  	state, _ = sharedtestutil.DeterministicGenesisState(t, 8192)
   502  	epoch := helpers.SlotToEpoch(state.Slot())
   503  
   504  	t.Run("Head All Committees", func(t *testing.T) {
   505  		s := Server{
   506  			StateFetcher: &testutil.MockFetcher{
   507  				BeaconState: state,
   508  			},
   509  		}
   510  
   511  		resp, err := s.ListCommittees(ctx, &ethpb.StateCommitteesRequest{
   512  			StateId: []byte("head"),
   513  		})
   514  		require.NoError(t, err)
   515  		assert.Equal(t, int(params.BeaconConfig().SlotsPerEpoch)*2, len(resp.Data))
   516  		for _, datum := range resp.Data {
   517  			assert.Equal(t, true, datum.Index == types.CommitteeIndex(0) || datum.Index == types.CommitteeIndex(1))
   518  			assert.Equal(t, epoch, helpers.SlotToEpoch(datum.Slot))
   519  		}
   520  	})
   521  
   522  	t.Run("Head All Committees of Epoch 10", func(t *testing.T) {
   523  		s := Server{
   524  			StateFetcher: &testutil.MockFetcher{
   525  				BeaconState: state,
   526  			},
   527  		}
   528  		epoch := types.Epoch(10)
   529  		resp, err := s.ListCommittees(ctx, &ethpb.StateCommitteesRequest{
   530  			StateId: []byte("head"),
   531  			Epoch:   &epoch,
   532  		})
   533  		require.NoError(t, err)
   534  		for _, datum := range resp.Data {
   535  			assert.Equal(t, true, datum.Slot >= 320 && datum.Slot <= 351)
   536  		}
   537  	})
   538  
   539  	t.Run("Head All Committees of Slot 4", func(t *testing.T) {
   540  		s := Server{
   541  			StateFetcher: &testutil.MockFetcher{
   542  				BeaconState: state,
   543  			},
   544  		}
   545  
   546  		slot := types.Slot(4)
   547  		resp, err := s.ListCommittees(ctx, &ethpb.StateCommitteesRequest{
   548  			StateId: []byte("head"),
   549  			Slot:    &slot,
   550  		})
   551  		require.NoError(t, err)
   552  		assert.Equal(t, 2, len(resp.Data))
   553  		index := types.CommitteeIndex(0)
   554  		for _, datum := range resp.Data {
   555  			assert.Equal(t, epoch, helpers.SlotToEpoch(datum.Slot))
   556  			assert.Equal(t, slot, datum.Slot)
   557  			assert.Equal(t, index, datum.Index)
   558  			index++
   559  		}
   560  	})
   561  
   562  	t.Run("Head All Committees of Index 1", func(t *testing.T) {
   563  		s := Server{
   564  			StateFetcher: &testutil.MockFetcher{
   565  				BeaconState: state,
   566  			},
   567  		}
   568  
   569  		index := types.CommitteeIndex(1)
   570  		resp, err := s.ListCommittees(ctx, &ethpb.StateCommitteesRequest{
   571  			StateId: []byte("head"),
   572  			Index:   &index,
   573  		})
   574  		require.NoError(t, err)
   575  		assert.Equal(t, int(params.BeaconConfig().SlotsPerEpoch), len(resp.Data))
   576  		slot := types.Slot(0)
   577  		for _, datum := range resp.Data {
   578  			assert.Equal(t, epoch, helpers.SlotToEpoch(datum.Slot))
   579  			assert.Equal(t, slot, datum.Slot)
   580  			assert.Equal(t, index, datum.Index)
   581  			slot++
   582  		}
   583  	})
   584  
   585  	t.Run("Head All Committees of Slot 2, Index 1", func(t *testing.T) {
   586  		s := Server{
   587  			StateFetcher: &testutil.MockFetcher{
   588  				BeaconState: state,
   589  			},
   590  		}
   591  
   592  		index := types.CommitteeIndex(1)
   593  		slot := types.Slot(2)
   594  		resp, err := s.ListCommittees(ctx, &ethpb.StateCommitteesRequest{
   595  			StateId: []byte("head"),
   596  			Slot:    &slot,
   597  			Index:   &index,
   598  		})
   599  		require.NoError(t, err)
   600  		assert.Equal(t, 1, len(resp.Data))
   601  		for _, datum := range resp.Data {
   602  			assert.Equal(t, epoch, helpers.SlotToEpoch(datum.Slot))
   603  			assert.Equal(t, slot, datum.Slot)
   604  			assert.Equal(t, index, datum.Index)
   605  		}
   606  	})
   607  }
   608  
   609  func Test_validatorStatus(t *testing.T) {
   610  	farFutureEpoch := params.BeaconConfig().FarFutureEpoch
   611  
   612  	type args struct {
   613  		validator *ethpb.Validator
   614  		epoch     types.Epoch
   615  	}
   616  	tests := []struct {
   617  		name    string
   618  		args    args
   619  		want    ethpb.ValidatorStatus
   620  		wantErr bool
   621  	}{
   622  		{
   623  			name: "pending initialized",
   624  			args: args{
   625  				validator: &ethpb.Validator{
   626  					ActivationEpoch:            farFutureEpoch,
   627  					ActivationEligibilityEpoch: farFutureEpoch,
   628  				},
   629  				epoch: types.Epoch(5),
   630  			},
   631  			want: ethpb.ValidatorStatus_PENDING,
   632  		},
   633  		{
   634  			name: "pending queued",
   635  			args: args{
   636  				validator: &ethpb.Validator{
   637  					ActivationEpoch:            10,
   638  					ActivationEligibilityEpoch: 2,
   639  				},
   640  				epoch: types.Epoch(5),
   641  			},
   642  			want: ethpb.ValidatorStatus_PENDING,
   643  		},
   644  		{
   645  			name: "active ongoing",
   646  			args: args{
   647  				validator: &ethpb.Validator{
   648  					ActivationEpoch: 3,
   649  					ExitEpoch:       farFutureEpoch,
   650  				},
   651  				epoch: types.Epoch(5),
   652  			},
   653  			want: ethpb.ValidatorStatus_ACTIVE,
   654  		},
   655  		{
   656  			name: "active slashed",
   657  			args: args{
   658  				validator: &ethpb.Validator{
   659  					ActivationEpoch: 3,
   660  					ExitEpoch:       30,
   661  					Slashed:         true,
   662  				},
   663  				epoch: types.Epoch(5),
   664  			},
   665  			want: ethpb.ValidatorStatus_ACTIVE,
   666  		},
   667  		{
   668  			name: "active exiting",
   669  			args: args{
   670  				validator: &ethpb.Validator{
   671  					ActivationEpoch: 3,
   672  					ExitEpoch:       30,
   673  					Slashed:         false,
   674  				},
   675  				epoch: types.Epoch(5),
   676  			},
   677  			want: ethpb.ValidatorStatus_ACTIVE,
   678  		},
   679  		{
   680  			name: "exited slashed",
   681  			args: args{
   682  				validator: &ethpb.Validator{
   683  					ActivationEpoch:   3,
   684  					ExitEpoch:         30,
   685  					WithdrawableEpoch: 40,
   686  					Slashed:           true,
   687  				},
   688  				epoch: types.Epoch(35),
   689  			},
   690  			want: ethpb.ValidatorStatus_EXITED,
   691  		},
   692  		{
   693  			name: "exited unslashed",
   694  			args: args{
   695  				validator: &ethpb.Validator{
   696  					ActivationEpoch:   3,
   697  					ExitEpoch:         30,
   698  					WithdrawableEpoch: 40,
   699  					Slashed:           false,
   700  				},
   701  				epoch: types.Epoch(35),
   702  			},
   703  			want: ethpb.ValidatorStatus_EXITED,
   704  		},
   705  		{
   706  			name: "withdrawal possible",
   707  			args: args{
   708  				validator: &ethpb.Validator{
   709  					ActivationEpoch:   3,
   710  					ExitEpoch:         30,
   711  					WithdrawableEpoch: 40,
   712  					EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   713  					Slashed:           false,
   714  				},
   715  				epoch: types.Epoch(45),
   716  			},
   717  			want: ethpb.ValidatorStatus_WITHDRAWAL,
   718  		},
   719  		{
   720  			name: "withdrawal done",
   721  			args: args{
   722  				validator: &ethpb.Validator{
   723  					ActivationEpoch:   3,
   724  					ExitEpoch:         30,
   725  					WithdrawableEpoch: 40,
   726  					EffectiveBalance:  0,
   727  					Slashed:           false,
   728  				},
   729  				epoch: types.Epoch(45),
   730  			},
   731  			want: ethpb.ValidatorStatus_WITHDRAWAL,
   732  		},
   733  	}
   734  	for _, tt := range tests {
   735  		t.Run(tt.name, func(t *testing.T) {
   736  			got, err := validatorStatus(tt.args.validator, tt.args.epoch)
   737  			require.NoError(t, err)
   738  			if got != tt.want {
   739  				t.Errorf("validatorStatus() got = %v, want %v", got, tt.want)
   740  			}
   741  		})
   742  	}
   743  }
   744  
   745  func Test_validatorSubStatus(t *testing.T) {
   746  	farFutureEpoch := params.BeaconConfig().FarFutureEpoch
   747  
   748  	type args struct {
   749  		validator *ethpb.Validator
   750  		epoch     types.Epoch
   751  	}
   752  	tests := []struct {
   753  		name    string
   754  		args    args
   755  		want    ethpb.ValidatorStatus
   756  		wantErr bool
   757  	}{
   758  		{
   759  			name: "pending initialized",
   760  			args: args{
   761  				validator: &ethpb.Validator{
   762  					ActivationEpoch:            farFutureEpoch,
   763  					ActivationEligibilityEpoch: farFutureEpoch,
   764  				},
   765  				epoch: types.Epoch(5),
   766  			},
   767  			want: ethpb.ValidatorStatus_PENDING_INITIALIZED,
   768  		},
   769  		{
   770  			name: "pending queued",
   771  			args: args{
   772  				validator: &ethpb.Validator{
   773  					ActivationEpoch:            10,
   774  					ActivationEligibilityEpoch: 2,
   775  				},
   776  				epoch: types.Epoch(5),
   777  			},
   778  			want: ethpb.ValidatorStatus_PENDING_QUEUED,
   779  		},
   780  		{
   781  			name: "active ongoing",
   782  			args: args{
   783  				validator: &ethpb.Validator{
   784  					ActivationEpoch: 3,
   785  					ExitEpoch:       farFutureEpoch,
   786  				},
   787  				epoch: types.Epoch(5),
   788  			},
   789  			want: ethpb.ValidatorStatus_ACTIVE_ONGOING,
   790  		},
   791  		{
   792  			name: "active slashed",
   793  			args: args{
   794  				validator: &ethpb.Validator{
   795  					ActivationEpoch: 3,
   796  					ExitEpoch:       30,
   797  					Slashed:         true,
   798  				},
   799  				epoch: types.Epoch(5),
   800  			},
   801  			want: ethpb.ValidatorStatus_ACTIVE_SLASHED,
   802  		},
   803  		{
   804  			name: "active exiting",
   805  			args: args{
   806  				validator: &ethpb.Validator{
   807  					ActivationEpoch: 3,
   808  					ExitEpoch:       30,
   809  					Slashed:         false,
   810  				},
   811  				epoch: types.Epoch(5),
   812  			},
   813  			want: ethpb.ValidatorStatus_ACTIVE_EXITING,
   814  		},
   815  		{
   816  			name: "exited slashed",
   817  			args: args{
   818  				validator: &ethpb.Validator{
   819  					ActivationEpoch:   3,
   820  					ExitEpoch:         30,
   821  					WithdrawableEpoch: 40,
   822  					Slashed:           true,
   823  				},
   824  				epoch: types.Epoch(35),
   825  			},
   826  			want: ethpb.ValidatorStatus_EXITED_SLASHED,
   827  		},
   828  		{
   829  			name: "exited unslashed",
   830  			args: args{
   831  				validator: &ethpb.Validator{
   832  					ActivationEpoch:   3,
   833  					ExitEpoch:         30,
   834  					WithdrawableEpoch: 40,
   835  					Slashed:           false,
   836  				},
   837  				epoch: types.Epoch(35),
   838  			},
   839  			want: ethpb.ValidatorStatus_EXITED_UNSLASHED,
   840  		},
   841  		{
   842  			name: "withdrawal possible",
   843  			args: args{
   844  				validator: &ethpb.Validator{
   845  					ActivationEpoch:   3,
   846  					ExitEpoch:         30,
   847  					WithdrawableEpoch: 40,
   848  					EffectiveBalance:  params.BeaconConfig().MaxEffectiveBalance,
   849  					Slashed:           false,
   850  				},
   851  				epoch: types.Epoch(45),
   852  			},
   853  			want: ethpb.ValidatorStatus_WITHDRAWAL_POSSIBLE,
   854  		},
   855  		{
   856  			name: "withdrawal done",
   857  			args: args{
   858  				validator: &ethpb.Validator{
   859  					ActivationEpoch:   3,
   860  					ExitEpoch:         30,
   861  					WithdrawableEpoch: 40,
   862  					EffectiveBalance:  0,
   863  					Slashed:           false,
   864  				},
   865  				epoch: types.Epoch(45),
   866  			},
   867  			want: ethpb.ValidatorStatus_WITHDRAWAL_DONE,
   868  		},
   869  	}
   870  	for _, tt := range tests {
   871  		t.Run(tt.name, func(t *testing.T) {
   872  			got, err := validatorSubStatus(tt.args.validator, tt.args.epoch)
   873  			require.NoError(t, err)
   874  			if got != tt.want {
   875  				t.Errorf("validatorSubStatus() got = %v, want %v", got, tt.want)
   876  			}
   877  		})
   878  	}
   879  }
   880  
   881  // This test verifies how many validator statuses have meaningful values.
   882  // The first expected non-meaningful value will have x.String() equal to its numeric representation.
   883  // This test assumes we start numbering from 0 and do not skip any values.
   884  // Having a test like this allows us to use e.g. `if value < 10` for validity checks.
   885  func TestNumberOfStatuses(t *testing.T) {
   886  	lastValidEnumValue := 12
   887  	x := ethpb.ValidatorStatus(lastValidEnumValue)
   888  	assert.NotEqual(t, strconv.Itoa(lastValidEnumValue), x.String())
   889  	x = ethpb.ValidatorStatus(lastValidEnumValue + 1)
   890  	assert.Equal(t, strconv.Itoa(lastValidEnumValue+1), x.String())
   891  }