fix(lite-backend): record the mined height of mempool-first transactions

When the mempool monitor saw a transaction first, its wallet entry kept
the monitor's height (often 0) after the transaction was mined, because
scanning the block reused the entry without updating its block. A later
reorg between the two heights then left a phantom spend of our own
send and a change note with an empty witness list until a rescan.

Scanning a block now sets the entry's block to the block height. This
applies to every monitor-first transaction, including payments received
from others: their reported block height, the verified/spendable timing
that depends on it, and the wallet birthday now use the real mined
height instead of the monitor's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 06:05:06 -05:00
co-authored by Claude Opus 5.5
parent 24a90ae532
commit 7c0afd06a8
3 changed files with 231 additions and 12 deletions
@@ -2398,6 +2398,10 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64
txs.insert(tx.txid, tx_entry);
}
let tx_entry = txs.get_mut(&tx.txid).unwrap();
// An existing entry can come from the mempool monitor (scan_full_mempool_tx), stamped with the
// height the server reported before the tx was mined. Record the block that mined it: a reorg of
// this block must remove the tx (invalidate_block and the witness clearing key on this field).
tx_entry.block = block_data.height;
tx_entry.total_shielded_value_spent = total_shielded_value_spent;
// Save notes.