github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/server.go (about)

     1  // Package validator defines a gRPC validator service implementation, providing
     2  // critical endpoints for validator clients to submit blocks/attestations to the
     3  // beacon node, receive assignments, and more.
     4  package validator
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/cache"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    15  	blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
    16  	opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
    17  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    19  	"github.com/prysmaticlabs/prysm/beacon-chain/db"
    20  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
    21  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
    22  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
    23  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    24  	"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
    25  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    26  	"github.com/prysmaticlabs/prysm/beacon-chain/sync"
    27  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    28  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    29  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    30  	"github.com/prysmaticlabs/prysm/shared/params"
    31  	"google.golang.org/grpc/codes"
    32  	"google.golang.org/grpc/status"
    33  	"google.golang.org/protobuf/types/known/emptypb"
    34  )
    35  
    36  // Server defines a server implementation of the gRPC Validator service,
    37  // providing RPC endpoints for obtaining validator assignments per epoch, the slots
    38  // and committees in which particular validators need to perform their responsibilities,
    39  // and more.
    40  type Server struct {
    41  	Ctx                    context.Context
    42  	BeaconDB               db.NoHeadAccessDatabase
    43  	AttestationCache       *cache.AttestationCache
    44  	HeadFetcher            blockchain.HeadFetcher
    45  	ForkFetcher            blockchain.ForkFetcher
    46  	FinalizationFetcher    blockchain.FinalizationFetcher
    47  	TimeFetcher            blockchain.TimeFetcher
    48  	CanonicalStateChan     chan *pbp2p.BeaconState
    49  	BlockFetcher           powchain.POWBlockFetcher
    50  	DepositFetcher         depositcache.DepositFetcher
    51  	ChainStartFetcher      powchain.ChainStartFetcher
    52  	Eth1InfoFetcher        powchain.ChainInfoFetcher
    53  	SyncChecker            sync.Checker
    54  	StateNotifier          statefeed.Notifier
    55  	BlockNotifier          blockfeed.Notifier
    56  	P2P                    p2p.Broadcaster
    57  	AttPool                attestations.Pool
    58  	SlashingsPool          slashings.PoolManager
    59  	ExitPool               voluntaryexits.PoolManager
    60  	BlockReceiver          blockchain.BlockReceiver
    61  	MockEth1Votes          bool
    62  	Eth1BlockFetcher       powchain.POWBlockFetcher
    63  	PendingDepositsFetcher depositcache.PendingDepositsFetcher
    64  	OperationNotifier      opfeed.Notifier
    65  	StateGen               stategen.StateManager
    66  }
    67  
    68  // WaitForActivation checks if a validator public key exists in the active validator registry of the current
    69  // beacon state, if not, then it creates a stream which listens for canonical states which contain
    70  // the validator with the public key as an active validator record.
    71  func (vs *Server) WaitForActivation(req *ethpb.ValidatorActivationRequest, stream ethpb.BeaconNodeValidator_WaitForActivationServer) error {
    72  	activeValidatorExists, validatorStatuses, err := vs.activationStatus(stream.Context(), req.PublicKeys)
    73  	if err != nil {
    74  		return status.Errorf(codes.Internal, "Could not fetch validator status: %v", err)
    75  	}
    76  	res := &ethpb.ValidatorActivationResponse{
    77  		Statuses: validatorStatuses,
    78  	}
    79  	if activeValidatorExists {
    80  		return stream.Send(res)
    81  	}
    82  	if err := stream.Send(res); err != nil {
    83  		return status.Errorf(codes.Internal, "Could not send response over stream: %v", err)
    84  	}
    85  
    86  	for {
    87  		select {
    88  		// Pinging every slot for activation.
    89  		case <-time.After(time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second):
    90  			activeValidatorExists, validatorStatuses, err := vs.activationStatus(stream.Context(), req.PublicKeys)
    91  			if err != nil {
    92  				return status.Errorf(codes.Internal, "Could not fetch validator status: %v", err)
    93  			}
    94  			res := &ethpb.ValidatorActivationResponse{
    95  				Statuses: validatorStatuses,
    96  			}
    97  			if activeValidatorExists {
    98  				return stream.Send(res)
    99  			}
   100  			if err := stream.Send(res); err != nil {
   101  				return status.Errorf(codes.Internal, "Could not send response over stream: %v", err)
   102  			}
   103  		case <-stream.Context().Done():
   104  			return status.Error(codes.Canceled, "Stream context canceled")
   105  		case <-vs.Ctx.Done():
   106  			return status.Error(codes.Canceled, "RPC context canceled")
   107  		}
   108  	}
   109  }
   110  
   111  // ValidatorIndex is called by a validator to get its index location in the beacon state.
   112  func (vs *Server) ValidatorIndex(ctx context.Context, req *ethpb.ValidatorIndexRequest) (*ethpb.ValidatorIndexResponse, error) {
   113  	st, err := vs.HeadFetcher.HeadState(ctx)
   114  	if err != nil {
   115  		return nil, status.Errorf(codes.Internal, "Could not determine head state: %v", err)
   116  	}
   117  	index, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(req.PublicKey))
   118  	if !ok {
   119  		return nil, status.Errorf(codes.Internal, "Could not find validator index for public key %#x not found", req.PublicKey)
   120  	}
   121  
   122  	return &ethpb.ValidatorIndexResponse{Index: index}, nil
   123  }
   124  
   125  // DomainData fetches the current domain version information from the beacon state.
   126  func (vs *Server) DomainData(_ context.Context, request *ethpb.DomainRequest) (*ethpb.DomainResponse, error) {
   127  	fork := vs.ForkFetcher.CurrentFork()
   128  	headGenesisValidatorRoot := vs.HeadFetcher.HeadGenesisValidatorRoot()
   129  	dv, err := helpers.Domain(fork, request.Epoch, bytesutil.ToBytes4(request.Domain), headGenesisValidatorRoot[:])
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	return &ethpb.DomainResponse{
   134  		SignatureDomain: dv,
   135  	}, nil
   136  }
   137  
   138  // CanonicalHead of the current beacon chain. This method is requested on-demand
   139  // by a validator when it is their time to propose or attest.
   140  func (vs *Server) CanonicalHead(ctx context.Context, _ *emptypb.Empty) (*ethpb.SignedBeaconBlock, error) {
   141  	headBlk, err := vs.HeadFetcher.HeadBlock(ctx)
   142  	if err != nil {
   143  		return nil, status.Errorf(codes.Internal, "Could not get head block: %v", err)
   144  	}
   145  	b, err := headBlk.PbPhase0Block()
   146  	if err != nil {
   147  		return nil, status.Errorf(codes.Internal, "Could not get head block: %v", err)
   148  	}
   149  	return b, nil
   150  }
   151  
   152  // WaitForChainStart queries the logs of the Deposit Contract in order to verify the beacon chain
   153  // has started its runtime and validators begin their responsibilities. If it has not, it then
   154  // subscribes to an event stream triggered by the powchain service whenever the ChainStart log does
   155  // occur in the Deposit Contract on ETH 1.0.
   156  func (vs *Server) WaitForChainStart(_ *emptypb.Empty, stream ethpb.BeaconNodeValidator_WaitForChainStartServer) error {
   157  	head, err := vs.HeadFetcher.HeadState(stream.Context())
   158  	if err != nil {
   159  		return status.Errorf(codes.Internal, "Could not retrieve head state: %v", err)
   160  	}
   161  	if head != nil && !head.IsNil() {
   162  		res := &ethpb.ChainStartResponse{
   163  			Started:               true,
   164  			GenesisTime:           head.GenesisTime(),
   165  			GenesisValidatorsRoot: head.GenesisValidatorRoot(),
   166  		}
   167  		return stream.Send(res)
   168  	}
   169  
   170  	stateChannel := make(chan *feed.Event, 1)
   171  	stateSub := vs.StateNotifier.StateFeed().Subscribe(stateChannel)
   172  	defer stateSub.Unsubscribe()
   173  	for {
   174  		select {
   175  		case event := <-stateChannel:
   176  			if event.Type == statefeed.Initialized {
   177  				data, ok := event.Data.(*statefeed.InitializedData)
   178  				if !ok {
   179  					return errors.New("event data is not type *statefeed.InitializedData")
   180  				}
   181  				log.WithField("starttime", data.StartTime).Debug("Received chain started event")
   182  				log.Debug("Sending genesis time notification to connected validator clients")
   183  				res := &ethpb.ChainStartResponse{
   184  					Started:               true,
   185  					GenesisTime:           uint64(data.StartTime.Unix()),
   186  					GenesisValidatorsRoot: data.GenesisValidatorsRoot,
   187  				}
   188  				return stream.Send(res)
   189  			}
   190  		case <-stateSub.Err():
   191  			return status.Error(codes.Aborted, "Subscriber closed, exiting goroutine")
   192  		case <-vs.Ctx.Done():
   193  			return status.Error(codes.Canceled, "Context canceled")
   194  		}
   195  	}
   196  }