forked from prysmaticlabs/prysm
/
committees.go
168 lines (161 loc) · 5.4 KB
/
committees.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package beacon
import (
"context"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"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) {
var requestingGenesis bool
var startSlot uint64
headSlot := bs.GenesisTimeFetcher.CurrentSlot()
switch q := req.QueryFilter.(type) {
case *ethpb.ListCommitteesRequest_Epoch:
startSlot = helpers.StartSlot(q.Epoch)
case *ethpb.ListCommitteesRequest_Genesis:
requestingGenesis = q.Genesis
if !requestingGenesis {
startSlot = headSlot
}
default:
startSlot = headSlot
}
committees, activeIndices, err := bs.retrieveCommitteesForEpoch(ctx, helpers.SlotToEpoch(startSlot))
if err != nil {
return nil, status.Errorf(
codes.Internal,
"Could not retrieve committees for epoch %d: %v",
helpers.SlotToEpoch(startSlot),
err,
)
}
return ðpb.BeaconCommittees{
Epoch: helpers.SlotToEpoch(startSlot),
Committees: committees,
ActiveValidatorCount: uint64(len(activeIndices)),
}, nil
}
func (bs *Server) retrieveCommitteesForEpoch(
ctx context.Context,
epoch uint64,
) (map[uint64]*ethpb.BeaconCommittees_CommitteesList, []uint64, error) {
var attesterSeed [32]byte
var activeIndices []uint64
var err error
startSlot := helpers.StartSlot(epoch)
currentEpoch := helpers.SlotToEpoch(bs.GenesisTimeFetcher.CurrentSlot())
if helpers.SlotToEpoch(startSlot)+1 < currentEpoch {
activeIndices, err = bs.HeadFetcher.HeadValidatorsIndices(helpers.SlotToEpoch(startSlot))
if err != nil {
return nil, nil, status.Errorf(
codes.Internal,
"Could not retrieve active indices for epoch %d: %v",
helpers.SlotToEpoch(startSlot),
err,
)
}
archivedCommitteeInfo, err := bs.BeaconDB.ArchivedCommitteeInfo(ctx, helpers.SlotToEpoch(startSlot))
if err != nil {
return nil, nil, status.Errorf(
codes.Internal,
"Could not request archival data for epoch %d: %v",
helpers.SlotToEpoch(startSlot),
err,
)
}
if archivedCommitteeInfo == nil {
return nil, nil, status.Errorf(
codes.NotFound,
"Could not retrieve data for epoch %d, perhaps --archive in the running beacon node is disabled",
helpers.SlotToEpoch(startSlot),
)
}
attesterSeed = bytesutil.ToBytes32(archivedCommitteeInfo.AttesterSeed)
} else if helpers.SlotToEpoch(startSlot)+1 == currentEpoch || helpers.SlotToEpoch(startSlot) == currentEpoch {
// Otherwise, we use current beacon state to calculate the committees.
requestedEpoch := helpers.SlotToEpoch(startSlot)
activeIndices, err = bs.HeadFetcher.HeadValidatorsIndices(requestedEpoch)
if err != nil {
return nil, nil, status.Errorf(
codes.Internal,
"Could not retrieve active indices for requested epoch %d: %v",
requestedEpoch,
err,
)
}
attesterSeed, err = bs.HeadFetcher.HeadSeed(requestedEpoch)
if err != nil {
return nil, nil, status.Errorf(
codes.Internal,
"Could not retrieve attester seed for requested epoch %d: %v",
requestedEpoch,
err,
)
}
} else {
// Otherwise, we are requesting data from the future and we return an error.
return nil, nil, status.Errorf(
codes.InvalidArgument,
"Cannot retrieve information about an epoch in the future, current epoch %d, requesting %d",
currentEpoch,
helpers.SlotToEpoch(startSlot),
)
}
committeesListsBySlot, err := computeCommittees(startSlot, activeIndices, attesterSeed)
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
}
// 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) {
committeesListsBySlot := make(map[uint64]*ethpb.BeaconCommittees_CommitteesList)
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
}
committeeItems := make([]*ethpb.BeaconCommittees_CommitteeItem, countAtSlot)
for committeeIndex := uint64(0); committeeIndex < countAtSlot; committeeIndex++ {
committee, err := helpers.BeaconCommittee(activeIndices, attesterSeed, slot, committeeIndex)
if err != nil {
return nil, status.Errorf(
codes.Internal,
"Could not compute committee for slot %d: %v",
slot,
err,
)
}
committeeItems[committeeIndex] = ðpb.BeaconCommittees_CommitteeItem{
ValidatorIndices: committee,
}
}
committeesListsBySlot[slot] = ðpb.BeaconCommittees_CommitteesList{
Committees: committeeItems,
}
}
return committeesListsBySlot, nil
}