github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/eth/v1/beacon/pool.go (about) 1 package beacon 2 3 import ( 4 "context" 5 6 "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" 7 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1" 8 ethpb_alpha "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 9 "github.com/prysmaticlabs/prysm/proto/migration" 10 "github.com/prysmaticlabs/prysm/shared/featureconfig" 11 "github.com/prysmaticlabs/prysm/shared/grpcutils" 12 "go.opencensus.io/trace" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15 "google.golang.org/protobuf/types/known/emptypb" 16 ) 17 18 // attestationsVerificationFailure represents failures when verifying submitted attestations. 19 type attestationsVerificationFailure struct { 20 Failures []*singleAttestationVerificationFailure `json:"failures"` 21 } 22 23 // singleAttestationVerificationFailure represents an issue when verifying a single submitted attestation. 24 type singleAttestationVerificationFailure struct { 25 Index int `json:"index"` 26 Message string `json:"message"` 27 } 28 29 // ListPoolAttestations retrieves attestations known by the node but 30 // not necessarily incorporated into any block. Allows filtering by committee index or slot. 31 func (bs *Server) ListPoolAttestations(ctx context.Context, req *ethpb.AttestationsPoolRequest) (*ethpb.AttestationsPoolResponse, error) { 32 ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttestations") 33 defer span.End() 34 35 attestations := bs.AttestationsPool.AggregatedAttestations() 36 unaggAtts, err := bs.AttestationsPool.UnaggregatedAttestations() 37 if err != nil { 38 return nil, status.Errorf(codes.Internal, "Could not get unaggregated attestations: %v", err) 39 } 40 attestations = append(attestations, unaggAtts...) 41 isEmptyReq := req.Slot == nil && req.CommitteeIndex == nil 42 if isEmptyReq { 43 allAtts := make([]*ethpb.Attestation, len(attestations)) 44 for i, att := range attestations { 45 allAtts[i] = migration.V1Alpha1AttestationToV1(att) 46 } 47 return ðpb.AttestationsPoolResponse{Data: allAtts}, nil 48 } 49 50 filteredAtts := make([]*ethpb.Attestation, 0, len(attestations)) 51 for _, att := range attestations { 52 bothDefined := req.Slot != nil && req.CommitteeIndex != nil 53 committeeIndexMatch := req.CommitteeIndex != nil && att.Data.CommitteeIndex == *req.CommitteeIndex 54 slotMatch := req.Slot != nil && att.Data.Slot == *req.Slot 55 56 if bothDefined && committeeIndexMatch && slotMatch { 57 filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att)) 58 } else if !bothDefined && (committeeIndexMatch || slotMatch) { 59 filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att)) 60 } 61 } 62 return ðpb.AttestationsPoolResponse{Data: filteredAtts}, nil 63 } 64 65 // SubmitAttestations submits Attestation object to node. If attestation passes all validation 66 // constraints, node MUST publish attestation on appropriate subnet. 67 func (bs *Server) SubmitAttestations(ctx context.Context, req *ethpb.SubmitAttestationsRequest) (*emptypb.Empty, error) { 68 ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitAttestation") 69 defer span.End() 70 71 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 72 if err != nil { 73 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 74 } 75 76 var validAttestations []*ethpb_alpha.Attestation 77 var attFailures []*singleAttestationVerificationFailure 78 for i, sourceAtt := range req.Data { 79 att := migration.V1AttToV1Alpha1(sourceAtt) 80 err = blocks.VerifyAttestationNoVerifySignature(ctx, headState, att) 81 if err != nil { 82 attFailures = append(attFailures, &singleAttestationVerificationFailure{ 83 Index: i, 84 Message: err.Error(), 85 }) 86 continue 87 } 88 err = blocks.VerifyAttestationSignature(ctx, headState, att) 89 if err != nil { 90 attFailures = append(attFailures, &singleAttestationVerificationFailure{ 91 Index: i, 92 Message: err.Error(), 93 }) 94 continue 95 } 96 validAttestations = append(validAttestations, att) 97 } 98 99 err = bs.AttestationsPool.SaveAggregatedAttestations(validAttestations) 100 if err != nil { 101 return nil, status.Errorf(codes.Internal, "Could not save attestations: %v", err) 102 } 103 broadcastFailed := false 104 for _, att := range validAttestations { 105 if err := bs.Broadcaster.Broadcast(ctx, att); err != nil { 106 broadcastFailed = true 107 } 108 } 109 if broadcastFailed { 110 return nil, status.Errorf( 111 codes.Internal, 112 "Could not publish one or more attestations. Some attestations could be published successfully.") 113 } 114 115 if len(attFailures) > 0 { 116 failuresContainer := &attestationsVerificationFailure{Failures: attFailures} 117 err = grpcutils.AppendCustomErrorHeader(ctx, failuresContainer) 118 if err != nil { 119 return nil, status.Errorf(codes.Internal, "Could not prepare attestation failure information: %v", err) 120 } 121 return nil, status.Errorf(codes.InvalidArgument, "One or more attestations failed validation") 122 } 123 124 return &emptypb.Empty{}, nil 125 } 126 127 // ListPoolAttesterSlashings retrieves attester slashings known by the node but 128 // not necessarily incorporated into any block. 129 func (bs *Server) ListPoolAttesterSlashings(ctx context.Context, req *emptypb.Empty) (*ethpb.AttesterSlashingsPoolResponse, error) { 130 ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttesterSlashings") 131 defer span.End() 132 133 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 134 if err != nil { 135 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 136 } 137 sourceSlashings := bs.SlashingsPool.PendingAttesterSlashings(ctx, headState, true /* return unlimited slashings */) 138 139 slashings := make([]*ethpb.AttesterSlashing, len(sourceSlashings)) 140 for i, s := range sourceSlashings { 141 slashings[i] = migration.V1Alpha1AttSlashingToV1(s) 142 } 143 144 return ðpb.AttesterSlashingsPoolResponse{ 145 Data: slashings, 146 }, nil 147 } 148 149 // SubmitAttesterSlashing submits AttesterSlashing object to node's pool and 150 // if passes validation node MUST broadcast it to network. 151 func (bs *Server) SubmitAttesterSlashing(ctx context.Context, req *ethpb.AttesterSlashing) (*emptypb.Empty, error) { 152 ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitAttesterSlashing") 153 defer span.End() 154 155 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 156 if err != nil { 157 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 158 } 159 160 alphaSlashing := migration.V1AttSlashingToV1Alpha1(req) 161 err = blocks.VerifyAttesterSlashing(ctx, headState, alphaSlashing) 162 if err != nil { 163 return nil, status.Errorf(codes.InvalidArgument, "Invalid attester slashing: %v", err) 164 } 165 166 err = bs.SlashingsPool.InsertAttesterSlashing(ctx, headState, alphaSlashing) 167 if err != nil { 168 return nil, status.Errorf(codes.Internal, "Could not insert attester slashing into pool: %v", err) 169 } 170 if !featureconfig.Get().DisableBroadcastSlashings { 171 if err := bs.Broadcaster.Broadcast(ctx, req); err != nil { 172 return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err) 173 } 174 } 175 176 return &emptypb.Empty{}, nil 177 } 178 179 // ListPoolProposerSlashings retrieves proposer slashings known by the node 180 // but not necessarily incorporated into any block. 181 func (bs *Server) ListPoolProposerSlashings(ctx context.Context, req *emptypb.Empty) (*ethpb.ProposerSlashingPoolResponse, error) { 182 ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolProposerSlashings") 183 defer span.End() 184 185 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 186 if err != nil { 187 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 188 } 189 sourceSlashings := bs.SlashingsPool.PendingProposerSlashings(ctx, headState, true /* return unlimited slashings */) 190 191 slashings := make([]*ethpb.ProposerSlashing, len(sourceSlashings)) 192 for i, s := range sourceSlashings { 193 slashings[i] = migration.V1Alpha1ProposerSlashingToV1(s) 194 } 195 196 return ðpb.ProposerSlashingPoolResponse{ 197 Data: slashings, 198 }, nil 199 } 200 201 // SubmitProposerSlashing submits AttesterSlashing object to node's pool and if 202 // passes validation node MUST broadcast it to network. 203 func (bs *Server) SubmitProposerSlashing(ctx context.Context, req *ethpb.ProposerSlashing) (*emptypb.Empty, error) { 204 ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitProposerSlashing") 205 defer span.End() 206 207 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 208 if err != nil { 209 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 210 } 211 212 alphaSlashing := migration.V1ProposerSlashingToV1Alpha1(req) 213 err = blocks.VerifyProposerSlashing(headState, alphaSlashing) 214 if err != nil { 215 return nil, status.Errorf(codes.InvalidArgument, "Invalid proposer slashing: %v", err) 216 } 217 218 err = bs.SlashingsPool.InsertProposerSlashing(ctx, headState, alphaSlashing) 219 if err != nil { 220 return nil, status.Errorf(codes.Internal, "Could not insert proposer slashing into pool: %v", err) 221 } 222 if !featureconfig.Get().DisableBroadcastSlashings { 223 if err := bs.Broadcaster.Broadcast(ctx, req); err != nil { 224 return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err) 225 } 226 } 227 228 return &emptypb.Empty{}, nil 229 } 230 231 // ListPoolVoluntaryExits retrieves voluntary exits known by the node but 232 // not necessarily incorporated into any block. 233 func (bs *Server) ListPoolVoluntaryExits(ctx context.Context, req *emptypb.Empty) (*ethpb.VoluntaryExitsPoolResponse, error) { 234 ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolVoluntaryExits") 235 defer span.End() 236 237 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 238 if err != nil { 239 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 240 } 241 242 sourceExits := bs.VoluntaryExitsPool.PendingExits(headState, headState.Slot(), true /* return unlimited exits */) 243 244 exits := make([]*ethpb.SignedVoluntaryExit, len(sourceExits)) 245 for i, s := range sourceExits { 246 exits[i] = migration.V1Alpha1ExitToV1(s) 247 } 248 249 return ðpb.VoluntaryExitsPoolResponse{ 250 Data: exits, 251 }, nil 252 } 253 254 // SubmitVoluntaryExit submits SignedVoluntaryExit object to node's pool 255 // and if passes validation node MUST broadcast it to network. 256 func (bs *Server) SubmitVoluntaryExit(ctx context.Context, req *ethpb.SignedVoluntaryExit) (*emptypb.Empty, error) { 257 ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitVoluntaryExit") 258 defer span.End() 259 260 headState, err := bs.ChainInfoFetcher.HeadState(ctx) 261 if err != nil { 262 return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) 263 } 264 265 validator, err := headState.ValidatorAtIndexReadOnly(req.Message.ValidatorIndex) 266 if err != nil { 267 return nil, status.Errorf(codes.Internal, "Could not get exiting validator: %v", err) 268 } 269 alphaExit := migration.V1ExitToV1Alpha1(req) 270 err = blocks.VerifyExitAndSignature(validator, headState.Slot(), headState.Fork(), alphaExit, headState.GenesisValidatorRoot()) 271 if err != nil { 272 return nil, status.Errorf(codes.InvalidArgument, "Invalid voluntary exit: %v", err) 273 } 274 275 bs.VoluntaryExitsPool.InsertVoluntaryExit(ctx, headState, alphaExit) 276 if err := bs.Broadcaster.Broadcast(ctx, req); err != nil { 277 return nil, status.Errorf(codes.Internal, "Could not broadcast voluntary exit object: %v", err) 278 } 279 280 return &emptypb.Empty{}, nil 281 }