@@ -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.
@@ -520,13 +525,26 @@ impl<'a> CoinSelector<'a> {
520525 }
521526 }
522527
523- /// Select candidates until `target` has been met assuming the `drain` output is attached.
528+ /// Select candidates until `target` has been met.
529+ ///
530+ /// # Errors
524531 ///
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 > {
532+ /// - [`SelectError::InsufficientFunds`] if the candidates can't cover the target value.
533+ /// - [`SelectError::MaxWeightExceeded`] if the value is met but the selection exceeds
534+ /// [`Target::max_weight`].
535+ pub fn select_until_target_met ( & mut self , target : Target ) -> Result < ( ) , SelectError > {
527536 self . select_until ( |cs| cs. is_target_met ( target) )
528- . ok_or_else ( || InsufficientFunds {
529- missing : self . excess ( target, Drain :: NONE ) . unsigned_abs ( ) ,
537+ . ok_or_else ( || {
538+ let excess = self . excess ( target, Drain :: NONE ) ;
539+ // excess < 0 means unfundable (InsufficientFunds),
540+ // else value is met so the weight cap failed (MaxWeightExceeded).
541+ if excess >= 0 {
542+ SelectError :: MaxWeightExceeded
543+ } else {
544+ SelectError :: InsufficientFunds ( InsufficientFunds {
545+ missing : excess. unsigned_abs ( ) ,
546+ } )
547+ }
530548 } )
531549 }
532550
@@ -641,6 +659,38 @@ impl DoubleEndedIterator for SelectIter<'_> {
641659 }
642660}
643661
662+ /// Error returned when a selection cannot satisfy the [`Target`].
663+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
664+ pub enum SelectError {
665+ /// The selected inputs don't cover the target value (plus fees).
666+ InsufficientFunds ( InsufficientFunds ) ,
667+ /// The target value is met, but the resulting transaction exceeds [`Target::max_weight`].
668+ MaxWeightExceeded ,
669+ }
670+
671+ impl core:: fmt:: Display for SelectError {
672+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
673+ match self {
674+ Self :: InsufficientFunds ( e) => write ! ( f, "{}" , e) ,
675+ Self :: MaxWeightExceeded => {
676+ write ! (
677+ f,
678+ "selection exceeds the maximum allowed transaction weight"
679+ )
680+ }
681+ }
682+ }
683+ }
684+
685+ #[ cfg( feature = "std" ) ]
686+ impl std:: error:: Error for SelectError { }
687+
688+ impl From < InsufficientFunds > for SelectError {
689+ fn from ( e : InsufficientFunds ) -> Self {
690+ Self :: InsufficientFunds ( e)
691+ }
692+ }
693+
644694/// Error type that occurs when the target amount cannot be met.
645695#[ derive( Clone , Debug , Copy , PartialEq , Eq ) ]
646696pub struct InsufficientFunds {
0 commit comments