diff --git a/WORKSPACE b/WORKSPACE index be4672cdb5d4..f446cc185dc7 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1309,7 +1309,7 @@ go_repository( go_repository( name = "com_github_prysmaticlabs_ethereumapis", - commit = "59479f4a647fcec5d8dbf7c50435cc10fb5751fc", + commit = "62699dc897a9f15fb935ad9e63d553a2c12434d6", importpath = "github.com/prysmaticlabs/ethereumapis", patch_args = ["-p1"], patches = [ diff --git a/beacon-chain/core/helpers/committee.go b/beacon-chain/core/helpers/committee.go index f52b422b3223..18564fe65957 100644 --- a/beacon-chain/core/helpers/committee.go +++ b/beacon-chain/core/helpers/committee.go @@ -181,7 +181,10 @@ type CommitteeAssignmentContainer struct { // 2. Compute all committees. // 3. Determine the attesting slot for each committee. // 4. Construct a map of validator indices pointing to the respective committees. -func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint64]*CommitteeAssignmentContainer, map[uint64]uint64, error) { +func CommitteeAssignments( + state *stateTrie.BeaconState, + epoch uint64, +) (map[uint64]*CommitteeAssignmentContainer, map[uint64][]uint64, error) { nextEpoch := NextEpoch(state) if epoch > nextEpoch { return nil, nil, fmt.Errorf( @@ -191,9 +194,11 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6 ) } - // Track which slot has which proposer. + // We determine the slots in which proposers are supposed to act. + // Some validators may need to propose multiple times per epoch, so + // we use a map of proposer idx -> []slot to keep track of this possibility. startSlot := StartSlot(epoch) - proposerIndexToSlot := make(map[uint64]uint64) + proposerIndexToSlots := make(map[uint64][]uint64) for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ { if err := state.SetSlot(slot); err != nil { return nil, nil, err @@ -202,7 +207,7 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6 if err != nil { return nil, nil, errors.Wrapf(err, "could not check proposer at slot %d", state.Slot()) } - proposerIndexToSlot[i] = slot + proposerIndexToSlots[i] = append(proposerIndexToSlots[i], slot) } activeValidatorIndices, err := ActiveValidatorIndices(state, epoch) @@ -235,85 +240,7 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6 } } - return validatorIndexToCommittee, proposerIndexToSlot, nil -} - -// CommitteeAssignment is used to query committee assignment from -// current and previous epoch. -// -// Deprecated: Consider using CommitteeAssignments, especially when computing more than one -// validator assignment as this method is O(n^2) in computational complexity. This method exists to -// ensure spec definition conformance and otherwise should probably not be used. -// -// Spec pseudocode definition: -// def get_committee_assignment(state: BeaconState, -// epoch: Epoch, -// validator_index: ValidatorIndex -// ) -> Optional[Tuple[Sequence[ValidatorIndex], CommitteeIndex, Slot]]: -// """ -// Return the committee assignment in the ``epoch`` for ``validator_index``. -// ``assignment`` returned is a tuple of the following form: -// * ``assignment[0]`` is the list of validators in the committee -// * ``assignment[1]`` is the index to which the committee is assigned -// * ``assignment[2]`` is the slot at which the committee is assigned -// Return None if no assignment. -// """ -// next_epoch = get_current_epoch(state) + 1 -// assert epoch <= next_epoch -// -// start_slot = compute_start_slot_at_epoch(epoch) -// for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH): -// for index in range(get_committee_count_at_slot(state, Slot(slot))): -// committee = get_beacon_committee(state, Slot(slot), CommitteeIndex(index)) -// if validator_index in committee: -// return committee, CommitteeIndex(index), Slot(slot) -// return None -func CommitteeAssignment( - state *stateTrie.BeaconState, - epoch uint64, - validatorIndex uint64, -) ([]uint64, uint64, uint64, uint64, error) { - nextEpoch := NextEpoch(state) - if epoch > nextEpoch { - return nil, 0, 0, 0, fmt.Errorf( - "epoch %d can't be greater than next epoch %d", - epoch, nextEpoch) - } - - // Track which slot has which proposer. - startSlot := StartSlot(epoch) - proposerIndexToSlot := make(map[uint64]uint64) - for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ { - if err := state.SetSlot(slot); err != nil { - return nil, 0, 0, 0, err - } - i, err := BeaconProposerIndex(state) - if err != nil { - return nil, 0, 0, 0, errors.Wrapf(err, "could not check proposer at slot %d", state.Slot()) - } - proposerIndexToSlot[i] = slot - } - - activeValidatorIndices, err := ActiveValidatorIndices(state, epoch) - if err != nil { - return nil, 0, 0, 0, err - } - for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ { - countAtSlot := SlotCommitteeCount(uint64(len(activeValidatorIndices))) - for i := uint64(0); i < countAtSlot; i++ { - committee, err := BeaconCommitteeFromState(state, slot, i) - if err != nil { - return nil, 0, 0, 0, errors.Wrapf(err, "could not get crosslink committee at slot %d", slot) - } - for _, v := range committee { - if validatorIndex == v { - proposerSlot, _ := proposerIndexToSlot[v] - return committee, i, slot, proposerSlot, nil - } - } - } - } - return []uint64{}, 0, 0, 0, fmt.Errorf("validator with index %d not found in assignments", validatorIndex) + return validatorIndexToCommittee, proposerIndexToSlots, nil } // VerifyBitfieldLength verifies that a bitfield length matches the given committee size. diff --git a/beacon-chain/core/helpers/committee_test.go b/beacon-chain/core/helpers/committee_test.go index 548034fa4765..cdd66480262a 100644 --- a/beacon-chain/core/helpers/committee_test.go +++ b/beacon-chain/core/helpers/committee_test.go @@ -4,13 +4,12 @@ import ( "fmt" "reflect" "strconv" - "strings" "testing" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-bitfield" - beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/shared/attestationutil" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/featureconfig" @@ -191,148 +190,6 @@ func TestVerifyBitfieldLength_OK(t *testing.T) { } } -func TestCommitteeAssignment_CanRetrieve(t *testing.T) { - ClearCache() - // Initialize test with 128 validators, each slot and each index gets 2 validators. - validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch) - for i := 0; i < len(validators); i++ { - validators[i] = ðpb.Validator{ - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - } - } - state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{ - Validators: validators, - Slot: params.BeaconConfig().SlotsPerEpoch, - RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), - }) - - tests := []struct { - index uint64 - slot uint64 - committee []uint64 - committeeIndex uint64 - isProposer bool - proposerSlot uint64 - }{ - { - index: 0, - slot: 78, - committee: []uint64{0, 38}, - committeeIndex: 0, - isProposer: false, - }, - { - index: 1, - slot: 71, - committee: []uint64{1, 4}, - committeeIndex: 0, - isProposer: true, - proposerSlot: 79, - }, - { - index: 11, - slot: 90, - committee: []uint64{31, 11}, - committeeIndex: 0, - isProposer: false, - }, - } - - for i, tt := range tests { - t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - committee, committeeIndex, slot, proposerSlot, err := CommitteeAssignment(state, tt.slot/params.BeaconConfig().SlotsPerEpoch, tt.index) - if err != nil { - t.Fatalf("failed to execute NextEpochCommitteeAssignment: %v", err) - } - if committeeIndex != tt.committeeIndex { - t.Errorf("wanted committeeIndex %d, got committeeIndex %d for validator index %d", - tt.committeeIndex, committeeIndex, tt.index) - } - if slot != tt.slot { - t.Errorf("wanted slot %d, got slot %d for validator index %d", - tt.slot, slot, tt.index) - } - if proposerSlot != tt.proposerSlot { - t.Errorf("wanted proposer slot %d, got proposer slot %d for validator index %d", - tt.proposerSlot, proposerSlot, tt.index) - } - if !reflect.DeepEqual(committee, tt.committee) { - t.Errorf("wanted committee %v, got committee %v for validator index %d", - tt.committee, committee, tt.index) - } - if proposerSlot != tt.proposerSlot { - t.Errorf("wanted proposer slot slot %d, got slot %d for validator index %d", - tt.slot, slot, tt.index) - } - }) - } -} - -func TestCommitteeAssignment_CantFindValidator(t *testing.T) { - ClearCache() - validators := make([]*ethpb.Validator, 1) - for i := 0; i < len(validators); i++ { - validators[i] = ðpb.Validator{ - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - } - } - state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{ - Validators: validators, - Slot: params.BeaconConfig().SlotsPerEpoch, - RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), - }) - - index := uint64(10000) - _, _, _, _, err := CommitteeAssignment(state, 1, index) - if err != nil && !strings.Contains(err.Error(), "not found in assignments") { - t.Errorf("Wanted 'not found in assignments', received %v", err) - } -} - -// Test helpers.CommitteeAssignments against the results of helpers.CommitteeAssignment by validator -// index. Warning: this test is a bit slow! -func TestCommitteeAssignments_AgreesWithSpecDefinitionMethod(t *testing.T) { - ClearCache() - // Initialize test with 256 validators, each slot and each index gets 4 validators. - validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch) - for i := 0; i < len(validators); i++ { - validators[i] = ðpb.Validator{ - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - } - } - state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{ - Validators: validators, - Slot: params.BeaconConfig().SlotsPerEpoch, - RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), - }) - // Test for 2 epochs. - for epoch := uint64(0); epoch < 2; epoch++ { - state, _ := beaconstate.InitializeFromProto(state.CloneInnerState()) - assignments, proposers, err := CommitteeAssignments(state, epoch) - if err != nil { - t.Fatal(err) - } - for i := uint64(0); int(i) < len(validators); i++ { - committee, committeeIndex, slot, proposerSlot, err := CommitteeAssignment(state, epoch, i) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(committee, assignments[i].Committee) { - t.Errorf("Computed different committees for validator %d", i) - } - if committeeIndex != assignments[i].CommitteeIndex { - t.Errorf("Computed different committee index for validator %d", i) - } - if slot != assignments[i].AttesterSlot { - t.Errorf("Computed different attesting slot for validator %d", i) - } - if proposerSlot != proposers[i] { - t.Errorf("Computed different proposing slot for validator %d", i) - } - } - } -} - func TestCommitteeAssignments_CanRetrieve(t *testing.T) { // Initialize test with 256 validators, each slot and each index gets 4 validators. validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch) @@ -395,7 +252,7 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) { for i, tt := range tests { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { ClearCache() - validatorIndexToCommittee, proposerIndexToSlot, err := CommitteeAssignments(state, SlotToEpoch(tt.slot)) + validatorIndexToCommittee, proposerIndexToSlots, err := CommitteeAssignments(state, SlotToEpoch(tt.slot)) if err != nil { t.Fatalf("failed to determine CommitteeAssignments: %v", err) } @@ -408,9 +265,9 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) { t.Errorf("wanted slot %d, got slot %d for validator index %d", tt.slot, cac.AttesterSlot, tt.index) } - if proposerIndexToSlot[tt.index] != tt.proposerSlot { + if len(proposerIndexToSlots[tt.index]) > 0 && proposerIndexToSlots[tt.index][0] != tt.proposerSlot { t.Errorf("wanted proposer slot %d, got proposer slot %d for validator index %d", - tt.proposerSlot, proposerIndexToSlot[tt.index], tt.index) + tt.proposerSlot, proposerIndexToSlots[tt.index][0], tt.index) } if !reflect.DeepEqual(cac.Committee, tt.committee) { t.Errorf("wanted committee %v, got committee %v for validator index %d", diff --git a/beacon-chain/rpc/beacon/assignments.go b/beacon-chain/rpc/beacon/assignments.go index d49b4eeae104..c9f115f34962 100644 --- a/beacon-chain/rpc/beacon/assignments.go +++ b/beacon-chain/rpc/beacon/assignments.go @@ -103,9 +103,9 @@ func (bs *Server) ListValidatorAssignments( // initialize all committee related data. committeeAssignments := map[uint64]*helpers.CommitteeAssignmentContainer{} - proposerIndexToSlot := map[uint64]uint64{} + proposerIndexToSlots := make(map[uint64][]uint64) archivedInfo := &pb.ArchivedCommitteeInfo{} - archivedBalances := []uint64{} + archivedBalances := make([]uint64, 0) archivedAssignments := make(map[uint64]*ethpb.ValidatorAssignments_CommitteeAssignment) if shouldFetchFromArchive { @@ -123,7 +123,7 @@ func (bs *Server) ListValidatorAssignments( return nil, status.Errorf(codes.Internal, "Could not retrieve archived assignment for epoch %d: %v", requestedEpoch, err) } } else { - committeeAssignments, proposerIndexToSlot, err = helpers.CommitteeAssignments(headState, requestedEpoch) + committeeAssignments, proposerIndexToSlots, err = helpers.CommitteeAssignments(headState, requestedEpoch) if err != nil { return nil, status.Errorf(codes.Internal, "Could not compute committee assignments: %v", err) } @@ -150,7 +150,7 @@ func (bs *Server) ListValidatorAssignments( BeaconCommittees: comAssignment.Committee, CommitteeIndex: comAssignment.CommitteeIndex, AttesterSlot: comAssignment.AttesterSlot, - ProposerSlot: proposerIndexToSlot[index], + ProposerSlots: proposerIndexToSlots[index], PublicKey: pubkey[:], } res = append(res, assign) @@ -176,7 +176,7 @@ func archivedValidatorCommittee( attesterSeed := bytesutil.ToBytes32(archivedInfo.AttesterSeed) startSlot := helpers.StartSlot(epoch) - proposerIndexToSlot := make(map[uint64]uint64) + proposerIndexToSlots := make(map[uint64][]uint64) activeVals := make([]*ethpb.Validator, len(archivedBalances)) for i, bal := range archivedBalances { activeVals[i] = ðpb.Validator{EffectiveBalance: bal} @@ -189,7 +189,7 @@ func archivedValidatorCommittee( if err != nil { return nil, errors.Wrapf(err, "could not check proposer at slot %d", slot) } - proposerIndexToSlot[i] = slot + proposerIndexToSlots[i] = append(proposerIndexToSlots[i], slot) } assignmentMap := make(map[uint64]*ethpb.ValidatorAssignments_CommitteeAssignment) @@ -211,7 +211,7 @@ func archivedValidatorCommittee( BeaconCommittees: committee, CommitteeIndex: i, AttesterSlot: slot, - ProposerSlot: proposerIndexToSlot[index], + ProposerSlots: proposerIndexToSlots[index], } } } diff --git a/beacon-chain/rpc/beacon/assignments_test.go b/beacon-chain/rpc/beacon/assignments_test.go index 5119cdd520a9..fd55f4e2d39c 100644 --- a/beacon-chain/rpc/beacon/assignments_test.go +++ b/beacon-chain/rpc/beacon/assignments_test.go @@ -213,24 +213,23 @@ func TestServer_ListAssignments_Pagination_DefaultPageSize_NoArchive(t *testing. if err != nil { t.Fatal(err) } + committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0) + if err != nil { + t.Fatal(err) + } for _, index := range activeIndices[0:params.BeaconConfig().DefaultPageSize] { - committee, committeeIndex, attesterSlot, proposerSlot, err := helpers.CommitteeAssignment(s, 0, index) - if err != nil { - t.Fatal(err) - } val, err := s.ValidatorAtIndex(index) if err != nil { t.Fatal(err) } wanted = append(wanted, ðpb.ValidatorAssignments_CommitteeAssignment{ - BeaconCommittees: committee, - CommitteeIndex: committeeIndex, - AttesterSlot: attesterSlot, - ProposerSlot: proposerSlot, + BeaconCommittees: committeeAssignments[index].Committee, + CommitteeIndex: committeeAssignments[index].CommitteeIndex, + AttesterSlot: committeeAssignments[index].AttesterSlot, + ProposerSlots: proposerIndexToSlots[index], PublicKey: val.PublicKey, }) } - if !reflect.DeepEqual(res.Assignments, wanted) { t.Error("Did not receive wanted assignments") } @@ -331,23 +330,22 @@ func TestServer_ListAssignments_Pagination_DefaultPageSize_FromArchive(t *testin if err != nil { t.Fatal(err) } + committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0) + if err != nil { + t.Fatal(err) + } for _, index := range activeIndices[0:params.BeaconConfig().DefaultPageSize] { - committee, committeeIndex, attesterSlot, proposerSlot, err := helpers.CommitteeAssignment(s, 0, index) - if err != nil { - t.Fatal(err) - } val, err := s.ValidatorAtIndex(index) if err != nil { t.Fatal(err) } - assign := ðpb.ValidatorAssignments_CommitteeAssignment{ - BeaconCommittees: committee, - CommitteeIndex: committeeIndex, - AttesterSlot: attesterSlot, - ProposerSlot: proposerSlot, + wanted = append(wanted, ðpb.ValidatorAssignments_CommitteeAssignment{ + BeaconCommittees: committeeAssignments[index].Committee, + CommitteeIndex: committeeAssignments[index].CommitteeIndex, + AttesterSlot: committeeAssignments[index].AttesterSlot, + ProposerSlots: proposerIndexToSlots[index], PublicKey: val.PublicKey, - } - wanted = append(wanted, assign) + }) } res, err := bs.ListValidatorAssignments(context.Background(), ðpb.ListValidatorAssignmentsRequest{ @@ -428,20 +426,20 @@ func TestServer_ListAssignments_FilterPubkeysIndices_NoPagination(t *testing.T) if err != nil { t.Fatal(err) } + committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0) + if err != nil { + t.Fatal(err) + } for _, index := range activeIndices[1:4] { - committee, committeeIndex, attesterSlot, proposerSlot, err := helpers.CommitteeAssignment(s, 0, index) - if err != nil { - t.Fatal(err) - } val, err := s.ValidatorAtIndex(index) if err != nil { t.Fatal(err) } wanted = append(wanted, ðpb.ValidatorAssignments_CommitteeAssignment{ - BeaconCommittees: committee, - CommitteeIndex: committeeIndex, - AttesterSlot: attesterSlot, - ProposerSlot: proposerSlot, + BeaconCommittees: committeeAssignments[index].Committee, + CommitteeIndex: committeeAssignments[index].CommitteeIndex, + AttesterSlot: committeeAssignments[index].AttesterSlot, + ProposerSlots: proposerIndexToSlots[index], PublicKey: val.PublicKey, }) } @@ -513,20 +511,20 @@ func TestServer_ListAssignments_CanFilterPubkeysIndices_WithPagination(t *testin if err != nil { t.Fatal(err) } + committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0) + if err != nil { + t.Fatal(err) + } for _, index := range activeIndices[3:5] { - committee, committeeIndex, attesterSlot, proposerSlot, err := helpers.CommitteeAssignment(s, 0, index) - if err != nil { - t.Fatal(err) - } val, err := s.ValidatorAtIndex(index) if err != nil { t.Fatal(err) } assignments = append(assignments, ðpb.ValidatorAssignments_CommitteeAssignment{ - BeaconCommittees: committee, - CommitteeIndex: committeeIndex, - AttesterSlot: attesterSlot, - ProposerSlot: proposerSlot, + BeaconCommittees: committeeAssignments[index].Committee, + CommitteeIndex: committeeAssignments[index].CommitteeIndex, + AttesterSlot: committeeAssignments[index].AttesterSlot, + ProposerSlots: proposerIndexToSlots[index], PublicKey: val.PublicKey, }) } @@ -548,21 +546,20 @@ func TestServer_ListAssignments_CanFilterPubkeysIndices_WithPagination(t *testin if err != nil { t.Fatal(err) } - + cAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, 0) + if err != nil { + t.Fatal(err) + } for _, index := range activeIndices[6:7] { - committee, committeeIndex, attesterSlot, proposerSlot, err := helpers.CommitteeAssignment(s, 0, index) - if err != nil { - t.Fatal(err) - } val, err := s.ValidatorAtIndex(index) if err != nil { t.Fatal(err) } assignments = append(assignments, ðpb.ValidatorAssignments_CommitteeAssignment{ - BeaconCommittees: committee, - CommitteeIndex: committeeIndex, - AttesterSlot: attesterSlot, - ProposerSlot: proposerSlot, + BeaconCommittees: cAssignments[index].Committee, + CommitteeIndex: cAssignments[index].CommitteeIndex, + AttesterSlot: cAssignments[index].AttesterSlot, + ProposerSlots: proposerIndexToSlots[index], PublicKey: val.PublicKey, }) } diff --git a/beacon-chain/rpc/validator/assignments.go b/beacon-chain/rpc/validator/assignments.go index ceca4f6b28f7..30421c9b46f4 100644 --- a/beacon-chain/rpc/validator/assignments.go +++ b/beacon-chain/rpc/validator/assignments.go @@ -33,7 +33,7 @@ func (vs *Server) GetDuties(ctx context.Context, req *ethpb.DutiesRequest) (*eth return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", epochStartSlot, err) } } - committeeAssignments, proposerIndexToSlot, err := helpers.CommitteeAssignments(s, req.Epoch) + committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(s, req.Epoch) if err != nil { return nil, status.Errorf(codes.Internal, "Could not compute committee assignments: %v", err) } @@ -67,7 +67,7 @@ func (vs *Server) GetDuties(ctx context.Context, req *ethpb.DutiesRequest) (*eth assignment.ValidatorIndex = idx assignment.PublicKey = pubKey assignment.AttesterSlot = ca.AttesterSlot - assignment.ProposerSlot = proposerIndexToSlot[idx] + assignment.ProposerSlots = proposerIndexToSlots[idx] assignment.CommitteeIndex = ca.CommitteeIndex committeeIDs = append(committeeIDs, ca.CommitteeIndex) } diff --git a/third_party/com_github_prysmaticlabs_ethereumapis-tags.patch b/third_party/com_github_prysmaticlabs_ethereumapis-tags.patch index 9d1d1c8b9941..73ab51442976 100644 --- a/third_party/com_github_prysmaticlabs_ethereumapis-tags.patch +++ b/third_party/com_github_prysmaticlabs_ethereumapis-tags.patch @@ -307,7 +307,7 @@ index ece6613..f396a77 100644 + bytes signature = 3 [(gogoproto.moretags) = "ssz-size:\"96\""]; } diff --git a/eth/v1alpha1/beacon_chain.proto b/eth/v1alpha1/beacon_chain.proto -index 8ee263b..60607de 100644 +index 51ffa20..29e1f89 100644 --- a/eth/v1alpha1/beacon_chain.proto +++ b/eth/v1alpha1/beacon_chain.proto @@ -15,6 +15,7 @@ syntax = "proto3"; @@ -438,7 +438,7 @@ index 8ee263b..60607de 100644 // Validator indicies to filter assignments for the given epoch. repeated uint64 indices = 4; @@ -710,7 +710,7 @@ message ValidatorAssignments { - uint64 proposer_slot = 4; + repeated uint64 proposer_slots = 4; // 48 byte BLS public key. - bytes public_key = 5; @@ -447,7 +447,7 @@ index 8ee263b..60607de 100644 // The epoch for which this set of validator assignments is valid. diff --git a/eth/v1alpha1/validator.proto b/eth/v1alpha1/validator.proto -index 3bc824b..53cd49b 100644 +index 4a64f89..e55e6c8 100644 --- a/eth/v1alpha1/validator.proto +++ b/eth/v1alpha1/validator.proto @@ -15,6 +15,7 @@ syntax = "proto3"; @@ -495,7 +495,7 @@ index 3bc824b..53cd49b 100644 message DutiesResponse { @@ -301,7 +302,7 @@ message DutiesResponse { - uint64 proposer_slot = 4; + repeated uint64 proposer_slots = 4; // 48 byte BLS public key for the validator who's assigned to perform a duty. - bytes public_key = 5; diff --git a/validator/client/validator.go b/validator/client/validator.go index 641e81f80076..7587f0f71517 100644 --- a/validator/client/validator.go +++ b/validator/client/validator.go @@ -317,8 +317,8 @@ func (v *validator) UpdateDuties(ctx context.Context, slot uint64) error { attesterSlot := duty.AttesterSlot committeeIndex := duty.CommitteeIndex - if duty.ProposerSlot > 0 { - lFields["proposerSlot"] = duty.ProposerSlot + if len(duty.ProposerSlots) > 0 { + lFields["proposerSlots"] = duty.ProposerSlots } lFields["attesterSlot"] = attesterSlot @@ -396,8 +396,13 @@ func (v *validator) RolesAt(ctx context.Context, slot uint64) (map[[48]byte][]va if duty == nil { continue } - if duty.ProposerSlot > 0 && duty.ProposerSlot == slot { - roles = append(roles, roleProposer) + if len(duty.ProposerSlots) > 0 { + for _, proposerSlot := range duty.ProposerSlots { + if proposerSlot != 0 && proposerSlot == slot { + roles = append(roles, roleProposer) + break + } + } } if duty.AttesterSlot == slot { roles = append(roles, roleAttester) diff --git a/validator/client/validator_test.go b/validator/client/validator_test.go index 3496f0158896..01713d2397ff 100644 --- a/validator/client/validator_test.go +++ b/validator/client/validator_test.go @@ -517,7 +517,7 @@ func TestUpdateDuties_OK(t *testing.T) { CommitteeIndex: 100, Committee: []uint64{0, 1, 2, 3}, PublicKey: []byte("testPubKey_1"), - ProposerSlot: params.BeaconConfig().SlotsPerEpoch + 1, + ProposerSlots: []uint64{params.BeaconConfig().SlotsPerEpoch + 1}, }, }, } @@ -543,11 +543,11 @@ func TestUpdateDuties_OK(t *testing.T) { if err := v.UpdateDuties(context.Background(), slot); err != nil { t.Fatalf("Could not update assignments: %v", err) } - if v.duties.Duties[0].ProposerSlot != params.BeaconConfig().SlotsPerEpoch+1 { + if v.duties.Duties[0].ProposerSlots[0] != params.BeaconConfig().SlotsPerEpoch+1 { t.Errorf( "Unexpected validator assignments. want=%v got=%v", params.BeaconConfig().SlotsPerEpoch+1, - v.duties.Duties[0].ProposerSlot, + v.duties.Duties[0].ProposerSlots[0], ) } if v.duties.Duties[0].AttesterSlot != params.BeaconConfig().SlotsPerEpoch { @@ -592,7 +592,7 @@ func TestRolesAt_OK(t *testing.T) { }, { CommitteeIndex: 2, - ProposerSlot: 1, + ProposerSlots: []uint64{1}, PublicKey: sks[1].PublicKey().Marshal(), }, { @@ -603,7 +603,7 @@ func TestRolesAt_OK(t *testing.T) { { CommitteeIndex: 2, AttesterSlot: 1, - ProposerSlot: 1, + ProposerSlots: []uint64{1, 5}, PublicKey: sks[3].PublicKey().Marshal(), }, }, @@ -658,19 +658,19 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) { { CommitteeIndex: 1, AttesterSlot: 0, - ProposerSlot: 0, + ProposerSlots: []uint64{0}, PublicKey: sks[0].PublicKey().Marshal(), }, { CommitteeIndex: 2, AttesterSlot: 4, - ProposerSlot: 0, + ProposerSlots: nil, PublicKey: sks[1].PublicKey().Marshal(), }, { CommitteeIndex: 1, AttesterSlot: 3, - ProposerSlot: 0, + ProposerSlots: nil, PublicKey: sks[2].PublicKey().Marshal(), }, },