@@ -169,29 +169,10 @@ impl<'a> CoinSelector<'a> {
169169 /// enough value.
170170 ///
171171 /// [`ban`]: Self::ban
172- pub fn is_selection_possible ( & self , target : Target , drain : Drain ) -> bool {
172+ pub fn is_selection_possible ( & self , target : Target ) -> bool {
173173 let mut test = self . clone ( ) ;
174174 test. select_all_effective ( target. feerate ) ;
175- test. is_target_met ( target, drain)
176- }
177-
178- /// Is meeting the target *plausible* with this `change_policy`.
179- /// Note this will respect [`ban`]ned candidates.
180- ///
181- /// This is very similar to [`is_selection_possible`] except that you pass in a change policy.
182- /// This method will give the right answer as long as `change_policy` is monotone but otherwise
183- /// can it can give false negatives.
184- ///
185- /// [`ban`]: Self::ban
186- /// [`is_selection_possible`]: Self::is_selection_possible
187- pub fn is_selection_plausible_with_change_policy (
188- & self ,
189- target : Target ,
190- change_policy : & impl Fn ( & CoinSelector < ' a > , Target ) -> Drain ,
191- ) -> bool {
192- let mut test = self . clone ( ) ;
193- test. select_all_effective ( target. feerate ) ;
194- test. is_target_met ( target, change_policy ( & test, target) )
175+ test. is_target_met ( target)
195176 }
196177
197178 /// Returns true if no candidates have been selected.
@@ -283,6 +264,14 @@ impl<'a> CoinSelector<'a> {
283264 ( self . weight ( drain_weight) as f32 * feerate. spwu ( ) ) . ceil ( ) as u64
284265 }
285266
267+ /// The actual fee the selection would pay if it was used in a transaction that had
268+ /// `target_value` value for outputs and change output of `drain_value`.
269+ ///
270+ /// This can be negative when the selection is invalid (outputs are greater than inputs).
271+ pub fn fee ( & self , target_value : u64 , drain_value : u64 ) -> i64 {
272+ self . selected_value ( ) as i64 - target_value as i64 - drain_value as i64
273+ }
274+
286275 /// The value of the current selected inputs minus the fee needed to pay for the selected inputs
287276 pub fn effective_value ( & self , feerate : FeeRate ) -> i64 {
288277 self . selected_value ( ) as i64 - ( self . input_weight ( ) as f32 * feerate. spwu ( ) ) . ceil ( ) as i64
@@ -330,7 +319,9 @@ impl<'a> CoinSelector<'a> {
330319
331320 /// Sorts the candidates by descending value per weight unit, tie-breaking with value.
332321 pub fn sort_candidates_by_descending_value_pwu ( & mut self ) {
333- self . sort_candidates_by_key ( |( _, wv) | core:: cmp:: Reverse ( ( wv. value_pwu ( ) , wv. value ) ) ) ;
322+ self . sort_candidates_by_key ( |( _, wv) | {
323+ core:: cmp:: Reverse ( ( Ordf32 ( wv. value_pwu ( ) ) , wv. value ) )
324+ } ) ;
334325 }
335326
336327 /// The waste created by the current selection as measured by the [waste metric].
@@ -405,19 +396,30 @@ impl<'a> CoinSelector<'a> {
405396 self . unselected_indices ( ) . next ( ) . is_none ( )
406397 }
407398
408- /// Whether the constraints of `Target` have been met if we include the `drain` ouput.
409- pub fn is_target_met ( & self , target : Target , drain : Drain ) -> bool {
399+ /// Whether the constraints of `Target` have been met if we include a specific `drain` ouput.
400+ ///
401+ /// Note if [`is_target_met`] is true and the `drain` is produced from the [`drain`] method then
402+ /// this method will also always be true.
403+ ///
404+ /// [`is_target_met`]: Self::is_target_met
405+ /// [`drain`]: Self::drain
406+ pub fn is_target_met_with_drain ( & self , target : Target , drain : Drain ) -> bool {
410407 self . excess ( target, drain) >= 0
411408 }
412409
410+ /// Whether the constraints of `Target` have been met.
411+ pub fn is_target_met ( & self , target : Target ) -> bool {
412+ self . is_target_met_with_drain ( target, Drain :: none ( ) )
413+ }
414+
413415 /// Whether the constrains of `Target` have been met if we include the drain (change) output
414416 /// when `change_policy` decides it should be present.
415417 pub fn is_target_met_with_change_policy (
416418 & self ,
417419 target : Target ,
418420 change_policy : ChangePolicy ,
419421 ) -> bool {
420- self . is_target_met ( target, self . drain ( target, change_policy) )
422+ self . is_target_met_with_drain ( target, self . drain ( target, change_policy) )
421423 }
422424
423425 /// Select all unselected candidates
@@ -442,17 +444,34 @@ impl<'a> CoinSelector<'a> {
442444 } ,
443445 ) ;
444446 if excess > change_policy. min_value as i64 {
447+ debug_assert_eq ! (
448+ self . is_target_met( target) ,
449+ self . is_target_met_with_drain(
450+ target,
451+ Drain {
452+ weights: change_policy. drain_weights,
453+ value: excess as u64
454+ }
455+ ) ,
456+ "if the target is met without a drain it must be met after adding the drain"
457+ ) ;
445458 Some ( excess as u64 )
446459 } else {
447460 None
448461 }
449462 }
450463
451- /// Convienince method that calls [`drain_value`] and converts the result into `Drain` by using
452- /// the provided `DrainWeights`. Note carefully that the `change_policy` should have been
453- /// calculated with the same `DrainWeights`.
464+ /// Figures out whether the current selection should have a change output given the
465+ /// `change_policy`. If it shouldn't then it will return a `Drain` where [`Drain::is_none`] is
466+ /// true. The value of the `Drain` will be the same as [`drain_value`].
467+ ///
468+ /// If [`is_target_met`] returns true for this selection then [`is_target_met_with_drain`] will
469+ /// also be true if you pass in the drain returned from this method.
454470 ///
455471 /// [`drain_value`]: Self::drain_value
472+ /// [`is_target_met_with_drain`]: Self::is_target_met_with_drain
473+ /// [`is_target_met`]: Self::is_target_met
474+ #[ must_use]
456475 pub fn drain ( & self , target : Target , change_policy : ChangePolicy ) -> Drain {
457476 match self . drain_value ( target, change_policy) {
458477 Some ( value) => Drain {
@@ -470,7 +489,7 @@ impl<'a> CoinSelector<'a> {
470489 for cand_index in self . candidate_order . iter ( ) {
471490 if self . selected . contains ( cand_index)
472491 || self . banned . contains ( cand_index)
473- || self . candidates [ * cand_index] . effective_value ( feerate) <= Ordf32 ( 0.0 )
492+ || self . candidates [ * cand_index] . effective_value ( feerate) <= 0.0
474493 {
475494 continue ;
476495 }
@@ -486,7 +505,7 @@ impl<'a> CoinSelector<'a> {
486505 target : Target ,
487506 drain : Drain ,
488507 ) -> Result < ( ) , InsufficientFunds > {
489- self . select_until ( |cs| cs. is_target_met ( target, drain) )
508+ self . select_until ( |cs| cs. is_target_met_with_drain ( target, drain) )
490509 . ok_or_else ( || InsufficientFunds {
491510 missing : self . excess ( target, drain) . unsigned_abs ( ) ,
492511 } )
@@ -615,13 +634,13 @@ impl Candidate {
615634 }
616635
617636 /// Effective value of this input candidate: `actual_value - input_weight * feerate (sats/wu)`.
618- pub fn effective_value ( & self , feerate : FeeRate ) -> Ordf32 {
619- Ordf32 ( self . value as f32 - ( self . weight as f32 * feerate. spwu ( ) ) )
637+ pub fn effective_value ( & self , feerate : FeeRate ) -> f32 {
638+ self . value as f32 - ( self . weight as f32 * feerate. spwu ( ) )
620639 }
621640
622641 /// Value per weight unit
623- pub fn value_pwu ( & self ) -> Ordf32 {
624- Ordf32 ( self . value as f32 / self . weight as f32 )
642+ pub fn value_pwu ( & self ) -> f32 {
643+ self . value as f32 / self . weight as f32
625644 }
626645}
627646
@@ -647,11 +666,17 @@ impl DrainWeights {
647666 + self . spend_weight as f32 * long_term_feerate. spwu ( )
648667 }
649668
650- /// Create [`DrainWeights`] that represents a drain output with a taproot keyspend.
669+ /// The fee you will pay to spend these change output(s) in the future.
670+ pub fn spend_fee ( & self , long_term_feerate : FeeRate ) -> u64 {
671+ ( self . spend_weight as f32 * long_term_feerate. spwu ( ) ) . ceil ( ) as u64
672+ }
673+
674+ /// Create [`DrainWeights`] that represents a drain output that will be spent with a taproot
675+ /// keyspend
651676 pub fn new_tr_keyspend ( ) -> Self {
652677 Self {
653678 output_weight : TXOUT_BASE_WEIGHT + TR_SPK_WEIGHT ,
654- spend_weight : TXIN_BASE_WEIGHT + TR_KEYSPEND_SATISFACTION_WEIGHT ,
679+ spend_weight : TR_KEYSPEND_TXIN_WEIGHT ,
655680 }
656681 }
657682}
0 commit comments