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 29d7b80..b5c64a2 100644 --- a/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs +++ b/third_party/silentdragonxlite/silentdragonxlite-cli/lib/src/lightwallet/data.rs @@ -1,5 +1,7 @@ use std::io::{self, Read, Write}; use std::sync::Arc; +use std::cell::RefCell; +use std::collections::HashMap; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use pairing::bls12_381::{Bls12}; @@ -26,6 +28,24 @@ use zcash_primitives::{ use zcash_primitives::zip32::ExtendedSpendingKey; +// C241: wallet open re-parsed the 169-byte ExtendedFullViewingKey once PER NOTE. Memoize the decode, +// keyed by the exact 169 raw bytes (content-addressed, so the result is always identical to a fresh +// parse). Thread-local and naturally bounded by the handful of distinct keys a wallet holds. +thread_local! { + static EFVK_CACHE: RefCell> = RefCell::new(HashMap::new()); +} + +fn read_efvk_cached(r: &mut R) -> io::Result { + let mut raw = [0u8; 169]; + r.read_exact(&mut raw)?; + if let Some(k) = EFVK_CACHE.with(|c| c.borrow().get(&raw).cloned()) { + return Ok(k); + } + let k = ExtendedFullViewingKey::read(&raw[..])?; // identical parser on identical bytes + EFVK_CACHE.with(|c| c.borrow_mut().insert(raw, k.clone())); + Ok(k) +} + pub struct BlockData { pub height: i32, pub hash: BlockHash, @@ -147,7 +167,7 @@ impl SaplingNoteData { let account = reader.read_u64::()? as usize; - let extfvk = ExtendedFullViewingKey::read(&mut reader)?; + let extfvk = read_efvk_cached(&mut reader)?; let mut diversifier_bytes = [0u8; 11]; reader.read_exact(&mut diversifier_bytes)?;