@@ -2,7 +2,19 @@ use super::*;
22#[ allow( unused) ] // some bug in <= 1.48.0 sees this as unused when it isn't
33use crate :: float:: FloatExt ;
44use crate :: { bnb:: BnbMetric , float:: Ordf32 , ChangePolicy , FeeRate , Target } ;
5- use alloc:: { borrow:: Cow , collections:: BTreeSet } ;
5+ use alloc:: { borrow:: Cow , collections:: BTreeSet , vec:: Vec } ;
6+
7+ /// An unconfirmed ancestor transaction that may need a fee bump (CPFP).
8+ ///
9+ /// When spending unconfirmed UTXOs, miners evaluate the transaction as a package with its
10+ /// unconfirmed ancestors. If ancestors paid below the target feerate, the child must overpay.
11+ #[ derive( Debug , Clone , Copy ) ]
12+ pub struct UnconfirmedAncestor {
13+ /// The weight of the ancestor transaction in weight units.
14+ pub weight : u64 ,
15+ /// The fee already paid by the ancestor transaction in satoshis.
16+ pub fee_paid : u64 ,
17+ }
618
719/// [`CoinSelector`] selects/deselects coins from a set of canididate coins.
820///
@@ -14,6 +26,7 @@ use alloc::{borrow::Cow, collections::BTreeSet};
1426#[ derive( Debug , Clone ) ]
1527pub struct CoinSelector < ' a > {
1628 candidates : & ' a [ Candidate ] ,
29+ ancestors : & ' a [ UnconfirmedAncestor ] ,
1730 selected : Cow < ' a , BTreeSet < usize > > ,
1831 banned : Cow < ' a , BTreeSet < usize > > ,
1932 candidate_order : Cow < ' a , [ usize ] > ,
@@ -34,26 +47,35 @@ impl<'a> CoinSelector<'a> {
3447 pub fn new ( candidates : & ' a [ Candidate ] ) -> Self {
3548 Self {
3649 candidates,
50+ ancestors : & [ ] ,
3751 selected : Cow :: Owned ( Default :: default ( ) ) ,
3852 banned : Cow :: Owned ( Default :: default ( ) ) ,
3953 candidate_order : Cow :: Owned ( ( 0 ..candidates. len ( ) ) . collect ( ) ) ,
4054 }
4155 }
4256
57+ /// Set the shared ancestor data for CPFP bump fee calculations.
58+ ///
59+ /// Each [`Candidate`]'s `ancestors` field contains indices into this slice.
60+ pub fn with_ancestors ( mut self , ancestors : & ' a [ UnconfirmedAncestor ] ) -> Self {
61+ self . ancestors = ancestors;
62+ self
63+ }
64+
4365 /// Iterate over all the candidates in their currently sorted order. Each item has the original
4466 /// index with the candidate.
4567 pub fn candidates (
4668 & self ,
47- ) -> impl DoubleEndedIterator < Item = ( usize , Candidate ) > + ExactSizeIterator + ' _ {
69+ ) -> impl DoubleEndedIterator < Item = ( usize , & Candidate ) > + ExactSizeIterator + ' _ {
4870 self . candidate_order
4971 . iter ( )
50- . map ( move |i| ( * i, self . candidates [ * i] ) )
72+ . map ( move |i| ( * i, & self . candidates [ * i] ) )
5173 }
5274
5375 /// Get the candidate at `index`. `index` refers to its position in the original `candidates`
5476 /// slice passed into [`CoinSelector::new`].
55- pub fn candidate ( & self , index : usize ) -> Candidate {
56- self . candidates [ index]
77+ pub fn candidate ( & self , index : usize ) -> & Candidate {
78+ & self . candidates [ index]
5779 }
5880
5981 /// Deselect a candidate at `index`. `index` refers to its position in the original `candidates`
@@ -172,6 +194,36 @@ impl<'a> CoinSelector<'a> {
172194 + target_ouputs. output_weight_with_drain ( drain_weight)
173195 }
174196
197+ /// Compute the package-level ancestor bump fee for the current selection at the given feerate.
198+ ///
199+ /// This collects unique ancestor indices across all selected candidates, sums their weights
200+ /// and fees, then computes `max(0, implied_fee(total_weight, feerate) - total_fees)`.
201+ ///
202+ /// High-feerate ancestors subsidize low-feerate ones within the package (matching Bitcoin
203+ /// Core's package relay approach).
204+ pub fn selected_ancestor_bump_fee ( & self , feerate : FeeRate ) -> u64 {
205+ if self . ancestors . is_empty ( ) {
206+ return 0 ;
207+ }
208+ let mut indices: Vec < usize > = self
209+ . selected
210+ . iter ( )
211+ . flat_map ( |& i| self . candidates [ i] . ancestors . iter ( ) . copied ( ) )
212+ . collect ( ) ;
213+ indices. sort_unstable ( ) ;
214+ indices. dedup ( ) ;
215+
216+ let mut total_weight = 0u64 ;
217+ let mut total_fee_paid = 0u64 ;
218+ for anc_index in indices {
219+ let anc = & self . ancestors [ anc_index] ;
220+ total_weight += anc. weight ;
221+ total_fee_paid += anc. fee_paid ;
222+ }
223+ let implied = feerate. implied_fee ( total_weight) ;
224+ implied. saturating_sub ( total_fee_paid)
225+ }
226+
175227 /// How much the current selection overshoots the value needed to achieve `target`.
176228 ///
177229 /// In order for the resulting transaction to be valid this must be 0 or above. If it's above 0
@@ -198,6 +250,7 @@ impl<'a> CoinSelector<'a> {
198250 - target. value ( ) as i64
199251 - drain. value as i64
200252 - self . implied_fee_from_feerate ( target, drain. weights ) as i64
253+ - self . selected_ancestor_bump_fee ( target. fee . rate ) as i64
201254 }
202255
203256 /// Same as [rate_excess](Self::rate_excess) except `target.fee.rate` is applied to the
@@ -207,6 +260,7 @@ impl<'a> CoinSelector<'a> {
207260 - target. value ( ) as i64
208261 - drain. value as i64
209262 - self . implied_fee_from_feerate_wu ( target, drain. weights ) as i64
263+ - self . selected_ancestor_bump_fee ( target. fee . rate ) as i64
210264 }
211265
212266 /// How much the current selection overshoots the value needed to satisfy RBF's rule 4.
@@ -220,6 +274,7 @@ impl<'a> CoinSelector<'a> {
220274 - target. value ( ) as i64
221275 - drain. value as i64
222276 - replacement_excess_needed as i64
277+ - self . selected_ancestor_bump_fee ( target. fee . rate ) as i64
223278 }
224279
225280 /// Same as [replacement_excess](Self::replacement_excess) except the replacement fee
@@ -234,6 +289,7 @@ impl<'a> CoinSelector<'a> {
234289 - target. value ( ) as i64
235290 - drain. value as i64
236291 - replacement_excess_needed as i64
292+ - self . selected_ancestor_bump_fee ( target. fee . rate ) as i64
237293 }
238294
239295 /// The feerate the transaction would have if we were to use this selection of inputs to achieve
@@ -292,8 +348,11 @@ impl<'a> CoinSelector<'a> {
292348 }
293349
294350 /// The value of the current selected inputs minus the fee needed to pay for the selected inputs
351+ /// and any ancestor bump fee.
295352 pub fn effective_value ( & self , feerate : FeeRate ) -> i64 {
296- self . selected_value ( ) as i64 - ( self . input_weight ( ) as f32 * feerate. spwu ( ) ) . ceil ( ) as i64
353+ self . selected_value ( ) as i64
354+ - ( self . input_weight ( ) as f32 * feerate. spwu ( ) ) . ceil ( ) as i64
355+ - self . selected_ancestor_bump_fee ( feerate) as i64
297356 }
298357
299358 // /// Waste sum of all selected inputs.
@@ -312,11 +371,11 @@ impl<'a> CoinSelector<'a> {
312371 /// [`unselected`]: CoinSelector::unselected
313372 pub fn sort_candidates_by < F > ( & mut self , mut cmp : F )
314373 where
315- F : FnMut ( ( usize , Candidate ) , ( usize , Candidate ) ) -> core:: cmp:: Ordering ,
374+ F : FnMut ( ( usize , & Candidate ) , ( usize , & Candidate ) ) -> core:: cmp:: Ordering ,
316375 {
317376 let order = self . candidate_order . to_mut ( ) ;
318377 let candidates = & self . candidates ;
319- order. sort_by ( |a, b| cmp ( ( * a, candidates[ * a] ) , ( * b, candidates[ * b] ) ) )
378+ order. sort_by ( |a, b| cmp ( ( * a, & candidates[ * a] ) , ( * b, & candidates[ * b] ) ) )
320379 }
321380
322381 /// Sorts the candidates by the key function.
@@ -330,10 +389,10 @@ impl<'a> CoinSelector<'a> {
330389 /// [`unselected`]: CoinSelector::unselected
331390 pub fn sort_candidates_by_key < F , K > ( & mut self , mut key_fn : F )
332391 where
333- F : FnMut ( ( usize , Candidate ) ) -> K ,
392+ F : FnMut ( ( usize , & Candidate ) ) -> K ,
334393 K : Ord ,
335394 {
336- self . sort_candidates_by ( |a, b| key_fn ( a) . cmp ( & key_fn ( b) ) )
395+ self . sort_candidates_by ( |a, b| key_fn ( a) . cmp ( & key_fn ( b) ) ) ;
337396 }
338397
339398 /// Sorts the candidates by descending value per weight unit, tie-breaking with value.
@@ -379,20 +438,20 @@ impl<'a> CoinSelector<'a> {
379438 /// The selected candidates with their index.
380439 pub fn selected (
381440 & self ,
382- ) -> impl ExactSizeIterator < Item = ( usize , Candidate ) > + DoubleEndedIterator + ' _ {
441+ ) -> impl ExactSizeIterator < Item = ( usize , & Candidate ) > + DoubleEndedIterator + ' _ {
383442 self . selected
384443 . iter ( )
385- . map ( move |& index| ( index, self . candidates [ index] ) )
444+ . map ( move |& index| ( index, & self . candidates [ index] ) )
386445 }
387446
388447 /// The unselected candidates with their index.
389448 ///
390449 /// The candidates are returned in sorted order. See [`sort_candidates_by`].
391450 ///
392451 /// [`sort_candidates_by`]: Self::sort_candidates_by
393- pub fn unselected ( & self ) -> impl DoubleEndedIterator < Item = ( usize , Candidate ) > + ' _ {
452+ pub fn unselected ( & self ) -> impl DoubleEndedIterator < Item = ( usize , & Candidate ) > + ' _ {
394453 self . unselected_indices ( )
395- . map ( move |i| ( i, self . candidates [ i] ) )
454+ . map ( move |i| ( i, & self . candidates [ i] ) )
396455 }
397456
398457 /// The indices of the selelcted candidates.
@@ -612,20 +671,23 @@ pub struct SelectIter<'a> {
612671}
613672
614673impl < ' a > Iterator for SelectIter < ' a > {
615- type Item = ( CoinSelector < ' a > , usize , Candidate ) ;
674+ type Item = ( CoinSelector < ' a > , usize , & ' a Candidate ) ;
616675
617676 fn next ( & mut self ) -> Option < Self :: Item > {
618- let ( index, wv) = self . cs . unselected ( ) . next ( ) ?;
677+ let index = self . cs . unselected_indices ( ) . next ( ) ?;
678+ // Access the underlying slice directly to get the `'a` lifetime.
679+ let candidates: & ' a [ Candidate ] = self . cs . candidates ;
619680 self . cs . select ( index) ;
620- Some ( ( self . cs . clone ( ) , index, wv ) )
681+ Some ( ( self . cs . clone ( ) , index, & candidates [ index ] ) )
621682 }
622683}
623684
624- impl DoubleEndedIterator for SelectIter < ' _ > {
685+ impl < ' a > DoubleEndedIterator for SelectIter < ' a > {
625686 fn next_back ( & mut self ) -> Option < Self :: Item > {
626- let ( index, wv) = self . cs . unselected ( ) . next_back ( ) ?;
687+ let index = self . cs . unselected_indices ( ) . next_back ( ) ?;
688+ let candidates: & ' a [ Candidate ] = self . cs . candidates ;
627689 self . cs . select ( index) ;
628- Some ( ( self . cs . clone ( ) , index, wv ) )
690+ Some ( ( self . cs . clone ( ) , index, & candidates [ index ] ) )
629691 }
630692}
631693
@@ -670,7 +732,7 @@ impl std::error::Error for NoBnbSolution {}
670732/// A `Candidate` represents an input candidate for [`CoinSelector`].
671733///
672734/// This can either be a single UTXO, or a group of UTXOs that should be spent together.
673- #[ derive( Debug , Clone , Copy ) ]
735+ #[ derive( Debug , Clone ) ]
674736pub struct Candidate {
675737 /// Total value of the UTXO(s) that this [`Candidate`] represents.
676738 pub value : u64 ,
@@ -682,6 +744,12 @@ pub struct Candidate {
682744 pub input_count : usize ,
683745 /// Whether this [`Candidate`] contains at least one segwit spend.
684746 pub is_segwit : bool ,
747+ /// Indices into the shared [`UnconfirmedAncestor`] slice (passed to
748+ /// [`CoinSelector::with_ancestors`]) that this candidate depends on.
749+ ///
750+ /// When multiple candidates share ancestors, those ancestors are automatically deduplicated
751+ /// during bump fee computation.
752+ pub ancestors : Vec < usize > ,
685753}
686754
687755impl Candidate {
@@ -695,13 +763,14 @@ impl Candidate {
695763 ///
696764 /// `satisfaction_weight` is the weight of `scriptSigLen + scriptSig + scriptWitnessLen +
697765 /// scriptWitness`.
698- pub fn new ( value : u64 , satisfaction_weight : u64 , is_segwit : bool ) -> Candidate {
766+ pub fn new ( value : u64 , satisfaction_weight : u64 , is_segwit : bool ) -> Self {
699767 let weight = TXIN_BASE_WEIGHT + satisfaction_weight;
700768 Candidate {
701769 value,
702770 weight,
703771 input_count : 1 ,
704772 is_segwit,
773+ ancestors : Vec :: new ( ) ,
705774 }
706775 }
707776
0 commit comments