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 ðpb.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 ðpb.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 ðpb.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 ðpb.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 ðpb.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 ðpb.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, ðpb.Peer{ 210 Address: address, 211 Direction: pbDirection, 212 ConnectionState: ethpb.ConnectionState_CONNECTED, 213 PeerId: pid.String(), 214 Enr: enr, 215 }) 216 } 217 218 return ðpb.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 }