@@ -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,15 @@ 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(
475+ debug_assert ! (
476+ self . excess(
473477 target,
474478 Drain {
475479 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"
480+ value: excess as u64 ,
481+ } ,
482+ ) >= 0 ,
483+ "if the target value is met without a drain it must be met after adding the drain"
480484 ) ;
481485 Some ( excess as u64 )
482486 } else {
@@ -520,13 +524,26 @@ impl<'a> CoinSelector<'a> {
520524 }
521525 }
522526
523- /// Select candidates until `target` has been met assuming the `drain` output is attached.
527+ /// Select candidates until `target` has been met.
528+ ///
529+ /// # Errors
524530 ///
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 > {
531+ /// - [`SelectError::InsufficientFunds`] if the candidates can't cover the target value.
532+ /// - [`SelectError::MaxWeightExceeded`] if the value is met but the selection exceeds
533+ /// [`Target::max_weight`].
534+ pub fn select_until_target_met ( & mut self , target : Target ) -> Result < ( ) , SelectError > {
527535 self . select_until ( |cs| cs. is_target_met ( target) )
528- . ok_or_else ( || InsufficientFunds {
529- missing : self . excess ( target, Drain :: NONE ) . unsigned_abs ( ) ,
536+ . ok_or_else ( || {
537+ let excess = self . excess ( target, Drain :: NONE ) ;
538+ // excess < 0 means unfundable (InsufficientFunds),
539+ // else value is met so the weight cap failed (MaxWeightExceeded).
540+ if excess >= 0 {
541+ SelectError :: MaxWeightExceeded
542+ } else {
543+ SelectError :: InsufficientFunds ( InsufficientFunds {
544+ missing : excess. unsigned_abs ( ) ,
545+ } )
546+ }
530547 } )
531548 }
532549
@@ -641,6 +658,38 @@ impl DoubleEndedIterator for SelectIter<'_> {
641658 }
642659}
643660
661+ /// Error returned when a selection cannot satisfy the [`Target`].
662+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
663+ pub enum SelectError {
664+ /// The selected inputs don't cover the target value (plus fees).
665+ InsufficientFunds ( InsufficientFunds ) ,
666+ /// The target value is met, but the resulting transaction exceeds [`Target::max_weight`].
667+ MaxWeightExceeded ,
668+ }
669+
670+ impl core:: fmt:: Display for SelectError {
671+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
672+ match self {
673+ Self :: InsufficientFunds ( e) => write ! ( f, "{}" , e) ,
674+ Self :: MaxWeightExceeded => {
675+ write ! (
676+ f,
677+ "selection exceeds the maximum allowed transaction weight"
678+ )
679+ }
680+ }
681+ }
682+ }
683+
684+ #[ cfg( feature = "std" ) ]
685+ impl std:: error:: Error for SelectError { }
686+
687+ impl From < InsufficientFunds > for SelectError {
688+ fn from ( e : InsufficientFunds ) -> Self {
689+ Self :: InsufficientFunds ( e)
690+ }
691+ }
692+
644693/// Error type that occurs when the target amount cannot be met.
645694#[ derive( Clone , Debug , Copy , PartialEq , Eq ) ]
646695pub struct InsufficientFunds {
0 commit comments