Skip to content

feat(ensindexer): per-chain eth_getLogs block range via ETH_GET_LOGS_BLOCK_RANGE_<chainId>#2222

Open
Quantumlyy wants to merge 12 commits into
namehash:mainfrom
Quantumlyy:Quantumlyy/per-chain-getlogs-block-range
Open

feat(ensindexer): per-chain eth_getLogs block range via ETH_GET_LOGS_BLOCK_RANGE_<chainId>#2222
Quantumlyy wants to merge 12 commits into
namehash:mainfrom
Quantumlyy:Quantumlyy/per-chain-getlogs-block-range

Conversation

@Quantumlyy
Copy link
Copy Markdown

@Quantumlyy Quantumlyy commented May 29, 2026

Summary

  • Adds tunable caps on Ponder's eth_getLogs block range, configured via environment variables:
    • ETH_GET_LOGS_BLOCK_RANGE sets a default applied to every chain.
    • ETH_GET_LOGS_BLOCK_RANGE_<chainId> overrides that default for a specific chain (analogous to RPC_URL_<chainId>).
    • ETH_GET_LOGS_BLOCK_RANGE_<chainId>=0 disables the cap for that chain so Ponder auto-determines its range; ETH_GET_LOGS_BLOCK_RANGE=0 is equivalent to unset.
  • Resolves into the per-chain Ponder chains config; chains without an effective cap keep Ponder's default behavior.
  • Documented in .env.local.example (embedded in the configuration docs) and the docker env example; changeset included.

Why

  • Some RPC providers reject Ponder's default eth_getLogs block range, which can stall indexing for a chain. ENSIndexer had no way to cap it; this adds a global default plus per-chain overrides (and a per-chain opt-out) without affecting other chains.
  • EthID

Testing

  • pnpm -F ensindexer typecheck, pnpm lint:ci, and pnpm generate (no drift) pass; the ensindexer test suite is green.
  • New tests cover the builder + schema (global default, per-chain override precedence, 0 disable), env→config resolution (config.test.ts), and chainsConnectionConfig asserting the option is absent when unset/disabled and present when configured (ponder-helpers.test.ts).

Notes for Reviewer (Optional)

  • No re-index on change. Verified against ponder@0.16.6 that the Build ID hashes only {ordering, contracts, accounts, blocks} and excludes config.chains, so these behave exactly like RPC_URL (changing them never forces a re-index). They are deliberately kept out of IndexingBehaviorInjectionContract, which injects into the hashed config.contracts.
  • Kept ENSIndexer-local, not on the shared SDK RpcConfig. RpcConfig / RpcEnvironment / buildRpcConfigsFromEnv are shared with ENSApi (which runs no Ponder), so the knob lives in a new app-local EthGetLogsBlockRangeEnvironment + ethGetLogsBlockRanges config field. No SDK / public-config / OpenAPI change.
  • The global default and 0 disable are resolved at config-build time into the effective per-chain ethGetLogsBlockRanges map, so the chainsConnectionConfig wiring stays a simple per-chain lookup.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Add an ENSIndexer-local mechanism, parallel to RPC_URL_<chainId>, that parses
optional per-chain ETH_GET_LOGS_BLOCK_RANGE_<chainId> environment variables into
config.ethGetLogsBlockRanges (Map<ChainId, number>), validated as positive
integers and surfaced in the redacted config serialization.

Kept separate from the shared SDK RpcConfig (used by ENSApi, which runs no
Ponder). Not yet consumed by the Ponder config; that follows in a later commit.
Thread config.ethGetLogsBlockRanges into the Ponder chains config. The two
chain-config helpers now take an EnsIndexerConfig slice instead of just
rpcConfigs, and chainsConnectionConfig sets chains[id].ethGetLogsBlockRange only
when an override is configured (otherwise Ponder auto-determines the range).

Because Ponder's Build ID excludes config.chains, configuring a block range does
not change the Build ID and does not trigger a re-index, just like RPC_URL.
Document the per-chain ETH_GET_LOGS_BLOCK_RANGE_<chainId> override in
.env.local.example (embedded into the configuration docs) and the docker env
example, and add a changeset.
Copilot AI review requested due to automatic review settings May 29, 2026 14:49
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 29, 2026

🦋 Changeset detected

Latest commit: 35a373c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
ensindexer Minor
ensadmin Minor
ensrainbow Minor
ensapi Minor
fallback-ensapi Minor
enssdk Minor
enscli Minor
enskit Minor
ensskills Minor
@ensnode/datasources Minor
@ensnode/ensrainbow-sdk Minor
@ensnode/ensdb-sdk Minor
@ensnode/ensnode-sdk Minor
@ensnode/integration-test-env Minor
@ensnode/ponder-sdk Minor
@ensnode/ponder-subgraph Minor
@ensnode/shared-configs Minor
@docs/ensnode Minor
@docs/ensrainbow Minor
@namehash/ens-referrals Minor
@namehash/namehash-ui Minor
@ensnode/ensindexer-perf-testing Minor
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 29, 2026

@Quantumlyy is attempting to deploy a commit to the NameHash Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds per-chain ETH_GET_LOGS_BLOCK_RANGE_${chainId} environment overrides for Ponder’s eth_getLogs block range, with environment parsing, validation, config-schema integration, serialization, Ponder helper wiring, plugin updates, tests, and documentation.

Changes

Per-chain eth_getLogs block range overrides

Layer / File(s) Summary
Configuration types and environment interface
apps/ensindexer/src/config/types.ts, apps/ensindexer/src/config/environment.ts
EthGetLogsBlockRanges type (Map<ChainId, number>) added to EnsIndexerConfig; EthGetLogsBlockRangeEnvironment added to define ETH_GET_LOGS_BLOCK_RANGE and ETH_GET_LOGS_BLOCK_RANGE_${number} env keys; ENSIndexerEnvironment extended.
Building and validating from environment
apps/ensindexer/src/config/eth-get-logs-block-ranges.ts, apps/ensindexer/src/config/eth-get-logs-block-ranges.test.ts
buildEthGetLogsBlockRangesFromEnv extracts per-chain/global env values scoped to a namespace; EthGetLogsBlockRangesSchema coerces/validates non-negative integers, omits 0 entries, and transforms to Map<ChainId, number>; tests cover namespace filtering, defaults, overrides, disable sentinel, and validation errors.
Configuration schema and parsing
apps/ensindexer/src/config/config.schema.ts, apps/ensindexer/src/config/config.test.ts
ENSIndexerConfigSchema extended to validate ethGetLogsBlockRanges; buildConfigFromEnvironment now builds and includes block ranges from env; config tests added for parsing and validation.
Serialization of block ranges
apps/ensindexer/src/config/serialize.ts, apps/ensindexer/src/config/serialized-types.ts
serializeEthGetLogsBlockRanges converts the Map into a Record<ChainIdString, number> using serializeChainId; SerializedENSIndexerConfig updated to include the serialized ethGetLogsBlockRanges.
Ponder helpers integration
apps/ensindexer/src/lib/ponder-helpers.ts, apps/ensindexer/src/lib/ponder-helpers.test.ts
chainsConnectionConfig and chainsConnectionConfigForDatasources refactored to accept a config slice including ethGetLogsBlockRanges and to conditionally inject ethGetLogsBlockRange into chain configs; tests verify conditional inclusion.
Plugin wiring updates
apps/ensindexer/src/plugins/...
All plugins updated to call chainsConnectionConfig/chainsConnectionConfigForDatasources with the full config object instead of separate namespace and rpcConfigs args so ethGetLogsBlockRanges is available.
Documentation and environment examples
.changeset/eth-getlogs-block-range.md, apps/ensindexer/.env.local.example, docker/envs/.env.docker.example
Adds changeset documenting per-chain ETH_GET_LOGS_BLOCK_RANGE_${chainId} behavior, documents env var semantics and no-reindex note in .env.local.example, and adds Docker example placeholders.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • namehash/ensnode#2036: Modifies chainsConnectionConfig logic; overlaps at the same helper function level.
  • namehash/ensnode#1766: Touches buildConfigFromEnvironment/Zod parsing pipeline; related changes to config parsing.

🐰 I tuned the logs, chain by chain, with care,
Env vars whisper limits into Ponder's air,
Zero skips the cap, defaults softly apply,
Tests and docs hopped in, now watchers fly. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main feature: per-chain eth_getLogs block range configuration via environment variable overrides.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the required template with all key sections completed: Summary, Why, Testing, Notes for Reviewer, and Pre-Review Checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Quantumlyy Quantumlyy marked this pull request as ready for review May 29, 2026 18:13
@Quantumlyy Quantumlyy requested a review from a team as a code owner May 29, 2026 18:13
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 29, 2026

Greptile Summary

Adds per-chain and global eth_getLogs block range caps to ENSIndexer, configured via ETH_GET_LOGS_BLOCK_RANGE and ETH_GET_LOGS_BLOCK_RANGE_<chainId> environment variables, following the same scoping pattern as RPC_URL_<chainId>. A chain-level 0 disables the cap for that chain while retaining any global default for others.

  • New eth-get-logs-block-ranges module: buildEthGetLogsBlockRangesFromEnv collects raw string values scoped to namespace chains; EthGetLogsBlockRangesSchema coerces them to integers, filters out the 0 disable-sentinel, and produces a Map<ChainId, number> that feeds into the Ponder chain config.
  • chainsConnectionConfig refactor: The function now accepts a Pick<ENSIndexerConfig, "rpcConfigs" | "ethGetLogsBlockRanges"> slice instead of just rpcConfigs, and spreads ethGetLogsBlockRange into the Ponder chain config only when explicitly configured; the prior Object.keys(Map) bug in the error message is also corrected in this change.
  • Call-site updates: All plugin files and chainsConnectionConfigForDatasources are updated to pass the new config slice; serialization and the serialized type are extended to cover ethGetLogsBlockRanges.

Confidence Score: 5/5

Safe to merge — the change is purely additive, excluded from Ponder's build ID so it cannot trigger a re-index, and fully isolated to ENSIndexer.

The env-to-config pipeline is well-tested (builder, schema, config integration, and Ponder chain config wiring each have dedicated tests). The "0" disable sentinel works correctly because "0" is a truthy string in JavaScript, preserving it through the || undefined normalization before the schema coerces it to integer 0 and filters it out. No data-affecting behavior is changed.

No files require special attention.

Important Files Changed

Filename Overview
apps/ensindexer/src/config/eth-get-logs-block-ranges.ts New module implementing env-to-config pipeline for eth_getLogs block range overrides; logic is correct, "0" string is truthy so the disable sentinel works as documented
apps/ensindexer/src/lib/ponder-helpers.ts Refactors chainsConnectionConfig / chainsConnectionConfigForDatasources to accept a config slice; fixes the prior Object.keys(Map) bug in the error message and correctly wires ethGetLogsBlockRange into Ponder chain config
apps/ensindexer/src/config/config.schema.ts Integrates buildEthGetLogsBlockRangesFromEnv and EthGetLogsBlockRangesSchema into the main config-build flow; changes are minimal and follow existing RPC config pattern
apps/ensindexer/src/config/types.ts Adds EthGetLogsBlockRanges type and ethGetLogsBlockRanges field to EnsIndexerConfig; type definition and invariant documentation are consistent with implementation
apps/ensindexer/src/config/environment.ts Adds EthGetLogsBlockRangeEnvironment interface with correct template-literal index signature for per-chain env vars
apps/ensindexer/src/config/eth-get-logs-block-ranges.test.ts New test suite with good coverage of the builder (namespace scoping, global default, per-chain override precedence, 0 sentinel) and schema (parse, transform, validation failures)
apps/ensindexer/src/lib/ponder-helpers.test.ts Adds tests for chainsConnectionConfig covering the absent-when-unset and present-when-configured cases for ethGetLogsBlockRange
apps/ensindexer/src/config/serialized-types.ts Adds ethGetLogsBlockRanges to the serialized config interface with correct Record<ChainIdString, number> shape
apps/ensindexer/src/config/serialize.ts Adds serializeEthGetLogsBlockRanges to convert the Map to a plain record; straightforward iteration over Map entries

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    ENV["Process Environment"] --> GLOBAL["ETH_GET_LOGS_BLOCK_RANGE\n(global default)"]
    ENV --> CHAIN["ETH_GET_LOGS_BLOCK_RANGE_chainId\n(per-chain override)"]

    GLOBAL & CHAIN --> BUILD["buildEthGetLogsBlockRangesFromEnv(env, namespace)"]

    BUILD --> SCOPE{"Chain in\nnamespace?"}
    SCOPE -- "No" --> SKIP["Ignored"]
    SCOPE -- "Yes" --> RESOLVE{"Per-chain\nvar set?"}
    RESOLVE -- "Yes (including 0)" --> USE_CHAIN["Use chain-specific value"]
    RESOLVE -- "No" --> USE_DEFAULT["Use global default\n(if set)"]
    USE_CHAIN & USE_DEFAULT --> RAW["Record ChainIdString string"]

    RAW --> SCHEMA["EthGetLogsBlockRangesSchema\n(zod parse + transform)"]
    SCHEMA --> VALIDATE{"Value > 0?"}
    VALIDATE -- "Yes" --> MAP["Map.set(chainId, blockRange)"]
    VALIDATE -- "No (0 = disable)" --> DROP["Omit - Ponder\nauto-determines"]

    MAP --> RESULT["Map ChainId number\nethGetLogsBlockRanges"]

    RESULT --> PONDER["chainsConnectionConfig()"]
    PONDER --> PONDER_CFG["Ponder Config chains"]
Loading

Reviews (7): Last reviewed commit: "Merge branch 'main' into Quantumlyy/per-..." | Re-trigger Greptile

Comment thread apps/ensindexer/src/lib/ponder-helpers.ts Outdated
Quantumlyy and others added 4 commits May 29, 2026 20:50
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Add a global ETH_GET_LOGS_BLOCK_RANGE applied to every chain, with each
ETH_GET_LOGS_BLOCK_RANGE_<chainId> overriding it per chain and a value of 0
disabling the override for that chain (so Ponder auto-determines its range).
ETH_GET_LOGS_BLOCK_RANGE=0 is equivalent to unset.

Values resolve into the existing per-chain effective map, so the Ponder chains
wiring is unchanged.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ensindexer/.env.local.example`:
- Around line 117-123: The documentation is contradictory about allowed values
for ETH_GET_LOGS_BLOCK_RANGE: change the wording to state that
ETH_GET_LOGS_BLOCK_RANGE and ETH_GET_LOGS_BLOCK_RANGE_${chainId} accept a
non-negative integer (0 included), and clarify that 0 disables the override so
Ponder auto-determines the range; also state that ETH_GET_LOGS_BLOCK_RANGE=0 is
equivalent to leaving it unset.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dee74bdf-27af-4bf0-9df1-6eab36032e0d

📥 Commits

Reviewing files that changed from the base of the PR and between d651ca4 and a6ba5b9.

📒 Files selected for processing (8)
  • .changeset/eth-getlogs-block-range.md
  • apps/ensindexer/.env.local.example
  • apps/ensindexer/src/config/config.test.ts
  • apps/ensindexer/src/config/environment.ts
  • apps/ensindexer/src/config/eth-get-logs-block-ranges.test.ts
  • apps/ensindexer/src/config/eth-get-logs-block-ranges.ts
  • apps/ensindexer/src/config/types.ts
  • docker/envs/.env.docker.example

Comment thread apps/ensindexer/.env.local.example Outdated
Quantumlyy and others added 2 commits May 30, 2026 20:28
The value-type line said "positive integer", which contradicted the documented
0-disables behavior. State that the value is a non-negative integer (0 included)
and that 0 disables the override so Ponder auto-determines the range.
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