Skip to content

Add SSZ response support for validator_balances endpoints#622

Merged
nflaig merged 5 commits into
ethereum:masterfrom
migalabs:feat/ssz-validator-balances
Jul 3, 2026
Merged

Add SSZ response support for validator_balances endpoints#622
nflaig merged 5 commits into
ethereum:masterfrom
migalabs:feat/ssz-validator-balances

Conversation

@Zyra-V21

Copy link
Copy Markdown
Contributor

What

Adds an application/octet-stream (SSZ) response to GET and POST /eth/v1/beacon/states/{state_id}/validator_balances, selectable via the
Accept header, plus a 406 Not Acceptable matching the other SSZ-enabled
state endpoints (validator_identities, pending_partial_withdrawals).

The SSZ payload is List[ValidatorBalanceResponse, VALIDATOR_REGISTRY_LIMIT],
each entry being the container { index: uint64, balance: uint64 }. It is
purely additive: no JSON changes, no new parameters, JSON consumers are
untouched.

Context

Split out of #601 per the discussion there (cc @nflaig, @etan-status,
@lodekeeper). validator_balances has no status and no enum, so the SSZ
enum questions raised for the validators endpoint do not apply here. The
validators side stays at status quo for now; this is the uncontroversial
half.

Already shipping

This documents behavior clients already serve. Lodestar has returned SSZ on
this endpoint since ChainSafe/lodestar#6749 (v1.20.0, around two years), with
the same {index, balance} shape (confirmed by @lodekeeper in #601). Adding
SSZ to an existing endpoint is backward compatible via Accept header content
negotiation.

The concrete consumer is analytics/indexing: MigaLabs' goteth snapshots
balances per processed epoch and backfills large historical ranges, where the
JSON encode/parse cost on both ends is the bottleneck (gzip cuts wire size but
not that CPU). SSZ reduces both.

Validation

redocly lint ./beacon-node-oapi.yaml is valid and swagger-cli bundle
succeeds, matching the CI.

Tests

The spec is validated by lint + bundle rather than a test suite, so there is
no test harness to extend here. If you would like anything beyond that (an
example payload, or a client conformance check), say so and I will add it.

Related: #601, #333.

@lodekeeper lodekeeper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM from the Lodestar side — and I can confirm this matches what Lodestar already serves, so it's really just documenting existing behavior (which was the point of splitting it out of #601 👍).

  • SSZ schema matches Lodestar exactly. List[ValidatorBalanceResponse, VALIDATOR_REGISTRY_LIMIT] with ValidatorBalanceResponse = {index: uint64, balance: uint64} is exactly what Lodestar has returned since #6749 (v1.20.0) — List[Container{index: ValidatorIndex, balance: UintNum64}], both uint64. So indexers already get this wire format from Lodestar today.
  • Additive + backward-compatible as intended: JSON response unchanged, SSZ opt-in via Accept, and the 406 NotAcceptable on both GET and POST is correct (the $ref resolves — beacon-node-oapi.yaml#/components/responses/NotAcceptable).
  • Matches house style — the application/octet-stream description follows the sibling state-list endpoints (pending_consolidations, proposer_lookahead, pending_partial_withdrawals); the extra "Each ValidatorBalanceResponse is the SSZ container {index, balance}" line is a helpful clarification since the JSON schema uses string-encoded uints.

One minor nit (non-blocking): the two new CHANGES.md rows are missing the [#622](https://github.com/ethereum/beacon-APIs/pull/622) PR-link prefix that every other row in that table carries — worth adding for consistency.

Thanks for splitting this out!

@Zyra-V21

Copy link
Copy Markdown
Contributor Author

Sure, will fix that soonish

Comment thread CHANGES.md Outdated
Comment thread apis/beacon/states/validator_balances.yaml Outdated
Zyra-V21 added 4 commits July 2, 2026 09:36
Document an application/octet-stream response for
GET /eth/v1/beacon/states/{state_id}/validator_balances, selectable
via the Accept header. The SSZ payload is
List[Container{index: uint64, balance: uint64}, VALIDATOR_REGISTRY_LIMIT].

Purely additive: JSON consumers are unaffected by content negotiation.
Match the convention used by other SSZ-enabled state endpoints
(validator_identities, pending_partial_withdrawals): return 406 when
the client requests an unsupported representation via Accept.
Mirror the GET endpoint: document an application/octet-stream response
for POST /eth/v1/beacon/states/{state_id}/validator_balances with the
same List[Container{index: uint64, balance: uint64}, VALIDATOR_REGISTRY_LIMIT]
encoding, keeping the GET and POST variants consistent.
Complete content negotiation on the POST variant to match GET.
@Zyra-V21 Zyra-V21 force-pushed the feat/ssz-validator-balances branch from d5e3564 to ba68cc4 Compare July 2, 2026 07:37

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks @Zyra-V21 for working on this, it's long overdue to add this to the spec, we've already implemented ssz response for this endpoint ~2 years ago.

@rolfyone rolfyone 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.

LGTM

pull Bot pushed a commit to All-Blockchains/prysm that referenced this pull request Jul 3, 2026
…oint (OffchainLabs#17077)

**What type of PR is this?**

> Feature

**What does this PR do? Why is it needed?**

Implements ethereum/beacon-APIs#622.

**Which issue(s) does this PR fix?**

N/A

**Other notes for review**

Mirrors `validator_identities` endpoint.

**Acknowledgements**

- [x] I have read
[CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md).
- [x] I have included a uniquely named [changelog fragment
file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd).
- [x] I have added a description with sufficient context for reviewers
to understand this PR.
- [x] I have tested that my changes work as expected and I added a
testing plan to the PR description (if applicable).
@nflaig nflaig merged commit 6a52d29 into ethereum:master Jul 3, 2026
3 checks passed
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.

5 participants