@@ -1259,180 +1259,59 @@ mod test {
12591259 ) ;
12601260 }
12611261
1262+ // Test that local outputs have precedence over utxos added via `add_foreign_utxo`
12621263 #[ test]
1263- fn test_prexisting_local_utxo_have_precedence_over_foreign_utxo_with_same_outpoint ( ) {
1264- // In this test we are assuming a setup where there are two wallets using the same
1265- // descriptor, but only one is tracking transactions, while the other is not.
1266- // Within this conditions we want the second wallet to be able to consider the unknown
1267- // LocalOutputs provided by the first wallet with greater precedence than any foreign UTXO,
1268- // even if the foreign UTXO shares the same outpoint.
1269- //
1270- // Remember the second wallet does not know about any UTXOs, so in principle, an unknown
1271- // local UTXO could be added as foreign.
1272- //
1273- // In this case, somehow the wallet has knowledge of one local UTXO and it tries to add the
1274- // same UTXO as a foreign one, but the API ignores this, because local UTXOs have higher
1275- // precedence.
1276- use crate :: test_utils:: { get_funded_wallet_wpkh, get_test_wpkh_and_change_desc} ;
1277- use bitcoin:: Network ;
1278-
1279- // Use the same wallet twice
1280- let ( mut wallet1, txid1) = get_funded_wallet_wpkh ( ) ;
1281- // But the second one has no knowledge of tx associated with txid1
1282- let ( main_descriptor, change_descriptor) = get_test_wpkh_and_change_desc ( ) ;
1283- let mut wallet2 = Wallet :: create ( main_descriptor, change_descriptor)
1284- . network ( Network :: Regtest )
1285- . create_wallet_no_persist ( )
1286- . expect ( "descriptors must be valid" ) ;
1287-
1288- let utxo1 = wallet1. list_unspent ( ) . next ( ) . unwrap ( ) ;
1289- let tx1 = wallet1. get_tx ( txid1) . unwrap ( ) . tx_node . as_ref ( ) . clone ( ) ;
1290-
1291- let satisfaction_weight = wallet1
1292- . public_descriptor ( KeychainKind :: External )
1293- . max_weight_to_satisfy ( )
1294- . unwrap ( ) ;
1295-
1296- // Here we are copying old_params to simulate, the very unlikely behavior where a wallet
1297- // becomes aware of a local UTXO while it is creating a transaction using the local UTXO
1298- // it just became aware of as a foreign UTXO
1299- let old_params = {
1300- let mut builder = wallet1. build_tx ( ) ;
1301-
1302- builder
1303- . add_utxo ( utxo1. outpoint )
1304- . expect ( "should add local utxo" ) ;
1264+ fn test_local_utxos_have_precedence_over_foreign_utxos ( ) {
1265+ use crate :: test_utils:: get_funded_wallet_wpkh;
1266+ let ( mut wallet, _) = get_funded_wallet_wpkh ( ) ;
13051267
1306- builder . params . clone ( )
1307- } ;
1268+ let utxo = wallet . list_unspent ( ) . next ( ) . unwrap ( ) ;
1269+ let outpoint = utxo . outpoint ;
13081270
1309- // Build a transaction as wallet2 was aware of utxo1 but not tracking transactions
1310- let mut new_builder = wallet2 . build_tx ( ) ;
1311- new_builder . params = old_params ;
1271+ // case 1: add foreign after local, expect local is kept
1272+ let mut builder = wallet . build_tx ( ) ;
1273+ builder . add_utxo ( outpoint ) . unwrap ( ) ;
13121274
1313- // Check the local UTXO is still there
1314- // UTXO should still be LocalOutput
1315- assert ! ( matches!(
1316- new_builder. params. utxos[ 0 ] ,
1317- WeightedUtxo {
1318- utxo: Utxo :: Local { .. } ,
1319- ..
1320- }
1321- ) ) ;
1275+ assert_eq ! ( builder. params. utxos[ 0 ] . utxo. outpoint( ) , outpoint) ;
13221276
1323- // add foreign UTXO
1324- assert ! ( new_builder
1277+ builder
13251278 . add_foreign_utxo (
1326- utxo1 . outpoint,
1279+ outpoint,
13271280 psbt:: Input {
1328- non_witness_utxo : Some ( tx1 ) ,
1281+ witness_utxo : Some ( utxo . txout . clone ( ) ) ,
13291282 ..Default :: default ( )
13301283 } ,
1331- satisfaction_weight ,
1284+ Weight :: from_wu ( 107 ) ,
13321285 )
1333- . is_ok ( ) ) ;
1286+ . unwrap ( ) ;
13341287
1335- assert_eq ! ( new_builder. params. utxos. len( ) , 1 ) ;
1336- assert_eq ! ( new_builder. params. utxos[ 0 ] . utxo. outpoint( ) , utxo1. outpoint) ;
1337- // UTXO should still be LocalOutput
1288+ assert_eq ! ( builder. params. utxos. len( ) , 1 ) ;
13381289 assert ! ( matches!(
1339- new_builder. params. utxos[ 0 ] ,
1340- WeightedUtxo {
1341- utxo: Utxo :: Local ( ..) ,
1342- ..
1343- }
1290+ & builder. params. utxos[ 0 ] . utxo,
1291+ Utxo :: Local ( output) if output. outpoint == outpoint,
13441292 ) ) ;
1345- }
1346-
1347- #[ test]
1348- fn test_prexisting_foreign_utxo_have_no_precedence_over_local_utxo_with_same_outpoint ( ) {
1349- // In this test we are assuming a setup where there are two wallets using the same
1350- // descriptor, but only one is tracking transactions, while the other is not.
1351- // Within this conditions we want the second wallet to be able to consider the unknown
1352- // LocalOutputs provided by the first wallet with greater precedence than any foreign UTXO,
1353- // even if the foreign UTXO shares the same outpoint.
1354- //
1355- // Remember the second wallet does not know about any UTXOs, so in principle, an unknown
1356- // local UTXO could be added as foreign.
1357- //
1358- // In this case, the wallet adds a local UTXO as if it were foreign and after this it adds
1359- // it as local UTXO. In this case the local UTXO should still have precedence over the
1360- // foreign UTXO.
1361- use crate :: test_utils:: { get_funded_wallet_wpkh, get_test_wpkh_and_change_desc, insert_tx} ;
1362- use bitcoin:: Network ;
1363-
1364- // Use the same wallet twice
1365- let ( wallet1, txid1) = get_funded_wallet_wpkh ( ) ;
1366- // But the second one has no knowledge of tx associated with txid1
1367- let ( main_descriptor, change_descriptor) = get_test_wpkh_and_change_desc ( ) ;
1368- let mut wallet2 = Wallet :: create ( main_descriptor, change_descriptor)
1369- . network ( Network :: Regtest )
1370- . create_wallet_no_persist ( )
1371- . expect ( "descriptors must be valid" ) ;
13721293
1373- let utxo1 = wallet1 . list_unspent ( ) . next ( ) . unwrap ( ) ;
1374- let tx1 = wallet1 . get_tx ( txid1 ) . unwrap ( ) . tx_node . as_ref ( ) . clone ( ) ;
1294+ // case 2: add local after foreign, expect foreign is removed
1295+ builder . params = TxParams :: default ( ) ;
13751296
1376- let satisfaction_weight = wallet1
1377- . public_descriptor ( KeychainKind :: External )
1378- . max_weight_to_satisfy ( )
1297+ builder
1298+ . add_foreign_utxo (
1299+ outpoint,
1300+ psbt:: Input {
1301+ witness_utxo : Some ( utxo. txout ) ,
1302+ ..Default :: default ( )
1303+ } ,
1304+ Weight :: from_wu ( 107 ) ,
1305+ )
13791306 . unwrap ( ) ;
13801307
1381- // Here we are copying old_params to simulate, the very unlikely behavior where a wallet
1382- // becomes aware of a local UTXO while it is creating a transaction using the local UTXO
1383- // it just became aware of as a foreign UTXO
1384- let old_params = {
1385- let mut builder = wallet2. build_tx ( ) ;
1386-
1387- // add foreign UTXO
1388- assert ! ( builder
1389- . add_foreign_utxo(
1390- utxo1. outpoint,
1391- psbt:: Input {
1392- non_witness_utxo: Some ( tx1. clone( ) ) ,
1393- ..Default :: default ( )
1394- } ,
1395- satisfaction_weight,
1396- )
1397- . is_ok( ) ) ;
1308+ assert_eq ! ( builder. params. utxos[ 0 ] . utxo. outpoint( ) , outpoint) ;
13981309
1399- builder. params . clone ( )
1400- } ;
1401-
1402- // The wallet becomes aware of the new UTXO
1403- insert_tx ( & mut wallet2, tx1. clone ( ) ) ;
1404-
1405- // Keep building the old transaction as we wouldn't have stopped of doing so
1406- let mut new_builder = wallet2. build_tx ( ) ;
1407- new_builder. params = old_params;
1408-
1409- // Check the foreign UTXO is still there
1410- // UTXO should still be LocalOutput
1411- assert ! ( matches!(
1412- new_builder. params. utxos[ 0 ] ,
1413- WeightedUtxo {
1414- utxo: Utxo :: Foreign { .. } ,
1415- ..
1416- }
1417- ) ) ;
1310+ builder. add_utxo ( outpoint) . unwrap ( ) ;
14181311
1419- // This method is the correct way of adding UTXOs to the builder.
1420- // It checks the local availability of the UTXO, so a precondition for this method to work
1421- // is that the transaction creating this UTXO must be already known by the wallet.
1422- new_builder
1423- . add_utxo ( utxo1. outpoint )
1424- . expect ( "should add local utxo" ) ;
1425-
1426- assert_eq ! ( new_builder. params. utxos. len( ) , 1 ) ;
1427- assert_eq ! ( new_builder. params. utxos[ 0 ] . utxo. outpoint( ) , utxo1. outpoint) ;
1428-
1429- // UTXO should still be LocalOutput
1430- assert ! ( matches!(
1431- new_builder. params. utxos[ 0 ] ,
1432- WeightedUtxo {
1433- utxo: Utxo :: Local ( ..) ,
1434- ..
1435- }
1436- ) ) ;
1312+ assert_eq ! ( builder. params. utxos. len( ) , 1 ) ;
1313+ assert ! (
1314+ matches!( & builder. params. utxos[ 0 ] . utxo, Utxo :: Local ( output) if output. outpoint == outpoint)
1315+ ) ;
14371316 }
14381317}
0 commit comments