Conversation
…ct` config into Ponder Config
|
The latest updates on your projects. Learn more about Vercel for GitHub. 3 Skipped Deployments
|
|
📝 WalkthroughWalkthroughThe PR refactors how indexing behavior dependencies feed into Ponder's build-id generation. Instead of directly modifying a config object property, it establishes a contracts-based injection mechanism that consolidates configuration parameters and database schema checksums into a deterministic input for Ponder's build process. Changes
Sequence DiagramsequenceDiagram
participant Ponder Config
participant buildInjectionContracts as buildIndexingBehaviorInjectionContracts()
participant EnsDbReader
participant Drizzle
Ponder Config->>buildInjectionContracts: Call with config & ensDbClient
buildInjectionContracts->>EnsDbReader: Read ensDbSchemaChecksum
EnsDbReader->>Drizzle: getDrizzleSchemaChecksum(merged schema)
Drizzle->>Drizzle: Safely stringify schema<br/>(handle circular refs)
Drizzle->>Drizzle: SHA-256 hash & truncate
Drizzle-->>EnsDbReader: Return checksum
EnsDbReader-->>buildInjectionContracts: Checksum value
buildInjectionContracts->>buildInjectionContracts: Embed checksum into<br/>indexingBehaviorDependencies
buildInjectionContracts-->>Ponder Config: Return contracts-like mapping
Ponder Config->>Ponder Config: Merge into ponderConfig.contracts
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
This PR updates how ENSIndexer influences Ponder’s build ID by introducing a schema checksum for the ENSDb Drizzle schema and injecting indexing-behavior dependencies into the Ponder contracts config.
Changes:
- Add a Drizzle schema checksum utility (
getDrizzleSchemaChecksum) to the ENSDb SDK. - Expose the checksum via
EnsDbReader.ensDbSchemaChecksum. - Replace the previous top-level
indexingBehaviorDependenciesinjection with a special “injection contract” added toponderConfig.contracts.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/ensdb-sdk/src/lib/drizzle.ts | Adds schema-safe stringification + schema checksum hashing utility. |
| packages/ensdb-sdk/src/client/ensdb-reader.ts | Exposes the schema checksum via a new getter on EnsDbReader. |
| apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts | Introduces a synthetic contract config containing indexing-behavior dependencies (including schema checksum). |
| apps/ensindexer/src/ponder/config.ts | Injects the synthetic contract into ponderConfig.contracts so it affects Ponder build ID generation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function buildIndexingBehaviorInjectionContracts() { | ||
| return { | ||
| IndexingBehaviorInjectionContract: { | ||
| chain: `${rootChainId}`, | ||
| indexingBehaviorDependencies, | ||
| }, |
There was a problem hiding this comment.
buildIndexingBehaviorInjectionContracts() adds an entry under ponderConfig.contracts, but the returned object doesn’t match the contract config shape used throughout the codebase (e.g. plugins always provide abi and a chain object keyed by chainId via chainConfigForContract(...)). With the current { chain: "${rootChainId}", indexingBehaviorDependencies }, Ponder config validation/typechecking is likely to fail at runtime or silently ignore the entry for build-id purposes.
Suggestion: make this a valid minimal contract config (include abi and use a chain mapping like { [rootChainId.toString()]: { address, startBlock, endBlock } }), and ensure the chosen blockrange/address won’t cause unnecessary indexing work.
| get ensDbSchemaChecksum(): string { | ||
| return getDrizzleSchemaChecksum({ | ||
| ...this._concreteEnsIndexerSchema, | ||
| ...this._ensNodeSchema, | ||
| }); | ||
| } |
There was a problem hiding this comment.
ensDbSchemaChecksum recomputes a full schema stringify + SHA-256 hash on every access. This can be relatively expensive given the size of the Drizzle schema objects.
Suggestion: compute once (e.g., in the constructor) or memoize the getter in a private field so repeated accesses don’t repeatedly hash the same data.
| export function getDrizzleSchemaChecksum(schema: Record<string, unknown>): string { | ||
| const stringifiedSchema = safeStringifyDrizzleSchema(schema); | ||
|
|
||
| return createHash("sha256").update(stringifiedSchema).digest("hex").slice(0, 10); | ||
| } |
There was a problem hiding this comment.
getDrizzleSchemaChecksum() is new exported behavior that will influence indexing build IDs, but there are no tests covering checksum determinism and that schema objects with circular references won’t throw.
Suggestion: add Vitest coverage in packages/ensdb-sdk/src/lib/drizzle.test.ts to assert (1) stable checksum for the same schema input and (2) no throw + stable output when circular references exist (and ideally that a meaningful schema change alters the checksum).
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts`:
- Around line 53-60: The current code uses module-level constants
indexingBehaviorDependencies and rootChainId which are evaluated at import time,
so change buildIndexingBehaviorInjectionContracts() to compute or fetch those
values inside the function instead of relying on the module-level variables:
move the logic that derives indexingBehaviorDependencies and rootChainId into
the body of buildIndexingBehaviorInjectionContracts (or call the functions that
return them) so the values are evaluated at call time; update references inside
the function to use the locally computed variables and leave the exported
function signature (buildIndexingBehaviorInjectionContracts) unchanged.
In `@packages/ensdb-sdk/src/lib/drizzle.ts`:
- Around line 188-199: The safeStringifyDrizzleSchema function can produce
non-deterministic output because JSON.stringify uses native key enumeration
order; modify safeStringifyDrizzleSchema to produce deterministic serialization
by sorting object keys before serializing while preserving arrays and the
existing circular-reference handling: in the replacer used by JSON.stringify
(inside safeStringifyDrizzleSchema) detect plain objects (not arrays), collect
and sort Object.keys(value) and build a new object with keys in sorted order (or
return a sorted-key representation) so the same schema yields identical strings
across environments; keep the WeakSet circular detection logic unchanged so
circular references still produce "[circular]".
🪄 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: 7315e0d0-5fd1-45ad-a7fc-6a473166ec0d
📒 Files selected for processing (4)
apps/ensindexer/src/ponder/config.tsapps/ensindexer/src/ponder/indexing-behavior-injection-contract.tspackages/ensdb-sdk/src/client/ensdb-reader.tspackages/ensdb-sdk/src/lib/drizzle.ts
| export function buildIndexingBehaviorInjectionContracts() { | ||
| return { | ||
| IndexingBehaviorInjectionContract: { | ||
| chain: `${rootChainId}`, | ||
| indexingBehaviorDependencies, | ||
| }, | ||
| } as const; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Module-level initialization occurs at import time.
The indexingBehaviorDependencies and rootChainId constants are evaluated when this module is first imported, not when buildIndexingBehaviorInjectionContracts() is called. This is fine for the current use case where config and ensDbClient are singleton modules that initialize synchronously. Just be aware that any import-time failures in those dependencies would surface here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts` around
lines 53 - 60, The current code uses module-level constants
indexingBehaviorDependencies and rootChainId which are evaluated at import time,
so change buildIndexingBehaviorInjectionContracts() to compute or fetch those
values inside the function instead of relying on the module-level variables:
move the logic that derives indexingBehaviorDependencies and rootChainId into
the body of buildIndexingBehaviorInjectionContracts (or call the functions that
return them) so the values are evaluated at call time; update references inside
the function to use the locally computed variables and leave the exported
function signature (buildIndexingBehaviorInjectionContracts) unchanged.
| function safeStringifyDrizzleSchema(schema: Record<string, unknown>): string { | ||
| const seen = new WeakSet(); | ||
|
|
||
| return JSON.stringify(schema, (_key, value) => { | ||
| if (typeof value === "object" && value !== null) { | ||
| if (seen.has(value)) return "[circular]"; | ||
| seen.add(value); | ||
| } | ||
|
|
||
| return value; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Non-deterministic key ordering may cause inconsistent checksums.
JSON.stringify does not guarantee consistent key ordering across different object instantiation orders or JavaScript engines. If the schema object's keys are enumerated in a different order (e.g., due to how Drizzle constructs the schema internally), the resulting checksum could differ for semantically identical schemas, potentially causing unexpected Ponder build-id changes.
Consider sorting keys during serialization for deterministic output:
🔧 Proposed fix for deterministic serialization
function safeStringifyDrizzleSchema(schema: Record<string, unknown>): string {
const seen = new WeakSet();
- return JSON.stringify(schema, (_key, value) => {
+ return JSON.stringify(schema, (_key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) return "[circular]";
seen.add(value);
+ // Sort object keys for deterministic output
+ if (!Array.isArray(value)) {
+ const sorted: Record<string, unknown> = {};
+ for (const k of Object.keys(value).sort()) {
+ sorted[k] = (value as Record<string, unknown>)[k];
+ }
+ return sorted;
+ }
}
return value;
});
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/ensdb-sdk/src/lib/drizzle.ts` around lines 188 - 199, The
safeStringifyDrizzleSchema function can produce non-deterministic output because
JSON.stringify uses native key enumeration order; modify
safeStringifyDrizzleSchema to produce deterministic serialization by sorting
object keys before serializing while preserving arrays and the existing
circular-reference handling: in the replacer used by JSON.stringify (inside
safeStringifyDrizzleSchema) detect plain objects (not arrays), collect and sort
Object.keys(value) and build a new object with keys in sorted order (or return a
sorted-key representation) so the same schema yields identical strings across
environments; keep the WeakSet circular detection logic unchanged so circular
references still produce "[circular]".
| export function buildIndexingBehaviorInjectionContracts() { | ||
| return { | ||
| IndexingBehaviorInjectionContract: { | ||
| chain: `${rootChainId}`, |
There was a problem hiding this comment.
| chain: `${rootChainId}`, | |
| chain: { | |
| [rootChainId.toString()]: { | |
| address: "0x0000000000000000000000000000000000000000", | |
| startBlock: 0, | |
| endBlock: 0, | |
| }, | |
| }, |
The IndexingBehaviorInjectionContract has an invalid chain property structure - it's a string instead of an object mapping chain IDs to configuration objects
Lite PR
Tip: Review docs on the ENSNode PR process
Summary
Why
Testing
Notes for Reviewer (Optional)
Pre-Review Checklist (Blocking)