mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-08 18:51:19 +00:00
5a66807989
* First take at updating everything to v5 * Patch gRPC gateway to use prysm v5 Fix patch * Update go ssz --------- Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
281 lines
8.1 KiB
Go
281 lines
8.1 KiB
Go
package node
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers"
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers/peerdata"
|
|
"github.com/prysmaticlabs/prysm/v5/network/httputil"
|
|
"github.com/prysmaticlabs/prysm/v5/proto/migration"
|
|
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
// GetPeer retrieves data about the given peer.
|
|
func (s *Server) GetPeer(w http.ResponseWriter, r *http.Request) {
|
|
_, span := trace.StartSpan(r.Context(), "node.GetPeer")
|
|
defer span.End()
|
|
|
|
rawId := mux.Vars(r)["peer_id"]
|
|
if rawId == "" {
|
|
httputil.HandleError(w, "peer_id is required in URL params", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
peerStatus := s.PeersFetcher.Peers()
|
|
id, err := peer.Decode(rawId)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Invalid peer ID: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
enr, err := peerStatus.ENR(id)
|
|
if err != nil {
|
|
if errors.Is(err, peerdata.ErrPeerUnknown) {
|
|
httputil.HandleError(w, "Peer not found: "+err.Error(), http.StatusNotFound)
|
|
return
|
|
}
|
|
httputil.HandleError(w, "Could not obtain ENR: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
serializedEnr, err := p2p.SerializeENR(enr)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain ENR: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
p2pAddress, err := peerStatus.Address(id)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain address: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
state, err := peerStatus.ConnectionState(id)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain connection state: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
direction, err := peerStatus.Direction(id)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain direction: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if eth.PeerDirection(direction) == eth.PeerDirection_UNKNOWN {
|
|
httputil.HandleError(w, "Peer not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
v1ConnState := migration.V1Alpha1ConnectionStateToV1(eth.ConnectionState(state))
|
|
v1PeerDirection, err := migration.V1Alpha1PeerDirectionToV1(eth.PeerDirection(direction))
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not handle peer direction: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
resp := &structs.GetPeerResponse{
|
|
Data: &structs.Peer{
|
|
PeerId: rawId,
|
|
Enr: "enr:" + serializedEnr,
|
|
LastSeenP2PAddress: p2pAddress.String(),
|
|
State: strings.ToLower(v1ConnState.String()),
|
|
Direction: strings.ToLower(v1PeerDirection.String()),
|
|
},
|
|
}
|
|
httputil.WriteJson(w, resp)
|
|
}
|
|
|
|
// GetPeers retrieves data about the node's network peers.
|
|
func (s *Server) GetPeers(w http.ResponseWriter, r *http.Request) {
|
|
_, span := trace.StartSpan(r.Context(), "node.GetPeers")
|
|
defer span.End()
|
|
|
|
states := r.URL.Query()["state"]
|
|
directions := r.URL.Query()["direction"]
|
|
|
|
peerStatus := s.PeersFetcher.Peers()
|
|
emptyStateFilter, emptyDirectionFilter := handleEmptyFilters(states, directions)
|
|
|
|
if emptyStateFilter && emptyDirectionFilter {
|
|
allIds := peerStatus.All()
|
|
allPeers := make([]*structs.Peer, 0, len(allIds))
|
|
for _, id := range allIds {
|
|
p, err := peerInfo(peerStatus, id)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not get peer info: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if p == nil {
|
|
continue
|
|
}
|
|
allPeers = append(allPeers, p)
|
|
}
|
|
resp := &structs.GetPeersResponse{Data: allPeers}
|
|
httputil.WriteJson(w, resp)
|
|
return
|
|
}
|
|
|
|
var stateIds []peer.ID
|
|
if emptyStateFilter {
|
|
stateIds = peerStatus.All()
|
|
} else {
|
|
for _, stateFilter := range states {
|
|
switch strings.ToUpper(stateFilter) {
|
|
case stateConnecting:
|
|
ids := peerStatus.Connecting()
|
|
stateIds = append(stateIds, ids...)
|
|
case stateConnected:
|
|
ids := peerStatus.Connected()
|
|
stateIds = append(stateIds, ids...)
|
|
case stateDisconnecting:
|
|
ids := peerStatus.Disconnecting()
|
|
stateIds = append(stateIds, ids...)
|
|
case stateDisconnected:
|
|
ids := peerStatus.Disconnected()
|
|
stateIds = append(stateIds, ids...)
|
|
}
|
|
}
|
|
}
|
|
|
|
var directionIds []peer.ID
|
|
if emptyDirectionFilter {
|
|
directionIds = peerStatus.All()
|
|
} else {
|
|
for _, directionFilter := range directions {
|
|
switch strings.ToUpper(directionFilter) {
|
|
case directionInbound:
|
|
ids := peerStatus.Inbound()
|
|
directionIds = append(directionIds, ids...)
|
|
case directionOutbound:
|
|
ids := peerStatus.Outbound()
|
|
directionIds = append(directionIds, ids...)
|
|
}
|
|
}
|
|
}
|
|
|
|
var filteredIds []peer.ID
|
|
for _, stateId := range stateIds {
|
|
for _, directionId := range directionIds {
|
|
if stateId.String() == directionId.String() {
|
|
filteredIds = append(filteredIds, stateId)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
filteredPeers := make([]*structs.Peer, 0, len(filteredIds))
|
|
for _, id := range filteredIds {
|
|
p, err := peerInfo(peerStatus, id)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not get peer info: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if p == nil {
|
|
continue
|
|
}
|
|
filteredPeers = append(filteredPeers, p)
|
|
}
|
|
|
|
resp := &structs.GetPeersResponse{Data: filteredPeers}
|
|
httputil.WriteJson(w, resp)
|
|
}
|
|
|
|
// GetPeerCount retrieves number of known peers.
|
|
func (s *Server) GetPeerCount(w http.ResponseWriter, r *http.Request) {
|
|
_, span := trace.StartSpan(r.Context(), "node.PeerCount")
|
|
defer span.End()
|
|
|
|
peerStatus := s.PeersFetcher.Peers()
|
|
|
|
resp := &structs.GetPeerCountResponse{
|
|
Data: &structs.PeerCount{
|
|
Disconnected: strconv.FormatInt(int64(len(peerStatus.Disconnected())), 10),
|
|
Connecting: strconv.FormatInt(int64(len(peerStatus.Connecting())), 10),
|
|
Connected: strconv.FormatInt(int64(len(peerStatus.Connected())), 10),
|
|
Disconnecting: strconv.FormatInt(int64(len(peerStatus.Disconnecting())), 10),
|
|
},
|
|
}
|
|
httputil.WriteJson(w, resp)
|
|
}
|
|
|
|
func handleEmptyFilters(states []string, directions []string) (emptyState, emptyDirection bool) {
|
|
emptyState = true
|
|
for _, stateFilter := range states {
|
|
normalized := strings.ToUpper(stateFilter)
|
|
filterValid := normalized == stateConnecting || normalized == stateConnected ||
|
|
normalized == stateDisconnecting || normalized == stateDisconnected
|
|
if filterValid {
|
|
emptyState = false
|
|
break
|
|
}
|
|
}
|
|
|
|
emptyDirection = true
|
|
for _, directionFilter := range directions {
|
|
normalized := strings.ToUpper(directionFilter)
|
|
filterValid := normalized == directionInbound || normalized == directionOutbound
|
|
if filterValid {
|
|
emptyDirection = false
|
|
break
|
|
}
|
|
}
|
|
|
|
return emptyState, emptyDirection
|
|
}
|
|
|
|
func peerInfo(peerStatus *peers.Status, id peer.ID) (*structs.Peer, error) {
|
|
enr, err := peerStatus.ENR(id)
|
|
if err != nil {
|
|
if errors.Is(err, peerdata.ErrPeerUnknown) {
|
|
return nil, nil
|
|
}
|
|
return nil, errors.Wrap(err, "could not obtain ENR")
|
|
}
|
|
var serializedEnr string
|
|
if enr != nil {
|
|
serializedEnr, err = p2p.SerializeENR(enr)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not serialize ENR")
|
|
}
|
|
}
|
|
address, err := peerStatus.Address(id)
|
|
if err != nil {
|
|
if errors.Is(err, peerdata.ErrPeerUnknown) {
|
|
return nil, nil
|
|
}
|
|
return nil, errors.Wrap(err, "could not obtain address")
|
|
}
|
|
connectionState, err := peerStatus.ConnectionState(id)
|
|
if err != nil {
|
|
if errors.Is(err, peerdata.ErrPeerUnknown) {
|
|
return nil, nil
|
|
}
|
|
return nil, errors.Wrap(err, "could not obtain connection state")
|
|
}
|
|
direction, err := peerStatus.Direction(id)
|
|
if err != nil {
|
|
if errors.Is(err, peerdata.ErrPeerUnknown) {
|
|
return nil, nil
|
|
}
|
|
return nil, errors.Wrap(err, "could not obtain direction")
|
|
}
|
|
if eth.PeerDirection(direction) == eth.PeerDirection_UNKNOWN {
|
|
return nil, nil
|
|
}
|
|
p := &structs.Peer{
|
|
PeerId: id.String(),
|
|
State: strings.ToLower(eth.ConnectionState(connectionState).String()),
|
|
Direction: strings.ToLower(eth.PeerDirection(direction).String()),
|
|
}
|
|
if address != nil {
|
|
p.LastSeenP2PAddress = address.String()
|
|
}
|
|
if serializedEnr != "" {
|
|
p.Enr = "enr:" + serializedEnr
|
|
}
|
|
|
|
return p, nil
|
|
}
|