Skip to content

Wallet robustness: name records-without-seed at the reuse point - #154

Draft
BullishNode wants to merge 1 commit into
getpaid-2-57-backup-redesignfrom
getpaid-2-58-wallet-seed-consistency
Draft

Wallet robustness: name records-without-seed at the reuse point#154
BullishNode wants to merge 1 commit into
getpaid-2-57-backup-redesignfrom
getpaid-2-58-wallet-seed-consistency

Conversation

@BullishNode

Copy link
Copy Markdown
Owner

Fixes #137. Stacked on the backup redesign PR.

Wallet records that survive without their seed (keystore invalidation, interrupted restore — the same failure family as upstream SatoshiPortal#2439) previously passed startup as "ready" and crashed at first xprv use, deep inside Lightning Address registration, as an opaque SeedNotFoundException.

  • Both record-reuse points now validate seed presence (never reading the seed) via SeedRepository.exists: the CreateDefaultWalletsUsecase early return, and the cold-start CheckForExistingDefaultWalletsUsecase — which previously decrypted both seeds on every startup just to prove they existed, and rethrew the raw exception into the generic "App failed to start" screen.
  • A missing seed is now a typed InconsistentWalletStateException carrying the fingerprint, surfaced on the two existing failure surfaces (startup rescue screen and onboarding) with recovery copy: the device still has the wallet records, the seed is gone, restore from backup.
  • The remedy can't trip over the defect: vault restore reaches the same early return, so when the supplied mnemonic's fingerprint matches the orphaned records, the seed is stored back and the wallets are reused; a non-matching mnemonic still fails and stores nothing.
  • iOS keychain-locked semantics preserved: exists() maps through the same wrapper, so the pre-first-unlock retry path is unaffected. The wizard's backup-activation deferral is untouched.

7 new test cases (reuse-with-seed, reuse-without-seed → typed failure, heal-on-matching-mnemonic, fail-on-mismatch, presence-check-never-reads, both failure surfaces). Full suite 2309 green, whole-project analyze clean, format clean.

A device whose wallet DB survived but whose secure storage did not passed
startup as "ready": both reuse paths took the records at face value without
asking the seed store whether the seed behind their fingerprint was still
there. The state only surfaced much later, as SeedNotFoundException wrapped in
WalletOwnedLightningAddressRegistrationException(localPreparation) — an opaque
crash in whichever flow happened to derive the xprv first.

Both places that reuse existing default wallet records now check seed presence
(exists, never a read of seed material) and throw the typed
InconsistentWalletStateException carrying the fingerprint:
CreateDefaultWalletsUsecase's early return and
CheckForExistingDefaultWalletsUsecase at cold start, which also stops
decrypting two seeds on the startup path just to prove they exist. exists()
still maps the iOS locked keychain to KeychainLockedException, so the
pre-first-unlock retry is untouched.

The failure reaches the user as recovery advice rather than "restart the app",
which can never resolve it: the startup rescue screen swaps in wallet-data-
incomplete copy, and onboarding maps it to
OnboardingInconsistentWalletStateFailure with the same message.

Restoring from a backup is the remedy the copy points at, so the reuse path
heals instead of failing when the caller supplies the very mnemonic those
records were built from — otherwise the vault restore would hit the same
exception it is meant to clear.

Refs #137
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.

2 participants