@@ -52,7 +52,7 @@ use rand_core::RngCore;
5252use super :: coin_selection:: CoinSelectionAlgorithm ;
5353use super :: utils:: shuffle_slice;
5454use super :: { CreateTxError , Wallet } ;
55- use crate :: collections:: { BTreeMap , HashSet } ;
55+ use crate :: collections:: { BTreeMap , HashMap , HashSet } ;
5656use crate :: { KeychainKind , LocalOutput , Utxo , WeightedUtxo } ;
5757
5858/// A transaction builder
@@ -126,7 +126,7 @@ pub(crate) struct TxParams {
126126 pub ( crate ) internal_policy_path : Option < BTreeMap < String , Vec < usize > > > ,
127127 pub ( crate ) external_policy_path : Option < BTreeMap < String , Vec < usize > > > ,
128128 pub ( crate ) utxos : HashSet < LocalOutput > ,
129- pub ( crate ) foreign_utxos : Vec < WeightedUtxo > ,
129+ pub ( crate ) foreign_utxos : HashMap < OutPoint , WeightedUtxo > ,
130130 pub ( crate ) unspendable : HashSet < OutPoint > ,
131131 pub ( crate ) manually_selected_only : bool ,
132132 pub ( crate ) sighash : Option < psbt:: PsbtSighashType > ,
@@ -382,14 +382,17 @@ impl<'a, Cs> TxBuilder<'a, Cs> {
382382 }
383383 }
384384
385- self . params . foreign_utxos . push ( WeightedUtxo {
386- satisfaction_weight,
387- utxo : Utxo :: Foreign {
388- outpoint,
389- sequence,
390- psbt_input : Box :: new ( psbt_input) ,
385+ self . params . foreign_utxos . insert (
386+ outpoint,
387+ WeightedUtxo {
388+ satisfaction_weight,
389+ utxo : Utxo :: Foreign {
390+ outpoint,
391+ sequence,
392+ psbt_input : Box :: new ( psbt_input) ,
393+ } ,
391394 } ,
392- } ) ;
395+ ) ;
393396
394397 Ok ( self )
395398 }
@@ -1100,4 +1103,48 @@ mod test {
11001103 params. utxos. into_iter( ) . collect:: <Vec <_>>( )
11011104 ) ;
11021105 }
1106+
1107+ #[ test]
1108+ fn not_duplicated_foreign_utxos_with_same_outpoint_but_different_weight ( ) {
1109+ use crate :: test_utils:: get_funded_wallet_wpkh;
1110+ // Use two different wallets to avoid adding local utxos
1111+ let ( wallet1, txid1) = get_funded_wallet_wpkh ( ) ;
1112+ let ( mut wallet2, _) = get_funded_wallet_wpkh ( ) ;
1113+
1114+ let utxo1 = wallet1. list_unspent ( ) . next ( ) . unwrap ( ) ;
1115+ let tx1 = wallet1. get_tx ( txid1) . unwrap ( ) . tx_node . tx . clone ( ) ;
1116+
1117+ let satisfaction_weight = wallet1
1118+ . public_descriptor ( KeychainKind :: External )
1119+ . max_weight_to_satisfy ( )
1120+ . unwrap ( ) ;
1121+
1122+ let mut builder = wallet2. build_tx ( ) ;
1123+
1124+ // add foreign utxo with satsifaction weight x
1125+ let _ = builder. add_foreign_utxo (
1126+ utxo1. outpoint ,
1127+ psbt:: Input {
1128+ non_witness_utxo : Some ( tx1. as_ref ( ) . clone ( ) ) ,
1129+ ..Default :: default ( )
1130+ } ,
1131+ satisfaction_weight,
1132+ ) ;
1133+
1134+ let modified_satisfaction_weight = satisfaction_weight - Weight :: from_wu ( 6 ) ;
1135+
1136+ assert_ne ! ( satisfaction_weight, modified_satisfaction_weight) ;
1137+
1138+ // add foreign utxo with same outpoint but satisfaction weight x - 6wu
1139+ let _ = builder. add_foreign_utxo (
1140+ utxo1. outpoint ,
1141+ psbt:: Input {
1142+ non_witness_utxo : Some ( tx1. as_ref ( ) . clone ( ) ) ,
1143+ ..Default :: default ( )
1144+ } ,
1145+ modified_satisfaction_weight,
1146+ ) ;
1147+
1148+ assert_eq ! ( builder. params. foreign_utxos. len( ) , 1 ) ;
1149+ }
11031150}
0 commit comments