Skip to content

Add SSZ response support for validators and validator_balances endpoints#601

Open
Zyra-V21 wants to merge 1 commit into
ethereum:masterfrom
Zyra-V21:feat/ssz-validators-endpoint
Open

Add SSZ response support for validators and validator_balances endpoints#601
Zyra-V21 wants to merge 1 commit into
ethereum:masterfrom
Zyra-V21:feat/ssz-validators-endpoint

Conversation

@Zyra-V21
Copy link
Copy Markdown

@Zyra-V21 Zyra-V21 commented Apr 28, 2026

Motivation

The /eth/v1/beacon/states/{state_id}/validators endpoint currently returns JSON only. On mainnet today this is roughly 1 GB per state for the full validator set, while the equivalent SSZ payload is around an order of magnitude smaller and trivially cheaper to serialize and parse on both sides. The same applies to validator_balances (around 85 MB JSON per state).

For analytics and indexing tooling that snapshots validators frequently — for example Migalabs' goteth and similar consensus-layer indexers — JSON parsing and beacon-node CPU time during state snapshots are a real bottleneck. Exposing SSZ on these endpoints reduces both ends of the cost.

This proposal does not introduce a new design: it implements the agreement reached in the discussion of #333 (which has been open and unactioned since 2023).

Scope

Adds application/octet-stream (SSZ) response support to:

  • GET /eth/v1/beacon/states/{state_id}/validators
  • POST /eth/v1/beacon/states/{state_id}/validators
  • GET /eth/v1/beacon/states/{state_id}/validators/{validator_id}
  • GET /eth/v1/beacon/states/{state_id}/validator_balances
  • POST /eth/v1/beacon/states/{state_id}/validator_balances

Each affected endpoint also gains a 406 Not Acceptable response, matching the pattern used by other SSZ-enabled endpoints in the spec (debug/state.v2, pending_partial_withdrawals, validator_identities, etc.).

Validator status encoding

ValidatorResponse is wire-encoded as the SSZ container:

{ index: uint64, balance: uint64, status: byte, validator: Validator }

Validator is the consensus-spec object. status is a single byte. The byte mapping is documented in the ValidatorStatus schema and is the one proposed by @mcdee in #333:

Value Status
0x00 unknown
0x01 pending_initialized
0x02 pending_queued
0x03 active_ongoing
0x04 active_exiting
0x05 active_slashed
0x06 exited_unslashed
0x07 exited_slashed
0x08 withdrawal_possible
0x09 withdrawal_done

byte is used rather than uint8 per the discussion in #333 (cc @arnetheduck, @michaelsproul) to avoid implying the status is a numeric value with arithmetic semantics.

ValidatorBalanceResponse SSZ encoding is the simpler { index: uint64, balance: uint64 } container; no new type definitions are required.

What this PR does not change

  • Existing JSON responses are untouched. Clients that do not advertise application/octet-stream continue to receive the same JSON they get today.
  • No changes to request schemas, query parameters, or POST request bodies.
  • No new endpoints, no deprecations.
  • The existing ValidatorStatus JSON enum (active_ongoing, etc.) remains the canonical string form. The byte mapping is only relevant on the SSZ wire.

Lint

redocly lint beacon-node-oapi.yaml reports the same baseline of pre-existing warnings/errors before and after this patch (84 errors, 15 warnings, all unrelated to the touched files). No new lint findings are introduced.

Background and credits

The endpoint design, the choice of byte over uint8, and the status mapping all come from the discussion in #333. This PR is the implementation of that agreement; the credit for the design belongs to:

validator_balances was added because it shares the same indexer use case and avoids leaving an obviously asymmetric gap.

Related prior art that did not result in a merged spec change:

Closes #333.

Adds `application/octet-stream` (SSZ) response type to:
- `GET /eth/v1/beacon/states/{state_id}/validators`
- `POST /eth/v1/beacon/states/{state_id}/validators`
- `GET /eth/v1/beacon/states/{state_id}/validators/{validator_id}`
- `GET /eth/v1/beacon/states/{state_id}/validator_balances`
- `POST /eth/v1/beacon/states/{state_id}/validator_balances`

The validators response uses the SSZ container
`{ index: uint64, balance: uint64, status: byte, validator: Validator }`,
where `status` is encoded as a single `byte` per the table now documented in
the `ValidatorStatus` schema. Mapping follows the proposal in
ethereum#333 (0x01..0x09, with 0x00 reserved for unknown).

Adds 406 responses for unsupported `Accept` media types and a CHANGES.md
entry under the development version.

Closes ethereum#333.
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.

Support SSZ for validators endpoint

1 participant