Skip to content

fix: drop legacy unique indexes on activity id that block wallet-scoped rows (#137) - #142

Open
coreyphillips wants to merge 1 commit into
masterfrom
issue-137
Open

fix: drop legacy unique indexes on activity id that block wallet-scoped rows (#137)#142
coreyphillips wants to merge 1 commit into
masterfrom
issue-137

Conversation

@coreyphillips

@coreyphillips coreyphillips commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Closes #137

Drop the legacy idx_onchain_id and idx_lightning_id unique indexes on activity DB init, so an activity id can exist once per wallet scope as the composite primary key intends.

Databases predating wallet-scoped activity data can still carry idx_onchain_id and idx_lightning_id, unique indexes over the activity id alone. They contradict the PRIMARY KEY (wallet_id, id) both tables now use: an on-chain id is the txid, so a transaction visible to two wallet scopes (paying your own hardware wallet) cannot be stored twice. The watcher writes its snapshot in one transaction, so the collision rejects the entire snapshot, not just the colliding row, and the hardware wallet shows an empty activity list that never recovers. The statements that created the indexes were removed from the crate by the wallet-scoping commit (cc1ff06), but nothing ever dropped them from existing databases.

What changed

  • ActivityDB::initialize now runs a new LEGACY_INDEX_DROP_STATEMENTS step (DROP INDEX IF EXISTS idx_onchain_id / idx_lightning_id) unconditionally, after the table migrations and before the index creation loop, in src/modules/activity/implementation.rs
  • Three regression tests in src/modules/activity/tests.rs: test_init_drops_legacy_activity_id_unique_indexes (legacy indexes hand-created on a current-schema database, then a two-scope snapshot upsert), test_legacy_schema_migration_drops_activity_id_unique_indexes (pre-wallet-scoped schema plus both indexes), and test_activity_tables_have_no_extra_unique_indexes (drift guard)
  • Test helper extra_unique_index_names reads PRAGMA index_list and returns unique indexes whose origin is not pk, so the drift guard fails on any future non-primary-key unique index over activities, onchain_activity, or lightning_activity

How to test

  • cargo test --lib modules::activity: 192 passed, 0 failed.
  • To confirm the tests are not vacuous, I replaced the drop loop with LEGACY_INDEX_DROP_STATEMENTS.iter().take(0) and reran: test_init_drops_legacy_activity_id_unique_indexes fails on the leftover index, and restoring the loop makes it pass. That test is the one that covers the reported failure.
  • cargo test (full suite): 496 passed, 11 failed. All 11 failures are modules::blocktank tests hitting api.stag.blocktank.to, which is unreachable from this sandbox; they are unrelated to this change.
  • rustfmt --check is clean on both touched files. cargo fmt --check reports a pre-existing diff in src/modules/activity/backup_migration.rs, which this change does not touch (reproduced against HEAD before the change).
  • cargo clippy --all-targets produces no errors and no new warnings.
Databases created before activity data became wallet-scoped can still
carry idx_onchain_id and idx_lightning_id, which make an activity id
globally unique and so contradict the PRIMARY KEY (wallet_id, id) both
tables now use. A transaction visible to two wallet scopes (paying your
own hardware wallet) then fails to insert, and since the watcher writes
its snapshot in one transaction, the whole snapshot is rejected and the
hardware wallet shows an empty activity list on every poll.

Drop both indexes on every init: the statements that created them are
gone from this crate, but CREATE ... IF NOT EXISTS never undid them, and
running an older build against a migrated database can recreate them.
@coreyphillips
coreyphillips requested a review from ovitrif August 31, 2026 15:07
@ovitrif

ovitrif commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Would this warrant changes in the app(s)? @coreyphillips just asking

@coreyphillips

Copy link
Copy Markdown
Collaborator Author

No app logic changes should be needed. This is handled by Core during the existing initDb call. Both apps will only need to bump to the Core release containing this fix.

@ovitrif ovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants