Skip to content

fix(audit): token_transfers unique constraint + raise orphan log to warn#47

Merged
satyakwok merged 1 commit into
mainfrom
fix/audit-medium-batch
May 21, 2026
Merged

fix(audit): token_transfers unique constraint + raise orphan log to warn#47
satyakwok merged 1 commit into
mainfrom
fix/audit-medium-batch

Conversation

@satyakwok
Copy link
Copy Markdown
Member

@satyakwok satyakwok commented May 21, 2026

Two audit follow-ups against the ERC-20 handler PR (#46) from internal bridge security audit.

Changes

M-3: token_transfers unique constraint

  • New migration 0003_token_transfers_unique.sql adds transfers_tx_log_unique_idx after deduping any existing duplicates (no-op on clean chains).
  • insert_batch re-enables ON CONFLICT (tx_hash, log_index) DO NOTHING so reorg / forensic-rerun replays stay idempotent at the DB layer.

M-5: raise orphan-log filter from debug to warn

The drop-orphan-logs path (added in #46) was silent at default log level. Sustained high-volume drops signal a real chain-side data inconsistency, so promote to warn! for visibility without changing log config.

Test plan

  • cargo check clean on indexer-sync + indexer-db
  • Migration is replay-safe (DELETE dedup runs before CREATE INDEX)
  • Apply migration to testnet pg, confirm no error
  • Trigger a reorg in test env, confirm no duplicate rows

Summary by CodeRabbit

  • Bug Fixes

    • Prevented duplicate token transfer records from being stored through database-level constraints.
    • Improved handling of blockchain reorganizations to prevent duplicate data insertion.
  • Chores

    • Enhanced diagnostic logging for orphan transaction detection to better identify chain inconsistencies.

Review Change Stack

Two audit follow-ups against the ERC-20 handler PR (#46):

## M-3: token_transfers unique constraint

`token_transfers` had only `PRIMARY KEY (id)` when shipped. On reorg
recovery + replay, the same `(tx_hash, log_index)` rows would re-insert
without a uniqueness gate, producing duplicate transfer rows that
double-count balances downstream. The atomic cursor advance in the
steady-state writer prevented this in practice, but reorg / forensic-
rerun paths bypass that protection.

- New migration `0003_token_transfers_unique.sql` adds
  `transfers_tx_log_unique_idx` after deduping any existing duplicates.
- `insert_batch` re-enabled `ON CONFLICT (tx_hash, log_index) DO NOTHING`
  so replay is now idempotent at the DB layer in addition to the
  cursor-based writer guard.

The DELETE in the migration is a no-op for chains that have only run
the indexer post-#46 (no duplicates accumulated); kept in place to
keep the migration replay-safe on chains that did.

## M-5: raise orphan-log filter to warn

`fetch_one` / `ingest_one` drop logs whose tx_hash isn't backed by a
tx row in the same bundle (added in #46 to work around a Sentrix-side
data inconsistency where reverted-tx log envelopes still come back
from `eth_getLogs`). Original commit logged at `debug!`, which is
silent at default log level. Sustained high-volume drops here signal
a real chain bug worth investigating, so promote to `warn!` to make
the gap visible without changing logging config.

Verified locally: no compile changes, existing tests pass.
@satyakwok satyakwok merged commit ab9e05d into main May 21, 2026
7 of 8 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9c5b704f-3908-4889-bce0-24b41ba90528

📥 Commits

Reviewing files that changed from the base of the PR and between 2214b7a and 8bc4006.

📒 Files selected for processing (3)
  • crates/db/migrations/0003_token_transfers_unique.sql
  • crates/db/src/token_transfers.rs
  • crates/sync/src/backfill.rs

📝 Walkthrough

Walkthrough

This PR establishes idempotency for token transfer records during blockchain reorganization replays. A SQL migration removes existing duplicates and creates a unique constraint on (tx_hash, log_index). The application code responds by adding ON CONFLICT DO NOTHING to batch inserts, making replay-inserts safe at the database level. Separately, orphan-log audit logging is upgraded from debug to warn to improve operator visibility into dropped logs during syncing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Sentriscloud/indexer-rs#46: Earlier PR that adds ERC transfer persistence where insert_batch previously lacked conflict handling, making this PR's idempotency changes a necessary complement to that work.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/audit-medium-batch

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

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