mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
**What type of PR is this?** Tooling **What does the PR do?** Every call to `httputil.HandleError` must be followed by a `return` statement. It's easy to miss this during reviews, so having a static analyzer that enforces this will make our life easier. **Acknowledgements** - [x] I have read [CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md). - [x] I have included a uniquely named [changelog fragment file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd). - [x] I have added a description with sufficient context for reviewers to understand this PR. - [x] I have tested that my changes work as expected and I added a testing plan to the PR description (if applicable). --------- Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
151 lines
5.2 KiB
Go
151 lines
5.2 KiB
Go
package node
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"runtime"
|
|
"strconv"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/eth/shared"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
|
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/eth/v1"
|
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
)
|
|
|
|
var (
|
|
stateConnecting = ethpb.ConnectionState_CONNECTING.String()
|
|
stateConnected = ethpb.ConnectionState_CONNECTED.String()
|
|
stateDisconnecting = ethpb.ConnectionState_DISCONNECTING.String()
|
|
stateDisconnected = ethpb.ConnectionState_DISCONNECTED.String()
|
|
directionInbound = ethpb.PeerDirection_INBOUND.String()
|
|
directionOutbound = ethpb.PeerDirection_OUTBOUND.String()
|
|
)
|
|
|
|
// GetSyncStatus requests the beacon node to describe if it's currently syncing or not, and
|
|
// if it is, what block it is up to.
|
|
func (s *Server) GetSyncStatus(w http.ResponseWriter, r *http.Request) {
|
|
ctx, span := trace.StartSpan(r.Context(), "node.GetSyncStatus")
|
|
defer span.End()
|
|
|
|
isOptimistic, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not check optimistic status: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
headSlot := s.HeadFetcher.HeadSlot()
|
|
response := &structs.SyncStatusResponse{
|
|
Data: &structs.SyncStatusResponseData{
|
|
HeadSlot: strconv.FormatUint(uint64(headSlot), 10),
|
|
SyncDistance: strconv.FormatUint(uint64(s.GenesisTimeFetcher.CurrentSlot()-headSlot), 10),
|
|
IsSyncing: s.SyncChecker.Syncing(),
|
|
IsOptimistic: isOptimistic,
|
|
ElOffline: !s.ExecutionChainInfoFetcher.ExecutionClientConnected(),
|
|
},
|
|
}
|
|
httputil.WriteJson(w, response)
|
|
}
|
|
|
|
// GetIdentity retrieves data about the node's network presence.
|
|
func (s *Server) GetIdentity(w http.ResponseWriter, r *http.Request) {
|
|
_, span := trace.StartSpan(r.Context(), "node.GetIdentity")
|
|
defer span.End()
|
|
|
|
peerId := s.PeerManager.PeerID().String()
|
|
sourcep2p := s.PeerManager.Host().Addrs()
|
|
p2pAddresses := make([]string, len(sourcep2p))
|
|
for i := range sourcep2p {
|
|
p2pAddresses[i] = sourcep2p[i].String() + "/p2p/" + peerId
|
|
}
|
|
sourceDisc, err := s.PeerManager.DiscoveryAddresses()
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain discovery address: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
discoveryAddresses := make([]string, len(sourceDisc))
|
|
for i := range sourceDisc {
|
|
discoveryAddresses[i] = sourceDisc[i].String()
|
|
}
|
|
serializedEnr, err := p2p.SerializeENR(s.PeerManager.ENR())
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not obtain enr: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
currentEpoch := slots.ToEpoch(s.GenesisTimeFetcher.CurrentSlot())
|
|
metadata := s.MetadataProvider.Metadata()
|
|
md := &structs.Metadata{
|
|
SeqNumber: strconv.FormatUint(s.MetadataProvider.MetadataSeq(), 10),
|
|
Attnets: hexutil.Encode(metadata.AttnetsBitfield()),
|
|
}
|
|
if currentEpoch >= params.BeaconConfig().AltairForkEpoch {
|
|
md.Syncnets = hexutil.Encode(metadata.SyncnetsBitfield())
|
|
}
|
|
if currentEpoch >= params.BeaconConfig().FuluForkEpoch {
|
|
md.Cgc = strconv.FormatUint(metadata.CustodyGroupCount(), 10)
|
|
}
|
|
resp := &structs.GetIdentityResponse{
|
|
Data: &structs.Identity{
|
|
PeerId: peerId,
|
|
Enr: "enr:" + serializedEnr,
|
|
P2PAddresses: p2pAddresses,
|
|
DiscoveryAddresses: discoveryAddresses,
|
|
Metadata: md,
|
|
},
|
|
}
|
|
httputil.WriteJson(w, resp)
|
|
}
|
|
|
|
// GetVersion requests that the beacon node identify information about its implementation in a
|
|
// format similar to a HTTP User-Agent field.
|
|
func (*Server) GetVersion(w http.ResponseWriter, r *http.Request) {
|
|
_, span := trace.StartSpan(r.Context(), "node.GetVersion")
|
|
defer span.End()
|
|
|
|
v := fmt.Sprintf("Prysm/%s (%s %s)", version.SemanticVersion(), runtime.GOOS, runtime.GOARCH)
|
|
resp := &structs.GetVersionResponse{
|
|
Data: &structs.Version{
|
|
Version: v,
|
|
},
|
|
}
|
|
httputil.WriteJson(w, resp)
|
|
}
|
|
|
|
// GetHealth returns node health status in http status codes. Useful for load balancers.
|
|
func (s *Server) GetHealth(w http.ResponseWriter, r *http.Request) {
|
|
ctx, span := trace.StartSpan(r.Context(), "node.GetHealth")
|
|
defer span.End()
|
|
|
|
rawSyncingStatus, syncingStatus, ok := shared.UintFromQuery(w, r, "syncing_status", false)
|
|
// lint:ignore uintcast -- custom syncing status being outside of range is harmless
|
|
intSyncingStatus := int(syncingStatus)
|
|
if !ok || (rawSyncingStatus != "" && http.StatusText(intSyncingStatus) == "") {
|
|
httputil.HandleError(w, "syncing_status is not a valid HTTP status code", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
|
|
if err != nil {
|
|
httputil.HandleError(w, "Could not check optimistic status: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if s.SyncChecker.Synced() && !optimistic {
|
|
return
|
|
}
|
|
if s.SyncChecker.Syncing() || optimistic {
|
|
if rawSyncingStatus != "" {
|
|
w.WriteHeader(intSyncingStatus)
|
|
} else {
|
|
w.WriteHeader(http.StatusPartialContent)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
}
|