Skip to content

fix(wallet): preserve walletDetails when merkletree-history version is undefined#135

Merged
zy0n merged 1 commit into
mainfrom
zy0n/preserve-wallet-details
May 26, 2026
Merged

fix(wallet): preserve walletDetails when merkletree-history version is undefined#135
zy0n merged 1 commit into
mainfrom
zy0n/preserve-wallet-details

Conversation

@zy0n

@zy0n zy0n commented May 26, 2026

Copy link
Copy Markdown
Contributor

The wallet-side merkletree-history-version key lives at [walletPrefix, 'merkleetree_history_version', chainId] — under the same namespace that clearDecryptedBalancesAllTXIDVersions clears via db.clearNamespace(walletPrefix). The engine's
clearUTXOMerkletreeAndLoadedWalletsAllTXIDVersions chain calls into the wallet-clear, wiping the version key but never re-stamping it; the engine's own version key (in ChainSyncInfo namespace) survives.

Result: every cold-sync followed by a refresh saw "wallet version undefined" in loadUTXOMerkletree, treated it as "stale schema, must clear", and wiped the freshly-rebuilt walletDetails — forcing decryptBalances to do a full leaf rescan from creationTreeHeight. A second cold-sync+refresh cycle finally landed the version key in a state where loadUTXOMerkletree skipped the clear path.

Fix: split the two cases the version check was conflating —

  • undefined: cold install or post-adjacent-wipe; namespace is empty or already at current schema. Just stamp the version, no clear.
  • < CURRENT: real schema migration. Clear and re-stamp.

Schema-bump behavior is preserved: a stored version older than CURRENT still triggers the clear+restamp. fullRedecryptBalancesAllTXIDVersions (driven by treeScannedHeights = [], not the version key) still rescans.

Includes regression test that seeds walletDetails after a clear leaves the version key undefined and asserts loadUTXOMerkletree preserves the seeded heights.

…s undefined

The wallet-side merkletree-history-version key lives at
[walletPrefix, 'merkleetree_history_version', chainId] — under the same
namespace that clearDecryptedBalancesAllTXIDVersions clears via
db.clearNamespace(walletPrefix). The engine's
clearUTXOMerkletreeAndLoadedWalletsAllTXIDVersions chain calls into the
wallet-clear, wiping the version key but never re-stamping it; the
engine's own version key (in ChainSyncInfo namespace) survives.

Result: every cold-sync followed by a refresh saw "wallet version
undefined" in loadUTXOMerkletree, treated it as "stale schema, must
clear", and wiped the freshly-rebuilt walletDetails — forcing
decryptBalances to do a full leaf rescan from creationTreeHeight.
A second cold-sync+refresh cycle finally landed the version key in a
state where loadUTXOMerkletree skipped the clear path.

Fix: split the two cases the version check was conflating —
  - undefined: cold install or post-adjacent-wipe; namespace is empty
    or already at current schema. Just stamp the version, no clear.
  - < CURRENT: real schema migration. Clear and re-stamp.

Schema-bump behavior is preserved: a stored version older than CURRENT
still triggers the clear+restamp. fullRedecryptBalancesAllTXIDVersions
(driven by treeScannedHeights = [], not the version key) still rescans.

Includes regression test that seeds walletDetails after a clear leaves
the version key undefined and asserts loadUTXOMerkletree preserves the
seeded heights.
@zy0n zy0n requested a review from mesquka May 26, 2026 10:07
@zy0n zy0n merged commit ab64c0c into main May 26, 2026
5 of 6 checks 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.

2 participants