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

     1  // Package rpc defines a gRPC server implementing the Ethereum consensus API as needed
     2  // by validator clients and consumers of chain data.
     3  package rpc
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"fmt"
     9  	"net"
    10  	"sync"
    11  
    12  	middleware "github.com/grpc-ecosystem/go-grpc-middleware"
    13  	recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
    14  	grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
    15  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/cache"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
    19  	blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
    20  	opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
    21  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    22  	"github.com/prysmaticlabs/prysm/beacon-chain/db"
    23  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
    24  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
    25  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
    26  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    27  	"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
    28  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/v1/beacon"
    29  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/v1/debug"
    30  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/v1/events"
    31  	node "github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/v1/node"
    32  	beaconv1alpha1 "github.com/prysmaticlabs/prysm/beacon-chain/rpc/prysm/v1alpha1/beacon"
    33  	debugv1alpha1 "github.com/prysmaticlabs/prysm/beacon-chain/rpc/prysm/v1alpha1/debug"
    34  	nodev1alpha1 "github.com/prysmaticlabs/prysm/beacon-chain/rpc/prysm/v1alpha1/node"
    35  	validatorv1alpha1 "github.com/prysmaticlabs/prysm/beacon-chain/rpc/prysm/v1alpha1/validator"
    36  	"github.com/prysmaticlabs/prysm/beacon-chain/rpc/statefetcher"
    37  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    38  	chainSync "github.com/prysmaticlabs/prysm/beacon-chain/sync"
    39  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    40  	pbrpc "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
    41  	ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
    42  	ethpbv1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    43  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    44  	"github.com/prysmaticlabs/prysm/shared/logutil"
    45  	"github.com/prysmaticlabs/prysm/shared/params"
    46  	"github.com/prysmaticlabs/prysm/shared/traceutil"
    47  	"github.com/sirupsen/logrus"
    48  	"go.opencensus.io/plugin/ocgrpc"
    49  	"google.golang.org/grpc"
    50  	"google.golang.org/grpc/credentials"
    51  	"google.golang.org/grpc/peer"
    52  	"google.golang.org/grpc/reflection"
    53  )
    54  
    55  const attestationBufferSize = 100
    56  
    57  // Service defining an RPC server for a beacon node.
    58  type Service struct {
    59  	cfg                  *Config
    60  	ctx                  context.Context
    61  	cancel               context.CancelFunc
    62  	listener             net.Listener
    63  	grpcServer           *grpc.Server
    64  	canonicalStateChan   chan *pbp2p.BeaconState
    65  	incomingAttestation  chan *ethpbv1alpha1.Attestation
    66  	credentialError      error
    67  	connectedRPCClients  map[net.Addr]bool
    68  	clientConnectionLock sync.Mutex
    69  }
    70  
    71  // Config options for the beacon node RPC server.
    72  type Config struct {
    73  	Host                    string
    74  	Port                    string
    75  	CertFlag                string
    76  	KeyFlag                 string
    77  	BeaconMonitoringHost    string
    78  	BeaconMonitoringPort    int
    79  	BeaconDB                db.HeadAccessDatabase
    80  	ChainInfoFetcher        blockchain.ChainInfoFetcher
    81  	HeadFetcher             blockchain.HeadFetcher
    82  	CanonicalFetcher        blockchain.CanonicalFetcher
    83  	ForkFetcher             blockchain.ForkFetcher
    84  	FinalizationFetcher     blockchain.FinalizationFetcher
    85  	AttestationReceiver     blockchain.AttestationReceiver
    86  	BlockReceiver           blockchain.BlockReceiver
    87  	POWChainService         powchain.Chain
    88  	ChainStartFetcher       powchain.ChainStartFetcher
    89  	GenesisTimeFetcher      blockchain.TimeFetcher
    90  	GenesisFetcher          blockchain.GenesisFetcher
    91  	EnableDebugRPCEndpoints bool
    92  	MockEth1Votes           bool
    93  	AttestationsPool        attestations.Pool
    94  	ExitPool                voluntaryexits.PoolManager
    95  	SlashingsPool           slashings.PoolManager
    96  	SyncService             chainSync.Checker
    97  	Broadcaster             p2p.Broadcaster
    98  	PeersFetcher            p2p.PeersProvider
    99  	PeerManager             p2p.PeerManager
   100  	MetadataProvider        p2p.MetadataProvider
   101  	DepositFetcher          depositcache.DepositFetcher
   102  	PendingDepositFetcher   depositcache.PendingDepositsFetcher
   103  	StateNotifier           statefeed.Notifier
   104  	BlockNotifier           blockfeed.Notifier
   105  	OperationNotifier       opfeed.Notifier
   106  	StateGen                *stategen.State
   107  	MaxMsgSize              int
   108  }
   109  
   110  // NewService instantiates a new RPC service instance that will
   111  // be registered into a running beacon node.
   112  func NewService(ctx context.Context, cfg *Config) *Service {
   113  	ctx, cancel := context.WithCancel(ctx)
   114  	return &Service{
   115  		cfg:                 cfg,
   116  		ctx:                 ctx,
   117  		cancel:              cancel,
   118  		canonicalStateChan:  make(chan *pbp2p.BeaconState, params.BeaconConfig().DefaultBufferSize),
   119  		incomingAttestation: make(chan *ethpbv1alpha1.Attestation, params.BeaconConfig().DefaultBufferSize),
   120  		connectedRPCClients: make(map[net.Addr]bool),
   121  	}
   122  }
   123  
   124  // Start the gRPC server.
   125  func (s *Service) Start() {
   126  	address := fmt.Sprintf("%s:%s", s.cfg.Host, s.cfg.Port)
   127  	lis, err := net.Listen("tcp", address)
   128  	if err != nil {
   129  		log.Errorf("Could not listen to port in Start() %s: %v", address, err)
   130  	}
   131  	s.listener = lis
   132  	log.WithField("address", address).Info("gRPC server listening on port")
   133  
   134  	opts := []grpc.ServerOption{
   135  		grpc.StatsHandler(&ocgrpc.ServerHandler{}),
   136  		grpc.StreamInterceptor(middleware.ChainStreamServer(
   137  			recovery.StreamServerInterceptor(
   138  				recovery.WithRecoveryHandlerContext(traceutil.RecoveryHandlerFunc),
   139  			),
   140  			grpc_prometheus.StreamServerInterceptor,
   141  			grpc_opentracing.StreamServerInterceptor(),
   142  			s.validatorStreamConnectionInterceptor,
   143  		)),
   144  		grpc.UnaryInterceptor(middleware.ChainUnaryServer(
   145  			recovery.UnaryServerInterceptor(
   146  				recovery.WithRecoveryHandlerContext(traceutil.RecoveryHandlerFunc),
   147  			),
   148  			grpc_prometheus.UnaryServerInterceptor,
   149  			grpc_opentracing.UnaryServerInterceptor(),
   150  			s.validatorUnaryConnectionInterceptor,
   151  		)),
   152  		grpc.MaxRecvMsgSize(s.cfg.MaxMsgSize),
   153  	}
   154  	grpc_prometheus.EnableHandlingTimeHistogram()
   155  	if s.cfg.CertFlag != "" && s.cfg.KeyFlag != "" {
   156  		creds, err := credentials.NewServerTLSFromFile(s.cfg.CertFlag, s.cfg.KeyFlag)
   157  		if err != nil {
   158  			log.WithError(err).Fatal("Could not load TLS keys")
   159  		}
   160  		opts = append(opts, grpc.Creds(creds))
   161  	} else {
   162  		log.Warn("You are using an insecure gRPC server. If you are running your beacon node and " +
   163  			"validator on the same machines, you can ignore this message. If you want to know " +
   164  			"how to enable secure connections, see: https://docs.prylabs.network/docs/prysm-usage/secure-grpc")
   165  	}
   166  	s.grpcServer = grpc.NewServer(opts...)
   167  
   168  	validatorServer := &validatorv1alpha1.Server{
   169  		Ctx:                    s.ctx,
   170  		BeaconDB:               s.cfg.BeaconDB,
   171  		AttestationCache:       cache.NewAttestationCache(),
   172  		AttPool:                s.cfg.AttestationsPool,
   173  		ExitPool:               s.cfg.ExitPool,
   174  		HeadFetcher:            s.cfg.HeadFetcher,
   175  		ForkFetcher:            s.cfg.ForkFetcher,
   176  		FinalizationFetcher:    s.cfg.FinalizationFetcher,
   177  		TimeFetcher:            s.cfg.GenesisTimeFetcher,
   178  		CanonicalStateChan:     s.canonicalStateChan,
   179  		BlockFetcher:           s.cfg.POWChainService,
   180  		DepositFetcher:         s.cfg.DepositFetcher,
   181  		ChainStartFetcher:      s.cfg.ChainStartFetcher,
   182  		Eth1InfoFetcher:        s.cfg.POWChainService,
   183  		SyncChecker:            s.cfg.SyncService,
   184  		StateNotifier:          s.cfg.StateNotifier,
   185  		BlockNotifier:          s.cfg.BlockNotifier,
   186  		OperationNotifier:      s.cfg.OperationNotifier,
   187  		P2P:                    s.cfg.Broadcaster,
   188  		BlockReceiver:          s.cfg.BlockReceiver,
   189  		MockEth1Votes:          s.cfg.MockEth1Votes,
   190  		Eth1BlockFetcher:       s.cfg.POWChainService,
   191  		PendingDepositsFetcher: s.cfg.PendingDepositFetcher,
   192  		SlashingsPool:          s.cfg.SlashingsPool,
   193  		StateGen:               s.cfg.StateGen,
   194  	}
   195  	nodeServer := &nodev1alpha1.Server{
   196  		LogsStreamer:         logutil.NewStreamServer(),
   197  		StreamLogsBufferSize: 1000, // Enough to handle bursts of beacon node logs for gRPC streaming.
   198  		BeaconDB:             s.cfg.BeaconDB,
   199  		Server:               s.grpcServer,
   200  		SyncChecker:          s.cfg.SyncService,
   201  		GenesisTimeFetcher:   s.cfg.GenesisTimeFetcher,
   202  		PeersFetcher:         s.cfg.PeersFetcher,
   203  		PeerManager:          s.cfg.PeerManager,
   204  		GenesisFetcher:       s.cfg.GenesisFetcher,
   205  		BeaconMonitoringHost: s.cfg.BeaconMonitoringHost,
   206  		BeaconMonitoringPort: s.cfg.BeaconMonitoringPort,
   207  	}
   208  	nodeServerV1 := &node.Server{
   209  		BeaconDB:           s.cfg.BeaconDB,
   210  		Server:             s.grpcServer,
   211  		SyncChecker:        s.cfg.SyncService,
   212  		GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
   213  		PeersFetcher:       s.cfg.PeersFetcher,
   214  		PeerManager:        s.cfg.PeerManager,
   215  		MetadataProvider:   s.cfg.MetadataProvider,
   216  		HeadFetcher:        s.cfg.HeadFetcher,
   217  	}
   218  
   219  	beaconChainServer := &beaconv1alpha1.Server{
   220  		Ctx:                         s.ctx,
   221  		BeaconDB:                    s.cfg.BeaconDB,
   222  		AttestationsPool:            s.cfg.AttestationsPool,
   223  		SlashingsPool:               s.cfg.SlashingsPool,
   224  		HeadFetcher:                 s.cfg.HeadFetcher,
   225  		FinalizationFetcher:         s.cfg.FinalizationFetcher,
   226  		CanonicalFetcher:            s.cfg.CanonicalFetcher,
   227  		ChainStartFetcher:           s.cfg.ChainStartFetcher,
   228  		DepositFetcher:              s.cfg.DepositFetcher,
   229  		BlockFetcher:                s.cfg.POWChainService,
   230  		CanonicalStateChan:          s.canonicalStateChan,
   231  		GenesisTimeFetcher:          s.cfg.GenesisTimeFetcher,
   232  		StateNotifier:               s.cfg.StateNotifier,
   233  		BlockNotifier:               s.cfg.BlockNotifier,
   234  		AttestationNotifier:         s.cfg.OperationNotifier,
   235  		Broadcaster:                 s.cfg.Broadcaster,
   236  		StateGen:                    s.cfg.StateGen,
   237  		SyncChecker:                 s.cfg.SyncService,
   238  		ReceivedAttestationsBuffer:  make(chan *ethpbv1alpha1.Attestation, attestationBufferSize),
   239  		CollectedAttestationsBuffer: make(chan []*ethpbv1alpha1.Attestation, attestationBufferSize),
   240  	}
   241  	beaconChainServerV1 := &beacon.Server{
   242  		BeaconDB:           s.cfg.BeaconDB,
   243  		AttestationsPool:   s.cfg.AttestationsPool,
   244  		SlashingsPool:      s.cfg.SlashingsPool,
   245  		ChainInfoFetcher:   s.cfg.ChainInfoFetcher,
   246  		GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
   247  		BlockNotifier:      s.cfg.BlockNotifier,
   248  		Broadcaster:        s.cfg.Broadcaster,
   249  		BlockReceiver:      s.cfg.BlockReceiver,
   250  		StateGenService:    s.cfg.StateGen,
   251  		StateFetcher: &statefetcher.StateProvider{
   252  			BeaconDB:           s.cfg.BeaconDB,
   253  			ChainInfoFetcher:   s.cfg.ChainInfoFetcher,
   254  			GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
   255  			StateGenService:    s.cfg.StateGen,
   256  		},
   257  		VoluntaryExitsPool: s.cfg.ExitPool,
   258  	}
   259  	ethpbv1alpha1.RegisterNodeServer(s.grpcServer, nodeServer)
   260  	ethpbv1.RegisterBeaconNodeServer(s.grpcServer, nodeServerV1)
   261  	pbrpc.RegisterHealthServer(s.grpcServer, nodeServer)
   262  	ethpbv1alpha1.RegisterBeaconChainServer(s.grpcServer, beaconChainServer)
   263  	ethpbv1.RegisterBeaconChainServer(s.grpcServer, beaconChainServerV1)
   264  	ethpbv1.RegisterEventsServer(s.grpcServer, &events.Server{
   265  		Ctx:               s.ctx,
   266  		StateNotifier:     s.cfg.StateNotifier,
   267  		BlockNotifier:     s.cfg.BlockNotifier,
   268  		OperationNotifier: s.cfg.OperationNotifier,
   269  	})
   270  	if s.cfg.EnableDebugRPCEndpoints {
   271  		log.Info("Enabled debug gRPC endpoints")
   272  		debugServer := &debugv1alpha1.Server{
   273  			GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
   274  			BeaconDB:           s.cfg.BeaconDB,
   275  			StateGen:           s.cfg.StateGen,
   276  			HeadFetcher:        s.cfg.HeadFetcher,
   277  			PeerManager:        s.cfg.PeerManager,
   278  			PeersFetcher:       s.cfg.PeersFetcher,
   279  		}
   280  		debugServerV1 := &debug.Server{
   281  			BeaconDB:    s.cfg.BeaconDB,
   282  			HeadFetcher: s.cfg.HeadFetcher,
   283  			StateFetcher: &statefetcher.StateProvider{
   284  				BeaconDB:           s.cfg.BeaconDB,
   285  				ChainInfoFetcher:   s.cfg.ChainInfoFetcher,
   286  				GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
   287  				StateGenService:    s.cfg.StateGen,
   288  			},
   289  		}
   290  		pbrpc.RegisterDebugServer(s.grpcServer, debugServer)
   291  		ethpbv1.RegisterBeaconDebugServer(s.grpcServer, debugServerV1)
   292  	}
   293  	ethpbv1alpha1.RegisterBeaconNodeValidatorServer(s.grpcServer, validatorServer)
   294  
   295  	// Register reflection service on gRPC server.
   296  	reflection.Register(s.grpcServer)
   297  
   298  	go func() {
   299  		if s.listener != nil {
   300  			if err := s.grpcServer.Serve(s.listener); err != nil {
   301  				log.Errorf("Could not serve gRPC: %v", err)
   302  			}
   303  		}
   304  	}()
   305  }
   306  
   307  // Stop the service.
   308  func (s *Service) Stop() error {
   309  	s.cancel()
   310  	if s.listener != nil {
   311  		s.grpcServer.GracefulStop()
   312  		log.Debug("Initiated graceful stop of gRPC server")
   313  	}
   314  	return nil
   315  }
   316  
   317  // Status returns nil or credentialError
   318  func (s *Service) Status() error {
   319  	if s.cfg.SyncService.Syncing() {
   320  		return errors.New("syncing")
   321  	}
   322  	if s.credentialError != nil {
   323  		return s.credentialError
   324  	}
   325  	return nil
   326  }
   327  
   328  // Stream interceptor for new validator client connections to the beacon node.
   329  func (s *Service) validatorStreamConnectionInterceptor(
   330  	srv interface{},
   331  	ss grpc.ServerStream,
   332  	_ *grpc.StreamServerInfo,
   333  	handler grpc.StreamHandler,
   334  ) error {
   335  	s.logNewClientConnection(ss.Context())
   336  	return handler(srv, ss)
   337  }
   338  
   339  // Unary interceptor for new validator client connections to the beacon node.
   340  func (s *Service) validatorUnaryConnectionInterceptor(
   341  	ctx context.Context,
   342  	req interface{},
   343  	_ *grpc.UnaryServerInfo,
   344  	handler grpc.UnaryHandler,
   345  ) (interface{}, error) {
   346  	s.logNewClientConnection(ctx)
   347  	return handler(ctx, req)
   348  }
   349  
   350  func (s *Service) logNewClientConnection(ctx context.Context) {
   351  	if featureconfig.Get().DisableGRPCConnectionLogs {
   352  		return
   353  	}
   354  	if clientInfo, ok := peer.FromContext(ctx); ok {
   355  		// Check if we have not yet observed this grpc client connection
   356  		// in the running beacon node.
   357  		s.clientConnectionLock.Lock()
   358  		defer s.clientConnectionLock.Unlock()
   359  		if !s.connectedRPCClients[clientInfo.Addr] {
   360  			log.WithFields(logrus.Fields{
   361  				"addr": clientInfo.Addr.String(),
   362  			}).Infof("New gRPC client connected to beacon node")
   363  			s.connectedRPCClients[clientInfo.Addr] = true
   364  		}
   365  	}
   366  }