@@ -1259,180 +1259,59 @@ mod test {
1259
1259
) ;
1260
1260
}
1261
1261
1262
+ // Test that local outputs have precedence over utxos added via `add_foreign_utxo`
1262
1263
#[ 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 ( ) ;
1305
1267
1306
- builder . params . clone ( )
1307
- } ;
1268
+ let utxo = wallet . list_unspent ( ) . next ( ) . unwrap ( ) ;
1269
+ let outpoint = utxo . outpoint ;
1308
1270
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 ( ) ;
1312
1274
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) ;
1322
1276
1323
- // add foreign UTXO
1324
- assert ! ( new_builder
1277
+ builder
1325
1278
. add_foreign_utxo (
1326
- utxo1 . outpoint,
1279
+ outpoint,
1327
1280
psbt:: Input {
1328
- non_witness_utxo : Some ( tx1 ) ,
1281
+ witness_utxo : Some ( utxo . txout . clone ( ) ) ,
1329
1282
..Default :: default ( )
1330
1283
} ,
1331
- satisfaction_weight ,
1284
+ Weight :: from_wu ( 107 ) ,
1332
1285
)
1333
- . is_ok ( ) ) ;
1286
+ . unwrap ( ) ;
1334
1287
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 ) ;
1338
1289
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,
1344
1292
) ) ;
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" ) ;
1372
1293
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 ( ) ;
1375
1296
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
+ )
1379
1306
. unwrap ( ) ;
1380
1307
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) ;
1398
1309
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 ( ) ;
1418
1311
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
+ ) ;
1437
1316
}
1438
1317
}
0 commit comments