github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/status_test.go (about)

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    13  	dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    14  	mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
    15  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    17  	v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    18  	mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
    19  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    20  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    21  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    22  	"github.com/prysmaticlabs/prysm/shared/bls"
    23  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    24  	"github.com/prysmaticlabs/prysm/shared/params"
    25  	"github.com/prysmaticlabs/prysm/shared/testutil"
    26  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    27  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    28  	"github.com/prysmaticlabs/prysm/shared/trieutil"
    29  	"google.golang.org/protobuf/proto"
    30  )
    31  
    32  func TestValidatorStatus_DepositedEth1(t *testing.T) {
    33  	db := dbutil.SetupDB(t)
    34  	ctx := context.Background()
    35  	deposits, _, err := testutil.DeterministicDepositsAndKeys(1)
    36  	require.NoError(t, err, "Could not generate deposits and keys")
    37  	deposit := deposits[0]
    38  	pubKey1 := deposit.Data.PublicKey
    39  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
    40  	require.NoError(t, err, "Could not setup deposit trie")
    41  	depositCache, err := depositcache.New()
    42  	require.NoError(t, err)
    43  
    44  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
    45  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
    46  	p := &mockPOW.POWChain{
    47  		TimesByHeight: map[int]uint64{
    48  			0: uint64(height),
    49  		},
    50  	}
    51  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{})
    52  	require.NoError(t, err)
    53  	vs := &Server{
    54  		BeaconDB:       db,
    55  		DepositFetcher: depositCache,
    56  		BlockFetcher:   p,
    57  		HeadFetcher: &mockChain.ChainService{
    58  			State: stateObj,
    59  		},
    60  		Eth1InfoFetcher: p,
    61  	}
    62  	req := &ethpb.ValidatorStatusRequest{
    63  		PublicKey: pubKey1,
    64  	}
    65  	resp, err := vs.ValidatorStatus(context.Background(), req)
    66  	require.NoError(t, err, "Could not get validator status")
    67  	assert.Equal(t, ethpb.ValidatorStatus_DEPOSITED, resp.Status)
    68  }
    69  
    70  func TestValidatorStatus_Deposited(t *testing.T) {
    71  	db := dbutil.SetupDB(t)
    72  	ctx := context.Background()
    73  
    74  	pubKey1 := pubKey(1)
    75  	depData := &ethpb.Deposit_Data{
    76  		Amount:                params.BeaconConfig().MaxEffectiveBalance,
    77  		PublicKey:             pubKey1,
    78  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
    79  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
    80  	}
    81  	deposit := &ethpb.Deposit{
    82  		Data: depData,
    83  	}
    84  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
    85  	require.NoError(t, err, "Could not setup deposit trie")
    86  	depositCache, err := depositcache.New()
    87  	require.NoError(t, err)
    88  
    89  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
    90  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
    91  	p := &mockPOW.POWChain{
    92  		TimesByHeight: map[int]uint64{
    93  			0: uint64(height),
    94  		},
    95  	}
    96  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
    97  		Validators: []*ethpb.Validator{
    98  			{
    99  				PublicKey:                  pubKey1,
   100  				ActivationEligibilityEpoch: 1,
   101  			},
   102  		},
   103  	})
   104  	require.NoError(t, err)
   105  	vs := &Server{
   106  		BeaconDB:       db,
   107  		DepositFetcher: depositCache,
   108  		BlockFetcher:   p,
   109  		HeadFetcher: &mockChain.ChainService{
   110  			State: stateObj,
   111  		},
   112  		Eth1InfoFetcher: p,
   113  	}
   114  	req := &ethpb.ValidatorStatusRequest{
   115  		PublicKey: pubKey1,
   116  	}
   117  	resp, err := vs.ValidatorStatus(context.Background(), req)
   118  	require.NoError(t, err, "Could not get validator status")
   119  	assert.Equal(t, ethpb.ValidatorStatus_DEPOSITED, resp.Status)
   120  }
   121  
   122  func TestValidatorStatus_PartiallyDeposited(t *testing.T) {
   123  	db := dbutil.SetupDB(t)
   124  	ctx := context.Background()
   125  
   126  	pubKey1 := pubKey(1)
   127  	depData := &ethpb.Deposit_Data{
   128  		Amount:                params.BeaconConfig().MinDepositAmount,
   129  		PublicKey:             pubKey1,
   130  		Signature:             []byte("hi"),
   131  		WithdrawalCredentials: []byte("hey"),
   132  	}
   133  	deposit := &ethpb.Deposit{
   134  		Data: depData,
   135  	}
   136  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   137  	require.NoError(t, err, "Could not setup deposit trie")
   138  	depositCache, err := depositcache.New()
   139  	require.NoError(t, err)
   140  
   141  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   142  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   143  	p := &mockPOW.POWChain{
   144  		TimesByHeight: map[int]uint64{
   145  			0: uint64(height),
   146  		},
   147  	}
   148  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
   149  		Validators: []*ethpb.Validator{
   150  			{
   151  				PublicKey:                  pubKey1,
   152  				ActivationEligibilityEpoch: 1,
   153  			},
   154  		},
   155  	})
   156  	require.NoError(t, err)
   157  	vs := &Server{
   158  		BeaconDB:       db,
   159  		DepositFetcher: depositCache,
   160  		BlockFetcher:   p,
   161  		HeadFetcher: &mockChain.ChainService{
   162  			State: stateObj,
   163  		},
   164  		Eth1InfoFetcher: p,
   165  	}
   166  	req := &ethpb.ValidatorStatusRequest{
   167  		PublicKey: pubKey1,
   168  	}
   169  	resp, err := vs.ValidatorStatus(context.Background(), req)
   170  	require.NoError(t, err, "Could not get validator status")
   171  	assert.Equal(t, ethpb.ValidatorStatus_PARTIALLY_DEPOSITED, resp.Status)
   172  }
   173  
   174  func TestValidatorStatus_Pending(t *testing.T) {
   175  	db := dbutil.SetupDB(t)
   176  	ctx := context.Background()
   177  
   178  	pubKey := pubKey(1)
   179  	block := testutil.NewBeaconBlock()
   180  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   181  	genesisRoot, err := block.Block.HashTreeRoot()
   182  	require.NoError(t, err, "Could not get signing root")
   183  	// Pending active because activation epoch is still defaulted at far future slot.
   184  	state, err := testutil.NewBeaconState()
   185  	require.NoError(t, err)
   186  	require.NoError(t, state.SetSlot(5000))
   187  	err = state.SetValidators([]*ethpb.Validator{
   188  		{
   189  			ActivationEpoch:       params.BeaconConfig().FarFutureEpoch,
   190  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   191  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   192  			PublicKey:             pubKey,
   193  			WithdrawalCredentials: make([]byte, 32),
   194  		},
   195  	})
   196  	require.NoError(t, err)
   197  	require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save state")
   198  	require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
   199  
   200  	depData := &ethpb.Deposit_Data{
   201  		PublicKey:             pubKey,
   202  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
   203  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   204  	}
   205  
   206  	deposit := &ethpb.Deposit{
   207  		Data: depData,
   208  	}
   209  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   210  	require.NoError(t, err, "Could not setup deposit trie")
   211  	depositCache, err := depositcache.New()
   212  	require.NoError(t, err)
   213  
   214  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   215  
   216  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   217  	p := &mockPOW.POWChain{
   218  		TimesByHeight: map[int]uint64{
   219  			0: uint64(height),
   220  		},
   221  	}
   222  	vs := &Server{
   223  		BeaconDB:          db,
   224  		ChainStartFetcher: p,
   225  		BlockFetcher:      p,
   226  		Eth1InfoFetcher:   p,
   227  		DepositFetcher:    depositCache,
   228  		HeadFetcher:       &mockChain.ChainService{State: state, Root: genesisRoot[:]},
   229  	}
   230  	req := &ethpb.ValidatorStatusRequest{
   231  		PublicKey: pubKey,
   232  	}
   233  	resp, err := vs.ValidatorStatus(context.Background(), req)
   234  	require.NoError(t, err, "Could not get validator status")
   235  	assert.Equal(t, ethpb.ValidatorStatus_PENDING, resp.Status)
   236  }
   237  
   238  func TestValidatorStatus_Active(t *testing.T) {
   239  	db := dbutil.SetupDB(t)
   240  	// This test breaks if it doesnt use mainnet config
   241  	params.SetupTestConfigCleanup(t)
   242  	params.OverrideBeaconConfig(params.MainnetConfig())
   243  	ctx := context.Background()
   244  
   245  	pubKey := pubKey(1)
   246  
   247  	depData := &ethpb.Deposit_Data{
   248  		PublicKey:             pubKey,
   249  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
   250  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   251  	}
   252  
   253  	deposit := &ethpb.Deposit{
   254  		Data: depData,
   255  	}
   256  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   257  	require.NoError(t, err, "Could not setup deposit trie")
   258  	depositCache, err := depositcache.New()
   259  	require.NoError(t, err)
   260  
   261  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   262  
   263  	// Active because activation epoch <= current epoch < exit epoch.
   264  	activeEpoch := helpers.ActivationExitEpoch(0)
   265  
   266  	block := testutil.NewBeaconBlock()
   267  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   268  	genesisRoot, err := block.Block.HashTreeRoot()
   269  	require.NoError(t, err, "Could not get signing root")
   270  
   271  	state := &pbp2p.BeaconState{
   272  		GenesisTime: uint64(time.Unix(0, 0).Unix()),
   273  		Slot:        10000,
   274  		Validators: []*ethpb.Validator{{
   275  			ActivationEpoch:   activeEpoch,
   276  			ExitEpoch:         params.BeaconConfig().FarFutureEpoch,
   277  			WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
   278  			PublicKey:         pubKey},
   279  		}}
   280  	stateObj, err := v1.InitializeFromProtoUnsafe(state)
   281  	require.NoError(t, err)
   282  
   283  	timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   284  	p := &mockPOW.POWChain{
   285  		TimesByHeight: map[int]uint64{
   286  			int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
   287  		},
   288  	}
   289  	vs := &Server{
   290  		BeaconDB:          db,
   291  		ChainStartFetcher: p,
   292  		BlockFetcher:      p,
   293  		Eth1InfoFetcher:   p,
   294  		DepositFetcher:    depositCache,
   295  		HeadFetcher:       &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   296  	}
   297  	req := &ethpb.ValidatorStatusRequest{
   298  		PublicKey: pubKey,
   299  	}
   300  	resp, err := vs.ValidatorStatus(context.Background(), req)
   301  	require.NoError(t, err, "Could not get validator status")
   302  
   303  	expected := &ethpb.ValidatorStatusResponse{
   304  		Status:          ethpb.ValidatorStatus_ACTIVE,
   305  		ActivationEpoch: 5,
   306  	}
   307  	if !proto.Equal(resp, expected) {
   308  		t.Errorf("Wanted %v, got %v", expected, resp)
   309  	}
   310  }
   311  
   312  func TestValidatorStatus_Exiting(t *testing.T) {
   313  	db := dbutil.SetupDB(t)
   314  	ctx := context.Background()
   315  
   316  	pubKey := pubKey(1)
   317  
   318  	// Initiated exit because validator exit epoch and withdrawable epoch are not FAR_FUTURE_EPOCH
   319  	slot := types.Slot(10000)
   320  	epoch := helpers.SlotToEpoch(slot)
   321  	exitEpoch := helpers.ActivationExitEpoch(epoch)
   322  	withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay
   323  	block := testutil.NewBeaconBlock()
   324  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   325  	genesisRoot, err := block.Block.HashTreeRoot()
   326  	require.NoError(t, err, "Could not get signing root")
   327  
   328  	state := &pbp2p.BeaconState{
   329  		Slot: slot,
   330  		Validators: []*ethpb.Validator{{
   331  			PublicKey:         pubKey,
   332  			ActivationEpoch:   0,
   333  			ExitEpoch:         exitEpoch,
   334  			WithdrawableEpoch: withdrawableEpoch},
   335  		}}
   336  	stateObj, err := v1.InitializeFromProtoUnsafe(state)
   337  	require.NoError(t, err)
   338  	depData := &ethpb.Deposit_Data{
   339  		PublicKey:             pubKey,
   340  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
   341  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   342  	}
   343  
   344  	deposit := &ethpb.Deposit{
   345  		Data: depData,
   346  	}
   347  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   348  	require.NoError(t, err, "Could not setup deposit trie")
   349  	depositCache, err := depositcache.New()
   350  	require.NoError(t, err)
   351  
   352  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   353  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   354  	p := &mockPOW.POWChain{
   355  		TimesByHeight: map[int]uint64{
   356  			0: uint64(height),
   357  		},
   358  	}
   359  	vs := &Server{
   360  		BeaconDB:          db,
   361  		ChainStartFetcher: p,
   362  		BlockFetcher:      p,
   363  		Eth1InfoFetcher:   p,
   364  		DepositFetcher:    depositCache,
   365  		HeadFetcher:       &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   366  	}
   367  	req := &ethpb.ValidatorStatusRequest{
   368  		PublicKey: pubKey,
   369  	}
   370  	resp, err := vs.ValidatorStatus(context.Background(), req)
   371  	require.NoError(t, err, "Could not get validator status")
   372  	assert.Equal(t, ethpb.ValidatorStatus_EXITING, resp.Status)
   373  }
   374  
   375  func TestValidatorStatus_Slashing(t *testing.T) {
   376  	db := dbutil.SetupDB(t)
   377  	ctx := context.Background()
   378  
   379  	pubKey := pubKey(1)
   380  
   381  	// Exit slashed because slashed is true, exit epoch is =< current epoch and withdrawable epoch > epoch .
   382  	slot := types.Slot(10000)
   383  	epoch := helpers.SlotToEpoch(slot)
   384  	block := testutil.NewBeaconBlock()
   385  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   386  	genesisRoot, err := block.Block.HashTreeRoot()
   387  	require.NoError(t, err, "Could not get signing root")
   388  
   389  	state := &pbp2p.BeaconState{
   390  		Slot: slot,
   391  		Validators: []*ethpb.Validator{{
   392  			Slashed:           true,
   393  			PublicKey:         pubKey,
   394  			WithdrawableEpoch: epoch + 1},
   395  		}}
   396  	stateObj, err := v1.InitializeFromProtoUnsafe(state)
   397  	require.NoError(t, err)
   398  	depData := &ethpb.Deposit_Data{
   399  		PublicKey:             pubKey,
   400  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
   401  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   402  	}
   403  
   404  	deposit := &ethpb.Deposit{
   405  		Data: depData,
   406  	}
   407  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   408  	require.NoError(t, err, "Could not setup deposit trie")
   409  	depositCache, err := depositcache.New()
   410  	require.NoError(t, err)
   411  
   412  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   413  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   414  	p := &mockPOW.POWChain{
   415  		TimesByHeight: map[int]uint64{
   416  			0: uint64(height),
   417  		},
   418  	}
   419  	vs := &Server{
   420  		BeaconDB:          db,
   421  		ChainStartFetcher: p,
   422  		Eth1InfoFetcher:   p,
   423  		DepositFetcher:    depositCache,
   424  		BlockFetcher:      p,
   425  		HeadFetcher:       &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   426  	}
   427  	req := &ethpb.ValidatorStatusRequest{
   428  		PublicKey: pubKey,
   429  	}
   430  	resp, err := vs.ValidatorStatus(context.Background(), req)
   431  	require.NoError(t, err, "Could not get validator status")
   432  	assert.Equal(t, ethpb.ValidatorStatus_EXITED, resp.Status)
   433  }
   434  
   435  func TestValidatorStatus_Exited(t *testing.T) {
   436  	db := dbutil.SetupDB(t)
   437  	ctx := context.Background()
   438  
   439  	pubKey := pubKey(1)
   440  
   441  	// Exit because only exit epoch is =< current epoch.
   442  	slot := types.Slot(10000)
   443  	epoch := helpers.SlotToEpoch(slot)
   444  	block := testutil.NewBeaconBlock()
   445  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   446  	genesisRoot, err := block.Block.HashTreeRoot()
   447  	require.NoError(t, err, "Could not get signing root")
   448  	params.SetupTestConfigCleanup(t)
   449  	params.OverrideBeaconConfig(params.MainnetConfig())
   450  	numDeposits := uint64(64)
   451  	beaconState, _ := testutil.DeterministicGenesisState(t, numDeposits)
   452  	require.NoError(t, db.SaveState(ctx, beaconState, genesisRoot))
   453  	require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
   454  	state, err := testutil.NewBeaconState()
   455  	require.NoError(t, err)
   456  	require.NoError(t, state.SetSlot(slot))
   457  	err = state.SetValidators([]*ethpb.Validator{{
   458  		PublicKey:             pubKey,
   459  		WithdrawableEpoch:     epoch + 1,
   460  		WithdrawalCredentials: make([]byte, 32)},
   461  	})
   462  	require.NoError(t, err)
   463  	depData := &ethpb.Deposit_Data{
   464  		PublicKey:             pubKey,
   465  		Signature:             bytesutil.PadTo([]byte("hi"), 96),
   466  		WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   467  	}
   468  
   469  	deposit := &ethpb.Deposit{
   470  		Data: depData,
   471  	}
   472  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   473  	require.NoError(t, err, "Could not setup deposit trie")
   474  	depositCache, err := depositcache.New()
   475  	require.NoError(t, err)
   476  
   477  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   478  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   479  	p := &mockPOW.POWChain{
   480  		TimesByHeight: map[int]uint64{
   481  			0: uint64(height),
   482  		},
   483  	}
   484  	vs := &Server{
   485  		BeaconDB:          db,
   486  		ChainStartFetcher: p,
   487  		Eth1InfoFetcher:   p,
   488  		BlockFetcher:      p,
   489  		DepositFetcher:    depositCache,
   490  		HeadFetcher:       &mockChain.ChainService{State: state, Root: genesisRoot[:]},
   491  	}
   492  	req := &ethpb.ValidatorStatusRequest{
   493  		PublicKey: pubKey,
   494  	}
   495  	resp, err := vs.ValidatorStatus(context.Background(), req)
   496  	require.NoError(t, err, "Could not get validator status")
   497  	assert.Equal(t, ethpb.ValidatorStatus_EXITED, resp.Status)
   498  }
   499  
   500  func TestValidatorStatus_UnknownStatus(t *testing.T) {
   501  	db := dbutil.SetupDB(t)
   502  	pubKey := pubKey(1)
   503  	depositCache, err := depositcache.New()
   504  	require.NoError(t, err)
   505  
   506  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
   507  		Slot: 0,
   508  	})
   509  	require.NoError(t, err)
   510  	vs := &Server{
   511  		DepositFetcher:  depositCache,
   512  		Eth1InfoFetcher: &mockPOW.POWChain{},
   513  		HeadFetcher: &mockChain.ChainService{
   514  			State: stateObj,
   515  		},
   516  		BeaconDB: db,
   517  	}
   518  	req := &ethpb.ValidatorStatusRequest{
   519  		PublicKey: pubKey,
   520  	}
   521  	resp, err := vs.ValidatorStatus(context.Background(), req)
   522  	require.NoError(t, err, "Could not get validator status")
   523  	assert.Equal(t, ethpb.ValidatorStatus_UNKNOWN_STATUS, resp.Status)
   524  }
   525  
   526  func TestActivationStatus_OK(t *testing.T) {
   527  	db := dbutil.SetupDB(t)
   528  	ctx := context.Background()
   529  
   530  	deposits, _, err := testutil.DeterministicDepositsAndKeys(4)
   531  	require.NoError(t, err)
   532  	pubKeys := [][]byte{deposits[0].Data.PublicKey, deposits[1].Data.PublicKey, deposits[2].Data.PublicKey, deposits[3].Data.PublicKey}
   533  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
   534  		Slot: 4000,
   535  		Validators: []*ethpb.Validator{
   536  			{
   537  				ActivationEpoch: 0,
   538  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   539  				PublicKey:       pubKeys[0],
   540  			},
   541  			{
   542  				ActivationEpoch: 0,
   543  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   544  				PublicKey:       pubKeys[1],
   545  			},
   546  			{
   547  				ActivationEligibilityEpoch: 700,
   548  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   549  				PublicKey:                  pubKeys[3],
   550  				EffectiveBalance:           params.BeaconConfig().MaxEffectiveBalance,
   551  			},
   552  		},
   553  	})
   554  	require.NoError(t, err)
   555  	block := testutil.NewBeaconBlock()
   556  	genesisRoot, err := block.Block.HashTreeRoot()
   557  	require.NoError(t, err, "Could not get signing root")
   558  	dep := deposits[0]
   559  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   560  	require.NoError(t, err, "Could not setup deposit trie")
   561  	depositCache, err := depositcache.New()
   562  	require.NoError(t, err)
   563  
   564  	assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.Root()))
   565  
   566  	dep = deposits[2]
   567  	depositTrie.Insert(dep.Data.Signature, 15)
   568  	assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.Root()))
   569  
   570  	vs := &Server{
   571  		BeaconDB:           db,
   572  		Ctx:                context.Background(),
   573  		CanonicalStateChan: make(chan *pbp2p.BeaconState, 1),
   574  		ChainStartFetcher:  &mockPOW.POWChain{},
   575  		BlockFetcher:       &mockPOW.POWChain{},
   576  		Eth1InfoFetcher:    &mockPOW.POWChain{},
   577  		DepositFetcher:     depositCache,
   578  		HeadFetcher:        &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   579  	}
   580  	activeExists, response, err := vs.activationStatus(context.Background(), pubKeys)
   581  	require.NoError(t, err)
   582  	require.Equal(t, true, activeExists, "No activated validator exists when there was supposed to be 2")
   583  	if response[0].Status.Status != ethpb.ValidatorStatus_ACTIVE {
   584  		t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s",
   585  			response[0].PublicKey, response[0].Status.Status.String())
   586  	}
   587  	if response[0].Index != 0 {
   588  		t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[0].PublicKey, 0, response[0].Index)
   589  	}
   590  
   591  	if response[1].Status.Status != ethpb.ValidatorStatus_ACTIVE {
   592  		t.Errorf("Validator with pubkey %#x was activated when not supposed to",
   593  			response[1].PublicKey)
   594  	}
   595  	if response[1].Index != 1 {
   596  		t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[1].PublicKey, 1, response[1].Index)
   597  	}
   598  
   599  	if response[2].Status.Status != ethpb.ValidatorStatus_DEPOSITED {
   600  		t.Errorf("Validator with pubkey %#x is not unknown and instead has this status: %s",
   601  			response[2].PublicKey, response[2].Status.Status.String())
   602  	}
   603  	if uint64(response[2].Index) != uint64(params.BeaconConfig().FarFutureEpoch) {
   604  		t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[2].PublicKey, params.BeaconConfig().FarFutureEpoch, response[2].Index)
   605  	}
   606  
   607  	if response[3].Status.Status != ethpb.ValidatorStatus_DEPOSITED {
   608  		t.Errorf("Validator with pubkey %#x was not deposited and has this status: %s",
   609  			response[3].PublicKey, response[3].Status.Status.String())
   610  	}
   611  	if response[3].Index != 2 {
   612  		t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[3].PublicKey, 2, response[3].Index)
   613  	}
   614  }
   615  
   616  func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
   617  	db := dbutil.SetupDB(t)
   618  	ctx := context.Background()
   619  
   620  	pbKey := pubKey(5)
   621  	block := testutil.NewBeaconBlock()
   622  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block")
   623  	genesisRoot, err := block.Block.HashTreeRoot()
   624  	require.NoError(t, err, "Could not get signing root")
   625  	currentSlot := types.Slot(5000)
   626  	// Pending active because activation epoch is still defaulted at far future slot.
   627  	validators := []*ethpb.Validator{
   628  		{
   629  			ActivationEpoch:       0,
   630  			PublicKey:             pubKey(0),
   631  			WithdrawalCredentials: make([]byte, 32),
   632  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   633  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   634  		},
   635  		{
   636  			ActivationEpoch:       0,
   637  			PublicKey:             pubKey(1),
   638  			WithdrawalCredentials: make([]byte, 32),
   639  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   640  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   641  		},
   642  		{
   643  			ActivationEpoch:       0,
   644  			PublicKey:             pubKey(2),
   645  			WithdrawalCredentials: make([]byte, 32),
   646  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   647  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   648  		},
   649  		{
   650  			ActivationEpoch:       0,
   651  			PublicKey:             pubKey(3),
   652  			WithdrawalCredentials: make([]byte, 32),
   653  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   654  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   655  		},
   656  		{
   657  			ActivationEpoch:       types.Epoch(currentSlot/params.BeaconConfig().SlotsPerEpoch + 1),
   658  			PublicKey:             pbKey,
   659  			WithdrawalCredentials: make([]byte, 32),
   660  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   661  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   662  		},
   663  		{
   664  			ActivationEpoch:       types.Epoch(currentSlot/params.BeaconConfig().SlotsPerEpoch + 4),
   665  			PublicKey:             pubKey(5),
   666  			WithdrawalCredentials: make([]byte, 32),
   667  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   668  			WithdrawableEpoch:     params.BeaconConfig().FarFutureEpoch,
   669  		},
   670  	}
   671  	state, err := testutil.NewBeaconState()
   672  	require.NoError(t, err)
   673  	require.NoError(t, state.SetValidators(validators))
   674  	require.NoError(t, state.SetSlot(currentSlot))
   675  	require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save state")
   676  	require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
   677  
   678  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   679  	require.NoError(t, err, "Could not setup deposit trie")
   680  	depositCache, err := depositcache.New()
   681  	require.NoError(t, err)
   682  
   683  	for i := 0; i < 6; i++ {
   684  		depData := &ethpb.Deposit_Data{
   685  			PublicKey:             pubKey(uint64(i)),
   686  			Signature:             bytesutil.PadTo([]byte("hi"), 96),
   687  			WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32),
   688  		}
   689  
   690  		deposit := &ethpb.Deposit{
   691  			Data: depData,
   692  		}
   693  		assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, int64(i), depositTrie.Root()))
   694  
   695  	}
   696  
   697  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   698  	p := &mockPOW.POWChain{
   699  		TimesByHeight: map[int]uint64{
   700  			0: uint64(height),
   701  		},
   702  	}
   703  	vs := &Server{
   704  		BeaconDB:          db,
   705  		ChainStartFetcher: p,
   706  		BlockFetcher:      p,
   707  		Eth1InfoFetcher:   p,
   708  		DepositFetcher:    depositCache,
   709  		HeadFetcher:       &mockChain.ChainService{State: state, Root: genesisRoot[:]},
   710  	}
   711  	req := &ethpb.ValidatorStatusRequest{
   712  		PublicKey: pbKey,
   713  	}
   714  	resp, err := vs.ValidatorStatus(context.Background(), req)
   715  	require.NoError(t, err, "Could not get validator status")
   716  	assert.Equal(t, ethpb.ValidatorStatus_PENDING, resp.Status)
   717  	assert.Equal(t, uint64(2), resp.PositionInActivationQueue, "Unexpected position in activation queue")
   718  }
   719  
   720  func TestMultipleValidatorStatus_Pubkeys(t *testing.T) {
   721  	db := dbutil.SetupDB(t)
   722  	ctx := context.Background()
   723  
   724  	deposits, _, err := testutil.DeterministicDepositsAndKeys(6)
   725  	require.NoError(t, err)
   726  	pubKeys := [][]byte{
   727  		deposits[0].Data.PublicKey,
   728  		deposits[1].Data.PublicKey,
   729  		deposits[2].Data.PublicKey,
   730  		deposits[3].Data.PublicKey,
   731  		deposits[4].Data.PublicKey,
   732  		deposits[5].Data.PublicKey,
   733  	}
   734  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
   735  		Slot: 4000,
   736  		Validators: []*ethpb.Validator{
   737  			{
   738  				ActivationEpoch: 0,
   739  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   740  				PublicKey:       pubKeys[0],
   741  			},
   742  			{
   743  				ActivationEpoch: 0,
   744  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   745  				PublicKey:       pubKeys[1],
   746  			},
   747  			{
   748  				ActivationEligibilityEpoch: 700,
   749  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   750  				PublicKey:                  pubKeys[3],
   751  				EffectiveBalance:           params.BeaconConfig().MaxEffectiveBalance,
   752  			},
   753  			{
   754  				ActivationEligibilityEpoch: 700,
   755  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   756  				PublicKey:                  pubKeys[4],
   757  				EffectiveBalance:           params.BeaconConfig().MinDepositAmount,
   758  			},
   759  			{
   760  				ActivationEligibilityEpoch: 700,
   761  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   762  				PublicKey:                  pubKeys[5],
   763  			},
   764  		},
   765  	})
   766  	require.NoError(t, err)
   767  	block := testutil.NewBeaconBlock()
   768  	genesisRoot, err := block.Block.HashTreeRoot()
   769  	require.NoError(t, err, "Could not get signing root")
   770  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   771  	require.NoError(t, err, "Could not setup deposit trie")
   772  	depositCache, err := depositcache.New()
   773  	require.NoError(t, err)
   774  
   775  	dep := deposits[0]
   776  	assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.Root()))
   777  	dep = deposits[2]
   778  	depositTrie.Insert(dep.Data.Signature, 15)
   779  	assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.Root()))
   780  
   781  	vs := &Server{
   782  		BeaconDB:           db,
   783  		Ctx:                context.Background(),
   784  		CanonicalStateChan: make(chan *pbp2p.BeaconState, 1),
   785  		ChainStartFetcher:  &mockPOW.POWChain{},
   786  		BlockFetcher:       &mockPOW.POWChain{},
   787  		Eth1InfoFetcher:    &mockPOW.POWChain{},
   788  		DepositFetcher:     depositCache,
   789  		HeadFetcher:        &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   790  		SyncChecker:        &mockSync.Sync{IsSyncing: false},
   791  	}
   792  
   793  	want := []*ethpb.ValidatorStatusResponse{
   794  		{
   795  			Status: ethpb.ValidatorStatus_ACTIVE,
   796  		},
   797  		{
   798  			Status: ethpb.ValidatorStatus_ACTIVE,
   799  		},
   800  		{
   801  			Status:          ethpb.ValidatorStatus_DEPOSITED,
   802  			ActivationEpoch: 18446744073709551615,
   803  		},
   804  		{
   805  			Status: ethpb.ValidatorStatus_DEPOSITED,
   806  		},
   807  		{
   808  			Status: ethpb.ValidatorStatus_PARTIALLY_DEPOSITED,
   809  		},
   810  		{
   811  			Status: ethpb.ValidatorStatus_PENDING,
   812  		},
   813  	}
   814  
   815  	req := &ethpb.MultipleValidatorStatusRequest{PublicKeys: pubKeys}
   816  	response, err := vs.MultipleValidatorStatus(context.Background(), req)
   817  	require.NoError(t, err)
   818  
   819  	assert.Equal(t, len(response.PublicKeys), len(pubKeys))
   820  	for i, resp := range response.PublicKeys {
   821  		require.DeepEqual(t, pubKeys[i], resp)
   822  	}
   823  	assert.Equal(t, len(pubKeys), len(response.Statuses))
   824  	for i, resp := range response.Statuses {
   825  		if !proto.Equal(want[i], resp) {
   826  			t.Fatalf("Wanted %v\n Recieved: %v\n", want[i], resp)
   827  		}
   828  	}
   829  }
   830  
   831  func TestMultipleValidatorStatus_Indices(t *testing.T) {
   832  	db := dbutil.SetupDB(t)
   833  	slot := types.Slot(10000)
   834  	epoch := helpers.SlotToEpoch(slot)
   835  	pubKeys := [][]byte{pubKey(1), pubKey(2), pubKey(3), pubKey(4), pubKey(5), pubKey(6), pubKey(7)}
   836  	beaconState := &pbp2p.BeaconState{
   837  		Slot: 4000,
   838  		Validators: []*ethpb.Validator{
   839  			{
   840  				ActivationEpoch: 0,
   841  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   842  				PublicKey:       pubKeys[0],
   843  			},
   844  			{
   845  				ActivationEpoch: 0,
   846  				ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   847  				PublicKey:       pubKeys[1],
   848  			},
   849  			{
   850  				ActivationEligibilityEpoch: 700,
   851  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   852  				PublicKey:                  pubKeys[2],
   853  				EffectiveBalance:           params.BeaconConfig().MaxEffectiveBalance,
   854  			},
   855  			{
   856  				Slashed:   true,
   857  				ExitEpoch: epoch + 1,
   858  				PublicKey: pubKeys[3],
   859  			},
   860  			{
   861  				ActivationEligibilityEpoch: 700,
   862  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   863  				PublicKey:                  pubKeys[4],
   864  				EffectiveBalance:           params.BeaconConfig().MinDepositAmount,
   865  			},
   866  			{
   867  				ActivationEligibilityEpoch: 700,
   868  				ExitEpoch:                  params.BeaconConfig().FarFutureEpoch,
   869  				PublicKey:                  pubKeys[5],
   870  			},
   871  		},
   872  	}
   873  	stateObj, err := v1.InitializeFromProtoUnsafe(beaconState)
   874  	require.NoError(t, err)
   875  	block := testutil.NewBeaconBlock()
   876  	genesisRoot, err := block.Block.HashTreeRoot()
   877  	require.NoError(t, err, "Could not get signing root")
   878  
   879  	vs := &Server{
   880  		BeaconDB:           db,
   881  		Ctx:                context.Background(),
   882  		CanonicalStateChan: make(chan *pbp2p.BeaconState, 1),
   883  		ChainStartFetcher:  &mockPOW.POWChain{},
   884  		BlockFetcher:       &mockPOW.POWChain{},
   885  		Eth1InfoFetcher:    &mockPOW.POWChain{},
   886  		HeadFetcher:        &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
   887  		SyncChecker:        &mockSync.Sync{IsSyncing: false},
   888  	}
   889  
   890  	want := []*ethpb.ValidatorStatusResponse{
   891  		{
   892  			Status: ethpb.ValidatorStatus_ACTIVE,
   893  		},
   894  		{
   895  			Status: ethpb.ValidatorStatus_ACTIVE,
   896  		},
   897  		{
   898  			Status: ethpb.ValidatorStatus_DEPOSITED,
   899  		},
   900  		{
   901  			Status: ethpb.ValidatorStatus_SLASHING,
   902  		},
   903  		{
   904  			Status: ethpb.ValidatorStatus_PARTIALLY_DEPOSITED,
   905  		},
   906  		{
   907  			Status: ethpb.ValidatorStatus_PENDING,
   908  		},
   909  	}
   910  
   911  	// Note: Index 6 should be skipped.
   912  	req := &ethpb.MultipleValidatorStatusRequest{Indices: []int64{0, 1, 2, 3, 4, 5, 6}}
   913  	response, err := vs.MultipleValidatorStatus(context.Background(), req)
   914  	require.NoError(t, err)
   915  
   916  	assert.Equal(t, len(beaconState.Validators), len(response.PublicKeys))
   917  	for i, resp := range response.PublicKeys {
   918  		expected := beaconState.Validators[i].PublicKey
   919  		require.DeepEqual(t, expected, resp)
   920  	}
   921  	assert.Equal(t, len(beaconState.Validators), len(response.Statuses))
   922  	for i, resp := range response.Statuses {
   923  		if !proto.Equal(want[i], resp) {
   924  			t.Fatalf("Wanted %v\n Recieved: %v\n", want[i], resp)
   925  		}
   926  	}
   927  }
   928  
   929  func TestValidatorStatus_Invalid(t *testing.T) {
   930  	db := dbutil.SetupDB(t)
   931  	ctx := context.Background()
   932  	deposits, _, err := testutil.DeterministicDepositsAndKeys(1)
   933  	require.NoError(t, err, "Could not generate deposits and keys")
   934  	deposit := deposits[0]
   935  	pubKey1 := deposit.Data.PublicKey
   936  	deposit.Data.Signature = deposit.Data.Signature[1:]
   937  	depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
   938  	require.NoError(t, err, "Could not setup deposit trie")
   939  	depositCache, err := depositcache.New()
   940  	require.NoError(t, err)
   941  
   942  	assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root()))
   943  	height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
   944  	p := &mockPOW.POWChain{
   945  		TimesByHeight: map[int]uint64{
   946  			0: uint64(height),
   947  		},
   948  	}
   949  	stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{})
   950  	require.NoError(t, err)
   951  	vs := &Server{
   952  		BeaconDB:       db,
   953  		DepositFetcher: depositCache,
   954  		BlockFetcher:   p,
   955  		HeadFetcher: &mockChain.ChainService{
   956  			State: stateObj,
   957  		},
   958  		Eth1InfoFetcher: p,
   959  	}
   960  	req := &ethpb.ValidatorStatusRequest{
   961  		PublicKey: pubKey1,
   962  	}
   963  	resp, err := vs.ValidatorStatus(context.Background(), req)
   964  	require.NoError(t, err, "Could not get validator status")
   965  	assert.Equal(t, ethpb.ValidatorStatus_INVALID, resp.Status)
   966  }
   967  
   968  func Test_DepositStatus(t *testing.T) {
   969  	assert.Equal(t, depositStatus(0), ethpb.ValidatorStatus_PENDING)
   970  	assert.Equal(t, depositStatus(params.BeaconConfig().MinDepositAmount), ethpb.ValidatorStatus_PARTIALLY_DEPOSITED)
   971  	assert.Equal(t, depositStatus(params.BeaconConfig().MaxEffectiveBalance), ethpb.ValidatorStatus_DEPOSITED)
   972  }
   973  
   974  func TestServer_CheckDoppelGanger(t *testing.T) {
   975  	tests := []struct {
   976  		name    string
   977  		wantErr bool
   978  		svSetup func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse)
   979  	}{
   980  		{
   981  			name:    "normal doppelganger request",
   982  			wantErr: false,
   983  			svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
   984  				db := dbutil.SetupDB(t)
   985  				mockGen := stategen.NewMockService()
   986  				hs, ps, os, keys := createStateSetup(t, 4, mockGen)
   987  				// Previous Epoch State
   988  				for i := 0; i < 3; i++ {
   989  					bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
   990  					assert.NoError(t, err)
   991  					// Add 100 gwei, to mock an inactivity leak
   992  					assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100))
   993  				}
   994  				// Older Epoch State
   995  				for i := 0; i < 3; i++ {
   996  					bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
   997  					assert.NoError(t, err)
   998  					// Add 200 gwei, to mock an inactivity leak
   999  					assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200))
  1000  				}
  1001  				vs := &Server{
  1002  					BeaconDB: db,
  1003  					StateGen: mockGen,
  1004  					HeadFetcher: &mockChain.ChainService{
  1005  						State: hs,
  1006  					},
  1007  					SyncChecker: &mockSync.Sync{IsSyncing: false},
  1008  				}
  1009  				request := &ethpb.DoppelGangerRequest{
  1010  					ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
  1011  				}
  1012  				response := &ethpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)}
  1013  				for i := 0; i < 3; i++ {
  1014  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1015  						PublicKey:  keys[i].PublicKey().Marshal(),
  1016  						Epoch:      1,
  1017  						SignedRoot: []byte{'A'},
  1018  					})
  1019  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1020  						PublicKey:       keys[i].PublicKey().Marshal(),
  1021  						DuplicateExists: false,
  1022  					})
  1023  				}
  1024  				return vs, request, response
  1025  			},
  1026  		},
  1027  		{
  1028  			name:    "doppelganger exists current epoch",
  1029  			wantErr: false,
  1030  			svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
  1031  				db := dbutil.SetupDB(t)
  1032  				mockGen := stategen.NewMockService()
  1033  
  1034  				hs, ps, os, keys := createStateSetup(t, 4, mockGen)
  1035  				// Previous Epoch State
  1036  				for i := 0; i < 2; i++ {
  1037  					bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
  1038  					assert.NoError(t, err)
  1039  					// Add 100 gwei, to mock an inactivity leak
  1040  					assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100))
  1041  				}
  1042  				bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2))
  1043  				assert.NoError(t, err)
  1044  				// Sub 100 gwei, to mock an active validator.
  1045  				assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100))
  1046  
  1047  				// Older Epoch State
  1048  				for i := 0; i < 2; i++ {
  1049  					bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
  1050  					assert.NoError(t, err)
  1051  					// Add 200 gwei, to mock an inactivity leak
  1052  					assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200))
  1053  				}
  1054  				bal, err = os.BalanceAtIndex(types.ValidatorIndex(2))
  1055  				assert.NoError(t, err)
  1056  				// Sub 100 gwei, to mock an active validator.
  1057  				assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100))
  1058  
  1059  				vs := &Server{
  1060  					BeaconDB: db,
  1061  					StateGen: mockGen,
  1062  					HeadFetcher: &mockChain.ChainService{
  1063  						State: hs,
  1064  					},
  1065  					SyncChecker: &mockSync.Sync{IsSyncing: false},
  1066  				}
  1067  				request := &ethpb.DoppelGangerRequest{
  1068  					ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
  1069  				}
  1070  				response := &ethpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)}
  1071  				for i := 0; i < 2; i++ {
  1072  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1073  						PublicKey:  keys[i].PublicKey().Marshal(),
  1074  						Epoch:      1,
  1075  						SignedRoot: []byte{'A'},
  1076  					})
  1077  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1078  						PublicKey:       keys[i].PublicKey().Marshal(),
  1079  						DuplicateExists: false,
  1080  					})
  1081  				}
  1082  
  1083  				// Add in for duplicate validator
  1084  				request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1085  					PublicKey:  keys[2].PublicKey().Marshal(),
  1086  					Epoch:      1,
  1087  					SignedRoot: []byte{'A'},
  1088  				})
  1089  				response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1090  					PublicKey:       keys[2].PublicKey().Marshal(),
  1091  					DuplicateExists: true,
  1092  				})
  1093  				return vs, request, response
  1094  			},
  1095  		},
  1096  		{
  1097  			name:    "doppelganger exists previous epoch",
  1098  			wantErr: false,
  1099  			svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
  1100  				db := dbutil.SetupDB(t)
  1101  				mockGen := stategen.NewMockService()
  1102  
  1103  				hs, ps, os, keys := createStateSetup(t, 4, mockGen)
  1104  				// Previous Epoch State
  1105  				for i := 0; i < 2; i++ {
  1106  					bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
  1107  					assert.NoError(t, err)
  1108  					// Add 100 gwei, to mock an inactivity leak
  1109  					assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100))
  1110  				}
  1111  				bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2))
  1112  				assert.NoError(t, err)
  1113  				// Sub 100 gwei, to mock an active validator.
  1114  				assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100))
  1115  
  1116  				// Older Epoch State
  1117  				for i := 0; i < 2; i++ {
  1118  					bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
  1119  					assert.NoError(t, err)
  1120  					// Add 200 gwei, to mock an inactivity leak
  1121  					assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200))
  1122  				}
  1123  				bal, err = os.BalanceAtIndex(types.ValidatorIndex(2))
  1124  				assert.NoError(t, err)
  1125  				// Sub 200 gwei, to mock an active validator.
  1126  				assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-200))
  1127  
  1128  				vs := &Server{
  1129  					BeaconDB: db,
  1130  					StateGen: mockGen,
  1131  					HeadFetcher: &mockChain.ChainService{
  1132  						State: hs,
  1133  					},
  1134  					SyncChecker: &mockSync.Sync{IsSyncing: false},
  1135  				}
  1136  				request := &ethpb.DoppelGangerRequest{
  1137  					ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
  1138  				}
  1139  				response := &ethpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)}
  1140  				for i := 0; i < 2; i++ {
  1141  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1142  						PublicKey:  keys[i].PublicKey().Marshal(),
  1143  						Epoch:      1,
  1144  						SignedRoot: []byte{'A'},
  1145  					})
  1146  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1147  						PublicKey:       keys[i].PublicKey().Marshal(),
  1148  						DuplicateExists: false,
  1149  					})
  1150  				}
  1151  
  1152  				// Add in for duplicate validator
  1153  				request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1154  					PublicKey:  keys[2].PublicKey().Marshal(),
  1155  					Epoch:      1,
  1156  					SignedRoot: []byte{'A'},
  1157  				})
  1158  				response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1159  					PublicKey:       keys[2].PublicKey().Marshal(),
  1160  					DuplicateExists: true,
  1161  				})
  1162  				return vs, request, response
  1163  			},
  1164  		},
  1165  		{
  1166  			name:    "multiple doppelganger exists",
  1167  			wantErr: false,
  1168  			svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
  1169  				db := dbutil.SetupDB(t)
  1170  				mockGen := stategen.NewMockService()
  1171  
  1172  				hs, ps, os, keys := createStateSetup(t, 4, mockGen)
  1173  				// Previous Epoch State
  1174  				for i := 10; i < 15; i++ {
  1175  					bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
  1176  					assert.NoError(t, err)
  1177  					// Add 100 gwei, to mock an inactivity leak
  1178  					assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-100))
  1179  				}
  1180  
  1181  				// Older Epoch State
  1182  				for i := 10; i < 15; i++ {
  1183  					bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
  1184  					assert.NoError(t, err)
  1185  					// Add 200 gwei, to mock an inactivity leak
  1186  					assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-200))
  1187  				}
  1188  
  1189  				vs := &Server{
  1190  					BeaconDB: db,
  1191  					StateGen: mockGen,
  1192  					HeadFetcher: &mockChain.ChainService{
  1193  						State: hs,
  1194  					},
  1195  					SyncChecker: &mockSync.Sync{IsSyncing: false},
  1196  				}
  1197  				request := &ethpb.DoppelGangerRequest{
  1198  					ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
  1199  				}
  1200  				response := &ethpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)}
  1201  				for i := 0; i < 10; i++ {
  1202  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1203  						PublicKey:  keys[i].PublicKey().Marshal(),
  1204  						Epoch:      1,
  1205  						SignedRoot: []byte{'A'},
  1206  					})
  1207  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1208  						PublicKey:       keys[i].PublicKey().Marshal(),
  1209  						DuplicateExists: false,
  1210  					})
  1211  				}
  1212  				for i := 10; i < 15; i++ {
  1213  					// Add in for duplicate validator
  1214  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1215  						PublicKey:  keys[i].PublicKey().Marshal(),
  1216  						Epoch:      1,
  1217  						SignedRoot: []byte{'A'},
  1218  					})
  1219  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1220  						PublicKey:       keys[i].PublicKey().Marshal(),
  1221  						DuplicateExists: true,
  1222  					})
  1223  				}
  1224  
  1225  				return vs, request, response
  1226  			},
  1227  		},
  1228  		{
  1229  			name:    "attesters are too recent",
  1230  			wantErr: false,
  1231  			svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) {
  1232  				db := dbutil.SetupDB(t)
  1233  				mockGen := stategen.NewMockService()
  1234  
  1235  				hs, ps, os, keys := createStateSetup(t, 4, mockGen)
  1236  				// Previous Epoch State
  1237  				for i := 10; i < 15; i++ {
  1238  					bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i))
  1239  					assert.NoError(t, err)
  1240  					// Add 100 gwei, to mock an active validator
  1241  					assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-100))
  1242  				}
  1243  
  1244  				// Older Epoch State
  1245  				for i := 10; i < 15; i++ {
  1246  					bal, err := os.BalanceAtIndex(types.ValidatorIndex(i))
  1247  					assert.NoError(t, err)
  1248  					// Add 200 gwei, to mock an active validator
  1249  					assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-200))
  1250  				}
  1251  
  1252  				vs := &Server{
  1253  					BeaconDB: db,
  1254  					StateGen: mockGen,
  1255  					HeadFetcher: &mockChain.ChainService{
  1256  						State: hs,
  1257  					},
  1258  					SyncChecker: &mockSync.Sync{IsSyncing: false},
  1259  				}
  1260  				request := &ethpb.DoppelGangerRequest{
  1261  					ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0),
  1262  				}
  1263  				response := &ethpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)}
  1264  				for i := 0; i < 15; i++ {
  1265  					request.ValidatorRequests = append(request.ValidatorRequests, &ethpb.DoppelGangerRequest_ValidatorRequest{
  1266  						PublicKey:  keys[i].PublicKey().Marshal(),
  1267  						Epoch:      2,
  1268  						SignedRoot: []byte{'A'},
  1269  					})
  1270  					response.Responses = append(response.Responses, &ethpb.DoppelGangerResponse_ValidatorResponse{
  1271  						PublicKey:       keys[i].PublicKey().Marshal(),
  1272  						DuplicateExists: false,
  1273  					})
  1274  				}
  1275  
  1276  				return vs, request, response
  1277  			},
  1278  		},
  1279  	}
  1280  	for _, tt := range tests {
  1281  		t.Run(tt.name, func(t *testing.T) {
  1282  			vs, req, resp := tt.svSetup(t)
  1283  			got, err := vs.CheckDoppelGanger(context.Background(), req)
  1284  			if (err != nil) != tt.wantErr {
  1285  				t.Errorf("CheckDoppelGanger() error = %v, wantErr %v", err, tt.wantErr)
  1286  				return
  1287  			}
  1288  			if !reflect.DeepEqual(got, resp) {
  1289  				t.Errorf("CheckDoppelGanger() got = %v, want %v", got.String(), resp.String())
  1290  			}
  1291  		})
  1292  	}
  1293  }
  1294  
  1295  func createStateSetup(t *testing.T, head types.Epoch, mockgen *stategen.MockStateManager) (iface.BeaconState,
  1296  	iface.BeaconState, iface.BeaconState, []bls.SecretKey) {
  1297  	gs, keys := testutil.DeterministicGenesisState(t, 64)
  1298  	hs := gs.Copy()
  1299  	// Head State
  1300  	headEpoch := head
  1301  	headSlot := types.Slot(headEpoch) * params.BeaconConfig().SlotsPerEpoch
  1302  	assert.NoError(t, hs.SetSlot(headSlot))
  1303  	mockgen.StatesBySlot[headSlot] = hs
  1304  
  1305  	// Previous Epoch State
  1306  	prevEpoch := headEpoch - 1
  1307  	ps := gs.Copy()
  1308  	prevSlot := types.Slot(prevEpoch) * params.BeaconConfig().SlotsPerEpoch
  1309  	assert.NoError(t, ps.SetSlot(prevSlot))
  1310  	mockgen.StatesBySlot[prevSlot] = ps
  1311  
  1312  	// Older Epoch State
  1313  	olderEpoch := prevEpoch - 1
  1314  	os := gs.Copy()
  1315  	olderSlot := types.Slot(olderEpoch) * params.BeaconConfig().SlotsPerEpoch
  1316  	assert.NoError(t, os.SetSlot(olderSlot))
  1317  	mockgen.StatesBySlot[olderSlot] = os
  1318  	return hs, ps, os, keys
  1319  }