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 ðpb.ListValidatorAssignmentsRequest{ 38 QueryFilter: ðpb.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 := ðpb.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 ðpb.ListValidatorAssignmentsRequest{ 73 QueryFilter: ðpb.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, ðpb.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: ðpb.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(), ðpb.ListValidatorAssignmentsRequest{ 129 PageToken: strconv.Itoa(2), 130 QueryFilter: ðpb.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 := ðpb.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, ðpb.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, ðpb.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: ðpb.Checkpoint{ 195 Epoch: 0, 196 }, 197 }, 198 GenesisTimeFetcher: &mock.ChainService{}, 199 StateGen: stategen.New(db), 200 } 201 202 res, err := bs.ListValidatorAssignments(context.Background(), ðpb.ListValidatorAssignmentsRequest{ 203 QueryFilter: ðpb.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, ðpb.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 := ðpb.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: ðpb.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 := ðpb.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, ðpb.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 := ðpb.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: ðpb.Checkpoint{ 330 Epoch: 0, 331 }, 332 }, 333 GenesisTimeFetcher: &mock.ChainService{}, 334 StateGen: stategen.New(db), 335 } 336 337 req := ðpb.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, ðpb.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 := ðpb.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 = ðpb.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, ðpb.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 = ðpb.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 }