github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/beacon/committees.go (about) 1 package beacon 2 3 import ( 4 "context" 5 "fmt" 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/params" 12 "google.golang.org/grpc/codes" 13 "google.golang.org/grpc/status" 14 ) 15 16 // ListBeaconCommittees for a given epoch. 17 // 18 // If no filter criteria is specified, the response returns 19 // all beacon committees for the current epoch. The results are paginated by default. 20 func (bs *Server) ListBeaconCommittees( 21 ctx context.Context, 22 req *ethpb.ListCommitteesRequest, 23 ) (*ethpb.BeaconCommittees, error) { 24 currentSlot := bs.GenesisTimeFetcher.CurrentSlot() 25 var requestedSlot types.Slot 26 switch q := req.QueryFilter.(type) { 27 case *ethpb.ListCommitteesRequest_Epoch: 28 startSlot, err := helpers.StartSlot(q.Epoch) 29 if err != nil { 30 return nil, err 31 } 32 requestedSlot = startSlot 33 case *ethpb.ListCommitteesRequest_Genesis: 34 requestedSlot = 0 35 default: 36 requestedSlot = currentSlot 37 } 38 39 requestedEpoch := helpers.SlotToEpoch(requestedSlot) 40 currentEpoch := helpers.SlotToEpoch(currentSlot) 41 if requestedEpoch > currentEpoch { 42 return nil, status.Errorf( 43 codes.InvalidArgument, 44 "Cannot retrieve information for an future epoch, current epoch %d, requesting %d", 45 currentEpoch, 46 requestedEpoch, 47 ) 48 } 49 50 committees, activeIndices, err := bs.retrieveCommitteesForEpoch(ctx, requestedEpoch) 51 if err != nil { 52 return nil, status.Errorf( 53 codes.Internal, 54 "Could not retrieve committees for epoch %d: %v", 55 requestedEpoch, 56 err, 57 ) 58 } 59 60 return ðpb.BeaconCommittees{ 61 Epoch: requestedEpoch, 62 Committees: committees.SlotToUint64(), 63 ActiveValidatorCount: uint64(len(activeIndices)), 64 }, nil 65 } 66 67 func (bs *Server) retrieveCommitteesForEpoch( 68 ctx context.Context, 69 epoch types.Epoch, 70 ) (SlotToCommiteesMap, []types.ValidatorIndex, error) { 71 startSlot, err := helpers.StartSlot(epoch) 72 if err != nil { 73 return nil, nil, err 74 } 75 requestedState, err := bs.StateGen.StateBySlot(ctx, startSlot) 76 if err != nil { 77 return nil, nil, status.Errorf(codes.Internal, "Could not get state: %v", err) 78 } 79 seed, err := helpers.Seed(requestedState, epoch, params.BeaconConfig().DomainBeaconAttester) 80 if err != nil { 81 return nil, nil, status.Error(codes.Internal, "Could not get seed") 82 } 83 activeIndices, err := helpers.ActiveValidatorIndices(requestedState, epoch) 84 if err != nil { 85 return nil, nil, status.Error(codes.Internal, "Could not get active indices") 86 } 87 88 committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, seed) 89 if err != nil { 90 return nil, nil, status.Errorf( 91 codes.InvalidArgument, 92 "Could not compute committees for epoch %d: %v", 93 helpers.SlotToEpoch(startSlot), 94 err, 95 ) 96 } 97 return committeesListsBySlot, activeIndices, nil 98 } 99 100 // retrieveCommitteesForRoot uses the provided state root to get the current epoch committees. 101 // Note: This function is always recommended over retrieveCommitteesForEpoch as states are 102 // retrieved from the DB for this function, rather than generated. 103 func (bs *Server) retrieveCommitteesForRoot( 104 ctx context.Context, 105 root []byte, 106 ) (SlotToCommiteesMap, []types.ValidatorIndex, error) { 107 requestedState, err := bs.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(root)) 108 if err != nil { 109 return nil, nil, status.Error(codes.Internal, fmt.Sprintf("Could not get state: %v", err)) 110 } 111 epoch := helpers.CurrentEpoch(requestedState) 112 seed, err := helpers.Seed(requestedState, epoch, params.BeaconConfig().DomainBeaconAttester) 113 if err != nil { 114 return nil, nil, status.Error(codes.Internal, "Could not get seed") 115 } 116 activeIndices, err := helpers.ActiveValidatorIndices(requestedState, epoch) 117 if err != nil { 118 return nil, nil, status.Error(codes.Internal, "Could not get active indices") 119 } 120 121 startSlot, err := helpers.StartSlot(epoch) 122 if err != nil { 123 return nil, nil, err 124 } 125 committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, seed) 126 if err != nil { 127 return nil, nil, status.Errorf( 128 codes.InvalidArgument, 129 "Could not compute committees for epoch %d: %v", 130 epoch, 131 err, 132 ) 133 } 134 return committeesListsBySlot, activeIndices, nil 135 } 136 137 // Compute committees given a start slot, active validator indices, and 138 // the attester seeds value. 139 func computeCommittees( 140 startSlot types.Slot, 141 activeIndices []types.ValidatorIndex, 142 attesterSeed [32]byte, 143 ) (SlotToCommiteesMap, error) { 144 committeesListsBySlot := make(SlotToCommiteesMap, params.BeaconConfig().SlotsPerEpoch) 145 for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ { 146 var countAtSlot = uint64(len(activeIndices)) / uint64(params.BeaconConfig().SlotsPerEpoch) / params.BeaconConfig().TargetCommitteeSize 147 if countAtSlot > params.BeaconConfig().MaxCommitteesPerSlot { 148 countAtSlot = params.BeaconConfig().MaxCommitteesPerSlot 149 } 150 if countAtSlot == 0 { 151 countAtSlot = 1 152 } 153 committeeItems := make([]*ethpb.BeaconCommittees_CommitteeItem, countAtSlot) 154 for committeeIndex := uint64(0); committeeIndex < countAtSlot; committeeIndex++ { 155 committee, err := helpers.BeaconCommittee(activeIndices, attesterSeed, slot, types.CommitteeIndex(committeeIndex)) 156 if err != nil { 157 return nil, status.Errorf( 158 codes.Internal, 159 "Could not compute committee for slot %d: %v", 160 slot, 161 err, 162 ) 163 } 164 committeeItems[committeeIndex] = ðpb.BeaconCommittees_CommitteeItem{ 165 ValidatorIndices: committee, 166 } 167 } 168 committeesListsBySlot[slot] = ðpb.BeaconCommittees_CommitteesList{ 169 Committees: committeeItems, 170 } 171 } 172 return committeesListsBySlot, nil 173 } 174 175 // SlotToCommiteesMap represents <slot, CommitteeList> map. 176 type SlotToCommiteesMap map[types.Slot]*ethpb.BeaconCommittees_CommitteesList 177 178 // SlotToUint64 updates map keys to slots (workaround which will be unnecessary if we can cast 179 // map<uint64, CommitteesList> correctly in beacon_chain.proto) 180 func (m SlotToCommiteesMap) SlotToUint64() map[uint64]*ethpb.BeaconCommittees_CommitteesList { 181 updatedCommittees := make(map[uint64]*ethpb.BeaconCommittees_CommitteesList, len(m)) 182 for k, v := range m { 183 updatedCommittees[uint64(k)] = v 184 } 185 return updatedCommittees 186 }