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.)
Found by FLOW 14 of
scripts/smoke-test-wallet-e2e.shon regtest, againstwork/post-merge(
f48fb6948, binaries built from that tree). Not a test artefact — the daemon's own log sayswhat went wrong.
Measured
The wallet spent the whole run building on-chain history, then was recovered two ways.
wallet export/wallet restore(keystore file)wallet import --birth-height 101(words)The history count was polled for 180 s (60 × 3 s) and never moved past 1.
The daemon says why
From the same run's
wraithd.log— the original wallet, and then the two restored ones: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 inblock_scanand starts at 1133.Everything the seed did below that height is outside its history for good.
What is already ruled out
WalletCommand::Import { name, birth_height }buildsRequest::WalletImport { .., birth_height }(apps/wraith-wallet/cli/src/main.rs:883).record_birth_height(state, &name, birth_height)(
apps/wraith-wallet/daemon/src/main.rs:4938), with the deliberate "nothing if they saidnothing" comment, so it is not defaulting to the tip.
record_birth_heightwarns on error and there are 0 occurrences ofcould not record the wallet's birth heightin 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 andwallet_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()==Nonebranch.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-heightis the documented way to ask for the rest. The GUI restore flow rides on the same request.
Reproduce
Stops at FLOW 14. (FLOW 15 and 16 are therefore also unexercised on that branch.)