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

     1  package beacon
     2  
     3  import (
     4  	"context"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"strconv"
     8  	"testing"
     9  
    10  	types "github.com/prysmaticlabs/eth2-types"
    11  	mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    13  	dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    15  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    16  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    17  	"github.com/prysmaticlabs/prysm/shared/cmd"
    18  	"github.com/prysmaticlabs/prysm/shared/params"
    19  	"github.com/prysmaticlabs/prysm/shared/testutil"
    20  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    21  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    22  	"google.golang.org/protobuf/proto"
    23  )
    24  
    25  func TestServer_ListAssignments_CannotRequestFutureEpoch(t *testing.T) {
    26  
    27  	db := dbTest.SetupDB(t)
    28  	ctx := context.Background()
    29  	bs := &Server{
    30  		BeaconDB:           db,
    31  		GenesisTimeFetcher: &mock.ChainService{},
    32  	}
    33  
    34  	wanted := errNoEpochInfoError
    35  	_, err := bs.ListValidatorAssignments(
    36  		ctx,
    37  		&ethpb.ListValidatorAssignmentsRequest{
    38  			QueryFilter: &ethpb.ListValidatorAssignmentsRequest_Epoch{
    39  				Epoch: helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1,
    40  			},
    41  		},
    42  	)
    43  	assert.ErrorContains(t, wanted, err)
    44  }
    45  
    46  func TestServer_ListAssignments_NoResults(t *testing.T) {
    47  
    48  	db := dbTest.SetupDB(t)
    49  	ctx := context.Background()
    50  	st, err := testutil.NewBeaconState()
    51  	require.NoError(t, err)
    52  
    53  	b := testutil.NewBeaconBlock()
    54  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
    55  	gRoot, err := b.Block.HashTreeRoot()
    56  	require.NoError(t, err)
    57  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, gRoot))
    58  	require.NoError(t, db.SaveState(ctx, st, gRoot))
    59  
    60  	bs := &Server{
    61  		BeaconDB:           db,
    62  		GenesisTimeFetcher: &mock.ChainService{},
    63  		StateGen:           stategen.New(db),
    64  	}
    65  	wanted := &ethpb.ValidatorAssignments{
    66  		Assignments:   make([]*ethpb.ValidatorAssignments_CommitteeAssignment, 0),
    67  		TotalSize:     int32(0),
    68  		NextPageToken: strconv.Itoa(0),
    69  	}
    70  	res, err := bs.ListValidatorAssignments(
    71  		ctx,
    72  		&ethpb.ListValidatorAssignmentsRequest{
    73  			QueryFilter: &ethpb.ListValidatorAssignmentsRequest_Genesis{
    74  				Genesis: true,
    75  			},
    76  		},
    77  	)
    78  	require.NoError(t, err)
    79  	if !proto.Equal(wanted, res) {
    80  		t.Errorf("Wanted %v, received %v", wanted, res)
    81  	}
    82  }
    83  
    84  func TestServer_ListAssignments_Pagination_InputOutOfRange(t *testing.T) {
    85  	helpers.ClearCache()
    86  	db := dbTest.SetupDB(t)
    87  	ctx := context.Background()
    88  	count := 100
    89  	validators := make([]*ethpb.Validator, 0, count)
    90  	for i := 0; i < count; i++ {
    91  		pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
    92  		withdrawalCred := make([]byte, 32)
    93  		binary.LittleEndian.PutUint64(pubKey, uint64(i))
    94  		validators = append(validators, &ethpb.Validator{
    95  			PublicKey:             pubKey,
    96  			WithdrawalCredentials: withdrawalCred,
    97  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
    98  			EffectiveBalance:      params.BeaconConfig().MaxEffectiveBalance,
    99  			ActivationEpoch:       0,
   100  		})
   101  	}
   102  
   103  	blk := testutil.NewBeaconBlock().Block
   104  	blockRoot, err := blk.HashTreeRoot()
   105  	require.NoError(t, err)
   106  
   107  	s, err := testutil.NewBeaconState()
   108  	require.NoError(t, err)
   109  	require.NoError(t, s.SetValidators(validators))
   110  	require.NoError(t, db.SaveState(ctx, s, blockRoot))
   111  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, blockRoot))
   112  
   113  	bs := &Server{
   114  		BeaconDB: db,
   115  		HeadFetcher: &mock.ChainService{
   116  			State: s,
   117  		},
   118  		FinalizationFetcher: &mock.ChainService{
   119  			FinalizedCheckPoint: &ethpb.Checkpoint{
   120  				Epoch: 0,
   121  			},
   122  		},
   123  		GenesisTimeFetcher: &mock.ChainService{},
   124  		StateGen:           stategen.New(db),
   125  	}
   126  
   127  	wanted := fmt.Sprintf("page start %d >= list %d", 500, count)
   128  	_, err = bs.ListValidatorAssignments(context.Background(), &ethpb.ListValidatorAssignmentsRequest{
   129  		PageToken:   strconv.Itoa(2),
   130  		QueryFilter: &ethpb.ListValidatorAssignmentsRequest_Genesis{Genesis: true},
   131  	})
   132  	assert.ErrorContains(t, wanted, err)
   133  }
   134  
   135  func TestServer_ListAssignments_Pagination_ExceedsMaxPageSize(t *testing.T) {
   136  	bs := &Server{}
   137  	exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1)
   138  
   139  	wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize)
   140  	req := &ethpb.ListValidatorAssignmentsRequest{
   141  		PageToken: strconv.Itoa(0),
   142  		PageSize:  exceedsMax,
   143  	}
   144  	_, err := bs.ListValidatorAssignments(context.Background(), req)
   145  	assert.ErrorContains(t, wanted, err)
   146  }
   147  
   148  func TestServer_ListAssignments_Pagination_DefaultPageSize_NoArchive(t *testing.T) {
   149  	helpers.ClearCache()
   150  	db := dbTest.SetupDB(t)
   151  	ctx := context.Background()
   152  	count := 500
   153  	validators := make([]*ethpb.Validator, 0, count)
   154  	for i := 0; i < count; i++ {
   155  		pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
   156  		withdrawalCred := make([]byte, 32)
   157  		binary.LittleEndian.PutUint64(pubKey, uint64(i))
   158  		// Mark the validators with index divisible by 3 inactive.
   159  		if i%3 == 0 {
   160  			validators = append(validators, &ethpb.Validator{
   161  				PublicKey:             pubKey,
   162  				WithdrawalCredentials: withdrawalCred,
   163  				ExitEpoch:             0,
   164  				ActivationEpoch:       0,
   165  				EffectiveBalance:      params.BeaconConfig().MaxEffectiveBalance,
   166  			})
   167  		} else {
   168  			validators = append(validators, &ethpb.Validator{
   169  				PublicKey:             pubKey,
   170  				WithdrawalCredentials: withdrawalCred,
   171  				ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   172  				EffectiveBalance:      params.BeaconConfig().MaxEffectiveBalance,
   173  				ActivationEpoch:       0,
   174  			})
   175  		}
   176  	}
   177  
   178  	blk := testutil.NewBeaconBlock().Block
   179  	blockRoot, err := blk.HashTreeRoot()
   180  	require.NoError(t, err)
   181  
   182  	s, err := testutil.NewBeaconState()
   183  	require.NoError(t, err)
   184  	require.NoError(t, s.SetValidators(validators))
   185  	require.NoError(t, db.SaveState(ctx, s, blockRoot))
   186  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, blockRoot))
   187  
   188  	bs := &Server{
   189  		BeaconDB: db,
   190  		HeadFetcher: &mock.ChainService{
   191  			State: s,
   192  		},
   193  		FinalizationFetcher: &mock.ChainService{
   194  			FinalizedCheckPoint: &ethpb.Checkpoint{
   195  				Epoch: 0,
   196  			},
   197  		},
   198  		GenesisTimeFetcher: &mock.ChainService{},
   199  		StateGen:           stategen.New(db),
   200  	}
   201  
   202  	res, err := bs.ListValidatorAssignments(context.Background(), &ethpb.ListValidatorAssignmentsRequest{
   203  		QueryFilter: &ethpb.ListValidatorAssignmentsRequest_Genesis{Genesis: true},
   204  	})
   205  	require.NoError(t, err)
   206  
   207  	// Construct the wanted assignments.
   208  	var wanted []*ethpb.ValidatorAssignments_CommitteeAssignment
   209  
   210  	activeIndices, err := helpers.ActiveValidatorIndices(s, 0)
   211  	require.NoError(t, err)
   212  	committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0)
   213  	require.NoError(t, err)
   214  	for _, index := range activeIndices[0:params.BeaconConfig().DefaultPageSize] {
   215  		val, err := s.ValidatorAtIndex(index)
   216  		require.NoError(t, err)
   217  		wanted = append(wanted, &ethpb.ValidatorAssignments_CommitteeAssignment{
   218  			BeaconCommittees: committeeAssignments[index].Committee,
   219  			CommitteeIndex:   committeeAssignments[index].CommitteeIndex,
   220  			AttesterSlot:     committeeAssignments[index].AttesterSlot,
   221  			ProposerSlots:    proposerIndexToSlots[index],
   222  			PublicKey:        val.PublicKey,
   223  			ValidatorIndex:   index,
   224  		})
   225  	}
   226  	assert.DeepSSZEqual(t, wanted, res.Assignments, "Did not receive wanted assignments")
   227  }
   228  
   229  func TestServer_ListAssignments_FilterPubkeysIndices_NoPagination(t *testing.T) {
   230  	helpers.ClearCache()
   231  	db := dbTest.SetupDB(t)
   232  
   233  	ctx := context.Background()
   234  	count := 100
   235  	validators := make([]*ethpb.Validator, 0, count)
   236  	withdrawCreds := make([]byte, 32)
   237  	for i := 0; i < count; i++ {
   238  		pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
   239  		binary.LittleEndian.PutUint64(pubKey, uint64(i))
   240  		val := &ethpb.Validator{
   241  			PublicKey:             pubKey,
   242  			WithdrawalCredentials: withdrawCreds,
   243  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   244  		}
   245  		validators = append(validators, val)
   246  	}
   247  
   248  	blk := testutil.NewBeaconBlock().Block
   249  	blockRoot, err := blk.HashTreeRoot()
   250  	require.NoError(t, err)
   251  	s, err := testutil.NewBeaconState()
   252  	require.NoError(t, err)
   253  	require.NoError(t, s.SetValidators(validators))
   254  	require.NoError(t, db.SaveState(ctx, s, blockRoot))
   255  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, blockRoot))
   256  
   257  	bs := &Server{
   258  		BeaconDB: db,
   259  		FinalizationFetcher: &mock.ChainService{
   260  			FinalizedCheckPoint: &ethpb.Checkpoint{
   261  				Epoch: 0,
   262  			},
   263  		},
   264  		GenesisTimeFetcher: &mock.ChainService{},
   265  		StateGen:           stategen.New(db),
   266  	}
   267  
   268  	pubKey1 := make([]byte, params.BeaconConfig().BLSPubkeyLength)
   269  	binary.LittleEndian.PutUint64(pubKey1, 1)
   270  	pubKey2 := make([]byte, params.BeaconConfig().BLSPubkeyLength)
   271  	binary.LittleEndian.PutUint64(pubKey2, 2)
   272  	req := &ethpb.ListValidatorAssignmentsRequest{PublicKeys: [][]byte{pubKey1, pubKey2}, Indices: []types.ValidatorIndex{2, 3}}
   273  	res, err := bs.ListValidatorAssignments(context.Background(), req)
   274  	require.NoError(t, err)
   275  
   276  	// Construct the wanted assignments.
   277  	var wanted []*ethpb.ValidatorAssignments_CommitteeAssignment
   278  
   279  	activeIndices, err := helpers.ActiveValidatorIndices(s, 0)
   280  	require.NoError(t, err)
   281  	committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0)
   282  	require.NoError(t, err)
   283  	for _, index := range activeIndices[1:4] {
   284  		val, err := s.ValidatorAtIndex(index)
   285  		require.NoError(t, err)
   286  		wanted = append(wanted, &ethpb.ValidatorAssignments_CommitteeAssignment{
   287  			BeaconCommittees: committeeAssignments[index].Committee,
   288  			CommitteeIndex:   committeeAssignments[index].CommitteeIndex,
   289  			AttesterSlot:     committeeAssignments[index].AttesterSlot,
   290  			ProposerSlots:    proposerIndexToSlots[index],
   291  			PublicKey:        val.PublicKey,
   292  			ValidatorIndex:   index,
   293  		})
   294  	}
   295  
   296  	assert.DeepEqual(t, wanted, res.Assignments, "Did not receive wanted assignments")
   297  }
   298  
   299  func TestServer_ListAssignments_CanFilterPubkeysIndices_WithPagination(t *testing.T) {
   300  	helpers.ClearCache()
   301  	db := dbTest.SetupDB(t)
   302  	ctx := context.Background()
   303  	count := 100
   304  	validators := make([]*ethpb.Validator, 0, count)
   305  	withdrawCred := make([]byte, 32)
   306  	for i := 0; i < count; i++ {
   307  		pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
   308  		binary.LittleEndian.PutUint64(pubKey, uint64(i))
   309  		val := &ethpb.Validator{
   310  			PublicKey:             pubKey,
   311  			WithdrawalCredentials: withdrawCred,
   312  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   313  		}
   314  		validators = append(validators, val)
   315  	}
   316  
   317  	blk := testutil.NewBeaconBlock().Block
   318  	blockRoot, err := blk.HashTreeRoot()
   319  	require.NoError(t, err)
   320  	s, err := testutil.NewBeaconState()
   321  	require.NoError(t, err)
   322  	require.NoError(t, s.SetValidators(validators))
   323  	require.NoError(t, db.SaveState(ctx, s, blockRoot))
   324  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, blockRoot))
   325  
   326  	bs := &Server{
   327  		BeaconDB: db,
   328  		FinalizationFetcher: &mock.ChainService{
   329  			FinalizedCheckPoint: &ethpb.Checkpoint{
   330  				Epoch: 0,
   331  			},
   332  		},
   333  		GenesisTimeFetcher: &mock.ChainService{},
   334  		StateGen:           stategen.New(db),
   335  	}
   336  
   337  	req := &ethpb.ListValidatorAssignmentsRequest{Indices: []types.ValidatorIndex{1, 2, 3, 4, 5, 6}, PageSize: 2, PageToken: "1"}
   338  	res, err := bs.ListValidatorAssignments(context.Background(), req)
   339  	require.NoError(t, err)
   340  
   341  	// Construct the wanted assignments.
   342  	var assignments []*ethpb.ValidatorAssignments_CommitteeAssignment
   343  
   344  	activeIndices, err := helpers.ActiveValidatorIndices(s, 0)
   345  	require.NoError(t, err)
   346  	committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0)
   347  	require.NoError(t, err)
   348  	for _, index := range activeIndices[3:5] {
   349  		val, err := s.ValidatorAtIndex(index)
   350  		require.NoError(t, err)
   351  		assignments = append(assignments, &ethpb.ValidatorAssignments_CommitteeAssignment{
   352  			BeaconCommittees: committeeAssignments[index].Committee,
   353  			CommitteeIndex:   committeeAssignments[index].CommitteeIndex,
   354  			AttesterSlot:     committeeAssignments[index].AttesterSlot,
   355  			ProposerSlots:    proposerIndexToSlots[index],
   356  			PublicKey:        val.PublicKey,
   357  			ValidatorIndex:   index,
   358  		})
   359  	}
   360  
   361  	wantedRes := &ethpb.ValidatorAssignments{
   362  		Assignments:   assignments,
   363  		TotalSize:     int32(len(req.Indices)),
   364  		NextPageToken: "2",
   365  	}
   366  
   367  	assert.DeepEqual(t, wantedRes, res, "Did not get wanted assignments")
   368  
   369  	// Test the wrap around scenario.
   370  	assignments = nil
   371  	req = &ethpb.ListValidatorAssignmentsRequest{Indices: []types.ValidatorIndex{1, 2, 3, 4, 5, 6}, PageSize: 5, PageToken: "1"}
   372  	res, err = bs.ListValidatorAssignments(context.Background(), req)
   373  	require.NoError(t, err)
   374  	cAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0)
   375  	require.NoError(t, err)
   376  	for _, index := range activeIndices[6:7] {
   377  		val, err := s.ValidatorAtIndex(index)
   378  		require.NoError(t, err)
   379  		assignments = append(assignments, &ethpb.ValidatorAssignments_CommitteeAssignment{
   380  			BeaconCommittees: cAssignments[index].Committee,
   381  			CommitteeIndex:   cAssignments[index].CommitteeIndex,
   382  			AttesterSlot:     cAssignments[index].AttesterSlot,
   383  			ProposerSlots:    proposerIndexToSlots[index],
   384  			PublicKey:        val.PublicKey,
   385  			ValidatorIndex:   index,
   386  		})
   387  	}
   388  
   389  	wantedRes = &ethpb.ValidatorAssignments{
   390  		Assignments:   assignments,
   391  		TotalSize:     int32(len(req.Indices)),
   392  		NextPageToken: "",
   393  	}
   394  
   395  	assert.DeepEqual(t, wantedRes, res, "Did not receive wanted assignments")
   396  }