Merge pull request #2847 from TheBlueMatt/2024-01-bindings-upstream
[rust-lightning] / lightning / src / routing / router.rs
index 284bf62f36e561f1f1793e3d302f0d7d54280175..d5072f9caa2330c1bedce52c70311cad6a9a574a 100644 (file)
@@ -10,8 +10,6 @@
 //! The router finds paths within a [`NetworkGraph`] for a payment.
 
 use bitcoin::secp256k1::{PublicKey, Secp256k1, self};
-use bitcoin::hashes::Hash;
-use bitcoin::hashes::sha256::Hash as Sha256;
 
 use crate::blinded_path::{BlindedHop, BlindedPath};
 use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs};
@@ -20,49 +18,50 @@ use crate::ln::channelmanager::{ChannelDetails, PaymentId};
 use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
 use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
 use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice};
-use crate::onion_message::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
+use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
 use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
 use crate::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp};
 use crate::sign::EntropySource;
 use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
 use crate::util::logger::{Level, Logger};
-use crate::util::chacha20::ChaCha20;
+use crate::crypto::chacha20::ChaCha20;
 
 use crate::io;
 use crate::prelude::*;
-use crate::sync::Mutex;
 use alloc::collections::BinaryHeap;
 use core::{cmp, fmt};
 use core::ops::Deref;
 
 /// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> where
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> where
        L::Target: Logger,
        S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>,
+       ES::Target: EntropySource,
 {
        network_graph: G,
        logger: L,
-       random_seed_bytes: Mutex<[u8; 32]>,
+       entropy_source: ES,
        scorer: S,
        score_params: SP,
-       message_router: DefaultMessageRouter<G, L>,
+       message_router: DefaultMessageRouter<G, L, ES>,
 }
 
-impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> DefaultRouter<G, L, S, SP, Sc> where
+impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref + Clone, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> DefaultRouter<G, L, ES, S, SP, Sc> where
        L::Target: Logger,
        S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>,
+       ES::Target: EntropySource,
 {
        /// Creates a new router.
-       pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S, score_params: SP) -> Self {
-               let random_seed_bytes = Mutex::new(random_seed_bytes);
-               let message_router = DefaultMessageRouter::new(network_graph.clone());
-               Self { network_graph, logger, random_seed_bytes, scorer, score_params, message_router }
+       pub fn new(network_graph: G, logger: L, entropy_source: ES, scorer: S, score_params: SP) -> Self {
+               let message_router = DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone());
+               Self { network_graph, logger, entropy_source, scorer, score_params, message_router }
        }
 }
 
-impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
+impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> Router for DefaultRouter<G, L, ES, S, SP, Sc> where
        L::Target: Logger,
        S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>,
+       ES::Target: EntropySource,
 {
        fn find_route(
                &self,
@@ -71,11 +70,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
                first_hops: Option<&[&ChannelDetails]>,
                inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError> {
-               let random_seed_bytes = {
-                       let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
-                       *locked_random_seed_bytes = Sha256::hash(&*locked_random_seed_bytes).to_byte_array();
-                       *locked_random_seed_bytes
-               };
+               let random_seed_bytes = self.entropy_source.get_secure_random_bytes();
                find_route(
                        payer, params, &self.network_graph, first_hops, &*self.logger,
                        &ScorerAccountingForInFlightHtlcs::new(self.scorer.read_lock(), &inflight_htlcs),
@@ -85,10 +80,10 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
        }
 
        fn create_blinded_payment_paths<
-               ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
-       >(
+               T: secp256k1::Signing + secp256k1::Verification
+       > (
                &self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
-               amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1<T>
+               amount_msats: u64, secp_ctx: &Secp256k1<T>
        ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
                // Limit the number of blinded paths that are computed.
                const MAX_PAYMENT_PATHS: usize = 3;
@@ -114,19 +109,14 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
                                        None => return None,
                                };
                                let payment_relay: PaymentRelay = match details.counterparty.forwarding_info {
-                                       Some(forwarding_info) => forwarding_info.into(),
+                                       Some(forwarding_info) => match forwarding_info.try_into() {
+                                               Ok(payment_relay) => payment_relay,
+                                               Err(()) => return None,
+                                       },
                                        None => return None,
                                };
 
-                               // Avoid exposing esoteric CLTV expiry deltas
-                               let cltv_expiry_delta = match payment_relay.cltv_expiry_delta {
-                                       0..=40 => 40u32,
-                                       41..=80 => 80u32,
-                                       81..=144 => 144u32,
-                                       145..=216 => 216u32,
-                                       _ => return None,
-                               };
-
+                               let cltv_expiry_delta = payment_relay.cltv_expiry_delta as u32;
                                let payment_constraints = PaymentConstraints {
                                        max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta,
                                        htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0),
@@ -144,7 +134,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
                        })
                        .map(|forward_node| {
                                BlindedPath::new_for_payment(
-                                       &[forward_node], recipient, tlvs.clone(), u64::MAX, entropy_source, secp_ctx
+                                       &[forward_node], recipient, tlvs.clone(), u64::MAX, &*self.entropy_source, secp_ctx
                                )
                        })
                        .take(MAX_PAYMENT_PATHS)
@@ -154,7 +144,7 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
                        Ok(paths) if !paths.is_empty() => Ok(paths),
                        _ => {
                                if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) {
-                                       BlindedPath::one_hop_for_payment(recipient, tlvs, entropy_source, secp_ctx)
+                                       BlindedPath::one_hop_for_payment(recipient, tlvs, &*self.entropy_source, secp_ctx)
                                                .map(|path| vec![path])
                                } else {
                                        Err(())
@@ -164,9 +154,10 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
        }
 }
 
-impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> MessageRouter for DefaultRouter<G, L, S, SP, Sc> where
+impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> MessageRouter for DefaultRouter<G, L, ES, S, SP, Sc> where
        L::Target: Logger,
        S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>,
+       ES::Target: EntropySource,
 {
        fn find_path(
                &self, sender: PublicKey, peers: Vec<PublicKey>, destination: Destination
@@ -175,12 +166,11 @@ impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
        }
 
        fn create_blinded_paths<
-               ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
-       >(
-               &self, recipient: PublicKey, peers: Vec<PublicKey>, entropy_source: &ES,
-               secp_ctx: &Secp256k1<T>
+               T: secp256k1::Signing + secp256k1::Verification
+       > (
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
-               self.message_router.create_blinded_paths(recipient, peers, entropy_source, secp_ctx)
+               self.message_router.create_blinded_paths(recipient, peers, secp_ctx)
        }
 }
 
@@ -214,10 +204,10 @@ pub trait Router: MessageRouter {
        /// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are
        /// given in `tlvs`.
        fn create_blinded_payment_paths<
-               ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
-       >(
+               T: secp256k1::Signing + secp256k1::Verification
+       > (
                &self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
-               amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1<T>
+               amount_msats: u64, secp_ctx: &Secp256k1<T>
        ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()>;
 }
 
@@ -1151,8 +1141,12 @@ pub struct FirstHopCandidate<'a> {
        /// has been funded and is able to pay), and accessor methods may panic otherwise.
        ///
        /// [`find_route`] validates this prior to constructing a [`CandidateRouteHop`].
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub details: &'a ChannelDetails,
        /// The node id of the payer, which is also the source side of this candidate route hop.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub payer_node_id: &'a NodeId,
 }
 
@@ -1161,6 +1155,8 @@ pub struct FirstHopCandidate<'a> {
 pub struct PublicHopCandidate<'a> {
        /// Information about the channel, including potentially its capacity and
        /// direction-specific information.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub info: DirectedChannelInfo<'a>,
        /// The short channel ID of the channel, i.e. the identifier by which we refer to this
        /// channel.
@@ -1171,8 +1167,12 @@ pub struct PublicHopCandidate<'a> {
 #[derive(Clone, Debug)]
 pub struct PrivateHopCandidate<'a> {
        /// Information about the private hop communicated via BOLT 11.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub hint: &'a RouteHintHop,
        /// Node id of the next hop in BOLT 11 route hint.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub target_node_id: &'a NodeId
 }
 
@@ -1181,6 +1181,8 @@ pub struct PrivateHopCandidate<'a> {
 pub struct BlindedPathCandidate<'a> {
        /// Information about the blinded path including the fee, HTLC amount limits, and
        /// cryptographic material required to build an HTLC through the given path.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub hint: &'a (BlindedPayInfo, BlindedPath),
        /// Index of the hint in the original list of blinded hints.
        ///
@@ -1196,6 +1198,8 @@ pub struct OneHopBlindedPathCandidate<'a> {
        /// cryptographic material required to build an HTLC terminating with the given path.
        ///
        /// Note that the [`BlindedPayInfo`] is ignored here.
+       ///
+       /// This is not exported to bindings users as lifetimes are not expressable in most languages.
        pub hint: &'a (BlindedPayInfo, BlindedPath),
        /// Index of the hint in the original list of blinded hints.
        ///
@@ -1383,6 +1387,15 @@ impl<'a> CandidateRouteHop<'a> {
                        _ => None,
                }
        }
+       fn blinded_hint_idx(&self) -> Option<usize> {
+               match self {
+                       Self::Blinded(BlindedPathCandidate { hint_idx, .. }) |
+                       Self::OneHopBlinded(OneHopBlindedPathCandidate { hint_idx, .. }) => {
+                               Some(*hint_idx)
+                       },
+                       _ => None,
+               }
+       }
        /// Returns the source node id of current hop.
        ///
        /// Source node id refers to the node forwarding the HTLC through this hop.
@@ -2134,8 +2147,15 @@ where L::Target: Logger {
                                                 (amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
                                                  recommended_value_msat >= $next_hops_path_htlc_minimum_msat));
 
-                                       let payment_failed_on_this_channel = scid_opt.map_or(false,
-                                               |scid| payment_params.previously_failed_channels.contains(&scid));
+                                       let payment_failed_on_this_channel = match scid_opt {
+                                               Some(scid) => payment_params.previously_failed_channels.contains(&scid),
+                                               None => match $candidate.blinded_hint_idx() {
+                                                       Some(idx) => {
+                                                               payment_params.previously_failed_blinded_path_idxs.contains(&(idx as u64))
+                                                       },
+                                                       None => false,
+                                               },
+                                       };
 
                                        let (should_log_candidate, first_hop_details) = match $candidate {
                                                CandidateRouteHop::FirstHop(hop) => (true, Some(hop.details)),
@@ -2729,7 +2749,7 @@ where L::Target: Logger {
                                                }
                                        }
 
-                                       // Means we succesfully traversed from the payer to the payee, now
+                                       // Means we successfully traversed from the payer to the payee, now
                                        // save this path for the payment route. Also, update the liquidity
                                        // remaining on the used hops, so that we take them into account
                                        // while looking for more paths.
@@ -3218,7 +3238,7 @@ mod tests {
        use crate::offers::invoice::BlindedPayInfo;
        use crate::util::config::UserConfig;
        use crate::util::test_utils as ln_test_utils;
-       use crate::util::chacha20::ChaCha20;
+       use crate::crypto::chacha20::ChaCha20;
        use crate::util::ser::{Readable, Writeable};
        #[cfg(c_bindings)]
        use crate::util::ser::Writer;
@@ -6925,7 +6945,7 @@ mod tests {
                        (route.paths[1].hops[1].short_channel_id == 4 && route.paths[0].hops[1].short_channel_id == 13));
        }
 
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        pub(super) fn random_init_seed() -> u64 {
                // Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG.
                use core::hash::{BuildHasher, Hasher};
@@ -6935,7 +6955,7 @@ mod tests {
        }
 
        #[test]
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        fn generate_routes() {
                use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 
@@ -6956,7 +6976,7 @@ mod tests {
        }
 
        #[test]
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        fn generate_routes_mpp() {
                use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 
@@ -6977,7 +6997,7 @@ mod tests {
        }
 
        #[test]
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        fn generate_large_mpp_routes() {
                use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
 
@@ -7826,7 +7846,7 @@ mod tests {
        fn do_min_htlc_overpay_violates_max_htlc(blinded_payee: bool) {
                // Test that if overpaying to meet a later hop's min_htlc and causes us to violate an earlier
                // hop's max_htlc, we don't consider that candidate hop valid. Previously we would add this hop
-               // to `targets` and build an invalid path with it, and subsquently hit a debug panic asserting
+               // to `targets` and build an invalid path with it, and subsequently hit a debug panic asserting
                // that the used liquidity for a hop was less than its available liquidity limit.
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(ln_test_utils::TestLogger::new());
@@ -8313,7 +8333,7 @@ mod tests {
        }
 }
 
-#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))]
+#[cfg(all(any(test, ldk_bench), feature = "std"))]
 pub(crate) mod bench_utils {
        use super::*;
        use std::fs::File;
@@ -8475,7 +8495,7 @@ pub(crate) mod bench_utils {
                                                        }
                                                        break;
                                                }
-                                               // If we couldn't find a path with a higer amount, reduce and try again.
+                                               // If we couldn't find a path with a higher amount, reduce and try again.
                                                score_amt /= 100;
                                        }