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 &ethpb.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 &ethpb.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 &ethpb.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 &ethpb.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 &ethpb.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  }