@@ -15,11 +15,13 @@ mod branch_and_bound;
1515mod coin_grinder;
1616mod single_random_draw;
1717
18+ mod weighted_utxo;
19+
20+ pub use crate :: weighted_utxo:: WeightedUtxo ;
21+
1822/// Possible returned error types if no match is found.
1923pub mod errors;
2024
21- use std:: cmp:: Ordering ;
22-
2325use bitcoin_units:: { Amount , FeeRate , SignedAmount , Weight } ;
2426#[ cfg( feature = "rand" ) ]
2527#[ cfg_attr( docsrs, doc( cfg( feature = "rand" ) ) ) ]
@@ -60,91 +62,6 @@ pub(crate) fn effective_value(
6062 Some ( eff_value)
6163}
6264
63- #[ derive( Debug , Clone , PartialEq , Eq ) ]
64- /// Represents the spendable conditions of a `UTXO`.
65- pub struct WeightedUtxo {
66- /// The `Amount` that the output contributes towards the selection target.
67- value : Amount ,
68- /// The estimated `Weight` (satisfaction weight + base weight) of the output.
69- weight : Weight ,
70- /// The positive effective value `(value - fee)`. This value is stored as a `u64` for
71- /// better performance.
72- effective_value : u64 ,
73- /// The `SignedAmount` required to spend the output at the given `fee_rate`.
74- fee : SignedAmount ,
75- /// The `SignedAmount` required to spend the output at the given `long_term_fee_rate`.
76- long_term_fee : SignedAmount ,
77- /// A metric for how wasteful it is to spend this `WeightedUtxo` given the current fee
78- /// environment.
79- waste : i64 ,
80- }
81-
82- impl WeightedUtxo {
83- /// Creates a new `WeightedUtxo`.
84- pub fn new (
85- value : Amount ,
86- weight : Weight ,
87- fee_rate : FeeRate ,
88- long_term_fee_rate : FeeRate ,
89- ) -> Option < WeightedUtxo > {
90- let positive_effective_value = Self :: positive_effective_value ( fee_rate, weight, value) ;
91-
92- if let Some ( effective_value) = positive_effective_value {
93- let fee = fee_rate. fee_wu ( weight) ?. to_signed ( ) ;
94- let long_term_fee: SignedAmount = long_term_fee_rate. fee_wu ( weight) ?. to_signed ( ) ;
95- let waste = Self :: calculate_waste ( fee, long_term_fee) ;
96- return Some ( Self { value, weight, effective_value, fee, long_term_fee, waste } ) ;
97- }
98-
99- None
100- }
101-
102- /// Calculates if the current fee environment is expensive.
103- pub fn is_fee_expensive ( & self ) -> bool { self . fee > self . long_term_fee }
104-
105- /// Returns the associated value.
106- pub fn value ( & self ) -> Amount { self . value }
107-
108- /// Returns the associated weight.
109- pub fn weight ( & self ) -> Weight { self . weight }
110-
111- /// Returns the associated waste.
112- pub fn waste ( & self ) -> SignedAmount { SignedAmount :: from_sat ( self . waste ) . unwrap ( ) }
113-
114- /// Returns the calculated effective value.
115- pub fn effective_value ( & self ) -> Amount { Amount :: from_sat ( self . effective_value ) . unwrap ( ) }
116-
117- /// Returns the calculated effective value using the underlying type without transformation.
118- pub fn effective_value_raw ( & self ) -> u64 { self . effective_value }
119-
120- /// Returns the calculated waste using the underlying type without transformation.
121- pub fn waste_raw ( & self ) -> i64 { self . waste }
122-
123- fn positive_effective_value ( fee_rate : FeeRate , weight : Weight , value : Amount ) -> Option < u64 > {
124- if let Some ( eff_value) = effective_value ( fee_rate, weight, value) {
125- if let Ok ( unsigned) = eff_value. to_unsigned ( ) {
126- return Some ( unsigned. to_sat ( ) ) ;
127- }
128- }
129-
130- None
131- }
132-
133- fn calculate_waste ( fee : SignedAmount , long_term_fee : SignedAmount ) -> i64 {
134- fee. to_sat ( ) - long_term_fee. to_sat ( )
135- }
136- }
137-
138- impl Ord for WeightedUtxo {
139- fn cmp ( & self , other : & Self ) -> Ordering {
140- other. effective_value . cmp ( & self . effective_value ) . then ( self . weight . cmp ( & other. weight ) )
141- }
142- }
143-
144- impl PartialOrd for WeightedUtxo {
145- fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > { Some ( self . cmp ( other) ) }
146- }
147-
14865/// Attempt a match with [`branch_and_bound`] falling back to [`single_random_draw`].
14966///
15067/// If [`branch_and_bound`] fails to find a changeless solution (basically, an exact match), then
@@ -336,28 +253,6 @@ mod tests {
336253 signed_absolute_value. to_unsigned ( ) . unwrap ( )
337254 }
338255
339- #[ test]
340- fn weighted_utxo_constructor_overflow ( ) {
341- let value = Amount :: from_sat_u32 ( 100 ) ;
342- let weight = Weight :: MAX ;
343- let fee_rate = FeeRate :: MAX ;
344- let long_term_fee_rate = FeeRate :: MAX ;
345-
346- let utxo = WeightedUtxo :: new ( value, weight, fee_rate, long_term_fee_rate) ;
347- assert ! ( utxo. is_none( ) ) ;
348- }
349-
350- #[ test]
351- fn weighted_utxo_constructor_negative_eff_value ( ) {
352- let value = Amount :: from_sat_u32 ( 1 ) ;
353- let weight = Weight :: from_vb ( 68 ) . unwrap ( ) ;
354- let fee_rate = FeeRate :: from_sat_per_kwu ( 20 ) ;
355- let long_term_fee_rate = FeeRate :: from_sat_per_kwu ( 20 ) ;
356-
357- let utxo = WeightedUtxo :: new ( value, weight, fee_rate, long_term_fee_rate) ;
358- assert ! ( utxo. is_none( ) ) ;
359- }
360-
361256 #[ test]
362257 fn select_coins_no_solution ( ) {
363258 // Test the code branch where both SRD and BnB fail.
0 commit comments