Add SSZ response support for validator_balances endpoints#622
Merged
Conversation
lodekeeper
reviewed
Jun 30, 2026
lodekeeper
left a comment
There was a problem hiding this comment.
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]withValidatorBalanceResponse = {index: uint64, balance: uint64}is exactly what Lodestar has returned since #6749 (v1.20.0) —List[Container{index: ValidatorIndex, balance: UintNum64}], bothuint64. So indexers already get this wire format from Lodestar today. - Additive + backward-compatible as intended: JSON response unchanged, SSZ opt-in via
Accept, and the406 NotAcceptableon both GET and POST is correct (the$refresolves —beacon-node-oapi.yaml#/components/responses/NotAcceptable). - Matches house style — the
application/octet-streamdescription follows the sibling state-list endpoints (pending_consolidations,proposer_lookahead,pending_partial_withdrawals); the extra "EachValidatorBalanceResponseis 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!
Contributor
Author
|
Sure, will fix that soonish |
nflaig
reviewed
Jun 30, 2026
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.
d5e3564 to
ba68cc4
Compare
4 tasks
james-prysm
approved these changes
Jul 2, 2026
2 tasks
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an
application/octet-stream(SSZ) response toGETandPOST /eth/v1/beacon/states/{state_id}/validator_balances, selectable via theAcceptheader, plus a406 Not Acceptablematching the other SSZ-enabledstate 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 ispurely 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_balanceshas nostatusand no enum, so the SSZenum questions raised for the
validatorsendpoint do not apply here. Thevalidatorsside stays at status quo for now; this is the uncontroversialhalf.
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). AddingSSZ to an existing endpoint is backward compatible via
Acceptheader contentnegotiation.
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.yamlis valid andswagger-cli bundlesucceeds, 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.