Skip to content

fix(http): unwrap JSON data envelope for execution payload envelopes#36

Open
samcm wants to merge 2 commits into
masterfrom
fix/envelope-json-unwrap
Open

fix(http): unwrap JSON data envelope for execution payload envelopes#36
samcm wants to merge 2 commits into
masterfrom
fix/envelope-json-unwrap

Conversation

@samcm

@samcm samcm commented Jul 2, 2026

Copy link
Copy Markdown
Member

The JSON path of SignedExecutionPayloadEnvelope and AgnosticSignedExecutionPayloadEnvelope passed the raw response body to UnmarshalJSON, which fails with message missing because beacon nodes wrap the payload as {"version":...,"data":{...}}. SSZ responses were unaffected, which hid the bug from SSZ-preferring clients — xatu cannon negotiates JSON and could not fetch any envelope from glamsterdam-devnet-6 (every envelope-sourced deriver failed).

Fix: use decodeJSONResponse like the other endpoints so the data field is extracted and response metadata is preserved.

Verification:

  • The beacon-APIs spec for the endpoint requires the JSON response shape {version, execution_optimistic, finalized, data} — unwrapping data is the spec-mandated behavior, not a client quirk.
  • Confirmed live against glamsterdam-devnet-6 on two client implementations: Nimbus and Prysm both return the spec wrapper and decode correctly with this fix (verified via connection-pinned /eth/v1/node/version + envelope requests through the network's load-balanced endpoint).
  • xatu cannon's envelope-sourced derivers proceed with this fix applied.

Side observation from testing (not addressed here): envelope retention varies by client — Nimbus serves historical envelopes, Prysm only a narrow near-head window (404 execution payload envelope not found otherwise).

The JSON path of SignedExecutionPayloadEnvelope and
AgnosticSignedExecutionPayloadEnvelope passed the raw response body to
UnmarshalJSON, which fails with "message missing" because beacon nodes
wrap the payload as {"version":...,"data":{...}}. Use
decodeJSONResponse like the other endpoints so the data field is
extracted (and response metadata preserved). SSZ responses were
unaffected, which hid the bug from SSZ-preferring clients.
@samcm samcm marked this pull request as ready for review July 2, 2026 07:17
The beacon-API eventstream spec wraps payload_attestation_message,
execution_payload_bid and proposer_preferences as
{"version": ..., "data": {...}}. Lighthouse follows the spec; Prysm
still sends the bare object. Decode the wrapper when present and fall
back to the bare shape, so both clients parse.

Observed live on glamsterdam-devnet-6: every lighthouse PTC message
failed with 'invalid JSON: beacon block root missing'.
@samcm

samcm commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Pushed a second fix to this branch: the gloas SSE events (payload_attestation_message, execution_payload_bid, proposer_preferences) now accept the spec's {"version", "data"} wrapper (Lighthouse) as well as the bare object (Prysm). Found live on glamsterdam-devnet-6 — every Lighthouse PTC message failed to parse. Test covers both shapes with a real devnet payload.

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.

1 participant