From ef9fcceb8c1aa62bdb27c8119ba63418190e542b Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Fri, 4 Oct 2019 21:18:01 -0700 Subject: [PATCH] Multi spend test --- src/lightwallet.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/src/lightwallet.rs b/src/lightwallet.rs index dcfe717..800f54a 100644 --- a/src/lightwallet.rs +++ b/src/lightwallet.rs @@ -2539,6 +2539,143 @@ pub mod tests { } + #[test] + fn test_multi_spends() { + const AMOUNT1: u64 = 50000; + let (wallet, txid1, block_hash) = get_test_wallet(AMOUNT1); + + let zaddr2 = wallet.add_zaddr(); + const ZAMOUNT2:u64 = 30; + let outgoing_memo2 = "Outgoing Memo2".to_string(); + + let zaddr3 = wallet.add_zaddr(); + const ZAMOUNT3:u64 = 40; + let outgoing_memo3 = "Outgoing Memo3".to_string(); + + let taddr2 = wallet.add_taddr(); + const TAMOUNT2:u64 = 50; + let taddr3 = wallet.add_taddr(); + const TAMOUNT3:u64 = 60; + + let fee: u64 = DEFAULT_FEE.try_into().unwrap(); + + let branch_id = u32::from_str_radix("2bb40e60", 16).unwrap(); + let (ss, so) = get_sapling_params().unwrap(); + + let tos = vec![ (zaddr2.as_str(), ZAMOUNT2, Some(outgoing_memo2.clone())), + (zaddr3.as_str(), ZAMOUNT3, Some(outgoing_memo3.clone())), + (taddr2.as_str(), TAMOUNT2, None), + (taddr3.as_str(), TAMOUNT3, None) ]; + + let raw_tx = wallet.send_to_address(branch_id, &ss, &so, tos).unwrap(); + let sent_tx = Transaction::read(&raw_tx[..]).unwrap(); + let sent_txid = sent_tx.txid(); + + let mut cb3 = FakeCompactBlock::new(2, block_hash); + cb3.add_tx(&sent_tx); + wallet.scan_block(&cb3.as_bytes()).unwrap(); + wallet.scan_full_tx(&sent_tx, 2); + + // Make sure all the outputs are there! + { + let txs = wallet.txs.read().unwrap(); + + // The single note was spent + assert_eq!(txs[&txid1].notes[0].note.value, AMOUNT1); + assert_eq!(txs[&txid1].notes[0].spent, Some(sent_txid)); + + // The outputs are all sent to the wallet, so they should + // correspond to notes & utxos. + // 2 notes + 1 change + assert_eq!(txs[&sent_txid].notes.len(), 3); + + // Find the change note + let change_note = txs[&sent_txid].notes.iter().find(|n| n.is_change).unwrap(); + assert_eq!(change_note.note.value, AMOUNT1 - (ZAMOUNT2+ZAMOUNT3+TAMOUNT2+TAMOUNT3+fee)); + assert_eq!(change_note.spent, None); + assert_eq!(change_note.unconfirmed_spent, None); + + // Find zaddr2 + let zaddr2_note = txs[&sent_txid].notes.iter().find(|n| n.note.value == ZAMOUNT2).unwrap(); + assert_eq!(zaddr2_note.account, 2-1); + assert_eq!(zaddr2_note.is_change, false); + assert_eq!(zaddr2_note.spent, None); + assert_eq!(zaddr2_note.unconfirmed_spent, None); + assert_eq!(LightWallet::memo_str(&zaddr2_note.memo), Some(outgoing_memo2)); + + // Find zaddr3 + let zaddr3_note = txs[&sent_txid].notes.iter().find(|n| n.note.value == ZAMOUNT3).unwrap(); + assert_eq!(zaddr3_note.account, 3-1); + assert_eq!(zaddr3_note.is_change, false); + assert_eq!(zaddr3_note.spent, None); + assert_eq!(zaddr3_note.unconfirmed_spent, None); + assert_eq!(LightWallet::memo_str(&zaddr3_note.memo), Some(outgoing_memo3)); + + // Find taddr2 + let utxo2 = txs[&sent_txid].utxos.iter().find(|u| u.value == TAMOUNT2).unwrap(); + assert_eq!(utxo2.address, taddr2); + assert_eq!(utxo2.txid, sent_txid); + assert_eq!(utxo2.spent, None); + assert_eq!(utxo2.unconfirmed_spent, None); + + // Find taddr3 + let utxo3 = txs[&sent_txid].utxos.iter().find(|u| u.value == TAMOUNT3).unwrap(); + assert_eq!(utxo3.address, taddr3); + assert_eq!(utxo3.txid, sent_txid); + assert_eq!(utxo3.spent, None); + assert_eq!(utxo3.unconfirmed_spent, None); + } + + // Now send an outgoing tx to one ext taddr and one ext zaddr + let fvk = ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[1u8; 32])); + let ext_address = encode_payment_address(wallet.config.hrp_sapling_address(), + &fvk.default_address().unwrap().1); + let ext_memo = "External memo".to_string(); + let ext_taddr = wallet.address_from_sk(&SecretKey::from_slice(&[1u8; 32]).unwrap()); + + const EXT_ZADDR_AMOUNT: u64 = 3000; + let ext_taddr_amount = AMOUNT1 - TAMOUNT2 - TAMOUNT3 - fee - EXT_ZADDR_AMOUNT - fee; // Spend everything + println!("taddr amount {}", ext_taddr_amount); + + let tos = vec![ (ext_address.as_str(), EXT_ZADDR_AMOUNT, Some(ext_memo.clone())), + (ext_taddr.as_str(), ext_taddr_amount, None)]; + let raw_tx = wallet.send_to_address(branch_id, &ss, &so, tos).unwrap(); + let sent_tx = Transaction::read(&raw_tx[..]).unwrap(); + let sent_txid2 = sent_tx.txid(); + + let mut cb4 = FakeCompactBlock::new(3, cb3.hash()); + cb4.add_tx(&sent_tx); + wallet.scan_block(&cb4.as_bytes()).unwrap(); + wallet.scan_full_tx(&sent_tx, 3); + + // Make sure all the outputs are there! + { + let txs = wallet.txs.read().unwrap(); + + // All notes were spent + assert_eq!(txs[&sent_txid].notes[0].spent, Some(sent_txid2)); + assert_eq!(txs[&sent_txid].notes[1].spent, Some(sent_txid2)); + assert_eq!(txs[&sent_txid].notes[2].spent, Some(sent_txid2)); + + // All utxos were NOT spent, since this outgoing Tx to a t addr + + // The new tx has no change + assert_eq!(txs[&sent_txid2].notes.len(), 0); + assert_eq!(txs[&sent_txid2].utxos.len(), 0); + + // Test the outgoing metadata + // Find the znote + let zoutgoing = txs[&sent_txid2].outgoing_metadata.iter().find(|o| o.address == ext_address).unwrap(); + assert_eq!(zoutgoing.value, EXT_ZADDR_AMOUNT); + assert_eq!(LightWallet::memo_str(&Some(zoutgoing.memo.clone())), Some(ext_memo)); + + // Find the taddr + let toutgoing = txs[&sent_txid2].outgoing_metadata.iter().find(|o| o.address == ext_taddr).unwrap(); + assert_eq!(toutgoing.value, ext_taddr_amount); + assert_eq!(LightWallet::memo_str(&Some(toutgoing.memo.clone())), None); + } + } + /// Test helper to add blocks fn add_blocks(wallet: &LightWallet, start: i32, num: i32, mut prev_hash: BlockHash) -> Result{ // Add it to a block