2019-11-13 05:32:42 +00:00
|
|
|
package beacon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-06-28 06:34:21 +00:00
|
|
|
"fmt"
|
2019-11-13 05:32:42 +00:00
|
|
|
|
2019-11-27 05:08:18 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
2019-11-13 05:32:42 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
2020-04-16 23:26:10 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
2019-11-13 05:32:42 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ListBeaconCommittees for a given epoch.
|
|
|
|
//
|
|
|
|
// If no filter criteria is specified, the response returns
|
|
|
|
// all beacon committees for the current epoch. The results are paginated by default.
|
|
|
|
func (bs *Server) ListBeaconCommittees(
|
|
|
|
ctx context.Context,
|
|
|
|
req *ethpb.ListCommitteesRequest,
|
|
|
|
) (*ethpb.BeaconCommittees, error) {
|
2020-04-20 03:41:32 +00:00
|
|
|
currentSlot := bs.GenesisTimeFetcher.CurrentSlot()
|
|
|
|
var requestedSlot uint64
|
2019-11-13 05:32:42 +00:00
|
|
|
switch q := req.QueryFilter.(type) {
|
|
|
|
case *ethpb.ListCommitteesRequest_Epoch:
|
2020-09-02 02:52:36 +00:00
|
|
|
startSlot, err := helpers.StartSlot(q.Epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
requestedSlot = startSlot
|
2019-11-13 05:32:42 +00:00
|
|
|
case *ethpb.ListCommitteesRequest_Genesis:
|
2020-04-20 03:41:32 +00:00
|
|
|
requestedSlot = 0
|
2019-11-13 05:32:42 +00:00
|
|
|
default:
|
2020-04-20 03:41:32 +00:00
|
|
|
requestedSlot = currentSlot
|
2019-11-13 05:32:42 +00:00
|
|
|
}
|
2020-04-20 03:41:32 +00:00
|
|
|
|
|
|
|
requestedEpoch := helpers.SlotToEpoch(requestedSlot)
|
|
|
|
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
|
|
|
if requestedEpoch > currentEpoch {
|
2020-02-17 21:57:13 +00:00
|
|
|
return nil, status.Errorf(
|
2020-04-20 03:41:32 +00:00
|
|
|
codes.InvalidArgument,
|
|
|
|
"Cannot retrieve information for an future epoch, current epoch %d, requesting %d",
|
|
|
|
currentEpoch,
|
|
|
|
requestedEpoch,
|
2020-02-17 21:57:13 +00:00
|
|
|
)
|
|
|
|
}
|
2020-04-20 03:41:32 +00:00
|
|
|
|
2020-07-01 20:04:02 +00:00
|
|
|
committees, activeIndices, err := bs.retrieveCommitteesForEpoch(ctx, requestedEpoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(
|
|
|
|
codes.Internal,
|
|
|
|
"Could not retrieve committees for epoch %d: %v",
|
|
|
|
requestedEpoch,
|
|
|
|
err,
|
|
|
|
)
|
2020-04-20 03:41:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-17 21:57:13 +00:00
|
|
|
return ðpb.BeaconCommittees{
|
2020-04-20 03:41:32 +00:00
|
|
|
Epoch: requestedEpoch,
|
2020-02-17 21:57:13 +00:00
|
|
|
Committees: committees,
|
|
|
|
ActiveValidatorCount: uint64(len(activeIndices)),
|
|
|
|
}, nil
|
|
|
|
}
|
2019-11-13 05:32:42 +00:00
|
|
|
|
2020-02-17 21:57:13 +00:00
|
|
|
func (bs *Server) retrieveCommitteesForEpoch(
|
|
|
|
ctx context.Context,
|
|
|
|
epoch uint64,
|
2020-04-20 03:41:32 +00:00
|
|
|
) (map[uint64]*ethpb.BeaconCommittees_CommitteesList, []uint64, error) {
|
2020-09-02 02:52:36 +00:00
|
|
|
startSlot, err := helpers.StartSlot(epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-04-20 03:41:32 +00:00
|
|
|
requestedState, err := bs.StateGen.StateBySlot(ctx, startSlot)
|
|
|
|
if err != nil {
|
2020-11-16 01:06:13 +00:00
|
|
|
return nil, nil, status.Errorf(codes.Internal, "Could not get state: %v", err)
|
2020-04-20 03:41:32 +00:00
|
|
|
}
|
|
|
|
seed, err := helpers.Seed(requestedState, epoch, params.BeaconConfig().DomainBeaconAttester)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Error(codes.Internal, "Could not get seed")
|
|
|
|
}
|
|
|
|
activeIndices, err := helpers.ActiveValidatorIndices(requestedState, epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Error(codes.Internal, "Could not get active indices")
|
|
|
|
}
|
|
|
|
|
|
|
|
committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, seed)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Errorf(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
"Could not compute committees for epoch %d: %v",
|
|
|
|
helpers.SlotToEpoch(startSlot),
|
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return committeesListsBySlot, activeIndices, nil
|
2020-05-26 16:21:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// retrieveCommitteesForRoot uses the provided state root to get the current epoch committees.
|
|
|
|
// Note: This function is always recommended over retrieveCommitteesForEpoch as states are
|
|
|
|
// retrieved from the DB for this function, rather than generated.
|
|
|
|
func (bs *Server) retrieveCommitteesForRoot(
|
|
|
|
ctx context.Context,
|
|
|
|
root []byte,
|
|
|
|
) (map[uint64]*ethpb.BeaconCommittees_CommitteesList, []uint64, error) {
|
|
|
|
requestedState, err := bs.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(root))
|
|
|
|
if err != nil {
|
2020-06-28 06:34:21 +00:00
|
|
|
return nil, nil, status.Error(codes.Internal, fmt.Sprintf("Could not get state: %v", err))
|
2020-05-26 16:21:17 +00:00
|
|
|
}
|
|
|
|
epoch := helpers.CurrentEpoch(requestedState)
|
|
|
|
seed, err := helpers.Seed(requestedState, epoch, params.BeaconConfig().DomainBeaconAttester)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Error(codes.Internal, "Could not get seed")
|
|
|
|
}
|
|
|
|
activeIndices, err := helpers.ActiveValidatorIndices(requestedState, epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Error(codes.Internal, "Could not get active indices")
|
|
|
|
}
|
|
|
|
|
2020-09-02 02:52:36 +00:00
|
|
|
startSlot, err := helpers.StartSlot(epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-05-26 16:21:17 +00:00
|
|
|
committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, seed)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, status.Errorf(
|
|
|
|
codes.InvalidArgument,
|
|
|
|
"Could not compute committees for epoch %d: %v",
|
|
|
|
epoch,
|
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return committeesListsBySlot, activeIndices, nil
|
2020-04-20 03:41:32 +00:00
|
|
|
}
|
|
|
|
|
2020-02-17 21:57:13 +00:00
|
|
|
// Compute committees given a start slot, active validator indices, and
|
|
|
|
// the attester seeds value.
|
|
|
|
func computeCommittees(
|
|
|
|
startSlot uint64,
|
|
|
|
activeIndices []uint64,
|
|
|
|
attesterSeed [32]byte,
|
|
|
|
) (map[uint64]*ethpb.BeaconCommittees_CommitteesList, error) {
|
2020-07-09 15:50:58 +00:00
|
|
|
committeesListsBySlot := make(map[uint64]*ethpb.BeaconCommittees_CommitteesList, params.BeaconConfig().SlotsPerEpoch)
|
2019-11-13 05:32:42 +00:00
|
|
|
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
|
|
|
var countAtSlot = uint64(len(activeIndices)) / params.BeaconConfig().SlotsPerEpoch / params.BeaconConfig().TargetCommitteeSize
|
|
|
|
if countAtSlot > params.BeaconConfig().MaxCommitteesPerSlot {
|
|
|
|
countAtSlot = params.BeaconConfig().MaxCommitteesPerSlot
|
|
|
|
}
|
|
|
|
if countAtSlot == 0 {
|
|
|
|
countAtSlot = 1
|
|
|
|
}
|
2019-12-03 23:44:58 +00:00
|
|
|
committeeItems := make([]*ethpb.BeaconCommittees_CommitteeItem, countAtSlot)
|
2020-01-09 16:28:11 +00:00
|
|
|
for committeeIndex := uint64(0); committeeIndex < countAtSlot; committeeIndex++ {
|
|
|
|
committee, err := helpers.BeaconCommittee(activeIndices, attesterSeed, slot, committeeIndex)
|
2019-11-13 05:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(
|
|
|
|
codes.Internal,
|
2019-11-13 21:03:12 +00:00
|
|
|
"Could not compute committee for slot %d: %v",
|
2019-11-13 05:32:42 +00:00
|
|
|
slot,
|
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
2020-01-09 16:28:11 +00:00
|
|
|
committeeItems[committeeIndex] = ðpb.BeaconCommittees_CommitteeItem{
|
2019-12-03 23:44:58 +00:00
|
|
|
ValidatorIndices: committee,
|
|
|
|
}
|
|
|
|
}
|
2020-02-17 21:57:13 +00:00
|
|
|
committeesListsBySlot[slot] = ðpb.BeaconCommittees_CommitteesList{
|
2019-12-03 23:44:58 +00:00
|
|
|
Committees: committeeItems,
|
2019-11-13 05:32:42 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-17 21:57:13 +00:00
|
|
|
return committeesListsBySlot, nil
|
2019-11-13 05:32:42 +00:00
|
|
|
}
|