Skip to content

wallet: a wallet imported with --birth-height still scans from the tip, so its history is lost #865

Description

@defenwycke

Found by FLOW 14 of scripts/smoke-test-wallet-e2e.sh on regtest, against work/post-merge
(f48fb6948, binaries built from that tree). Not a test artefact — the daemon's own log says
what went wrong.

Measured

The wallet spent the whole run building on-chain history, then was recovered two ways.

path balance history
wallet export / wallet restore (keystore file) recovered (not asserted)
wallet import --birth-height 101 (words) 2,896,345 sats — exact 1 of 13 entries

The history count was polled for 180 s (60 × 3 s) and never moved past 1.

before recovery: balance=2896345 history_entries=13
  PASS: words + birth height recover the balance (2896345 sats)
FAIL: the recovered wallet rebuilt 1 of 13 history entries from birth height 101
      — the coins are found but what they did is lost

The daemon says why

From the same run's wraithd.log — the original wallet, and then the two restored ones:

02:05:32Z INFO wraithd::server: block scanner rebuilding history from the wallet's birth height
                                birth_height=101 tip=108 behind=7
02:08:14Z INFO wraithd::server: block scanner started watching from the tip — this wallet has no
                                recorded birth height, so nothing before now will appear in its
                                history height=1133
02:08:37Z INFO wraithd::server: block scanner started watching from the tip — ... height=1133

So the machinery works (line 1, the original wallet); the imported wallet reaches the scanner with
no birth height, takes the birth.unwrap_or(tip) branch in block_scan and starts at 1133.
Everything the seed did below that height is outside its history for good.

What is already ruled out

  • The CLI does forward the flag — WalletCommand::Import { name, birth_height } builds
    Request::WalletImport { .., birth_height } (apps/wraith-wallet/cli/src/main.rs:883).
  • The handler does record it — record_birth_height(state, &name, birth_height)
    (apps/wraith-wallet/daemon/src/main.rs:4938), with the deliberate "nothing if they said
    nothing" comment, so it is not defaulting to the tip.
  • The write did not fail: record_birth_height warns on error and there are 0 occurrences of
    could not record the wallet's birth height in the run's log.

So the value is written and then not seen. Root cause NOT established. The two things to check
first are (a) whether wallet_data_dir(state, wallet) at write time and wallet_meta_for(state)
at scan time resolve to the same directory for a freshly imported wallet, and (b) ordering —
whether a scan bookmark is already set for that wallet by the time the meta lands, since the birth
height is only consulted on the bookmark.point() == None branch.

Why it matters

This is the "device is lost" path. The money is reachable — balance and UTXO scan the whole UTXO
set — but a restored wallet shows one line of history where there were thirteen, and --birth-height
is the documented way to ask for the rest. The GUI restore flow rides on the same request.

Reproduce

WRAITH_BIN_DIR=<target>/debug ./scripts/smoke-test-wallet-e2e.sh

Stops at FLOW 14. (FLOW 15 and 16 are therefore also unexercised on that branch.)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions