1010use std:: collections:: HashMap ;
1111use std:: fmt;
1212use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
13+ #[ cfg( feature = "uniffi" ) ]
14+ use std:: sync:: RwLock ;
1315use std:: sync:: { Arc , Mutex } ;
1416use std:: time:: { Duration , Instant } ;
1517
@@ -40,23 +42,20 @@ pub(crate) enum ProbingStrategyKind {
4042
4143/// Configuration for the background probing subsystem.
4244///
43- /// Use the constructor methods [`high_degree`], [`random_walk`], or [`custom`] to start
44- /// building, then chain optional setters and call [`build`].
45+ /// Construct via [`ProbingConfigBuilder`]. Pick a strategy with
46+ /// [`ProbingConfigBuilder::high_degree`], [`ProbingConfigBuilder::random_walk`], or
47+ /// [`ProbingConfigBuilder::custom`], chain optional setters, and finalize with
48+ /// [`ProbingConfigBuilder::build`].
4549///
4650/// # Example
4751/// ```ignore
48- /// let config = ProbingConfig ::high_degree(100)
52+ /// let config = ProbingConfigBuilder ::high_degree(100)
4953/// .interval(Duration::from_secs(30))
5054/// .max_locked_msat(500_000)
5155/// .diversity_penalty_msat(250)
5256/// .build();
5357/// builder.set_probing_config(config);
5458/// ```
55- ///
56- /// [`high_degree`]: Self::high_degree
57- /// [`random_walk`]: Self::random_walk
58- /// [`custom`]: Self::custom
59- /// [`build`]: ProbingConfigBuilder::build
6059#[ derive( Clone ) ]
6160#[ cfg_attr( feature = "uniffi" , derive( uniffi:: Object ) ) ]
6261pub struct ProbingConfig {
@@ -88,86 +87,14 @@ impl fmt::Debug for ProbingConfig {
8887 }
8988}
9089
91- impl ProbingConfig {
92- /// Start building a config that probes toward the highest-degree nodes in the graph.
93- ///
94- /// `top_node_count` controls how many of the most-connected nodes are cycled through.
95- pub fn high_degree ( top_node_count : usize ) -> ProbingConfigBuilder {
96- ProbingConfigBuilder :: new ( ProbingStrategyKind :: HighDegree { top_node_count } )
97- }
98-
99- /// Start building a config that probes via random graph walks.
100- ///
101- /// `max_hops` is the upper bound on the number of hops in a randomly constructed path.
102- pub fn random_walk ( max_hops : usize ) -> ProbingConfigBuilder {
103- ProbingConfigBuilder :: new ( ProbingStrategyKind :: Random { max_hops } )
104- }
105-
106- /// Start building a config with a custom [`ProbingStrategy`] implementation.
107- pub fn custom ( strategy : Arc < dyn ProbingStrategy > ) -> ProbingConfigBuilder {
108- ProbingConfigBuilder :: new ( ProbingStrategyKind :: Custom ( strategy) )
109- }
110- }
111-
112- #[ cfg( feature = "uniffi" ) ]
113- #[ uniffi:: export]
114- impl ProbingConfig {
115- /// Creates a probing config that probes toward the highest-degree nodes in the graph.
116- ///
117- /// `top_node_count` controls how many of the most-connected nodes are cycled through.
118- /// All other parameters are optional and fall back to sensible defaults when `None`.
119- #[ uniffi:: constructor]
120- pub fn new_high_degree (
121- top_node_count : u64 , interval_secs : Option < u64 > , max_locked_msat : Option < u64 > ,
122- diversity_penalty_msat : Option < u64 > , cooldown_secs : Option < u64 > ,
123- ) -> Self {
124- let mut builder = Self :: high_degree ( top_node_count as usize ) ;
125- if let Some ( secs) = interval_secs {
126- builder = builder. interval ( Duration :: from_secs ( secs) ) ;
127- }
128- if let Some ( msat) = max_locked_msat {
129- builder = builder. max_locked_msat ( msat) ;
130- }
131- if let Some ( penalty) = diversity_penalty_msat {
132- builder = builder. diversity_penalty_msat ( penalty) ;
133- }
134- if let Some ( secs) = cooldown_secs {
135- builder = builder. cooldown ( Duration :: from_secs ( secs) ) ;
136- }
137- builder. build ( )
138- }
139-
140- /// Creates a probing config that probes via random graph walks.
141- ///
142- /// `max_hops` is the upper bound on the number of hops in a randomly constructed path.
143- /// All other parameters are optional and fall back to sensible defaults when `None`.
144- #[ uniffi:: constructor]
145- pub fn new_random_walk (
146- max_hops : u64 , interval_secs : Option < u64 > , max_locked_msat : Option < u64 > ,
147- diversity_penalty_msat : Option < u64 > , cooldown_secs : Option < u64 > ,
148- ) -> Self {
149- let mut builder = Self :: random_walk ( max_hops as usize ) ;
150- if let Some ( secs) = interval_secs {
151- builder = builder. interval ( Duration :: from_secs ( secs) ) ;
152- }
153- if let Some ( msat) = max_locked_msat {
154- builder = builder. max_locked_msat ( msat) ;
155- }
156- if let Some ( penalty) = diversity_penalty_msat {
157- builder = builder. diversity_penalty_msat ( penalty) ;
158- }
159- if let Some ( secs) = cooldown_secs {
160- builder = builder. cooldown ( Duration :: from_secs ( secs) ) ;
161- }
162- builder. build ( )
163- }
164- }
165-
16690/// Builder for [`ProbingConfig`].
16791///
168- /// Created via [`ProbingConfig:: high_degree`], [`ProbingConfig:: random_walk`], or
169- /// [`ProbingConfig::custom`]. Call [`build`] to finalize.
92+ /// Pick a strategy with [` high_degree`], [`random_walk`], or [`custom`], chain optional
93+ /// setters, and call [`build`] to finalize.
17094///
95+ /// [`high_degree`]: Self::high_degree
96+ /// [`random_walk`]: Self::random_walk
97+ /// [`custom`]: Self::custom
17198/// [`build`]: Self::build
17299pub struct ProbingConfigBuilder {
173100 kind : ProbingStrategyKind ,
@@ -178,7 +105,7 @@ pub struct ProbingConfigBuilder {
178105}
179106
180107impl ProbingConfigBuilder {
181- fn new ( kind : ProbingStrategyKind ) -> Self {
108+ fn with_kind ( kind : ProbingStrategyKind ) -> Self {
182109 Self {
183110 kind,
184111 interval : Duration :: from_secs ( DEFAULT_PROBING_INTERVAL_SECS ) ,
@@ -188,18 +115,37 @@ impl ProbingConfigBuilder {
188115 }
189116 }
190117
118+ /// Start building a config that probes toward the highest-degree nodes in the graph.
119+ ///
120+ /// `top_node_count` controls how many of the most-connected nodes are cycled through.
121+ pub fn high_degree ( top_node_count : usize ) -> Self {
122+ Self :: with_kind ( ProbingStrategyKind :: HighDegree { top_node_count } )
123+ }
124+
125+ /// Start building a config that probes via random graph walks.
126+ ///
127+ /// `max_hops` is the upper bound on the number of hops in a randomly constructed path.
128+ pub fn random_walk ( max_hops : usize ) -> Self {
129+ Self :: with_kind ( ProbingStrategyKind :: Random { max_hops } )
130+ }
131+
132+ /// Start building a config with a custom [`ProbingStrategy`] implementation.
133+ pub fn custom ( strategy : Arc < dyn ProbingStrategy > ) -> Self {
134+ Self :: with_kind ( ProbingStrategyKind :: Custom ( strategy) )
135+ }
136+
191137 /// Overrides the interval between probe attempts.
192138 ///
193139 /// Defaults to 10 seconds.
194- pub fn interval ( mut self , interval : Duration ) -> Self {
140+ pub fn interval ( & mut self , interval : Duration ) -> & mut Self {
195141 self . interval = interval;
196142 self
197143 }
198144
199145 /// Overrides the maximum millisatoshis that may be locked in in-flight probes at any time.
200146 ///
201147 /// Defaults to 100 000 000 msat (100k sats).
202- pub fn max_locked_msat ( mut self , max_msat : u64 ) -> Self {
148+ pub fn max_locked_msat ( & mut self , max_msat : u64 ) -> & mut Self {
203149 self . max_locked_msat = max_msat;
204150 self
205151 }
@@ -215,23 +161,23 @@ impl ProbingConfigBuilder {
215161 /// (e.g., [`RandomStrategy`]) bypass the scorer entirely.
216162 ///
217163 /// If unset, LDK's default of `0` (no penalty) is used.
218- pub fn diversity_penalty_msat ( mut self , penalty_msat : u64 ) -> Self {
164+ pub fn diversity_penalty_msat ( & mut self , penalty_msat : u64 ) -> & mut Self {
219165 self . diversity_penalty_msat = Some ( penalty_msat) ;
220166 self
221167 }
222168
223169 /// Sets how long a probed node stays ineligible before being probed again.
224170 ///
225171 /// Only applies to [`HighDegreeStrategy`]. Defaults to 1 hour.
226- pub fn cooldown ( mut self , cooldown : Duration ) -> Self {
172+ pub fn cooldown ( & mut self , cooldown : Duration ) -> & mut Self {
227173 self . cooldown = cooldown;
228174 self
229175 }
230176
231177 /// Builds the [`ProbingConfig`].
232- pub fn build ( self ) -> ProbingConfig {
178+ pub fn build ( & self ) -> ProbingConfig {
233179 ProbingConfig {
234- kind : self . kind ,
180+ kind : self . kind . clone ( ) ,
235181 interval : self . interval ,
236182 max_locked_msat : self . max_locked_msat ,
237183 diversity_penalty_msat : self . diversity_penalty_msat ,
@@ -240,6 +186,78 @@ impl ProbingConfigBuilder {
240186 }
241187}
242188
189+ /// A UniFFI-compatible wrapper around [`ProbingConfigBuilder`] that uses interior mutability
190+ /// so it can be shared behind an `Arc` as required by the FFI object model.
191+ ///
192+ /// Obtain one via the constructors [`new_high_degree`] or [`new_random_walk`], configure it
193+ /// with the `set_*` methods, then call [`build`] to produce a [`ProbingConfig`].
194+ ///
195+ /// [`new_high_degree`]: Self::new_high_degree
196+ /// [`new_random_walk`]: Self::new_random_walk
197+ /// [`build`]: Self::build
198+ #[ cfg( feature = "uniffi" ) ]
199+ #[ derive( uniffi:: Object ) ]
200+ pub struct ArcedProbingConfigBuilder {
201+ inner : RwLock < ProbingConfigBuilder > ,
202+ }
203+
204+ #[ cfg( feature = "uniffi" ) ]
205+ #[ uniffi:: export]
206+ impl ArcedProbingConfigBuilder {
207+ /// Creates a builder configured to probe toward the highest-degree nodes in the graph.
208+ ///
209+ /// `top_node_count` controls how many of the most-connected nodes are cycled through.
210+ #[ uniffi:: constructor]
211+ pub fn new_high_degree ( top_node_count : u64 ) -> Arc < Self > {
212+ Arc :: new ( Self {
213+ inner : RwLock :: new ( ProbingConfigBuilder :: high_degree ( top_node_count as usize ) ) ,
214+ } )
215+ }
216+
217+ /// Creates a builder configured to probe via random graph walks.
218+ ///
219+ /// `max_hops` is the upper bound on the number of hops in a randomly constructed path.
220+ #[ uniffi:: constructor]
221+ pub fn new_random_walk ( max_hops : u64 ) -> Arc < Self > {
222+ Arc :: new ( Self { inner : RwLock :: new ( ProbingConfigBuilder :: random_walk ( max_hops as usize ) ) } )
223+ }
224+
225+ /// Overrides the interval between probe attempts. Defaults to 10 seconds.
226+ pub fn set_interval ( & self , secs : u64 ) {
227+ self . inner . write ( ) . unwrap ( ) . interval ( Duration :: from_secs ( secs) ) ;
228+ }
229+
230+ /// Overrides the maximum millisatoshis that may be locked in in-flight probes at any time.
231+ ///
232+ /// Defaults to 100 000 000 msat (100k sats).
233+ pub fn set_max_locked_msat ( & self , max_msat : u64 ) {
234+ self . inner . write ( ) . unwrap ( ) . max_locked_msat ( max_msat) ;
235+ }
236+
237+ /// Sets the probing diversity penalty applied by the probabilistic scorer.
238+ ///
239+ /// When set, the scorer will penalize channels that have been recently probed,
240+ /// encouraging path diversity during background probing. The penalty decays
241+ /// quadratically over 24 hours.
242+ ///
243+ /// If unset, LDK's default of `0` (no penalty) is used.
244+ pub fn set_diversity_penalty_msat ( & self , penalty_msat : u64 ) {
245+ self . inner . write ( ) . unwrap ( ) . diversity_penalty_msat ( penalty_msat) ;
246+ }
247+
248+ /// Sets how long a probed node stays ineligible before being probed again.
249+ ///
250+ /// Only applies to the high-degree strategy. Defaults to 1 hour.
251+ pub fn set_cooldown ( & self , secs : u64 ) {
252+ self . inner . write ( ) . unwrap ( ) . cooldown ( Duration :: from_secs ( secs) ) ;
253+ }
254+
255+ /// Builds the [`ProbingConfig`].
256+ pub fn build ( & self ) -> Arc < ProbingConfig > {
257+ Arc :: new ( self . inner . read ( ) . unwrap ( ) . build ( ) )
258+ }
259+ }
260+
243261/// Strategy can be used for determining the next target and amount for probing.
244262pub trait ProbingStrategy : Send + Sync + ' static {
245263 /// Returns the next probe path to run, or `None` to skip this tick.
0 commit comments