Skip to content

fix(contract-sync): close reliability gaps in Soroban event indexer - #165

Merged
SudiptaPaul-31 merged 2 commits into
Lumina-eX:mainfrom
modecodes:157-blockchain-event-indexer
Jul 26, 2026
Merged

fix(contract-sync): close reliability gaps in Soroban event indexer#165
SudiptaPaul-31 merged 2 commits into
Lumina-eX:mainfrom
modecodes:157-blockchain-event-indexer

Conversation

@modecodes

Copy link
Copy Markdown
Contributor

Summary

The Soroban contract-sync pipeline (lib/contract-sync/) already existed and covered most of this issue's scope — a listener polling for on-chain events, a retry queue, an event-to-DB mapper, and an audit table (contract_sync_log). However, two of the acceptance criteria were not actually being met in practice, so this PR closes those gaps rather than rebuilding the indexer from scratch.

What was broken

  • Audit trail was incomplete on failure. Only the success path ever called updateSyncLog, so any event that failed and was retried — or exhausted its retries and went to the dead-letter queue — stayed stuck at status = 'pending' in contract_sync_log forever. Failures and retries were invisible in the audit trail.
  • A restart silently dropped events. The listener always resumed polling from the chain's current latest ledger on startup. Any event emitted while the service was down (deploy, crash, restart) was permanently skipped — never processed, never logged.
  • Redelivered events had no durable dedup. Deduplication only lived in the in-memory queue, so if the process restarted, the same event could be logged and reprocessed a second time.

What changed

  • lib/contract-sync/queue.ts — added onRetry / onDeadLetter hooks so every retry attempt and terminal failure is reported, not just successes.
  • lib/contract-sync/service.ts — wires those hooks to updateSyncLog, so contract_sync_log now accurately reflects failed and dead_letter states with the error message and retry count.
  • lib/contract-sync/listener.ts — added a persisted ledger checkpoint (initialLedger / setInitialLedger / onCheckpoint), so on restart polling resumes from where it left off instead of jumping to "now". The checkpoint only advances after the event callback is awaited, so a crash mid-processing can't advance past an event that was never durably logged.
  • lib/contract-sync/types.ts — added buildSyncDedupeKey, a single shared identity (txHash:event:milestoneId) used by both the in-memory queue and the audit table.
  • lib/db/migrations/007_contract_sync_durability.sql — adds dedupe_key (+ unique index) to contract_sync_log and a new contract_sync_checkpoint table.

Acceptance criteria

  • ✅ Event listening implemented — unchanged, already working.
  • ✅ Backend synchronization — unchanged, already working.
  • ✅ No duplicate processing — now enforced via dedupe_key + unique index, durable across restarts (previously only in-memory).
  • ✅ Error handling & retries — retries now actually recorded in the audit trail via onRetry / onDeadLetter (previously silently lost).
  • ✅ Audit trail maintained — contract_sync_log now reflects every outcome (success, failed, dead_letter), not just success.

Testing

Added/updated unit tests across __tests__/contract-sync/ (listener checkpoint behavior, queue retry/dead-letter hooks, and a new service.test.ts covering dedup + checkpoint persistence + failure logging). Full suite passes; no new lint or type errors introduced.

Closes #157

@drips-wave

drips-wave Bot commented Jul 25, 2026

Copy link
Copy Markdown

@modecodes 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

@SudiptaPaul-31
SudiptaPaul-31 merged commit 0ca02f4 into Lumina-eX:main Jul 26, 2026
1 check 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.

[Feature]: Blockchain Event Indexer

2 participants