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

     1  package beacon
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
     9  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    10  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    11  	"github.com/prysmaticlabs/prysm/shared/cmd"
    12  	"github.com/prysmaticlabs/prysm/shared/pagination"
    13  	"google.golang.org/grpc/codes"
    14  	"google.golang.org/grpc/status"
    15  )
    16  
    17  const errEpoch = "Cannot retrieve information about an epoch in the future, current epoch %d, requesting %d"
    18  
    19  // ListValidatorAssignments retrieves the validator assignments for a given epoch,
    20  // optional validator indices or public keys may be included to filter validator assignments.
    21  func (bs *Server) ListValidatorAssignments(
    22  	ctx context.Context, req *ethpb.ListValidatorAssignmentsRequest,
    23  ) (*ethpb.ValidatorAssignments, error) {
    24  	if int(req.PageSize) > cmd.Get().MaxRPCPageSize {
    25  		return nil, status.Errorf(
    26  			codes.InvalidArgument,
    27  			"Requested page size %d can not be greater than max size %d",
    28  			req.PageSize,
    29  			cmd.Get().MaxRPCPageSize,
    30  		)
    31  	}
    32  
    33  	var res []*ethpb.ValidatorAssignments_CommitteeAssignment
    34  	filtered := map[types.ValidatorIndex]bool{} // track filtered validators to prevent duplication in the response.
    35  	filteredIndices := make([]types.ValidatorIndex, 0)
    36  	var requestedEpoch types.Epoch
    37  	switch q := req.QueryFilter.(type) {
    38  	case *ethpb.ListValidatorAssignmentsRequest_Genesis:
    39  		if q.Genesis {
    40  			requestedEpoch = 0
    41  		}
    42  	case *ethpb.ListValidatorAssignmentsRequest_Epoch:
    43  		requestedEpoch = q.Epoch
    44  	}
    45  
    46  	currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot())
    47  	if requestedEpoch > currentEpoch {
    48  		return nil, status.Errorf(
    49  			codes.InvalidArgument,
    50  			errEpoch,
    51  			currentEpoch,
    52  			requestedEpoch,
    53  		)
    54  	}
    55  
    56  	startSlot, err := helpers.StartSlot(requestedEpoch)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	requestedState, err := bs.StateGen.StateBySlot(ctx, startSlot)
    61  	if err != nil {
    62  		return nil, status.Errorf(codes.Internal, "Could not retrieve archived state for epoch %d: %v", requestedEpoch, err)
    63  	}
    64  
    65  	// Filter out assignments by public keys.
    66  	for _, pubKey := range req.PublicKeys {
    67  		index, ok := requestedState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
    68  		if !ok {
    69  			return nil, status.Errorf(codes.NotFound, "Could not find validator index for public key %#x", pubKey)
    70  		}
    71  		filtered[index] = true
    72  		filteredIndices = append(filteredIndices, index)
    73  	}
    74  
    75  	// Filter out assignments by validator indices.
    76  	for _, index := range req.Indices {
    77  		if !filtered[index] {
    78  			filteredIndices = append(filteredIndices, index)
    79  		}
    80  	}
    81  
    82  	activeIndices, err := helpers.ActiveValidatorIndices(requestedState, requestedEpoch)
    83  	if err != nil {
    84  		return nil, status.Errorf(codes.Internal, "Could not retrieve active validator indices: %v", err)
    85  	}
    86  	if len(filteredIndices) == 0 {
    87  		if len(activeIndices) == 0 {
    88  			return &ethpb.ValidatorAssignments{
    89  				Assignments:   make([]*ethpb.ValidatorAssignments_CommitteeAssignment, 0),
    90  				TotalSize:     int32(0),
    91  				NextPageToken: strconv.Itoa(0),
    92  			}, nil
    93  		}
    94  		// If no filter was specified, return assignments from active validator indices with pagination.
    95  		filteredIndices = activeIndices
    96  	}
    97  
    98  	start, end, nextPageToken, err := pagination.StartAndEndPage(req.PageToken, int(req.PageSize), len(filteredIndices))
    99  	if err != nil {
   100  		return nil, status.Errorf(codes.Internal, "Could not paginate results: %v", err)
   101  	}
   102  
   103  	// Initialize all committee related data.
   104  	committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(requestedState, requestedEpoch)
   105  	if err != nil {
   106  		return nil, status.Errorf(codes.Internal, "Could not compute committee assignments: %v", err)
   107  	}
   108  
   109  	for _, index := range filteredIndices[start:end] {
   110  		if uint64(index) >= uint64(requestedState.NumValidators()) {
   111  			return nil, status.Errorf(codes.OutOfRange, "Validator index %d >= validator count %d",
   112  				index, requestedState.NumValidators())
   113  		}
   114  		comAssignment := committeeAssignments[index]
   115  		pubkey := requestedState.PubkeyAtIndex(index)
   116  		assign := &ethpb.ValidatorAssignments_CommitteeAssignment{
   117  			BeaconCommittees: comAssignment.Committee,
   118  			CommitteeIndex:   comAssignment.CommitteeIndex,
   119  			AttesterSlot:     comAssignment.AttesterSlot,
   120  			ProposerSlots:    proposerIndexToSlots[index],
   121  			PublicKey:        pubkey[:],
   122  			ValidatorIndex:   index,
   123  		}
   124  		res = append(res, assign)
   125  	}
   126  
   127  	return &ethpb.ValidatorAssignments{
   128  		Epoch:         requestedEpoch,
   129  		Assignments:   res,
   130  		NextPageToken: nextPageToken,
   131  		TotalSize:     int32(len(filteredIndices)),
   132  	}, nil
   133  }