X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=b26298391b2f9cb2fe3561b2b5786927a27ef6a2;hb=8f4bd19c04de9b0cb67e0f607d49213a7d71a1f6;hp=28ca2c4bfc700d2509cfa00539472546e154797f;hpb=c8fd77de254c0ca1d941c7980a278beae9979c0f;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 28ca2c4b..b2629839 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -172,6 +172,12 @@ impl InFlightHtlcs { /// Takes in a path with payer's node id and adds the path's details to `InFlightHtlcs`. pub fn process_path(&mut self, path: &Path, payer_node_id: PublicKey) { if path.hops.is_empty() { return }; + + let mut cumulative_msat = 0; + if let Some(tail) = &path.blinded_tail { + cumulative_msat += tail.final_value_msat; + } + // total_inflight_map needs to be direction-sensitive when keeping track of the HTLC value // that is held up. However, the `hops` array, which is a path returned by `find_route` in // the router excludes the payer node. In the following lines, the payer's information is @@ -180,7 +186,6 @@ impl InFlightHtlcs { let reversed_hops_with_payer = path.hops.iter().rev().skip(1) .map(|hop| hop.pubkey) .chain(core::iter::once(payer_node_id)); - let mut cumulative_msat = 0; // Taking the reversed vector from above, we zip it with just the reversed hops list to // work "backwards" of the given path, since the last hop's `fee_msat` actually represents @@ -2175,6 +2180,10 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, shadow_ctlv_expiry_delta_offset = cmp::min(shadow_ctlv_expiry_delta_offset, max_path_offset); // Add 'shadow' CLTV offset to the final hop + if let Some(tail) = path.blinded_tail.as_mut() { + tail.excess_final_cltv_expiry_delta = tail.excess_final_cltv_expiry_delta + .checked_add(shadow_ctlv_expiry_delta_offset).unwrap_or(tail.excess_final_cltv_expiry_delta); + } if let Some(last_hop) = path.hops.last_mut() { last_hop.cltv_expiry_delta = last_hop.cltv_expiry_delta .checked_add(shadow_ctlv_expiry_delta_offset).unwrap_or(last_hop.cltv_expiry_delta); @@ -2267,7 +2276,7 @@ mod tests { use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity}; use crate::routing::utxo::UtxoResult; use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features, - BlindedTail, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, + BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE}; use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel}; @@ -5828,6 +5837,89 @@ mod tests { assert_eq!(decoded_route.paths[0].blinded_tail, route.paths[0].blinded_tail); assert_eq!(decoded_route.paths[1].blinded_tail, route.paths[1].blinded_tail); } + + #[test] + fn blinded_path_inflight_processing() { + // Ensure we'll score the channel that's inbound to a blinded path's introduction node, and + // account for the blinded tail's final amount_msat. + let mut inflight_htlcs = InFlightHtlcs::new(); + let blinded_path = BlindedPath { + introduction_node_id: ln_test_utils::pubkey(43), + blinding_point: ln_test_utils::pubkey(48), + blinded_hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() }], + }; + let path = Path { + hops: vec![RouteHop { + pubkey: ln_test_utils::pubkey(42), + node_features: NodeFeatures::empty(), + short_channel_id: 42, + channel_features: ChannelFeatures::empty(), + fee_msat: 100, + cltv_expiry_delta: 0, + }, + RouteHop { + pubkey: blinded_path.introduction_node_id, + node_features: NodeFeatures::empty(), + short_channel_id: 43, + channel_features: ChannelFeatures::empty(), + fee_msat: 1, + cltv_expiry_delta: 0, + }], + blinded_tail: Some(BlindedTail { + hops: blinded_path.blinded_hops, + blinding_point: blinded_path.blinding_point, + excess_final_cltv_expiry_delta: 0, + final_value_msat: 200, + }), + }; + inflight_htlcs.process_path(&path, ln_test_utils::pubkey(44)); + assert_eq!(*inflight_htlcs.0.get(&(42, true)).unwrap(), 301); + assert_eq!(*inflight_htlcs.0.get(&(43, false)).unwrap(), 201); + } + + #[test] + fn blinded_path_cltv_shadow_offset() { + // Make sure we add a shadow offset when sending to blinded paths. + let blinded_path = BlindedPath { + introduction_node_id: ln_test_utils::pubkey(43), + blinding_point: ln_test_utils::pubkey(44), + blinded_hops: vec![ + BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() }, + BlindedHop { blinded_node_id: ln_test_utils::pubkey(46), encrypted_payload: Vec::new() } + ], + }; + let mut route = Route { paths: vec![Path { + hops: vec![RouteHop { + pubkey: ln_test_utils::pubkey(42), + node_features: NodeFeatures::empty(), + short_channel_id: 42, + channel_features: ChannelFeatures::empty(), + fee_msat: 100, + cltv_expiry_delta: 0, + }, + RouteHop { + pubkey: blinded_path.introduction_node_id, + node_features: NodeFeatures::empty(), + short_channel_id: 43, + channel_features: ChannelFeatures::empty(), + fee_msat: 1, + cltv_expiry_delta: 0, + } + ], + blinded_tail: Some(BlindedTail { + hops: blinded_path.blinded_hops, + blinding_point: blinded_path.blinding_point, + excess_final_cltv_expiry_delta: 0, + final_value_msat: 200, + }), + }], payment_params: None}; + + let payment_params = PaymentParameters::from_node_id(ln_test_utils::pubkey(47), 18); + let (_, network_graph, _, _, _) = build_line_graph(); + add_random_cltv_offset(&mut route, &payment_params, &network_graph.read_only(), &[0; 32]); + assert_eq!(route.paths[0].blinded_tail.as_ref().unwrap().excess_final_cltv_expiry_delta, 40); + assert_eq!(route.paths[0].hops.last().unwrap().cltv_expiry_delta, 40); + } } #[cfg(all(test, not(feature = "no-std")))]