From cde6615126f43e78e205255b87d245f20575a5c5 Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Sat, 2 Mar 2024 08:35:53 -0500 Subject: [PATCH 1/6] Removed is_utxo_our_method and refactored wallet api --- src/wallet/api.rs | 370 ++++++++++++++++++++++++++---------------- src/wallet/storage.rs | 29 ++-- 2 files changed, 245 insertions(+), 154 deletions(-) diff --git a/src/wallet/api.rs b/src/wallet/api.rs index 6431177a..fb1a4dbd 100644 --- a/src/wallet/api.rs +++ b/src/wallet/api.rs @@ -281,7 +281,7 @@ impl Wallet { println!( "[{}] locktime={}", Address::from_script(&bond.script_pub_key(), self.store.network).unwrap(), - locktime, + locktime ); } } @@ -442,6 +442,27 @@ impl Wallet { .fold(Amount::ZERO, |a, (utxo, _)| a + utxo.amount)) } + pub fn balance_fidelity_bonds(&self) -> Result { + Ok(self + .list_fidelity_unspend_from_wallet()? + .iter() + .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) + } + + pub fn balance_live_transaction(&self) -> Result { + Ok(self + .list_live_contract_unspend_from_wallet()? + .iter() + .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) + } + + pub fn balance_descriptor_utxo_or_swap_coins(&self) -> Result { + Ok(self + .list_descriptor_utxo_or_swap_coin_unspend_from_wallet()? + .iter() + .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) + } + /// Checks if the previous output (prevout) matches the cached contract in the wallet. /// /// This function is used in two scenarios: @@ -640,9 +661,11 @@ impl Wallet { let result = self.rpc.import_multi( &import_requests, - Some(&ImportMultiOptions { - rescan: Some(false), - }), + Some( + &(ImportMultiOptions { + rescan: Some(false), + }), + ), )?; // Only hard error if it errors, or else log the warning @@ -687,100 +710,6 @@ impl Wallet { .collect::>() } - fn is_utxo_ours_and_spendable_get_pointer( - &self, - u: &ListUnspentResultEntry, - option_contract_scriptpubkeys_outgoing_swapcoins: Option< - &HashMap, - >, - option_contract_scriptpubkeys_incoming_swapcoins: Option< - &HashMap, - >, - include_all_fidelity_bonds: bool, - ) -> Option { - if include_all_fidelity_bonds { - if let Some((i, (b, _, _))) = self.store.fidelity_bond.iter().find(|(_, (b, _, _))| { - b.script_pub_key() == u.script_pub_key && b.amount == u.amount.to_sat() - }) { - return Some(UTXOSpendInfo::FidelityBondCoin { - index: *i, - input_value: b.amount, - }); - } - } - - if u.descriptor.is_none() { - if let Some(map) = option_contract_scriptpubkeys_outgoing_swapcoins { - if let Some(swapcoin) = map.get(&u.script_pub_key) { - let timelock = swapcoin.get_timelock(); - if u.confirmations >= timelock.into() { - return Some(UTXOSpendInfo::TimelockContract { - swapcoin_multisig_redeemscript: swapcoin.get_multisig_redeemscript(), - input_value: u.amount.to_sat(), - }); - } - } - } - if let Some(map) = option_contract_scriptpubkeys_incoming_swapcoins { - if let Some(swapcoin) = map.get(&u.script_pub_key) { - if swapcoin.is_hash_preimage_known() && u.confirmations >= 1 { - return Some(UTXOSpendInfo::HashlockContract { - swapcoin_multisig_redeemscript: swapcoin.get_multisig_redeemscript(), - input_value: u.amount.to_sat(), - }); - } - } - } - return None; - } - let descriptor = u.descriptor.as_ref().unwrap(); - if let Some(ret) = get_hd_path_from_descriptor(descriptor) { - //utxo is in a hd wallet - let (fingerprint, addr_type, index) = ret; - - let secp = Secp256k1::new(); - let master_private_key = self - .store - .master_key - .derive_priv( - &secp, - &DerivationPath::from_str(HARDENDED_DERIVATION).unwrap(), - ) - .unwrap(); - if fingerprint == master_private_key.fingerprint(&secp).to_string() { - Some(UTXOSpendInfo::SeedCoin { - path: format!("m/{}/{}", addr_type, index), - input_value: u.amount.to_sat(), - }) - } else { - None - } - } else { - //utxo might be one of our swapcoins - let found = self - .find_incoming_swapcoin( - u.witness_script - .as_ref() - .unwrap_or(&ScriptBuf::from(Vec::from_hex("").unwrap())), - ) - .map_or(false, |sc| sc.other_privkey.is_some()) - || self - .find_outgoing_swapcoin( - u.witness_script - .as_ref() - .unwrap_or(&ScriptBuf::from(Vec::from_hex("").unwrap())), - ) - .map_or(false, |sc| sc.hash_preimage.is_some()); - if found { - Some(UTXOSpendInfo::SwapCoin { - multisig_redeemscript: u.witness_script.as_ref().unwrap().clone(), - }) - } else { - None - } - } - } - /// Locks all non-wallet unspent transaction outputs (UTXOs) & returns a `WalletError` /// if there is an issue with the RPC call or locking the UTXOs. pub fn lock_all_nonwallet_unspents(&self) -> Result<(), WalletError> { @@ -794,10 +723,7 @@ impl Wallet { .list_unspent(Some(0), Some(9999999), None, None, None)?; let utxos_to_lock = &all_unspents .into_iter() - .filter(|u| { - self.is_utxo_ours_and_spendable_get_pointer(u, None, None, false) - .is_none() - }) + .filter(|u| self.check_descriptor_utxo_or_swap_coin(u).is_none()) .map(|u| OutPoint { txid: u.txid, vout: u.vout, @@ -807,49 +733,217 @@ impl Wallet { Ok(()) } + fn check_fidelity_bonds(&self, utxo: &ListUnspentResultEntry) -> Option { + self.store + .fidelity_bond + .iter() + .find_map(|(i, (bond, _, _))| { + if bond.script_pub_key() == utxo.script_pub_key + && bond.amount == utxo.amount.to_sat() + { + Some(UTXOSpendInfo::FidelityBondCoin { + index: *i, + input_value: bond.amount, + }) + } else { + None + } + }) + } + + fn check_live_contracts( + &self, + utxo: &ListUnspentResultEntry, + contract_scriptpubkeys_outgoing: &HashMap, + contract_scriptpubkeys_incoming: &HashMap, + ) -> Option { + if let Some(outgoing_swapcoin) = contract_scriptpubkeys_outgoing.get(&utxo.script_pub_key) { + if utxo.confirmations >= outgoing_swapcoin.get_timelock().into() { + return Some(UTXOSpendInfo::TimelockContract { + swapcoin_multisig_redeemscript: outgoing_swapcoin.get_multisig_redeemscript(), + input_value: utxo.amount.to_sat(), + }); + } + } else if let Some(incoming_swapcoin) = + contract_scriptpubkeys_incoming.get(&utxo.script_pub_key) + { + if incoming_swapcoin.is_hash_preimage_known() && utxo.confirmations >= 1 { + return Some(UTXOSpendInfo::HashlockContract { + swapcoin_multisig_redeemscript: incoming_swapcoin.get_multisig_redeemscript(), + input_value: utxo.amount.to_sat(), + }); + } + } + None + } + + fn check_descriptor_utxo_or_swap_coin( + &self, + utxo: &ListUnspentResultEntry, + ) -> Option { + if let Some(descriptor) = &utxo.descriptor { + // Descriptor logic here + if let Some(ret) = get_hd_path_from_descriptor(descriptor) { + //utxo is in a hd wallet + let (fingerprint, addr_type, index) = ret; + + let secp = Secp256k1::new(); + let master_private_key = self + .store + .master_key + .derive_priv( + &secp, + &DerivationPath::from_str(HARDENDED_DERIVATION).unwrap(), + ) + .unwrap(); + if fingerprint == master_private_key.fingerprint(&secp).to_string() { + return Some(UTXOSpendInfo::SeedCoin { + path: format!("m/{}/{}", addr_type, index), + input_value: utxo.amount.to_sat(), + }); + } + } else { + //utxo might be one of our swapcoins + let found = self + .find_incoming_swapcoin( + utxo.witness_script + .as_ref() + .unwrap_or(&ScriptBuf::from(Vec::from_hex("").unwrap())), + ) + .map_or(false, |sc| sc.other_privkey.is_some()) + || self + .find_outgoing_swapcoin( + utxo.witness_script + .as_ref() + .unwrap_or(&ScriptBuf::from(Vec::from_hex("").unwrap())), + ) + .map_or(false, |sc| sc.hash_preimage.is_some()); + if found { + return Some(UTXOSpendInfo::SwapCoin { + multisig_redeemscript: utxo.witness_script.as_ref().unwrap().clone(), + }); + } + }; + } + None + } + /// Lists UTXOs from the wallet, optionally including live contracts and fidelity bonds. + /// Simplified method to list UTXOs from the wallet, integrating the logic directly. pub fn list_unspent_from_wallet( &self, include_live_contracts: bool, include_fidelity_bonds: bool, ) -> Result, WalletError> { - let (contract_scriptpubkeys_outgoing_swapcoins, contract_scriptpubkeys_incoming_swapcoins) = + let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = if include_live_contracts { ( self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), self.create_contract_scriptpubkey_incoming_swapcoin_hashmap(), ) } else { - (HashMap::<_, _>::new(), HashMap::<_, _>::new()) + (HashMap::new(), HashMap::new()) }; + self.rpc .call::("lockunspent", &[Value::Bool(true)])?; - Ok(self + let all_utxos = self .rpc - .list_unspent(Some(0), Some(9999999), None, None, None)? + .list_unspent(Some(0), Some(9999999), None, None, None)?; + + let processed_utxos = all_utxos .iter() - .map(|u| { - ( - u, - self.is_utxo_ours_and_spendable_get_pointer( - u, - if include_live_contracts { - Some(&contract_scriptpubkeys_outgoing_swapcoins) - } else { - None - }, - if include_live_contracts { - Some(&contract_scriptpubkeys_incoming_swapcoins) - } else { - None - }, - include_fidelity_bonds, - ), - ) + .filter_map(|utxo| { + let mut spend_info = if include_fidelity_bonds { + self.check_fidelity_bonds(utxo) + } else { + None + }; + + if spend_info.is_none() && utxo.descriptor.is_none() { + spend_info = self.check_live_contracts( + utxo, + &contract_scriptpubkeys_outgoing, + &contract_scriptpubkeys_incoming, + ); + } + + if spend_info.is_none() { + spend_info = self.check_descriptor_utxo_or_swap_coin(utxo); + } + + spend_info.map(|info| (utxo.clone(), info)) + }) + .collect::>(); + + Ok(processed_utxos) + } + + pub fn list_live_contract_unspend_from_wallet( + &self, + ) -> Result, WalletError> { + let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = ( + self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), + self.create_contract_scriptpubkey_incoming_swapcoin_hashmap(), + ); + self.rpc + .call::("lockunspent", &[Value::Bool(true)])?; + let all_utxos = self + .rpc + .list_unspent(Some(0), Some(9999999), None, None, None)?; + let processed_utxos = all_utxos + .iter() + .filter_map(|utxo| { + let spend_info = self.check_live_contracts( + utxo, + &contract_scriptpubkeys_outgoing, + &contract_scriptpubkeys_incoming, + ); + + spend_info.map(|info| (utxo.clone(), info)) + }) + .collect::>(); + + Ok(processed_utxos) + } + + pub fn list_fidelity_unspend_from_wallet( + &self, + ) -> Result, WalletError> { + self.rpc + .call::("lockunspent", &[Value::Bool(true)])?; + let all_utxos = self + .rpc + .list_unspent(Some(0), Some(9999999), None, None, None)?; + let processed_utxos = all_utxos + .iter() + .filter_map(|utxo| { + let spend_info = self.check_fidelity_bonds(utxo); + + spend_info.map(|info| (utxo.clone(), info)) + }) + .collect::>(); + + Ok(processed_utxos) + } + + pub fn list_descriptor_utxo_or_swap_coin_unspend_from_wallet( + &self, + ) -> Result, WalletError> { + self.rpc + .call::("lockunspent", &[Value::Bool(true)])?; + let all_utxos = self + .rpc + .list_unspent(Some(0), Some(9999999), None, None, None)?; + let processed_utxos = all_utxos + .iter() + .filter_map(|utxo| { + let spend_info = self.check_descriptor_utxo_or_swap_coin(utxo); + spend_info.map(|info| (utxo.clone(), info)) }) - .filter(|(_u, o_info)| o_info.is_some()) - .map(|(u, o_info)| (u.clone(), o_info.unwrap())) - .collect::>()) + .collect::>(); + + Ok(processed_utxos) } /// Finds incomplete coin swaps in the wallet. @@ -971,7 +1065,7 @@ impl Wallet { u, ) }) - .filter(|isc_osc_u| isc_osc_u.0.is_some() || isc_osc_u.1.is_some()) + .filter(|isc_osc_u| (isc_osc_u.0.is_some() || isc_osc_u.1.is_some())) .partition(|isc_osc_u| isc_osc_u.0.is_some()); Ok(( @@ -990,7 +1084,7 @@ impl Wallet { pub(super) fn find_hd_next_index(&self, keychain: KeychainKind) -> Result { let mut max_index: i32 = -1; //TODO error handling - let utxos = self.list_unspent_from_wallet(false, false)?; + let utxos = self.list_descriptor_utxo_or_swap_coin_unspend_from_wallet()?; for (utxo, _) in utxos { if utxo.descriptor.is_none() { continue; @@ -1044,7 +1138,7 @@ impl Wallet { /// Refreshes the offer maximum size cache based on the current wallet's unspent transaction outputs (UTXOs). pub fn refresh_offer_maxsize_cache(&mut self) -> Result<(), WalletError> { - let utxos = self.list_unspent_from_wallet(false, false)?; + let utxos = self.list_descriptor_utxo_or_swap_coin_unspend_from_wallet()?; let balance: Amount = utxos.iter().fold(Amount::ZERO, |acc, u| acc + u.0.amount); self.store.offer_maxsize = balance.to_sat(); Ok(()) @@ -1432,9 +1526,11 @@ impl Wallet { label: Some(address_label), ..Default::default() }], - Some(&ImportMultiOptions { - rescan: Some(false), - }), + Some( + &(ImportMultiOptions { + rescan: Some(false), + }), + ), ) .unwrap(); for r in result { @@ -1464,9 +1560,11 @@ impl Wallet { label: Some(address_label), ..Default::default() }], - Some(&ImportMultiOptions { - rescan: Some(false), - }), + Some( + &(ImportMultiOptions { + rescan: Some(false), + }), + ), )?; for r in result { if !r.success { diff --git a/src/wallet/storage.rs b/src/wallet/storage.rs index de9a247d..44464a45 100644 --- a/src/wallet/storage.rs +++ b/src/wallet/storage.rs @@ -2,19 +2,16 @@ //! //! Wallet data is currently written in unencrypted CBOR files which are not directly human readable. -use std::{collections::HashMap, path::PathBuf}; +use std::{ collections::HashMap, path::PathBuf }; use bip39::Mnemonic; -use bitcoin::{bip32::ExtendedPrivKey, Network, OutPoint, ScriptBuf}; -use serde::{Deserialize, Serialize}; -use std::{ - fs::OpenOptions, - io::{BufReader, BufWriter}, -}; +use bitcoin::{ bip32::ExtendedPrivKey, Network, OutPoint, ScriptBuf }; +use serde::{ Deserialize, Serialize }; +use std::{ fs::OpenOptions, io::{ BufReader, BufWriter } }; -use super::{error::WalletError, fidelity::FidelityBond}; +use super::{ error::WalletError, fidelity::FidelityBond }; -use super::swapcoin::{IncomingSwapCoin, OutgoingSwapCoin}; +use super::swapcoin::{ IncomingSwapCoin, OutgoingSwapCoin }; /// Represents the internal data store for a Bitcoin wallet. // TODO: Derive Serialize/Deserialize for this structure, and remove FileData @@ -48,7 +45,7 @@ impl WalletStore { path: &PathBuf, network: Network, seedphrase: String, - passphrase: String, + passphrase: String ) -> Result { let mnemonic = Mnemonic::parse(seedphrase)?; let seed = mnemonic.to_seed(passphrase); @@ -69,11 +66,7 @@ impl WalletStore { std::fs::create_dir_all(path.parent().expect("Path should NOT be root!"))?; // write: overwrites existing file. // create: creates new file if doesn't exist. - let file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path)?; + let file = OpenOptions::new().write(true).create(true).truncate(true).open(path)?; let writer = BufWriter::new(file); serde_cbor::to_writer(writer, &store)?; // let store_read = WalletStore::read_from_disk(path)?; @@ -99,6 +92,7 @@ impl WalletStore { #[cfg(test)] mod tests { use super::*; + use bitcoind::tempfile::tempdir; #[test] @@ -112,9 +106,8 @@ mod tests { &file_path, Network::Bitcoin, mnemonic, - "passphrase".to_string(), - ) - .unwrap(); + "passphrase".to_string() + ).unwrap(); original_wallet_store.write_to_disk(&file_path).unwrap(); From 233f63d400d6f52403fd5d5ec2d3b7389d3c7889 Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Sat, 2 Mar 2024 08:54:50 -0500 Subject: [PATCH 2/6] Fixed fmt and clippy issues --- src/wallet/storage.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/wallet/storage.rs b/src/wallet/storage.rs index 44464a45..fb4702f4 100644 --- a/src/wallet/storage.rs +++ b/src/wallet/storage.rs @@ -2,16 +2,19 @@ //! //! Wallet data is currently written in unencrypted CBOR files which are not directly human readable. -use std::{ collections::HashMap, path::PathBuf }; +use std::{collections::HashMap, path::PathBuf}; use bip39::Mnemonic; -use bitcoin::{ bip32::ExtendedPrivKey, Network, OutPoint, ScriptBuf }; -use serde::{ Deserialize, Serialize }; -use std::{ fs::OpenOptions, io::{ BufReader, BufWriter } }; +use bitcoin::{bip32::ExtendedPrivKey, Network, OutPoint, ScriptBuf}; +use serde::{Deserialize, Serialize}; +use std::{ + fs::OpenOptions, + io::{BufReader, BufWriter}, +}; -use super::{ error::WalletError, fidelity::FidelityBond }; +use super::{error::WalletError, fidelity::FidelityBond}; -use super::swapcoin::{ IncomingSwapCoin, OutgoingSwapCoin }; +use super::swapcoin::{IncomingSwapCoin, OutgoingSwapCoin}; /// Represents the internal data store for a Bitcoin wallet. // TODO: Derive Serialize/Deserialize for this structure, and remove FileData @@ -45,7 +48,7 @@ impl WalletStore { path: &PathBuf, network: Network, seedphrase: String, - passphrase: String + passphrase: String, ) -> Result { let mnemonic = Mnemonic::parse(seedphrase)?; let seed = mnemonic.to_seed(passphrase); @@ -66,7 +69,11 @@ impl WalletStore { std::fs::create_dir_all(path.parent().expect("Path should NOT be root!"))?; // write: overwrites existing file. // create: creates new file if doesn't exist. - let file = OpenOptions::new().write(true).create(true).truncate(true).open(path)?; + let file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path)?; let writer = BufWriter::new(file); serde_cbor::to_writer(writer, &store)?; // let store_read = WalletStore::read_from_disk(path)?; @@ -106,8 +113,9 @@ mod tests { &file_path, Network::Bitcoin, mnemonic, - "passphrase".to_string() - ).unwrap(); + "passphrase".to_string(), + ) + .unwrap(); original_wallet_store.write_to_disk(&file_path).unwrap(); From cccbe8070bfb6e9c287fae4ea070278dc2ece9c9 Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Sat, 2 Mar 2024 16:04:23 -0500 Subject: [PATCH 3/6] Added suggestion and modified IT --- src/wallet/api.rs | 149 +++++++++++++++----------------------- src/wallet/direct_send.rs | 2 +- src/wallet/fidelity.rs | 7 +- src/wallet/funding.rs | 18 +++-- tests/abort1.rs | 41 ++++++++--- tests/abort2_case2.rs | 56 +++++++++----- tests/fidelity.rs | 10 ++- tests/malice1.rs | 36 +++++++-- tests/malice2.rs | 36 +++++++-- tests/standard_swap.rs | 59 +++++++++++---- 10 files changed, 254 insertions(+), 160 deletions(-) diff --git a/src/wallet/api.rs b/src/wallet/api.rs index fb1a4dbd..f1c8337f 100644 --- a/src/wallet/api.rs +++ b/src/wallet/api.rs @@ -431,13 +431,9 @@ impl Wallet { } /// Calculates the total balance of the wallet, considering live contracts and fidelity bonds. - pub fn balance( - &self, - live_contracts: bool, - fidelity_bonds: bool, - ) -> Result { + pub fn balance(&self) -> Result { Ok(self - .list_unspent_from_wallet(live_contracts, fidelity_bonds)? + .list_unspent_from_wallet()? .iter() .fold(Amount::ZERO, |a, (utxo, _)| a + utxo.amount)) } @@ -456,9 +452,16 @@ impl Wallet { .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } - pub fn balance_descriptor_utxo_or_swap_coins(&self) -> Result { + pub fn balance_descriptor_utxo(&self) -> Result { Ok(self - .list_descriptor_utxo_or_swap_coin_unspend_from_wallet()? + .list_descriptor_utxo_unspend_from_wallet()? + .iter() + .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) + } + + pub fn balance_swap_coins(&self) -> Result { + Ok(self + .list_swap_coin_unspend_from_wallet()? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } @@ -751,12 +754,12 @@ impl Wallet { }) } - fn check_live_contracts( - &self, - utxo: &ListUnspentResultEntry, - contract_scriptpubkeys_outgoing: &HashMap, - contract_scriptpubkeys_incoming: &HashMap, - ) -> Option { + fn check_live_contracts(&self, utxo: &ListUnspentResultEntry) -> Option { + let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = ( + self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), + self.create_contract_scriptpubkey_incoming_swapcoin_hashmap(), + ); + if let Some(outgoing_swapcoin) = contract_scriptpubkeys_outgoing.get(&utxo.script_pub_key) { if utxo.confirmations >= outgoing_swapcoin.get_timelock().into() { return Some(UTXOSpendInfo::TimelockContract { @@ -832,19 +835,7 @@ impl Wallet { /// Simplified method to list UTXOs from the wallet, integrating the logic directly. pub fn list_unspent_from_wallet( &self, - include_live_contracts: bool, - include_fidelity_bonds: bool, ) -> Result, WalletError> { - let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = - if include_live_contracts { - ( - self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), - self.create_contract_scriptpubkey_incoming_swapcoin_hashmap(), - ) - } else { - (HashMap::new(), HashMap::new()) - }; - self.rpc .call::("lockunspent", &[Value::Bool(true)])?; let all_utxos = self @@ -854,24 +845,13 @@ impl Wallet { let processed_utxos = all_utxos .iter() .filter_map(|utxo| { - let mut spend_info = if include_fidelity_bonds { - self.check_fidelity_bonds(utxo) - } else { - None - }; - - if spend_info.is_none() && utxo.descriptor.is_none() { - spend_info = self.check_live_contracts( - utxo, - &contract_scriptpubkeys_outgoing, - &contract_scriptpubkeys_incoming, - ); + let mut spend_info = self.check_fidelity_bonds(utxo); + if spend_info.is_none() { + spend_info = self.check_live_contracts(utxo); } - if spend_info.is_none() { spend_info = self.check_descriptor_utxo_or_swap_coin(utxo); } - spend_info.map(|info| (utxo.clone(), info)) }) .collect::>(); @@ -882,68 +862,52 @@ impl Wallet { pub fn list_live_contract_unspend_from_wallet( &self, ) -> Result, WalletError> { - let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = ( - self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), - self.create_contract_scriptpubkey_incoming_swapcoin_hashmap(), - ); - self.rpc - .call::("lockunspent", &[Value::Bool(true)])?; - let all_utxos = self - .rpc - .list_unspent(Some(0), Some(9999999), None, None, None)?; - let processed_utxos = all_utxos + let all_valid_utxo = self.list_unspent_from_wallet()?; + let filtered_utxos: Vec<_> = all_valid_utxo .iter() - .filter_map(|utxo| { - let spend_info = self.check_live_contracts( - utxo, - &contract_scriptpubkeys_outgoing, - &contract_scriptpubkeys_incoming, - ); - - spend_info.map(|info| (utxo.clone(), info)) + .filter(|x| { + matches!(x.1, UTXOSpendInfo::HashlockContract { .. }) + || matches!(x.1, UTXOSpendInfo::TimelockContract { .. }) }) - .collect::>(); - - Ok(processed_utxos) + .cloned() + .collect(); + Ok(filtered_utxos) } pub fn list_fidelity_unspend_from_wallet( &self, ) -> Result, WalletError> { - self.rpc - .call::("lockunspent", &[Value::Bool(true)])?; - let all_utxos = self - .rpc - .list_unspent(Some(0), Some(9999999), None, None, None)?; - let processed_utxos = all_utxos + let all_valid_utxo = self.list_unspent_from_wallet()?; + let filtered_utxos: Vec<_> = all_valid_utxo .iter() - .filter_map(|utxo| { - let spend_info = self.check_fidelity_bonds(utxo); - - spend_info.map(|info| (utxo.clone(), info)) - }) - .collect::>(); - - Ok(processed_utxos) + .filter(|x| matches!(x.1, UTXOSpendInfo::FidelityBondCoin { .. })) + .cloned() + .collect(); + Ok(filtered_utxos) } - pub fn list_descriptor_utxo_or_swap_coin_unspend_from_wallet( + pub fn list_descriptor_utxo_unspend_from_wallet( &self, ) -> Result, WalletError> { - self.rpc - .call::("lockunspent", &[Value::Bool(true)])?; - let all_utxos = self - .rpc - .list_unspent(Some(0), Some(9999999), None, None, None)?; - let processed_utxos = all_utxos + let all_valid_utxo = self.list_unspent_from_wallet()?; + let filtered_utxos: Vec<_> = all_valid_utxo .iter() - .filter_map(|utxo| { - let spend_info = self.check_descriptor_utxo_or_swap_coin(utxo); - spend_info.map(|info| (utxo.clone(), info)) - }) - .collect::>(); + .filter(|x| matches!(x.1, UTXOSpendInfo::SeedCoin { .. })) + .cloned() + .collect(); + Ok(filtered_utxos) + } - Ok(processed_utxos) + pub fn list_swap_coin_unspend_from_wallet( + &self, + ) -> Result, WalletError> { + let all_valid_utxo = self.list_unspent_from_wallet()?; + let filtered_utxos: Vec<_> = all_valid_utxo + .iter() + .filter(|x| matches!(x.1, UTXOSpendInfo::SwapCoin { .. })) + .cloned() + .collect(); + Ok(filtered_utxos) } /// Finds incomplete coin swaps in the wallet. @@ -1084,7 +1048,10 @@ impl Wallet { pub(super) fn find_hd_next_index(&self, keychain: KeychainKind) -> Result { let mut max_index: i32 = -1; //TODO error handling - let utxos = self.list_descriptor_utxo_or_swap_coin_unspend_from_wallet()?; + let mut utxos = self.list_descriptor_utxo_unspend_from_wallet()?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + utxos.append(&mut swap_coin_utxo); + for (utxo, _) in utxos { if utxo.descriptor.is_none() { continue; @@ -1138,7 +1105,9 @@ impl Wallet { /// Refreshes the offer maximum size cache based on the current wallet's unspent transaction outputs (UTXOs). pub fn refresh_offer_maxsize_cache(&mut self) -> Result<(), WalletError> { - let utxos = self.list_descriptor_utxo_or_swap_coin_unspend_from_wallet()?; + let mut utxos = self.list_descriptor_utxo_unspend_from_wallet()?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + utxos.append(&mut swap_coin_utxo); let balance: Amount = utxos.iter().fold(Amount::ZERO, |acc, u| acc + u.0.amount); self.store.offer_maxsize = balance.to_sat(); Ok(()) diff --git a/src/wallet/direct_send.rs b/src/wallet/direct_send.rs index b68ec717..3d4ce13e 100644 --- a/src/wallet/direct_send.rs +++ b/src/wallet/direct_send.rs @@ -120,7 +120,7 @@ impl Wallet { //TODO this search within a search could get very slow // Filter out fidelity bonds. Use `wallet.redeem_fidelity()` function to spend fidelity bond coins. let list_unspent_result = self - .list_unspent_from_wallet(true, true)? + .list_unspent_from_wallet()? .into_iter() .filter(|(_, info)| !matches!(info, UTXOSpendInfo::FidelityBondCoin { .. })) .collect::>(); diff --git a/src/wallet/fidelity.rs b/src/wallet/fidelity.rs index ce0546ac..b96dc4b1 100644 --- a/src/wallet/fidelity.rs +++ b/src/wallet/fidelity.rs @@ -309,9 +309,12 @@ impl Wallet { ) -> Result { let (index, fidelity_addr, fidelity_pubkey) = self.get_next_fidelity_address(locktime)?; + let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet()?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + seed_coin_utxo.append(&mut swap_coin_utxo); + // Fetch utxos, filter out existing fidelity coins - let mut unspents = self - .list_unspent_from_wallet(false, false)? + let mut unspents = seed_coin_utxo .into_iter() .filter(|(_, spend_info)| !matches!(spend_info, UTXOSpendInfo::FidelityBondCoin { .. })) .collect::>(); diff --git a/src/wallet/funding.rs b/src/wallet/funding.rs index 1b10d1c4..aedc3797 100644 --- a/src/wallet/funding.rs +++ b/src/wallet/funding.rs @@ -70,7 +70,7 @@ impl Wallet { ) -> Result, WalletError> { for _ in 0..100000 { let mut knives = (1..count) - .map(|_| OsRng.next_u32() as f32 / u32::MAX as f32) + .map(|_| (OsRng.next_u32() as f32) / (u32::MAX as f32)) .collect::>(); knives.sort_by(|a, b| b.partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal)); @@ -84,7 +84,7 @@ impl Wallet { if fractions .iter() - .all(|f| *f * (total_amount as f32) > lower_limit as f32) + .all(|f| *f * (total_amount as f32) > (lower_limit as f32)) { return Ok(fractions); } @@ -102,7 +102,7 @@ impl Wallet { //there should always be enough to pay miner fees )? .iter() - .map(|f| (*f * total_amount as f32) as u64) + .map(|f| (*f * (total_amount as f32)) as u64) .collect::>(); //rounding errors mean usually 1 or 2 satoshis are lost, add them back @@ -203,9 +203,8 @@ impl Wallet { destinations: &[Address], fee_rate: u64, change_address: &Address, - utxos: &mut dyn Iterator, - //utxos item is (txid, vout, value) - //utxos should be sorted by size, largest first + utxos: &mut dyn Iterator, //utxos item is (txid, vout, value) + //utxos should be sorted by size, largest first ) -> Result, WalletError> { let mut funding_txes = Vec::::new(); let mut payment_output_positions = Vec::::new(); @@ -215,7 +214,7 @@ impl Wallet { let mut destinations_iter = destinations.iter(); let first_tx_input = utxos.next().unwrap(); - for _ in 0..(destinations.len() - 2) { + for _ in 0..destinations.len() - 2 { let (txid, vout, value) = utxos.next().unwrap(); let mut outputs = HashMap::::new(); @@ -417,8 +416,11 @@ impl Wallet { ) -> Result, WalletError> { //this function will pick the top most valuable UTXOs and use them //to create funding transactions + let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet()?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + seed_coin_utxo.append(&mut swap_coin_utxo); - let mut list_unspent_result = self.list_unspent_from_wallet(false, false)?; + let mut list_unspent_result = seed_coin_utxo; if list_unspent_result.len() < destinations.len() { return Err(WalletError::Protocol( "Not enough UTXOs to create this many funding txes".to_string(), diff --git a/tests/abort1.rs b/tests/abort1.rs index 83794cf6..26dee420 100644 --- a/tests/abort1.rs +++ b/tests/abort1.rs @@ -68,6 +68,7 @@ async fn test_stop_taker_after_setup() { .unwrap(); test_framework.send_to_address(&maker_addrs, Amount::from_btc(0.05).unwrap()); }); + }); } // Coins for fidelity creation @@ -89,8 +90,14 @@ async fn test_stop_taker_after_setup() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -127,8 +134,14 @@ async fn test_stop_taker_after_setup() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -172,8 +185,14 @@ async fn test_stop_taker_after_setup() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); assert_eq!(org_taker_balance - taker_balance, Amount::from_sat(4227)); makers @@ -184,10 +203,14 @@ async fn test_stop_taker_after_setup() { .get_wallet() .read() .unwrap() - .balance(false, false) - .unwrap(); - log::info!("Org Balance: {}", *org_balance); - log::info!("New_balance: {}", new_balance); + .balance_descriptor_utxo() + .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap(); assert_eq!(*org_balance - new_balance, Amount::from_sat(4227)); }); diff --git a/tests/abort2_case2.rs b/tests/abort2_case2.rs index 610f0320..4054ec9e 100644 --- a/tests/abort2_case2.rs +++ b/tests/abort2_case2.rs @@ -32,6 +32,9 @@ async fn test_abort_case_2_recover_if_no_makers_found() { ((16102, 19052), MakerBehavior::Normal), ]; + warn!( + "Running test: Maker 6102 Closes before sending sender's sigs. Taker recovers. Or Swap cancels" + ); warn!( "Running test: Maker 6102 Closes before sending sender's sigs. Taker recovers. Or Swap cancels" ); @@ -89,8 +92,14 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -124,8 +133,14 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -172,19 +187,18 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); - - // Balance will not differ if the first maker drops and swap doesn't take place. - // The recovery will happen only if the 2nd maker drops, which has 50% probabiltiy. - // Only do this assert if the balance differs, implying that the swap took place. - if new_taker_balance != org_taker_balance { - assert_eq!( - org_taker_balance - new_taker_balance, - Amount::from_sat(4227) - ); - } - + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); + assert_eq!( + org_taker_balance - new_taker_balance, + Amount::from_sat(4227) + ); makers .iter() .zip(org_maker_balances.iter()) @@ -193,8 +207,14 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .get_wallet() .read() .unwrap() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap(); assert_eq!(*org_balance - new_balance, Amount::from_sat(0)); }); diff --git a/tests/fidelity.rs b/tests/fidelity.rs index f64d3c07..55652488 100644 --- a/tests/fidelity.rs +++ b/tests/fidelity.rs @@ -69,7 +69,7 @@ async fn test_fidelity() { expected_error.err().unwrap(), MakerError::Wallet(WalletError::Fidelity(FidelityError::InsufficientFund { available: 4000000, - required: 5000000 + required: 5000000, })) ); @@ -108,7 +108,7 @@ async fn test_fidelity() { let index = wallet_write .create_fidelity( Amount::from_sat(1000000), - LockTime::from_height(test_framework.get_block_count() as u32 + 100).unwrap(), + LockTime::from_height((test_framework.get_block_count() as u32) + 100).unwrap(), ) .unwrap(); assert_eq!(index, 1); @@ -124,7 +124,8 @@ async fn test_fidelity() { // Check the balances { let wallet = maker.get_wallet().read().unwrap(); - let normal_balance = wallet.balance(false, false).unwrap(); + let normal_balance = + wallet.balance_descriptor_utxo().unwrap() + wallet.balance_swap_coins().unwrap(); assert_eq!(normal_balance.to_sat(), 1998000); } @@ -161,7 +162,8 @@ async fn test_fidelity() { // Check the balances again { let wallet = maker.get_wallet().read().unwrap(); - let normal_balance = wallet.balance(false, false).unwrap(); + let normal_balance = + wallet.balance_descriptor_utxo().unwrap() + wallet.balance_swap_coins().unwrap(); assert_eq!(normal_balance.to_sat(), 7996000); } diff --git a/tests/malice1.rs b/tests/malice1.rs index c564aec1..42c5d365 100644 --- a/tests/malice1.rs +++ b/tests/malice1.rs @@ -84,8 +84,14 @@ async fn malice1_taker_broadcast_contract_prematurely() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -121,8 +127,14 @@ async fn malice1_taker_broadcast_contract_prematurely() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -158,8 +170,14 @@ async fn malice1_taker_broadcast_contract_prematurely() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -167,8 +185,14 @@ async fn malice1_taker_broadcast_contract_prematurely() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); assert!(maker_balances.len() == 1); // The set only contains one element, assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); diff --git a/tests/malice2.rs b/tests/malice2.rs index 0c11e6c5..9c1f96a0 100644 --- a/tests/malice2.rs +++ b/tests/malice2.rs @@ -80,8 +80,14 @@ async fn malice2_maker_broadcast_contract_prematurely() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -115,8 +121,14 @@ async fn malice2_maker_broadcast_contract_prematurely() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -152,8 +164,14 @@ async fn malice2_maker_broadcast_contract_prematurely() { .get_wallet() .read() .unwrap() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap() }) .collect::>(); @@ -161,8 +179,14 @@ async fn malice2_maker_broadcast_contract_prematurely() { .read() .unwrap() .get_wallet() - .balance(false, false) - .unwrap(); + .balance_descriptor_utxo() + .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap(); assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); diff --git a/tests/standard_swap.rs b/tests/standard_swap.rs index fdd2d49d..90164a9b 100644 --- a/tests/standard_swap.rs +++ b/tests/standard_swap.rs @@ -90,9 +90,23 @@ async fn test_standard_coinswap() { .read() .unwrap() .get_wallet() - .list_unspent_from_wallet(false, true) + .list_descriptor_utxo_unspend_from_wallet() .unwrap() - .len(), + .len() + + taker + .read() + .unwrap() + .get_wallet() + .list_fidelity_unspend_from_wallet() + .unwrap() + .len() + + taker + .read() + .unwrap() + .get_wallet() + .list_swap_coin_unspend_from_wallet() + .unwrap() + .len(), 3 ); makers.iter().for_each(|maker| { @@ -100,10 +114,18 @@ async fn test_standard_coinswap() { .get_wallet() .read() .unwrap() - .list_unspent_from_wallet(false, false) - .unwrap(); + .list_descriptor_utxo_unspend_from_wallet() + .unwrap() + .len() + + maker + .get_wallet() + .read() + .unwrap() + .list_swap_coin_unspend_from_wallet() + .unwrap() + .len(); - assert_eq!(utxo_count.len(), 4); + assert_eq!(utxo_count, 4); }); // Check locking non-wallet utxos worked. @@ -189,26 +211,31 @@ async fn test_standard_coinswap() { .read() .unwrap() .get_wallet() - .balance(false, false) + .balance_descriptor_utxo() .unwrap() + + taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins() + .unwrap() ); assert!( - taker - .read() - .unwrap() - .get_wallet() - .balance(false, false) - .unwrap() - < Amount::from_btc(0.15).unwrap() + taker.read().unwrap().get_wallet().balance().unwrap() < Amount::from_btc(0.15).unwrap() ); makers.iter().for_each(|maker| { let balance = maker .get_wallet() .read() .unwrap() - .balance(false, false) - .unwrap(); - log::info!("Lets see the amount {:?}", balance); + .balance_descriptor_utxo() + .unwrap() + + maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins() + .unwrap(); assert!(balance > Amount::from_btc(0.15).unwrap()); }); From 2826bfb9b9828a0578ca02833954060d0c1badf9 Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Thu, 21 Mar 2024 04:54:16 -0400 Subject: [PATCH 4/6] Added single responsible unspent output --- src/wallet/api.rs | 74 +++++++++++++++++++++++++++------------ src/wallet/direct_send.rs | 2 +- src/wallet/fidelity.rs | 6 ++-- src/wallet/funding.rs | 7 ++-- tests/abort1.rs | 22 +++++++----- tests/abort2_case2.rs | 23 +++++++----- tests/fidelity.rs | 10 +++--- tests/malice1.rs | 22 +++++++----- tests/malice2.rs | 22 +++++++----- tests/standard_swap.rs | 24 ++++++++----- 10 files changed, 140 insertions(+), 72 deletions(-) diff --git a/src/wallet/api.rs b/src/wallet/api.rs index f1c8337f..6003c3f7 100644 --- a/src/wallet/api.rs +++ b/src/wallet/api.rs @@ -433,35 +433,47 @@ impl Wallet { /// Calculates the total balance of the wallet, considering live contracts and fidelity bonds. pub fn balance(&self) -> Result { Ok(self - .list_unspent_from_wallet()? + .list_unspent_from_wallet(None)? .iter() .fold(Amount::ZERO, |a, (utxo, _)| a + utxo.amount)) } - pub fn balance_fidelity_bonds(&self) -> Result { + pub fn balance_fidelity_bonds( + &self, + all_utxos: Option<&Vec>, + ) -> Result { Ok(self - .list_fidelity_unspend_from_wallet()? + .list_fidelity_unspend_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } - pub fn balance_live_transaction(&self) -> Result { + pub fn balance_live_transaction( + &self, + all_utxos: Option<&Vec>, + ) -> Result { Ok(self - .list_live_contract_unspend_from_wallet()? + .list_live_contract_unspend_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } - pub fn balance_descriptor_utxo(&self) -> Result { + pub fn balance_descriptor_utxo( + &self, + all_utxos: Option<&Vec>, + ) -> Result { Ok(self - .list_descriptor_utxo_unspend_from_wallet()? + .list_descriptor_utxo_unspend_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } - pub fn balance_swap_coins(&self) -> Result { + pub fn balance_swap_coins( + &self, + all_utxos: Option<&Vec>, + ) -> Result { Ok(self - .list_swap_coin_unspend_from_wallet()? + .list_swap_coin_unspend_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } @@ -831,16 +843,28 @@ impl Wallet { None } - /// Lists UTXOs from the wallet, optionally including live contracts and fidelity bonds. - /// Simplified method to list UTXOs from the wallet, integrating the logic directly. - pub fn list_unspent_from_wallet( - &self, - ) -> Result, WalletError> { + pub fn get_all_utxo(&self) -> Result, WalletError> { self.rpc .call::("lockunspent", &[Value::Bool(true)])?; let all_utxos = self .rpc .list_unspent(Some(0), Some(9999999), None, None, None)?; + Ok(all_utxos) + } + + /// Lists UTXOs from the wallet, optionally including live contracts and fidelity bonds. + /// Simplified method to list UTXOs from the wallet, integrating the logic directly. + pub fn list_unspent_from_wallet( + &self, + utxos: Option<&Vec>, + ) -> Result, WalletError> { + let owned_utxo: Option> = if utxos.is_none() { + Some(self.get_all_utxo()?) + } else { + None + }; + + let all_utxos = utxos.unwrap_or_else(|| owned_utxo.as_ref().unwrap()); let processed_utxos = all_utxos .iter() @@ -861,8 +885,9 @@ impl Wallet { pub fn list_live_contract_unspend_from_wallet( &self, + all_utxos: Option<&Vec>, ) -> Result, WalletError> { - let all_valid_utxo = self.list_unspent_from_wallet()?; + let all_valid_utxo = self.list_unspent_from_wallet(all_utxos)?; let filtered_utxos: Vec<_> = all_valid_utxo .iter() .filter(|x| { @@ -876,8 +901,9 @@ impl Wallet { pub fn list_fidelity_unspend_from_wallet( &self, + all_utxos: Option<&Vec>, ) -> Result, WalletError> { - let all_valid_utxo = self.list_unspent_from_wallet()?; + let all_valid_utxo = self.list_unspent_from_wallet(all_utxos)?; let filtered_utxos: Vec<_> = all_valid_utxo .iter() .filter(|x| matches!(x.1, UTXOSpendInfo::FidelityBondCoin { .. })) @@ -888,8 +914,9 @@ impl Wallet { pub fn list_descriptor_utxo_unspend_from_wallet( &self, + all_utxos: Option<&Vec>, ) -> Result, WalletError> { - let all_valid_utxo = self.list_unspent_from_wallet()?; + let all_valid_utxo = self.list_unspent_from_wallet(all_utxos)?; let filtered_utxos: Vec<_> = all_valid_utxo .iter() .filter(|x| matches!(x.1, UTXOSpendInfo::SeedCoin { .. })) @@ -900,8 +927,9 @@ impl Wallet { pub fn list_swap_coin_unspend_from_wallet( &self, + all_utxos: Option<&Vec>, ) -> Result, WalletError> { - let all_valid_utxo = self.list_unspent_from_wallet()?; + let all_valid_utxo = self.list_unspent_from_wallet(all_utxos)?; let filtered_utxos: Vec<_> = all_valid_utxo .iter() .filter(|x| matches!(x.1, UTXOSpendInfo::SwapCoin { .. })) @@ -1048,8 +1076,9 @@ impl Wallet { pub(super) fn find_hd_next_index(&self, keychain: KeychainKind) -> Result { let mut max_index: i32 = -1; //TODO error handling - let mut utxos = self.list_descriptor_utxo_unspend_from_wallet()?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + let all_utxos = self.get_all_utxo()?; + let mut utxos = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; utxos.append(&mut swap_coin_utxo); for (utxo, _) in utxos { @@ -1105,8 +1134,9 @@ impl Wallet { /// Refreshes the offer maximum size cache based on the current wallet's unspent transaction outputs (UTXOs). pub fn refresh_offer_maxsize_cache(&mut self) -> Result<(), WalletError> { - let mut utxos = self.list_descriptor_utxo_unspend_from_wallet()?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + let all_utxos = self.get_all_utxo()?; + let mut utxos = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; utxos.append(&mut swap_coin_utxo); let balance: Amount = utxos.iter().fold(Amount::ZERO, |acc, u| acc + u.0.amount); self.store.offer_maxsize = balance.to_sat(); diff --git a/src/wallet/direct_send.rs b/src/wallet/direct_send.rs index 3d4ce13e..1ccc8d8d 100644 --- a/src/wallet/direct_send.rs +++ b/src/wallet/direct_send.rs @@ -120,7 +120,7 @@ impl Wallet { //TODO this search within a search could get very slow // Filter out fidelity bonds. Use `wallet.redeem_fidelity()` function to spend fidelity bond coins. let list_unspent_result = self - .list_unspent_from_wallet()? + .list_unspent_from_wallet(None)? .into_iter() .filter(|(_, info)| !matches!(info, UTXOSpendInfo::FidelityBondCoin { .. })) .collect::>(); diff --git a/src/wallet/fidelity.rs b/src/wallet/fidelity.rs index b96dc4b1..f5ea0982 100644 --- a/src/wallet/fidelity.rs +++ b/src/wallet/fidelity.rs @@ -309,8 +309,10 @@ impl Wallet { ) -> Result { let (index, fidelity_addr, fidelity_pubkey) = self.get_next_fidelity_address(locktime)?; - let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet()?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + let all_utxos = self.get_all_utxo()?; + + let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; seed_coin_utxo.append(&mut swap_coin_utxo); // Fetch utxos, filter out existing fidelity coins diff --git a/src/wallet/funding.rs b/src/wallet/funding.rs index aedc3797..64bb4476 100644 --- a/src/wallet/funding.rs +++ b/src/wallet/funding.rs @@ -416,8 +416,11 @@ impl Wallet { ) -> Result, WalletError> { //this function will pick the top most valuable UTXOs and use them //to create funding transactions - let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet()?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet()?; + + let all_utxos = self.get_all_utxo()?; + + let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; seed_coin_utxo.append(&mut swap_coin_utxo); let mut list_unspent_result = seed_coin_utxo; diff --git a/tests/abort1.rs b/tests/abort1.rs index 26dee420..8b7f1fe4 100644 --- a/tests/abort1.rs +++ b/tests/abort1.rs @@ -85,18 +85,20 @@ async fn test_stop_taker_after_setup() { // confirm balances test_framework.generate_1_block(); + let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + // Get the original balances let org_taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -130,17 +132,18 @@ async fn test_stop_taker_after_setup() { let org_maker_balances = makers .iter() .map(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap() }) .collect::>(); @@ -180,18 +183,20 @@ async fn test_stop_taker_after_setup() { // All pending swapcoins are cleared now. assert_eq!(taker.read().unwrap().get_wallet().get_swapcoins_count(), 0); + all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + // Check everybody looses mining fees of contract txs. let taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert_eq!(org_taker_balance - taker_balance, Amount::from_sat(4227)); @@ -199,17 +204,18 @@ async fn test_stop_taker_after_setup() { .iter() .zip(org_maker_balances.iter()) .for_each(|(maker, org_balance)| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); let new_balance = maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert_eq!(*org_balance - new_balance, Amount::from_sat(4227)); }); diff --git a/tests/abort2_case2.rs b/tests/abort2_case2.rs index 4054ec9e..4baaf796 100644 --- a/tests/abort2_case2.rs +++ b/tests/abort2_case2.rs @@ -87,18 +87,20 @@ async fn test_abort_case_2_recover_if_no_makers_found() { // confirm balances test_framework.generate_1_block(); + let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + // Get the original balances let org_taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -129,17 +131,18 @@ async fn test_abort_case_2_recover_if_no_makers_found() { let org_maker_balances = makers .iter() .map(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap() }) .collect::>(); @@ -181,19 +184,21 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .to_string() ); + all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + // Assert that Taker burned the mining fees, // Makers are fine. let new_taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert_eq!( org_taker_balance - new_taker_balance, @@ -203,17 +208,19 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .iter() .zip(org_maker_balances.iter()) .for_each(|(maker, org_balance)| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); + let new_balance = maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert_eq!(*org_balance - new_balance, Amount::from_sat(0)); }); diff --git a/tests/fidelity.rs b/tests/fidelity.rs index 55652488..0529a888 100644 --- a/tests/fidelity.rs +++ b/tests/fidelity.rs @@ -124,8 +124,9 @@ async fn test_fidelity() { // Check the balances { let wallet = maker.get_wallet().read().unwrap(); - let normal_balance = - wallet.balance_descriptor_utxo().unwrap() + wallet.balance_swap_coins().unwrap(); + let all_utxos = wallet.get_all_utxo().unwrap(); + let normal_balance = wallet.balance_descriptor_utxo(Some(&all_utxos)).unwrap() + + wallet.balance_swap_coins(Some(&all_utxos)).unwrap(); assert_eq!(normal_balance.to_sat(), 1998000); } @@ -162,8 +163,9 @@ async fn test_fidelity() { // Check the balances again { let wallet = maker.get_wallet().read().unwrap(); - let normal_balance = - wallet.balance_descriptor_utxo().unwrap() + wallet.balance_swap_coins().unwrap(); + let all_utxos = wallet.get_all_utxo().unwrap(); + let normal_balance = wallet.balance_descriptor_utxo(Some(&all_utxos)).unwrap() + + wallet.balance_swap_coins(Some(&all_utxos)).unwrap(); assert_eq!(normal_balance.to_sat(), 7996000); } diff --git a/tests/malice1.rs b/tests/malice1.rs index 42c5d365..872dfde8 100644 --- a/tests/malice1.rs +++ b/tests/malice1.rs @@ -80,17 +80,19 @@ async fn malice1_taker_broadcast_contract_prematurely() { // confirm balances test_framework.generate_1_block(); + let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + let org_take_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -123,17 +125,18 @@ async fn malice1_taker_broadcast_contract_prematurely() { let org_maker_balances = makers .iter() .map(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap() }) .collect::>(); @@ -166,32 +169,35 @@ async fn malice1_taker_broadcast_contract_prematurely() { let maker_balances = makers .iter() .map(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap() }) .collect::>(); + all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + let taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert!(maker_balances.len() == 1); // The set only contains one element, diff --git a/tests/malice2.rs b/tests/malice2.rs index 9c1f96a0..00b34f65 100644 --- a/tests/malice2.rs +++ b/tests/malice2.rs @@ -76,17 +76,19 @@ async fn malice2_maker_broadcast_contract_prematurely() { // confirm balances test_framework.generate_1_block(); + let mut unspend_utxo = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + let org_take_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&unspend_utxo)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&unspend_utxo)) .unwrap(); // ---- Start Servers and attempt Swap ---- @@ -117,17 +119,18 @@ async fn malice2_maker_broadcast_contract_prematurely() { let org_maker_balances = makers .iter() .map(|maker| { + unspend_utxo = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&unspend_utxo)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&unspend_utxo)) .unwrap() }) .collect::>(); @@ -160,32 +163,35 @@ async fn malice2_maker_broadcast_contract_prematurely() { let maker_balances = makers .iter() .map(|maker| { + unspend_utxo = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&unspend_utxo)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&unspend_utxo)) .unwrap() }) .collect::>(); + unspend_utxo = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + let taker_balance = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&unspend_utxo)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&unspend_utxo)) .unwrap(); assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); diff --git a/tests/standard_swap.rs b/tests/standard_swap.rs index 90164a9b..6a1b81c7 100644 --- a/tests/standard_swap.rs +++ b/tests/standard_swap.rs @@ -85,43 +85,47 @@ async fn test_standard_coinswap() { // Check if utxo list looks good. // TODO: Assert other interesting things from the utxo list. + + let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + assert_eq!( taker .read() .unwrap() .get_wallet() - .list_descriptor_utxo_unspend_from_wallet() + .list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos)) .unwrap() .len() + taker .read() .unwrap() .get_wallet() - .list_fidelity_unspend_from_wallet() + .list_fidelity_unspend_from_wallet(Some(&all_utxos)) .unwrap() .len() + taker .read() .unwrap() .get_wallet() - .list_swap_coin_unspend_from_wallet() + .list_swap_coin_unspend_from_wallet(Some(&all_utxos)) .unwrap() .len(), 3 ); makers.iter().for_each(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); let utxo_count = maker .get_wallet() .read() .unwrap() - .list_descriptor_utxo_unspend_from_wallet() + .list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos)) .unwrap() .len() + maker .get_wallet() .read() .unwrap() - .list_swap_coin_unspend_from_wallet() + .list_swap_coin_unspend_from_wallet(Some(&all_utxos)) .unwrap() .len(); @@ -205,36 +209,38 @@ async fn test_standard_coinswap() { }); // Check balances makes sense + all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); warn!( "Taker balance : {}", taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + taker .read() .unwrap() .get_wallet() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap() ); assert!( taker.read().unwrap().get_wallet().balance().unwrap() < Amount::from_btc(0.15).unwrap() ); makers.iter().for_each(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); let balance = maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo() + .balance_descriptor_utxo(Some(&all_utxos)) .unwrap() + maker .get_wallet() .read() .unwrap() - .balance_swap_coins() + .balance_swap_coins(Some(&all_utxos)) .unwrap(); assert!(balance > Amount::from_btc(0.15).unwrap()); }); From bfeaf1d80f3b18eb7cfb92565ce4f78c7bd3d2af Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Thu, 21 Mar 2024 07:41:29 -0400 Subject: [PATCH 5/6] Rebased to master --- tests/abort1.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/abort1.rs b/tests/abort1.rs index 8b7f1fe4..5b35fdc1 100644 --- a/tests/abort1.rs +++ b/tests/abort1.rs @@ -68,7 +68,6 @@ async fn test_stop_taker_after_setup() { .unwrap(); test_framework.send_to_address(&maker_addrs, Amount::from_btc(0.05).unwrap()); }); - }); } // Coins for fidelity creation From c0e078c92d90d74456505c1dcf731f81d2790175 Mon Sep 17 00:00:00 2001 From: Shourya Sharma Date: Fri, 22 Mar 2024 06:13:17 -0400 Subject: [PATCH 6/6] Added more asserts in IT --- src/wallet/api.rs | 39 +++++---- src/wallet/fidelity.rs | 4 +- src/wallet/funding.rs | 4 +- tests/abort1.rs | 141 ++++++++++++++++++++++++++----- tests/abort2_case2.rs | 129 +++++++++++++++++++++-------- tests/malice1.rs | 156 +++++++++++++++++++++++++++------- tests/malice2.rs | 167 ++++++++++++++++++++++++++++--------- tests/standard_swap.rs | 184 +++++++++++++++++++++++++++++++---------- 8 files changed, 639 insertions(+), 185 deletions(-) diff --git a/src/wallet/api.rs b/src/wallet/api.rs index 6003c3f7..ad251319 100644 --- a/src/wallet/api.rs +++ b/src/wallet/api.rs @@ -438,42 +438,46 @@ impl Wallet { .fold(Amount::ZERO, |a, (utxo, _)| a + utxo.amount)) } + /// Calculates the total balance of the wallet, considering only fidelity bonds pub fn balance_fidelity_bonds( &self, all_utxos: Option<&Vec>, ) -> Result { Ok(self - .list_fidelity_unspend_from_wallet(all_utxos)? + .list_fidelity_unspent_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } - pub fn balance_live_transaction( + /// Calculates the total balance of the wallet, considering only live contracts + pub fn balance_live_contract( &self, all_utxos: Option<&Vec>, ) -> Result { Ok(self - .list_live_contract_unspend_from_wallet(all_utxos)? + .list_live_contract_unspent_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } + /// Calculates the total balance of the wallet, considering only descriptor utxo pub fn balance_descriptor_utxo( &self, all_utxos: Option<&Vec>, ) -> Result { Ok(self - .list_descriptor_utxo_unspend_from_wallet(all_utxos)? + .list_descriptor_utxo_unspent_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } + /// Calculates the total balance of the wallet, considering only swap coins pub fn balance_swap_coins( &self, all_utxos: Option<&Vec>, ) -> Result { Ok(self - .list_swap_coin_unspend_from_wallet(all_utxos)? + .list_swap_coin_unspent_from_wallet(all_utxos)? .iter() .fold(Amount::ZERO, |sum, (utxo, _)| sum + utxo.amount)) } @@ -748,6 +752,7 @@ impl Wallet { Ok(()) } + /// Checks if a UTXO belongs to fidelity bonds, and then returns corresponding UTXOSpendInfo fn check_fidelity_bonds(&self, utxo: &ListUnspentResultEntry) -> Option { self.store .fidelity_bond @@ -766,6 +771,7 @@ impl Wallet { }) } + /// Checks if a UTXO belongs to live contracts, and then returns corresponding UTXOSpendInfo fn check_live_contracts(&self, utxo: &ListUnspentResultEntry) -> Option { let (contract_scriptpubkeys_outgoing, contract_scriptpubkeys_incoming) = ( self.create_contract_scriptpubkey_outgoing_swapcoin_hashmap(), @@ -792,6 +798,7 @@ impl Wallet { None } + /// Checks if a UTXO belongs to descriptor or swap coin, and then returns corresponding UTXOSpendInfo fn check_descriptor_utxo_or_swap_coin( &self, utxo: &ListUnspentResultEntry, @@ -852,7 +859,7 @@ impl Wallet { Ok(all_utxos) } - /// Lists UTXOs from the wallet, optionally including live contracts and fidelity bonds. + /// Lists UTXOs from the wallet /// Simplified method to list UTXOs from the wallet, integrating the logic directly. pub fn list_unspent_from_wallet( &self, @@ -883,7 +890,8 @@ impl Wallet { Ok(processed_utxos) } - pub fn list_live_contract_unspend_from_wallet( + /// Lists live contract UTXOs from the wallet + pub fn list_live_contract_unspent_from_wallet( &self, all_utxos: Option<&Vec>, ) -> Result, WalletError> { @@ -899,7 +907,8 @@ impl Wallet { Ok(filtered_utxos) } - pub fn list_fidelity_unspend_from_wallet( + /// Lists fidelity UTXOs from the wallet + pub fn list_fidelity_unspent_from_wallet( &self, all_utxos: Option<&Vec>, ) -> Result, WalletError> { @@ -912,7 +921,8 @@ impl Wallet { Ok(filtered_utxos) } - pub fn list_descriptor_utxo_unspend_from_wallet( + /// Lists descriptor UTXOs from the wallet + pub fn list_descriptor_utxo_unspent_from_wallet( &self, all_utxos: Option<&Vec>, ) -> Result, WalletError> { @@ -925,7 +935,8 @@ impl Wallet { Ok(filtered_utxos) } - pub fn list_swap_coin_unspend_from_wallet( + /// Lists swap coin UTXOs from the wallet + pub fn list_swap_coin_unspent_from_wallet( &self, all_utxos: Option<&Vec>, ) -> Result, WalletError> { @@ -1077,8 +1088,8 @@ impl Wallet { let mut max_index: i32 = -1; //TODO error handling let all_utxos = self.get_all_utxo()?; - let mut utxos = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; + let mut utxos = self.list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspent_from_wallet(Some(&all_utxos))?; utxos.append(&mut swap_coin_utxo); for (utxo, _) in utxos { @@ -1135,8 +1146,8 @@ impl Wallet { /// Refreshes the offer maximum size cache based on the current wallet's unspent transaction outputs (UTXOs). pub fn refresh_offer_maxsize_cache(&mut self) -> Result<(), WalletError> { let all_utxos = self.get_all_utxo()?; - let mut utxos = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; + let mut utxos = self.list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspent_from_wallet(Some(&all_utxos))?; utxos.append(&mut swap_coin_utxo); let balance: Amount = utxos.iter().fold(Amount::ZERO, |acc, u| acc + u.0.amount); self.store.offer_maxsize = balance.to_sat(); diff --git a/src/wallet/fidelity.rs b/src/wallet/fidelity.rs index f5ea0982..d7c60fad 100644 --- a/src/wallet/fidelity.rs +++ b/src/wallet/fidelity.rs @@ -311,8 +311,8 @@ impl Wallet { let all_utxos = self.get_all_utxo()?; - let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; + let mut seed_coin_utxo = self.list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspent_from_wallet(Some(&all_utxos))?; seed_coin_utxo.append(&mut swap_coin_utxo); // Fetch utxos, filter out existing fidelity coins diff --git a/src/wallet/funding.rs b/src/wallet/funding.rs index 64bb4476..61f43854 100644 --- a/src/wallet/funding.rs +++ b/src/wallet/funding.rs @@ -419,8 +419,8 @@ impl Wallet { let all_utxos = self.get_all_utxo()?; - let mut seed_coin_utxo = self.list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos))?; - let mut swap_coin_utxo = self.list_swap_coin_unspend_from_wallet(Some(&all_utxos))?; + let mut seed_coin_utxo = self.list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos))?; + let mut swap_coin_utxo = self.list_swap_coin_unspent_from_wallet(Some(&all_utxos))?; seed_coin_utxo.append(&mut swap_coin_utxo); let mut list_unspent_result = seed_coin_utxo; diff --git a/tests/abort1.rs b/tests/abort1.rs index 5b35fdc1..442971a1 100644 --- a/tests/abort1.rs +++ b/tests/abort1.rs @@ -8,7 +8,7 @@ use coinswap::{ mod test_framework; use log::{info, warn}; -use std::{sync::Arc, thread, time::Duration}; +use std::{assert_eq, sync::Arc, thread, time::Duration}; use test_framework::*; /// Abort 1: TAKER Drops After Full Setup. @@ -87,18 +87,31 @@ async fn test_stop_taker_after_setup() { let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); // Get the original balances - let org_taker_balance = taker + let org_taker_balance_fidelity = taker + .read() + .unwrap() + .get_wallet() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + let org_taker_balance = org_taker_balance_descriptor_utxo + org_taker_balance_swap_coins; // ---- Start Servers and attempt Swap ---- @@ -132,18 +145,38 @@ async fn test_stop_taker_after_setup() { .iter() .map(|maker| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() + .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14999).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + maker_balance_descriptor_utxo + maker_balance_swap_coins }) .collect::>(); @@ -185,25 +218,80 @@ async fn test_stop_taker_after_setup() { all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); // Check everybody looses mining fees of contract txs. - let taker_balance = taker + let taker_balance_fidelity = taker + .read() + .unwrap() + .get_wallet() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + let taker_balance = taker_balance_descriptor_utxo + taker_balance_swap_coins; + assert_eq!(org_taker_balance - taker_balance, Amount::from_sat(4227)); + assert_eq!(org_taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + org_taker_balance_descriptor_utxo, + Amount::from_btc(0.15).unwrap() + ); + assert_eq!(org_taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!( + org_taker_balance_live_contract, + Amount::from_btc(0.0).unwrap() + ); + assert_eq!(taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + taker_balance_descriptor_utxo, + Amount::from_btc(0.14995773).unwrap() + ); + assert_eq!(taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(taker_balance_live_contract, Amount::from_btc(0.0).unwrap()); makers .iter() .zip(org_maker_balances.iter()) .for_each(|(maker, org_balance)| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker + .get_wallet() + .read() + .unwrap() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() + .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); let new_balance = maker .get_wallet() .read() @@ -216,7 +304,16 @@ async fn test_stop_taker_after_setup() { .unwrap() .balance_swap_coins(Some(&all_utxos)) .unwrap(); + assert_eq!(*org_balance - new_balance, Amount::from_sat(4227)); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.05).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14994773).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); }); info!("All checks successful. Terminating integration test case"); diff --git a/tests/abort2_case2.rs b/tests/abort2_case2.rs index 4baaf796..805afab4 100644 --- a/tests/abort2_case2.rs +++ b/tests/abort2_case2.rs @@ -90,18 +90,20 @@ async fn test_abort_case_2_recover_if_no_makers_found() { let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); // Get the original balances - let org_taker_balance = taker + let org_taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + + let org_taker_balance = org_taker_balance_descriptor_utxo + org_taker_balance_swap_coins; // ---- Start Servers and attempt Swap ---- @@ -132,18 +134,46 @@ async fn test_abort_case_2_recover_if_no_makers_found() { .iter() .map(|maker| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14999).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + + ( + maker_balance_fidelity, + maker_balance_descriptor_utxo, + maker_balance_swap_coins, + maker_balance_live_contract, + maker_balance_descriptor_utxo + maker_balance_swap_coins, + ) }) .collect::>(); @@ -188,41 +218,72 @@ async fn test_abort_case_2_recover_if_no_makers_found() { // Assert that Taker burned the mining fees, // Makers are fine. - let new_taker_balance = taker + + let new_taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let new_taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); - assert_eq!( - org_taker_balance - new_taker_balance, - Amount::from_sat(4227) - ); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + + let new_taker_balance = new_taker_balance_descriptor_utxo + new_taker_balance_swap_coins; + + // Balance will not differ if the first maker drops and swap doesn't take place. + // The recovery will happen only if the 2nd maker drops, which has 50% probabiltiy. + // Only do this assert if the balance differs, implying that the swap took place. + if new_taker_balance != org_taker_balance { + assert_eq!( + org_taker_balance - new_taker_balance, + Amount::from_sat(4227) + ); + } makers .iter() .zip(org_maker_balances.iter()) .for_each(|(maker, org_balance)| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - - let new_balance = maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); - assert_eq!(*org_balance - new_balance, Amount::from_sat(0)); + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() + .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + let new_balance = maker_balance_descriptor_utxo + maker_balance_swap_coins; + + assert_eq!(org_balance.4 - new_balance, Amount::from_sat(0)); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14999000).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); }); // Stop test and clean everything. diff --git a/tests/malice1.rs b/tests/malice1.rs index 872dfde8..c2e0784f 100644 --- a/tests/malice1.rs +++ b/tests/malice1.rs @@ -10,7 +10,7 @@ mod test_framework; use test_framework::*; use log::{info, warn}; -use std::{collections::BTreeSet, sync::Arc, thread, time::Duration}; +use std::{assert_eq, collections::BTreeSet, sync::Arc, thread, time::Duration}; /// Malice 1: Taker Broadcasts contract transactions prematurely. /// @@ -82,18 +82,33 @@ async fn malice1_taker_broadcast_contract_prematurely() { let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); - let org_take_balance = taker + // Get the original balances + let org_taker_balance_fidelity = taker + .read() + .unwrap() + .get_wallet() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + let org_taker_balance = org_taker_balance_descriptor_utxo + org_taker_balance_swap_coins; // ---- Start Servers and attempt Swap ---- @@ -126,18 +141,40 @@ async fn malice1_taker_broadcast_contract_prematurely() { .iter() .map(|maker| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14999).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + + maker_balance_descriptor_utxo + maker_balance_swap_coins }) .collect::>(); @@ -170,38 +207,75 @@ async fn malice1_taker_broadcast_contract_prematurely() { .iter() .map(|maker| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() + .unwrap() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.05).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14994773).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + + maker_balance_descriptor_utxo + maker_balance_swap_coins }) .collect::>(); all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); - let taker_balance = taker + // Check everybody looses mining fees of contract txs. + let taker_balance_fidelity = taker + .read() + .unwrap() + .get_wallet() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let taker_balance_descriptor_utxo = taker .read() .unwrap() .get_wallet() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let taker_balance_swap_coins = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + let taker_balance = taker_balance_descriptor_utxo + taker_balance_swap_coins; assert!(maker_balances.len() == 1); // The set only contains one element, - assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); + // assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); // Everybody looses 4227 sats for contract transactions. assert_eq!( @@ -212,8 +286,28 @@ async fn malice1_taker_broadcast_contract_prematurely() { .unwrap(), Amount::from_sat(4227) ); + + assert_eq!(org_taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + org_taker_balance_descriptor_utxo, + Amount::from_btc(0.15).unwrap() + ); + assert_eq!( + org_taker_balance_live_contract, + Amount::from_btc(0.0).unwrap() + ); + assert_eq!(org_taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + + assert_eq!(taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + taker_balance_descriptor_utxo, + Amount::from_btc(0.14995773).unwrap() + ); + assert_eq!(taker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + assert_eq!(taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!( - org_take_balance.checked_sub(taker_balance).unwrap(), + org_taker_balance.checked_sub(taker_balance).unwrap(), Amount::from_sat(4227) ); diff --git a/tests/malice2.rs b/tests/malice2.rs index 00b34f65..60dd0973 100644 --- a/tests/malice2.rs +++ b/tests/malice2.rs @@ -76,20 +76,34 @@ async fn malice2_maker_broadcast_contract_prematurely() { // confirm balances test_framework.generate_1_block(); - let mut unspend_utxo = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); - let org_take_balance = taker + let org_taker_balance_fidelity = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo(Some(&unspend_utxo)) + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_descriptor_utxo = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&unspend_utxo)) - .unwrap(); + .get_wallet() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_swap_coins = taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let org_taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + let org_taker_balance = org_taker_balance_descriptor_utxo + org_taker_balance_swap_coins; // ---- Start Servers and attempt Swap ---- @@ -119,19 +133,40 @@ async fn malice2_maker_broadcast_contract_prematurely() { let org_maker_balances = makers .iter() .map(|maker| { - unspend_utxo = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker + .get_wallet() + .read() + .unwrap() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo(Some(&unspend_utxo)) + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&unspend_utxo)) - .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14999).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + maker_balance_descriptor_utxo + maker_balance_swap_coins }) .collect::>(); @@ -163,38 +198,93 @@ async fn malice2_maker_broadcast_contract_prematurely() { let maker_balances = makers .iter() .map(|maker| { - unspend_utxo = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - maker + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker + .get_wallet() + .read() + .unwrap() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker .get_wallet() .read() .unwrap() - .balance_descriptor_utxo(Some(&unspend_utxo)) + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&unspend_utxo)) - .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.05).unwrap()); + assert_eq!( + maker_balance_descriptor_utxo, + Amount::from_btc(0.14994773).unwrap() + ); + assert_eq!(maker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + + maker_balance_descriptor_utxo + maker_balance_swap_coins }) .collect::>(); - unspend_utxo = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); + all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); - let taker_balance = taker + let taker_balance_fidelity = taker .read() .unwrap() .get_wallet() - .balance_descriptor_utxo(Some(&unspend_utxo)) + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let taker_balance_descriptor_utxo = taker + .read() .unwrap() - + taker - .read() - .unwrap() - .get_wallet() - .balance_swap_coins(Some(&unspend_utxo)) - .unwrap(); + .get_wallet() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let taker_balance_swap_coins = taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); - assert_eq!(maker_balances.first().unwrap(), &Amount::from_sat(14994773)); + let taker_balance = taker_balance_descriptor_utxo + taker_balance_swap_coins; + + assert_eq!(org_taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + org_taker_balance_descriptor_utxo, + Amount::from_btc(0.15).unwrap() + ); + assert_eq!( + org_taker_balance_live_contract, + Amount::from_btc(0.0).unwrap() + ); + assert_eq!(org_taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + + assert_eq!(taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!( + taker_balance_descriptor_utxo, + Amount::from_btc(0.14995773).unwrap() + ); + assert_eq!(taker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + assert_eq!(taker_balance_swap_coins, Amount::from_btc(0.0).unwrap()); + + assert_eq!(*maker_balances.first().unwrap(), Amount::from_sat(14994773)); // Everybody looses 4227 sats for contract transactions. assert_eq!( @@ -205,8 +295,9 @@ async fn malice2_maker_broadcast_contract_prematurely() { .unwrap(), Amount::from_sat(4227) ); + assert_eq!( - org_take_balance.checked_sub(taker_balance).unwrap(), + org_taker_balance.checked_sub(taker_balance).unwrap(), Amount::from_sat(4227) ); diff --git a/tests/standard_swap.rs b/tests/standard_swap.rs index 6a1b81c7..9e54bc2d 100644 --- a/tests/standard_swap.rs +++ b/tests/standard_swap.rs @@ -10,7 +10,7 @@ mod test_framework; use test_framework::*; use log::{info, warn}; -use std::{sync::Arc, thread, time::Duration}; +use std::{assert_eq, sync::Arc, thread, time::Duration}; /// This test demonstrates a standard coinswap round between a Taker and 2 Makers. Nothing goes wrong /// and the coinswap completes successfully. @@ -88,48 +88,81 @@ async fn test_standard_coinswap() { let mut all_utxos = taker.read().unwrap().get_wallet().get_all_utxo().unwrap(); - assert_eq!( - taker + let taker_no_of_descriptor_utxo_unspent = taker + .read() + .unwrap() + .get_wallet() + .list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + + let taker_no_of_fidelity_unspent = taker + .read() + .unwrap() + .get_wallet() + .list_fidelity_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + let taker_no_of_swap_coin_unspent = taker + .read() + .unwrap() + .get_wallet() + .list_swap_coin_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + + let taker_no_of_live_contract_unspent = taker + .read() + .unwrap() + .get_wallet() + .list_live_contract_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + + assert_eq!(taker_no_of_descriptor_utxo_unspent, 3); + assert_eq!(taker_no_of_fidelity_unspent, 0); + assert_eq!(taker_no_of_swap_coin_unspent, 0); + assert_eq!(taker_no_of_live_contract_unspent, 0); + + makers.iter().for_each(|maker| { + all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); + + let maker_no_of_descriptor_utxo_unspent = maker + .get_wallet() .read() .unwrap() + .list_descriptor_utxo_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + + let maker_no_of_fidelity_unspent = maker .get_wallet() - .list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos)) + .read() .unwrap() - .len() - + taker - .read() - .unwrap() - .get_wallet() - .list_fidelity_unspend_from_wallet(Some(&all_utxos)) - .unwrap() - .len() - + taker - .read() - .unwrap() - .get_wallet() - .list_swap_coin_unspend_from_wallet(Some(&all_utxos)) - .unwrap() - .len(), - 3 - ); - makers.iter().for_each(|maker| { - all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - let utxo_count = maker + .list_fidelity_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); + + let maker_no_of_swap_coin_unspent = maker .get_wallet() .read() .unwrap() - .list_descriptor_utxo_unspend_from_wallet(Some(&all_utxos)) + .list_swap_coin_unspent_from_wallet(Some(&all_utxos)) .unwrap() - .len() - + maker - .get_wallet() - .read() - .unwrap() - .list_swap_coin_unspend_from_wallet(Some(&all_utxos)) - .unwrap() - .len(); + .len(); + + let maker_no_of_live_contract_unspent = maker + .get_wallet() + .read() + .unwrap() + .list_live_contract_unspent_from_wallet(Some(&all_utxos)) + .unwrap() + .len(); - assert_eq!(utxo_count, 4); + assert_eq!(maker_no_of_descriptor_utxo_unspent, 4); + assert_eq!(maker_no_of_fidelity_unspent, 0); + assert_eq!(maker_no_of_swap_coin_unspent, 0); + assert_eq!(maker_no_of_live_contract_unspent, 0); }); // Check locking non-wallet utxos worked. @@ -225,23 +258,90 @@ async fn test_standard_coinswap() { .balance_swap_coins(Some(&all_utxos)) .unwrap() ); + let taker_balance_fidelity = taker + .read() + .unwrap() + .get_wallet() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let taker_balance_descriptor_utxo = taker + .read() + .unwrap() + .get_wallet() + .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let taker_balance_swap_coins = taker + .read() + .unwrap() + .get_wallet() + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let taker_balance_live_contract = taker + .read() + .unwrap() + .get_wallet() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); assert!( - taker.read().unwrap().get_wallet().balance().unwrap() < Amount::from_btc(0.15).unwrap() + taker_balance_fidelity + + taker_balance_descriptor_utxo + + taker_balance_swap_coins + + taker_balance_live_contract + < Amount::from_btc(0.15).unwrap() + ); + assert_eq!( + taker_balance_descriptor_utxo, + Amount::from_btc(0.14499541).unwrap() + ); + assert_eq!( + taker_balance_swap_coins, + Amount::from_btc(0.0048584).unwrap() ); + assert_eq!(taker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!(taker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + makers.iter().for_each(|maker| { all_utxos = maker.get_wallet().read().unwrap().get_all_utxo().unwrap(); - let balance = maker + let maker_balance_fidelity = maker + .get_wallet() + .read() + .unwrap() + .balance_fidelity_bonds(Some(&all_utxos)) + .unwrap(); + let maker_balance_descriptor_utxo = maker .get_wallet() .read() .unwrap() .balance_descriptor_utxo(Some(&all_utxos)) + .unwrap(); + let maker_balance_swap_coins = maker + .get_wallet() + .read() .unwrap() - + maker - .get_wallet() - .read() - .unwrap() - .balance_swap_coins(Some(&all_utxos)) - .unwrap(); + .balance_swap_coins(Some(&all_utxos)) + .unwrap(); + let maker_balance_live_contract = maker + .get_wallet() + .read() + .unwrap() + .balance_live_contract(Some(&all_utxos)) + .unwrap(); + + assert!( + maker_balance_descriptor_utxo == Amount::from_btc(0.14505657).unwrap() + || maker_balance_descriptor_utxo == Amount::from_btc(0.14512701).unwrap(), + "maker_balance_descriptor_utxo does not match any of the expected values" + ); + assert!( + maker_balance_swap_coins == Amount::from_btc(0.00492884).unwrap() + || maker_balance_swap_coins == Amount::from_btc(0.005).unwrap(), + "maker_balance_swap_coins does not match any of the expected values" + ); + assert_eq!(maker_balance_fidelity, Amount::from_btc(0.0).unwrap()); + assert_eq!(maker_balance_live_contract, Amount::from_btc(0.0).unwrap()); + + let balance = maker_balance_descriptor_utxo + maker_balance_swap_coins; + assert!(balance > Amount::from_btc(0.15).unwrap()); });