55// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66// accordance with one or both of these licenses.
77
8- //! Background probing strategies for training the payment scorer.
8+ //! Background probing for training the payment scorer.
9+ //!
10+ //! Lightning Network nodes only know channels' capacities via their initially announced limits;
11+ //! the real values change unpredictably after payments have been sent, which makes some of
12+ //! the channels inoperable (capacity has been depleted). The only way to know about channel
13+ //! depletion is to attempt sending a payment through it. Thus, sending a live payment
14+ //! might involve a significant time delay for finding an appropriate channel with enough capacity,
15+ //! up to complete failure when a route with enough capacity cannot be found.
16+ //!
17+ //! The background probing service fires probes to learn about the live state of channels and
18+ //! their capacities, providing accurate data to the scorer and router.
19+ //!
20+ //! This module provides the configuration for such a service. There are two pre-built strategies,
21+ //! [`RandomStrategy`] and [`HighDegreeStrategy`], as well as a [`ProbingStrategy`] trait which
22+ //! allows defining a custom probing strategy (for example if there is an established payment
23+ //! pattern).
24+ //!
25+ //! # Configuration
26+ //!
27+ //! Probing is opt-in: a node only runs the service if a [`ProbingConfig`] has been registered
28+ //! on the [`Builder`] via [`Builder::set_probing_config`] before [`Builder::build`]. Without a
29+ //! config, no probes are sent.
30+ //!
31+ //! # Example
32+ //!
33+ //! ```no_run
34+ //! # #[cfg(not(feature = "uniffi"))]
35+ //! # {
36+ //! use std::time::Duration;
37+ //! use ldk_node::Builder;
38+ //! use ldk_node::probing::ProbingConfigBuilder;
39+ //!
40+ //! let probing_config = ProbingConfigBuilder::high_degree(100)
41+ //! .interval(Duration::from_secs(30))
42+ //! .max_locked_msat(500_000)
43+ //! .diversity_penalty_msat(250)
44+ //! .build();
45+ //!
46+ //! let mut builder = Builder::new();
47+ //! builder.set_probing_config(probing_config);
48+ //! # }
49+ //! ```
50+ //!
51+ //! # Caution
52+ //!
53+ //! Probes send real HTLCs along real paths. If an intermediate hop is offline or
54+ //! misbehaving, the probe HTLC can remain in-flight — locking outbound liquidity
55+ //! on the first-hop channel until the HTLC timeout elapses (potentially hours).
56+ //! `max_locked_msat` caps the total outbound capacity that in-flight probes may
57+ //! hold at any one time; tune it conservatively for nodes with tight liquidity.
58+ //!
59+ //! [`Builder`]: crate::Builder
60+ //! [`Builder::set_probing_config`]: crate::Builder::set_probing_config
61+ //! [`Builder::build`]: crate::Builder::build
962
1063use std:: collections:: HashMap ;
1164use std:: fmt;
@@ -58,27 +111,51 @@ impl fmt::Debug for ProbingStrategyKind {
58111
59112/// Configuration for the background probing subsystem.
60113///
61- /// Construct via [`ProbingConfigBuilder`]. Pick a strategy with
62- /// [`ProbingConfigBuilder::high_degree`], [`ProbingConfigBuilder::random_walk`], or
63- /// [`ProbingConfigBuilder::custom`], chain optional setters, and finalize with
64- /// [`ProbingConfigBuilder::build`].
114+ /// Instances are produced by [`ProbingConfigBuilder`], which exposes three strategy
115+ /// constructors: [`ProbingConfigBuilder::high_degree`], [`ProbingConfigBuilder::random_walk`],
116+ /// and [`ProbingConfigBuilder::custom`].
65117///
66- /// # Caution
118+ /// Optional setters on the builder tune timing and liquidity limits, and
119+ /// [`ProbingConfigBuilder::build`] finalizes the value.
67120///
68- /// Probes send real HTLCs along real paths. If an intermediate hop is offline or
69- /// misbehaving, the probe HTLC can remain in-flight — locking outbound liquidity
70- /// on the first-hop channel until the HTLC timeout elapses (potentially hours).
71- /// `max_locked_msat` caps the total outbound capacity that in-flight probes may
72- /// hold at any one time; tune it conservatively for nodes with tight liquidity.
121+ /// # Examples
122+ ///
123+ /// Using pre-built strategy:
124+ /// ```no_run
125+ /// # #[cfg(not(feature = "uniffi"))]
126+ /// # {
127+ /// use std::time::Duration;
128+ /// use ldk_node::Builder;
129+ /// use ldk_node::probing::ProbingConfigBuilder;
73130///
74- /// # Example
75- /// ```ignore
76131/// let config = ProbingConfigBuilder::high_degree(100)
77132/// .interval(Duration::from_secs(30))
78133/// .max_locked_msat(500_000)
79134/// .diversity_penalty_msat(250)
80135/// .build();
136+ ///
137+ /// let mut builder = Builder::new();
81138/// builder.set_probing_config(config);
139+ /// # }
140+ /// ```
141+ ///
142+ /// Creating a custom strategy that always probes the same path:
143+ /// ```
144+ /// use ldk_node::lightning::routing::router::Path;
145+ /// use ldk_node::probing::ProbingStrategy;
146+ ///
147+ /// struct FixedPathStrategy {
148+ /// path: Path,
149+ /// }
150+ /// impl ProbingStrategy for FixedPathStrategy {
151+ /// fn next_probe(&self) -> Option<Path> {
152+ /// if self.path.hops.len() > 1 {
153+ /// Some(self.path.clone())
154+ /// } else {
155+ /// None
156+ /// }
157+ /// }
158+ /// }
82159/// ```
83160#[ derive( Clone , Debug ) ]
84161#[ cfg_attr( feature = "uniffi" , derive( uniffi:: Object ) ) ]
@@ -92,8 +169,9 @@ pub struct ProbingConfig {
92169
93170/// Builder for [`ProbingConfig`].
94171///
95- /// Pick a strategy with [`high_degree`], [`random_walk`], or [`custom`], chain optional
96- /// setters, and call [`build`] to finalize.
172+ /// A new instance starts from one of three strategy constructors — [`high_degree`],
173+ /// [`random_walk`], or [`custom`] — and is finalized through [`build`]. Optional setters
174+ /// in between override the timing and liquidity defaults.
97175///
98176/// [`high_degree`]: Self::high_degree
99177/// [`random_walk`]: Self::random_walk
@@ -193,8 +271,9 @@ impl ProbingConfigBuilder {
193271/// A UniFFI-compatible wrapper around [`ProbingConfigBuilder`] that uses interior mutability
194272/// so it can be shared behind an `Arc` as required by the FFI object model.
195273///
196- /// Obtain one via the constructors [`new_high_degree`] or [`new_random_walk`], configure it
197- /// with the `set_*` methods, then call [`build`] to produce a [`ProbingConfig`].
274+ /// Instances are produced by the constructors [`new_high_degree`] and [`new_random_walk`].
275+ /// The `set_*` methods override the defaults, and [`build`] yields the resulting
276+ /// [`ProbingConfig`].
198277///
199278/// [`new_high_degree`]: Self::new_high_degree
200279/// [`new_random_walk`]: Self::new_random_walk
@@ -263,7 +342,7 @@ impl ArcedProbingConfigBuilder {
263342 }
264343}
265344
266- /// Strategy can be used for determining the next target and amount for probing .
345+ /// A strategy that decides which path the probing service should probe next .
267346pub trait ProbingStrategy : Send + Sync + ' static {
268347 /// Returns the next probe path to run, or `None` to skip this tick.
269348 fn next_probe ( & self ) -> Option < Path > ;
@@ -281,6 +360,8 @@ pub trait ProbingStrategy: Send + Sync + 'static {
281360///
282361/// The probe amount is chosen uniformly at random from
283362/// `[min_amount_msat, max_amount_msat]`.
363+ ///
364+ /// `HighDegreeStrategy` can only use publicly announced channels for probing.
284365pub struct HighDegreeStrategy {
285366 network_graph : Arc < Graph > ,
286367 channel_manager : Arc < ChannelManager > ,
@@ -406,7 +487,7 @@ impl ProbingStrategy for HighDegreeStrategy {
406487 }
407488}
408489
409- /// Explores the graph by walking a random number of hops outward from one of our own
490+ /// Explores the graph by walking a random number (≥2) of hops outward from one of our own
410491/// channels, constructing the [`Path`] explicitly.
411492///
412493/// On each tick:
@@ -418,6 +499,8 @@ impl ProbingStrategy for HighDegreeStrategy {
418499///
419500/// Because path selection ignores the scorer, this probes channels the router
420501/// would never try on its own, teaching the scorer about previously unknown paths.
502+ ///
503+ /// `RandomStrategy` can only use publicly announced channels for probing.
421504pub struct RandomStrategy {
422505 network_graph : Arc < Graph > ,
423506 channel_manager : Arc < ChannelManager > ,
0 commit comments