github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/beacon/validators_test.go (about) 1 package beacon 2 3 import ( 4 "context" 5 "encoding/binary" 6 "fmt" 7 "sort" 8 "strconv" 9 "testing" 10 "time" 11 12 types "github.com/prysmaticlabs/eth2-types" 13 "github.com/prysmaticlabs/go-bitfield" 14 mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 15 "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" 16 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 17 "github.com/prysmaticlabs/prysm/beacon-chain/db" 18 dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 19 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 20 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 21 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 22 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 23 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 24 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 25 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 26 "github.com/prysmaticlabs/prysm/shared/bytesutil" 27 "github.com/prysmaticlabs/prysm/shared/cmd" 28 "github.com/prysmaticlabs/prysm/shared/params" 29 "github.com/prysmaticlabs/prysm/shared/testutil" 30 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 31 "github.com/prysmaticlabs/prysm/shared/testutil/require" 32 "github.com/prysmaticlabs/prysm/shared/timeutils" 33 "google.golang.org/protobuf/proto" 34 "google.golang.org/protobuf/types/known/emptypb" 35 ) 36 37 const ( 38 errNoEpochInfoError = "Cannot retrieve information about an epoch in the future" 39 ) 40 41 func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing.T) { 42 beaconDB := dbTest.SetupDB(t) 43 ctx := context.Background() 44 st, err := testutil.NewBeaconState() 45 require.NoError(t, err) 46 require.NoError(t, st.SetSlot(0)) 47 bs := &Server{ 48 GenesisTimeFetcher: &mock.ChainService{}, 49 HeadFetcher: &mock.ChainService{ 50 State: st, 51 }, 52 BeaconDB: beaconDB, 53 } 54 55 wanted := errNoEpochInfoError 56 _, err = bs.GetValidatorActiveSetChanges( 57 ctx, 58 ðpb.GetValidatorActiveSetChangesRequest{ 59 QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Epoch{ 60 Epoch: helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1, 61 }, 62 }, 63 ) 64 assert.ErrorContains(t, wanted, err) 65 } 66 67 func TestServer_ListValidatorBalances_CannotRequestFutureEpoch(t *testing.T) { 68 beaconDB := dbTest.SetupDB(t) 69 ctx := context.Background() 70 71 st, err := testutil.NewBeaconState() 72 require.NoError(t, err) 73 require.NoError(t, st.SetSlot(0)) 74 bs := &Server{ 75 BeaconDB: beaconDB, 76 HeadFetcher: &mock.ChainService{ 77 State: st, 78 }, 79 GenesisTimeFetcher: &mock.ChainService{}, 80 } 81 82 wanted := errNoEpochInfoError 83 _, err = bs.ListValidatorBalances( 84 ctx, 85 ðpb.ListValidatorBalancesRequest{ 86 QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{ 87 Epoch: helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1, 88 }, 89 }, 90 ) 91 assert.ErrorContains(t, wanted, err) 92 } 93 94 func TestServer_ListValidatorBalances_NoResults(t *testing.T) { 95 beaconDB := dbTest.SetupDB(t) 96 97 ctx := context.Background() 98 st, err := testutil.NewBeaconState() 99 require.NoError(t, err) 100 require.NoError(t, st.SetSlot(0)) 101 bs := &Server{ 102 GenesisTimeFetcher: &mock.ChainService{}, 103 StateGen: stategen.New(beaconDB), 104 } 105 106 headState, err := testutil.NewBeaconState() 107 require.NoError(t, err) 108 b := testutil.NewBeaconBlock() 109 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 110 gRoot, err := b.Block.HashTreeRoot() 111 require.NoError(t, err) 112 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 113 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 114 115 wanted := ðpb.ValidatorBalances{ 116 Balances: make([]*ethpb.ValidatorBalances_Balance, 0), 117 TotalSize: int32(0), 118 NextPageToken: strconv.Itoa(0), 119 } 120 res, err := bs.ListValidatorBalances( 121 ctx, 122 ðpb.ListValidatorBalancesRequest{ 123 QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{ 124 Epoch: 0, 125 }, 126 }, 127 ) 128 require.NoError(t, err) 129 if !proto.Equal(wanted, res) { 130 t.Errorf("Wanted %v, received %v", wanted, res) 131 } 132 } 133 134 func TestServer_ListValidatorBalances_DefaultResponse_NoArchive(t *testing.T) { 135 beaconDB := dbTest.SetupDB(t) 136 ctx := context.Background() 137 138 numItems := 100 139 validators := make([]*ethpb.Validator, numItems) 140 balances := make([]uint64, numItems) 141 balancesResponse := make([]*ethpb.ValidatorBalances_Balance, numItems) 142 for i := 0; i < numItems; i++ { 143 validators[i] = ðpb.Validator{ 144 PublicKey: pubKey(uint64(i)), 145 WithdrawalCredentials: make([]byte, 32), 146 } 147 balances[i] = params.BeaconConfig().MaxEffectiveBalance 148 balancesResponse[i] = ðpb.ValidatorBalances_Balance{ 149 PublicKey: pubKey(uint64(i)), 150 Index: types.ValidatorIndex(i), 151 Balance: params.BeaconConfig().MaxEffectiveBalance, 152 Status: "EXITED", 153 } 154 } 155 st, err := testutil.NewBeaconState() 156 require.NoError(t, err) 157 require.NoError(t, st.SetSlot(0)) 158 require.NoError(t, st.SetValidators(validators)) 159 require.NoError(t, st.SetBalances(balances)) 160 b := testutil.NewBeaconBlock() 161 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 162 gRoot, err := b.Block.HashTreeRoot() 163 require.NoError(t, err) 164 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 165 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 166 bs := &Server{ 167 GenesisTimeFetcher: &mock.ChainService{}, 168 StateGen: stategen.New(beaconDB), 169 HeadFetcher: &mock.ChainService{ 170 State: st, 171 }, 172 } 173 res, err := bs.ListValidatorBalances( 174 ctx, 175 ðpb.ListValidatorBalancesRequest{ 176 QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}, 177 }, 178 ) 179 require.NoError(t, err) 180 assert.DeepEqual(t, balancesResponse, res.Balances) 181 } 182 183 func TestServer_ListValidatorBalances_PaginationOutOfRange(t *testing.T) { 184 beaconDB := dbTest.SetupDB(t) 185 ctx := context.Background() 186 187 _, _, headState := setupValidators(t, beaconDB, 100) 188 b := testutil.NewBeaconBlock() 189 gRoot, err := b.Block.HashTreeRoot() 190 require.NoError(t, err) 191 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 192 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 193 194 bs := &Server{ 195 GenesisTimeFetcher: &mock.ChainService{}, 196 StateGen: stategen.New(beaconDB), 197 HeadFetcher: &mock.ChainService{ 198 State: headState, 199 }, 200 } 201 202 wanted := fmt.Sprintf("page start %d >= list %d", 200, len(headState.Balances())) 203 _, err = bs.ListValidatorBalances(context.Background(), ðpb.ListValidatorBalancesRequest{ 204 PageToken: strconv.Itoa(2), 205 PageSize: 100, 206 QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}, 207 }) 208 assert.ErrorContains(t, wanted, err) 209 } 210 211 func TestServer_ListValidatorBalances_ExceedsMaxPageSize(t *testing.T) { 212 bs := &Server{} 213 exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1) 214 215 wanted := fmt.Sprintf( 216 "Requested page size %d can not be greater than max size %d", 217 exceedsMax, 218 cmd.Get().MaxRPCPageSize, 219 ) 220 req := ðpb.ListValidatorBalancesRequest{PageSize: exceedsMax} 221 _, err := bs.ListValidatorBalances(context.Background(), req) 222 assert.ErrorContains(t, wanted, err) 223 } 224 225 func pubKey(i uint64) []byte { 226 pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength) 227 binary.LittleEndian.PutUint64(pubKey, i) 228 return pubKey 229 } 230 231 func TestServer_ListValidatorBalances_Pagination_Default(t *testing.T) { 232 beaconDB := dbTest.SetupDB(t) 233 ctx := context.Background() 234 235 _, _, headState := setupValidators(t, beaconDB, 100) 236 b := testutil.NewBeaconBlock() 237 gRoot, err := b.Block.HashTreeRoot() 238 require.NoError(t, err) 239 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 240 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 241 242 bs := &Server{ 243 GenesisTimeFetcher: &mock.ChainService{}, 244 StateGen: stategen.New(beaconDB), 245 HeadFetcher: &mock.ChainService{ 246 State: headState, 247 }, 248 } 249 250 tests := []struct { 251 req *ethpb.ListValidatorBalancesRequest 252 res *ethpb.ValidatorBalances 253 }{ 254 {req: ðpb.ListValidatorBalancesRequest{PublicKeys: [][]byte{pubKey(99)}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 255 res: ðpb.ValidatorBalances{ 256 Balances: []*ethpb.ValidatorBalances_Balance{ 257 {Index: 99, PublicKey: pubKey(99), Balance: 99, Status: "EXITED"}, 258 }, 259 NextPageToken: "", 260 TotalSize: 1, 261 }, 262 }, 263 {req: ðpb.ListValidatorBalancesRequest{Indices: []types.ValidatorIndex{1, 2, 3}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 264 res: ðpb.ValidatorBalances{ 265 Balances: []*ethpb.ValidatorBalances_Balance{ 266 {Index: 1, PublicKey: pubKey(1), Balance: 1, Status: "EXITED"}, 267 {Index: 2, PublicKey: pubKey(2), Balance: 2, Status: "EXITED"}, 268 {Index: 3, PublicKey: pubKey(3), Balance: 3, Status: "EXITED"}, 269 }, 270 NextPageToken: "", 271 TotalSize: 3, 272 }, 273 }, 274 {req: ðpb.ListValidatorBalancesRequest{PublicKeys: [][]byte{pubKey(10), pubKey(11), pubKey(12)}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 275 res: ðpb.ValidatorBalances{ 276 Balances: []*ethpb.ValidatorBalances_Balance{ 277 {Index: 10, PublicKey: pubKey(10), Balance: 10, Status: "EXITED"}, 278 {Index: 11, PublicKey: pubKey(11), Balance: 11, Status: "EXITED"}, 279 {Index: 12, PublicKey: pubKey(12), Balance: 12, Status: "EXITED"}, 280 }, 281 NextPageToken: "", 282 TotalSize: 3, 283 }}, 284 {req: ðpb.ListValidatorBalancesRequest{PublicKeys: [][]byte{pubKey(2), pubKey(3)}, Indices: []types.ValidatorIndex{3, 4}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, // Duplication 285 res: ðpb.ValidatorBalances{ 286 Balances: []*ethpb.ValidatorBalances_Balance{ 287 {Index: 2, PublicKey: pubKey(2), Balance: 2, Status: "EXITED"}, 288 {Index: 3, PublicKey: pubKey(3), Balance: 3, Status: "EXITED"}, 289 {Index: 4, PublicKey: pubKey(4), Balance: 4, Status: "EXITED"}, 290 }, 291 NextPageToken: "", 292 TotalSize: 3, 293 }}, 294 {req: ðpb.ListValidatorBalancesRequest{PublicKeys: [][]byte{{}}, Indices: []types.ValidatorIndex{3, 4}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, // Public key has a blank value 295 res: ðpb.ValidatorBalances{ 296 Balances: []*ethpb.ValidatorBalances_Balance{ 297 {Index: 3, PublicKey: pubKey(3), Balance: 3, Status: "EXITED"}, 298 {Index: 4, PublicKey: pubKey(4), Balance: 4, Status: "EXITED"}, 299 }, 300 NextPageToken: "", 301 TotalSize: 2, 302 }}, 303 } 304 for _, test := range tests { 305 res, err := bs.ListValidatorBalances(context.Background(), test.req) 306 require.NoError(t, err) 307 if !proto.Equal(res, test.res) { 308 t.Errorf("Expected %v, received %v", test.res, res) 309 } 310 } 311 } 312 313 func TestServer_ListValidatorBalances_Pagination_CustomPageSizes(t *testing.T) { 314 beaconDB := dbTest.SetupDB(t) 315 ctx := context.Background() 316 317 count := 1000 318 _, _, headState := setupValidators(t, beaconDB, count) 319 b := testutil.NewBeaconBlock() 320 gRoot, err := b.Block.HashTreeRoot() 321 require.NoError(t, err) 322 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 323 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 324 325 bs := &Server{ 326 GenesisTimeFetcher: &mock.ChainService{}, 327 StateGen: stategen.New(beaconDB), 328 HeadFetcher: &mock.ChainService{ 329 State: headState, 330 }, 331 } 332 333 tests := []struct { 334 req *ethpb.ListValidatorBalancesRequest 335 res *ethpb.ValidatorBalances 336 }{ 337 {req: ðpb.ListValidatorBalancesRequest{PageToken: strconv.Itoa(1), PageSize: 3, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 338 res: ðpb.ValidatorBalances{ 339 Balances: []*ethpb.ValidatorBalances_Balance{ 340 {PublicKey: pubKey(3), Index: 3, Balance: uint64(3), Status: "EXITED"}, 341 {PublicKey: pubKey(4), Index: 4, Balance: uint64(4), Status: "EXITED"}, 342 {PublicKey: pubKey(5), Index: 5, Balance: uint64(5), Status: "EXITED"}}, 343 NextPageToken: strconv.Itoa(2), 344 TotalSize: int32(count)}}, 345 {req: ðpb.ListValidatorBalancesRequest{PageToken: strconv.Itoa(10), PageSize: 5, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 346 res: ðpb.ValidatorBalances{ 347 Balances: []*ethpb.ValidatorBalances_Balance{ 348 {PublicKey: pubKey(50), Index: 50, Balance: uint64(50), Status: "EXITED"}, 349 {PublicKey: pubKey(51), Index: 51, Balance: uint64(51), Status: "EXITED"}, 350 {PublicKey: pubKey(52), Index: 52, Balance: uint64(52), Status: "EXITED"}, 351 {PublicKey: pubKey(53), Index: 53, Balance: uint64(53), Status: "EXITED"}, 352 {PublicKey: pubKey(54), Index: 54, Balance: uint64(54), Status: "EXITED"}}, 353 NextPageToken: strconv.Itoa(11), 354 TotalSize: int32(count)}}, 355 {req: ðpb.ListValidatorBalancesRequest{PageToken: strconv.Itoa(33), PageSize: 3, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 356 res: ðpb.ValidatorBalances{ 357 Balances: []*ethpb.ValidatorBalances_Balance{ 358 {PublicKey: pubKey(99), Index: 99, Balance: uint64(99), Status: "EXITED"}, 359 {PublicKey: pubKey(100), Index: 100, Balance: uint64(100), Status: "EXITED"}, 360 {PublicKey: pubKey(101), Index: 101, Balance: uint64(101), Status: "EXITED"}, 361 }, 362 NextPageToken: "34", 363 TotalSize: int32(count)}}, 364 {req: ðpb.ListValidatorBalancesRequest{PageSize: 2, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}}, 365 res: ðpb.ValidatorBalances{ 366 Balances: []*ethpb.ValidatorBalances_Balance{ 367 {PublicKey: pubKey(0), Index: 0, Balance: uint64(0), Status: "EXITED"}, 368 {PublicKey: pubKey(1), Index: 1, Balance: uint64(1), Status: "EXITED"}}, 369 NextPageToken: strconv.Itoa(1), 370 TotalSize: int32(count)}}, 371 } 372 for _, test := range tests { 373 res, err := bs.ListValidatorBalances(context.Background(), test.req) 374 require.NoError(t, err) 375 if !proto.Equal(res, test.res) { 376 t.Errorf("Expected %v, received %v", test.res, res) 377 } 378 } 379 } 380 381 func TestServer_ListValidatorBalances_OutOfRange(t *testing.T) { 382 beaconDB := dbTest.SetupDB(t) 383 384 ctx := context.Background() 385 _, _, headState := setupValidators(t, beaconDB, 1) 386 b := testutil.NewBeaconBlock() 387 gRoot, err := b.Block.HashTreeRoot() 388 require.NoError(t, err) 389 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 390 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 391 392 bs := &Server{ 393 GenesisTimeFetcher: &mock.ChainService{}, 394 StateGen: stategen.New(beaconDB), 395 HeadFetcher: &mock.ChainService{ 396 State: headState, 397 }, 398 } 399 400 req := ðpb.ListValidatorBalancesRequest{Indices: []types.ValidatorIndex{types.ValidatorIndex(1)}, QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}} 401 wanted := "Validator index 1 >= balance list 1" 402 _, err = bs.ListValidatorBalances(context.Background(), req) 403 assert.ErrorContains(t, wanted, err) 404 } 405 406 func TestServer_ListValidators_CannotRequestFutureEpoch(t *testing.T) { 407 beaconDB := dbTest.SetupDB(t) 408 ctx := context.Background() 409 410 st, err := testutil.NewBeaconState() 411 require.NoError(t, err) 412 require.NoError(t, st.SetSlot(0)) 413 bs := &Server{ 414 BeaconDB: beaconDB, 415 GenesisTimeFetcher: &mock.ChainService{ 416 // We are in epoch 0. 417 Genesis: time.Now(), 418 }, 419 HeadFetcher: &mock.ChainService{ 420 State: st, 421 }, 422 } 423 424 wanted := errNoEpochInfoError 425 _, err = bs.ListValidators( 426 ctx, 427 ðpb.ListValidatorsRequest{ 428 QueryFilter: ðpb.ListValidatorsRequest_Epoch{ 429 Epoch: 1, 430 }, 431 }, 432 ) 433 assert.ErrorContains(t, wanted, err) 434 } 435 436 func TestServer_ListValidators_NoResults(t *testing.T) { 437 beaconDB := dbTest.SetupDB(t) 438 439 ctx := context.Background() 440 st, err := testutil.NewBeaconState() 441 require.NoError(t, err) 442 require.NoError(t, st.SetSlot(0)) 443 gRoot := [32]byte{'g'} 444 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 445 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 446 bs := &Server{ 447 BeaconDB: beaconDB, 448 GenesisTimeFetcher: &mock.ChainService{ 449 // We are in epoch 0. 450 Genesis: time.Now(), 451 }, 452 HeadFetcher: &mock.ChainService{ 453 State: st, 454 }, 455 StateGen: stategen.New(beaconDB), 456 } 457 wanted := ðpb.Validators{ 458 ValidatorList: make([]*ethpb.Validators_ValidatorContainer, 0), 459 TotalSize: int32(0), 460 NextPageToken: strconv.Itoa(0), 461 } 462 res, err := bs.ListValidators( 463 ctx, 464 ðpb.ListValidatorsRequest{ 465 QueryFilter: ðpb.ListValidatorsRequest_Epoch{ 466 Epoch: 0, 467 }, 468 }, 469 ) 470 require.NoError(t, err) 471 if !proto.Equal(wanted, res) { 472 t.Errorf("Wanted %v, received %v", wanted, res) 473 } 474 } 475 476 func TestServer_ListValidators_OnlyActiveValidators(t *testing.T) { 477 ctx := context.Background() 478 beaconDB := dbTest.SetupDB(t) 479 count := 100 480 balances := make([]uint64, count) 481 validators := make([]*ethpb.Validator, count) 482 activeValidators := make([]*ethpb.Validators_ValidatorContainer, 0) 483 for i := 0; i < count; i++ { 484 pubKey := pubKey(uint64(i)) 485 balances[i] = params.BeaconConfig().MaxEffectiveBalance 486 487 // We mark even validators as active, and odd validators as inactive. 488 if i%2 == 0 { 489 val := ðpb.Validator{ 490 PublicKey: pubKey, 491 WithdrawalCredentials: make([]byte, 32), 492 ActivationEpoch: 0, 493 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 494 } 495 validators[i] = val 496 activeValidators = append(activeValidators, ðpb.Validators_ValidatorContainer{ 497 Index: types.ValidatorIndex(i), 498 Validator: val, 499 }) 500 } else { 501 validators[i] = ðpb.Validator{ 502 PublicKey: pubKey, 503 WithdrawalCredentials: make([]byte, 32), 504 ActivationEpoch: 0, 505 ExitEpoch: 0, 506 } 507 } 508 } 509 st, err := testutil.NewBeaconState() 510 require.NoError(t, err) 511 require.NoError(t, st.SetValidators(validators)) 512 require.NoError(t, st.SetBalances(balances)) 513 514 bs := &Server{ 515 HeadFetcher: &mock.ChainService{ 516 State: st, 517 }, 518 GenesisTimeFetcher: &mock.ChainService{ 519 // We are in epoch 0. 520 Genesis: time.Now(), 521 }, 522 StateGen: stategen.New(beaconDB), 523 } 524 525 b := testutil.NewBeaconBlock() 526 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 527 gRoot, err := b.Block.HashTreeRoot() 528 require.NoError(t, err) 529 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 530 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 531 532 received, err := bs.ListValidators(ctx, ðpb.ListValidatorsRequest{ 533 Active: true, 534 }) 535 require.NoError(t, err) 536 assert.DeepEqual(t, activeValidators, received.ValidatorList) 537 } 538 539 func TestServer_ListValidators_InactiveInTheMiddle(t *testing.T) { 540 ctx := context.Background() 541 beaconDB := dbTest.SetupDB(t) 542 count := 100 543 balances := make([]uint64, count) 544 validators := make([]*ethpb.Validator, count) 545 activeValidators := make([]*ethpb.Validators_ValidatorContainer, 0) 546 for i := 0; i < count; i++ { 547 pubKey := pubKey(uint64(i)) 548 balances[i] = params.BeaconConfig().MaxEffectiveBalance 549 550 // We mark even validators as active, and odd validators as inactive. 551 if i%2 == 0 { 552 val := ðpb.Validator{ 553 PublicKey: pubKey, 554 WithdrawalCredentials: make([]byte, 32), 555 ActivationEpoch: 0, 556 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 557 } 558 validators[i] = val 559 activeValidators = append(activeValidators, ðpb.Validators_ValidatorContainer{ 560 Index: types.ValidatorIndex(i), 561 Validator: val, 562 }) 563 } else { 564 validators[i] = ðpb.Validator{ 565 PublicKey: pubKey, 566 WithdrawalCredentials: make([]byte, 32), 567 ActivationEpoch: 0, 568 ExitEpoch: 0, 569 } 570 } 571 } 572 573 // Set first validator to be inactive. 574 validators[0].ActivationEpoch = params.BeaconConfig().FarFutureEpoch 575 activeValidators[0].Validator.ActivationEpoch = params.BeaconConfig().FarFutureEpoch 576 577 st, err := testutil.NewBeaconState() 578 require.NoError(t, err) 579 require.NoError(t, st.SetValidators(validators)) 580 require.NoError(t, st.SetBalances(balances)) 581 582 bs := &Server{ 583 HeadFetcher: &mock.ChainService{ 584 State: st, 585 }, 586 GenesisTimeFetcher: &mock.ChainService{ 587 // We are in epoch 0. 588 Genesis: time.Now(), 589 }, 590 StateGen: stategen.New(beaconDB), 591 } 592 593 b := testutil.NewBeaconBlock() 594 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 595 gRoot, err := b.Block.HashTreeRoot() 596 require.NoError(t, err) 597 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 598 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 599 600 received, err := bs.ListValidators(ctx, ðpb.ListValidatorsRequest{ 601 Active: true, 602 }) 603 require.NoError(t, err) 604 605 require.Equal(t, count/2-1, len(received.ValidatorList)) 606 require.Equal(t, count/2-1, int(received.TotalSize)) 607 } 608 609 func TestServer_ListValidatorBalances_UnknownValidatorInResponse(t *testing.T) { 610 beaconDB := dbTest.SetupDB(t) 611 ctx := context.Background() 612 613 _, _, headState := setupValidators(t, beaconDB, 4) 614 b := testutil.NewBeaconBlock() 615 gRoot, err := b.Block.HashTreeRoot() 616 require.NoError(t, err) 617 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 618 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 619 620 bs := &Server{ 621 GenesisTimeFetcher: &mock.ChainService{}, 622 StateGen: stategen.New(beaconDB), 623 HeadFetcher: &mock.ChainService{ 624 State: headState, 625 }, 626 } 627 628 nonExistentPubKey := [32]byte{8} 629 req := ðpb.ListValidatorBalancesRequest{ 630 PublicKeys: [][]byte{ 631 pubKey(1), 632 pubKey(2), 633 nonExistentPubKey[:], 634 }, 635 QueryFilter: ðpb.ListValidatorBalancesRequest_Epoch{Epoch: 0}, 636 } 637 638 wanted := ðpb.ValidatorBalances{ 639 Balances: []*ethpb.ValidatorBalances_Balance{ 640 {Status: "UNKNOWN"}, 641 {Index: 1, PublicKey: pubKey(1), Balance: 1, Status: "EXITED"}, 642 {Index: 2, PublicKey: pubKey(2), Balance: 2, Status: "EXITED"}, 643 }, 644 NextPageToken: "", 645 TotalSize: 3, 646 } 647 res, err := bs.ListValidatorBalances(context.Background(), req) 648 require.NoError(t, err) 649 if !proto.Equal(res, wanted) { 650 t.Errorf("Expected %v, received %v", wanted, res) 651 } 652 } 653 654 func TestServer_ListValidators_NoPagination(t *testing.T) { 655 beaconDB := dbTest.SetupDB(t) 656 657 validators, _, headState := setupValidators(t, beaconDB, 100) 658 want := make([]*ethpb.Validators_ValidatorContainer, len(validators)) 659 for i := 0; i < len(validators); i++ { 660 want[i] = ðpb.Validators_ValidatorContainer{ 661 Index: types.ValidatorIndex(i), 662 Validator: validators[i], 663 } 664 } 665 666 bs := &Server{ 667 HeadFetcher: &mock.ChainService{ 668 State: headState, 669 }, 670 GenesisTimeFetcher: &mock.ChainService{ 671 // We are in epoch 0. 672 Genesis: time.Now(), 673 }, 674 FinalizationFetcher: &mock.ChainService{ 675 FinalizedCheckPoint: ðpb.Checkpoint{ 676 Epoch: 0, 677 }, 678 }, 679 StateGen: stategen.New(beaconDB), 680 } 681 682 received, err := bs.ListValidators(context.Background(), ðpb.ListValidatorsRequest{}) 683 require.NoError(t, err) 684 assert.DeepSSZEqual(t, want, received.ValidatorList, "Incorrect respond of validators") 685 } 686 687 func TestServer_ListValidators_StategenNotUsed(t *testing.T) { 688 beaconDB := dbTest.SetupDB(t) 689 690 validators, _, headState := setupValidators(t, beaconDB, 100) 691 want := make([]*ethpb.Validators_ValidatorContainer, len(validators)) 692 for i := 0; i < len(validators); i++ { 693 want[i] = ðpb.Validators_ValidatorContainer{ 694 Index: types.ValidatorIndex(i), 695 Validator: validators[i], 696 } 697 } 698 699 bs := &Server{ 700 HeadFetcher: &mock.ChainService{ 701 State: headState, 702 }, 703 GenesisTimeFetcher: &mock.ChainService{ 704 // We are in epoch 0. 705 Genesis: time.Now(), 706 }, 707 } 708 709 received, err := bs.ListValidators(context.Background(), ðpb.ListValidatorsRequest{}) 710 require.NoError(t, err) 711 assert.DeepEqual(t, want, received.ValidatorList, "Incorrect respond of validators") 712 } 713 714 func TestServer_ListValidators_IndicesPubKeys(t *testing.T) { 715 beaconDB := dbTest.SetupDB(t) 716 717 validators, _, headState := setupValidators(t, beaconDB, 100) 718 indicesWanted := []types.ValidatorIndex{2, 7, 11, 17} 719 pubkeyIndicesWanted := []types.ValidatorIndex{3, 5, 9, 15} 720 allIndicesWanted := append(indicesWanted, pubkeyIndicesWanted...) 721 want := make([]*ethpb.Validators_ValidatorContainer, len(allIndicesWanted)) 722 for i, idx := range allIndicesWanted { 723 want[i] = ðpb.Validators_ValidatorContainer{ 724 Index: idx, 725 Validator: validators[idx], 726 } 727 } 728 sort.Slice(want, func(i int, j int) bool { 729 return want[i].Index < want[j].Index 730 }) 731 732 bs := &Server{ 733 HeadFetcher: &mock.ChainService{ 734 State: headState, 735 }, 736 FinalizationFetcher: &mock.ChainService{ 737 FinalizedCheckPoint: ðpb.Checkpoint{ 738 Epoch: 0, 739 }, 740 }, 741 GenesisTimeFetcher: &mock.ChainService{ 742 // We are in epoch 0. 743 Genesis: time.Now(), 744 }, 745 StateGen: stategen.New(beaconDB), 746 } 747 748 pubKeysWanted := make([][]byte, len(pubkeyIndicesWanted)) 749 for i, indice := range pubkeyIndicesWanted { 750 pubKeysWanted[i] = pubKey(uint64(indice)) 751 } 752 req := ðpb.ListValidatorsRequest{ 753 Indices: indicesWanted, 754 PublicKeys: pubKeysWanted, 755 } 756 received, err := bs.ListValidators(context.Background(), req) 757 require.NoError(t, err) 758 assert.DeepEqual(t, want, received.ValidatorList, "Incorrect respond of validators") 759 } 760 761 func TestServer_ListValidators_Pagination(t *testing.T) { 762 beaconDB := dbTest.SetupDB(t) 763 764 count := 100 765 _, _, headState := setupValidators(t, beaconDB, count) 766 767 bs := &Server{ 768 BeaconDB: beaconDB, 769 HeadFetcher: &mock.ChainService{ 770 State: headState, 771 }, 772 FinalizationFetcher: &mock.ChainService{ 773 FinalizedCheckPoint: ðpb.Checkpoint{ 774 Epoch: 0, 775 }, 776 }, 777 GenesisTimeFetcher: &mock.ChainService{ 778 // We are in epoch 0. 779 Genesis: time.Now(), 780 }, 781 StateGen: stategen.New(beaconDB), 782 } 783 784 tests := []struct { 785 req *ethpb.ListValidatorsRequest 786 res *ethpb.Validators 787 }{ 788 {req: ðpb.ListValidatorsRequest{PageToken: strconv.Itoa(1), PageSize: 3}, 789 res: ðpb.Validators{ 790 ValidatorList: []*ethpb.Validators_ValidatorContainer{ 791 { 792 Validator: ðpb.Validator{ 793 PublicKey: pubKey(3), 794 WithdrawalCredentials: make([]byte, 32), 795 }, 796 Index: 3, 797 }, 798 { 799 Validator: ðpb.Validator{ 800 PublicKey: pubKey(4), 801 WithdrawalCredentials: make([]byte, 32), 802 }, 803 Index: 4, 804 }, 805 { 806 Validator: ðpb.Validator{ 807 PublicKey: pubKey(5), 808 WithdrawalCredentials: make([]byte, 32), 809 }, 810 Index: 5, 811 }, 812 }, 813 NextPageToken: strconv.Itoa(2), 814 TotalSize: int32(count)}}, 815 {req: ðpb.ListValidatorsRequest{PageToken: strconv.Itoa(10), PageSize: 5}, 816 res: ðpb.Validators{ 817 ValidatorList: []*ethpb.Validators_ValidatorContainer{ 818 { 819 Validator: ðpb.Validator{ 820 PublicKey: pubKey(50), 821 WithdrawalCredentials: make([]byte, 32), 822 }, 823 Index: 50, 824 }, 825 { 826 Validator: ðpb.Validator{ 827 PublicKey: pubKey(51), 828 WithdrawalCredentials: make([]byte, 32), 829 }, 830 Index: 51, 831 }, 832 { 833 Validator: ðpb.Validator{ 834 PublicKey: pubKey(52), 835 WithdrawalCredentials: make([]byte, 32), 836 }, 837 Index: 52, 838 }, 839 { 840 Validator: ðpb.Validator{ 841 PublicKey: pubKey(53), 842 WithdrawalCredentials: make([]byte, 32), 843 }, 844 Index: 53, 845 }, 846 { 847 Validator: ðpb.Validator{ 848 PublicKey: pubKey(54), 849 WithdrawalCredentials: make([]byte, 32), 850 }, 851 Index: 54, 852 }, 853 }, 854 NextPageToken: strconv.Itoa(11), 855 TotalSize: int32(count)}}, 856 {req: ðpb.ListValidatorsRequest{PageToken: strconv.Itoa(33), PageSize: 3}, 857 res: ðpb.Validators{ 858 ValidatorList: []*ethpb.Validators_ValidatorContainer{ 859 { 860 Validator: ðpb.Validator{ 861 PublicKey: pubKey(99), 862 WithdrawalCredentials: make([]byte, 32), 863 }, 864 Index: 99, 865 }, 866 }, 867 NextPageToken: "", 868 TotalSize: int32(count)}}, 869 {req: ðpb.ListValidatorsRequest{PageSize: 2}, 870 res: ðpb.Validators{ 871 ValidatorList: []*ethpb.Validators_ValidatorContainer{ 872 { 873 Validator: ðpb.Validator{ 874 PublicKey: pubKey(0), 875 WithdrawalCredentials: make([]byte, 32), 876 }, 877 Index: 0, 878 }, 879 { 880 Validator: ðpb.Validator{ 881 PublicKey: pubKey(1), 882 WithdrawalCredentials: make([]byte, 32), 883 }, 884 Index: 1, 885 }, 886 }, 887 NextPageToken: strconv.Itoa(1), 888 TotalSize: int32(count)}}, 889 } 890 for _, test := range tests { 891 res, err := bs.ListValidators(context.Background(), test.req) 892 require.NoError(t, err) 893 if !proto.Equal(res, test.res) { 894 t.Errorf("Incorrect validator response, wanted %v, received %v", test.res, res) 895 } 896 } 897 } 898 899 func TestServer_ListValidators_PaginationOutOfRange(t *testing.T) { 900 beaconDB := dbTest.SetupDB(t) 901 902 count := 1 903 validators, _, headState := setupValidators(t, beaconDB, count) 904 905 bs := &Server{ 906 HeadFetcher: &mock.ChainService{ 907 State: headState, 908 }, 909 FinalizationFetcher: &mock.ChainService{ 910 FinalizedCheckPoint: ðpb.Checkpoint{ 911 Epoch: 0, 912 }, 913 }, 914 GenesisTimeFetcher: &mock.ChainService{ 915 // We are in epoch 0. 916 Genesis: time.Now(), 917 }, 918 StateGen: stategen.New(beaconDB), 919 } 920 921 req := ðpb.ListValidatorsRequest{PageToken: strconv.Itoa(1), PageSize: 100} 922 wanted := fmt.Sprintf("page start %d >= list %d", req.PageSize, len(validators)) 923 _, err := bs.ListValidators(context.Background(), req) 924 assert.ErrorContains(t, wanted, err) 925 } 926 927 func TestServer_ListValidators_ExceedsMaxPageSize(t *testing.T) { 928 bs := &Server{} 929 exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1) 930 931 wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize) 932 req := ðpb.ListValidatorsRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax} 933 _, err := bs.ListValidators(context.Background(), req) 934 assert.ErrorContains(t, wanted, err) 935 } 936 937 func TestServer_ListValidators_DefaultPageSize(t *testing.T) { 938 beaconDB := dbTest.SetupDB(t) 939 940 validators, _, headState := setupValidators(t, beaconDB, 1000) 941 want := make([]*ethpb.Validators_ValidatorContainer, len(validators)) 942 for i := 0; i < len(validators); i++ { 943 want[i] = ðpb.Validators_ValidatorContainer{ 944 Index: types.ValidatorIndex(i), 945 Validator: validators[i], 946 } 947 } 948 949 bs := &Server{ 950 HeadFetcher: &mock.ChainService{ 951 State: headState, 952 }, 953 FinalizationFetcher: &mock.ChainService{ 954 FinalizedCheckPoint: ðpb.Checkpoint{ 955 Epoch: 0, 956 }, 957 }, 958 GenesisTimeFetcher: &mock.ChainService{ 959 // We are in epoch 0. 960 Genesis: time.Now(), 961 }, 962 StateGen: stategen.New(beaconDB), 963 } 964 965 req := ðpb.ListValidatorsRequest{} 966 res, err := bs.ListValidators(context.Background(), req) 967 require.NoError(t, err) 968 969 i := 0 970 j := params.BeaconConfig().DefaultPageSize 971 assert.DeepEqual(t, want[i:j], res.ValidatorList, "Incorrect respond of validators") 972 } 973 974 func TestServer_ListValidators_FromOldEpoch(t *testing.T) { 975 beaconDB := dbTest.SetupDB(t) 976 ctx := context.Background() 977 978 numEpochs := types.Epoch(30) 979 validators := make([]*ethpb.Validator, numEpochs) 980 for i := types.Epoch(0); i < numEpochs; i++ { 981 validators[i] = ðpb.Validator{ 982 ActivationEpoch: i, 983 PublicKey: make([]byte, 48), 984 WithdrawalCredentials: make([]byte, 32), 985 } 986 } 987 want := make([]*ethpb.Validators_ValidatorContainer, len(validators)) 988 for i := 0; i < len(validators); i++ { 989 want[i] = ðpb.Validators_ValidatorContainer{ 990 Index: types.ValidatorIndex(i), 991 Validator: validators[i], 992 } 993 } 994 995 st, err := testutil.NewBeaconState() 996 require.NoError(t, err) 997 require.NoError(t, st.SetSlot(20*params.BeaconConfig().SlotsPerEpoch)) 998 require.NoError(t, st.SetValidators(validators)) 999 b := testutil.NewBeaconBlock() 1000 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1001 gRoot, err := b.Block.HashTreeRoot() 1002 require.NoError(t, err) 1003 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 1004 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 1005 secondsPerEpoch := params.BeaconConfig().SecondsPerSlot * uint64(params.BeaconConfig().SlotsPerEpoch) 1006 bs := &Server{ 1007 HeadFetcher: &mock.ChainService{ 1008 State: st, 1009 }, 1010 GenesisTimeFetcher: &mock.ChainService{ 1011 // We are in epoch 30 1012 Genesis: time.Now().Add(time.Duration(-1*int64(30*secondsPerEpoch)) * time.Second), 1013 }, 1014 StateGen: stategen.New(beaconDB), 1015 } 1016 1017 req := ðpb.ListValidatorsRequest{ 1018 QueryFilter: ðpb.ListValidatorsRequest_Genesis{ 1019 Genesis: true, 1020 }, 1021 } 1022 res, err := bs.ListValidators(context.Background(), req) 1023 require.NoError(t, err) 1024 assert.Equal(t, 30, len(res.ValidatorList)) 1025 1026 req = ðpb.ListValidatorsRequest{ 1027 QueryFilter: ðpb.ListValidatorsRequest_Epoch{ 1028 Epoch: 20, 1029 }, 1030 } 1031 res, err = bs.ListValidators(context.Background(), req) 1032 require.NoError(t, err) 1033 assert.DeepEqual(t, want, res.ValidatorList, "Incorrect number of validators") 1034 } 1035 1036 func TestServer_ListValidators_ProcessHeadStateSlots(t *testing.T) { 1037 params.UseMinimalConfig() 1038 1039 beaconDB := dbTest.SetupDB(t) 1040 ctx := context.Background() 1041 1042 headSlot := types.Slot(32) 1043 numValidators := params.BeaconConfig().MinGenesisActiveValidatorCount 1044 validators := make([]*ethpb.Validator, numValidators) 1045 balances := make([]uint64, numValidators) 1046 for i := uint64(0); i < numValidators; i++ { 1047 validators[i] = ðpb.Validator{ 1048 ActivationEpoch: 0, 1049 PublicKey: make([]byte, 48), 1050 WithdrawalCredentials: make([]byte, 32), 1051 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 1052 } 1053 balances[i] = params.BeaconConfig().MaxEffectiveBalance 1054 } 1055 want := make([]*ethpb.Validators_ValidatorContainer, len(validators)) 1056 for i := 0; i < len(validators); i++ { 1057 want[i] = ðpb.Validators_ValidatorContainer{ 1058 Index: types.ValidatorIndex(i), 1059 Validator: validators[i], 1060 } 1061 } 1062 1063 st, err := testutil.NewBeaconState() 1064 require.NoError(t, err) 1065 require.NoError(t, st.SetSlot(headSlot)) 1066 require.NoError(t, st.SetValidators(validators)) 1067 require.NoError(t, st.SetBalances(balances)) 1068 b := testutil.NewBeaconBlock() 1069 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1070 gRoot, err := b.Block.HashTreeRoot() 1071 require.NoError(t, err) 1072 require.NoError(t, beaconDB.SaveState(ctx, st, gRoot)) 1073 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 1074 secondsPerEpoch := params.BeaconConfig().SecondsPerSlot * uint64(params.BeaconConfig().SlotsPerEpoch) 1075 bs := &Server{ 1076 HeadFetcher: &mock.ChainService{ 1077 State: st, 1078 }, 1079 GenesisTimeFetcher: &mock.ChainService{ 1080 Genesis: time.Now().Add(time.Duration(-1*int64(secondsPerEpoch)) * time.Second), 1081 }, 1082 StateGen: stategen.New(beaconDB), 1083 } 1084 1085 req := ðpb.ListValidatorsRequest{ 1086 QueryFilter: ðpb.ListValidatorsRequest_Epoch{ 1087 Epoch: 1, 1088 }, 1089 } 1090 res, err := bs.ListValidators(context.Background(), req) 1091 require.NoError(t, err) 1092 assert.Equal(t, len(want), len(res.ValidatorList), "Incorrect number of validators") 1093 for i := 0; i < len(res.ValidatorList); i++ { 1094 assert.DeepEqual(t, want[i], res.ValidatorList[i]) 1095 } 1096 } 1097 1098 func TestServer_GetValidator(t *testing.T) { 1099 count := types.Epoch(30) 1100 validators := make([]*ethpb.Validator, count) 1101 for i := types.Epoch(0); i < count; i++ { 1102 validators[i] = ðpb.Validator{ 1103 ActivationEpoch: i, 1104 PublicKey: pubKey(uint64(i)), 1105 WithdrawalCredentials: make([]byte, 32), 1106 } 1107 } 1108 1109 st, err := testutil.NewBeaconState() 1110 require.NoError(t, err) 1111 require.NoError(t, st.SetValidators(validators)) 1112 1113 bs := &Server{ 1114 HeadFetcher: &mock.ChainService{ 1115 State: st, 1116 }, 1117 } 1118 1119 tests := []struct { 1120 req *ethpb.GetValidatorRequest 1121 res *ethpb.Validator 1122 wantedErr string 1123 }{ 1124 { 1125 req: ðpb.GetValidatorRequest{ 1126 QueryFilter: ðpb.GetValidatorRequest_Index{ 1127 Index: 0, 1128 }, 1129 }, 1130 res: validators[0], 1131 }, 1132 { 1133 req: ðpb.GetValidatorRequest{ 1134 QueryFilter: ðpb.GetValidatorRequest_Index{ 1135 Index: types.ValidatorIndex(count - 1), 1136 }, 1137 }, 1138 res: validators[count-1], 1139 }, 1140 { 1141 req: ðpb.GetValidatorRequest{ 1142 QueryFilter: ðpb.GetValidatorRequest_PublicKey{ 1143 PublicKey: pubKey(5), 1144 }, 1145 }, 1146 res: validators[5], 1147 }, 1148 { 1149 req: ðpb.GetValidatorRequest{ 1150 QueryFilter: ðpb.GetValidatorRequest_PublicKey{ 1151 PublicKey: []byte("bad-keyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), 1152 }, 1153 }, 1154 res: nil, 1155 wantedErr: "No validator matched filter criteria", 1156 }, 1157 { 1158 req: ðpb.GetValidatorRequest{ 1159 QueryFilter: ðpb.GetValidatorRequest_Index{ 1160 Index: types.ValidatorIndex(len(validators)), 1161 }, 1162 }, 1163 res: nil, 1164 wantedErr: fmt.Sprintf("there are only %d validators", len(validators)), 1165 }, 1166 } 1167 1168 for _, test := range tests { 1169 res, err := bs.GetValidator(context.Background(), test.req) 1170 if test.wantedErr != "" { 1171 require.ErrorContains(t, test.wantedErr, err) 1172 } else { 1173 require.NoError(t, err) 1174 } 1175 assert.DeepEqual(t, test.res, res) 1176 } 1177 } 1178 1179 func TestServer_GetValidatorActiveSetChanges(t *testing.T) { 1180 beaconDB := dbTest.SetupDB(t) 1181 1182 ctx := context.Background() 1183 validators := make([]*ethpb.Validator, 8) 1184 headState, err := testutil.NewBeaconState() 1185 require.NoError(t, err) 1186 require.NoError(t, headState.SetSlot(0)) 1187 require.NoError(t, headState.SetValidators(validators)) 1188 for i := 0; i < len(validators); i++ { 1189 activationEpoch := params.BeaconConfig().FarFutureEpoch 1190 withdrawableEpoch := params.BeaconConfig().FarFutureEpoch 1191 exitEpoch := params.BeaconConfig().FarFutureEpoch 1192 slashed := false 1193 balance := params.BeaconConfig().MaxEffectiveBalance 1194 // Mark indices divisible by two as activated. 1195 if i%2 == 0 { 1196 activationEpoch = 0 1197 } else if i%3 == 0 { 1198 // Mark indices divisible by 3 as slashed. 1199 withdrawableEpoch = params.BeaconConfig().EpochsPerSlashingsVector 1200 slashed = true 1201 } else if i%5 == 0 { 1202 // Mark indices divisible by 5 as exited. 1203 exitEpoch = 0 1204 withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay 1205 } else if i%7 == 0 { 1206 // Mark indices divisible by 7 as ejected. 1207 exitEpoch = 0 1208 withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay 1209 balance = params.BeaconConfig().EjectionBalance 1210 } 1211 err := headState.UpdateValidatorAtIndex(types.ValidatorIndex(i), ðpb.Validator{ 1212 ActivationEpoch: activationEpoch, 1213 PublicKey: pubKey(uint64(i)), 1214 EffectiveBalance: balance, 1215 WithdrawalCredentials: make([]byte, 32), 1216 WithdrawableEpoch: withdrawableEpoch, 1217 Slashed: slashed, 1218 ExitEpoch: exitEpoch, 1219 }) 1220 require.NoError(t, err) 1221 } 1222 b := testutil.NewBeaconBlock() 1223 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1224 1225 gRoot, err := b.Block.HashTreeRoot() 1226 require.NoError(t, err) 1227 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 1228 require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot)) 1229 1230 bs := &Server{ 1231 FinalizationFetcher: &mock.ChainService{ 1232 FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 1233 }, 1234 GenesisTimeFetcher: &mock.ChainService{}, 1235 StateGen: stategen.New(beaconDB), 1236 } 1237 res, err := bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{ 1238 QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Genesis{Genesis: true}, 1239 }) 1240 require.NoError(t, err) 1241 wantedActive := [][]byte{ 1242 pubKey(0), 1243 pubKey(2), 1244 pubKey(4), 1245 pubKey(6), 1246 } 1247 wantedActiveIndices := []types.ValidatorIndex{0, 2, 4, 6} 1248 wantedExited := [][]byte{ 1249 pubKey(5), 1250 } 1251 wantedExitedIndices := []types.ValidatorIndex{5} 1252 wantedSlashed := [][]byte{ 1253 pubKey(3), 1254 } 1255 wantedSlashedIndices := []types.ValidatorIndex{3} 1256 wantedEjected := [][]byte{ 1257 pubKey(7), 1258 } 1259 wantedEjectedIndices := []types.ValidatorIndex{7} 1260 wanted := ðpb.ActiveSetChanges{ 1261 Epoch: 0, 1262 ActivatedPublicKeys: wantedActive, 1263 ActivatedIndices: wantedActiveIndices, 1264 ExitedPublicKeys: wantedExited, 1265 ExitedIndices: wantedExitedIndices, 1266 SlashedPublicKeys: wantedSlashed, 1267 SlashedIndices: wantedSlashedIndices, 1268 EjectedPublicKeys: wantedEjected, 1269 EjectedIndices: wantedEjectedIndices, 1270 } 1271 if !proto.Equal(wanted, res) { 1272 t.Errorf("Wanted \n%v, received \n%v", wanted, res) 1273 } 1274 } 1275 1276 func TestServer_GetValidatorQueue_PendingActivation(t *testing.T) { 1277 headState, err := v1.InitializeFromProto(&pb.BeaconState{ 1278 Validators: []*ethpb.Validator{ 1279 { 1280 ActivationEpoch: helpers.ActivationExitEpoch(0), 1281 ActivationEligibilityEpoch: 3, 1282 PublicKey: pubKey(3), 1283 WithdrawalCredentials: make([]byte, 32), 1284 }, 1285 { 1286 ActivationEpoch: helpers.ActivationExitEpoch(0), 1287 ActivationEligibilityEpoch: 2, 1288 PublicKey: pubKey(2), 1289 WithdrawalCredentials: make([]byte, 32), 1290 }, 1291 { 1292 ActivationEpoch: helpers.ActivationExitEpoch(0), 1293 ActivationEligibilityEpoch: 1, 1294 PublicKey: pubKey(1), 1295 WithdrawalCredentials: make([]byte, 32), 1296 }, 1297 }, 1298 FinalizedCheckpoint: ðpb.Checkpoint{ 1299 Epoch: 0, 1300 }, 1301 }) 1302 require.NoError(t, err) 1303 bs := &Server{ 1304 HeadFetcher: &mock.ChainService{ 1305 State: headState, 1306 }, 1307 } 1308 res, err := bs.GetValidatorQueue(context.Background(), &emptypb.Empty{}) 1309 require.NoError(t, err) 1310 // We verify the keys are properly sorted by the validators' activation eligibility epoch. 1311 wanted := [][]byte{ 1312 pubKey(1), 1313 pubKey(2), 1314 pubKey(3), 1315 } 1316 activeValidatorCount, err := helpers.ActiveValidatorCount(headState, helpers.CurrentEpoch(headState)) 1317 require.NoError(t, err) 1318 wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount) 1319 require.NoError(t, err) 1320 assert.Equal(t, wantChurn, res.ChurnLimit) 1321 assert.DeepEqual(t, wanted, res.ActivationPublicKeys) 1322 wantedActiveIndices := []types.ValidatorIndex{2, 1, 0} 1323 assert.DeepEqual(t, wantedActiveIndices, res.ActivationValidatorIndices) 1324 } 1325 1326 func TestServer_GetValidatorQueue_ExitedValidatorLeavesQueue(t *testing.T) { 1327 validators := []*ethpb.Validator{ 1328 { 1329 ActivationEpoch: 0, 1330 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1331 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 1332 PublicKey: bytesutil.PadTo([]byte("1"), 48), 1333 }, 1334 { 1335 ActivationEpoch: 0, 1336 ExitEpoch: 4, 1337 WithdrawableEpoch: 6, 1338 PublicKey: bytesutil.PadTo([]byte("2"), 48), 1339 }, 1340 } 1341 1342 headState, err := testutil.NewBeaconState() 1343 require.NoError(t, err) 1344 require.NoError(t, headState.SetValidators(validators)) 1345 require.NoError(t, headState.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)})) 1346 bs := &Server{ 1347 HeadFetcher: &mock.ChainService{ 1348 State: headState, 1349 }, 1350 } 1351 1352 // First we check if validator with index 1 is in the exit queue. 1353 res, err := bs.GetValidatorQueue(context.Background(), &emptypb.Empty{}) 1354 require.NoError(t, err) 1355 wanted := [][]byte{ 1356 bytesutil.PadTo([]byte("2"), 48), 1357 } 1358 activeValidatorCount, err := helpers.ActiveValidatorCount(headState, helpers.CurrentEpoch(headState)) 1359 require.NoError(t, err) 1360 wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount) 1361 require.NoError(t, err) 1362 assert.Equal(t, wantChurn, res.ChurnLimit) 1363 assert.DeepEqual(t, wanted, res.ExitPublicKeys) 1364 wantedExitIndices := []types.ValidatorIndex{1} 1365 assert.DeepEqual(t, wantedExitIndices, res.ExitValidatorIndices) 1366 1367 // Now, we move the state.slot past the exit epoch of the validator, and now 1368 // the validator should no longer exist in the queue. 1369 require.NoError(t, headState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(validators[1].ExitEpoch+1)))) 1370 res, err = bs.GetValidatorQueue(context.Background(), &emptypb.Empty{}) 1371 require.NoError(t, err) 1372 assert.Equal(t, 0, len(res.ExitPublicKeys)) 1373 } 1374 1375 func TestServer_GetValidatorQueue_PendingExit(t *testing.T) { 1376 headState, err := v1.InitializeFromProto(&pb.BeaconState{ 1377 Validators: []*ethpb.Validator{ 1378 { 1379 ActivationEpoch: 0, 1380 ExitEpoch: 4, 1381 WithdrawableEpoch: 3, 1382 PublicKey: pubKey(3), 1383 WithdrawalCredentials: make([]byte, 32), 1384 }, 1385 { 1386 ActivationEpoch: 0, 1387 ExitEpoch: 4, 1388 WithdrawableEpoch: 2, 1389 PublicKey: pubKey(2), 1390 WithdrawalCredentials: make([]byte, 32), 1391 }, 1392 { 1393 ActivationEpoch: 0, 1394 ExitEpoch: 4, 1395 WithdrawableEpoch: 1, 1396 PublicKey: pubKey(1), 1397 WithdrawalCredentials: make([]byte, 32), 1398 }, 1399 }, 1400 FinalizedCheckpoint: ðpb.Checkpoint{ 1401 Epoch: 0, 1402 }, 1403 }) 1404 require.NoError(t, err) 1405 bs := &Server{ 1406 HeadFetcher: &mock.ChainService{ 1407 State: headState, 1408 }, 1409 } 1410 res, err := bs.GetValidatorQueue(context.Background(), &emptypb.Empty{}) 1411 require.NoError(t, err) 1412 // We verify the keys are properly sorted by the validators' withdrawable epoch. 1413 wanted := [][]byte{ 1414 pubKey(1), 1415 pubKey(2), 1416 pubKey(3), 1417 } 1418 activeValidatorCount, err := helpers.ActiveValidatorCount(headState, helpers.CurrentEpoch(headState)) 1419 require.NoError(t, err) 1420 wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount) 1421 require.NoError(t, err) 1422 assert.Equal(t, wantChurn, res.ChurnLimit) 1423 assert.DeepEqual(t, wanted, res.ExitPublicKeys) 1424 } 1425 1426 func TestServer_GetValidatorParticipation_CannotRequestFutureEpoch(t *testing.T) { 1427 beaconDB := dbTest.SetupDB(t) 1428 1429 ctx := context.Background() 1430 headState, err := testutil.NewBeaconState() 1431 require.NoError(t, err) 1432 require.NoError(t, headState.SetSlot(0)) 1433 bs := &Server{ 1434 BeaconDB: beaconDB, 1435 HeadFetcher: &mock.ChainService{ 1436 State: headState, 1437 }, 1438 GenesisTimeFetcher: &mock.ChainService{}, 1439 StateGen: stategen.New(beaconDB), 1440 } 1441 1442 wanted := "Cannot retrieve information about an epoch" 1443 _, err = bs.GetValidatorParticipation( 1444 ctx, 1445 ðpb.GetValidatorParticipationRequest{ 1446 QueryFilter: ðpb.GetValidatorParticipationRequest_Epoch{ 1447 Epoch: helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1, 1448 }, 1449 }, 1450 ) 1451 assert.ErrorContains(t, wanted, err) 1452 } 1453 1454 func TestServer_GetValidatorParticipation_UnknownState(t *testing.T) { 1455 beaconDB := dbTest.SetupDB(t) 1456 1457 ctx := context.Background() 1458 headState, err := testutil.NewBeaconState() 1459 require.NoError(t, err) 1460 require.NoError(t, headState.SetSlot(0)) 1461 epoch := types.Epoch(50) 1462 slots := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)) 1463 mockStateGen := &stategen.MockStateManager{ 1464 StatesBySlot: map[types.Slot]iface.BeaconState{ 1465 0: (*v1.BeaconState)(nil), 1466 }, 1467 } 1468 bs := &Server{ 1469 BeaconDB: beaconDB, 1470 HeadFetcher: &mock.ChainService{ 1471 State: headState, 1472 }, 1473 GenesisTimeFetcher: &mock.ChainService{ 1474 Genesis: time.Now().Add(time.Duration(-1*int64(slots)) * time.Second), 1475 }, 1476 StateGen: mockStateGen, 1477 } 1478 1479 wanted := "Could not set up pre compute instance: failed to initialize precompute: nil inner state" 1480 _, err = bs.GetValidatorParticipation( 1481 ctx, 1482 ðpb.GetValidatorParticipationRequest{ 1483 QueryFilter: ðpb.GetValidatorParticipationRequest_Epoch{ 1484 Epoch: 1, 1485 }, 1486 }, 1487 ) 1488 assert.ErrorContains(t, wanted, err) 1489 } 1490 1491 func TestServer_GetValidatorParticipation_CurrentAndPrevEpoch(t *testing.T) { 1492 helpers.ClearCache() 1493 beaconDB := dbTest.SetupDB(t) 1494 1495 ctx := context.Background() 1496 validatorCount := uint64(32) 1497 1498 validators := make([]*ethpb.Validator, validatorCount) 1499 balances := make([]uint64, validatorCount) 1500 for i := 0; i < len(validators); i++ { 1501 validators[i] = ðpb.Validator{ 1502 PublicKey: bytesutil.ToBytes(uint64(i), 48), 1503 WithdrawalCredentials: make([]byte, 32), 1504 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1505 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 1506 } 1507 balances[i] = params.BeaconConfig().MaxEffectiveBalance 1508 } 1509 1510 atts := []*pb.PendingAttestation{{ 1511 Data: testutil.HydrateAttestationData(ðpb.AttestationData{}), 1512 InclusionDelay: 1, 1513 AggregationBits: bitfield.NewBitlist(validatorCount / uint64(params.BeaconConfig().SlotsPerEpoch)), 1514 }} 1515 headState, err := testutil.NewBeaconState() 1516 require.NoError(t, err) 1517 require.NoError(t, headState.SetSlot(2*params.BeaconConfig().SlotsPerEpoch-1)) 1518 require.NoError(t, headState.SetValidators(validators)) 1519 require.NoError(t, headState.SetBalances(balances)) 1520 require.NoError(t, headState.AppendCurrentEpochAttestations(atts[0])) 1521 require.NoError(t, headState.AppendPreviousEpochAttestations(atts[0])) 1522 1523 b := testutil.NewBeaconBlock() 1524 b.Block.Slot = 16 1525 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1526 bRoot, err := b.Block.HashTreeRoot() 1527 require.NoError(t, beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 1528 require.NoError(t, beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: params.BeaconConfig().ZeroHash[:]})) 1529 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bRoot)) 1530 require.NoError(t, err) 1531 require.NoError(t, beaconDB.SaveState(ctx, headState, bRoot)) 1532 1533 m := &mock.ChainService{State: headState} 1534 offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) 1535 bs := &Server{ 1536 BeaconDB: beaconDB, 1537 HeadFetcher: m, 1538 StateGen: stategen.New(beaconDB), 1539 GenesisTimeFetcher: &mock.ChainService{ 1540 Genesis: timeutils.Now().Add(time.Duration(-1*offset) * time.Second), 1541 }, 1542 CanonicalFetcher: &mock.ChainService{ 1543 CanonicalRoots: map[[32]byte]bool{ 1544 bRoot: true, 1545 }, 1546 }, 1547 FinalizationFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}}, 1548 } 1549 1550 res, err := bs.GetValidatorParticipation(ctx, ðpb.GetValidatorParticipationRequest{QueryFilter: ðpb.GetValidatorParticipationRequest_Epoch{Epoch: 1}}) 1551 require.NoError(t, err) 1552 1553 wanted := ðpb.ValidatorParticipation{ 1554 GlobalParticipationRate: float32(params.BeaconConfig().EffectiveBalanceIncrement) / float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance), 1555 VotedEther: params.BeaconConfig().EffectiveBalanceIncrement, 1556 EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1557 CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1558 CurrentEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1559 CurrentEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1560 PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1561 PreviousEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1562 PreviousEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1563 PreviousEpochHeadAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1564 } 1565 assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond") 1566 assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond") 1567 } 1568 1569 func TestServer_GetValidatorParticipation_OrphanedUntilGenesis(t *testing.T) { 1570 helpers.ClearCache() 1571 params.UseMainnetConfig() 1572 1573 beaconDB := dbTest.SetupDB(t) 1574 ctx := context.Background() 1575 validatorCount := uint64(100) 1576 1577 validators := make([]*ethpb.Validator, validatorCount) 1578 balances := make([]uint64, validatorCount) 1579 for i := 0; i < len(validators); i++ { 1580 validators[i] = ðpb.Validator{ 1581 PublicKey: bytesutil.ToBytes(uint64(i), 48), 1582 WithdrawalCredentials: make([]byte, 32), 1583 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1584 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 1585 } 1586 balances[i] = params.BeaconConfig().MaxEffectiveBalance 1587 } 1588 1589 atts := []*pb.PendingAttestation{{ 1590 Data: testutil.HydrateAttestationData(ðpb.AttestationData{}), 1591 InclusionDelay: 1, 1592 AggregationBits: bitfield.NewBitlist(validatorCount / uint64(params.BeaconConfig().SlotsPerEpoch)), 1593 }} 1594 headState, err := testutil.NewBeaconState() 1595 require.NoError(t, err) 1596 require.NoError(t, headState.SetSlot(2*params.BeaconConfig().SlotsPerEpoch-1)) 1597 require.NoError(t, headState.SetValidators(validators)) 1598 require.NoError(t, headState.SetBalances(balances)) 1599 require.NoError(t, headState.AppendCurrentEpochAttestations(atts[0])) 1600 require.NoError(t, headState.AppendPreviousEpochAttestations(atts[0])) 1601 1602 b := testutil.NewBeaconBlock() 1603 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1604 bRoot, err := b.Block.HashTreeRoot() 1605 require.NoError(t, beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 1606 require.NoError(t, beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: params.BeaconConfig().ZeroHash[:]})) 1607 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bRoot)) 1608 require.NoError(t, err) 1609 require.NoError(t, beaconDB.SaveState(ctx, headState, bRoot)) 1610 1611 m := &mock.ChainService{State: headState} 1612 offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) 1613 bs := &Server{ 1614 BeaconDB: beaconDB, 1615 HeadFetcher: m, 1616 StateGen: stategen.New(beaconDB), 1617 GenesisTimeFetcher: &mock.ChainService{ 1618 Genesis: timeutils.Now().Add(time.Duration(-1*offset) * time.Second), 1619 }, 1620 CanonicalFetcher: &mock.ChainService{ 1621 CanonicalRoots: map[[32]byte]bool{ 1622 bRoot: true, 1623 }, 1624 }, 1625 FinalizationFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}}, 1626 } 1627 1628 res, err := bs.GetValidatorParticipation(ctx, ðpb.GetValidatorParticipationRequest{QueryFilter: ðpb.GetValidatorParticipationRequest_Epoch{Epoch: 1}}) 1629 require.NoError(t, err) 1630 1631 wanted := ðpb.ValidatorParticipation{ 1632 GlobalParticipationRate: float32(params.BeaconConfig().EffectiveBalanceIncrement) / float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance), 1633 VotedEther: params.BeaconConfig().EffectiveBalanceIncrement, 1634 EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1635 CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1636 CurrentEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1637 CurrentEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1638 PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance, 1639 PreviousEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1640 PreviousEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1641 PreviousEpochHeadAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, 1642 } 1643 assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond") 1644 assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond") 1645 } 1646 1647 func TestGetValidatorPerformance_Syncing(t *testing.T) { 1648 ctx := context.Background() 1649 1650 bs := &Server{ 1651 SyncChecker: &mockSync.Sync{IsSyncing: true}, 1652 } 1653 1654 wanted := "Syncing to latest head, not ready to respond" 1655 _, err := bs.GetValidatorPerformance(ctx, nil) 1656 assert.ErrorContains(t, wanted, err) 1657 } 1658 1659 func TestGetValidatorPerformance_OK(t *testing.T) { 1660 helpers.ClearCache() 1661 params.UseMinimalConfig() 1662 defer params.UseMainnetConfig() 1663 1664 ctx := context.Background() 1665 epoch := types.Epoch(1) 1666 headState, err := testutil.NewBeaconState() 1667 require.NoError(t, err) 1668 require.NoError(t, headState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch+1)))) 1669 atts := make([]*pb.PendingAttestation, 3) 1670 for i := 0; i < len(atts); i++ { 1671 atts[i] = &pb.PendingAttestation{ 1672 Data: ðpb.AttestationData{ 1673 Target: ðpb.Checkpoint{Root: make([]byte, 32)}, 1674 Source: ðpb.Checkpoint{Root: make([]byte, 32)}, 1675 }, 1676 AggregationBits: bitfield.Bitlist{}, 1677 InclusionDelay: 1, 1678 } 1679 require.NoError(t, headState.AppendPreviousEpochAttestations(atts[i])) 1680 } 1681 defaultBal := params.BeaconConfig().MaxEffectiveBalance 1682 extraBal := params.BeaconConfig().MaxEffectiveBalance + params.BeaconConfig().GweiPerEth 1683 balances := []uint64{defaultBal, extraBal, extraBal + params.BeaconConfig().GweiPerEth} 1684 require.NoError(t, headState.SetBalances(balances)) 1685 publicKey1 := bytesutil.ToBytes48([]byte{1}) 1686 publicKey2 := bytesutil.ToBytes48([]byte{2}) 1687 publicKey3 := bytesutil.ToBytes48([]byte{3}) 1688 validators := []*ethpb.Validator{ 1689 { 1690 PublicKey: publicKey1[:], 1691 ActivationEpoch: 5, 1692 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1693 }, 1694 { 1695 PublicKey: publicKey2[:], 1696 EffectiveBalance: defaultBal, 1697 ActivationEpoch: 0, 1698 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1699 }, 1700 { 1701 PublicKey: publicKey3[:], 1702 EffectiveBalance: defaultBal, 1703 ActivationEpoch: 0, 1704 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1705 }, 1706 } 1707 require.NoError(t, headState.SetValidators(validators)) 1708 require.NoError(t, headState.SetBalances([]uint64{100, 101, 102})) 1709 offset := int64(headState.Slot().Mul(params.BeaconConfig().SecondsPerSlot)) 1710 bs := &Server{ 1711 HeadFetcher: &mock.ChainService{ 1712 State: headState, 1713 }, 1714 GenesisTimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 1715 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1716 } 1717 farFuture := params.BeaconConfig().FarFutureSlot 1718 want := ðpb.ValidatorPerformanceResponse{ 1719 PublicKeys: [][]byte{publicKey2[:], publicKey3[:]}, 1720 CurrentEffectiveBalances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 1721 InclusionSlots: []types.Slot{farFuture, farFuture}, 1722 InclusionDistances: []types.Slot{farFuture, farFuture}, 1723 CorrectlyVotedSource: []bool{false, false}, 1724 CorrectlyVotedTarget: []bool{false, false}, 1725 CorrectlyVotedHead: []bool{false, false}, 1726 BalancesBeforeEpochTransition: []uint64{101, 102}, 1727 BalancesAfterEpochTransition: []uint64{0, 0}, 1728 MissingValidators: [][]byte{publicKey1[:]}, 1729 } 1730 1731 res, err := bs.GetValidatorPerformance(ctx, ðpb.ValidatorPerformanceRequest{ 1732 PublicKeys: [][]byte{publicKey1[:], publicKey3[:], publicKey2[:]}, 1733 }) 1734 require.NoError(t, err) 1735 if !proto.Equal(want, res) { 1736 t.Errorf("Wanted %v\nReceived %v", want, res) 1737 } 1738 } 1739 1740 func TestGetValidatorPerformance_Indices(t *testing.T) { 1741 ctx := context.Background() 1742 epoch := types.Epoch(1) 1743 defaultBal := params.BeaconConfig().MaxEffectiveBalance 1744 extraBal := params.BeaconConfig().MaxEffectiveBalance + params.BeaconConfig().GweiPerEth 1745 headState, err := testutil.NewBeaconState() 1746 require.NoError(t, err) 1747 require.NoError(t, headState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch+1)))) 1748 balances := []uint64{defaultBal, extraBal, extraBal + params.BeaconConfig().GweiPerEth} 1749 require.NoError(t, headState.SetBalances(balances)) 1750 publicKey1 := bytesutil.ToBytes48([]byte{1}) 1751 publicKey2 := bytesutil.ToBytes48([]byte{2}) 1752 publicKey3 := bytesutil.ToBytes48([]byte{3}) 1753 validators := []*ethpb.Validator{ 1754 { 1755 PublicKey: publicKey1[:], 1756 ActivationEpoch: 5, 1757 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1758 }, 1759 { 1760 PublicKey: publicKey2[:], 1761 EffectiveBalance: defaultBal, 1762 ActivationEpoch: 0, 1763 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1764 }, 1765 { 1766 PublicKey: publicKey3[:], 1767 EffectiveBalance: defaultBal, 1768 ActivationEpoch: 0, 1769 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1770 }, 1771 } 1772 require.NoError(t, headState.SetValidators(validators)) 1773 offset := int64(headState.Slot().Mul(params.BeaconConfig().SecondsPerSlot)) 1774 bs := &Server{ 1775 HeadFetcher: &mock.ChainService{ 1776 // 10 epochs into the future. 1777 State: headState, 1778 }, 1779 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1780 GenesisTimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 1781 } 1782 c := headState.Copy() 1783 vp, bp, err := precompute.New(ctx, c) 1784 require.NoError(t, err) 1785 vp, bp, err = precompute.ProcessAttestations(ctx, c, vp, bp) 1786 require.NoError(t, err) 1787 _, err = precompute.ProcessRewardsAndPenaltiesPrecompute(c, bp, vp, precompute.AttestationsDelta, precompute.ProposersDelta) 1788 require.NoError(t, err) 1789 farFuture := params.BeaconConfig().FarFutureSlot 1790 want := ðpb.ValidatorPerformanceResponse{ 1791 PublicKeys: [][]byte{publicKey2[:], publicKey3[:]}, 1792 CurrentEffectiveBalances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 1793 InclusionSlots: []types.Slot{farFuture, farFuture}, 1794 InclusionDistances: []types.Slot{farFuture, farFuture}, 1795 CorrectlyVotedSource: []bool{false, false}, 1796 CorrectlyVotedTarget: []bool{false, false}, 1797 CorrectlyVotedHead: []bool{false, false}, 1798 BalancesBeforeEpochTransition: []uint64{extraBal, extraBal + params.BeaconConfig().GweiPerEth}, 1799 BalancesAfterEpochTransition: []uint64{vp[1].AfterEpochTransitionBalance, vp[2].AfterEpochTransitionBalance}, 1800 MissingValidators: [][]byte{publicKey1[:]}, 1801 } 1802 1803 res, err := bs.GetValidatorPerformance(ctx, ðpb.ValidatorPerformanceRequest{ 1804 Indices: []types.ValidatorIndex{2, 1, 0}, 1805 }) 1806 require.NoError(t, err) 1807 if !proto.Equal(want, res) { 1808 t.Errorf("Wanted %v\nReceived %v", want, res) 1809 } 1810 } 1811 1812 func TestGetValidatorPerformance_IndicesPubkeys(t *testing.T) { 1813 ctx := context.Background() 1814 epoch := types.Epoch(1) 1815 defaultBal := params.BeaconConfig().MaxEffectiveBalance 1816 extraBal := params.BeaconConfig().MaxEffectiveBalance + params.BeaconConfig().GweiPerEth 1817 headState, err := testutil.NewBeaconState() 1818 require.NoError(t, err) 1819 require.NoError(t, headState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch+1)))) 1820 balances := []uint64{defaultBal, extraBal, extraBal + params.BeaconConfig().GweiPerEth} 1821 require.NoError(t, headState.SetBalances(balances)) 1822 publicKey1 := bytesutil.ToBytes48([]byte{1}) 1823 publicKey2 := bytesutil.ToBytes48([]byte{2}) 1824 publicKey3 := bytesutil.ToBytes48([]byte{3}) 1825 validators := []*ethpb.Validator{ 1826 { 1827 PublicKey: publicKey1[:], 1828 ActivationEpoch: 5, 1829 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1830 }, 1831 { 1832 PublicKey: publicKey2[:], 1833 EffectiveBalance: defaultBal, 1834 ActivationEpoch: 0, 1835 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1836 }, 1837 { 1838 PublicKey: publicKey3[:], 1839 EffectiveBalance: defaultBal, 1840 ActivationEpoch: 0, 1841 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 1842 }, 1843 } 1844 require.NoError(t, headState.SetValidators(validators)) 1845 1846 offset := int64(headState.Slot().Mul(params.BeaconConfig().SecondsPerSlot)) 1847 bs := &Server{ 1848 HeadFetcher: &mock.ChainService{ 1849 // 10 epochs into the future. 1850 State: headState, 1851 }, 1852 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1853 GenesisTimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 1854 } 1855 c := headState.Copy() 1856 vp, bp, err := precompute.New(ctx, c) 1857 require.NoError(t, err) 1858 vp, bp, err = precompute.ProcessAttestations(ctx, c, vp, bp) 1859 require.NoError(t, err) 1860 _, err = precompute.ProcessRewardsAndPenaltiesPrecompute(c, bp, vp, precompute.AttestationsDelta, precompute.ProposersDelta) 1861 require.NoError(t, err) 1862 farFuture := params.BeaconConfig().FarFutureSlot 1863 want := ðpb.ValidatorPerformanceResponse{ 1864 PublicKeys: [][]byte{publicKey2[:], publicKey3[:]}, 1865 CurrentEffectiveBalances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}, 1866 InclusionSlots: []types.Slot{farFuture, farFuture}, 1867 InclusionDistances: []types.Slot{farFuture, farFuture}, 1868 CorrectlyVotedSource: []bool{false, false}, 1869 CorrectlyVotedTarget: []bool{false, false}, 1870 CorrectlyVotedHead: []bool{false, false}, 1871 BalancesBeforeEpochTransition: []uint64{extraBal, extraBal + params.BeaconConfig().GweiPerEth}, 1872 BalancesAfterEpochTransition: []uint64{vp[1].AfterEpochTransitionBalance, vp[2].AfterEpochTransitionBalance}, 1873 MissingValidators: [][]byte{publicKey1[:]}, 1874 } 1875 // Index 2 and publicKey3 points to the same validator. 1876 // Should not return duplicates. 1877 res, err := bs.GetValidatorPerformance(ctx, ðpb.ValidatorPerformanceRequest{ 1878 PublicKeys: [][]byte{publicKey1[:], publicKey3[:]}, Indices: []types.ValidatorIndex{1, 2}, 1879 }) 1880 require.NoError(t, err) 1881 if !proto.Equal(want, res) { 1882 t.Errorf("Wanted %v\nReceived %v", want, res) 1883 } 1884 } 1885 1886 func BenchmarkListValidatorBalances(b *testing.B) { 1887 b.StopTimer() 1888 beaconDB := dbTest.SetupDB(b) 1889 ctx := context.Background() 1890 1891 count := 1000 1892 _, _, headState := setupValidators(b, beaconDB, count) 1893 bs := &Server{ 1894 HeadFetcher: &mock.ChainService{ 1895 State: headState, 1896 }, 1897 } 1898 1899 req := ðpb.ListValidatorBalancesRequest{PageSize: 100} 1900 b.StartTimer() 1901 for i := 0; i < b.N; i++ { 1902 _, err := bs.ListValidatorBalances(ctx, req) 1903 require.NoError(b, err) 1904 } 1905 } 1906 1907 func setupValidators(t testing.TB, _ db.Database, count int) ([]*ethpb.Validator, []uint64, iface.BeaconState) { 1908 balances := make([]uint64, count) 1909 validators := make([]*ethpb.Validator, 0, count) 1910 for i := 0; i < count; i++ { 1911 pubKey := pubKey(uint64(i)) 1912 balances[i] = uint64(i) 1913 validators = append(validators, ðpb.Validator{ 1914 PublicKey: pubKey, 1915 WithdrawalCredentials: make([]byte, 32), 1916 }) 1917 } 1918 s, err := testutil.NewBeaconState() 1919 require.NoError(t, err) 1920 require.NoError(t, s.SetValidators(validators)) 1921 require.NoError(t, s.SetBalances(balances)) 1922 return validators, balances, s 1923 } 1924 1925 func TestServer_GetIndividualVotes_RequestFutureSlot(t *testing.T) { 1926 ds := &Server{GenesisTimeFetcher: &mock.ChainService{}} 1927 req := ðpb.IndividualVotesRequest{ 1928 Epoch: helpers.SlotToEpoch(ds.GenesisTimeFetcher.CurrentSlot()) + 1, 1929 } 1930 wanted := errNoEpochInfoError 1931 _, err := ds.GetIndividualVotes(context.Background(), req) 1932 assert.ErrorContains(t, wanted, err) 1933 } 1934 1935 func TestServer_GetIndividualVotes_ValidatorsDontExist(t *testing.T) { 1936 params.UseMinimalConfig() 1937 defer params.UseMainnetConfig() 1938 1939 beaconDB := dbTest.SetupDB(t) 1940 ctx := context.Background() 1941 1942 validators := uint64(64) 1943 stateWithValidators, _ := testutil.DeterministicGenesisState(t, validators) 1944 beaconState, err := testutil.NewBeaconState() 1945 require.NoError(t, err) 1946 require.NoError(t, beaconState.SetValidators(stateWithValidators.Validators())) 1947 require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch)) 1948 1949 b := testutil.NewBeaconBlock() 1950 b.Block.Slot = params.BeaconConfig().SlotsPerEpoch 1951 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 1952 gRoot, err := b.Block.HashTreeRoot() 1953 require.NoError(t, err) 1954 gen := stategen.New(beaconDB) 1955 require.NoError(t, gen.SaveState(ctx, gRoot, beaconState)) 1956 require.NoError(t, beaconDB.SaveState(ctx, beaconState, gRoot)) 1957 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 1958 bs := &Server{ 1959 StateGen: gen, 1960 GenesisTimeFetcher: &mock.ChainService{}, 1961 } 1962 1963 // Test non exist public key. 1964 res, err := bs.GetIndividualVotes(ctx, ðpb.IndividualVotesRequest{ 1965 PublicKeys: [][]byte{{'a'}}, 1966 Epoch: 0, 1967 }) 1968 require.NoError(t, err) 1969 wanted := ðpb.IndividualVotesRespond{ 1970 IndividualVotes: []*ethpb.IndividualVotesRespond_IndividualVote{ 1971 {PublicKey: []byte{'a'}, ValidatorIndex: types.ValidatorIndex(^uint64(0))}, 1972 }, 1973 } 1974 assert.DeepEqual(t, wanted, res, "Unexpected response") 1975 1976 // Test non-existent validator index. 1977 res, err = bs.GetIndividualVotes(ctx, ðpb.IndividualVotesRequest{ 1978 Indices: []types.ValidatorIndex{100}, 1979 Epoch: 0, 1980 }) 1981 require.NoError(t, err) 1982 wanted = ðpb.IndividualVotesRespond{ 1983 IndividualVotes: []*ethpb.IndividualVotesRespond_IndividualVote{ 1984 {ValidatorIndex: 100}, 1985 }, 1986 } 1987 assert.DeepEqual(t, wanted, res, "Unexpected response") 1988 1989 // Test both. 1990 res, err = bs.GetIndividualVotes(ctx, ðpb.IndividualVotesRequest{ 1991 PublicKeys: [][]byte{{'a'}, {'b'}}, 1992 Indices: []types.ValidatorIndex{100, 101}, 1993 Epoch: 0, 1994 }) 1995 require.NoError(t, err) 1996 wanted = ðpb.IndividualVotesRespond{ 1997 IndividualVotes: []*ethpb.IndividualVotesRespond_IndividualVote{ 1998 {PublicKey: []byte{'a'}, ValidatorIndex: types.ValidatorIndex(^uint64(0))}, 1999 {PublicKey: []byte{'b'}, ValidatorIndex: types.ValidatorIndex(^uint64(0))}, 2000 {ValidatorIndex: 100}, 2001 {ValidatorIndex: 101}, 2002 }, 2003 } 2004 assert.DeepEqual(t, wanted, res, "Unexpected response") 2005 } 2006 2007 func TestServer_GetIndividualVotes_Working(t *testing.T) { 2008 helpers.ClearCache() 2009 2010 params.UseMinimalConfig() 2011 defer params.UseMainnetConfig() 2012 beaconDB := dbTest.SetupDB(t) 2013 ctx := context.Background() 2014 2015 validators := uint64(32) 2016 stateWithValidators, _ := testutil.DeterministicGenesisState(t, validators) 2017 beaconState, err := testutil.NewBeaconState() 2018 require.NoError(t, err) 2019 require.NoError(t, beaconState.SetValidators(stateWithValidators.Validators())) 2020 require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch)) 2021 2022 bf := bitfield.NewBitlist(validators / uint64(params.BeaconConfig().SlotsPerEpoch)) 2023 att1 := testutil.NewAttestation() 2024 att1.AggregationBits = bf 2025 att2 := testutil.NewAttestation() 2026 att2.AggregationBits = bf 2027 rt := [32]byte{'A'} 2028 att1.Data.Target.Root = rt[:] 2029 att1.Data.BeaconBlockRoot = rt[:] 2030 br := beaconState.BlockRoots() 2031 newRt := [32]byte{'B'} 2032 br[0] = newRt[:] 2033 require.NoError(t, beaconState.SetBlockRoots(br)) 2034 att2.Data.Target.Root = rt[:] 2035 att2.Data.BeaconBlockRoot = newRt[:] 2036 err = beaconState.AppendPreviousEpochAttestations(&pb.PendingAttestation{ 2037 Data: att1.Data, AggregationBits: bf, InclusionDelay: 1, 2038 }) 2039 require.NoError(t, err) 2040 err = beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{ 2041 Data: att2.Data, AggregationBits: bf, InclusionDelay: 1, 2042 }) 2043 require.NoError(t, err) 2044 2045 b := testutil.NewBeaconBlock() 2046 b.Block.Slot = params.BeaconConfig().SlotsPerEpoch 2047 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 2048 gRoot, err := b.Block.HashTreeRoot() 2049 require.NoError(t, err) 2050 gen := stategen.New(beaconDB) 2051 require.NoError(t, gen.SaveState(ctx, gRoot, beaconState)) 2052 require.NoError(t, beaconDB.SaveState(ctx, beaconState, gRoot)) 2053 require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot)) 2054 bs := &Server{ 2055 StateGen: gen, 2056 GenesisTimeFetcher: &mock.ChainService{}, 2057 } 2058 2059 res, err := bs.GetIndividualVotes(ctx, ðpb.IndividualVotesRequest{ 2060 Indices: []types.ValidatorIndex{0, 1}, 2061 Epoch: 0, 2062 }) 2063 require.NoError(t, err) 2064 wanted := ðpb.IndividualVotesRespond{ 2065 IndividualVotes: []*ethpb.IndividualVotesRespond_IndividualVote{ 2066 { 2067 ValidatorIndex: 0, 2068 PublicKey: beaconState.Validators()[0].PublicKey, 2069 IsActiveInCurrentEpoch: true, 2070 IsActiveInPreviousEpoch: true, 2071 CurrentEpochEffectiveBalanceGwei: params.BeaconConfig().MaxEffectiveBalance, 2072 InclusionSlot: params.BeaconConfig().FarFutureSlot, 2073 InclusionDistance: params.BeaconConfig().FarFutureSlot, 2074 }, 2075 { 2076 ValidatorIndex: 1, 2077 PublicKey: beaconState.Validators()[1].PublicKey, 2078 IsActiveInCurrentEpoch: true, 2079 IsActiveInPreviousEpoch: true, 2080 CurrentEpochEffectiveBalanceGwei: params.BeaconConfig().MaxEffectiveBalance, 2081 InclusionSlot: params.BeaconConfig().FarFutureSlot, 2082 InclusionDistance: params.BeaconConfig().FarFutureSlot, 2083 }, 2084 }, 2085 } 2086 assert.DeepEqual(t, wanted, res, "Unexpected response") 2087 } 2088 2089 func Test_validatorStatus(t *testing.T) { 2090 tests := []struct { 2091 name string 2092 validator *ethpb.Validator 2093 epoch types.Epoch 2094 want ethpb.ValidatorStatus 2095 }{ 2096 { 2097 name: "Unknown", 2098 validator: nil, 2099 epoch: 0, 2100 want: ethpb.ValidatorStatus_UNKNOWN_STATUS, 2101 }, 2102 { 2103 name: "Deposited", 2104 validator: ðpb.Validator{ 2105 ActivationEligibilityEpoch: 1, 2106 }, 2107 epoch: 0, 2108 want: ethpb.ValidatorStatus_DEPOSITED, 2109 }, 2110 { 2111 name: "Pending", 2112 validator: ðpb.Validator{ 2113 ActivationEligibilityEpoch: 0, 2114 ActivationEpoch: 1, 2115 }, 2116 epoch: 0, 2117 want: ethpb.ValidatorStatus_PENDING, 2118 }, 2119 { 2120 name: "Active", 2121 validator: ðpb.Validator{ 2122 ActivationEligibilityEpoch: 0, 2123 ActivationEpoch: 0, 2124 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 2125 }, 2126 epoch: 0, 2127 want: ethpb.ValidatorStatus_ACTIVE, 2128 }, 2129 { 2130 name: "Slashed", 2131 validator: ðpb.Validator{ 2132 ActivationEligibilityEpoch: 0, 2133 ActivationEpoch: 0, 2134 ExitEpoch: 5, 2135 Slashed: true, 2136 }, 2137 epoch: 4, 2138 want: ethpb.ValidatorStatus_SLASHING, 2139 }, 2140 { 2141 name: "Exiting", 2142 validator: ðpb.Validator{ 2143 ActivationEligibilityEpoch: 0, 2144 ActivationEpoch: 0, 2145 ExitEpoch: 5, 2146 Slashed: false, 2147 }, 2148 epoch: 4, 2149 want: ethpb.ValidatorStatus_EXITING, 2150 }, 2151 { 2152 name: "Exiting", 2153 validator: ðpb.Validator{ 2154 ActivationEligibilityEpoch: 0, 2155 ActivationEpoch: 0, 2156 ExitEpoch: 3, 2157 Slashed: false, 2158 }, 2159 epoch: 4, 2160 want: ethpb.ValidatorStatus_EXITED, 2161 }, 2162 } 2163 for _, tt := range tests { 2164 t.Run(tt.name, func(t *testing.T) { 2165 if got := validatorStatus(tt.validator, tt.epoch); got != tt.want { 2166 t.Errorf("validatorStatus() = %v, want %v", got, tt.want) 2167 } 2168 }) 2169 } 2170 } 2171 2172 func TestServer_isSlotCanonical(t *testing.T) { 2173 beaconDB := dbTest.SetupDB(t) 2174 ctx := context.Background() 2175 var roots [][32]byte 2176 cRoots := map[[32]byte]bool{} 2177 for i := 1; i < 100; i++ { 2178 b := testutil.NewBeaconBlock() 2179 b.Block.Slot = types.Slot(i) 2180 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 2181 br, err := b.Block.HashTreeRoot() 2182 require.NoError(t, err) 2183 if i%2 == 0 { 2184 cRoots[br] = true 2185 } 2186 roots = append(roots, br) 2187 } 2188 2189 bs := &Server{ 2190 BeaconDB: beaconDB, 2191 CanonicalFetcher: &mock.ChainService{ 2192 CanonicalRoots: cRoots, 2193 }, 2194 } 2195 2196 for i := range roots { 2197 slot := types.Slot(i + 1) 2198 c, err := bs.isSlotCanonical(ctx, slot) 2199 require.NoError(t, err) 2200 if slot%2 == 0 { 2201 require.Equal(t, true, c) 2202 } else { 2203 require.Equal(t, false, c) 2204 } 2205 } 2206 } 2207 2208 func TestServer_isSlotCanonical_MultipleBlocks(t *testing.T) { 2209 beaconDB := dbTest.SetupDB(t) 2210 ctx := context.Background() 2211 var roots [][32]byte 2212 cRoots := map[[32]byte]bool{} 2213 for i := 1; i < 100; i++ { 2214 b := testutil.NewBeaconBlock() 2215 b.Block.Slot = types.Slot(i) 2216 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 2217 br, err := b.Block.HashTreeRoot() 2218 require.NoError(t, err) 2219 if i%2 == 0 { 2220 cRoots[br] = true 2221 // Save a block in the same slot 2222 b = testutil.NewBeaconBlock() 2223 b.Block.Slot = types.Slot(i) 2224 b.Block.ProposerIndex = 100 2225 require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 2226 } 2227 roots = append(roots, br) 2228 } 2229 2230 bs := &Server{ 2231 BeaconDB: beaconDB, 2232 CanonicalFetcher: &mock.ChainService{ 2233 CanonicalRoots: cRoots, 2234 }, 2235 } 2236 2237 for i := range roots { 2238 slot := types.Slot(i + 1) 2239 c, err := bs.isSlotCanonical(ctx, slot) 2240 require.NoError(t, err) 2241 if slot%2 == 0 { 2242 require.Equal(t, true, c) 2243 } else { 2244 require.Equal(t, false, c) 2245 } 2246 } 2247 } 2248 2249 func TestServer_isSlotCanonicalForSlot0(t *testing.T) { 2250 ctx := context.Background() 2251 bs := &Server{} 2252 c, err := bs.isSlotCanonical(ctx, 0) 2253 require.NoError(t, err) 2254 require.Equal(t, true, c) 2255 }