Skip to content

engineapi: switch Engine API SSZ to execution-apis#793#21729

Draft
yperbasis wants to merge 1 commit into
mainfrom
yperbasis/engine-ssz-793
Draft

engineapi: switch Engine API SSZ to execution-apis#793#21729
yperbasis wants to merge 1 commit into
mainfrom
yperbasis/engine-ssz-793

Conversation

@yperbasis

@yperbasis yperbasis commented Jun 10, 2026

Copy link
Copy Markdown
Member

Closes #21600.

PR #21203 implemented the Engine API SSZ transport per execution-apis#764, which has since been closed in favour of execution-apis#793. This PR replaces the execution-apis#764 surface with the execution-apis#793 one.

New surface

Endpoint Replaces
POST /engine/v2/{fork}/payloads engine_newPayloadV{1..5} — SSZ ExecutionPayloadEnvelope; expectedBlobVersionedHashes removed, recomputed from payload.transactions
GET /engine/v2/{fork}/payloads/{id} engine_getPayloadV{1..6} — SSZ BuiltPayload (new field order), Cache-Control: no-store
POST /engine/v2/{fork}/forkchoice engine_forkchoiceUpdatedV{1..4} — optional payload_attributes; optional custody_columns (Amsterdam) decoded but ignored for now
POST /engine/v2/{fork}/bodies/hash, GET /engine/v2/{fork}/bodies?from=N&count=M engine_getPayloadBodiesBy* — new in the SSZ transport; fork-era-scoped, out-of-era/missing blocks come back available=false
POST /engine/v2/blobs/v{1..3} engine_getBlobsV{1..3}BlobEntry{available, contents} lists, 204 No Content for can't-serve / v2 all-or-nothing miss
GET /engine/v2/capabilities, GET /engine/v2/identity JSON discovery (supported forks from the chain config, request limits) and client version

The fork segment maps paris…amsterdamBellatrix…Gloas; unscheduled forks return 400 unsupported-fork. Errors are RFC 7807 application/problem+json with the spec's type URIs; wrong Content-Type → 415; trailing slashes → 404. The old /engine/v{N}/... endpoints are gone (404), and their strings are removed from engine_exchangeCapabilities (discovery now happens via GET /engine/v2/capabilities). HTTP/2 cleartext required no transport work: node.StartHTTPEndpoint already wraps handlers in h2c.

Wire-format changes

  • PayloadStatus.validation_error is now Optional[String] (List[List[byte, 1024], 1]), so absence is distinguishable from an empty message. A test pins the spec's 41-byte VALID example byte-for-byte.
  • BuiltPayload uses the spec's field order (execution_requests before should_override_builder) and carries requests as opaque List[ByteList].
  • Fixing the above surfaced a latent bug: PayloadAttributes SSZ for Electra/Fulu fell into the Gloas branch; Prague/Osaka now correctly use the Cancun shape.

Caveat: engine_getBlobsV4 / POST /blobs/v4

The spec says ELs MUST serve at least the blobs revision matching their current fork — /blobs/v4 (Amsterdam cell-range selection) once Amsterdam is live. This PR does not implement /blobs/v4 because Erigon has no engine_getBlobsV4 implementation anywhere yet (the JSON-RPC API also stops at V3). GET /capabilities honestly advertises {"blobs": ["v1", "v2", "v3"]}. /blobs/v4 should be added in a follow-up together with engine_getBlobsV4 itself.

Interpretation notes

execution-apis#793 is still a draft and only pins the Amsterdam container shapes. Where the spec is not explicit:

  • Earlier-fork envelope/BuiltPayload variants drop the fields their fork didn't have, mirroring the JSON-RPC method progression (e.g. the Paris envelope is just {payload}, the Cancun one adds parent_beacon_block_root).
  • Requests/responses are bare SSZ lists per refactor.md (the normative doc), not the single-field containers sketched in refactor-ssz.md.

Verification

  • TDD: sszrest_test.go was rewritten against the new spec first (red), then the implementation brought it to green; go test ./execution/engineapi/... passes.
  • make erigon integration builds; scoped golangci-lint on the changed packages reports 0 issues.
  • Live smoke test on an ephemeral dev node over curl --http2-prior-knowledge (JWT-authenticated): capabilities/identity JSON, all problem+json error paths, fork-scoped routing, legacy endpoints 404, and a bodies-by-range SSZ response verified byte-by-byte.

Replace the execution-apis#764 surface (version-scoped /engine/vN/...
endpoints) with the fork-scoped REST surface of execution-apis#793:
POST/GET /engine/v2/{fork}/payloads, POST /engine/v2/{fork}/forkchoice,
fork-era-scoped bodies endpoints, POST /engine/v2/blobs/v{1..3}, JSON
GET /engine/v2/capabilities + /engine/v2/identity, and RFC 7807
problem+json errors. PayloadStatus.validation_error becomes
Optional[String]; expectedBlobVersionedHashes is recomputed from the
payload transactions; PayloadAttributes SSZ for Electra/Fulu now uses
the Cancun shape instead of falling into the Gloas branch.

Closes #21600

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates Erigon’s authenticated SSZ-REST Engine API transport to match the newer draft surface from execution-apis#793, replacing the previously implemented #764-based endpoints. This affects both HTTP routing (/engine/v2/…) and several SSZ wire types/codecs used by newPayload/getPayload/forkchoice/blobs/bodies.

Changes:

  • Replaces legacy /engine/v{N}/… SSZ-REST endpoints with fork-scoped /engine/v2/{fork}/… endpoints plus JSON discovery endpoints (GET /engine/v2/capabilities, GET /engine/v2/identity) and RFC7807 application/problem+json error responses.
  • Updates SSZ codecs for the new envelopes/responses (newPayload envelope, BuiltPayload field order, forkchoice update + optional custody columns, blob/body entry wrappers).
  • Rewrites SSZ-REST tests to target the new surface, error mapping, and wire-format details (including the PayloadStatus spec example).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
execution/engineapi/sszrest_wire.go Implements new fork-scoped SSZ schemas/codecs for payload envelopes, forkchoice update, BuiltPayload, bodies, and blobs responses.
execution/engineapi/sszrest_handler.go Replaces routing with /engine/v2/... fork-scoped handlers, adds JSON discovery endpoints, and standardizes errors to RFC7807 problem+json.
execution/engineapi/engine_types/ssz.go Updates SSZ encoding/decoding for PayloadStatus.validation_error optionality and fixes fork-branching for PayloadAttributes encoding.
execution/engineapi/sszrest_test.go Rewrites tests to validate new endpoints, routing/error behavior, and updated SSZ wire formats.
execution/engineapi/engine_api_methods.go Removes legacy SSZ-REST endpoint strings from engine_exchangeCapabilities advertised capabilities.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +307 to 311
switch {
case version < clparams.DenebVersion:
return ssz2.MarshalSSZ(nil, payload, blockValue[:])
case clparams.DenebVersion:
case version < clparams.ElectraVersion:
return ssz2.MarshalSSZ(nil, payload, blockValue[:], blobsBundle, resp.ShouldOverrideBuilder)
Comment on lines +324 to +328
switch {
case version < clparams.DenebVersion:
err = ssz2.UnmarshalSSZ(buf, int(version), payload, blockValue[:])
case version < clparams.ElectraVersion:
err = ssz2.UnmarshalSSZ(buf, int(version), payload, blockValue[:], blobsBundle, &shouldOverride)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch Engine API SSZ to execution-apis#793

2 participants