fix(wallet): preserve walletDetails when merkletree-history version is undefined#135
Merged
Conversation
…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.
mesquka
approved these changes
May 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 —
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.