Skip to content

Add fork-agnostic api/v1 types (api/v1/all)#37

Open
pk910 wants to merge 7 commits into
masterfrom
pk910/apiv1-agnostic-blockcontents
Open

Add fork-agnostic api/v1 types (api/v1/all)#37
pk910 wants to merge 7 commits into
masterfrom
pk910/apiv1-agnostic-blockcontents

Conversation

@pk910

@pk910 pk910 commented Jul 2, 2026

Copy link
Copy Markdown
Member

Add fork-agnostic api/v1 types (api/v1/all)

Motivation

The spec/all package provides fork-agnostic union types for consensus spec
containers, but the api/v1 wire types (block contents, blinded blocks) only
exist as per-fork packages. Consumers that handle multiple forks — builders,
relays, tooling — have to hardcode a fork package (apiv1fulu,
apiv1electra, ...) and duplicate a version switch at every call site.

This PR adds api/v1/all: fork-agnostic counterparts for the api/v1 wire
types, following the spec/all conventions (version-multiplexed views,
dynamic-ssz codecs, JSON/YAML delegation to the per-fork wire shapes).

Types

Type Forks Notes
BlockContents / SignedBlockContents Deneb, Electra, Fulu pre-Deneb submits bare blocks; other versions rejected
BlindedBeaconBlockBody / BlindedBeaconBlock / SignedBlindedBeaconBlock Bellatrix → Electra (+ Fulu on the Electra schema) mirrors spec/all's Electra/Fulu schema sharing

Each type carries a Version field and spec/all component fields
(*all.SignedBeaconBlock, *all.ExecutionPayloadHeader, ...), and implements
the full spec/all codec surface:

  • dynamic-ssz view codecs (MarshalSSZDyn / UnmarshalSSZDyn /
    SizeSSZDyn / HashTreeRootWithDyn) plus the fastssz-compatible wrappers,
    generated via dynssz-gen (view-only mode, like spec/all)
  • JSON/YAML marshaling that delegates to the per-fork wire type, so the bytes
    are identical to the fork-specific packages'
  • ToView / FromView for converting to/from the per-fork types
  • ToVersioned / FromVersioned bridging to api.VersionedProposal,
    api.VersionedSignedProposal, api.VersionedBlindedBeaconBlock,
    api.VersionedSignedBlindedBeaconBlock

Additionally, ProposalFromSignedBlock(*all.SignedBeaconBlock) maps a
post-Gloas bare block into api.VersionedSignedProposal (Gloas/Heze). From
Gloas onwards blocks are submitted without a block-contents wrapper — EIP-7732
separates the execution payload and blobs from the block — so the bare-block
mapping lives here as a helper rather than as a SignedBlockContents version.

Fix included

spec/all.ExecutionPayloadHeader.viewType only accepted
Bellatrix/Capella/Deneb, while ExecutionPayload already mapped
Electra/Fulu → Deneb. An Electra- or Fulu-versioned agnostic header failed to
encode. The multiplexers now match.

Wire compatibility

JSON/SSZ marshaling delegates to the same per-fork view the concrete types
use, so compatibility holds by construction — and is pinned by tests:

  • Test*JSONWireCompat / Test*SSZWireCompat: byte-identical JSON and SSZ
    (and equal hash tree roots) versus the fork-specific type built from the
    same data, per version
  • Test*ToVersioned: the populated Versioned* field is the exact per-fork
    view; for proposals additionally Blinded == false and byte-identical
    encoding of the field the HTTP client actually submits
  • TestSignedBlockContentsFromVersionedBlinded: blinded proposals are
    rejected rather than misread
  • Test*ViewRoundtrip, Test*UnsupportedVersion, version-propagation checks

Notes

  • One helper (propagateVersion) re-implements spec/all's unexported
    populateVersion cascade via reflection, since it is unreachable
    cross-package; behavior is asserted by the round-trip tests.
  • Generated *_ssz.go files are not gofmt-formatted, matching the existing
    generated files in spec/all.

pk910 added 4 commits July 3, 2026 00:05
New api/v1/all package with fork-agnostic BlockContents, SignedBlockContents,
BlindedBeaconBlockBody, BlindedBeaconBlock and SignedBlindedBeaconBlock,
following the spec/all conventions: dynamic-ssz view codecs, JSON/YAML
delegation to the per-fork wire types, ToView/FromView conversion and
ToVersioned/FromVersioned bridging to the api Versioned* containers.
Block contents cover Deneb/Electra/Fulu; blinded blocks cover
Bellatrix..Electra with Fulu mapped to the Electra schema.
Strengthen the ToVersioned tests: the plain (unblinded) per-fork field of
api.VersionedSignedProposal/VersionedProposal must carry the exact per-fork
view (byte-identical JSON and SSZ — the body the http client submits after
AssertPresent), the Blinded flag and *Blinded fields must stay untouched,
and FromVersioned must reject blinded proposals.
The ExecutionPayloadHeader multiplexer only matched Bellatrix/Capella/Deneb,
so an Electra- or Fulu-versioned agnostic header (e.g. seeded by the version
cascade of a blinded beacon block) failed to encode with "unsupported
version". Electra and Fulu do not redefine the container; map them to the
Deneb view, matching the ExecutionPayload multiplexer.
Add SignedExecutionPayloadEnvelopeContents (per-fork api/v1/gloas view +
fork-agnostic api/v1/all union) per the beacon-APIs envelope_post schema,
and wire it into a new ExecutionPayloadEnvelopeSubmitter service interface
(versioned SubmitExecutionPayloadEnvelope + fork-agnostic
SubmitAgnosticExecutionPayloadEnvelope, mirroring the fetch pair).
POST /eth/v1/beacon/execution_payload_envelopes sends the stateless
contents body (Eth-Execution-Payload-Blinded: false) with the consensus
version header from the envelope, as SSZ or JSON per client negotiation.
@pk910 pk910 force-pushed the pk910/apiv1-agnostic-blockcontents branch from d3542f1 to 9d24dac Compare July 3, 2026 01:20
pk910 added 2 commits July 3, 2026 03:26
Add ExecutionPayloadBidSubmitter (versioned SubmitExecutionPayloadBid +
fork-agnostic SubmitAgnosticExecutionPayloadBid) posting the bare signed
bid to /eth/v1/beacon/execution_payload_bids as SSZ or JSON with the
consensus version header, per the beacon-APIs bid schema.
Add NodeIdentityProvider for GET /eth/v1/node/identity.
Bellatrix and capella proposals are plain signed beacon blocks — blobs
only enter the proposal wrapper at Deneb. The helper previously handled
only the post-Gloas bare-block forks, leaving no way to build a
versioned proposal for an unblinded pre-Deneb block (SignedBlockContents
is Deneb+ and its ToVersioned rejects earlier versions). Deneb through
Fulu remain rejected with a pointer to SignedBlockContents.ToVersioned.
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