Skip to content

Duplicate rows in nodes table due to missing unique constraint + racy import guard #296

@jorgecuesta

Description

@jorgecuesta

Problem

1045 supplier addresses appear twice in the nodes table (75% of all staked rows). Both rows are identical (same owner, provider, stake, status) and were created within seconds of each other.

Evidence (mainnet middleman DB, 2026-05-27)

  • 1023 duplicate pairs created on 2026-04-09, gap of exactly 61s between inserts
  • 20 duplicate pairs created on 2026-05-24, gap of 11s

Root cause

  1. packages/db/src/middleman/schema/node.ts:35address column has no UNIQUE constraint (composite or otherwise)
  2. apps/middleman/src/actions/ImportSuppliers.ts:127 — uses .onConflictDoNothing() without a target, which silently does nothing when no unique constraint exists
  3. CompleteImportAttempt reads getExistingNodes() then inserts — classic check-then-act race window. Two concurrent requests (double-click on "Import", retry, etc.) both pass the existence check and both insert.

Proposed fix

  • Add unique index on nodes.address (or composite (address, providerId))
  • Run migration to dedupe existing rows first (delete newer row, keep oldest, remap any transactions_to_nodes)
  • Make .onConflictDoNothing() target the new unique index

Impact

  • UI may render some nodes twice
  • Reconciliation jobs do duplicate work
  • supplier_changes can fire twice per real event

Cleanup task (separate)

Production DB has 1043 dup pairs to remove. Plan: keep min(id), move any transactions_to_nodes references to the kept row, delete the dup.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions