diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index c0775286355..19adf6ae077 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -105,6 +105,9 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, // The minimum channel balance certainty required for using a channel in a blinded path. const MIN_CHANNEL_CERTAINTY: f64 = 0.5; + // The minimum success probability required for using a channel in a blinded path. + const MIN_SUCCESS_PROBABILITY: f64 = 0.25; + let network_graph = self.network_graph.deref().read_only(); let counterparty_channels = first_hops.into_iter() .filter(|details| details.counterparty.features.supports_route_blinding()) @@ -180,6 +183,21 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, // // source --- info ---> counterparty --- counterparty_forward_node ---> recipient .filter_map(|(introduction_node_id, scid, info, counterparty_forward_node)| { + let amount_msat = amount_msats; + let effective_capacity = info.effective_capacity(); + let usage = ChannelUsage { amount_msat, inflight_htlc_msat: 0, effective_capacity }; + let success_probability = scorer.channel_success_probability( + scid, &info, usage, &self.score_params + ); + + if !success_probability.is_finite() { + return None; + } + + if success_probability < MIN_SUCCESS_PROBABILITY { + return None; + } + let htlc_minimum_msat = info.direction().htlc_minimum_msat; let htlc_maximum_msat = info.direction().htlc_maximum_msat; let payment_relay: PaymentRelay = match info.try_into() { @@ -201,12 +219,13 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, node_id: introduction_node_id.as_pubkey().unwrap(), htlc_maximum_msat, }; - Some(BlindedPath::new_for_payment( + let path = BlindedPath::new_for_payment( &[introduction_forward_node, counterparty_forward_node], recipient, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, entropy_source, secp_ctx - )) - }) - .take(MAX_PAYMENT_PATHS); + ); + + Some(path.map(|path| (path, success_probability))) + }); let two_hop_paths = counterparty_channels .map(|(forward_node, _)| { @@ -220,6 +239,10 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, three_hop_paths .collect::, _>>().ok() .and_then(|paths| (!paths.is_empty()).then(|| paths)) + .map(|mut paths| { + paths.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + paths.into_iter().map(|(path, _)| path).take(MAX_PAYMENT_PATHS).collect::>() + }) .or_else(|| two_hop_paths.collect::, _>>().ok()) .and_then(|paths| (!paths.is_empty()).then(|| paths)) .or_else(|| network_graph diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index 1c16fbf494c..3c7b623065d 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -109,6 +109,18 @@ pub trait ScoreLookUp { &self, candidate: &CandidateRouteHop, usage: ChannelUsage, score_params: &Self::ScoreParams ) -> u64; + /// Returns the success probability of sending an HTLC through a channel. + /// + /// Expected to return a value between `0.0` and `1.0`, inclusive, where `0.0` indicates + /// highly unlikely and `1.0` highly likely. + /// + /// This is useful to determine whether a channel should be included in a blinded path and the + /// preferred ordering of blinded paths. + fn channel_success_probability( + &self, _short_channel_id: u64, _info: &DirectedChannelInfo, _usage: ChannelUsage, + _score_params: &Self::ScoreParams + ) -> f64 { 0.5 } + /// Returns how certain any knowledge gained about the channel's liquidity balance is. /// /// Expected to return a value between `0.0` and `1.0`, inclusive, where `0.0` indicates