github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/aggregator.go (about) 1 package validator 2 3 import ( 4 "bytes" 5 "context" 6 7 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 8 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 9 "github.com/prysmaticlabs/prysm/shared/bytesutil" 10 "github.com/prysmaticlabs/prysm/shared/params" 11 "github.com/sirupsen/logrus" 12 "go.opencensus.io/trace" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15 ) 16 17 // SubmitAggregateSelectionProof is called by a validator when its assigned to be an aggregator. 18 // The aggregator submits the selection proof to obtain the aggregated attestation 19 // object to sign over. 20 func (vs *Server) SubmitAggregateSelectionProof(ctx context.Context, req *ethpb.AggregateSelectionRequest) (*ethpb.AggregateSelectionResponse, error) { 21 ctx, span := trace.StartSpan(ctx, "AggregatorServer.SubmitAggregateSelectionProof") 22 defer span.End() 23 span.AddAttributes(trace.Int64Attribute("slot", int64(req.Slot))) 24 25 if vs.SyncChecker.Syncing() { 26 return nil, status.Errorf(codes.Unavailable, "Syncing to latest head, not ready to respond") 27 } 28 29 st, err := vs.HeadFetcher.HeadState(ctx) 30 if err != nil { 31 return nil, status.Errorf(codes.Internal, "Could not determine head state: %v", err) 32 } 33 34 validatorIndex, exists := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(req.PublicKey)) 35 if !exists { 36 return nil, status.Error(codes.Internal, "Could not locate validator index in DB") 37 } 38 39 epoch := helpers.SlotToEpoch(req.Slot) 40 activeValidatorIndices, err := helpers.ActiveValidatorIndices(st, epoch) 41 if err != nil { 42 return nil, status.Errorf(codes.Internal, "Could not get validators: %v", err) 43 } 44 seed, err := helpers.Seed(st, epoch, params.BeaconConfig().DomainBeaconAttester) 45 if err != nil { 46 return nil, status.Errorf(codes.Internal, "Could not get seed: %v", err) 47 } 48 committee, err := helpers.BeaconCommittee(activeValidatorIndices, seed, req.Slot, req.CommitteeIndex) 49 if err != nil { 50 return nil, err 51 } 52 53 // Check if the validator is an aggregator 54 isAggregator, err := helpers.IsAggregator(uint64(len(committee)), req.SlotSignature) 55 if err != nil { 56 return nil, status.Errorf(codes.Internal, "Could not get aggregator status: %v", err) 57 } 58 if !isAggregator { 59 return nil, status.Errorf(codes.InvalidArgument, "Validator is not an aggregator") 60 } 61 62 if err := vs.AttPool.AggregateUnaggregatedAttestationsBySlotIndex(ctx, req.Slot, req.CommitteeIndex); err != nil { 63 return nil, status.Errorf(codes.Internal, "Could not aggregate unaggregated attestations") 64 } 65 aggregatedAtts := vs.AttPool.AggregatedAttestationsBySlotIndex(ctx, req.Slot, req.CommitteeIndex) 66 67 // Filter out the best aggregated attestation (ie. the one with the most aggregated bits). 68 if len(aggregatedAtts) == 0 { 69 aggregatedAtts = vs.AttPool.UnaggregatedAttestationsBySlotIndex(ctx, req.Slot, req.CommitteeIndex) 70 if len(aggregatedAtts) == 0 { 71 return nil, status.Errorf(codes.NotFound, "Could not find attestation for slot and committee in pool") 72 } 73 } 74 75 var indexInCommittee uint64 76 for i, idx := range committee { 77 if idx == validatorIndex { 78 indexInCommittee = uint64(i) 79 } 80 } 81 82 best := aggregatedAtts[0] 83 for _, aggregatedAtt := range aggregatedAtts[1:] { 84 // The aggregator should prefer an attestation that they have signed. We check this by 85 // looking at the attestation's committee index against the validator's committee index 86 // and check the aggregate bits to ensure the validator's index is set. 87 if aggregatedAtt.Data.CommitteeIndex == req.CommitteeIndex && 88 aggregatedAtt.AggregationBits.BitAt(indexInCommittee) && 89 (!best.AggregationBits.BitAt(indexInCommittee) || 90 aggregatedAtt.AggregationBits.Count() > best.AggregationBits.Count()) { 91 best = aggregatedAtt 92 } 93 94 // If the "best" still doesn't contain the validator's index, check the aggregation bits to 95 // choose the attestation with the most bits set. 96 if !best.AggregationBits.BitAt(indexInCommittee) && 97 aggregatedAtt.AggregationBits.Count() > best.AggregationBits.Count() { 98 best = aggregatedAtt 99 } 100 } 101 a := ðpb.AggregateAttestationAndProof{ 102 Aggregate: best, 103 SelectionProof: req.SlotSignature, 104 AggregatorIndex: validatorIndex, 105 } 106 return ðpb.AggregateSelectionResponse{AggregateAndProof: a}, nil 107 } 108 109 // SubmitSignedAggregateSelectionProof is called by a validator to broadcast a signed 110 // aggregated and proof object. 111 func (vs *Server) SubmitSignedAggregateSelectionProof( 112 ctx context.Context, 113 req *ethpb.SignedAggregateSubmitRequest, 114 ) (*ethpb.SignedAggregateSubmitResponse, error) { 115 if req.SignedAggregateAndProof == nil || req.SignedAggregateAndProof.Message == nil || 116 req.SignedAggregateAndProof.Message.Aggregate == nil || req.SignedAggregateAndProof.Message.Aggregate.Data == nil { 117 return nil, status.Error(codes.InvalidArgument, "Signed aggregate request can't be nil") 118 } 119 emptySig := make([]byte, params.BeaconConfig().BLSSignatureLength) 120 if bytes.Equal(req.SignedAggregateAndProof.Signature, emptySig) || 121 bytes.Equal(req.SignedAggregateAndProof.Message.SelectionProof, emptySig) { 122 return nil, status.Error(codes.InvalidArgument, "Signed signatures can't be zero hashes") 123 } 124 125 // As a preventive measure, a beacon node shouldn't broadcast an attestation whose slot is out of range. 126 if err := helpers.ValidateAttestationTime(req.SignedAggregateAndProof.Message.Aggregate.Data.Slot, 127 vs.TimeFetcher.GenesisTime(), params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil { 128 return nil, status.Error(codes.InvalidArgument, "Attestation slot is no longer valid from current time") 129 } 130 131 if err := vs.P2P.Broadcast(ctx, req.SignedAggregateAndProof); err != nil { 132 return nil, status.Errorf(codes.Internal, "Could not broadcast signed aggregated attestation: %v", err) 133 } 134 135 log.WithFields(logrus.Fields{ 136 "slot": req.SignedAggregateAndProof.Message.Aggregate.Data.Slot, 137 "committeeIndex": req.SignedAggregateAndProof.Message.Aggregate.Data.CommitteeIndex, 138 "validatorIndex": req.SignedAggregateAndProof.Message.AggregatorIndex, 139 "aggregatedCount": req.SignedAggregateAndProof.Message.Aggregate.AggregationBits.Count(), 140 }).Debug("Broadcasting aggregated attestation and proof") 141 142 return ðpb.SignedAggregateSubmitResponse{}, nil 143 }