@@ -121,7 +121,7 @@ impl<'a> CoinSelector<'a> {
121121 pub fn is_selection_possible ( & self , target : Target ) -> bool {
122122 let mut test = self . clone ( ) ;
123123 test. select_all_effective ( target. fee . rate ) ;
124- test. is_target_met ( target)
124+ test. excess ( target, Drain :: NONE ) >= 0
125125 }
126126
127127 /// Returns true if no candidates have been selected.
@@ -308,7 +308,7 @@ impl<'a> CoinSelector<'a> {
308308 self . selected_value ( ) as i64 - ( self . input_weight ( ) as f32 * feerate. spwu ( ) ) . ceil ( ) as i64
309309 }
310310
311- // // / Waste sum of all selected inputs.
311+ /// Waste sum of all selected inputs.
312312 fn input_waste ( & self , feerate : FeeRate , long_term_feerate : FeeRate ) -> f32 {
313313 self . input_weight ( ) as f32 * ( feerate. spwu ( ) - long_term_feerate. spwu ( ) )
314314 }
@@ -429,15 +429,20 @@ impl<'a> CoinSelector<'a> {
429429 self . unselected_indices ( ) . next ( ) . is_none ( )
430430 }
431431
432+ /// Whether the tx implied by the current selection and `drain` is within `target.max_weight`.
433+ fn is_within_max_weight ( & self , target : Target , drain : Drain ) -> bool {
434+ match target. max_weight {
435+ Some ( max_weight) => self . weight ( target. outputs , drain. weights ) <= max_weight,
436+ None => true ,
437+ }
438+ }
439+
432440 /// Whether the constraints of `Target` have been met if we include a specific `drain` ouput.
433441 ///
434- /// Note if [`is_target_met`] is true and the `drain` is produced from the [`drain`] method then
435- /// this method will also always be true.
436- ///
437- /// [`is_target_met`]: Self::is_target_met
438- /// [`drain`]: Self::drain
442+ /// Note: even if [`Self::is_target_met`] is true, this can be false when adding the `drain` pushes
443+ /// the transaction weight over [`Target::max_weight`].
439444 pub fn is_target_met_with_drain ( & self , target : Target , drain : Drain ) -> bool {
440- self . excess ( target, drain) >= 0
445+ self . excess ( target, drain) >= 0 && self . is_within_max_weight ( target , drain )
441446 }
442447
443448 /// Whether the constraints of `Target` have been met.
@@ -467,16 +472,14 @@ impl<'a> CoinSelector<'a> {
467472 } ,
468473 ) ;
469474 if excess > change_policy. min_value as i64 {
470- debug_assert_eq ! (
471- self . is_target_met( target) ,
472- self . is_target_met_with_drain(
473- target,
474- Drain {
475- weights: change_policy. drain_weights,
476- value: excess as u64
477- }
478- ) ,
479- "if the target is met without a drain it must be met after adding the drain"
475+ let drain = Drain {
476+ weights : change_policy. drain_weights ,
477+ value : excess as u64 ,
478+ } ;
479+ debug_assert ! (
480+ self . is_target_met_with_drain( target, drain)
481+ || !self . is_within_max_weight( target, drain) ,
482+ "if the target value is met without a drain it must be met after adding the drain"
480483 ) ;
481484 Some ( excess as u64 )
482485 } else {
@@ -520,13 +523,22 @@ impl<'a> CoinSelector<'a> {
520523 }
521524 }
522525
523- /// Select candidates until `target` has been met assuming the `drain` output is attached .
526+ /// Select candidates until `target` has been met.
524527 ///
525- /// Returns an error if the target was unable to be met.
526- pub fn select_until_target_met ( & mut self , target : Target ) -> Result < ( ) , InsufficientFunds > {
528+ /// # Errors
529+ ///
530+ /// - [`SelectError::InsufficientFunds`] if the candidates can't cover the target value.
531+ /// - [`SelectError::MaxWeightExceeded`] if the value is met but the selection exceeds [`Target::max_weight`].
532+ pub fn select_until_target_met ( & mut self , target : Target ) -> Result < ( ) , SelectError > {
527533 self . select_until ( |cs| cs. is_target_met ( target) )
528- . ok_or_else ( || InsufficientFunds {
529- missing : self . excess ( target, Drain :: NONE ) . unsigned_abs ( ) ,
534+ . ok_or_else ( || {
535+ if !self . is_within_max_weight ( target, Drain :: NONE ) {
536+ SelectError :: MaxWeightExceeded
537+ } else {
538+ SelectError :: InsufficientFunds ( InsufficientFunds {
539+ missing : self . excess ( target, Drain :: NONE ) . unsigned_abs ( ) ,
540+ } )
541+ }
530542 } )
531543 }
532544
@@ -641,6 +653,38 @@ impl DoubleEndedIterator for SelectIter<'_> {
641653 }
642654}
643655
656+ /// Error returned when a selection cannot satisfy the [`Target`].
657+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
658+ pub enum SelectError {
659+ /// The selected inputs don't cover the target value (plus fees).
660+ InsufficientFunds ( InsufficientFunds ) ,
661+ /// The target value is met, but the resulting transaction exceeds [`Target::max_weight`].
662+ MaxWeightExceeded ,
663+ }
664+
665+ impl core:: fmt:: Display for SelectError {
666+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
667+ match self {
668+ Self :: InsufficientFunds ( e) => write ! ( f, "{}" , e) ,
669+ Self :: MaxWeightExceeded => {
670+ write ! (
671+ f,
672+ "selection exceeds the maximum allowed transaction weight"
673+ )
674+ }
675+ }
676+ }
677+ }
678+
679+ #[ cfg( feature = "std" ) ]
680+ impl std:: error:: Error for SelectError { }
681+
682+ impl From < InsufficientFunds > for SelectError {
683+ fn from ( e : InsufficientFunds ) -> Self {
684+ Self :: InsufficientFunds ( e)
685+ }
686+ }
687+
644688/// Error type that occurs when the target amount cannot be met.
645689#[ derive( Clone , Debug , Copy , PartialEq , Eq ) ]
646690pub struct InsufficientFunds {
0 commit comments