From 5fdf1cd292b23ea351c3a00babeca5dd7c3e3080 Mon Sep 17 00:00:00 2001 From: StephenChi-hi Date: Mon, 16 Feb 2026 06:09:28 +0100 Subject: [PATCH 1/3] Clarify find_route Documentation --- lightning/src/routing/router.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 2a00d44287a..8fe953f8ee3 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -2593,6 +2593,25 @@ fn sort_first_hop_channels( /// However, the enabled/disabled bit on such channels as well as the `htlc_minimum_msat` / /// `htlc_maximum_msat` *are* checked as they may change based on the receiving node. /// +/// Routes are constructed by searching the provided [`NetworkGraph`] for paths from the payer +/// to the payee that satisfy the constraints in [`RouteParameters`]. Fees are accumulated +/// backwards from the payee to the payer, and CLTV expiry deltas are aggregated hop-by-hop. +/// +/// Channel selection and path ranking are influenced by the provided [`ScoreLookUp`] +/// implementation, which may apply penalties based on historical reliability, +/// liquidity hints, or in-flight HTLCs. +/// +/// If `first_hops` is provided, those channels are used as the only outbound candidates +/// from the payer, overriding the corresponding entries in the [`NetworkGraph`]. +/// +/// # Errors +/// +/// Returns an error if: +/// - The payer and payee are the same node. +/// - The payment amount is zero or exceeds the maximum representable value. +/// - The total CLTV expiry constraint cannot accommodate the payee's required final CLTV delta. +/// - No route satisfying liquidity, feature, and policy constraints can be found. +/// /// # Panics /// /// Panics if first_hops contains channels without `short_channel_id`s; From c4fc6b8fb864139290bfd1c6b8bf46eeefcf0094 Mon Sep 17 00:00:00 2001 From: StephenChi-hi Date: Tue, 3 Mar 2026 02:41:15 +0100 Subject: [PATCH 2/3] Enhance documentation for find_route function, detailing parameters, routing behavior, and error handling --- lightning/src/routing/router.rs | 103 +++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 8fe953f8ee3..1ade3fb8fff 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -2578,48 +2578,93 @@ fn sort_first_hop_channels( /// Finds a route from us (payer) to the given target node (payee). /// -/// If the payee provided features in their invoice, they should be provided via the `payee` field -/// in the given [`RouteParameters::payment_params`]. -/// Without this, MPP will only be used if the payee's features are available in the network graph. +/// This function computes one or more payment paths for sending a payment to the payee while +/// respecting all constraints like fees, CLTV expiry deltas, channel liquidity, and the payee's +/// feature requirements. You'll get multiple paths back if multi-path payments (MPP) are needed. /// -/// Private routing paths between a public node and the target may be included in the `payee` field -/// of [`RouteParameters::payment_params`]. +/// # Parameters /// -/// If some channels aren't announced, it may be useful to fill in `first_hops` with the results -/// from [`ChannelManager::list_usable_channels`]. If it is filled in, the view of these channels -/// from `network_graph` will be ignored, and only those in `first_hops` will be used. +/// * `our_node_pubkey` - The public key of the payer (us). +/// * `route_params` - Payment parameters including the final value, payee information, feature +/// requirements from any invoice, and routing constraints like max fees and path count. +/// * `network_graph` - The network graph with all known channels and nodes. +/// * `first_hops` - Channels directly connected to us. If you provide this, it takes priority +/// over what's in the network graph, which is useful for unannounced channels. You can get +/// this from [`ChannelManager::list_usable_channels`]. +/// * `logger` - For logging routing progress and debug info. +/// * `scorer` - The implementation that ranks and selects paths based on reliability, liquidity, +/// and congestion metrics. +/// * `score_params` - Parameters for tuning the scorer's behavior. +/// * `random_seed_bytes` - A random seed for adding privacy-enhancing offsets to CLTV values. /// -/// The fees on channels from us to the next hop are ignored as they are assumed to all be equal. -/// However, the enabled/disabled bit on such channels as well as the `htlc_minimum_msat` / -/// `htlc_maximum_msat` *are* checked as they may change based on the receiving node. +/// # Payee Information /// -/// Routes are constructed by searching the provided [`NetworkGraph`] for paths from the payer -/// to the payee that satisfy the constraints in [`RouteParameters`]. Fees are accumulated -/// backwards from the payee to the payer, and CLTV expiry deltas are aggregated hop-by-hop. +/// How we handle the payee depends on what they provided: +/// * Bolt11 invoices: Include features via [`RouteParameters::payment_params`] to enable MPP. +/// Without features, MPP only works if the payee is already known in the network graph. +/// * Bolt12 invoices: May include blinded paths for privacy. We unblind these in the returned +/// [`Route`] so you can actually construct the payment. +/// * BOLT11 route hints: Private hops near the payee get included in the final route. /// -/// Channel selection and path ranking are influenced by the provided [`ScoreLookUp`] -/// implementation, which may apply penalties based on historical reliability, -/// liquidity hints, or in-flight HTLCs. +/// # First Hop Behavior /// -/// If `first_hops` is provided, those channels are used as the only outbound candidates -/// from the payer, overriding the corresponding entries in the [`NetworkGraph`]. +/// Fees on channels from us to the next hop are ignored during routing since we assume all +/// first-hop channels cost the same. However, we do check the channel's enabled/disabled status +/// and HTLC limits (htlc_minimum_msat and htlc_maximum_msat) since those can vary. +/// +/// # How It Works +/// +/// We use a modified Dijkstra's algorithm, searching backwards from the payee to us: +/// +/// 1. Fee calculation: We total up fees at each hop from the payee going back to the payer, +/// computing them based on the amount being routed. This gives us accurate estimates because +/// the amount increases as we move backward toward the payer. +/// 2. CLTV deltas: Each hop's CLTV expiry delta is aggregated hop-by-hop to ensure we have +/// enough time for on-chain resolution if needed. +/// 3. Penalties: The scorer's penalties (from your provided scorer) are factored directly into +/// the pathfinding algorithm itself, not just applied afterward. This means channels with +/// higher penalties are naturally less likely to be selected during the search. +/// 4. Path construction: We build multiple candidate paths while staying within the fee limit +/// and respecting all liquidity and feature constraints. +/// 5. Value provisioning: We collect paths until the total value is roughly 3x the requested +/// payment (this gives us room to find cheaper combinations), then we pick the cheapest set. +/// +/// # Scoring and Channel Selection +/// +/// The scorer you provide influences which paths we select during the actual pathfinding. The +/// scorer assigns penalties to channels based on factors like: +/// * How reliable the channel has been historically +/// * Known liquidity constraints and in-flight HTLCs +/// * Estimated network congestion +/// +/// These penalties are built into the algorithm's scoring, so channels with higher penalties are +/// naturally deprioritized as we search for paths, letting us favor more reliable and liquid +/// options. +/// +/// # Returns +/// +/// On success, you get a [`Route`] with one or more payment paths. The route respects all +/// your constraints and is ready to use for payment construction. /// /// # Errors /// -/// Returns an error if: -/// - The payer and payee are the same node. -/// - The payment amount is zero or exceeds the maximum representable value. -/// - The total CLTV expiry constraint cannot accommodate the payee's required final CLTV delta. -/// - No route satisfying liquidity, feature, and policy constraints can be found. +/// The function returns an error if: +/// * The payer and payee are the same node (that doesn't make sense). +/// * The payment amount is zero or larger than [`MAX_VALUE_MSAT`]. +/// * The total CLTV delta constraint is too tight for the payee's final CLTV delta. +/// * No route can be found that meets all the liquidity, feature, and policy constraints. /// /// # Panics /// -/// Panics if first_hops contains channels without `short_channel_id`s; -/// [`ChannelManager::list_usable_channels`] will never include such channels. +/// This will panic if `first_hops` contains channels without a short_channel_id. This shouldn't +/// happen in practice since [`ChannelManager::list_usable_channels`] always provides proper IDs, +/// so it's safe to pass that output directly. +/// +/// # See Also /// -/// [`ChannelManager::list_usable_channels`]: crate::ln::channelmanager::ChannelManager::list_usable_channels -/// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed -/// [`NetworkGraph`]: crate::routing::gossip::NetworkGraph +/// [`ChannelManager::list_usable_channels`] to get the first_hops list. +/// [`NetworkGraph`] for more on the network graph parameter. +/// [`RouteParameters`] for available routing constraints. #[rustfmt::skip] pub fn find_route( our_node_pubkey: &PublicKey, route_params: &RouteParameters, From eb778b2b34546147ca91952e713126fa5ad5fbc2 Mon Sep 17 00:00:00 2001 From: StephenChi-hi Date: Tue, 3 Mar 2026 03:25:42 +0100 Subject: [PATCH 3/3] Refactor documentation --- lightning/src/routing/router.rs | 63 ++++++++++++++------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 1ade3fb8fff..d9113a2b5da 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -2582,40 +2582,34 @@ fn sort_first_hop_channels( /// respecting all constraints like fees, CLTV expiry deltas, channel liquidity, and the payee's /// feature requirements. You'll get multiple paths back if multi-path payments (MPP) are needed. /// -/// # Parameters -/// -/// * `our_node_pubkey` - The public key of the payer (us). -/// * `route_params` - Payment parameters including the final value, payee information, feature +/// Parameters +/// - `our_node_pubkey` - The public key of the payer (us). +/// - `route_params` - Payment parameters including the final value, payee information, feature /// requirements from any invoice, and routing constraints like max fees and path count. -/// * `network_graph` - The network graph with all known channels and nodes. -/// * `first_hops` - Channels directly connected to us. If you provide this, it takes priority +/// - `network_graph` - The network graph with all known channels and nodes. +/// - `first_hops` - Channels directly connected to us. If you provide this, it takes priority /// over what's in the network graph, which is useful for unannounced channels. You can get /// this from [`ChannelManager::list_usable_channels`]. -/// * `logger` - For logging routing progress and debug info. -/// * `scorer` - The implementation that ranks and selects paths based on reliability, liquidity, +/// - `logger` - For logging routing progress and debug info. +/// - `scorer` - The implementation that ranks and selects paths based on reliability, liquidity, /// and congestion metrics. -/// * `score_params` - Parameters for tuning the scorer's behavior. -/// * `random_seed_bytes` - A random seed for adding privacy-enhancing offsets to CLTV values. -/// -/// # Payee Information +/// - `score_params` - Parameters for tuning the scorer's behavior. +/// - `random_seed_bytes` - A random seed for adding privacy-enhancing offsets to CLTV values. /// -/// How we handle the payee depends on what they provided: -/// * Bolt11 invoices: Include features via [`RouteParameters::payment_params`] to enable MPP. +/// Payee Information +/// How we handle the payee depends on what they provided: +/// - Bolt11 invoices: Include features via [`RouteParameters::payment_params`] to enable MPP. /// Without features, MPP only works if the payee is already known in the network graph. -/// * Bolt12 invoices: May include blinded paths for privacy. We unblind these in the returned +/// - Bolt12 invoices: May include blinded paths for privacy. We unblind these in the returned /// [`Route`] so you can actually construct the payment. -/// * BOLT11 route hints: Private hops near the payee get included in the final route. -/// -/// # First Hop Behavior +/// - BOLT11 route hints: Private hops near the payee get included in the final route. /// +/// First Hop Behavior /// Fees on channels from us to the next hop are ignored during routing since we assume all /// first-hop channels cost the same. However, we do check the channel's enabled/disabled status /// and HTLC limits (htlc_minimum_msat and htlc_maximum_msat) since those can vary. /// -/// # How It Works -/// /// We use a modified Dijkstra's algorithm, searching backwards from the payee to us: -/// /// 1. Fee calculation: We total up fees at each hop from the payee going back to the payer, /// computing them based on the amount being routed. This gives us accurate estimates because /// the amount increases as we move backward toward the payer. @@ -2629,38 +2623,33 @@ fn sort_first_hop_channels( /// 5. Value provisioning: We collect paths until the total value is roughly 3x the requested /// payment (this gives us room to find cheaper combinations), then we pick the cheapest set. /// -/// # Scoring and Channel Selection -/// +/// Scoring and Channel Selection /// The scorer you provide influences which paths we select during the actual pathfinding. The /// scorer assigns penalties to channels based on factors like: -/// * How reliable the channel has been historically -/// * Known liquidity constraints and in-flight HTLCs -/// * Estimated network congestion +/// - How reliable the channel has been historically +/// - Known liquidity constraints and in-flight HTLCs +/// - Estimated network congestion /// /// These penalties are built into the algorithm's scoring, so channels with higher penalties are /// naturally deprioritized as we search for paths, letting us favor more reliable and liquid /// options. /// -/// # Returns -/// +/// Returns /// On success, you get a [`Route`] with one or more payment paths. The route respects all /// your constraints and is ready to use for payment construction. /// -/// # Errors -/// +/// Errors /// The function returns an error if: -/// * The payer and payee are the same node (that doesn't make sense). -/// * The payment amount is zero or larger than [`MAX_VALUE_MSAT`]. -/// * The total CLTV delta constraint is too tight for the payee's final CLTV delta. -/// * No route can be found that meets all the liquidity, feature, and policy constraints. -/// -/// # Panics +/// - The payer and payee are the same node (that doesn't make sense). +/// - The payment amount is zero or larger than [`MAX_VALUE_MSAT`]. +/// - The total CLTV delta constraint is too tight for the payee's final CLTV delta. +/// - No route can be found that meets all the liquidity, feature, and policy constraints. /// /// This will panic if `first_hops` contains channels without a short_channel_id. This shouldn't /// happen in practice since [`ChannelManager::list_usable_channels`] always provides proper IDs, /// so it's safe to pass that output directly. /// -/// # See Also +/// See Also /// /// [`ChannelManager::list_usable_channels`] to get the first_hops list. /// [`NetworkGraph`] for more on the network graph parameter.