github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/beacon/validators.go (about) 1 package beacon 2 3 import ( 4 "context" 5 "sort" 6 "strconv" 7 "time" 8 9 types "github.com/prysmaticlabs/eth2-types" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" 11 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 12 "github.com/prysmaticlabs/prysm/beacon-chain/core/state" 13 "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" 14 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 15 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 16 "github.com/prysmaticlabs/prysm/shared/bytesutil" 17 "github.com/prysmaticlabs/prysm/shared/cmd" 18 "github.com/prysmaticlabs/prysm/shared/pagination" 19 "github.com/prysmaticlabs/prysm/shared/params" 20 "google.golang.org/grpc/codes" 21 "google.golang.org/grpc/status" 22 "google.golang.org/protobuf/types/known/emptypb" 23 ) 24 25 // BalancesTimeout for gRPC requests to ListValidatorBalances. 26 const BalancesTimeout = time.Second * 30 27 28 // ListValidatorBalances retrieves the validator balances for a given set of public keys. 29 // An optional Epoch parameter is provided to request historical validator balances from 30 // archived, persistent data. 31 func (bs *Server) ListValidatorBalances( 32 ctx context.Context, 33 req *ethpb.ListValidatorBalancesRequest, 34 ) (*ethpb.ValidatorBalances, error) { 35 ctx, cancel := context.WithTimeout(ctx, BalancesTimeout) 36 defer cancel() 37 if int(req.PageSize) > cmd.Get().MaxRPCPageSize { 38 return nil, status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", 39 req.PageSize, cmd.Get().MaxRPCPageSize) 40 } 41 42 if bs.GenesisTimeFetcher == nil { 43 return nil, status.Errorf(codes.Internal, "Nil genesis time fetcher") 44 } 45 currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) 46 requestedEpoch := currentEpoch 47 switch q := req.QueryFilter.(type) { 48 case *ethpb.ListValidatorBalancesRequest_Epoch: 49 requestedEpoch = q.Epoch 50 case *ethpb.ListValidatorBalancesRequest_Genesis: 51 requestedEpoch = 0 52 } 53 54 if requestedEpoch > currentEpoch { 55 return nil, status.Errorf( 56 codes.InvalidArgument, 57 errEpoch, 58 currentEpoch, 59 requestedEpoch, 60 ) 61 } 62 res := make([]*ethpb.ValidatorBalances_Balance, 0) 63 filtered := map[types.ValidatorIndex]bool{} // Track filtered validators to prevent duplication in the response. 64 65 startSlot, err := helpers.StartSlot(requestedEpoch) 66 if err != nil { 67 return nil, err 68 } 69 requestedState, err := bs.StateGen.StateBySlot(ctx, startSlot) 70 if err != nil { 71 return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) 72 } 73 74 vals := requestedState.Validators() 75 balances := requestedState.Balances() 76 balancesCount := len(balances) 77 for _, pubKey := range req.PublicKeys { 78 // Skip empty public key. 79 if len(pubKey) == 0 { 80 continue 81 } 82 pubkeyBytes := bytesutil.ToBytes48(pubKey) 83 index, ok := requestedState.ValidatorIndexByPubkey(pubkeyBytes) 84 if !ok { 85 // We continue the loop if one validator in the request is not found. 86 res = append(res, ðpb.ValidatorBalances_Balance{ 87 Status: "UNKNOWN", 88 }) 89 balancesCount = len(res) 90 continue 91 } 92 filtered[index] = true 93 94 if uint64(index) >= uint64(len(balances)) { 95 return nil, status.Errorf(codes.OutOfRange, "Validator index %d >= balance list %d", 96 index, len(balances)) 97 } 98 99 val := vals[index] 100 st := validatorStatus(val, requestedEpoch) 101 res = append(res, ðpb.ValidatorBalances_Balance{ 102 PublicKey: pubKey, 103 Index: index, 104 Balance: balances[index], 105 Status: st.String(), 106 }) 107 balancesCount = len(res) 108 } 109 110 for _, index := range req.Indices { 111 if uint64(index) >= uint64(len(balances)) { 112 return nil, status.Errorf(codes.OutOfRange, "Validator index %d >= balance list %d", 113 index, len(balances)) 114 } 115 116 if !filtered[index] { 117 val := vals[index] 118 st := validatorStatus(val, requestedEpoch) 119 res = append(res, ðpb.ValidatorBalances_Balance{ 120 PublicKey: vals[index].PublicKey, 121 Index: index, 122 Balance: balances[index], 123 Status: st.String(), 124 }) 125 } 126 balancesCount = len(res) 127 } 128 // Depending on the indices and public keys given, results might not be sorted. 129 sort.Slice(res, func(i, j int) bool { 130 return res[i].Index < res[j].Index 131 }) 132 133 // If there are no balances, we simply return a response specifying this. 134 // Otherwise, attempting to paginate 0 balances below would result in an error. 135 if balancesCount == 0 { 136 return ðpb.ValidatorBalances{ 137 Epoch: requestedEpoch, 138 Balances: make([]*ethpb.ValidatorBalances_Balance, 0), 139 TotalSize: int32(0), 140 NextPageToken: strconv.Itoa(0), 141 }, nil 142 } 143 144 start, end, nextPageToken, err := pagination.StartAndEndPage(req.PageToken, int(req.PageSize), balancesCount) 145 if err != nil { 146 return nil, status.Errorf( 147 codes.Internal, 148 "Could not paginate results: %v", 149 err, 150 ) 151 } 152 153 if len(req.Indices) == 0 && len(req.PublicKeys) == 0 { 154 // Return everything. 155 for i := start; i < end; i++ { 156 pubkey := requestedState.PubkeyAtIndex(types.ValidatorIndex(i)) 157 val := vals[i] 158 st := validatorStatus(val, requestedEpoch) 159 res = append(res, ðpb.ValidatorBalances_Balance{ 160 PublicKey: pubkey[:], 161 Index: types.ValidatorIndex(i), 162 Balance: balances[i], 163 Status: st.String(), 164 }) 165 } 166 return ðpb.ValidatorBalances{ 167 Epoch: requestedEpoch, 168 Balances: res, 169 TotalSize: int32(balancesCount), 170 NextPageToken: nextPageToken, 171 }, nil 172 } 173 174 if end > len(res) || end < start { 175 return nil, status.Error(codes.OutOfRange, "Request exceeds response length") 176 } 177 178 return ðpb.ValidatorBalances{ 179 Epoch: requestedEpoch, 180 Balances: res[start:end], 181 TotalSize: int32(balancesCount), 182 NextPageToken: nextPageToken, 183 }, nil 184 } 185 186 // ListValidators retrieves the current list of active validators with an optional historical epoch flag to 187 // to retrieve validator set in time. 188 func (bs *Server) ListValidators( 189 ctx context.Context, 190 req *ethpb.ListValidatorsRequest, 191 ) (*ethpb.Validators, error) { 192 if int(req.PageSize) > cmd.Get().MaxRPCPageSize { 193 return nil, status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", 194 req.PageSize, cmd.Get().MaxRPCPageSize) 195 } 196 197 currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) 198 requestedEpoch := currentEpoch 199 200 switch q := req.QueryFilter.(type) { 201 case *ethpb.ListValidatorsRequest_Genesis: 202 if q.Genesis { 203 requestedEpoch = 0 204 } 205 case *ethpb.ListValidatorsRequest_Epoch: 206 if q.Epoch > currentEpoch { 207 return nil, status.Errorf( 208 codes.InvalidArgument, 209 errEpoch, 210 currentEpoch, 211 q.Epoch, 212 ) 213 } 214 requestedEpoch = q.Epoch 215 } 216 var reqState iface.BeaconState 217 var err error 218 if requestedEpoch != currentEpoch { 219 var s types.Slot 220 s, err = helpers.StartSlot(requestedEpoch) 221 if err != nil { 222 return nil, err 223 } 224 reqState, err = bs.StateGen.StateBySlot(ctx, s) 225 } else { 226 reqState, err = bs.HeadFetcher.HeadState(ctx) 227 } 228 if err != nil { 229 return nil, status.Errorf(codes.Internal, "Could not get requested state: %v", err) 230 } 231 232 s, err := helpers.StartSlot(requestedEpoch) 233 if err != nil { 234 return nil, err 235 } 236 if s > reqState.Slot() { 237 reqState = reqState.Copy() 238 reqState, err = state.ProcessSlots(ctx, reqState, s) 239 if err != nil { 240 return nil, status.Errorf( 241 codes.Internal, 242 "Could not process slots up to epoch %d: %v", 243 requestedEpoch, 244 err, 245 ) 246 } 247 } 248 249 validatorList := make([]*ethpb.Validators_ValidatorContainer, 0) 250 251 for _, index := range req.Indices { 252 val, err := reqState.ValidatorAtIndex(index) 253 if err != nil { 254 return nil, status.Errorf(codes.Internal, "Could not get validator: %v", err) 255 } 256 validatorList = append(validatorList, ðpb.Validators_ValidatorContainer{ 257 Index: index, 258 Validator: val, 259 }) 260 } 261 262 for _, pubKey := range req.PublicKeys { 263 // Skip empty public key. 264 if len(pubKey) == 0 { 265 continue 266 } 267 pubkeyBytes := bytesutil.ToBytes48(pubKey) 268 index, ok := reqState.ValidatorIndexByPubkey(pubkeyBytes) 269 if !ok { 270 continue 271 } 272 val, err := reqState.ValidatorAtIndex(index) 273 if err != nil { 274 return nil, status.Errorf(codes.Internal, "Could not get validator: %v", err) 275 } 276 validatorList = append(validatorList, ðpb.Validators_ValidatorContainer{ 277 Index: index, 278 Validator: val, 279 }) 280 } 281 // Depending on the indices and public keys given, results might not be sorted. 282 sort.Slice(validatorList, func(i, j int) bool { 283 return validatorList[i].Index < validatorList[j].Index 284 }) 285 286 if len(req.PublicKeys) == 0 && len(req.Indices) == 0 { 287 for i := types.ValidatorIndex(0); uint64(i) < uint64(reqState.NumValidators()); i++ { 288 val, err := reqState.ValidatorAtIndex(i) 289 if err != nil { 290 return nil, status.Errorf(codes.Internal, "Could not get validator: %v", err) 291 } 292 validatorList = append(validatorList, ðpb.Validators_ValidatorContainer{ 293 Index: i, 294 Validator: val, 295 }) 296 } 297 } 298 299 // Filter active validators if the request specifies it. 300 res := validatorList 301 if req.Active { 302 filteredValidators := make([]*ethpb.Validators_ValidatorContainer, 0) 303 for _, item := range validatorList { 304 if helpers.IsActiveValidator(item.Validator, requestedEpoch) { 305 filteredValidators = append(filteredValidators, item) 306 } 307 } 308 res = filteredValidators 309 } 310 311 validatorCount := len(res) 312 // If there are no items, we simply return a response specifying this. 313 // Otherwise, attempting to paginate 0 validators below would result in an error. 314 if validatorCount == 0 { 315 return ðpb.Validators{ 316 ValidatorList: make([]*ethpb.Validators_ValidatorContainer, 0), 317 TotalSize: int32(0), 318 NextPageToken: strconv.Itoa(0), 319 }, nil 320 } 321 322 start, end, nextPageToken, err := pagination.StartAndEndPage(req.PageToken, int(req.PageSize), validatorCount) 323 if err != nil { 324 return nil, status.Errorf( 325 codes.Internal, 326 "Could not paginate results: %v", 327 err, 328 ) 329 } 330 331 return ðpb.Validators{ 332 ValidatorList: res[start:end], 333 TotalSize: int32(validatorCount), 334 NextPageToken: nextPageToken, 335 }, nil 336 } 337 338 // GetValidator information from any validator in the registry by index or public key. 339 func (bs *Server) GetValidator( 340 ctx context.Context, req *ethpb.GetValidatorRequest, 341 ) (*ethpb.Validator, error) { 342 var requestingIndex bool 343 var index types.ValidatorIndex 344 var pubKey []byte 345 switch q := req.QueryFilter.(type) { 346 case *ethpb.GetValidatorRequest_Index: 347 index = q.Index 348 requestingIndex = true 349 case *ethpb.GetValidatorRequest_PublicKey: 350 pubKey = q.PublicKey 351 default: 352 return nil, status.Error( 353 codes.InvalidArgument, 354 "Need to specify either validator index or public key in request", 355 ) 356 } 357 headState, err := bs.HeadFetcher.HeadState(ctx) 358 if err != nil { 359 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 360 } 361 if requestingIndex { 362 if uint64(index) >= uint64(headState.NumValidators()) { 363 return nil, status.Errorf( 364 codes.OutOfRange, 365 "Requesting index %d, but there are only %d validators", 366 index, 367 headState.NumValidators(), 368 ) 369 } 370 return headState.ValidatorAtIndex(index) 371 } 372 pk48 := bytesutil.ToBytes48(pubKey) 373 for i := types.ValidatorIndex(0); uint64(i) < uint64(headState.NumValidators()); i++ { 374 keyFromState := headState.PubkeyAtIndex(i) 375 if keyFromState == pk48 { 376 return headState.ValidatorAtIndex(i) 377 } 378 } 379 return nil, status.Error(codes.NotFound, "No validator matched filter criteria") 380 } 381 382 // GetValidatorActiveSetChanges retrieves the active set changes for a given epoch. 383 // 384 // This data includes any activations, voluntary exits, and involuntary 385 // ejections. 386 func (bs *Server) GetValidatorActiveSetChanges( 387 ctx context.Context, req *ethpb.GetValidatorActiveSetChangesRequest, 388 ) (*ethpb.ActiveSetChanges, error) { 389 currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) 390 391 var requestedEpoch types.Epoch 392 switch q := req.QueryFilter.(type) { 393 case *ethpb.GetValidatorActiveSetChangesRequest_Genesis: 394 requestedEpoch = 0 395 case *ethpb.GetValidatorActiveSetChangesRequest_Epoch: 396 requestedEpoch = q.Epoch 397 default: 398 requestedEpoch = currentEpoch 399 } 400 if requestedEpoch > currentEpoch { 401 return nil, status.Errorf( 402 codes.InvalidArgument, 403 errEpoch, 404 currentEpoch, 405 requestedEpoch, 406 ) 407 } 408 409 s, err := helpers.StartSlot(requestedEpoch) 410 if err != nil { 411 return nil, err 412 } 413 requestedState, err := bs.StateGen.StateBySlot(ctx, s) 414 if err != nil { 415 return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) 416 } 417 418 activeValidatorCount, err := helpers.ActiveValidatorCount(requestedState, helpers.CurrentEpoch(requestedState)) 419 if err != nil { 420 return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err) 421 } 422 vs := requestedState.Validators() 423 activatedIndices := validators.ActivatedValidatorIndices(helpers.CurrentEpoch(requestedState), vs) 424 exitedIndices, err := validators.ExitedValidatorIndices(helpers.CurrentEpoch(requestedState), vs, activeValidatorCount) 425 if err != nil { 426 return nil, status.Errorf(codes.Internal, "Could not determine exited validator indices: %v", err) 427 } 428 slashedIndices := validators.SlashedValidatorIndices(helpers.CurrentEpoch(requestedState), vs) 429 ejectedIndices, err := validators.EjectedValidatorIndices(helpers.CurrentEpoch(requestedState), vs, activeValidatorCount) 430 if err != nil { 431 return nil, status.Errorf(codes.Internal, "Could not determine ejected validator indices: %v", err) 432 } 433 434 // Retrieve public keys for the indices. 435 activatedKeys := make([][]byte, len(activatedIndices)) 436 exitedKeys := make([][]byte, len(exitedIndices)) 437 slashedKeys := make([][]byte, len(slashedIndices)) 438 ejectedKeys := make([][]byte, len(ejectedIndices)) 439 for i, idx := range activatedIndices { 440 pubkey := requestedState.PubkeyAtIndex(idx) 441 activatedKeys[i] = pubkey[:] 442 } 443 for i, idx := range exitedIndices { 444 pubkey := requestedState.PubkeyAtIndex(idx) 445 exitedKeys[i] = pubkey[:] 446 } 447 for i, idx := range slashedIndices { 448 pubkey := requestedState.PubkeyAtIndex(idx) 449 slashedKeys[i] = pubkey[:] 450 } 451 for i, idx := range ejectedIndices { 452 pubkey := requestedState.PubkeyAtIndex(idx) 453 ejectedKeys[i] = pubkey[:] 454 } 455 return ðpb.ActiveSetChanges{ 456 Epoch: requestedEpoch, 457 ActivatedPublicKeys: activatedKeys, 458 ActivatedIndices: activatedIndices, 459 ExitedPublicKeys: exitedKeys, 460 ExitedIndices: exitedIndices, 461 SlashedPublicKeys: slashedKeys, 462 SlashedIndices: slashedIndices, 463 EjectedPublicKeys: ejectedKeys, 464 EjectedIndices: ejectedIndices, 465 }, nil 466 } 467 468 // GetValidatorParticipation retrieves the validator participation information for a given epoch, 469 // it returns the information about validator's participation rate in voting on the proof of stake 470 // rules based on their balance compared to the total active validator balance. 471 func (bs *Server) GetValidatorParticipation( 472 ctx context.Context, req *ethpb.GetValidatorParticipationRequest, 473 ) (*ethpb.ValidatorParticipationResponse, error) { 474 currentSlot := bs.GenesisTimeFetcher.CurrentSlot() 475 currentEpoch := helpers.SlotToEpoch(currentSlot) 476 477 var requestedEpoch types.Epoch 478 switch q := req.QueryFilter.(type) { 479 case *ethpb.GetValidatorParticipationRequest_Genesis: 480 requestedEpoch = 0 481 case *ethpb.GetValidatorParticipationRequest_Epoch: 482 requestedEpoch = q.Epoch 483 default: 484 requestedEpoch = currentEpoch 485 } 486 487 if requestedEpoch > currentEpoch { 488 return nil, status.Errorf( 489 codes.InvalidArgument, 490 "Cannot retrieve information about an epoch greater than current epoch, current epoch %d, requesting %d", 491 currentEpoch, 492 requestedEpoch, 493 ) 494 } 495 496 // Get current slot state for current epoch attestations. 497 startSlot, err := helpers.StartSlot(requestedEpoch) 498 if err != nil { 499 return nil, err 500 } 501 // Use the last slot of requested epoch to obtain current and previous epoch attestations. 502 // This ensures that we don't miss previous attestations when input requested epochs. 503 startSlot += params.BeaconConfig().SlotsPerEpoch - 1 504 // The start slot should be a canonical slot. 505 canonical, err := bs.isSlotCanonical(ctx, startSlot) 506 if err != nil { 507 return nil, err 508 } 509 // Keep looking back until there's a canonical slot. 510 for i := int(startSlot - 1); !canonical && i >= 0; i-- { 511 canonical, err = bs.isSlotCanonical(ctx, types.Slot(i)) 512 if err != nil { 513 return nil, err 514 } 515 startSlot = types.Slot(i) 516 } 517 beaconState, err := bs.StateGen.StateBySlot(ctx, startSlot) 518 if err != nil { 519 return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) 520 } 521 522 v, b, err := precompute.New(ctx, beaconState) 523 if err != nil { 524 return nil, status.Errorf(codes.Internal, "Could not set up pre compute instance: %v", err) 525 } 526 _, b, err = precompute.ProcessAttestations(ctx, beaconState, v, b) 527 if err != nil { 528 return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) 529 } 530 531 p := ðpb.ValidatorParticipationResponse{ 532 Epoch: requestedEpoch, 533 Finalized: requestedEpoch <= bs.FinalizationFetcher.FinalizedCheckpt().Epoch, 534 Participation: ðpb.ValidatorParticipation{ 535 // TODO(7130): Remove these three deprecated fields. 536 GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch), 537 VotedEther: b.PrevEpochTargetAttested, 538 EligibleEther: b.ActivePrevEpoch, 539 CurrentEpochActiveGwei: b.ActiveCurrentEpoch, 540 CurrentEpochAttestingGwei: b.CurrentEpochAttested, 541 CurrentEpochTargetAttestingGwei: b.CurrentEpochTargetAttested, 542 PreviousEpochActiveGwei: b.ActivePrevEpoch, 543 PreviousEpochAttestingGwei: b.PrevEpochAttested, 544 PreviousEpochTargetAttestingGwei: b.PrevEpochTargetAttested, 545 PreviousEpochHeadAttestingGwei: b.PrevEpochHeadAttested, 546 }, 547 } 548 549 return p, nil 550 } 551 552 // GetValidatorQueue retrieves the current validator queue information. 553 func (bs *Server) GetValidatorQueue( 554 ctx context.Context, _ *emptypb.Empty, 555 ) (*ethpb.ValidatorQueue, error) { 556 headState, err := bs.HeadFetcher.HeadState(ctx) 557 if err != nil { 558 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 559 } 560 // Queue the validators whose eligible to activate and sort them by activation eligibility epoch number. 561 // Additionally, determine those validators queued to exit 562 awaitingExit := make([]types.ValidatorIndex, 0) 563 exitEpochs := make([]types.Epoch, 0) 564 activationQ := make([]types.ValidatorIndex, 0) 565 vals := headState.Validators() 566 for idx, validator := range vals { 567 eligibleActivated := validator.ActivationEligibilityEpoch != params.BeaconConfig().FarFutureEpoch 568 canBeActive := validator.ActivationEpoch >= helpers.ActivationExitEpoch(headState.FinalizedCheckpointEpoch()) 569 if eligibleActivated && canBeActive { 570 activationQ = append(activationQ, types.ValidatorIndex(idx)) 571 } 572 if validator.ExitEpoch != params.BeaconConfig().FarFutureEpoch { 573 exitEpochs = append(exitEpochs, validator.ExitEpoch) 574 awaitingExit = append(awaitingExit, types.ValidatorIndex(idx)) 575 } 576 } 577 sort.Slice(activationQ, func(i, j int) bool { 578 return vals[i].ActivationEligibilityEpoch < vals[j].ActivationEligibilityEpoch 579 }) 580 sort.Slice(awaitingExit, func(i, j int) bool { 581 return vals[i].WithdrawableEpoch < vals[j].WithdrawableEpoch 582 }) 583 584 // Only activate just enough validators according to the activation churn limit. 585 activeValidatorCount, err := helpers.ActiveValidatorCount(headState, helpers.CurrentEpoch(headState)) 586 if err != nil { 587 return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err) 588 } 589 churnLimit, err := helpers.ValidatorChurnLimit(activeValidatorCount) 590 if err != nil { 591 return nil, status.Errorf(codes.Internal, "Could not compute churn limit: %v", err) 592 } 593 594 exitQueueEpoch := types.Epoch(0) 595 for _, i := range exitEpochs { 596 if exitQueueEpoch < i { 597 exitQueueEpoch = i 598 } 599 } 600 exitQueueChurn := uint64(0) 601 for _, val := range vals { 602 if val.ExitEpoch == exitQueueEpoch { 603 exitQueueChurn++ 604 } 605 } 606 // Prevent churn limit from causing index out of bound issues. 607 if churnLimit < exitQueueChurn { 608 // If we are above the churn limit, we simply increase the churn by one. 609 exitQueueEpoch++ 610 } 611 612 // We use the exit queue churn to determine if we have passed a churn limit. 613 minEpoch := exitQueueEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay 614 exitQueueIndices := make([]types.ValidatorIndex, 0) 615 for _, valIdx := range awaitingExit { 616 val := vals[valIdx] 617 // Ensure the validator has not yet exited before adding its index to the exit queue. 618 if val.WithdrawableEpoch < minEpoch && !validatorHasExited(val, helpers.CurrentEpoch(headState)) { 619 exitQueueIndices = append(exitQueueIndices, valIdx) 620 } 621 } 622 623 // Get the public keys for the validators in the queues up to the allowed churn limits. 624 activationQueueKeys := make([][]byte, len(activationQ)) 625 exitQueueKeys := make([][]byte, len(exitQueueIndices)) 626 for i, idx := range activationQ { 627 activationQueueKeys[i] = vals[idx].PublicKey 628 } 629 for i, idx := range exitQueueIndices { 630 exitQueueKeys[i] = vals[idx].PublicKey 631 } 632 633 return ðpb.ValidatorQueue{ 634 ChurnLimit: churnLimit, 635 ActivationPublicKeys: activationQueueKeys, 636 ExitPublicKeys: exitQueueKeys, 637 ActivationValidatorIndices: activationQ, 638 ExitValidatorIndices: exitQueueIndices, 639 }, nil 640 } 641 642 // GetValidatorPerformance reports the validator's latest balance along with other important metrics on 643 // rewards and penalties throughout its lifecycle in the beacon chain. 644 func (bs *Server) GetValidatorPerformance( 645 ctx context.Context, req *ethpb.ValidatorPerformanceRequest, 646 ) (*ethpb.ValidatorPerformanceResponse, error) { 647 if bs.SyncChecker.Syncing() { 648 return nil, status.Errorf(codes.Unavailable, "Syncing to latest head, not ready to respond") 649 } 650 651 headState, err := bs.HeadFetcher.HeadState(ctx) 652 if err != nil { 653 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 654 } 655 656 if bs.GenesisTimeFetcher.CurrentSlot() > headState.Slot() { 657 headState, err = state.ProcessSlots(ctx, headState, bs.GenesisTimeFetcher.CurrentSlot()) 658 if err != nil { 659 return nil, status.Errorf(codes.Internal, "Could not process slots: %v", err) 660 } 661 } 662 vp, bp, err := precompute.New(ctx, headState) 663 if err != nil { 664 return nil, err 665 } 666 vp, bp, err = precompute.ProcessAttestations(ctx, headState, vp, bp) 667 if err != nil { 668 return nil, err 669 } 670 headState, err = precompute.ProcessRewardsAndPenaltiesPrecompute(headState, bp, vp, precompute.AttestationsDelta, precompute.ProposersDelta) 671 if err != nil { 672 return nil, err 673 } 674 validatorSummary := vp 675 676 responseCap := len(req.Indices) + len(req.PublicKeys) 677 validatorIndices := make([]types.ValidatorIndex, 0, responseCap) 678 missingValidators := make([][]byte, 0, responseCap) 679 680 filtered := map[types.ValidatorIndex]bool{} // Track filtered validators to prevent duplication in the response. 681 // Convert the list of validator public keys to validator indices and add to the indices set. 682 for _, pubKey := range req.PublicKeys { 683 // Skip empty public key. 684 if len(pubKey) == 0 { 685 continue 686 } 687 pubkeyBytes := bytesutil.ToBytes48(pubKey) 688 idx, ok := headState.ValidatorIndexByPubkey(pubkeyBytes) 689 if !ok { 690 // Validator index not found, track as missing. 691 missingValidators = append(missingValidators, pubKey) 692 continue 693 } 694 if !filtered[idx] { 695 validatorIndices = append(validatorIndices, idx) 696 filtered[idx] = true 697 } 698 } 699 // Add provided indices to the indices set. 700 for _, idx := range req.Indices { 701 if !filtered[idx] { 702 validatorIndices = append(validatorIndices, idx) 703 filtered[idx] = true 704 } 705 } 706 // Depending on the indices and public keys given, results might not be sorted. 707 sort.Slice(validatorIndices, func(i, j int) bool { 708 return validatorIndices[i] < validatorIndices[j] 709 }) 710 711 currentEpoch := helpers.CurrentEpoch(headState) 712 responseCap = len(validatorIndices) 713 pubKeys := make([][]byte, 0, responseCap) 714 beforeTransitionBalances := make([]uint64, 0, responseCap) 715 afterTransitionBalances := make([]uint64, 0, responseCap) 716 effectiveBalances := make([]uint64, 0, responseCap) 717 inclusionSlots := make([]types.Slot, 0, responseCap) 718 inclusionDistances := make([]types.Slot, 0, responseCap) 719 correctlyVotedSource := make([]bool, 0, responseCap) 720 correctlyVotedTarget := make([]bool, 0, responseCap) 721 correctlyVotedHead := make([]bool, 0, responseCap) 722 // Append performance summaries. 723 // Also track missing validators using public keys. 724 for _, idx := range validatorIndices { 725 val, err := headState.ValidatorAtIndexReadOnly(idx) 726 if err != nil { 727 return nil, status.Errorf(codes.Internal, "could not get validator: %v", err) 728 } 729 pubKey := val.PublicKey() 730 if uint64(idx) >= uint64(len(validatorSummary)) { 731 // Not listed in validator summary yet; treat it as missing. 732 missingValidators = append(missingValidators, pubKey[:]) 733 continue 734 } 735 if !helpers.IsActiveValidatorUsingTrie(val, currentEpoch) { 736 // Inactive validator; treat it as missing. 737 missingValidators = append(missingValidators, pubKey[:]) 738 continue 739 } 740 741 summary := validatorSummary[idx] 742 pubKeys = append(pubKeys, pubKey[:]) 743 effectiveBalances = append(effectiveBalances, summary.CurrentEpochEffectiveBalance) 744 beforeTransitionBalances = append(beforeTransitionBalances, summary.BeforeEpochTransitionBalance) 745 afterTransitionBalances = append(afterTransitionBalances, summary.AfterEpochTransitionBalance) 746 inclusionSlots = append(inclusionSlots, summary.InclusionSlot) 747 inclusionDistances = append(inclusionDistances, summary.InclusionDistance) 748 correctlyVotedSource = append(correctlyVotedSource, summary.IsPrevEpochAttester) 749 correctlyVotedTarget = append(correctlyVotedTarget, summary.IsPrevEpochTargetAttester) 750 correctlyVotedHead = append(correctlyVotedHead, summary.IsPrevEpochHeadAttester) 751 } 752 753 return ðpb.ValidatorPerformanceResponse{ 754 PublicKeys: pubKeys, 755 InclusionSlots: inclusionSlots, 756 InclusionDistances: inclusionDistances, 757 CorrectlyVotedSource: correctlyVotedSource, 758 CorrectlyVotedTarget: correctlyVotedTarget, 759 CorrectlyVotedHead: correctlyVotedHead, 760 CurrentEffectiveBalances: effectiveBalances, 761 BalancesBeforeEpochTransition: beforeTransitionBalances, 762 BalancesAfterEpochTransition: afterTransitionBalances, 763 MissingValidators: missingValidators, 764 }, nil 765 } 766 767 // GetIndividualVotes retrieves individual voting status of validators. 768 func (bs *Server) GetIndividualVotes( 769 ctx context.Context, 770 req *ethpb.IndividualVotesRequest, 771 ) (*ethpb.IndividualVotesRespond, error) { 772 currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) 773 if req.Epoch > currentEpoch { 774 return nil, status.Errorf( 775 codes.InvalidArgument, 776 errEpoch, 777 currentEpoch, 778 req.Epoch, 779 ) 780 } 781 782 s, err := helpers.StartSlot(req.Epoch) 783 if err != nil { 784 return nil, err 785 } 786 requestedState, err := bs.StateGen.StateBySlot(ctx, s) 787 if err != nil { 788 return nil, status.Errorf(codes.Internal, "Could not retrieve archived state for epoch %d: %v", req.Epoch, err) 789 } 790 // Track filtered validators to prevent duplication in the response. 791 filtered := map[types.ValidatorIndex]bool{} 792 filteredIndices := make([]types.ValidatorIndex, 0) 793 votes := make([]*ethpb.IndividualVotesRespond_IndividualVote, 0, len(req.Indices)+len(req.PublicKeys)) 794 // Filter out assignments by public keys. 795 for _, pubKey := range req.PublicKeys { 796 index, ok := requestedState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey)) 797 if !ok { 798 votes = append(votes, ðpb.IndividualVotesRespond_IndividualVote{PublicKey: pubKey, ValidatorIndex: types.ValidatorIndex(^uint64(0))}) 799 continue 800 } 801 filtered[index] = true 802 filteredIndices = append(filteredIndices, index) 803 } 804 // Filter out assignments by validator indices. 805 for _, index := range req.Indices { 806 if !filtered[index] { 807 filteredIndices = append(filteredIndices, index) 808 } 809 } 810 sort.Slice(filteredIndices, func(i, j int) bool { 811 return filteredIndices[i] < filteredIndices[j] 812 }) 813 814 v, bal, err := precompute.New(ctx, requestedState) 815 if err != nil { 816 return nil, status.Errorf(codes.Internal, "Could not set up pre compute instance: %v", err) 817 } 818 v, _, err = precompute.ProcessAttestations(ctx, requestedState, v, bal) 819 if err != nil { 820 return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err) 821 } 822 for _, index := range filteredIndices { 823 if uint64(index) >= uint64(len(v)) { 824 votes = append(votes, ðpb.IndividualVotesRespond_IndividualVote{ValidatorIndex: index}) 825 continue 826 } 827 val, err := requestedState.ValidatorAtIndexReadOnly(index) 828 if err != nil { 829 return nil, status.Errorf(codes.Internal, "Could not retrieve validator: %v", err) 830 831 } 832 pb := val.PublicKey() 833 votes = append(votes, ðpb.IndividualVotesRespond_IndividualVote{ 834 Epoch: req.Epoch, 835 PublicKey: pb[:], 836 ValidatorIndex: index, 837 IsSlashed: v[index].IsSlashed, 838 IsWithdrawableInCurrentEpoch: v[index].IsWithdrawableCurrentEpoch, 839 IsActiveInCurrentEpoch: v[index].IsActiveCurrentEpoch, 840 IsActiveInPreviousEpoch: v[index].IsActivePrevEpoch, 841 IsCurrentEpochAttester: v[index].IsCurrentEpochAttester, 842 IsCurrentEpochTargetAttester: v[index].IsCurrentEpochTargetAttester, 843 IsPreviousEpochAttester: v[index].IsPrevEpochAttester, 844 IsPreviousEpochTargetAttester: v[index].IsPrevEpochTargetAttester, 845 IsPreviousEpochHeadAttester: v[index].IsPrevEpochHeadAttester, 846 CurrentEpochEffectiveBalanceGwei: v[index].CurrentEpochEffectiveBalance, 847 InclusionSlot: v[index].InclusionSlot, 848 InclusionDistance: v[index].InclusionDistance, 849 }) 850 } 851 852 return ðpb.IndividualVotesRespond{ 853 IndividualVotes: votes, 854 }, nil 855 } 856 857 // isSlotCanonical returns true if the input slot has a canonical block in the chain, 858 // if the input slot has a skip block, false is returned, 859 // if the input slot has more than one block, an error is returned. 860 func (bs *Server) isSlotCanonical(ctx context.Context, slot types.Slot) (bool, error) { 861 if slot == 0 { 862 return true, nil 863 } 864 865 hasBlockRoots, roots, err := bs.BeaconDB.BlockRootsBySlot(ctx, slot) 866 if err != nil { 867 return false, err 868 } 869 if !hasBlockRoots { 870 return false, nil 871 } 872 873 // Loop through all roots in slot, and 874 // check which one is canonical. 875 for _, rt := range roots { 876 canonical, err := bs.CanonicalFetcher.IsCanonical(ctx, rt) 877 if err != nil { 878 return false, err 879 } 880 if canonical { 881 return true, nil 882 } 883 884 } 885 return false, nil 886 } 887 888 // Determines whether a validator has already exited. 889 func validatorHasExited(validator *ethpb.Validator, currentEpoch types.Epoch) bool { 890 farFutureEpoch := params.BeaconConfig().FarFutureEpoch 891 if currentEpoch < validator.ActivationEligibilityEpoch { 892 return false 893 } 894 if currentEpoch < validator.ActivationEpoch { 895 return false 896 } 897 if validator.ExitEpoch == farFutureEpoch { 898 return false 899 } 900 if currentEpoch < validator.ExitEpoch { 901 if validator.Slashed { 902 return false 903 } 904 return false 905 } 906 return true 907 } 908 909 func validatorStatus(validator *ethpb.Validator, epoch types.Epoch) ethpb.ValidatorStatus { 910 farFutureEpoch := params.BeaconConfig().FarFutureEpoch 911 if validator == nil { 912 return ethpb.ValidatorStatus_UNKNOWN_STATUS 913 } 914 if epoch < validator.ActivationEligibilityEpoch { 915 return ethpb.ValidatorStatus_DEPOSITED 916 } 917 if epoch < validator.ActivationEpoch { 918 return ethpb.ValidatorStatus_PENDING 919 } 920 if validator.ExitEpoch == farFutureEpoch { 921 return ethpb.ValidatorStatus_ACTIVE 922 } 923 if epoch < validator.ExitEpoch { 924 if validator.Slashed { 925 return ethpb.ValidatorStatus_SLASHING 926 } 927 return ethpb.ValidatorStatus_EXITING 928 } 929 return ethpb.ValidatorStatus_EXITED 930 }