fix(lite-backend): don't panic when a reorg lands during a send
After broadcasting, the send path looked up the spent notes' and UTXOs' transactions with unwrap. A reorg while the transaction was being proved could remove one of them, so the backend panicked and poisoned the wallet lock although the transaction was already broadcast. The lookups are now `if let` with a warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+19
-10
@@ -2747,22 +2747,31 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64
|
||||
|
||||
// Mark notes as spent.
|
||||
{
|
||||
// Mark sapling notes as unconfirmed spent
|
||||
// Mark sapling notes as unconfirmed spent. The tx is already broadcast, so never panic here: a
|
||||
// reorg or a rescan (clear_blocks) while it was proved can have removed the tx that holds a
|
||||
// selected note or utxo. Skip those with a warning (a panic would poison `txs`; the send went out).
|
||||
let mut txs = self.txs.write().unwrap();
|
||||
for selected in notes {
|
||||
let mut spent_note = txs.get_mut(&selected.txid).unwrap()
|
||||
.notes.iter_mut()
|
||||
.find(|nd| &nd.nullifier[..] == &selected.nullifier[..])
|
||||
.unwrap();
|
||||
spent_note.unconfirmed_spent = Some(tx.txid());
|
||||
if let Some(spent_note) = txs.get_mut(&selected.txid)
|
||||
.and_then(|wtx| wtx.notes.iter_mut().find(|nd| &nd.nullifier[..] == &selected.nullifier[..]))
|
||||
{
|
||||
spent_note.unconfirmed_spent = Some(tx.txid());
|
||||
} else {
|
||||
warn!("Sent {}, but its input note from tx {} is no longer in the wallet (reorg or rescan); not marked pending",
|
||||
tx.txid(), selected.txid);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this utxo as unconfirmed spent
|
||||
for utxo in tinputs {
|
||||
let mut spent_utxo = txs.get_mut(&utxo.txid).unwrap().utxos.iter_mut()
|
||||
.find(|u| utxo.txid == u.txid && utxo.output_index == u.output_index)
|
||||
.unwrap();
|
||||
spent_utxo.unconfirmed_spent = Some(tx.txid());
|
||||
if let Some(spent_utxo) = txs.get_mut(&utxo.txid)
|
||||
.and_then(|wtx| wtx.utxos.iter_mut().find(|u| utxo.txid == u.txid && utxo.output_index == u.output_index))
|
||||
{
|
||||
spent_utxo.unconfirmed_spent = Some(tx.txid());
|
||||
} else {
|
||||
warn!("Sent {}, but its input utxo {}:{} is no longer in the wallet (reorg or rescan); not marked pending",
|
||||
tx.txid(), utxo.txid, utxo.output_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user