mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 12:16:44 +00:00
engine: move fork into header out of path
This commit is contained in:
parent
fcefb32655
commit
4797f85ef1
13 changed files with 136 additions and 88 deletions
|
|
@ -61,7 +61,7 @@ func Register(stack *node.Node, backend *eth.Ethereum) error {
|
|||
},
|
||||
})
|
||||
// Mount the REST + SSZ Engine API (execution-apis #793) under
|
||||
// /engine/v2/ on the authenticated HTTP server. The router shares
|
||||
// /engine/v1/ on the authenticated HTTP server. The router shares
|
||||
// catalyst's business logic via the restBackend adapter.
|
||||
stack.RegisterAuthHandler("engine-rest", engineapi.BasePath+"/",
|
||||
http.StripPrefix(engineapi.BasePath, engineapi.NewRouter(newRESTBackend(api))))
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@ func (b *restBackend) NewPayload(ctx context.Context, data engine.ExecutableData
|
|||
|
||||
func (b *restBackend) GetPayload(id engine.PayloadID, allowedForks []forks.Fork) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
// full=true so the envelope carries the complete payload; versions=nil
|
||||
// because the REST router selects the fork from the URL, not the payload
|
||||
// id's embedded version. allowedForks enforces the URL fork's era.
|
||||
// because the REST router selects the fork from the Eth-Execution-Version
|
||||
// header, not the payload id's embedded version. allowedForks enforces the
|
||||
// header fork's era.
|
||||
return b.api.getPayload(id, true, nil, allowedForks)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ type Backend interface {
|
|||
NewPayload(ctx context.Context, data engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (engine.PayloadStatusV1, error)
|
||||
|
||||
// GetPayload returns a previously-built payload. allowedForks filters
|
||||
// to the fork the URL selected; an empty slice disables the check.
|
||||
// to the fork the Eth-Execution-Version header selected; an empty slice
|
||||
// disables the check.
|
||||
GetPayload(id engine.PayloadID, allowedForks []forks.Fork) (*engine.ExecutionPayloadEnvelope, error)
|
||||
|
||||
// GetBlobs returns blob bundle entries indexed by versioned hash.
|
||||
|
|
@ -53,7 +54,7 @@ type Backend interface {
|
|||
// BodiesByHash returns block bodies for the given hashes. Order matches
|
||||
// the input; an entry is nil for unknown/pruned blocks. The second slice
|
||||
// returns the timestamp of each known block (zero for unknown) so the
|
||||
// router can enforce the URL fork's era window.
|
||||
// router can enforce the header fork's era window.
|
||||
BodiesByHash(hashes []common.Hash) ([]*types.Body, []uint64)
|
||||
|
||||
// BodiesByRange returns block bodies for [from, from+count), but the
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
"github.com/karalabe/ssz"
|
||||
)
|
||||
|
||||
// handleBlobs dispatches POST /engine/v2/blobs/v{1,2,3,4}.
|
||||
// handleBlobs dispatches POST /engine/v1/blobs/v{1,2,3,4}.
|
||||
// suffix is the path remainder after "/blobs/".
|
||||
func (rt *Router) handleBlobs(w http.ResponseWriter, r *http.Request, suffix string) {
|
||||
if r.Method != http.MethodPost {
|
||||
|
|
@ -110,7 +110,7 @@ func (rt *Router) handleBlobsV2(w http.ResponseWriter, r *http.Request, allowPar
|
|||
writeSSZResponse(w, resp, ssz.ForkUnknown)
|
||||
}
|
||||
|
||||
// handleBlobsV4 implements POST /engine/v2/blobs/v4 (cell-range selection).
|
||||
// handleBlobsV4 implements POST /engine/v1/blobs/v4 (cell-range selection).
|
||||
// The custody/cell-range logic is not yet plumbed into the txpool; we return
|
||||
// 204 to signal the EL cannot serve it. The handler still validates the
|
||||
// request body and the indices_bitarray length to keep the wire contract live.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import (
|
|||
"github.com/karalabe/ssz"
|
||||
)
|
||||
|
||||
// handleBodiesByHash implements POST /engine/v2/{fork}/bodies/hash.
|
||||
// handleBodiesByHash implements POST /engine/v1/bodies/hash (fork via Eth-Execution-Version).
|
||||
func (rt *Router) handleBodiesByHash(w http.ResponseWriter, r *http.Request, fork forks.Fork) {
|
||||
sf, ok := resolveFork(w, fork, forks.Paris)
|
||||
if !ok {
|
||||
|
|
@ -44,7 +44,7 @@ func (rt *Router) handleBodiesByHash(w http.ResponseWriter, r *http.Request, for
|
|||
writeSSZResponse(w, buildBodiesResponse(rt.backend, fork, sf, bodies, timestamps), sf)
|
||||
}
|
||||
|
||||
// handleBodiesByRange implements GET /engine/v2/{fork}/bodies?from=&count=.
|
||||
// handleBodiesByRange implements GET /engine/v1/bodies?from=&count= (fork via Eth-Execution-Version).
|
||||
func (rt *Router) handleBodiesByRange(w http.ResponseWriter, r *http.Request, fork forks.Fork) {
|
||||
sf, ok := resolveFork(w, fork, forks.Paris)
|
||||
if !ok {
|
||||
|
|
@ -70,7 +70,7 @@ func (rt *Router) handleBodiesByRange(w http.ResponseWriter, r *http.Request, fo
|
|||
}
|
||||
|
||||
// buildBodiesResponse assembles a BodiesResponse for the given fork, marking
|
||||
// out-of-era blocks as available=false per the URL fork window. The body shape
|
||||
// out-of-era blocks as available=false per the header fork window. The body shape
|
||||
// is fork-driven by the codec; bodyToSSZ populates the superset and the codec
|
||||
// emits only the fork's active fields.
|
||||
func buildBodiesResponse(b Backend, fork forks.Fork, sf ssz.Fork, bodies []*types.Body, ts []uint64) *sszt.BodiesResponse {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ type capabilitiesResponse struct {
|
|||
Limits map[string]uint64 `json:"limits"`
|
||||
}
|
||||
|
||||
// handleCapabilities implements GET /engine/v2/capabilities.
|
||||
// handleCapabilities implements GET /engine/v1/capabilities.
|
||||
func (rt *Router) handleCapabilities(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeProblem(w, http.StatusNotFound, ErrMethodNotFound, "")
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
)
|
||||
|
||||
// handleForkchoice implements POST /engine/v2/{fork}/forkchoice.
|
||||
// handleForkchoice implements POST /engine/v1/forkchoice (fork via Eth-Execution-Version).
|
||||
func (rt *Router) handleForkchoice(w http.ResponseWriter, r *http.Request, fork forks.Fork) {
|
||||
// The forkchoice envelope shape is fork-driven by the codec; every fork
|
||||
// from Paris on has a valid wire shape.
|
||||
|
|
@ -48,13 +48,13 @@ func (rt *Router) handleForkchoice(w http.ResponseWriter, r *http.Request, fork
|
|||
writeProblem(w, http.StatusBadRequest, ErrInvalidAttributes, err.Error())
|
||||
return
|
||||
}
|
||||
// If PayloadAttributes is present the URL fork MUST match the fork
|
||||
// the new payload would belong to. ForkFromTimestamp can return a BPO
|
||||
// fork (which has no URL segment of its own); collapse it onto the
|
||||
// named fork it layers on before comparing.
|
||||
// If PayloadAttributes is present the Eth-Execution-Version header MUST
|
||||
// match the fork the new payload would belong to. ForkFromTimestamp can
|
||||
// return a BPO fork (which has no header value of its own); collapse it
|
||||
// onto the named fork it layers on before comparing.
|
||||
if baseFork(rt.backend.ForkFromTimestamp(attr.Timestamp)) != fork {
|
||||
writeProblem(w, http.StatusBadRequest, ErrUnsupportedFork,
|
||||
"payload_attributes timestamp does not match URL fork")
|
||||
"payload_attributes timestamp does not match Eth-Execution-Version header")
|
||||
return
|
||||
}
|
||||
attrs = sszt.PayloadAttributesToEngine(attr)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"github.com/karalabe/ssz"
|
||||
)
|
||||
|
||||
// resolveFork maps the URL fork onto the ssz.Fork the codec multiplexes on,
|
||||
// resolveFork maps the header fork onto the ssz.Fork the codec multiplexes on,
|
||||
// enforcing that it is at least min. On failure it writes the appropriate
|
||||
// problem response and returns ok=false; the caller should return immediately.
|
||||
func resolveFork(w http.ResponseWriter, fork, min forks.Fork) (ssz.Fork, bool) {
|
||||
|
|
@ -42,9 +42,9 @@ func resolveFork(w http.ResponseWriter, fork, min forks.Fork) (ssz.Fork, bool) {
|
|||
}
|
||||
|
||||
// baseFork collapses a BPO fork onto the named fork that it layers on. BPO1..5
|
||||
// sit between Osaka and Amsterdam in params/forks but have no Engine API URL
|
||||
// segment of their own: a chain in a BPO era still negotiates /osaka/*. Named
|
||||
// forks map to themselves.
|
||||
// sit between Osaka and Amsterdam in params/forks but have no Engine API fork
|
||||
// header value of their own: a chain in a BPO era still negotiates
|
||||
// Eth-Execution-Version: osaka. Named forks map to themselves.
|
||||
func baseFork(f forks.Fork) forks.Fork {
|
||||
switch f {
|
||||
case forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5:
|
||||
|
|
@ -54,7 +54,7 @@ func baseFork(f forks.Fork) forks.Fork {
|
|||
}
|
||||
}
|
||||
|
||||
// eraForks returns the set of params/forks values that share a URL fork's
|
||||
// eraForks returns the set of params/forks values that share a header fork's
|
||||
// wire shape: the named fork plus any BPO forks that layer on it. checkFork in
|
||||
// the catalyst layer derives a cached payload's fork via LatestFork, which can
|
||||
// return a BPO fork, so the allowed set passed to GetPayload must include them.
|
||||
|
|
@ -66,7 +66,7 @@ func eraForks(fork forks.Fork) []forks.Fork {
|
|||
}
|
||||
|
||||
// payloadVersionFor selects the JSON-RPC PayloadVersion that the catalyst layer
|
||||
// expects for a given URL fork, mirroring the per-fork version table on the
|
||||
// expects for a given header fork, mirroring the per-fork version table on the
|
||||
// JSON-RPC ForkchoiceUpdatedVx path (Amsterdam -> V4, Cancun..Osaka -> V3,
|
||||
// Shanghai -> V2, Paris -> V1).
|
||||
func payloadVersionFor(fork forks.Fork) engine.PayloadVersion {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import (
|
|||
"github.com/karalabe/ssz"
|
||||
)
|
||||
|
||||
// handleGetPayload implements GET /engine/v2/{fork}/payloads/{payloadId}.
|
||||
// handleGetPayload implements GET /engine/v1/payloads/{payloadId} (fork via Eth-Execution-Version).
|
||||
func (rt *Router) handleGetPayload(w http.ResponseWriter, r *http.Request, fork forks.Fork, idHex string) {
|
||||
sf, ok := resolveFork(w, fork, forks.Paris)
|
||||
if !ok {
|
||||
|
|
@ -41,7 +41,7 @@ func (rt *Router) handleGetPayload(w http.ResponseWriter, r *http.Request, fork
|
|||
var id engine.PayloadID
|
||||
copy(id[:], raw)
|
||||
|
||||
// allowedForks is the URL fork's era: the named fork plus any BPO forks
|
||||
// allowedForks is the header fork's era: the named fork plus any BPO forks
|
||||
// that layer on it. The catalyst layer derives the cached payload's fork
|
||||
// via LatestFork, which can yield a BPO fork.
|
||||
env, err := rt.backend.GetPayload(id, eraForks(fork))
|
||||
|
|
@ -56,7 +56,7 @@ func (rt *Router) handleGetPayload(w http.ResponseWriter, r *http.Request, fork
|
|||
}
|
||||
|
||||
// buildBuiltPayloadAmsterdam packages an engine.ExecutionPayloadEnvelope into
|
||||
// the SSZ BuiltPayload shape for the URL fork. BlockValue/Requests come straight
|
||||
// the SSZ BuiltPayload shape for the header fork. BlockValue/Requests come straight
|
||||
// across; the inner payload goes through the SSZ converter. The blobs bundle is
|
||||
// emitted as V1 (Cancun/Prague) or V2 (Osaka+) per the fork; pre-Cancun forks
|
||||
// carry no bundle (and no should_override_builder), so those fields are left
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
)
|
||||
|
||||
// handleIdentity implements GET /engine/v2/identity.
|
||||
// handleIdentity implements GET /engine/v1/identity.
|
||||
// The CL surfaces itself via the X-Engine-Client-Version request header; the
|
||||
// EL responds with its own ClientVersion in JSON.
|
||||
func (rt *Router) handleIdentity(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
)
|
||||
|
||||
// handleNewPayload implements POST /engine/v2/{fork}/payloads.
|
||||
// handleNewPayload implements POST /engine/v1/payloads (fork via Eth-Execution-Version).
|
||||
func (rt *Router) handleNewPayload(w http.ResponseWriter, r *http.Request, fork forks.Fork) {
|
||||
// The payload envelope shape is fork-driven by the codec; every fork from
|
||||
// Paris on has a valid wire shape.
|
||||
|
|
|
|||
|
|
@ -25,11 +25,14 @@ import (
|
|||
|
||||
// BasePath is the mount prefix for the REST Engine API. Handlers below assume
|
||||
// requests have already been routed under this prefix.
|
||||
const BasePath = "/engine/v2"
|
||||
const BasePath = "/engine/v1"
|
||||
|
||||
// supportedForks lists the fork URL segments the router recognises. Order is
|
||||
// chronological; the router does an exact prefix match so /amsterdam/payloads
|
||||
// is not confused with /amsterdam-foo/payloads.
|
||||
// forkHeader carries the fork name on hot-path requests, replacing the former
|
||||
// /{fork}/ URL segment. Mirrors the Beacon API's Eth-Consensus-Version idiom.
|
||||
const forkHeader = "Eth-Execution-Version"
|
||||
|
||||
// supportedForks lists the fork names the router recognises in the
|
||||
// Eth-Execution-Version header. Lookup is case-insensitive (keys are lower).
|
||||
var supportedForks = map[string]forks.Fork{
|
||||
"paris": forks.Paris,
|
||||
"shanghai": forks.Shanghai,
|
||||
|
|
@ -59,6 +62,8 @@ func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
writeProblem(w, http.StatusNotFound, ErrMethodNotFound, "")
|
||||
return
|
||||
}
|
||||
// Unscoped endpoints ignore the Eth-Execution-Version header; fork-scoped
|
||||
// endpoints resolve the fork from it (see handleForkScoped).
|
||||
switch {
|
||||
case path == "/capabilities":
|
||||
rt.handleCapabilities(w, r)
|
||||
|
|
@ -71,36 +76,50 @@ func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// handleForkScoped routes /{fork}/<endpoint>... paths.
|
||||
// handleForkScoped routes the fork-scoped endpoints (/payloads, /forkchoice,
|
||||
// /bodies). The fork is selected by the Eth-Execution-Version request header
|
||||
// rather than a URL segment. The path is matched first so an entirely unknown
|
||||
// route yields method-not-found rather than masking it as a fork error.
|
||||
func (rt *Router) handleForkScoped(w http.ResponseWriter, r *http.Request, path string) {
|
||||
if len(path) < 2 || path[0] != '/' {
|
||||
writeProblem(w, http.StatusNotFound, ErrMethodNotFound, "")
|
||||
return
|
||||
}
|
||||
rest := path[1:]
|
||||
slash := strings.IndexByte(rest, '/')
|
||||
if slash < 0 {
|
||||
writeProblem(w, http.StatusNotFound, ErrMethodNotFound, "")
|
||||
return
|
||||
}
|
||||
forkName, sub := rest[:slash], rest[slash:]
|
||||
fork, ok := supportedForks[forkName]
|
||||
if !ok {
|
||||
writeProblem(w, http.StatusBadRequest, ErrUnsupportedFork, "unknown fork "+forkName)
|
||||
return
|
||||
}
|
||||
var handler func(w http.ResponseWriter, r *http.Request, fork forks.Fork)
|
||||
switch {
|
||||
case sub == "/payloads" && r.Method == http.MethodPost:
|
||||
rt.handleNewPayload(w, r, fork)
|
||||
case sub == "/forkchoice" && r.Method == http.MethodPost:
|
||||
rt.handleForkchoice(w, r, fork)
|
||||
case strings.HasPrefix(sub, "/payloads/") && r.Method == http.MethodGet:
|
||||
rt.handleGetPayload(w, r, fork, sub[len("/payloads/"):])
|
||||
case sub == "/bodies/hash" && r.Method == http.MethodPost:
|
||||
rt.handleBodiesByHash(w, r, fork)
|
||||
case sub == "/bodies" && r.Method == http.MethodGet:
|
||||
rt.handleBodiesByRange(w, r, fork)
|
||||
case path == "/payloads" && r.Method == http.MethodPost:
|
||||
handler = rt.handleNewPayload
|
||||
case path == "/forkchoice" && r.Method == http.MethodPost:
|
||||
handler = rt.handleForkchoice
|
||||
case strings.HasPrefix(path, "/payloads/") && r.Method == http.MethodGet:
|
||||
id := path[len("/payloads/"):]
|
||||
handler = func(w http.ResponseWriter, r *http.Request, fork forks.Fork) {
|
||||
rt.handleGetPayload(w, r, fork, id)
|
||||
}
|
||||
case path == "/bodies/hash" && r.Method == http.MethodPost:
|
||||
handler = rt.handleBodiesByHash
|
||||
case path == "/bodies" && r.Method == http.MethodGet:
|
||||
handler = rt.handleBodiesByRange
|
||||
default:
|
||||
writeProblem(w, http.StatusNotFound, ErrMethodNotFound, "")
|
||||
return
|
||||
}
|
||||
fork, ok := rt.forkFromHeader(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
handler(w, r, fork)
|
||||
}
|
||||
|
||||
// forkFromHeader resolves the Eth-Execution-Version request header to a fork.
|
||||
// A missing or unrecognised value writes a 400 unsupported-fork problem and
|
||||
// returns ok=false; callers must stop on false.
|
||||
func (rt *Router) forkFromHeader(w http.ResponseWriter, r *http.Request) (forks.Fork, bool) {
|
||||
name := strings.ToLower(strings.TrimSpace(r.Header.Get(forkHeader)))
|
||||
if name == "" {
|
||||
writeProblem(w, http.StatusBadRequest, ErrUnsupportedFork, "missing "+forkHeader+" header")
|
||||
return 0, false
|
||||
}
|
||||
fork, ok := supportedForks[name]
|
||||
if !ok {
|
||||
writeProblem(w, http.StatusBadRequest, ErrUnsupportedFork, "unknown fork "+name)
|
||||
return 0, false
|
||||
}
|
||||
return fork, true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,10 @@ func newTestServer(t *testing.T, b Backend) *httptest.Server {
|
|||
return httptest.NewServer(http.StripPrefix(BasePath, NewRouter(b)))
|
||||
}
|
||||
|
||||
func sszPost(t *testing.T, srv *httptest.Server, path string, body ssz.Object, fork ssz.Fork) *http.Response {
|
||||
// sszPost SSZ-encodes body and POSTs it. forkHdr, when non-empty, is sent as
|
||||
// the Eth-Execution-Version header that fork-scoped endpoints route on; pass ""
|
||||
// for unscoped endpoints (e.g. /blobs/vN) which ignore it.
|
||||
func sszPost(t *testing.T, srv *httptest.Server, path string, body ssz.Object, fork ssz.Fork, forkHdr string) *http.Response {
|
||||
t.Helper()
|
||||
buf := make([]byte, ssz.SizeOnFork(body, fork))
|
||||
if err := ssz.EncodeToBytesOnFork(buf, body, fork); err != nil {
|
||||
|
|
@ -111,6 +114,9 @@ func sszPost(t *testing.T, srv *httptest.Server, path string, body ssz.Object, f
|
|||
}
|
||||
req, _ := http.NewRequest(http.MethodPost, srv.URL+BasePath+path, bytes.NewReader(buf))
|
||||
req.Header.Set("Content-Type", sszContentType)
|
||||
if forkHdr != "" {
|
||||
req.Header.Set(forkHeader, forkHdr)
|
||||
}
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("post %s: %v", path, err)
|
||||
|
|
@ -118,6 +124,19 @@ func sszPost(t *testing.T, srv *httptest.Server, path string, body ssz.Object, f
|
|||
return resp
|
||||
}
|
||||
|
||||
// getFork issues a GET against a fork-scoped endpoint with the given fork set in
|
||||
// the Eth-Execution-Version header.
|
||||
func getFork(t *testing.T, srv *httptest.Server, path, forkHdr string) *http.Response {
|
||||
t.Helper()
|
||||
req, _ := http.NewRequest(http.MethodGet, srv.URL+BasePath+path, nil)
|
||||
req.Header.Set(forkHeader, forkHdr)
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("get %s: %v", path, err)
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func decodeSSZ[T ssz.Object](t *testing.T, resp *http.Response, obj T, fork ssz.Fork) {
|
||||
t.Helper()
|
||||
defer resp.Body.Close()
|
||||
|
|
@ -151,7 +170,7 @@ func TestRouterNewPayload(t *testing.T) {
|
|||
},
|
||||
ParentBeaconBlockRoot: &common.Hash{0x55},
|
||||
}
|
||||
resp := sszPost(t, srv, "/amsterdam/payloads", env, amsterdam)
|
||||
resp := sszPost(t, srv, "/payloads", env, amsterdam, "amsterdam")
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("want 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
|
@ -178,7 +197,7 @@ func TestRouterForkchoice(t *testing.T) {
|
|||
fcu := &sszt.ForkchoiceUpdateAmsterdam{
|
||||
ForkchoiceState: &sszt.ForkchoiceState{HeadBlockHash: common.Hash{0xaa}},
|
||||
}
|
||||
resp := sszPost(t, srv, "/amsterdam/forkchoice", fcu, amsterdam)
|
||||
resp := sszPost(t, srv, "/forkchoice", fcu, amsterdam, "amsterdam")
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("want 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
|
@ -196,14 +215,27 @@ func TestRouterUnsupportedFork(t *testing.T) {
|
|||
srv := newTestServer(t, &stubBackend{})
|
||||
defer srv.Close()
|
||||
|
||||
// Bogus fork in URL: the router does not recognise the segment at all.
|
||||
resp, err := srv.Client().Post(srv.URL+BasePath+"/bogus/payloads", sszContentType, bytes.NewReader(nil))
|
||||
post := func(forkHdr string) int {
|
||||
req, _ := http.NewRequest(http.MethodPost, srv.URL+BasePath+"/payloads", bytes.NewReader(nil))
|
||||
req.Header.Set("Content-Type", sszContentType)
|
||||
if forkHdr != "" {
|
||||
req.Header.Set(forkHeader, forkHdr)
|
||||
}
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 400 {
|
||||
t.Fatalf("want 400, got %d", resp.StatusCode)
|
||||
return resp.StatusCode
|
||||
}
|
||||
|
||||
// Missing Eth-Execution-Version header on a fork-scoped endpoint.
|
||||
if got := post(""); got != 400 {
|
||||
t.Fatalf("missing fork header: want 400, got %d", got)
|
||||
}
|
||||
// Bogus fork: the router does not recognise the header value at all.
|
||||
if got := post("bogus"); got != 400 {
|
||||
t.Fatalf("bogus fork: want 400, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +256,7 @@ func TestRouterAdvertisedForkRoutable(t *testing.T) {
|
|||
npStatus: engine.PayloadStatusV1{Status: engine.VALID},
|
||||
envelope: env,
|
||||
// Osaka chain sitting in a BPO era: ForkFromTimestamp returns a BPO
|
||||
// fork, which must collapse onto the osaka URL fork.
|
||||
// fork, which must collapse onto the osaka header fork.
|
||||
forkAtTime: func(uint64) forks.Fork { return forks.BPO1 },
|
||||
}
|
||||
srv := newTestServer(t, b)
|
||||
|
|
@ -241,7 +273,7 @@ func TestRouterAdvertisedForkRoutable(t *testing.T) {
|
|||
ParentBeaconBlockRoot: &common.Hash{0x55},
|
||||
}},
|
||||
}
|
||||
resp := sszPost(t, srv, "/osaka/forkchoice", fcu, osaka)
|
||||
resp := sszPost(t, srv, "/forkchoice", fcu, osaka, "osaka")
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("forkchoice: want 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
|
@ -259,17 +291,14 @@ func TestRouterAdvertisedForkRoutable(t *testing.T) {
|
|||
},
|
||||
ParentBeaconBlockRoot: &common.Hash{0x55},
|
||||
}
|
||||
resp = sszPost(t, srv, "/osaka/payloads", penv, osaka)
|
||||
resp = sszPost(t, srv, "/payloads", penv, osaka, "osaka")
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("newPayload: want 200, got %d", resp.StatusCode)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// getPayload.
|
||||
resp, err := srv.Client().Get(srv.URL + BasePath + "/osaka/payloads/0x0102030405060708")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp = getFork(t, srv, "/payloads/0x0102030405060708", "osaka")
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("getPayload: want 200, got %d", resp.StatusCode)
|
||||
|
|
@ -279,7 +308,10 @@ func TestRouterAdvertisedForkRoutable(t *testing.T) {
|
|||
func TestRouterUnsupportedMediaType(t *testing.T) {
|
||||
srv := newTestServer(t, &stubBackend{})
|
||||
defer srv.Close()
|
||||
resp, err := srv.Client().Post(srv.URL+BasePath+"/amsterdam/payloads", "application/json", strings.NewReader("{}"))
|
||||
req, _ := http.NewRequest(http.MethodPost, srv.URL+BasePath+"/payloads", strings.NewReader("{}"))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set(forkHeader, "amsterdam")
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -360,8 +392,9 @@ func TestRouterTrailingSlash404(t *testing.T) {
|
|||
func TestRouterSSZDecodeError(t *testing.T) {
|
||||
srv := newTestServer(t, &stubBackend{})
|
||||
defer srv.Close()
|
||||
req, _ := http.NewRequest(http.MethodPost, srv.URL+BasePath+"/amsterdam/payloads", bytes.NewReader([]byte{0xff}))
|
||||
req, _ := http.NewRequest(http.MethodPost, srv.URL+BasePath+"/payloads", bytes.NewReader([]byte{0xff}))
|
||||
req.Header.Set("Content-Type", sszContentType)
|
||||
req.Header.Set(forkHeader, "amsterdam")
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -385,7 +418,7 @@ func TestRouterBlobsV2AllOrNothing(t *testing.T) {
|
|||
srv := newTestServer(t, b)
|
||||
defer srv.Close()
|
||||
req := &sszt.BlobsVersionedHashesRequest{VersionedHashes: []common.Hash{{0x01}}}
|
||||
resp := sszPost(t, srv, "/blobs/v2", req, ssz.ForkUnknown)
|
||||
resp := sszPost(t, srv, "/blobs/v2", req, ssz.ForkUnknown, "")
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 204 {
|
||||
t.Fatalf("want 204, got %d", resp.StatusCode)
|
||||
|
|
@ -397,7 +430,7 @@ func TestRouterBlobsV3PartialOK(t *testing.T) {
|
|||
srv := newTestServer(t, b)
|
||||
defer srv.Close()
|
||||
req := &sszt.BlobsVersionedHashesRequest{VersionedHashes: []common.Hash{{0x01}, {0x02}}}
|
||||
resp := sszPost(t, srv, "/blobs/v3", req, ssz.ForkUnknown)
|
||||
resp := sszPost(t, srv, "/blobs/v3", req, ssz.ForkUnknown, "")
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("want 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
|
@ -421,10 +454,7 @@ func TestRouterGetPayloadCacheControl(t *testing.T) {
|
|||
}
|
||||
srv := newTestServer(t, &stubBackend{envelope: env})
|
||||
defer srv.Close()
|
||||
resp, err := srv.Client().Get(srv.URL + BasePath + "/amsterdam/payloads/0x0102030405060708")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp := getFork(t, srv, "/payloads/0x0102030405060708", "amsterdam")
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("want 200, got %d", resp.StatusCode)
|
||||
|
|
@ -437,10 +467,7 @@ func TestRouterGetPayloadCacheControl(t *testing.T) {
|
|||
func TestRouterGetPayloadUnknown(t *testing.T) {
|
||||
srv := newTestServer(t, &stubBackend{getErr: engine.UnknownPayload})
|
||||
defer srv.Close()
|
||||
resp, err := srv.Client().Get(srv.URL + BasePath + "/amsterdam/payloads/0x0102030405060708")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp := getFork(t, srv, "/payloads/0x0102030405060708", "amsterdam")
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 404 {
|
||||
t.Fatalf("want 404, got %d", resp.StatusCode)
|
||||
|
|
|
|||
Loading…
Reference in a new issue