From fc15de5687045efb1359a0c01a5e608fc930fbc5 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Sat, 19 Oct 2019 11:18:22 -0700 Subject: [PATCH] Support mutable wallets --- lib/src/lightclient.rs | 231 ++++++++++++++++++++++------------------- lib/src/lightwallet.rs | 100 +++++++++++------- 2 files changed, 188 insertions(+), 143 deletions(-) diff --git a/lib/src/lightclient.rs b/lib/src/lightclient.rs index b19f2f6..a242d63 100644 --- a/lib/src/lightclient.rs +++ b/lib/src/lightclient.rs @@ -179,7 +179,7 @@ impl LightClientConfig { } pub struct LightClient { - pub wallet : Arc, + pub wallet : Arc>, pub config : LightClientConfig, @@ -196,7 +196,7 @@ impl LightClient { let state = self.config.get_initial_state(); match state { - Some((height, hash, tree)) => self.wallet.set_initial_block(height.try_into().unwrap(), hash, tree), + Some((height, hash, tree)) => self.wallet.read().unwrap().set_initial_block(height.try_into().unwrap(), hash, tree), _ => true, }; } @@ -213,14 +213,14 @@ impl LightClient { let wallet = LightWallet::read(&mut file_buffer, config)?; LightClient { - wallet : Arc::new(wallet), + wallet : Arc::new(RwLock::new(wallet)), config : config.clone(), sapling_output : vec![], sapling_spend : vec![] } } else { let l = LightClient { - wallet : Arc::new(LightWallet::new(seed_phrase, config, latest_block)?), + wallet : Arc::new(RwLock::new(LightWallet::new(seed_phrase, config, latest_block)?)), config : config.clone(), sapling_output : vec![], sapling_spend : vec![] @@ -231,7 +231,7 @@ impl LightClient { l }; - info!("Read wallet with birthday {}", lc.wallet.get_first_tx_block()); + info!("Read wallet with birthday {}", lc.wallet.read().unwrap().get_first_tx_block()); // Read Sapling Params lc.sapling_output.extend_from_slice(SaplingParams::get("sapling-output.params").unwrap().as_ref()); @@ -243,16 +243,16 @@ impl LightClient { } pub fn last_scanned_height(&self) -> u64 { - self.wallet.last_scanned_height() as u64 + self.wallet.read().unwrap().last_scanned_height() as u64 } // Export private keys pub fn do_export(&self, addr: Option) -> JsonValue { // Clone address so it can be moved into the closure let address = addr.clone(); - + let wallet = self.wallet.read().unwrap(); // Go over all z addresses - let z_keys = self.wallet.get_z_private_keys().iter() + let z_keys = wallet.get_z_private_keys().iter() .filter( move |(addr, _)| address.is_none() || address.as_ref() == Some(addr)) .map( |(addr, pk)| object!{ @@ -265,7 +265,7 @@ impl LightClient { let address = addr.clone(); // Go over all t addresses - let t_keys = self.wallet.get_t_secret_keys().iter() + let t_keys = wallet.get_t_secret_keys().iter() .filter( move |(addr, _)| address.is_none() || address.as_ref() == Some(addr)) .map( |(addr, sk)| object!{ @@ -282,15 +282,15 @@ impl LightClient { } pub fn do_address(&self) -> JsonValue { + let wallet = self.wallet.read().unwrap(); // Collect z addresses - let z_addresses = self.wallet.address.read().unwrap().iter().map( |ad| { + let z_addresses = wallet.zaddress.read().unwrap().iter().map( |ad| { encode_payment_address(self.config.hrp_sapling_address(), &ad) }).collect::>(); // Collect t addresses - let t_addresses = self.wallet.tkeys.read().unwrap().iter().map( |sk| { - self.wallet.address_from_sk(&sk) - }).collect::>(); + let t_addresses = wallet.taddresses.read().unwrap().iter().map( |a| a.clone() ) + .collect::>(); object!{ "z_addresses" => z_addresses, @@ -299,33 +299,33 @@ impl LightClient { } pub fn do_balance(&self) -> JsonValue { + let wallet = self.wallet.read().unwrap(); + // Collect z addresses - let z_addresses = self.wallet.address.read().unwrap().iter().map( |ad| { + let z_addresses = wallet.zaddress.read().unwrap().iter().map( |ad| { let address = encode_payment_address(self.config.hrp_sapling_address(), &ad); object!{ "address" => address.clone(), - "zbalance" => self.wallet.zbalance(Some(address.clone())), - "verified_zbalance" => self.wallet.verified_zbalance(Some(address)), + "zbalance" => wallet.zbalance(Some(address.clone())), + "verified_zbalance" => wallet.verified_zbalance(Some(address)), } }).collect::>(); // Collect t addresses - let t_addresses = self.wallet.tkeys.read().unwrap().iter().map( |sk| { - let address = self.wallet.address_from_sk(&sk); - + let t_addresses = wallet.taddresses.read().unwrap().iter().map( |address| { // Get the balance for this address - let balance = self.wallet.tbalance(Some(address.clone())); + let balance = wallet.tbalance(Some(address.clone())); object!{ - "address" => address, + "address" => address.clone(), "balance" => balance, } }).collect::>(); object!{ - "zbalance" => self.wallet.zbalance(None), - "verified_zbalance" => self.wallet.verified_zbalance(None), - "tbalance" => self.wallet.tbalance(None), + "zbalance" => wallet.zbalance(None), + "verified_zbalance" => wallet.verified_zbalance(None), + "tbalance" => wallet.tbalance(None), "z_addresses" => z_addresses, "t_addresses" => t_addresses, } @@ -336,7 +336,7 @@ impl LightClient { 1_000_000, // 1 MB write buffer File::create(self.config.get_wallet_path()).unwrap()); - match self.wallet.write(&mut file_buffer) { + match self.wallet.write().unwrap().write(&mut file_buffer) { Ok(_) => { info!("Saved wallet"); let response = object!{ @@ -375,9 +375,10 @@ impl LightClient { } pub fn do_seed_phrase(&self) -> JsonValue { + let wallet = self.wallet.read().unwrap(); object!{ - "seed" => self.wallet.get_seed_phrase(), - "birthday" => self.wallet.get_birthday() + "seed" => wallet.get_seed_phrase(), + "birthday" => wallet.get_birthday() } } @@ -387,69 +388,75 @@ impl LightClient { let mut spent_notes : Vec = vec![]; let mut pending_notes: Vec = vec![]; - // Collect Sapling notes - self.wallet.txs.read().unwrap().iter() - .flat_map( |(txid, wtx)| { - wtx.notes.iter().filter_map(move |nd| - if !all_notes && nd.spent.is_some() { - None + { + // Collect Sapling notes + let wallet = self.wallet.read().unwrap(); + wallet.txs.read().unwrap().iter() + .flat_map( |(txid, wtx)| { + wtx.notes.iter().filter_map(move |nd| + if !all_notes && nd.spent.is_some() { + None + } else { + Some(object!{ + "created_in_block" => wtx.block, + "datetime" => wtx.datetime, + "created_in_txid" => format!("{}", txid), + "value" => nd.note.value, + "is_change" => nd.is_change, + "address" => LightWallet::note_address(self.config.hrp_sapling_address(), nd), + "spent" => nd.spent.map(|spent_txid| format!("{}", spent_txid)), + "unconfirmed_spent" => nd.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)), + }) + } + ) + }) + .for_each( |note| { + if note["spent"].is_null() && note["unconfirmed_spent"].is_null() { + unspent_notes.push(note); + } else if !note["spent"].is_null() { + spent_notes.push(note); } else { - Some(object!{ - "created_in_block" => wtx.block, - "datetime" => wtx.datetime, - "created_in_txid" => format!("{}", txid), - "value" => nd.note.value, - "is_change" => nd.is_change, - "address" => self.wallet.note_address(nd), - "spent" => nd.spent.map(|spent_txid| format!("{}", spent_txid)), - "unconfirmed_spent" => nd.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)), - }) + pending_notes.push(note); } - ) - }) - .for_each( |note| { - if note["spent"].is_null() && note["unconfirmed_spent"].is_null() { - unspent_notes.push(note); - } else if !note["spent"].is_null() { - spent_notes.push(note); - } else { - pending_notes.push(note); - } - }); + }); + } let mut unspent_utxos: Vec = vec![]; let mut spent_utxos : Vec = vec![]; let mut pending_utxos: Vec = vec![]; - - self.wallet.txs.read().unwrap().iter() - .flat_map( |(txid, wtx)| { - wtx.utxos.iter().filter_map(move |utxo| - if !all_notes && utxo.spent.is_some() { - None + + { + let wallet = self.wallet.read().unwrap(); + wallet.txs.read().unwrap().iter() + .flat_map( |(txid, wtx)| { + wtx.utxos.iter().filter_map(move |utxo| + if !all_notes && utxo.spent.is_some() { + None + } else { + Some(object!{ + "created_in_block" => wtx.block, + "datetime" => wtx.datetime, + "created_in_txid" => format!("{}", txid), + "value" => utxo.value, + "scriptkey" => hex::encode(utxo.script.clone()), + "is_change" => false, // TODO: Identify notes as change if we send change to taddrs + "address" => utxo.address.clone(), + "spent" => utxo.spent.map(|spent_txid| format!("{}", spent_txid)), + "unconfirmed_spent" => utxo.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)), + }) + } + ) + }) + .for_each( |utxo| { + if utxo["spent"].is_null() && utxo["unconfirmed_spent"].is_null() { + unspent_utxos.push(utxo); + } else if !utxo["spent"].is_null() { + spent_utxos.push(utxo); } else { - Some(object!{ - "created_in_block" => wtx.block, - "datetime" => wtx.datetime, - "created_in_txid" => format!("{}", txid), - "value" => utxo.value, - "scriptkey" => hex::encode(utxo.script.clone()), - "is_change" => false, // TODO: Identify notes as change if we send change to taddrs - "address" => utxo.address.clone(), - "spent" => utxo.spent.map(|spent_txid| format!("{}", spent_txid)), - "unconfirmed_spent" => utxo.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)), - }) + pending_utxos.push(utxo); } - ) - }) - .for_each( |utxo| { - if utxo["spent"].is_null() && utxo["unconfirmed_spent"].is_null() { - unspent_utxos.push(utxo); - } else if !utxo["spent"].is_null() { - spent_utxos.push(utxo); - } else { - pending_utxos.push(utxo); - } - }); + }); + } let mut res = object!{ "unspent_notes" => unspent_notes, @@ -467,8 +474,9 @@ impl LightClient { } pub fn do_list_transactions(&self) -> JsonValue { + let wallet = self.wallet.read().unwrap(); // Create a list of TransactionItems - let mut tx_list = self.wallet.txs.read().unwrap().iter() + let mut tx_list = wallet.txs.read().unwrap().iter() .flat_map(| (_k, v) | { let mut txns: Vec = vec![]; @@ -512,7 +520,7 @@ impl LightClient { "datetime" => v.datetime, "txid" => format!("{}", v.txid), "amount" => nd.note.value as i64, - "address" => self.wallet.note_address(nd), + "address" => LightWallet::note_address(self.config.hrp_sapling_address(), nd), "memo" => LightWallet::memo_str(&nd.memo), }) ); @@ -547,9 +555,11 @@ impl LightClient { /// Create a new address, deriving it from the seed. pub fn do_new_address(&self, addr_type: &str) -> JsonValue { + let wallet = self.wallet.write().unwrap(); + let new_address = match addr_type { - "z" => self.wallet.add_zaddr(), - "t" => self.wallet.add_taddr(), + "z" => wallet.add_zaddr(), + "t" => wallet.add_taddr(), _ => { let e = format!("Unrecognized address type: {}", addr_type); error!("{}", e); @@ -565,7 +575,7 @@ impl LightClient { pub fn do_rescan(&self) -> String { info!("Rescan starting"); // First, clear the state from the wallet - self.wallet.clear_blocks(); + self.wallet.read().unwrap().clear_blocks(); // Then set the initial block self.set_wallet_initial_state(); @@ -583,7 +593,7 @@ impl LightClient { // 2. Get all the blocks that we don't have // 3. Find all new Txns that don't have the full Tx, and get them as full transactions // and scan them, mainly to get the memos - let mut last_scanned_height = self.wallet.last_scanned_height() as u64; + let mut last_scanned_height = self.wallet.read().unwrap().last_scanned_height() as u64; // This will hold the latest block fetched from the RPC let latest_block_height = Arc::new(AtomicU64::new(0)); @@ -662,7 +672,7 @@ impl LightClient { Err(_) => {} } - match local_light_wallet.scan_block(encoded_block) { + match local_light_wallet.read().unwrap().scan_block(encoded_block) { Ok(block_txns) => { // Add to global tx list all_txs.write().unwrap().extend_from_slice(&block_txns.iter().map(|txid| (txid.clone(), height as i32)).collect::>()[..]); @@ -679,7 +689,7 @@ impl LightClient { // Check if there was any invalid block, which means we might have to do a reorg let invalid_height = last_invalid_height.load(Ordering::SeqCst); if invalid_height > 0 { - total_reorg += self.wallet.invalidate_block(invalid_height); + total_reorg += self.wallet.read().unwrap().invalidate_block(invalid_height); warn!("Invalidated block at height {}. Total reorg is now {}", invalid_height, total_reorg); } @@ -705,19 +715,28 @@ impl LightClient { total_reorg = 0; // We'll also fetch all the txids that our transparent addresses are involved with - // TODO: Use for all t addresses - let address = self.wallet.address_from_sk(&self.wallet.tkeys.read().unwrap()[0]); - let wallet = self.wallet.clone(); - fetch_transparent_txids(&self.get_server_uri(), address, start_height, end_height, self.config.no_cert_verification, - move |tx_bytes: &[u8], height: u64 | { - let tx = Transaction::read(tx_bytes).unwrap(); + { + // Copy over addresses so as to not lock up the wallet, which we'll use inside the callback below. + let addresses = self.wallet.read().unwrap() + .taddresses.read().unwrap().iter().map(|a| a.clone()) + .collect::>(); + for address in addresses { + let wallet = self.wallet.clone(); + let block_times_inner = block_times.clone(); - // Scan this Tx for transparent inputs and outputs - let datetime = block_times.read().unwrap().get(&height).map(|v| *v).unwrap_or(0); - wallet.scan_full_tx(&tx, height as i32, datetime as u64); + fetch_transparent_txids(&self.get_server_uri(), address, start_height, end_height, self.config.no_cert_verification, + move |tx_bytes: &[u8], height: u64| { + let tx = Transaction::read(tx_bytes).unwrap(); + + // Scan this Tx for transparent inputs and outputs + let datetime = block_times_inner.read().unwrap().get(&height).map(|v| *v).unwrap_or(0); + wallet.read().unwrap().scan_full_tx(&tx, height as i32, datetime as u64); + } + ); } - ); + } + // Do block height accounting last_scanned_height = end_height; end_height = last_scanned_height + 1000; @@ -741,10 +760,10 @@ impl LightClient { // We need to first copy over the Txids from the wallet struct, because // we need to free the read lock from here (Because we'll self.wallet.txs later) - let mut txids_to_fetch: Vec<(TxId, i32)> = self.wallet.txs.read().unwrap().values() - .filter(|wtx| wtx.full_tx_scanned == false) - .map(|wtx| (wtx.txid, wtx.block)) - .collect::>(); + let mut txids_to_fetch: Vec<(TxId, i32)> = self.wallet.read().unwrap().txs.read().unwrap().values() + .filter(|wtx| wtx.full_tx_scanned == false) + .map(|wtx| (wtx.txid.clone(), wtx.block)) + .collect::>(); info!("Fetching {} new txids, total {} with decoy", txids_to_fetch.len(), all_new_txs.read().unwrap().len()); txids_to_fetch.extend_from_slice(&all_new_txs.read().unwrap()[..]); @@ -763,7 +782,7 @@ impl LightClient { fetch_full_tx(&self.get_server_uri(), txid, self.config.no_cert_verification, move |tx_bytes: &[u8] | { let tx = Transaction::read(tx_bytes).unwrap(); - light_wallet_clone.scan_full_tx(&tx, height, 0); + light_wallet_clone.read().unwrap().scan_full_tx(&tx, height, 0); }); }; @@ -773,7 +792,7 @@ impl LightClient { pub fn do_send(&self, addrs: Vec<(&str, u64, Option)>) -> String { info!("Creating transaction"); - let rawtx = self.wallet.send_to_address( + let rawtx = self.wallet.write().unwrap().send_to_address( u32::from_str_radix(&self.config.consensus_branch_id, 16).unwrap(), &self.sapling_spend, &self.sapling_output, addrs diff --git a/lib/src/lightwallet.rs b/lib/src/lightwallet.rs index 99e1698..d849440 100644 --- a/lib/src/lightwallet.rs +++ b/lib/src/lightwallet.rs @@ -99,10 +99,12 @@ pub struct LightWallet { extsks: Arc>>, extfvks: Arc>>, - pub address: Arc>>>, + pub zaddress: Arc>>>, - // Transparent keys. TODO: Make it not pubic - pub tkeys: Arc>>, + // Transparent keys. If the wallet is locked, then the secret keys will be encrypted, + // but the addresses will be present. + tkeys: Arc>>, + pub taddresses: Arc>>, blocks: Arc>>, pub txs: Arc>>, @@ -165,8 +167,9 @@ impl LightWallet { // we need to get the 64 byte bip39 entropy let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&seed_bytes, Language::English).unwrap(), ""); - // Derive only the first address + // Derive only the first sk and address let tpk = LightWallet::get_taddr_from_bip39seed(&config, &bip39_seed.as_bytes(), 0); + let taddr = LightWallet::address_from_prefix_sk(&config.base58_pubkey_address(), &tpk); // TODO: We need to monitor addresses, and always keep 1 "free" address, so // users can import a seed phrase and automatically get all used addresses @@ -174,16 +177,17 @@ impl LightWallet { = LightWallet::get_zaddr_from_bip39seed(&config, &bip39_seed.as_bytes(), 0); Ok(LightWallet { - locked: false, - seed: seed_bytes, - extsks: Arc::new(RwLock::new(vec![extsk])), - extfvks: Arc::new(RwLock::new(vec![extfvk])), - address: Arc::new(RwLock::new(vec![address])), - tkeys: Arc::new(RwLock::new(vec![tpk])), - blocks: Arc::new(RwLock::new(vec![])), - txs: Arc::new(RwLock::new(HashMap::new())), - config: config.clone(), - birthday: latest_block, + locked: false, + seed: seed_bytes, + extsks: Arc::new(RwLock::new(vec![extsk])), + extfvks: Arc::new(RwLock::new(vec![extfvk])), + zaddress: Arc::new(RwLock::new(vec![address])), + tkeys: Arc::new(RwLock::new(vec![tpk])), + taddresses: Arc::new(RwLock::new(vec![taddr])), + blocks: Arc::new(RwLock::new(vec![])), + txs: Arc::new(RwLock::new(HashMap::new())), + config: config.clone(), + birthday: latest_block, }) } @@ -224,6 +228,14 @@ impl LightWallet { secp256k1::SecretKey::from_slice(&tpk_bytes).map_err(|e| io::Error::new(ErrorKind::InvalidData, e)) })?; + let taddresses = if version >= 4 { + // Read the addresses + Vector::read(&mut reader, |r| utils::read_string(r))? + } else { + // Calculate the addresses + tkeys.iter().map(|sk| LightWallet::address_from_prefix_sk(&config.base58_pubkey_address(), sk)).collect() + }; + let blocks = Vector::read(&mut reader, |r| BlockData::read(r))?; let txs_tuples = Vector::read(&mut reader, |r| { @@ -244,15 +256,16 @@ impl LightWallet { let birthday = reader.read_u64::()?; Ok(LightWallet{ - locked: locked, - seed: seed_bytes, - extsks: Arc::new(RwLock::new(extsks)), - extfvks: Arc::new(RwLock::new(extfvks)), - address: Arc::new(RwLock::new(addresses)), - tkeys: Arc::new(RwLock::new(tkeys)), - blocks: Arc::new(RwLock::new(blocks)), - txs: Arc::new(RwLock::new(txs)), - config: config.clone(), + locked: locked, + seed: seed_bytes, + extsks: Arc::new(RwLock::new(extsks)), + extfvks: Arc::new(RwLock::new(extfvks)), + zaddress: Arc::new(RwLock::new(addresses)), + tkeys: Arc::new(RwLock::new(tkeys)), + taddresses: Arc::new(RwLock::new(taddresses)), + blocks: Arc::new(RwLock::new(blocks)), + txs: Arc::new(RwLock::new(txs)), + config: config.clone(), birthday, }) } @@ -280,11 +293,16 @@ impl LightWallet { |w, fvk| fvk.write(w) )?; - // Write the transparent private key + // Write the transparent private keys Vector::write(&mut writer, &self.tkeys.read().unwrap(), |w, pk| w.write_all(&pk[..]) )?; + // Write the transparent addresses + Vector::write(&mut writer, &self.taddresses.read().unwrap(), + |w, a| utils::write_string(w, a) + )?; + Vector::write(&mut writer, &self.blocks.read().unwrap(), |w, b| b.write(w))?; // The hashmap, write as a set of tuples @@ -302,9 +320,9 @@ impl LightWallet { Ok(()) } - pub fn note_address(&self, note: &SaplingNoteData) -> Option { + pub fn note_address(hrp: &str, note: &SaplingNoteData) -> Option { match note.extfvk.fvk.vk.into_payment_address(note.diversifier, &JUBJUB) { - Some(pa) => Some(encode_payment_address(self.config.hrp_sapling_address(), &pa)), + Some(pa) => Some(encode_payment_address(hrp, &pa)), None => None } } @@ -340,7 +358,8 @@ impl LightWallet { /// Get all t-address private keys. Returns a Vector of (address, secretkey) pub fn get_t_secret_keys(&self) -> Vec<(String, String)> { self.tkeys.read().unwrap().iter().map(|sk| { - (self.address_from_sk(sk), sk[..].to_base58check(&self.config.base58_secretkey_prefix(), &[0x01])) + (self.address_from_sk(sk), + sk[..].to_base58check(&self.config.base58_secretkey_prefix(), &[0x01])) }).collect::>() } @@ -355,7 +374,7 @@ impl LightWallet { let zaddr = encode_payment_address(self.config.hrp_sapling_address(), &address); self.extsks.write().unwrap().push(extsk); self.extfvks.write().unwrap().push(extfvk); - self.address.write().unwrap().push(address); + self.zaddress.write().unwrap().push(address); zaddr } @@ -365,11 +384,14 @@ impl LightWallet { /// NOTE: This is not rescan the wallet pub fn add_taddr(&self) -> String { let pos = self.tkeys.read().unwrap().len() as u32; + let sk = LightWallet::get_taddr_from_bip39seed(&self.config, &self.seed, pos); + let address = self.address_from_sk(&sk); self.tkeys.write().unwrap().push(sk); + self.taddresses.write().unwrap().push(address.clone()); - self.address_from_sk(&sk) + address } /// Clears all the downloaded blocks and resets the state back to the initial block. @@ -476,7 +498,7 @@ impl LightWallet { } } - pub fn address_from_sk(&self, sk: &secp256k1::SecretKey) -> String { + pub fn address_from_prefix_sk(prefix: &[u8; 2], sk: &secp256k1::SecretKey) -> String { let secp = secp256k1::Secp256k1::new(); let pk = secp256k1::PublicKey::from_secret_key(&secp, &sk); @@ -484,7 +506,11 @@ impl LightWallet { let mut hash160 = ripemd160::Ripemd160::new(); hash160.input(Sha256::digest(&pk.serialize()[..].to_vec())); - hash160.result().to_base58check(&self.config.base58_pubkey_address(), &[]) + hash160.result().to_base58check(prefix, &[]) + } + + pub fn address_from_sk(&self, sk: &secp256k1::SecretKey) -> String { + LightWallet::address_from_prefix_sk(&self.config.base58_pubkey_address(), sk) } pub fn address_from_pubkeyhash(&self, ta: Option) -> Option { @@ -699,8 +725,8 @@ impl LightWallet { // outgoing metadata // Collect our t-addresses - let wallet_taddrs = self.tkeys.read().unwrap().iter() - .map(|sk| self.address_from_sk(sk)) + let wallet_taddrs = self.taddresses.read().unwrap().iter() + .map(|a| a.clone()) .collect::>(); for vout in tx.vout.iter() { @@ -768,7 +794,7 @@ impl LightWallet { // First, collect all our z addresses, to check for change // Collect z addresses - let z_addresses = self.address.read().unwrap().iter().map( |ad| { + let z_addresses = self.zaddress.read().unwrap().iter().map( |ad| { encode_payment_address(self.config.hrp_sapling_address(), &ad) }).collect::>(); @@ -1870,7 +1896,7 @@ pub mod tests { assert_eq!(wallet.extsks.read().unwrap().len(), wallet2.extsks.read().unwrap().len()); assert_eq!(wallet.extsks.read().unwrap()[0], wallet2.extsks.read().unwrap()[0]); assert_eq!(wallet.extfvks.read().unwrap()[0], wallet2.extfvks.read().unwrap()[0]); - assert_eq!(wallet.address.read().unwrap()[0], wallet2.address.read().unwrap()[0]); + assert_eq!(wallet.zaddress.read().unwrap()[0], wallet2.zaddress.read().unwrap()[0]); assert_eq!(wallet.tkeys.read().unwrap().len(), wallet2.tkeys.read().unwrap().len()); assert_eq!(wallet.tkeys.read().unwrap()[0], wallet2.tkeys.read().unwrap()[0]); @@ -1939,7 +1965,7 @@ pub mod tests { assert_eq!(wallet2.tkeys.read().unwrap().len(), 2); assert_eq!(wallet2.extsks.read().unwrap().len(), 2); assert_eq!(wallet2.extfvks.read().unwrap().len(), 2); - assert_eq!(wallet2.address.read().unwrap().len(), 2); + assert_eq!(wallet2.zaddress.read().unwrap().len(), 2); assert_eq!(taddr1, wallet.address_from_sk(&wallet.tkeys.read().unwrap()[0])); assert_eq!(taddr2, wallet.address_from_sk(&wallet.tkeys.read().unwrap()[1])); @@ -2359,7 +2385,7 @@ pub mod tests { assert_eq!(txs[&sent_txid].notes[0].extfvk, wallet.extfvks.read().unwrap()[0]); assert_eq!(txs[&sent_txid].notes[0].note.value, AMOUNT1 - fee); - assert_eq!(wallet.note_address(&txs[&sent_txid].notes[0]), Some(my_address)); + assert_eq!(LightWallet::note_address(wallet.config.hrp_sapling_address(), &txs[&sent_txid].notes[0]), Some(my_address)); assert_eq!(LightWallet::memo_str(&txs[&sent_txid].notes[0].memo), Some(memo)); } }