@@ -30,6 +30,7 @@ use crate::sign::{
30
30
ChannelDerivationParameters , HTLCDescriptor , SignerProvider , P2WPKH_WITNESS_WEIGHT ,
31
31
} ;
32
32
use crate :: sync:: Mutex ;
33
+ use crate :: util:: async_poll:: { AsyncResult , MaybeSend , MaybeSync } ;
33
34
use crate :: util:: logger:: Logger ;
34
35
35
36
use bitcoin:: amount:: Amount ;
@@ -346,42 +347,42 @@ pub trait CoinSelectionSource {
346
347
/// other claims, implementations must be willing to double spend their UTXOs. The choice of
347
348
/// which UTXOs to double spend is left to the implementation, but it must strive to keep the
348
349
/// set of other claims being double spent to a minimum.
349
- fn select_confirmed_utxos (
350
- & self , claim_id : ClaimId , must_spend : Vec < Input > , must_pay_to : & [ TxOut ] ,
350
+ fn select_confirmed_utxos < ' a > (
351
+ & ' a self , claim_id : ClaimId , must_spend : Vec < Input > , must_pay_to : & ' a [ TxOut ] ,
351
352
target_feerate_sat_per_1000_weight : u32 ,
352
- ) -> Result < CoinSelection , ( ) > ;
353
+ ) -> AsyncResult < ' a , CoinSelection > ;
353
354
/// Signs and provides the full witness for all inputs within the transaction known to the
354
355
/// trait (i.e., any provided via [`CoinSelectionSource::select_confirmed_utxos`]).
355
356
///
356
357
/// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
357
358
/// unsigned transaction and then sign it with your wallet.
358
- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > ;
359
+ fn sign_psbt < ' a > ( & ' a self , psbt : Psbt ) -> AsyncResult < ' a , Transaction > ;
359
360
}
360
361
361
362
/// An alternative to [`CoinSelectionSource`] that can be implemented and used along [`Wallet`] to
362
363
/// provide a default implementation to [`CoinSelectionSource`].
363
364
pub trait WalletSource {
364
365
/// Returns all UTXOs, with at least 1 confirmation each, that are available to spend.
365
- fn list_confirmed_utxos ( & self ) -> Result < Vec < Utxo > , ( ) > ;
366
+ fn list_confirmed_utxos < ' a > ( & ' a self ) -> AsyncResult < ' a , Vec < Utxo > > ;
366
367
/// Returns a script to use for change above dust resulting from a successful coin selection
367
368
/// attempt.
368
- fn get_change_script ( & self ) -> Result < ScriptBuf , ( ) > ;
369
+ fn get_change_script < ' a > ( & ' a self ) -> AsyncResult < ' a , ScriptBuf > ;
369
370
/// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
370
371
/// the transaction known to the wallet (i.e., any provided via
371
372
/// [`WalletSource::list_confirmed_utxos`]).
372
373
///
373
374
/// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
374
375
/// unsigned transaction and then sign it with your wallet.
375
- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > ;
376
+ fn sign_psbt < ' a > ( & ' a self , psbt : Psbt ) -> AsyncResult < ' a , Transaction > ;
376
377
}
377
378
378
379
/// A wrapper over [`WalletSource`] that implements [`CoinSelection`] by preferring UTXOs that would
379
380
/// avoid conflicting double spends. If not enough UTXOs are available to do so, conflicting double
380
381
/// spends may happen.
381
- pub struct Wallet < W : Deref , L : Deref >
382
+ pub struct Wallet < W : Deref + MaybeSync + MaybeSend , L : Deref + MaybeSync + MaybeSend >
382
383
where
383
- W :: Target : WalletSource ,
384
- L :: Target : Logger ,
384
+ W :: Target : WalletSource + MaybeSend ,
385
+ L :: Target : Logger + MaybeSend ,
385
386
{
386
387
source : W ,
387
388
logger : L ,
@@ -391,10 +392,10 @@ where
391
392
locked_utxos : Mutex < HashMap < OutPoint , ClaimId > > ,
392
393
}
393
394
394
- impl < W : Deref , L : Deref > Wallet < W , L >
395
+ impl < W : Deref + MaybeSync + MaybeSend , L : Deref + MaybeSync + MaybeSend > Wallet < W , L >
395
396
where
396
- W :: Target : WalletSource ,
397
- L :: Target : Logger ,
397
+ W :: Target : WalletSource + MaybeSend ,
398
+ L :: Target : Logger + MaybeSend ,
398
399
{
399
400
/// Returns a new instance backed by the given [`WalletSource`] that serves as an implementation
400
401
/// of [`CoinSelectionSource`].
@@ -410,7 +411,7 @@ where
410
411
/// `tolerate_high_network_feerates` is set, we'll attempt to spend UTXOs that contribute at
411
412
/// least 1 satoshi at the current feerate, otherwise, we'll only attempt to spend those which
412
413
/// contribute at least twice their fee.
413
- fn select_confirmed_utxos_internal (
414
+ async fn select_confirmed_utxos_internal (
414
415
& self , utxos : & [ Utxo ] , claim_id : ClaimId , force_conflicting_utxo_spend : bool ,
415
416
tolerate_high_network_feerates : bool , target_feerate_sat_per_1000_weight : u32 ,
416
417
preexisting_tx_weight : u64 , input_amount_sat : Amount , target_amount_sat : Amount ,
@@ -484,7 +485,7 @@ where
484
485
}
485
486
486
487
let remaining_amount = selected_amount - target_amount_sat - total_fees;
487
- let change_script = self . source . get_change_script ( ) ?;
488
+ let change_script = self . source . get_change_script ( ) . await ?;
488
489
let change_output_fee = fee_for_weight (
489
490
target_feerate_sat_per_1000_weight,
490
491
( 8 /* value */ + change_script. consensus_encode ( & mut sink ( ) ) . unwrap ( ) as u64 )
@@ -503,60 +504,67 @@ where
503
504
}
504
505
}
505
506
506
- impl < W : Deref , L : Deref > CoinSelectionSource for Wallet < W , L >
507
+ impl < W : Deref + MaybeSync + MaybeSend , L : Deref + MaybeSync + MaybeSend > CoinSelectionSource
508
+ for Wallet < W , L >
507
509
where
508
- W :: Target : WalletSource ,
509
- L :: Target : Logger ,
510
+ W :: Target : WalletSource + MaybeSend + MaybeSync ,
511
+ L :: Target : Logger + MaybeSend + MaybeSync ,
510
512
{
511
- fn select_confirmed_utxos (
512
- & self , claim_id : ClaimId , must_spend : Vec < Input > , must_pay_to : & [ TxOut ] ,
513
+ fn select_confirmed_utxos < ' a > (
514
+ & ' a self , claim_id : ClaimId , must_spend : Vec < Input > , must_pay_to : & ' a [ TxOut ] ,
513
515
target_feerate_sat_per_1000_weight : u32 ,
514
- ) -> Result < CoinSelection , ( ) > {
515
- let utxos = self . source . list_confirmed_utxos ( ) ?;
516
- // TODO: Use fee estimation utils when we upgrade to bitcoin v0.30.0.
517
- const BASE_TX_SIZE : u64 = 4 /* version */ + 1 /* input count */ + 1 /* output count */ + 4 /* locktime */ ;
518
- let total_output_size: u64 = must_pay_to
519
- . iter ( )
520
- . map ( |output| 8 /* value */ + 1 /* script len */ + output. script_pubkey . len ( ) as u64 )
521
- . sum ( ) ;
522
- let total_satisfaction_weight: u64 =
523
- must_spend. iter ( ) . map ( |input| input. satisfaction_weight ) . sum ( ) ;
524
- let total_input_weight =
525
- ( BASE_INPUT_WEIGHT * must_spend. len ( ) as u64 ) + total_satisfaction_weight;
526
-
527
- let preexisting_tx_weight = 2 /* segwit marker & flag */ + total_input_weight +
516
+ ) -> AsyncResult < ' a , CoinSelection > {
517
+ Box :: pin ( async move {
518
+ let utxos = self . source . list_confirmed_utxos ( ) . await ?;
519
+ // TODO: Use fee estimation utils when we upgrade to bitcoin v0.30.0.
520
+ const BASE_TX_SIZE : u64 = 4 /* version */ + 1 /* input count */ + 1 /* output count */ + 4 /* locktime */ ;
521
+ let total_output_size: u64 = must_pay_to
522
+ . iter ( )
523
+ . map (
524
+ |output| 8 /* value */ + 1 /* script len */ + output. script_pubkey . len ( ) as u64 ,
525
+ )
526
+ . sum ( ) ;
527
+ let total_satisfaction_weight: u64 =
528
+ must_spend. iter ( ) . map ( |input| input. satisfaction_weight ) . sum ( ) ;
529
+ let total_input_weight =
530
+ ( BASE_INPUT_WEIGHT * must_spend. len ( ) as u64 ) + total_satisfaction_weight;
531
+
532
+ let preexisting_tx_weight = 2 /* segwit marker & flag */ + total_input_weight +
528
533
( ( BASE_TX_SIZE + total_output_size) * WITNESS_SCALE_FACTOR as u64 ) ;
529
- let input_amount_sat = must_spend. iter ( ) . map ( |input| input. previous_utxo . value ) . sum ( ) ;
530
- let target_amount_sat = must_pay_to. iter ( ) . map ( |output| output. value ) . sum ( ) ;
534
+ let input_amount_sat = must_spend. iter ( ) . map ( |input| input. previous_utxo . value ) . sum ( ) ;
535
+ let target_amount_sat = must_pay_to. iter ( ) . map ( |output| output. value ) . sum ( ) ;
531
536
532
- let configs = [ ( false , false ) , ( false , true ) , ( true , false ) , ( true , true ) ] ;
533
- for ( force_conflicting_utxo_spend, tolerate_high_network_feerates) in configs {
534
- log_debug ! (
535
- self . logger,
536
- "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})" ,
537
- target_feerate_sat_per_1000_weight,
538
- force_conflicting_utxo_spend,
539
- tolerate_high_network_feerates
540
- ) ;
541
- let attempt = self . select_confirmed_utxos_internal (
542
- & utxos,
543
- claim_id,
544
- force_conflicting_utxo_spend,
545
- tolerate_high_network_feerates,
546
- target_feerate_sat_per_1000_weight,
547
- preexisting_tx_weight,
548
- input_amount_sat,
549
- target_amount_sat,
550
- ) ;
551
- if attempt. is_ok ( ) {
552
- return attempt;
537
+ let configs = [ ( false , false ) , ( false , true ) , ( true , false ) , ( true , true ) ] ;
538
+ for ( force_conflicting_utxo_spend, tolerate_high_network_feerates) in configs {
539
+ log_debug ! (
540
+ self . logger,
541
+ "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})" ,
542
+ target_feerate_sat_per_1000_weight,
543
+ force_conflicting_utxo_spend,
544
+ tolerate_high_network_feerates
545
+ ) ;
546
+ let attempt = self
547
+ . select_confirmed_utxos_internal (
548
+ & utxos,
549
+ claim_id,
550
+ force_conflicting_utxo_spend,
551
+ tolerate_high_network_feerates,
552
+ target_feerate_sat_per_1000_weight,
553
+ preexisting_tx_weight,
554
+ input_amount_sat,
555
+ target_amount_sat,
556
+ )
557
+ . await ;
558
+ if attempt. is_ok ( ) {
559
+ return attempt;
560
+ }
553
561
}
554
- }
555
- Err ( ( ) )
562
+ Err ( ( ) )
563
+ } )
556
564
}
557
565
558
- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > {
559
- self . source . sign_psbt ( psbt)
566
+ fn sign_psbt < ' a > ( & ' a self , psbt : Psbt ) -> AsyncResult < ' a , Transaction > {
567
+ Box :: pin ( async move { self . source . sign_psbt ( psbt) . await } )
560
568
}
561
569
}
562
570
@@ -635,7 +643,7 @@ where
635
643
/// Handles a [`BumpTransactionEvent::ChannelClose`] event variant by producing a fully-signed
636
644
/// transaction spending an anchor output of the commitment transaction to bump its fee and
637
645
/// broadcasts them to the network as a package.
638
- fn handle_channel_close (
646
+ async fn handle_channel_close (
639
647
& self , claim_id : ClaimId , package_target_feerate_sat_per_1000_weight : u32 ,
640
648
commitment_tx : & Transaction , commitment_tx_fee_sat : u64 ,
641
649
anchor_descriptor : & AnchorDescriptor ,
@@ -662,12 +670,15 @@ where
662
670
663
671
log_debug ! ( self . logger, "Performing coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW" ,
664
672
package_target_feerate_sat_per_1000_weight) ;
665
- let coin_selection: CoinSelection = self . utxo_source . select_confirmed_utxos (
666
- claim_id,
667
- must_spend,
668
- & [ ] ,
669
- package_target_feerate_sat_per_1000_weight,
670
- ) ?;
673
+ let coin_selection: CoinSelection = self
674
+ . utxo_source
675
+ . select_confirmed_utxos (
676
+ claim_id,
677
+ must_spend,
678
+ & [ ] ,
679
+ package_target_feerate_sat_per_1000_weight,
680
+ )
681
+ . await ?;
671
682
672
683
let mut anchor_tx = Transaction {
673
684
version : Version :: TWO ,
@@ -733,7 +744,7 @@ where
733
744
}
734
745
735
746
log_debug ! ( self . logger, "Signing anchor transaction {}" , anchor_txid) ;
736
- anchor_tx = self . utxo_source . sign_psbt ( anchor_psbt) ?;
747
+ anchor_tx = self . utxo_source . sign_psbt ( anchor_psbt) . await ?;
737
748
738
749
let signer = self
739
750
. signer_provider
@@ -780,7 +791,7 @@ where
780
791
781
792
/// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
782
793
/// fully-signed, fee-bumped HTLC transaction that is broadcast to the network.
783
- fn handle_htlc_resolution (
794
+ async fn handle_htlc_resolution (
784
795
& self , claim_id : ClaimId , target_feerate_sat_per_1000_weight : u32 ,
785
796
htlc_descriptors : & [ HTLCDescriptor ] , tx_lock_time : LockTime ,
786
797
) -> Result < ( ) , ( ) > {
@@ -821,12 +832,15 @@ where
821
832
let must_spend_amount =
822
833
must_spend. iter ( ) . map ( |input| input. previous_utxo . value . to_sat ( ) ) . sum :: < u64 > ( ) ;
823
834
824
- let coin_selection: CoinSelection = self . utxo_source . select_confirmed_utxos (
825
- claim_id,
826
- must_spend,
827
- & htlc_tx. output ,
828
- target_feerate_sat_per_1000_weight,
829
- ) ?;
835
+ let coin_selection: CoinSelection = self
836
+ . utxo_source
837
+ . select_confirmed_utxos (
838
+ claim_id,
839
+ must_spend,
840
+ & htlc_tx. output ,
841
+ target_feerate_sat_per_1000_weight,
842
+ )
843
+ . await ?;
830
844
831
845
#[ cfg( debug_assertions) ]
832
846
let input_satisfaction_weight: u64 =
@@ -870,7 +884,7 @@ where
870
884
"Signing HTLC transaction {}" ,
871
885
htlc_psbt. unsigned_tx. compute_txid( )
872
886
) ;
873
- htlc_tx = self . utxo_source . sign_psbt ( htlc_psbt) ?;
887
+ htlc_tx = self . utxo_source . sign_psbt ( htlc_psbt) . await ?;
874
888
875
889
let mut signers = BTreeMap :: new ( ) ;
876
890
for ( idx, htlc_descriptor) in htlc_descriptors. iter ( ) . enumerate ( ) {
@@ -909,7 +923,7 @@ where
909
923
}
910
924
911
925
/// Handles all variants of [`BumpTransactionEvent`].
912
- pub fn handle_event ( & self , event : & BumpTransactionEvent ) {
926
+ pub async fn handle_event ( & self , event : & BumpTransactionEvent ) {
913
927
match event {
914
928
BumpTransactionEvent :: ChannelClose {
915
929
claim_id,
@@ -925,19 +939,21 @@ where
925
939
log_bytes!( claim_id. 0 ) ,
926
940
commitment_tx. compute_txid( )
927
941
) ;
928
- if let Err ( _ ) = self . handle_channel_close (
942
+ self . handle_channel_close (
929
943
* claim_id,
930
944
* package_target_feerate_sat_per_1000_weight,
931
945
commitment_tx,
932
946
* commitment_tx_fee_satoshis,
933
947
anchor_descriptor,
934
- ) {
948
+ )
949
+ . await
950
+ . unwrap_or_else ( |_| {
935
951
log_error ! (
936
952
self . logger,
937
953
"Failed bumping commitment transaction fee for {}" ,
938
954
commitment_tx. compute_txid( )
939
955
) ;
940
- }
956
+ } ) ;
941
957
} ,
942
958
BumpTransactionEvent :: HTLCResolution {
943
959
claim_id,
@@ -952,18 +968,20 @@ where
952
968
log_bytes!( claim_id. 0 ) ,
953
969
log_iter!( htlc_descriptors. iter( ) . map( |d| d. outpoint( ) ) )
954
970
) ;
955
- if let Err ( _ ) = self . handle_htlc_resolution (
971
+ self . handle_htlc_resolution (
956
972
* claim_id,
957
973
* target_feerate_sat_per_1000_weight,
958
974
htlc_descriptors,
959
975
* tx_lock_time,
960
- ) {
976
+ )
977
+ . await
978
+ . unwrap_or_else ( |_| {
961
979
log_error ! (
962
980
self . logger,
963
981
"Failed bumping HTLC transaction fee for commitment {}" ,
964
982
htlc_descriptors[ 0 ] . commitment_txid
965
983
) ;
966
- }
984
+ } ) ;
967
985
} ,
968
986
}
969
987
}
@@ -973,6 +991,9 @@ where
973
991
mod tests {
974
992
use super :: * ;
975
993
994
+ use crate :: events:: bump_transaction_sync:: {
995
+ BumpTransactionEventHandlerSync , CoinSelectionSourceSync ,
996
+ } ;
976
997
use crate :: io:: Cursor ;
977
998
use crate :: ln:: chan_utils:: ChannelTransactionParameters ;
978
999
use crate :: sign:: KeysManager ;
@@ -988,7 +1009,7 @@ mod tests {
988
1009
// (commitment + anchor value, commitment + input weight, target feerate, result)
989
1010
expected_selects : Mutex < Vec < ( u64 , u64 , u32 , CoinSelection ) > > ,
990
1011
}
991
- impl CoinSelectionSource for TestCoinSelectionSource {
1012
+ impl CoinSelectionSourceSync for TestCoinSelectionSource {
992
1013
fn select_confirmed_utxos (
993
1014
& self , _claim_id : ClaimId , must_spend : Vec < Input > , _must_pay_to : & [ TxOut ] ,
994
1015
target_feerate_sat_per_1000_weight : u32 ,
@@ -1073,7 +1094,7 @@ mod tests {
1073
1094
} ;
1074
1095
let signer = KeysManager :: new ( & [ 42 ; 32 ] , 42 , 42 ) ;
1075
1096
let logger = TestLogger :: new ( ) ;
1076
- let handler = BumpTransactionEventHandler :: new ( & broadcaster, & source, & signer, & logger) ;
1097
+ let handler = BumpTransactionEventHandlerSync :: new ( & broadcaster, & source, & signer, & logger) ;
1077
1098
1078
1099
let mut transaction_parameters = ChannelTransactionParameters :: test_dummy ( 42_000_000 ) ;
1079
1100
transaction_parameters. channel_type_features =
0 commit comments