Skip to content

Commit 05d94f3

Browse files
committed
test(wallet): check there are no duplicates across required and optional utxos
This test replaces the one used to test `coin_selection::filter_duplicates` introduced in 5299db3. As the code changed and there is not a single point to verificate the following properties: - there are no duplicates in required utxos - there are no duplicates in optional utxos - there are no duplicates across optional and required utxos anymore, test have been prefixed with `not_duplicated_utxos*` to allow its joint execution by using the following command: cargo test -- not_duplicated_utxos
1 parent 0bbf8f0 commit 05d94f3

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

crates/wallet/src/wallet/mod.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,3 +2557,137 @@ macro_rules! doctest_wallet {
25572557
wallet
25582558
}}
25592559
}
2560+
2561+
#[cfg(test)]
2562+
mod test {
2563+
use super::*;
2564+
use crate::test_utils::get_test_tr_single_sig_xprv_and_change_desc;
2565+
use crate::test_utils::insert_anchor;
2566+
use crate::test_utils::insert_tx;
2567+
2568+
#[test]
2569+
fn not_duplicated_utxos_across_optional_and_required() {
2570+
let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc();
2571+
2572+
// create new wallet
2573+
let mut wallet = Wallet::create(external_desc, internal_desc)
2574+
.network(Network::Testnet)
2575+
.create_wallet_no_persist()
2576+
.unwrap();
2577+
2578+
let two_output_tx = Transaction {
2579+
input: vec![],
2580+
output: vec![
2581+
TxOut {
2582+
script_pubkey: wallet
2583+
.next_unused_address(KeychainKind::External)
2584+
.script_pubkey(),
2585+
value: Amount::from_sat(25_000),
2586+
},
2587+
TxOut {
2588+
script_pubkey: wallet
2589+
.next_unused_address(KeychainKind::External)
2590+
.script_pubkey(),
2591+
value: Amount::from_sat(75_000),
2592+
},
2593+
],
2594+
version: transaction::Version::non_standard(0),
2595+
lock_time: absolute::LockTime::ZERO,
2596+
};
2597+
2598+
let txid = two_output_tx.compute_txid();
2599+
insert_tx(&mut wallet, two_output_tx);
2600+
2601+
let expected_anchor = ConfirmationBlockTime {
2602+
block_id: wallet.latest_checkpoint().block_id(),
2603+
confirmation_time: 200,
2604+
};
2605+
2606+
insert_anchor(&mut wallet, txid, expected_anchor);
2607+
2608+
let mut params = TxParams::default();
2609+
wallet
2610+
.get_utxo(OutPoint { txid, vout: 0 })
2611+
.map(|outpoint| {
2612+
params.utxos.insert(outpoint);
2613+
})
2614+
.unwrap();
2615+
// enforce selection of first output in transaction
2616+
let received = wallet.filter_utxos(&params, wallet.latest_checkpoint().block_id().height);
2617+
// notice expected doesn't include the first output from two_output_tx as it should be
2618+
// filtered out
2619+
let expected = vec![wallet
2620+
.get_utxo(OutPoint { txid, vout: 1 })
2621+
.map(|utxo| WeightedUtxo {
2622+
satisfaction_weight: wallet
2623+
.public_descriptor(utxo.keychain)
2624+
.max_weight_to_satisfy()
2625+
.unwrap(),
2626+
utxo: Utxo::Local(utxo),
2627+
})
2628+
.unwrap()];
2629+
2630+
assert_eq!(expected, received);
2631+
}
2632+
2633+
#[test]
2634+
fn not_duplicated_utxos_in_optional_list() {
2635+
let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc();
2636+
2637+
// create new wallet
2638+
let mut wallet = Wallet::create(external_desc, internal_desc)
2639+
.network(Network::Testnet)
2640+
.create_wallet_no_persist()
2641+
.unwrap();
2642+
2643+
let two_output_tx = Transaction {
2644+
input: vec![],
2645+
output: vec![
2646+
TxOut {
2647+
script_pubkey: wallet
2648+
.next_unused_address(KeychainKind::External)
2649+
.script_pubkey(),
2650+
value: Amount::from_sat(25_000),
2651+
},
2652+
TxOut {
2653+
script_pubkey: wallet
2654+
.next_unused_address(KeychainKind::External)
2655+
.script_pubkey(),
2656+
value: Amount::from_sat(75_000),
2657+
},
2658+
],
2659+
version: transaction::Version::non_standard(0),
2660+
lock_time: absolute::LockTime::ZERO,
2661+
};
2662+
2663+
let txid = two_output_tx.compute_txid();
2664+
2665+
for _ in 0..3 {
2666+
insert_tx(&mut wallet, two_output_tx.clone());
2667+
}
2668+
2669+
let expected_anchor = ConfirmationBlockTime {
2670+
block_id: wallet.latest_checkpoint().block_id(),
2671+
confirmation_time: 200,
2672+
};
2673+
2674+
insert_anchor(&mut wallet, txid, expected_anchor);
2675+
2676+
// enforce selection of first output in transaction
2677+
let received = wallet
2678+
.indexed_graph
2679+
.graph()
2680+
.filter_chain_unspents(
2681+
&wallet.chain,
2682+
wallet.chain.tip().block_id(),
2683+
wallet.indexed_graph.index.outpoints().iter().cloned(),
2684+
)
2685+
.map(|(_, full_txout)| full_txout.outpoint)
2686+
.collect::<Vec<_>>();
2687+
// notice expected doesn't include the first output from two_output_tx as it should be
2688+
// filtered out
2689+
let expected = vec![OutPoint { txid, vout: 0 }, OutPoint { txid, vout: 1 }];
2690+
2691+
assert_eq!(expected, received);
2692+
}
2693+
}

crates/wallet/src/wallet/tx_builder.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,4 +1041,17 @@ mod test {
10411041
assert_eq!(filtered.len(), 1);
10421042
assert_eq!(filtered[0].keychain, KeychainKind::Internal);
10431043
}
1044+
1045+
#[test]
1046+
fn not_duplicated_utxos_in_required_list() {
1047+
let mut params = TxParams::default();
1048+
let test_utxos = get_test_utxos();
1049+
for _ in 0..3 {
1050+
params.utxos.insert(test_utxos[0].clone());
1051+
}
1052+
assert_eq!(
1053+
vec![test_utxos[0].clone()],
1054+
params.utxos.into_iter().collect::<Vec<_>>()
1055+
);
1056+
}
10441057
}

0 commit comments

Comments
 (0)