Skip to content

exporter: bound slot ranges on trace/decideds endpoints (unbounded work + MaxUint64 wrap) #2986

Description

@momosh-ssv

Surfaced by Greptile on #2975 (#2975 (comment)), but the pattern is shared by every exporter range endpoint, so it deserves one consistent fix rather than a per-endpoint patch.

Problem

All exporter slot-range loops iterate inclusively with uint64 bounds and no range-size limit:

  • exporter/validator.go:51 (ValidatorTracesCore) and exporter/validator.go:240 (buildValidatorSchedule)
  • exporter/committee.go:26 and exporter/committee.go:95
  • exporter/decided.go:35

Two consequences:

  1. Unbounded work: a request with a huge [from, to] window performs one store read per slot (per role), with CPU/memory/response size growing linearly with the range. No validation rejects oversized windows.
  2. Non-termination: with to == math.MaxUint64, the inclusive condition s <= request.To is always true and s++ wraps, so the loop never terminates — a single request pins a goroutine forever.

The response-amplification half of the original finding (one note per post-fork slot) was fixed in #2975 by aggregating notes per role; the unbounded-range/overflow half is pre-existing and endpoint-wide, hence this issue.

Suggested fix

Add a shared range validation applied by all exporter query validators (validateValidatorRequest, committee/decideds equivalents):

  • reject to - from > maxSlotRange with a 400 (limit value to be agreed — needs a product/API-contract decision, e.g. a few epochs' worth of slots),
  • which also removes the MaxUint64 wrap case, since any to that survives validation leaves the loop finite.

Document the limit in the OpenAPI descriptions of the affected endpoints.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions