diff --git a/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet.rs b/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet.rs index 371a70a..50bb3c5 100644 --- a/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet.rs +++ b/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet.rs @@ -2304,10 +2304,10 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64 // Prepare the note witnesses for updating for tx in txs.values_mut() { for nd in tx.notes.iter_mut() { - // Duplicate the most recent witness (nothing to do for notes with no history) + // Duplicate the most recent witness (shares the allocation; deep-cloned only when appended to) if let Some(witness) = nd.witnesses.last() { - let clone = witness.clone(); - nd.witnesses.push(clone); + let shared = Arc::clone(witness); + nd.witnesses.push(shared); // Trim the oldest witnesses in place (no fresh Vec per note per block) let len = nd.witnesses.len(); if len > MAX_REORG { @@ -2322,12 +2322,18 @@ pub fn scan_full_mempool_tx(&self, tx: &Transaction, height: i32, _datetime: u64 let extfvks: Vec = self.zkeys.read().unwrap().iter().map(|zk| zk.extfvk.clone()).collect(); // Create a single mutable slice of all the newly-added witnesses. - let mut witness_refs: Vec<_> = txs - .values_mut() - .map(|tx| tx.notes.iter_mut().filter_map( - |nd| if nd.spent.is_none() && nd.unconfirmed_spent.is_none() { nd.witnesses.last_mut() } else { None })) - .flatten() - .collect(); + // A block without shielded outputs appends nothing to any witness: don't un-share (deep-clone) them. + let block_has_outputs = block.vtx.iter().any(|t| !t.outputs.is_empty()); + let mut witness_refs: Vec<&mut IncrementalWitness> = if block_has_outputs { + txs + .values_mut() + .map(|tx| tx.notes.iter_mut().filter_map( + |nd| if nd.spent.is_none() && nd.unconfirmed_spent.is_none() { nd.witnesses.last_mut().map(|w| Arc::make_mut(w)) } else { None })) + .flatten() + .collect() + } else { + Vec::new() + }; self.scan_block_internal( block.clone(), diff --git a/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs b/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs index 3db0d1a..72157ed 100644 --- a/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs +++ b/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs @@ -1,4 +1,5 @@ use std::io::{self, Read, Write}; +use std::sync::Arc; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use pairing::bls12_381::{Bls12}; @@ -66,7 +67,8 @@ pub struct SaplingNoteData { pub(super) extfvk: ExtendedFullViewingKey, // Technically, this should be recoverable from the account number, but we're going to refactor this in the future, so I'll write it again here. pub diversifier: Diversifier, pub note: Note, - pub(super) witnesses: Vec>, + // One entry per block (<= MAX_REORG), oldest first. Entries of blocks that appended nothing share one allocation. + pub(super) witnesses: Vec>>, pub(super) nullifier: [u8; 32], pub spent: Option, // If this note was confirmed spent pub unconfirmed_spent: Option, // If this note was spent in a send, but has not yet been confirmed. @@ -130,7 +132,7 @@ impl SaplingNoteData { extfvk: extfvk.clone(), diversifier: output.to.diversifier, note: output.note, - witnesses: vec![witness], + witnesses: vec![Arc::new(witness)], nullifier: nf, spent: None, unconfirmed_spent: None, @@ -162,7 +164,7 @@ impl SaplingNoteData { None => Err(io::Error::new(io::ErrorKind::InvalidInput, "Couldn't create the note for the address")) }?; - let witnesses = Vector::read(&mut reader, |r| IncrementalWitness::::read(r))?; + let witnesses = Vector::read(&mut reader, |r| IncrementalWitness::::read(r).map(Arc::new))?; let mut nullifier = [0u8; 32]; reader.read_exact(&mut nullifier)?; @@ -553,7 +555,7 @@ impl SpendableNote { nullifier: nd.nullifier, diversifier: nd.diversifier, note: nd.note.clone(), - witness: w.clone(), + witness: (**w).clone(), extsk: extsk.clone().unwrap(), }) } else {