Skip to content

feat(indexer): rewind cursor and prune dropped ledgers during chain reorgs - #1064

Merged
p3ris0n merged 6 commits into
BCPathway:mainfrom
Ayfataan:feature/947-indexer-reorg
Sep 29, 2026
Merged

p3ris0n merged 6 commits into
BCPathway:mainfrom
Ayfataan:feature/947-indexer-reorg

Conversation

@Ayfataan

Copy link
Copy Markdown
Contributor

Summary

  • Extend the persistent indexer cursor with the latest ledger hash and parent hash, and add per-ledger hash checkpoints for a rolling 1,000-ledger verification window.
  • Fetch and validate ledger sequences and parent hashes before processing each bounded event range.
  • Reconcile persisted coordinates against Stellar RPC ledger headers on startup and before each ingestion range.
  • On a missing sequence, hash mismatch, or parent-hash mismatch, rewind to the latest common verified checkpoint.
  • In one Prisma transaction, delete mint, burn, transfer, and checkpoint rows above the rewind ledger and update the singleton cursor.
  • Seed recent verified checkpoints for existing cursors without stored hashes so existing deployments can establish a baseline after applying the migration.
  • Keep txHash uniqueness intact and tolerate Prisma duplicate-key errors during replay.
  • Add a Prisma migration, fake-RPC fork and continuity tests, simulated persisted-row pruning assertions, and event replay idempotency coverage.

Validation

  • Focused reorg tests: 4 passed, covering common-checkpoint rewind, parent mismatch, sequence/parent continuity, pruning in all indexed tables, and duplicate txHash replay.
  • Full indexer suite: 47 tests passed.
  • Indexer TypeScript build: passed.
  • Prisma schema validation with a placeholder DATABASE_URL: passed.
  • git diff --check: passed.

Operational note

Apply the new Prisma migration before deploying this branch. Existing rows retain their current txHash uniqueness constraints. A legacy cursor is initialized with verified coordinates from the active RPC ledger history on startup.

Closes #947

@drips-wave

drips-wave Bot commented Sep 28, 2026

Copy link
Copy Markdown

@Ayfataan Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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

Review

The design matches #947: ledger hash checkpoints, rewind to the last common checkpoint, deletion of mint/burn/transfer/checkpoint rows above that ledger, and txHash uniqueness for replay. I am not merging it.

Indexer CI failed. replaying an event after rewind does not duplicate its unique txHash row dies in a hook before the assertion:

@prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.

indexer/src/indexer.ts constructs PrismaClient at import time, and indexer.reorg.test.ts imports that module. The new migration/schema is not generated in the test job before that import. The other 46 indexer tests passed. Please generate the client in CI (or stop constructing Prisma at module scope in the test) and re-run the rewind replay test.

Holding merge until Indexer is green. The branch is otherwise mergeable.

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

Review

The reorg design still matches #947, and Indexer CI is green. I am not merging it.

reconcileLedgerCursor in indexer/src/cursor.ts rewinds to the last common checkpoint and deletes mint, burn, transfer, and indexedLedger rows above that ledger. Replay still relies on the unique txHash constraint (P2002 is ignored in processEvent). That is the behavior the issue asks for.

The tests that prove it are not executed. indexer/package.json test lists the older files only. It does not include src/cursor.test.ts or src/indexer.reorg.test.ts. The previous failure (@prisma/client did not initialize yet) is gone because that test never runs. A green Indexer job does not cover the rewind or the replay assertion.

Please add both files to the test script (and run prisma generate before them if the client is still constructed at import time), and re-run until replaying an event after rewind does not duplicate its unique txHash row passes in CI.

Holding merge until those tests are part of the Indexer job.

p3ris0n and others added 2 commits September 29, 2026 13:53
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
p3ris0n
p3ris0n previously approved these changes Sep 29, 2026

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

Review

Reorg and cursor tests are in the indexer test script, prisma generate runs first, and the merge keeps holder aggregates. Approving once CI is green.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

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

Review

This covers #947.

reconcileLedgerCursor compares stored ledger hashes with RPC and rewinds LastIndexedLedger to the last common checkpoint. The same transaction deletes mint, burn, transfer, and IndexedLedger rows above that ledger. Replay stays idempotent on the unique txHash constraint. indexer/package.json runs prisma generate and then src/cursor.test.ts and src/indexer.reorg.test.ts, so the rewind and the non-duplicate replay assertion are part of the Indexer job.

CI is green and the branch merges cleanly. Approving and merging.

@p3ris0n
p3ris0n merged commit d2d4ed0 into BCPathway:main Sep 29, 2026
10 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.

Rewind the indexer cursor when a ledger reorgs

2 participants