@@ -266,56 +266,49 @@ impl ProbingConfigBuilder {
266266 }
267267}
268268
269- /// A UniFFI-compatible wrapper around [`ProbingConfigBuilder`] that uses interior mutability
270- /// so it can be shared behind an `Arc` as required by the FFI object model.
269+ /// Builder for [`ProbingConfig`].
271270///
272- /// Instances are produced by the constructors [`new_high_degree`] and [`new_random_walk`].
273- /// The `set_*` methods override the defaults, and [`build`] yields the resulting
274- /// [`ProbingConfig`] .
271+ /// A new instance starts from one of two strategy constructors — [`high_degree`] or
272+ /// [`random_walk`] — and is finalized through [`build`]. Optional setters in between
273+ /// override the timing and liquidity defaults .
275274///
276- /// [`new_high_degree `]: Self::new_high_degree
277- /// [`new_random_walk `]: Self::new_random_walk
275+ /// [`high_degree `]: Self::high_degree
276+ /// [`random_walk `]: Self::random_walk
278277/// [`build`]: Self::build
279278#[ cfg( feature = "uniffi" ) ]
280- #[ derive( uniffi:: Object ) ]
281279pub struct ArcedProbingConfigBuilder {
282280 inner : RwLock < ProbingConfigBuilder > ,
283281}
284282
285283#[ cfg( feature = "uniffi" ) ]
286- #[ uniffi:: export]
287284impl ArcedProbingConfigBuilder {
288285 /// Start building a config that probes toward the highest-degree nodes in the graph.
289286 ///
290287 /// `top_node_count` controls how many of the most-connected nodes are cycled through.
291- #[ uniffi:: constructor]
292- pub fn new_high_degree ( top_node_count : u64 ) -> Arc < Self > {
293- Arc :: new ( Self {
294- inner : RwLock :: new ( ProbingConfigBuilder :: high_degree ( top_node_count as usize ) ) ,
295- } )
288+ pub fn high_degree ( top_node_count : u64 ) -> Self {
289+ Self { inner : RwLock :: new ( ProbingConfigBuilder :: high_degree ( top_node_count as usize ) ) }
296290 }
297291
298292 /// Start building a config that probes via random graph walks.
299293 ///
300294 /// `max_hops` is the upper bound on the number of hops in a randomly constructed path.
301295 /// Values below `2` are clamped to `2`.
302- #[ uniffi:: constructor]
303- pub fn new_random_walk ( max_hops : u64 ) -> Arc < Self > {
304- Arc :: new ( Self { inner : RwLock :: new ( ProbingConfigBuilder :: random_walk ( max_hops as usize ) ) } )
296+ pub fn random_walk ( max_hops : u64 ) -> Self {
297+ Self { inner : RwLock :: new ( ProbingConfigBuilder :: random_walk ( max_hops as usize ) ) }
305298 }
306299
307300 /// Overrides the interval between probe attempts.
308301 ///
309302 /// Defaults to 10 seconds.
310303 pub fn set_interval ( & self , secs : u64 ) {
311- self . inner . write ( ) . unwrap ( ) . interval ( Duration :: from_secs ( secs) ) ;
304+ self . inner . write ( ) . expect ( "lock" ) . interval ( Duration :: from_secs ( secs) ) ;
312305 }
313306
314307 /// Overrides the maximum millisatoshis that may be locked in in-flight probes at any time.
315308 ///
316309 /// Defaults to 100 000 000 msat (100k sats).
317310 pub fn set_max_locked_msat ( & self , max_msat : u64 ) {
318- self . inner . write ( ) . unwrap ( ) . max_locked_msat ( max_msat) ;
311+ self . inner . write ( ) . expect ( "lock" ) . max_locked_msat ( max_msat) ;
319312 }
320313
321314 /// Sets the probing diversity penalty applied by the probabilistic scorer.
@@ -330,19 +323,19 @@ impl ArcedProbingConfigBuilder {
330323 ///
331324 /// If unset, LDK's default of `0` (no penalty) is used.
332325 pub fn set_diversity_penalty_msat ( & self , penalty_msat : u64 ) {
333- self . inner . write ( ) . unwrap ( ) . diversity_penalty_msat ( penalty_msat) ;
326+ self . inner . write ( ) . expect ( "lock" ) . diversity_penalty_msat ( penalty_msat) ;
334327 }
335328
336329 /// Sets how long a probed node stays ineligible before being probed again.
337330 ///
338331 /// Only applies to [`HighDegreeStrategy`]. Defaults to 1 hour.
339332 pub fn set_cooldown ( & self , secs : u64 ) {
340- self . inner . write ( ) . unwrap ( ) . cooldown ( Duration :: from_secs ( secs) ) ;
333+ self . inner . write ( ) . expect ( "lock" ) . cooldown ( Duration :: from_secs ( secs) ) ;
341334 }
342335
343336 /// Builds the [`ProbingConfig`].
344337 pub fn build ( & self ) -> Arc < ProbingConfig > {
345- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build ( ) )
338+ Arc :: new ( self . inner . read ( ) . expect ( "lock" ) . build ( ) )
346339 }
347340}
348341
@@ -382,7 +375,7 @@ pub struct HighDegreeStrategy {
382375 /// `path_value * liquidity_limit_multiplier`.
383376 pub liquidity_limit_multiplier : u64 ,
384377 /// Nodes probed recently, with the time they were last probed.
385- recently_probed : Mutex < HashMap < PublicKey , Instant > > ,
378+ recently_probed : Mutex < HashMap < NodeId , Instant > > ,
386379}
387380
388381impl HighDegreeStrategy {
@@ -414,13 +407,8 @@ impl ProbingStrategy for HighDegreeStrategy {
414407 fn next_probe ( & self ) -> Option < Path > {
415408 let graph = self . network_graph . read_only ( ) ;
416409
417- let mut nodes_by_degree: Vec < ( PublicKey , usize ) > = graph
418- . nodes ( )
419- . unordered_iter ( )
420- . filter_map ( |( id, info) | {
421- PublicKey :: try_from ( * id) . ok ( ) . map ( |pubkey| ( pubkey, info. channels . len ( ) ) )
422- } )
423- . collect ( ) ;
410+ let mut nodes_by_degree: Vec < ( NodeId , usize ) > =
411+ graph. nodes ( ) . unordered_iter ( ) . map ( |( id, info) | ( * id, info. channels . len ( ) ) ) . collect ( ) ;
424412
425413 if nodes_by_degree. is_empty ( ) {
426414 return None ;
@@ -438,21 +426,23 @@ impl ProbingStrategy for HighDegreeStrategy {
438426 probed. retain ( |_, probed_at| now. duration_since ( * probed_at) < self . cooldown ) ;
439427
440428 // If all top nodes are on cooldown, reset and start a new cycle.
441- let final_node = match nodes_by_degree[ ..top_node_count]
429+ let final_node_id = match nodes_by_degree[ ..top_node_count]
442430 . iter ( )
443- . find ( |( pubkey , _) | !probed. contains_key ( pubkey ) )
431+ . find ( |( node_id , _) | !probed. contains_key ( node_id ) )
444432 {
445- Some ( ( pubkey , _) ) => * pubkey ,
433+ Some ( ( node_id , _) ) => * node_id ,
446434 None => {
447435 probed. clear ( ) ;
448436 nodes_by_degree[ 0 ] . 0
449437 } ,
450438 } ;
451439
452- probed. insert ( final_node , now) ;
440+ probed. insert ( final_node_id , now) ;
453441 drop ( probed) ;
454442 drop ( graph) ;
455443
444+ let final_node = PublicKey :: try_from ( final_node_id) . ok ( ) ?;
445+
456446 let amount_msat = random_range ( self . min_amount_msat , self . max_amount_msat ) ;
457447 let payment_params =
458448 PaymentParameters :: from_node_id ( final_node, DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA as u32 ) ;
@@ -471,6 +461,10 @@ impl ProbingStrategy for HighDegreeStrategy {
471461
472462 let path = route. paths . into_iter ( ) . next ( ) ?;
473463
464+ if path. hops . len ( ) < 2 && path. blinded_tail . is_none ( ) {
465+ return None ;
466+ }
467+
474468 // Liquidity-limit check (mirrors send_preflight_probes): skip the path when the
475469 // first-hop outbound liquidity is less than path_value * liquidity_limit_multiplier.
476470 if let Some ( first_hop_hop) = path. hops . first ( ) {
@@ -711,6 +705,10 @@ impl RandomWalkStrategy {
711705
712706 hops. reverse ( ) ;
713707
708+ if hops. len ( ) < 2 {
709+ return None ;
710+ }
711+
714712 // The first-hop HTLC carries amount_msat + all intermediate fees.
715713 // Verify the total fits within our live outbound limit before returning.
716714 let total_outgoing: u64 = hops. iter ( ) . map ( |h| h. fee_msat ) . sum ( ) ;
@@ -759,9 +757,12 @@ impl Prober {
759757 . list_recent_payments ( )
760758 . into_iter ( )
761759 . filter_map ( |p| match p {
762- RecentPaymentDetails :: Pending { is_probe : true , total_msat, .. } => {
763- Some ( total_msat)
764- } ,
760+ RecentPaymentDetails :: Pending {
761+ is_probe : true ,
762+ total_msat,
763+ pending_fee_msat,
764+ ..
765+ } => Some ( total_msat + pending_fee_msat. unwrap_or ( 0 ) ) ,
765766 _ => None ,
766767 } )
767768 . sum ( ) ;
0 commit comments