2020-10-05 00:15:27 +00:00
|
|
|
package beaconv1
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1"
|
2021-03-08 14:42:05 +00:00
|
|
|
ethpb_alpha "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
2021-02-25 17:14:04 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
2021-02-23 15:17:07 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/proto/migration"
|
2021-02-25 17:14:04 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
2021-02-23 15:17:07 +00:00
|
|
|
"go.opencensus.io/trace"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2021-05-17 18:32:04 +00:00
|
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
2020-10-05 00:15:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ListPoolAttestations retrieves attestations known by the node but
|
2021-05-19 14:55:24 +00:00
|
|
|
// not necessarily incorporated into any block. Allows filtering by committee index or slot.
|
2020-10-05 00:15:27 +00:00
|
|
|
func (bs *Server) ListPoolAttestations(ctx context.Context, req *ethpb.AttestationsPoolRequest) (*ethpb.AttestationsPoolResponse, error) {
|
2021-05-19 14:55:24 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttestations")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
attestations := bs.AttestationsPool.AggregatedAttestations()
|
|
|
|
unaggAtts, err := bs.AttestationsPool.UnaggregatedAttestations()
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get unaggregated attestations: %v", err)
|
|
|
|
}
|
|
|
|
attestations = append(attestations, unaggAtts...)
|
|
|
|
isEmptyReq := req.Slot == nil && req.CommitteeIndex == nil
|
|
|
|
if isEmptyReq {
|
|
|
|
allAtts := make([]*ethpb.Attestation, len(attestations))
|
|
|
|
for i, att := range attestations {
|
|
|
|
allAtts[i] = migration.V1Alpha1AttestationToV1(att)
|
|
|
|
}
|
|
|
|
return ðpb.AttestationsPoolResponse{Data: allAtts}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
filteredAtts := make([]*ethpb.Attestation, 0, len(attestations))
|
|
|
|
for _, att := range attestations {
|
|
|
|
bothDefined := req.Slot != nil && req.CommitteeIndex != nil
|
|
|
|
committeeIndexMatch := req.CommitteeIndex != nil && att.Data.CommitteeIndex == *req.CommitteeIndex
|
|
|
|
slotMatch := req.Slot != nil && att.Data.Slot == *req.Slot
|
|
|
|
|
|
|
|
if bothDefined && committeeIndexMatch && slotMatch {
|
|
|
|
filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att))
|
|
|
|
} else if !bothDefined && (committeeIndexMatch || slotMatch) {
|
|
|
|
filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ðpb.AttestationsPoolResponse{Data: filteredAtts}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
2021-04-23 12:06:05 +00:00
|
|
|
// SubmitAttestations submits Attestation object to node. If attestation passes all validation
|
2020-10-05 00:15:27 +00:00
|
|
|
// constraints, node MUST publish attestation on appropriate subnet.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) SubmitAttestations(ctx context.Context, req *ethpb.SubmitAttestationsRequest) (*emptypb.Empty, error) {
|
2021-03-08 14:42:05 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitAttestation")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var validAttestations []*ethpb_alpha.Attestation
|
|
|
|
for _, sourceAtt := range req.Data {
|
|
|
|
att := migration.V1AttToV1Alpha1(sourceAtt)
|
2021-03-12 21:43:20 +00:00
|
|
|
err = blocks.VerifyAttestationNoVerifySignature(ctx, headState, att)
|
2021-03-08 14:42:05 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
err = blocks.VerifyAttestationSignature(ctx, headState, att)
|
|
|
|
if err == nil {
|
|
|
|
validAttestations = append(validAttestations, att)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bs.AttestationsPool.SaveAggregatedAttestations(validAttestations)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not save attestations: %v", err)
|
|
|
|
}
|
|
|
|
broadcastFailed := false
|
|
|
|
for _, att := range validAttestations {
|
|
|
|
if err := bs.Broadcaster.Broadcast(ctx, att); err != nil {
|
|
|
|
broadcastFailed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if broadcastFailed {
|
|
|
|
return nil, status.Errorf(
|
|
|
|
codes.Internal,
|
|
|
|
"Could not publish one or more attestations. Some attestations could be published successfully.")
|
|
|
|
}
|
2021-05-17 18:32:04 +00:00
|
|
|
return &emptypb.Empty{}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListPoolAttesterSlashings retrieves attester slashings known by the node but
|
|
|
|
// not necessarily incorporated into any block.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) ListPoolAttesterSlashings(ctx context.Context, req *emptypb.Empty) (*ethpb.AttesterSlashingsPoolResponse, error) {
|
2021-02-23 15:17:07 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttesterSlashings")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
2021-02-24 15:29:25 +00:00
|
|
|
sourceSlashings := bs.SlashingsPool.PendingAttesterSlashings(ctx, headState, true /* return unlimited slashings */)
|
2021-02-23 15:17:07 +00:00
|
|
|
|
|
|
|
slashings := make([]*ethpb.AttesterSlashing, len(sourceSlashings))
|
|
|
|
for i, s := range sourceSlashings {
|
|
|
|
slashings[i] = migration.V1Alpha1AttSlashingToV1(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ðpb.AttesterSlashingsPoolResponse{
|
|
|
|
Data: slashings,
|
|
|
|
}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SubmitAttesterSlashing submits AttesterSlashing object to node's pool and
|
|
|
|
// if passes validation node MUST broadcast it to network.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) SubmitAttesterSlashing(ctx context.Context, req *ethpb.AttesterSlashing) (*emptypb.Empty, error) {
|
2021-02-25 17:14:04 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitAttesterSlashing")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:08:39 +00:00
|
|
|
alphaSlashing := migration.V1AttSlashingToV1Alpha1(req)
|
|
|
|
err = blocks.VerifyAttesterSlashing(ctx, headState, alphaSlashing)
|
2021-02-25 17:14:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Invalid attester slashing: %v", err)
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:08:39 +00:00
|
|
|
err = bs.SlashingsPool.InsertAttesterSlashing(ctx, headState, alphaSlashing)
|
2021-02-25 17:14:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not insert attester slashing into pool: %v", err)
|
|
|
|
}
|
|
|
|
if !featureconfig.Get().DisableBroadcastSlashings {
|
|
|
|
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
|
2021-02-25 20:00:33 +00:00
|
|
|
return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err)
|
2021-02-25 17:14:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 18:32:04 +00:00
|
|
|
return &emptypb.Empty{}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListPoolProposerSlashings retrieves proposer slashings known by the node
|
|
|
|
// but not necessarily incorporated into any block.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) ListPoolProposerSlashings(ctx context.Context, req *emptypb.Empty) (*ethpb.ProposerSlashingPoolResponse, error) {
|
2021-02-24 15:29:25 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolProposerSlashings")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
sourceSlashings := bs.SlashingsPool.PendingProposerSlashings(ctx, headState, true /* return unlimited slashings */)
|
|
|
|
|
|
|
|
slashings := make([]*ethpb.ProposerSlashing, len(sourceSlashings))
|
|
|
|
for i, s := range sourceSlashings {
|
|
|
|
slashings[i] = migration.V1Alpha1ProposerSlashingToV1(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ðpb.ProposerSlashingPoolResponse{
|
|
|
|
Data: slashings,
|
|
|
|
}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SubmitProposerSlashing submits AttesterSlashing object to node's pool and if
|
|
|
|
// passes validation node MUST broadcast it to network.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) SubmitProposerSlashing(ctx context.Context, req *ethpb.ProposerSlashing) (*emptypb.Empty, error) {
|
2021-03-01 16:08:39 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitProposerSlashing")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
alphaSlashing := migration.V1ProposerSlashingToV1Alpha1(req)
|
|
|
|
err = blocks.VerifyProposerSlashing(headState, alphaSlashing)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Invalid proposer slashing: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bs.SlashingsPool.InsertProposerSlashing(ctx, headState, alphaSlashing)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not insert proposer slashing into pool: %v", err)
|
|
|
|
}
|
|
|
|
if !featureconfig.Get().DisableBroadcastSlashings {
|
|
|
|
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 18:32:04 +00:00
|
|
|
return &emptypb.Empty{}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListPoolVoluntaryExits retrieves voluntary exits known by the node but
|
|
|
|
// not necessarily incorporated into any block.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) ListPoolVoluntaryExits(ctx context.Context, req *emptypb.Empty) (*ethpb.VoluntaryExitsPoolResponse, error) {
|
2021-02-24 15:29:25 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolVoluntaryExits")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sourceExits := bs.VoluntaryExitsPool.PendingExits(headState, headState.Slot(), true /* return unlimited exits */)
|
|
|
|
|
|
|
|
exits := make([]*ethpb.SignedVoluntaryExit, len(sourceExits))
|
|
|
|
for i, s := range sourceExits {
|
|
|
|
exits[i] = migration.V1Alpha1ExitToV1(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ðpb.VoluntaryExitsPoolResponse{
|
|
|
|
Data: exits,
|
|
|
|
}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SubmitVoluntaryExit submits SignedVoluntaryExit object to node's pool
|
|
|
|
// and if passes validation node MUST broadcast it to network.
|
2021-05-17 18:32:04 +00:00
|
|
|
func (bs *Server) SubmitVoluntaryExit(ctx context.Context, req *ethpb.SignedVoluntaryExit) (*emptypb.Empty, error) {
|
2021-03-01 16:08:39 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitVoluntaryExit")
|
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
headState, err := bs.ChainInfoFetcher.HeadState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
validator, err := headState.ValidatorAtIndexReadOnly(req.Exit.ValidatorIndex)
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not get exiting validator: %v", err)
|
|
|
|
}
|
|
|
|
alphaExit := migration.V1ExitToV1Alpha1(req)
|
|
|
|
err = blocks.VerifyExitAndSignature(validator, headState.Slot(), headState.Fork(), alphaExit, headState.GenesisValidatorRoot())
|
|
|
|
if err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Invalid voluntary exit: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
bs.VoluntaryExitsPool.InsertVoluntaryExit(ctx, headState, alphaExit)
|
|
|
|
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
|
|
|
|
return nil, status.Errorf(codes.Internal, "Could not broadcast voluntary exit object: %v", err)
|
|
|
|
}
|
|
|
|
|
2021-05-17 18:32:04 +00:00
|
|
|
return &emptypb.Empty{}, nil
|
2020-10-05 00:15:27 +00:00
|
|
|
}
|