X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=1758cbbf9c3eaae24151050f488c2524f43109da;hb=971f7a7e42652d5697d761df6650ae9e6dcaa5db;hp=10bdd69b51a9b4a66e14ace4278645da4ada4be4;hpb=6082b57097a4ccca168641dac872d6afa9659502;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 10bdd69b..1758cbbf 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -250,10 +250,20 @@ pub struct RouteHop { /// /// [`BlindedPath`]: crate::blinded_path::BlindedPath pub cltv_expiry_delta: u32, + /// Indicates whether this hop is possibly announced in the public network graph. + /// + /// Will be `true` if there is a possibility that the channel is publicly known, i.e., if we + /// either know for sure it's announced in the public graph, or if any public channels exist + /// for which the given `short_channel_id` could be an alias for. Will be `false` if we believe + /// the channel to be unannounced. + /// + /// Will be `true` for objects serialized with LDK version 0.0.116 and before. + pub maybe_announced_channel: bool, } impl_writeable_tlv_based!(RouteHop, { (0, pubkey, required), + (1, maybe_announced_channel, (default_value, true)), (2, node_features, required), (4, short_channel_id, required), (6, channel_features, required), @@ -359,8 +369,12 @@ impl Route { overpaid_value_msat + self.paths.iter().map(|path| path.fee_msat()).sum::() } - /// Returns the total amount paid on this [`Route`], excluding the fees. Might be more than - /// requested if we had to reach htlc_minimum_msat. + /// Returns the total amount paid on this [`Route`], excluding the fees. + /// + /// Might be more than requested as part of the given [`RouteParameters::final_value_msat`] if + /// we had to reach the [`htlc_minimum_msat`] limits. + /// + /// [`htlc_minimum_msat`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_update-message pub fn get_total_amount(&self) -> u64 { self.paths.iter().map(|path| path.final_value_msat()).sum() } @@ -2468,9 +2482,27 @@ where L::Target: Logger { let mut paths = Vec::new(); for payment_path in selected_route { let mut hops = Vec::with_capacity(payment_path.hops.len()); + let mut prev_hop_node_id = our_node_id; for (hop, node_features) in payment_path.hops.iter() .filter(|(h, _)| h.candidate.short_channel_id().is_some()) { + let maybe_announced_channel = if let CandidateRouteHop::PublicHop { .. } = hop.candidate { + // If we sourced the hop from the graph we're sure the target node is announced. + true + } else if let CandidateRouteHop::FirstHop { details } = hop.candidate { + // If this is a first hop we also know if it's announced. + details.is_public + } else { + // If we sourced it any other way, we double-check the network graph to see if + // there are announced channels between the endpoints. If so, the hop might be + // referring to any of the announced channels, as its `short_channel_id` might be + // an alias, in which case we don't take any chances here. + network_graph.node(&hop.node_id).map_or(false, |hop_node| + hop_node.channels.iter().any(|scid| network_graph.channel(*scid) + .map_or(false, |c| c.as_directed_from(&prev_hop_node_id).is_some())) + ) + }; + hops.push(RouteHop { pubkey: PublicKey::from_slice(hop.node_id.as_slice()).map_err(|_| LightningError{err: format!("Public key {:?} is invalid", &hop.node_id), action: ErrorAction::IgnoreAndLog(Level::Trace)})?, node_features: node_features.clone(), @@ -2478,7 +2510,10 @@ where L::Target: Logger { channel_features: hop.candidate.features(), fee_msat: hop.fee_msat, cltv_expiry_delta: hop.candidate.cltv_expiry_delta(), + maybe_announced_channel, }); + + prev_hop_node_id = hop.node_id; } let mut final_cltv_delta = final_cltv_expiry_delta; let blinded_tail = payment_path.hops.last().and_then(|(h, _)| { @@ -5960,17 +5995,17 @@ mod tests { RouteHop { pubkey: PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0, maybe_announced_channel: true, }, RouteHop { pubkey: PublicKey::from_slice(&hex::decode("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0, maybe_announced_channel: true, }, RouteHop { pubkey: PublicKey::from_slice(&hex::decode("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 225, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 225, cltv_expiry_delta: 0, maybe_announced_channel: true, }, ], blinded_tail: None }], route_params: None, @@ -5987,23 +6022,23 @@ mod tests { RouteHop { pubkey: PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0, maybe_announced_channel: true, }, RouteHop { pubkey: PublicKey::from_slice(&hex::decode("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0, maybe_announced_channel: true, }, ], blinded_tail: None }, Path { hops: vec![ RouteHop { pubkey: PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 100, cltv_expiry_delta: 0, maybe_announced_channel: true, }, RouteHop { pubkey: PublicKey::from_slice(&hex::decode("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()[..]).unwrap(), channel_features: ChannelFeatures::empty(), node_features: NodeFeatures::empty(), - short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0 + short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0, maybe_announced_channel: true, }, ], blinded_tail: None }], route_params: None, @@ -6602,6 +6637,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 100, cltv_expiry_delta: 0, + maybe_announced_channel: true, }], blinded_tail: Some(BlindedTail { hops: blinded_path_1.blinded_hops, @@ -6616,6 +6652,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 100, cltv_expiry_delta: 0, + maybe_announced_channel: true, }], blinded_tail: None }], route_params: None, }; @@ -6655,6 +6692,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 100, cltv_expiry_delta: 0, + maybe_announced_channel: false, }, RouteHop { pubkey: blinded_path.introduction_node_id, @@ -6663,6 +6701,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 1, cltv_expiry_delta: 0, + maybe_announced_channel: false, }], blinded_tail: Some(BlindedTail { hops: blinded_path.blinded_hops, @@ -6695,6 +6734,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 100, cltv_expiry_delta: 0, + maybe_announced_channel: false, }, RouteHop { pubkey: blinded_path.introduction_node_id, @@ -6703,6 +6743,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 1, cltv_expiry_delta: 0, + maybe_announced_channel: false, } ], blinded_tail: Some(BlindedTail {