mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
Middleware for Caplin Beacon API (#8103)
This commit is contained in:
parent
9b63764b16
commit
e7dbc69571
64
cl/beacon/handler/format.go
Normal file
64
cl/beacon/handler/format.go
Normal file
@ -0,0 +1,64 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/types/ssz"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
)
|
||||
|
||||
type BeaconResponse struct {
|
||||
Finalized *bool `json:"finalized,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
ExecutionOptimistic *bool `json:"execution_optimistic,omitempty"`
|
||||
Data ssz.Marshaler `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// In case of it being a json we need to also expose finalization, version, etc...
|
||||
type beaconHandlerFn func(r *http.Request) (data ssz.Marshaler, finalized *bool, version *clparams.StateVersion, httpStatus int, err error)
|
||||
|
||||
func beaconHandlerWrapper(fn beaconHandlerFn) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
accept := r.Header.Get("Accept")
|
||||
isSSZ := !strings.Contains(accept, "application/json") && strings.Contains(accept, "application/stream-octect")
|
||||
data, finalized, version, httpStatus, err := fn(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(httpStatus)
|
||||
io.WriteString(w, err.Error())
|
||||
log.Debug("[Beacon API] failed", "method", r.Method, "err", err, "ssz", isSSZ)
|
||||
return
|
||||
}
|
||||
|
||||
if isSSZ {
|
||||
// SSZ encoding
|
||||
encoded, err := data.EncodeSSZ(nil)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
io.WriteString(w, err.Error())
|
||||
log.Debug("[Beacon API] failed", "method", r.Method, "err", err, "accepted", accept)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.WriteHeader(httpStatus)
|
||||
w.Write(encoded)
|
||||
log.Debug("[Beacon API] genesis handler failed", err)
|
||||
return
|
||||
}
|
||||
resp := &BeaconResponse{Data: data}
|
||||
if version != nil {
|
||||
resp.Version = clparams.ClVersionToString(*version)
|
||||
}
|
||||
if finalized != nil {
|
||||
resp.ExecutionOptimistic = new(bool)
|
||||
resp.Finalized = new(bool)
|
||||
*resp.Finalized = *finalized
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(httpStatus)
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon-lib/types/ssz"
|
||||
"github.com/ledgerwatch/erigon/cl/beacon/types"
|
||||
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||
"github.com/ledgerwatch/erigon/cl/fork"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
ssz2 "github.com/ledgerwatch/erigon/cl/ssz"
|
||||
)
|
||||
|
||||
type genesisReponse struct {
|
||||
@ -17,26 +18,33 @@ type genesisReponse struct {
|
||||
GenesisForkVersion types.Bytes4 `json:"genesis_fork_version,omitempty"`
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getGenesis(w http.ResponseWriter, _ *http.Request) {
|
||||
func (g *genesisReponse) EncodeSSZ(buf []byte) ([]byte, error) {
|
||||
return ssz2.MarshalSSZ(buf, g.GenesisTime, g.GenesisValidatorRoot[:], g.GenesisForkVersion[:])
|
||||
}
|
||||
|
||||
func (g *genesisReponse) EncodingSizeSSZ() int {
|
||||
return 44
|
||||
}
|
||||
|
||||
func (a *ApiHandler) getGenesis(r *http.Request) (data ssz.Marshaler, finalized *bool, version *clparams.StateVersion, httpStatus int, err error) {
|
||||
if a.genesisCfg == nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
io.WriteString(w, "Genesis Config is missing")
|
||||
err = errors.New("Genesis Config is missing")
|
||||
httpStatus = http.StatusNotFound
|
||||
return
|
||||
}
|
||||
|
||||
digest, err := fork.ComputeForkDigest(a.beaconChainCfg, a.genesisCfg)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
io.WriteString(w, "Failed to compute fork digest")
|
||||
log.Error("[Beacon API] genesis handler failed", err)
|
||||
err = errors.New("Failed to compute fork digest")
|
||||
httpStatus = http.StatusInternalServerError
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "Application/json")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
json.NewEncoder(w).Encode(genesisReponse{
|
||||
data = &genesisReponse{
|
||||
GenesisTime: a.genesisCfg.GenesisTime,
|
||||
GenesisValidatorRoot: a.genesisCfg.GenesisValidatorRoot,
|
||||
GenesisForkVersion: types.Bytes4(digest),
|
||||
})
|
||||
}
|
||||
httpStatus = http.StatusAccepted
|
||||
return
|
||||
}
|
||||
|
@ -35,12 +35,17 @@ func (a *ApiHandler) init() {
|
||||
r.Route("/v1", func(r chi.Router) {
|
||||
r.Get("/events", nil)
|
||||
r.Route("/beacon", func(r chi.Router) {
|
||||
r.Get("/headers/{tag}", nil) // otterscan
|
||||
r.Get("/blocks/{block_id}", a.getBlock) //otterscan
|
||||
r.Get("/blocks/{block_id}/root", a.getBlockRoot) //otterscan
|
||||
r.Get("/genesis", a.getGenesis)
|
||||
r.Route("/headers", func(r chi.Router) {
|
||||
r.Get("/", nil)
|
||||
r.Get("/{block_id}", nil)
|
||||
})
|
||||
r.Route("/blocks", func(r chi.Router) {
|
||||
r.Post("/", nil)
|
||||
r.Get("/{block_id}", a.getBlock)
|
||||
r.Get("/block_id}/root", a.getBlockRoot)
|
||||
})
|
||||
r.Get("/genesis", beaconHandlerWrapper(a.getGenesis))
|
||||
r.Post("/binded_blocks", nil)
|
||||
r.Post("/blocks", nil)
|
||||
r.Route("/pool", func(r chi.Router) {
|
||||
r.Post("/attestations", nil)
|
||||
r.Post("/sync_committees", nil)
|
||||
|
19
cl/beacon/middleware.go
Normal file
19
cl/beacon/middleware.go
Normal file
@ -0,0 +1,19 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func newBeaconMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if contentType != "application/json" && contentType != "" {
|
||||
fmt.Println(contentType)
|
||||
http.Error(w, "Content-Type header must be application/json", http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
@ -23,7 +23,7 @@ type RouterConfiguration struct {
|
||||
func ListenAndServe(api *handler.ApiHandler, routerCfg *RouterConfiguration) {
|
||||
listener, err := net.Listen(routerCfg.Protocol, routerCfg.Address)
|
||||
server := &http.Server{
|
||||
Handler: api,
|
||||
Handler: newBeaconMiddleware(api),
|
||||
ReadTimeout: routerCfg.ReadTimeTimeout,
|
||||
IdleTimeout: routerCfg.IdleTimeout,
|
||||
WriteTimeout: routerCfg.IdleTimeout,
|
||||
|
@ -27,3 +27,20 @@ func StringToClVersion(s string) StateVersion {
|
||||
panic("unsupported fork version: " + s)
|
||||
}
|
||||
}
|
||||
|
||||
func ClVersionToString(s StateVersion) string {
|
||||
switch s {
|
||||
case Phase0Version:
|
||||
return "phase0"
|
||||
case AltairVersion:
|
||||
return "altair"
|
||||
case BellatrixVersion:
|
||||
return "bellatrix"
|
||||
case CapellaVersion:
|
||||
return "capella"
|
||||
case DenebVersion:
|
||||
return "deneb"
|
||||
default:
|
||||
panic("unsupported fork version")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user