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

     1  // Package node defines a gRPC node service implementation, providing
     2  // useful endpoints for checking a node's sync status, peer info,
     3  // genesis data, and version information.
     4  package node
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"sort"
    10  	"time"
    11  
    12  	"github.com/golang/protobuf/ptypes/empty"
    13  	"github.com/golang/protobuf/ptypes/timestamp"
    14  	"github.com/libp2p/go-libp2p-core/network"
    15  	"github.com/libp2p/go-libp2p-core/peer"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/db"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    19  	"github.com/prysmaticlabs/prysm/beacon-chain/sync"
    20  	pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
    21  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    22  	"github.com/prysmaticlabs/prysm/shared/logutil"
    23  	"github.com/prysmaticlabs/prysm/shared/version"
    24  	"google.golang.org/grpc"
    25  	"google.golang.org/grpc/codes"
    26  	"google.golang.org/grpc/status"
    27  	"google.golang.org/protobuf/types/known/timestamppb"
    28  )
    29  
    30  // Server defines a server implementation of the gRPC Node service,
    31  // providing RPC endpoints for verifying a beacon node's sync status, genesis and
    32  // version information, and services the node implements and runs.
    33  type Server struct {
    34  	LogsStreamer         logutil.Streamer
    35  	StreamLogsBufferSize int
    36  	SyncChecker          sync.Checker
    37  	Server               *grpc.Server
    38  	BeaconDB             db.ReadOnlyDatabase
    39  	PeersFetcher         p2p.PeersProvider
    40  	PeerManager          p2p.PeerManager
    41  	GenesisTimeFetcher   blockchain.TimeFetcher
    42  	GenesisFetcher       blockchain.GenesisFetcher
    43  	BeaconMonitoringHost string
    44  	BeaconMonitoringPort int
    45  }
    46  
    47  // GetSyncStatus checks the current network sync status of the node.
    48  func (ns *Server) GetSyncStatus(_ context.Context, _ *empty.Empty) (*ethpb.SyncStatus, error) {
    49  	return &ethpb.SyncStatus{
    50  		Syncing: ns.SyncChecker.Syncing(),
    51  	}, nil
    52  }
    53  
    54  // GetGenesis fetches genesis chain information of Ethereum. Returns unix timestamp 0
    55  // if a genesis time has yet to be determined.
    56  func (ns *Server) GetGenesis(ctx context.Context, _ *empty.Empty) (*ethpb.Genesis, error) {
    57  	contractAddr, err := ns.BeaconDB.DepositContractAddress(ctx)
    58  	if err != nil {
    59  		return nil, status.Errorf(codes.Internal, "Could not retrieve contract address from db: %v", err)
    60  	}
    61  	genesisTime := ns.GenesisTimeFetcher.GenesisTime()
    62  	var defaultGenesisTime time.Time
    63  	var gt *timestamp.Timestamp
    64  	if genesisTime == defaultGenesisTime {
    65  		gt = timestamppb.New(time.Unix(0, 0))
    66  	} else {
    67  		gt = timestamppb.New(genesisTime)
    68  	}
    69  
    70  	genValRoot := ns.GenesisFetcher.GenesisValidatorRoot()
    71  	return &ethpb.Genesis{
    72  		GenesisTime:            gt,
    73  		DepositContractAddress: contractAddr,
    74  		GenesisValidatorsRoot:  genValRoot[:],
    75  	}, nil
    76  }
    77  
    78  // GetVersion checks the version information of the beacon node.
    79  func (ns *Server) GetVersion(_ context.Context, _ *empty.Empty) (*ethpb.Version, error) {
    80  	return &ethpb.Version{
    81  		Version: version.Version(),
    82  	}, nil
    83  }
    84  
    85  // ListImplementedServices lists the services implemented and enabled by this node.
    86  //
    87  // Any service not present in this list may return UNIMPLEMENTED or
    88  // PERMISSION_DENIED. The server may also support fetching services by grpc
    89  // reflection.
    90  func (ns *Server) ListImplementedServices(_ context.Context, _ *empty.Empty) (*ethpb.ImplementedServices, error) {
    91  	serviceInfo := ns.Server.GetServiceInfo()
    92  	serviceNames := make([]string, 0, len(serviceInfo))
    93  	for svc := range serviceInfo {
    94  		serviceNames = append(serviceNames, svc)
    95  	}
    96  	sort.Strings(serviceNames)
    97  	return &ethpb.ImplementedServices{
    98  		Services: serviceNames,
    99  	}, nil
   100  }
   101  
   102  // GetHost returns the p2p data on the current local and host peer.
   103  func (ns *Server) GetHost(_ context.Context, _ *empty.Empty) (*ethpb.HostData, error) {
   104  	var stringAddr []string
   105  	for _, addr := range ns.PeerManager.Host().Addrs() {
   106  		stringAddr = append(stringAddr, addr.String())
   107  	}
   108  	record := ns.PeerManager.ENR()
   109  	enr := ""
   110  	var err error
   111  	if record != nil {
   112  		enr, err = p2p.SerializeENR(record)
   113  		if err != nil {
   114  			return nil, status.Errorf(codes.Internal, "Unable to serialize enr: %v", err)
   115  		}
   116  	}
   117  
   118  	return &ethpb.HostData{
   119  		Addresses: stringAddr,
   120  		PeerId:    ns.PeerManager.PeerID().String(),
   121  		Enr:       enr,
   122  	}, nil
   123  }
   124  
   125  // GetPeer returns the data known about the peer defined by the provided peer id.
   126  func (ns *Server) GetPeer(_ context.Context, peerReq *ethpb.PeerRequest) (*ethpb.Peer, error) {
   127  	pid, err := peer.Decode(peerReq.PeerId)
   128  	if err != nil {
   129  		return nil, status.Errorf(codes.InvalidArgument, "Unable to parse provided peer id: %v", err)
   130  	}
   131  	addr, err := ns.PeersFetcher.Peers().Address(pid)
   132  	if err != nil {
   133  		return nil, status.Errorf(codes.NotFound, "Requested peer does not exist: %v", err)
   134  	}
   135  	dir, err := ns.PeersFetcher.Peers().Direction(pid)
   136  	if err != nil {
   137  		return nil, status.Errorf(codes.NotFound, "Requested peer does not exist: %v", err)
   138  	}
   139  	pbDirection := ethpb.PeerDirection_UNKNOWN
   140  	switch dir {
   141  	case network.DirInbound:
   142  		pbDirection = ethpb.PeerDirection_INBOUND
   143  	case network.DirOutbound:
   144  		pbDirection = ethpb.PeerDirection_OUTBOUND
   145  	}
   146  	connState, err := ns.PeersFetcher.Peers().ConnectionState(pid)
   147  	if err != nil {
   148  		return nil, status.Errorf(codes.NotFound, "Requested peer does not exist: %v", err)
   149  	}
   150  	record, err := ns.PeersFetcher.Peers().ENR(pid)
   151  	if err != nil {
   152  		return nil, status.Errorf(codes.NotFound, "Requested peer does not exist: %v", err)
   153  	}
   154  	enr := ""
   155  	if record != nil {
   156  		enr, err = p2p.SerializeENR(record)
   157  		if err != nil {
   158  			return nil, status.Errorf(codes.Internal, "Unable to serialize enr: %v", err)
   159  		}
   160  	}
   161  	return &ethpb.Peer{
   162  		Address:         addr.String(),
   163  		Direction:       pbDirection,
   164  		ConnectionState: ethpb.ConnectionState(connState),
   165  		PeerId:          peerReq.PeerId,
   166  		Enr:             enr,
   167  	}, nil
   168  }
   169  
   170  // ListPeers lists the peers connected to this node.
   171  func (ns *Server) ListPeers(ctx context.Context, _ *empty.Empty) (*ethpb.Peers, error) {
   172  	peers := ns.PeersFetcher.Peers().Connected()
   173  	res := make([]*ethpb.Peer, 0, len(peers))
   174  	for _, pid := range peers {
   175  		if ctx.Err() != nil {
   176  			return nil, ctx.Err()
   177  		}
   178  		multiaddr, err := ns.PeersFetcher.Peers().Address(pid)
   179  		if err != nil {
   180  			continue
   181  		}
   182  		direction, err := ns.PeersFetcher.Peers().Direction(pid)
   183  		if err != nil {
   184  			continue
   185  		}
   186  		record, err := ns.PeersFetcher.Peers().ENR(pid)
   187  		if err != nil {
   188  			continue
   189  		}
   190  		enr := ""
   191  		if record != nil {
   192  			enr, err = p2p.SerializeENR(record)
   193  			if err != nil {
   194  				continue
   195  			}
   196  		}
   197  		multiAddrStr := "unknown"
   198  		if multiaddr != nil {
   199  			multiAddrStr = multiaddr.String()
   200  		}
   201  		address := fmt.Sprintf("%s/p2p/%s", multiAddrStr, pid.Pretty())
   202  		pbDirection := ethpb.PeerDirection_UNKNOWN
   203  		switch direction {
   204  		case network.DirInbound:
   205  			pbDirection = ethpb.PeerDirection_INBOUND
   206  		case network.DirOutbound:
   207  			pbDirection = ethpb.PeerDirection_OUTBOUND
   208  		}
   209  		res = append(res, &ethpb.Peer{
   210  			Address:         address,
   211  			Direction:       pbDirection,
   212  			ConnectionState: ethpb.ConnectionState_CONNECTED,
   213  			PeerId:          pid.String(),
   214  			Enr:             enr,
   215  		})
   216  	}
   217  
   218  	return &ethpb.Peers{
   219  		Peers: res,
   220  	}, nil
   221  }
   222  
   223  // StreamBeaconLogs from the beacon node via a gRPC server-side stream.
   224  func (ns *Server) StreamBeaconLogs(_ *empty.Empty, stream pb.Health_StreamBeaconLogsServer) error {
   225  	ch := make(chan []byte, ns.StreamLogsBufferSize)
   226  	sub := ns.LogsStreamer.LogsFeed().Subscribe(ch)
   227  	defer func() {
   228  		sub.Unsubscribe()
   229  		close(ch)
   230  	}()
   231  
   232  	recentLogs := ns.LogsStreamer.GetLastFewLogs()
   233  	logStrings := make([]string, len(recentLogs))
   234  	for i, log := range recentLogs {
   235  		logStrings[i] = string(log)
   236  	}
   237  	if err := stream.Send(&pb.LogsResponse{
   238  		Logs: logStrings,
   239  	}); err != nil {
   240  		return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
   241  	}
   242  	for {
   243  		select {
   244  		case log := <-ch:
   245  			resp := &pb.LogsResponse{
   246  				Logs: []string{string(log)},
   247  			}
   248  			if err := stream.Send(resp); err != nil {
   249  				return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
   250  			}
   251  		case err := <-sub.Err():
   252  			return status.Errorf(codes.Canceled, "Subscriber error, closing: %v", err)
   253  		case <-stream.Context().Done():
   254  			return status.Error(codes.Canceled, "Context canceled")
   255  		}
   256  	}
   257  }