From e000ff3bc93def34e9374f2c38fe5b2c077d7d57 Mon Sep 17 00:00:00 2001 From: Cryptoforge Date: Wed, 5 Aug 2020 21:55:33 -0700 Subject: [PATCH] newline cleanup --- README.md | 12 +-- lib/src/commands.rs | 20 ++-- lib/src/lightclient.rs | 126 ++++++++++++------------ lib/src/lightwallet.rs | 184 ++++++++++++++++++------------------ lib/src/lightwallet/bugs.rs | 20 ++-- lib/src/lightwallet/data.rs | 2 +- 6 files changed, 182 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index 2528139..13e7dd8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -## Zecwallet CLI - A command line ZecWallet light client. +## Zecwallet CLI - A command line ZecWallet light client. `zecwallet-cli` is a command line ZecWallet light client. To use it, download the latest binary from the releases page and run `./zecwallet-cli` This will launch the interactive prompt. Type `help` to get a list of commands ## Running in non-interactive mode: -You can also run `zecwallet-cli` in non-interactive mode by passing the command you want to run as an argument. For example, `zecwallet-cli addresses` will list all wallet addresses and exit. -Run `zecwallet-cli help` to see a list of all commands. +You can also run `zecwallet-cli` in non-interactive mode by passing the command you want to run as an argument. For example, `zecwallet-cli addresses` will list all wallet addresses and exit. +Run `zecwallet-cli help` to see a list of all commands. -## Privacy +## Privacy * While all the keys and transaction detection happens on the client, the server can learn what blocks contain your shielded transactions. * The server also learns other metadata about you like your ip address etc... * Also remember that t-addresses don't provide any privacy protection. @@ -42,9 +42,9 @@ cargo build --release ``` ## Options -Here are some CLI arguments you can pass to `zecwallet-cli`. Please run `zecwallet-cli --help` for the full list. +Here are some CLI arguments you can pass to `zecwallet-cli`. Please run `zecwallet-cli --help` for the full list. -* `--server`: Connect to a custom zecwallet lightwalletd server. +* `--server`: Connect to a custom zecwallet lightwalletd server. * Example: `./zecwallet-cli --server 127.0.0.1:9067` * `--seed`: Restore a wallet from a seed phrase. Note that this will fail if there is an existing wallet. Delete (or move) any existing wallet to restore from the 24-word seed phrase * Example: `./zecwallet-cli --seed "twenty four words seed phrase"` diff --git a/lib/src/commands.rs b/lib/src/commands.rs index 8b63e87..5c27144 100644 --- a/lib/src/commands.rs +++ b/lib/src/commands.rs @@ -79,7 +79,7 @@ impl Command for SyncStatusCommand { false => object!{ "syncing" => "false" }, true => object!{ "syncing" => "true", "synced_blocks" => status.synced_blocks, - "total_blocks" => status.total_blocks } + "total_blocks" => status.total_blocks } }.pretty(2) } } @@ -120,7 +120,7 @@ impl Command for ClearCommand { h.push("clear"); h.push(""); h.push("This command will clear all notes, utxos and transactions from the wallet, setting up the wallet to be synced from scratch."); - + h.join("\n") } @@ -130,9 +130,9 @@ impl Command for ClearCommand { fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { lightclient.clear_state(); - + let result = object!{ "result" => "success" }; - + result.pretty(2) } } @@ -197,7 +197,7 @@ impl Command for InfoCommand { "Get the lightwalletd server's info".to_string() } - fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { + fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { lightclient.do_info() } } @@ -436,7 +436,7 @@ impl Command for LockCommand { let mut h = vec![]; h.push("Extra arguments to lock. Did you mean 'encrypt'?"); h.push(""); - + return format!("{}\n{}", h.join("\n"), self.help()); } @@ -584,9 +584,9 @@ impl Command for SaveCommand { r.pretty(2) }, Err(e) => { - let r = object!{ + let r = object!{ "result" => "error", - "error" => e + "error" => e }; r.pretty(2) } @@ -715,7 +715,7 @@ impl Command for NotesCommand { } fn exec(&self, args: &[&str], lightclient: &LightClient) -> String { - // Parse the args. + // Parse the args. if args.len() > 1 { return self.short_help(); } @@ -843,6 +843,6 @@ pub mod tests { #[test] pub fn test_nosync_commands() { - // The following commands should run + // The following commands should run } } diff --git a/lib/src/lightclient.rs b/lib/src/lightclient.rs index 1cbb29c..8962f19 100644 --- a/lib/src/lightclient.rs +++ b/lib/src/lightclient.rs @@ -140,7 +140,7 @@ impl LightClientConfig { } pub fn get_zcash_data_path(&self) -> Box { - let mut zcash_data_location; + let mut zcash_data_location; if self.data_dir.is_some() { zcash_data_location = PathBuf::from(&self.data_dir.as_ref().unwrap()); } else { @@ -178,7 +178,7 @@ impl LightClientConfig { pub fn get_wallet_path(&self) -> Box { let mut wallet_location = self.get_zcash_data_path().into_path_buf(); wallet_location.push(WALLET_NAME); - + wallet_location.into_boxed_path() } @@ -296,7 +296,7 @@ pub struct LightClient { } impl LightClient { - + pub fn set_wallet_initial_state(&self, height: u64) { use std::convert::TryInto; @@ -349,14 +349,14 @@ impl LightClient { let mut l = LightClient { wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), &config, 0)?)), config : config.clone(), - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), }; l.set_wallet_initial_state(0); - + #[cfg(feature = "embed_params")] l.read_sapling_params(); @@ -366,11 +366,11 @@ impl LightClient { Ok(l) } - /// Create a brand new wallet with a new seed phrase. Will fail if a wallet file + /// Create a brand new wallet with a new seed phrase. Will fail if a wallet file /// already exists on disk pub fn new(config: &LightClientConfig, latest_block: u64) -> io::Result { #[cfg(all(not(target_os="ios"), not(target_os="android")))] - { + { if config.wallet_exists() { return Err(Error::new(ErrorKind::AlreadyExists, "Cannot create a new wallet from seed, because a wallet already exists")); @@ -380,14 +380,14 @@ impl LightClient { let mut l = LightClient { wallet : Arc::new(RwLock::new(LightWallet::new(None, config, latest_block)?)), config : config.clone(), - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), }; l.set_wallet_initial_state(latest_block); - + #[cfg(feature = "embed_params")] l.read_sapling_params(); @@ -412,7 +412,7 @@ impl LightClient { let mut l = LightClient { wallet : Arc::new(RwLock::new(LightWallet::new(Some(seed_phrase), config, birthday)?)), config : config.clone(), - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), @@ -420,7 +420,7 @@ impl LightClient { println!("Setting birthday to {}", birthday); l.set_wallet_initial_state(birthday); - + #[cfg(feature = "embed_params")] l.read_sapling_params(); @@ -438,7 +438,7 @@ impl LightClient { let mut lc = LightClient { wallet : Arc::new(RwLock::new(wallet)), config : config.clone(), - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), @@ -460,12 +460,12 @@ impl LightClient { } let mut file_buffer = BufReader::new(File::open(config.get_wallet_path())?); - + let wallet = LightWallet::read(&mut file_buffer, config)?; let mut lc = LightClient { wallet : Arc::new(RwLock::new(wallet)), config : config.clone(), - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), @@ -547,16 +547,16 @@ impl LightClient { Ok(s) => s, Err(_) => return Err("Decryption failed. Is your password correct?".to_string()) }; - + Mnemonic::from_entropy(&seed, Language::English) } else { // Seed let mut seed_bytes = [0u8; 32]; reader.read_exact(&mut seed_bytes).unwrap(); - Mnemonic::from_entropy(&seed_bytes, Language::English) + Mnemonic::from_entropy(&seed_bytes, Language::English) }.map_err(|e| format!("Failed to read seed. {:?}", e)); - + phrase.map(|m| m.phrase().to_string()) } @@ -640,7 +640,7 @@ impl LightClient { let t_addresses = wallet.taddresses.read().unwrap().iter().map( |address| { // Get the balance for this address let balance = wallet.tbalance(Some(address.clone())); - + object!{ "address" => address.clone(), "balance" => balance, @@ -656,9 +656,9 @@ impl LightClient { } } - pub fn do_save(&self) -> Result<(), String> { + pub fn do_save(&self) -> Result<(), String> { // On mobile platforms, disable the save, because the saves will be handled by the native layer, and not in rust - if cfg!(all(not(target_os="ios"), not(target_os="android"))) { + if cfg!(all(not(target_os="ios"), not(target_os="android"))) { // If the wallet is encrypted but unlocked, lock it again. { let mut wallet = self.wallet.write().unwrap(); @@ -672,7 +672,7 @@ impl LightClient { } } } - } + } { // Prevent any overlapping syncs during save, and don't save in the middle of a sync @@ -686,7 +686,7 @@ impl LightClient { let mut file = File::create(self.config.get_wallet_path()).unwrap(); file.write_all(&wallet_bytes).map_err(|e| format!("{}", e))?; Ok(()) - }, + }, Err(e) => { let err = format!("ERR: {}", e); error!("{}", err); @@ -715,7 +715,7 @@ impl LightClient { } } } - } + } let mut buffer: Vec = vec![]; match self.wallet.write().unwrap().write(&mut buffer) { @@ -774,7 +774,7 @@ impl LightClient { let wallet = self.wallet.read().unwrap(); wallet.txs.read().unwrap().iter() .flat_map( |(txid, wtx)| { - wtx.notes.iter().filter_map(move |nd| + wtx.notes.iter().filter_map(move |nd| if !all_notes && nd.spent.is_some() { None } else { @@ -801,16 +801,16 @@ impl LightClient { } }); } - + let mut unspent_utxos: Vec = vec![]; let mut spent_utxos : Vec = vec![]; let mut pending_utxos: Vec = vec![]; - + { let wallet = self.wallet.read().unwrap(); wallet.txs.read().unwrap().iter() .flat_map( |(txid, wtx)| { - wtx.utxos.iter().filter_map(move |utxo| + wtx.utxos.iter().filter_map(move |utxo| if !all_notes && utxo.spent.is_some() { None } else { @@ -945,12 +945,12 @@ impl LightClient { // Collect outgoing metadata let outgoing_json = wtx.outgoing_metadata.iter() - .map(|om| + .map(|om| object!{ "address" => om.address.clone(), "value" => om.value, "memo" => LightWallet::memo_str(&Some(om.memo.clone())), - }).collect::>(); + }).collect::>(); object! { "block_height" => wtx.block, @@ -1004,16 +1004,16 @@ impl LightClient { // Then set the initial block self.set_wallet_initial_state(self.wallet.read().unwrap().get_birthday()); - info!("Cleared wallet state"); + info!("Cleared wallet state"); } pub fn do_rescan(&self) -> Result { if !self.wallet.read().unwrap().is_unlocked_for_spending() { warn!("Wallet is locked, new HD addresses won't be added!"); } - + info!("Rescan starting"); - + self.clear_state(); // Then, do a sync, which will force a full rescan from the initial state @@ -1056,13 +1056,13 @@ impl LightClient { // Sync is 3 parts // 1. Get the latest block // 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 + // 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.read().unwrap().last_scanned_height() as u64; // This will hold the latest block fetched from the RPC let latest_block = fetch_latest_block(&self.get_server_uri())?.height; - + if latest_block < last_scanned_height { let w = format!("Server's latest block({}) is behind ours({})", latest_block, last_scanned_height); warn!("{}", w); @@ -1145,7 +1145,7 @@ impl LightClient { return; } - // Parse the block and save it's time. We'll use this timestamp for + // Parse the block and save it's time. We'll use this timestamp for // transactions in this block that might belong to us. let block: Result = parse_from_bytes(encoded_block); @@ -1172,13 +1172,13 @@ impl LightClient { { // println!("Total scan duration: {:?}", self.wallet.read().unwrap().total_scan_duration.read().unwrap().get(0).unwrap().as_millis()); - + let t = self.wallet.read().unwrap(); let mut d = t.total_scan_duration.write().unwrap(); d.clear(); d.push(std::time::Duration::new(0, 0)); } - + // 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); @@ -1192,8 +1192,8 @@ impl LightClient { if total_reorg > (crate::lightwallet::MAX_REORG - 1) as u64 { error!("Reorg has now exceeded {} blocks!", crate::lightwallet::MAX_REORG); return Err(format!("Reorg has exceeded {} blocks. Aborting.", crate::lightwallet::MAX_REORG)); - } - + } + if invalid_height > 0 { // Reset the scanning heights last_scanned_height = (invalid_height - 1) as u64; @@ -1204,17 +1204,17 @@ impl LightClient { continue; } - // If it got here, that means the blocks are scanning properly now. + // If it got here, that means the blocks are scanning properly now. // So, reset the total_reorg total_reorg = 0; // We'll also fetch all the txids that our transparent addresses are involved with { - // Copy over addresses so as to not lock up the wallet, which we'll use inside the callback below. + // 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::>(); - + // Create a channel so the fetch_transparent_txids can send the results back let (ctx, crx) = channel(); let num_addresses = addresses.len(); @@ -1236,7 +1236,7 @@ impl LightClient { let ctx = ctx.clone(); pool.execute(move || { - // Fetch the transparent transactions for this address, and send the results + // Fetch the transparent transactions for this address, and send the results // via the channel let r = fetch_transparent_txids(&server_uri, address, transparent_start_height, end_height, move |tx_bytes: &[u8], height: u64| { @@ -1244,17 +1244,17 @@ impl LightClient { // 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); + wallet.read().unwrap().scan_full_tx(&tx, height as i32, datetime as u64); }); ctx.send(r).unwrap(); }); } - // Collect all results from the transparent fetches, and make sure everything was OK. + // Collect all results from the transparent fetches, and make sure everything was OK. // If it was not, we return an error, which will go back to the retry crx.iter().take(num_addresses).collect::, String>>()?; - } - + } + // Do block height accounting last_scanned_height = end_height; end_height = last_scanned_height + 1000; @@ -1269,7 +1269,7 @@ impl LightClient { if print_updates{ println!(""); // New line to finish up the updates } - + info!("Synced to {}, Downloaded {} kB", latest_block, bytes_downloaded.load(Ordering::SeqCst) / 1024); { let mut status = self.sync_status.write().unwrap(); @@ -1292,13 +1292,13 @@ impl LightClient { txids_to_fetch.sort(); txids_to_fetch.dedup(); - let mut rng = OsRng; + let mut rng = OsRng; txids_to_fetch.shuffle(&mut rng); let num_fetches = txids_to_fetch.len(); let (ctx, crx) = channel(); - // And go and fetch the txids, getting the full transaction, so we can + // And go and fetch the txids, getting the full transaction, so we can // read the memos for (txid, height) in txids_to_fetch { let light_wallet_clone = self.wallet.clone(); @@ -1306,19 +1306,19 @@ impl LightClient { let pool = pool.clone(); let server_uri = self.get_server_uri(); let ctx = ctx.clone(); - + pool.execute(move || { info!("Fetching full Tx: {}", txid); match fetch_full_tx(&server_uri, txid) { Ok(tx_bytes) => { let tx = Transaction::read(&tx_bytes[..]).unwrap(); - + light_wallet_clone.read().unwrap().scan_full_tx(&tx, height, 0); ctx.send(Ok(())).unwrap(); }, Err(e) => ctx.send(Err(e)).unwrap() - }; + }; }); }; @@ -1331,7 +1331,7 @@ impl LightClient { "downloaded_bytes" => bytes_downloaded.load(Ordering::SeqCst) }), Err(e) => Err(format!("Error fetching all txns for memos: {}", e)) - } + } } pub fn do_send(&self, from: &str, addrs: Vec<(&str, u64, Option)>, fee: &u64) -> Result { @@ -1350,7 +1350,7 @@ impl LightClient { info!("Transaction Complete"); - + match rawtx { Ok(txbytes) => broadcast_raw_tx(&self.get_server_uri(), txbytes), Err(e) => Err(format!("Error: No Tx to broadcast. Error was: {}", e)) @@ -1393,27 +1393,27 @@ pub mod tests { // This will lock the wallet again, so after this, we'll need to unlock again assert!(!lc.do_new_address("t").is_err()); lc.wallet.write().unwrap().unlock("password".to_string()).unwrap(); - + assert!(!lc.do_new_address("z").is_err()); } #[test] pub fn test_addresses() { let lc = super::LightClient::unconnected(TEST_SEED.to_string(), None).unwrap(); - + { let addresses = lc.do_address(); // When restoring from seed, there should be 5+1 addresses assert_eq!(addresses["z_addresses"].len(), 6); assert_eq!(addresses["t_addresses"].len(), 6); } - + // Add new z and t addresses let taddr1 = lc.do_new_address("t").unwrap()[0].as_str().unwrap().to_string(); - let taddr2 = lc.do_new_address("t").unwrap()[0].as_str().unwrap().to_string(); + let taddr2 = lc.do_new_address("t").unwrap()[0].as_str().unwrap().to_string(); let zaddr1 = lc.do_new_address("z").unwrap()[0].as_str().unwrap().to_string(); let zaddr2 = lc.do_new_address("z").unwrap()[0].as_str().unwrap().to_string(); - + let addresses = lc.do_address(); assert_eq!(addresses["z_addresses"].len(), 8); assert_eq!(addresses["z_addresses"][6], zaddr1); @@ -1431,7 +1431,7 @@ pub mod tests { let lc = LightClient { wallet : Arc::new(RwLock::new(LightWallet::new(None, &config, 0).unwrap())), config : config, - sapling_output : vec![], + sapling_output : vec![], sapling_spend : vec![], sync_lock : Mutex::new(()), sync_status : Arc::new(RwLock::new(WalletStatus::new())), @@ -1523,8 +1523,8 @@ pub mod tests { use crate::SaplingParams; assert!(lc.set_sapling_params( - SaplingParams::get("sapling-output.params").unwrap().as_ref(), + SaplingParams::get("sapling-output.params").unwrap().as_ref(), SaplingParams::get("sapling-spend.params").unwrap().as_ref()).is_ok()); } -} \ No newline at end of file +} diff --git a/lib/src/lightwallet.rs b/lib/src/lightwallet.rs index 3e807a5..a39a8e1 100644 --- a/lib/src/lightwallet.rs +++ b/lib/src/lightwallet.rs @@ -99,16 +99,16 @@ impl ToBase58Check for [u8] { } pub struct LightWallet { - // Is the wallet encrypted? If it is, then when writing to disk, the seed is always encrypted - // and the individual spending keys are not written - encrypted: bool, + // Is the wallet encrypted? If it is, then when writing to disk, the seed is always encrypted + // and the individual spending keys are not written + encrypted: bool, // In memory only (i.e, this field is not written to disk). Is the wallet unlocked and are // the spending keys present to allow spending from this wallet? unlocked: bool, enc_seed: [u8; 48], // If locked, this contains the encrypted seed - nonce: Vec, // Nonce used to encrypt the wallet. + nonce: Vec, // Nonce used to encrypt the wallet. seed: [u8; 32], // Seed phrase for this wallet. If wallet is locked, this is 0 @@ -118,17 +118,17 @@ pub struct LightWallet { extfvks: Arc>>, pub zaddress: Arc>>>, - + // Transparent keys. If the wallet is locked, then the secret keys will be encrypted, - // but the addresses will be present. + // but the addresses will be present. tkeys: Arc>>, pub taddresses: Arc>>, blocks: Arc>>, pub txs: Arc>>, - // Transactions that are only in the mempool, but haven't been confirmed yet. - // This is not stored to disk. + // Transactions that are only in the mempool, but haven't been confirmed yet. + // This is not stored to disk. pub mempool_txs: Arc>>, // The block at which this wallet was born. Rescans @@ -163,7 +163,7 @@ impl LightWallet { fn get_zaddr_from_bip39seed(config: &LightClientConfig, bip39_seed: &[u8], pos: u32) -> (ExtendedSpendingKey, ExtendedFullViewingKey, PaymentAddress) { assert_eq!(bip39_seed.len(), 64); - + let extsk: ExtendedSpendingKey = ExtendedSpendingKey::from_path( &ExtendedSpendingKey::master(bip39_seed), &[ @@ -180,12 +180,12 @@ impl LightWallet { pub fn is_shielded_address(addr: &String, config: &LightClientConfig) -> bool { match address::RecipientAddress::from_str(addr, - config.hrp_sapling_address(), - config.base58_pubkey_address(), + config.hrp_sapling_address(), + config.base58_pubkey_address(), config.base58_script_address()) { Some(address::RecipientAddress::Shielded(_)) => true, _ => false, - } + } } pub fn new(seed_phrase: Option, config: &LightClientConfig, latest_block: u64) -> io::Result { @@ -193,7 +193,7 @@ impl LightWallet { let mut seed_bytes = [0u8; 32]; if seed_phrase.is_none() { - // Create a random seed. + // Create a random seed. let mut system_rng = OsRng; system_rng.fill(&mut seed_bytes); } else { @@ -205,11 +205,11 @@ impl LightWallet { return Err(io::Error::new(ErrorKind::InvalidData, e)); } }; - + seed_bytes.copy_from_slice(&phrase.entropy()); } - // The seed bytes is the raw entropy. To pass it to HD wallet generation, + // The seed bytes is the raw entropy. To pass it to HD wallet generation, // we need to get the 64 byte bip39 entropy let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&seed_bytes, Language::English).unwrap(), ""); @@ -217,7 +217,7 @@ impl LightWallet { 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 + // 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 let (extsk, extfvk, address) = LightWallet::get_zaddr_from_bip39seed(&config, &bip39_seed.as_bytes(), 0); @@ -262,7 +262,7 @@ impl LightWallet { println!("Reading wallet version {}", version); info!("Reading wallet version {}", version); - + // At version 5, we're writing the rest of the file as a compressed stream (gzip) let mut reader: Box = if version != 5 { info!("Reading direct"); @@ -278,12 +278,12 @@ impl LightWallet { false }; info!("Wallet Encryption {:?}", encrypted); - + let mut enc_seed = [0u8; 48]; if version >= 4 { reader.read_exact(&mut enc_seed)?; } - + let nonce = if version >= 4 { Vector::read(&mut reader, |r| r.read_u8())? } else { @@ -293,10 +293,10 @@ impl LightWallet { // Seed let mut seed_bytes = [0u8; 32]; reader.read_exact(&mut seed_bytes)?; - + // Read the spending keys let extsks = Vector::read(&mut reader, |r| ExtendedSpendingKey::read(r))?; - + let extfvks = if version >= 4 { // Read the viewing keys Vector::read(&mut reader, |r| ExtendedFullViewingKey::read(r))? @@ -305,7 +305,7 @@ impl LightWallet { extsks.iter().map(|sk| ExtendedFullViewingKey::from(sk)) .collect::>() }; - + // Calculate the addresses let addresses = extfvks.iter().map( |fvk| fvk.default_address().unwrap().1 ) .collect::>>(); @@ -314,8 +314,8 @@ impl LightWallet { let mut tpk_bytes = [0u8; 32]; r.read_exact(&mut tpk_bytes)?; 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))? @@ -323,9 +323,9 @@ impl LightWallet { // 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| { let mut txid_bytes = [0u8; 32]; r.read_exact(&mut txid_bytes)?; @@ -345,7 +345,7 @@ impl LightWallet { Ok(LightWallet{ encrypted: encrypted, - unlocked: !encrypted, // When reading from disk, if wallet is encrypted, it starts off locked. + unlocked: !encrypted, // When reading from disk, if wallet is encrypted, it starts off locked. enc_seed: enc_seed, nonce: nonce, seed: seed_bytes, @@ -365,7 +365,7 @@ impl LightWallet { pub fn write(&self, mut writer: W) -> io::Result<()> { if self.encrypted && self.unlocked { - return Err(Error::new(ErrorKind::InvalidInput, + return Err(Error::new(ErrorKind::InvalidInput, format!("Cannot write while wallet is unlocked while encrypted."))); } @@ -408,7 +408,7 @@ impl LightWallet { )?; Vector::write(&mut writer, &self.blocks.read().unwrap(), |w, b| b.write(w))?; - + // The hashmap, write as a set of tuples. Store them sorted so that wallets are // deterministically saved { @@ -471,7 +471,7 @@ 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), + (self.address_from_sk(sk), sk[..].to_base58check(&self.config.base58_secretkey_prefix(), &[0x01])) }).collect::>() } @@ -508,7 +508,7 @@ impl LightWallet { let pos = self.tkeys.read().unwrap().len() as u32; let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&self.seed, Language::English).unwrap(), ""); - + let sk = LightWallet::get_taddr_from_bip39seed(&self.config, &bip39_seed.as_bytes(), pos); let address = self.address_from_sk(&sk); @@ -637,7 +637,7 @@ impl LightWallet { 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 { match ta { Some(TransparentAddress::PublicKey(hash)) => { @@ -655,7 +655,7 @@ impl LightWallet { return "".to_string(); } - Mnemonic::from_entropy(&self.seed, + Mnemonic::from_entropy(&self.seed, Language::English, ).unwrap().phrase().to_string() } @@ -672,7 +672,7 @@ impl LightWallet { let nonce = secretbox::gen_nonce(); let cipher = secretbox::seal(&self.seed, &nonce, &key); - + self.enc_seed.copy_from_slice(&cipher); self.nonce = vec![]; self.nonce.extend_from_slice(nonce.as_ref()); @@ -725,7 +725,7 @@ impl LightWallet { // Now that we have the seed, we'll generate the extsks and tkeys, and verify the fvks and addresses // respectively match - // The seed bytes is the raw entropy. To pass it to HD wallet generation, + // The seed bytes is the raw entropy. To pass it to HD wallet generation, // we need to get the 64 byte bip39 entropy let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&seed, Language::English).unwrap(), ""); @@ -736,12 +736,12 @@ impl LightWallet { LightWallet::get_zaddr_from_bip39seed(&self.config, &bip39_seed.as_bytes(), pos as u32); if address != self.zaddress.read().unwrap()[pos] { - return Err(io::Error::new(ErrorKind::InvalidData, + return Err(io::Error::new(ErrorKind::InvalidData, format!("zaddress mismatch at {}. {:?} vs {:?}", pos, address, self.zaddress.read().unwrap()[pos]))); } if extfvk != self.extfvks.read().unwrap()[pos] { - return Err(io::Error::new(ErrorKind::InvalidData, + return Err(io::Error::new(ErrorKind::InvalidData, format!("fvk mismatch at {}. {:?} vs {:?}", pos, extfvk, self.extfvks.read().unwrap()[pos]))); } @@ -756,7 +756,7 @@ impl LightWallet { let address = self.address_from_sk(&sk); if address != self.taddresses.read().unwrap()[pos] { - return Err(io::Error::new(ErrorKind::InvalidData, + return Err(io::Error::new(ErrorKind::InvalidData, format!("taddress mismatch at {}. {} vs {}", pos, address, self.taddresses.read().unwrap()[pos]))); } @@ -767,7 +767,7 @@ impl LightWallet { self.extsks = Arc::new(RwLock::new(extsks)); self.tkeys = Arc::new(RwLock::new(tkeys)); self.seed.copy_from_slice(&seed); - + self.encrypted = true; self.unlocked = true; @@ -776,7 +776,7 @@ impl LightWallet { // Removing encryption means unlocking it and setting the self.encrypted = false, // permanantly removing the encryption - pub fn remove_encryption(&mut self, passwd: String) -> io::Result<()> { + pub fn remove_encryption(&mut self, passwd: String) -> io::Result<()> { if !self.encrypted { return Err(Error::new(ErrorKind::AlreadyExists, "Wallet is not encrypted")); } @@ -785,7 +785,7 @@ impl LightWallet { if !self.unlocked { self.unlock(passwd)?; } - + // Permanantly remove the encryption self.encrypted = false; self.nonce = vec![]; @@ -807,7 +807,7 @@ impl LightWallet { .values() .map(|tx| { tx.notes.iter() - .filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it. + .filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it. match addr.clone() { Some(a) => a == encode_payment_address( self.config.hrp_sapling_address(), @@ -861,7 +861,7 @@ impl LightWallet { if tx.block as u32 <= anchor_height { tx.notes .iter() - .filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it. + .filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it. match addr.clone() { Some(a) => a == encode_payment_address( self.config.hrp_sapling_address(), @@ -894,7 +894,7 @@ impl LightWallet { match tx_entry.utxos.iter().find(|utxo| { utxo.txid == *txid && utxo.output_index == n && Amount::from_u64(utxo.value).unwrap() == vout.value }) { - Some(utxo) => { + Some(utxo) => { info!("Already have {}:{}", utxo.txid, utxo.output_index); } None => { @@ -919,14 +919,14 @@ impl LightWallet { } } - // If one of the last 'n' taddress was used, ensure we add the next HD taddress to the wallet. - pub fn ensure_hd_taddresses(&self, address: &String) { + // If one of the last 'n' taddress was used, ensure we add the next HD taddress to the wallet. + pub fn ensure_hd_taddresses(&self, address: &String) { let last_addresses = { self.taddresses.read().unwrap().iter().rev().take(GAP_RULE_UNUSED_ADDRESSES).map(|s| s.clone()).collect::>() }; - + match last_addresses.iter().position(|s| *s == *address) { - None => { + None => { return; }, Some(pos) => { @@ -935,7 +935,7 @@ impl LightWallet { for _ in 0..(GAP_RULE_UNUSED_ADDRESSES - pos) { // If the wallet is locked, this is a no-op. That is fine, since we really // need to only add new addresses when restoring a new wallet, when it will not be locked. - // Also, if it is locked, the user can't create new addresses anyway. + // Also, if it is locked, the user can't create new addresses anyway. self.add_taddr(); } } @@ -949,7 +949,7 @@ impl LightWallet { .map(|s| encode_payment_address(self.config.hrp_sapling_address(), s)) .collect::>() }; - + match last_addresses.iter().position(|s| *s == *address) { None => { return; @@ -960,7 +960,7 @@ impl LightWallet { for _ in 0..(GAP_RULE_UNUSED_ADDRESSES - pos) { // If the wallet is locked, this is a no-op. That is fine, since we really // need to only add new addresses when restoring a new wallet, when it will not be locked. - // Also, if it is locked, the user can't create new addresses anyway. + // Also, if it is locked, the user can't create new addresses anyway. self.add_zaddr(); } } @@ -1006,7 +1006,7 @@ impl LightWallet { let tx_entry = WalletTx::new(height, datetime, &tx.txid()); txs.insert(tx.txid().clone(), tx_entry); } - + txs.get_mut(&tx.txid()).unwrap() .total_transparent_value_spent = total_transparent_spend; } @@ -1093,11 +1093,11 @@ impl LightWallet { { info!("A sapling note was sent in {}, getting memo", tx.txid()); - - // Do it in a short scope because of the write lock. + + // Do it in a short scope because of the write lock. let mut txs = self.txs.write().unwrap(); - // Update memo if we have this Tx. + // Update memo if we have this Tx. match txs.get_mut(&tx.txid()) .and_then(|t| { t.notes.iter_mut().find(|nd| nd.note == note) @@ -1127,13 +1127,13 @@ impl LightWallet { for (_account, ovk) in ovks.iter().enumerate() { match try_sapling_output_recovery(ovk, - &output.cv, - &output.cmu, - &output.ephemeral_key.as_prime_order(&JUBJUB).unwrap(), + &output.cv, + &output.cmu, + &output.ephemeral_key.as_prime_order(&JUBJUB).unwrap(), &output.enc_ciphertext, &output.out_ciphertext) { Some((note, payment_address, memo)) => { - let address = encode_payment_address(self.config.hrp_sapling_address(), + let address = encode_payment_address(self.config.hrp_sapling_address(), &payment_address); // Check if this is a change address @@ -1183,9 +1183,9 @@ impl LightWallet { let mut num_invalidated = 0; // First remove the blocks - { + { let mut blks = self.blocks.write().unwrap(); - + while blks.last().unwrap().height >= at_height { blks.pop(); num_invalidated += 1; @@ -1232,7 +1232,7 @@ impl LightWallet { } } } - + num_invalidated as u64 } @@ -1275,7 +1275,7 @@ impl LightWallet { tx.send(Some(None)) } }; - + match r { Ok(_) => {}, Err(e) => println!("Send error {:?}", e) @@ -1301,7 +1301,7 @@ impl LightWallet { for _i in 0..ivks.len() { let n = rx.recv().unwrap(); let epk = epk.clone(); - + let wso = match n { None => panic!("Got a none!"), Some(None) => None, @@ -1313,7 +1313,7 @@ impl LightWallet { // - Notes created by consolidation transactions. // - Notes sent from one account to itself. //let is_change = spent_from_accounts.contains(&account); - + Some(WalletShieldedOutput { index, cmu, epk, account, note, to, is_change: false, witness: IncrementalWitness::from_tree(tree), @@ -1322,7 +1322,7 @@ impl LightWallet { }; wsos.push(wso); } - + match wsos.into_iter().find(|wso| wso.is_some()) { Some(Some(wso)) => Some(wso), _ => None @@ -1513,12 +1513,12 @@ impl LightWallet { .map(|block| block.tree.clone()) .unwrap_or(CommitmentTree::new()), }; - + // These are filled in inside the block let new_txs; let nfs: Vec<_>; { - // Create a write lock + // Create a write lock let mut txs = self.txs.write().unwrap(); // Create a Vec containing all unspent nullifiers. @@ -1574,8 +1574,8 @@ impl LightWallet { ) }; } - - // If this block had any new Txs, return the list of ALL txids in this block, + + // If this block had any new Txs, return the list of ALL txids in this block, // so the wallet can fetch them all as a decoy. let all_txs = if !new_txs.is_empty() { block.vtx.iter().map(|vtx| { @@ -1588,7 +1588,7 @@ impl LightWallet { }; for tx in new_txs { - // Create a write lock + // Create a write lock let mut txs = self.txs.write().unwrap(); // Mark notes as spent. @@ -1596,7 +1596,7 @@ impl LightWallet { info!("Txid {} belongs to wallet", tx.txid); - for spend in &tx.shielded_spends { + for spend in &tx.shielded_spends { let txid = nfs .iter() .find(|(nf, _, _)| &nf[..] == &spend.nf[..]) @@ -1609,7 +1609,7 @@ impl LightWallet { .iter_mut() .find(|nd| &nd.nullifier[..] == &spend.nf[..]) .unwrap(); - + // Mark the note as spent, and remove the unconfirmed part of it info!("Marked a note as spent"); spent_note.spent = Some(tx.txid); @@ -1641,13 +1641,13 @@ impl LightWallet { match tx_entry.notes.iter().find(|nd| nd.nullifier == new_note.nullifier) { None => tx_entry.notes.push(new_note), Some(_) => warn!("Tried to insert duplicate note for Tx {}", tx.txid) - }; + }; } } { let mut blks = self.blocks.write().unwrap(); - + // Store scanned data for this block. blks.push(block_data); @@ -1658,7 +1658,7 @@ impl LightWallet { blks.drain(..drain_first); } } - + { // Cleanup mempool tx after adding a block, to remove all txns that got mined self.cleanup_mempool(); @@ -1701,9 +1701,9 @@ impl LightWallet { // Convert address (str) to RecepientAddress and value to Amount let recepients = tos.iter().map(|to| { - let ra = match address::RecipientAddress::from_str(to.0, - self.config.hrp_sapling_address(), - self.config.base58_pubkey_address(), + let ra = match address::RecipientAddress::from_str(to.0, + self.config.hrp_sapling_address(), + self.config.base58_pubkey_address(), self.config.base58_script_address()) { Some(to) => to, None => { @@ -1756,8 +1756,8 @@ impl LightWallet { builder.set_fee(Amount::from_u64(*fee).unwrap()); // A note on t addresses - // Funds received by t-addresses can't be explicitly spent in ZecWallet. - // ZecWallet will lazily consolidate all t address funds into your shielded addresses. + // Funds received by t-addresses can't be explicitly spent in ZecWallet. + // ZecWallet will lazily consolidate all t address funds into your shielded addresses. // Specifically, if you send an outgoing transaction that is sent to a shielded address, // ZecWallet will add all your t-address funds into that transaction, and send them to your shielded // address as change. @@ -1766,8 +1766,8 @@ impl LightWallet { .filter(|utxo| utxo.unconfirmed_spent.is_none()) // Remove any unconfirmed spends .map(|utxo| utxo.clone()) .collect(); - - // Create a map from address -> sk for all taddrs, so we can spend from the + + // Create a map from address -> sk for all taddrs, so we can spend from the // right address let address_to_sk = self.tkeys.read().unwrap().iter() .map(|sk| (self.address_from_sk(&sk), sk.clone())) @@ -1777,7 +1777,7 @@ impl LightWallet { tinputs.iter() .map(|utxo| { let outpoint: OutPoint = utxo.to_outpoint(); - + let coin = TxOut { value: Amount::from_u64(utxo.value).unwrap(), script_pubkey: Script { 0: utxo.script.clone() }, @@ -1793,14 +1793,14 @@ impl LightWallet { Err(zcash_primitives::transaction::builder::Error::InvalidAddress) } } - + }) .collect::, _>>() .map_err(|e| format!("{:?}", e))?; - + // Confirm we were able to select sufficient value - let selected_value = notes.iter().map(|selected| selected.note.value).sum::() + let selected_value = notes.iter().map(|selected| selected.note.value).sum::() + tinputs.iter().map::(|utxo| utxo.value.into()).sum::(); if selected_value < u64::from(target_value) { @@ -1895,7 +1895,7 @@ impl LightWallet { return Err(e); } } - + println!("{}: Building transaction", now() - start_time); let (tx, _) = match builder.build( @@ -1952,7 +1952,7 @@ impl LightWallet { Memo::from_bytes(s.as_bytes()).unwrap() } else { Memo::default() - } + } } }, } @@ -1962,7 +1962,7 @@ impl LightWallet { let mut wtx = WalletTx::new(height as i32, now() as u64, &tx.txid()); wtx.outgoing_metadata = outgoing_metadata; - // Add it into the mempool + // Add it into the mempool mempool_txs.insert(tx.txid(), wtx); }, Some(_) => { @@ -1989,7 +1989,7 @@ impl LightWallet { { // Remove all expired Txns self.mempool_txs.write().unwrap().retain( | _, wtx| { - current_height < (wtx.block + DEFAULT_TX_EXPIRY_DELTA) + current_height < (wtx.block + DEFAULT_TX_EXPIRY_DELTA) }); } @@ -2003,4 +2003,4 @@ impl LightWallet { } #[cfg(test)] -pub mod tests; \ No newline at end of file +pub mod tests; diff --git a/lib/src/lightwallet/bugs.rs b/lib/src/lightwallet/bugs.rs index e81642f..2aab2ec 100644 --- a/lib/src/lightwallet/bugs.rs +++ b/lib/src/lightwallet/bugs.rs @@ -1,10 +1,10 @@ /// -/// In v1.0 of zecwallet-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the -/// first key, address was correct, but subsequent ones were not. -/// -/// The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the +/// In v1.0 of zecwallet-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the +/// first key, address was correct, but subsequent ones were not. +/// +/// The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the /// 64-byte pkdf2(seed). The issue affected both t and z addresses -/// +/// /// To fix the bug, we need to: /// 1. Check if the wallet has more than 1 address for t or z addresses /// 2. Move any funds in these addresses to the first address @@ -32,7 +32,7 @@ impl BugBip39Derivation { return false; } - // The seed bytes is the raw entropy. To pass it to HD wallet generation, + // The seed bytes is the raw entropy. To pass it to HD wallet generation, // we need to get the 64 byte bip39 entropy let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&wallet.seed, Language::English).unwrap(), ""); @@ -70,13 +70,13 @@ impl BugBip39Derivation { }; return r.pretty(2); - } - + } + // Tranfer money // 1. The desination is z address #0 let zaddr = client.do_address()["z_addresses"][0].as_str().unwrap().to_string(); let balance_json = client.do_balance(); - let amount: u64 = balance_json["zbalance"].as_u64().unwrap() + let amount: u64 = balance_json["zbalance"].as_u64().unwrap() + balance_json["tbalance"].as_u64().unwrap(); let txid = if amount > 0 { @@ -127,4 +127,4 @@ impl BugBip39Derivation { return r.pretty(2); } -} \ No newline at end of file +} diff --git a/lib/src/lightwallet/data.rs b/lib/src/lightwallet/data.rs index 1acc84e..89f9980 100644 --- a/lib/src/lightwallet/data.rs +++ b/lib/src/lightwallet/data.rs @@ -10,7 +10,7 @@ use zcash_primitives::{ sapling::Node, serialize::{Vector, Optional}, transaction::{ - components::{OutPoint}, + components::{OutPoint}, TxId, }, note_encryption::{Memo,},