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