diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index a98dc1def0..d0955d8765 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -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)))) diff --git a/eth/catalyst/rest_backend.go b/eth/catalyst/rest_backend.go index d2ea1e4edd..5f8856a12b 100644 --- a/eth/catalyst/rest_backend.go +++ b/eth/catalyst/rest_backend.go @@ -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) } diff --git a/eth/engineapi/backend.go b/eth/engineapi/backend.go index 36dee977bf..5b3f943759 100644 --- a/eth/engineapi/backend.go +++ b/eth/engineapi/backend.go @@ -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 diff --git a/eth/engineapi/blobs.go b/eth/engineapi/blobs.go index 0d80da45c6..419a22bda0 100644 --- a/eth/engineapi/blobs.go +++ b/eth/engineapi/blobs.go @@ -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. diff --git a/eth/engineapi/bodies.go b/eth/engineapi/bodies.go index 75f76136a3..48c646351d 100644 --- a/eth/engineapi/bodies.go +++ b/eth/engineapi/bodies.go @@ -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 { diff --git a/eth/engineapi/capabilities.go b/eth/engineapi/capabilities.go index 448b702afc..ce58e3e6e9 100644 --- a/eth/engineapi/capabilities.go +++ b/eth/engineapi/capabilities.go @@ -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, "") diff --git a/eth/engineapi/forkchoice.go b/eth/engineapi/forkchoice.go index a433cfa8fa..421ad6e7e0 100644 --- a/eth/engineapi/forkchoice.go +++ b/eth/engineapi/forkchoice.go @@ -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) diff --git a/eth/engineapi/forkresolve.go b/eth/engineapi/forkresolve.go index ec6ed6479b..cc4eb034fb 100644 --- a/eth/engineapi/forkresolve.go +++ b/eth/engineapi/forkresolve.go @@ -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 { diff --git a/eth/engineapi/get_payload.go b/eth/engineapi/get_payload.go index 1108e21a79..623430ca43 100644 --- a/eth/engineapi/get_payload.go +++ b/eth/engineapi/get_payload.go @@ -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 diff --git a/eth/engineapi/identity.go b/eth/engineapi/identity.go index 54986fb512..96354fdaa4 100644 --- a/eth/engineapi/identity.go +++ b/eth/engineapi/identity.go @@ -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) { diff --git a/eth/engineapi/payloads.go b/eth/engineapi/payloads.go index 627d4bc2b4..1f030e2873 100644 --- a/eth/engineapi/payloads.go +++ b/eth/engineapi/payloads.go @@ -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. diff --git a/eth/engineapi/router.go b/eth/engineapi/router.go index 7b379c4341..ba381b48dc 100644 --- a/eth/engineapi/router.go +++ b/eth/engineapi/router.go @@ -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}/... 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 } diff --git a/eth/engineapi/router_test.go b/eth/engineapi/router_test.go index 4b229d0637..9cd42c428c 100644 --- a/eth/engineapi/router_test.go +++ b/eth/engineapi/router_test.go @@ -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)) - if err != nil { - t.Fatal(err) + 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() + return resp.StatusCode } - resp.Body.Close() - if resp.StatusCode != 400 { - t.Fatalf("want 400, got %d", 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)