X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=c680d57a6dc4f05e97d838d038e2e90276f92874;hb=26b515c13cccd1d027e67d0c65d69321d235ce40;hp=799b6407981341b0bc4fbfae0f387bdbe23186ad;hpb=266a3aa9152e9d50570ae41b3be1548a715d0754;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 799b6407..c680d57a 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), @@ -337,23 +347,34 @@ pub struct Route { /// [`BlindedTail`]s are present, then the pubkey of the last [`RouteHop`] in each path must be /// the same. pub paths: Vec, - /// The `payment_params` parameter passed via [`RouteParameters`] to [`find_route`]. + /// The `route_params` parameter passed to [`find_route`]. /// /// This is used by `ChannelManager` to track information which may be required for retries. - pub payment_params: Option, + /// + /// Will be `None` for objects serialized with LDK versions prior to 0.0.117. + pub route_params: Option, } impl Route { /// Returns the total amount of fees paid on this [`Route`]. /// - /// This doesn't include any extra payment made to the recipient, which can happen in excess of - /// the amount passed to [`find_route`]'s `route_params.final_value_msat`. + /// For objects serialized with LDK 0.0.117 and after, this includes any extra payment made to + /// the recipient, which can happen in excess of the amount passed to [`find_route`] via + /// [`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_fees(&self) -> u64 { - self.paths.iter().map(|path| path.fee_msat()).sum() + let overpaid_value_msat = self.route_params.as_ref() + .map_or(0, |p| self.get_total_amount().saturating_sub(p.final_value_msat)); + 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() } @@ -383,8 +404,12 @@ impl Writeable for Route { } } write_tlv_fields!(writer, { - (1, self.payment_params, option), + // For compatibility with LDK versions prior to 0.0.117, we take the individual + // RouteParameters' fields and reconstruct them on read. + (1, self.route_params.as_ref().map(|p| &p.payment_params), option), (2, blinded_tails, optional_vec), + (3, self.route_params.as_ref().map(|p| p.final_value_msat), option), + (5, self.route_params.as_ref().map(|p| p.max_total_routing_fee_msat), option), }); Ok(()) } @@ -411,6 +436,8 @@ impl Readable for Route { _init_and_read_len_prefixed_tlv_fields!(reader, { (1, payment_params, (option: ReadableArgs, min_final_cltv_expiry_delta)), (2, blinded_tails, optional_vec), + (3, final_value_msat, option), + (5, max_total_routing_fee_msat, option) }); let blinded_tails = blinded_tails.unwrap_or(Vec::new()); if blinded_tails.len() != 0 { @@ -419,26 +446,43 @@ impl Readable for Route { path.blinded_tail = blinded_tail_opt; } } - Ok(Route { paths, payment_params }) + + // If we previously wrote the corresponding fields, reconstruct RouteParameters. + let route_params = match (payment_params, final_value_msat) { + (Some(payment_params), Some(final_value_msat)) => { + Some(RouteParameters { payment_params, final_value_msat, max_total_routing_fee_msat }) + } + _ => None, + }; + + Ok(Route { paths, route_params }) } } /// Parameters needed to find a [`Route`]. /// /// Passed to [`find_route`] and [`build_route_from_hops`]. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct RouteParameters { /// The parameters of the failed payment path. pub payment_params: PaymentParameters, /// The amount in msats sent on the failed payment path. pub final_value_msat: u64, + + /// The maximum total fees, in millisatoshi, that may accrue during route finding. + /// + /// This limit also applies to the total fees that may arise while retrying failed payment + /// paths. + /// + /// Default value: `None` + pub max_total_routing_fee_msat: Option, } impl RouteParameters { /// Constructs [`RouteParameters`] from the given [`PaymentParameters`] and a payment amount. pub fn from_payment_params_and_value(payment_params: PaymentParameters, final_value_msat: u64) -> Self { - Self { payment_params, final_value_msat } + Self { payment_params, final_value_msat, max_total_routing_fee_msat: None } } } @@ -446,6 +490,7 @@ impl Writeable for RouteParameters { fn write(&self, writer: &mut W) -> Result<(), io::Error> { write_tlv_fields!(writer, { (0, self.payment_params, required), + (1, self.max_total_routing_fee_msat, option), (2, self.final_value_msat, required), // LDK versions prior to 0.0.114 had the `final_cltv_expiry_delta` parameter in // `RouteParameters` directly. For compatibility, we write it here. @@ -459,6 +504,7 @@ impl Readable for RouteParameters { fn read(reader: &mut R) -> Result { _init_and_read_len_prefixed_tlv_fields!(reader, { (0, payment_params, (required: ReadableArgs, 0)), + (1, max_total_routing_fee_msat, option), (2, final_value_msat, required), (4, final_cltv_delta, option), }); @@ -471,6 +517,7 @@ impl Readable for RouteParameters { Ok(Self { payment_params, final_value_msat: final_value_msat.0.unwrap(), + max_total_routing_fee_msat, }) } } @@ -1646,6 +1693,7 @@ where L::Target: Logger { let mut num_ignored_path_length_limit = 0; let mut num_ignored_cltv_delta_limit = 0; let mut num_ignored_previously_failed = 0; + let mut num_ignored_total_fee_limit = 0; macro_rules! add_entry { // Adds entry which goes from $src_node_id to $dest_node_id over the $candidate hop. @@ -1807,89 +1855,98 @@ where L::Target: Logger { total_fee_msat = total_fee_msat.saturating_add(hop_use_fee_msat); } - let channel_usage = ChannelUsage { - amount_msat: amount_to_transfer_over_msat, - inflight_htlc_msat: used_liquidity_msat, - effective_capacity, - }; - let channel_penalty_msat = scid_opt.map_or(0, - |scid| scorer.channel_penalty_msat(scid, &$src_node_id, &$dest_node_id, - channel_usage, score_params)); - let path_penalty_msat = $next_hops_path_penalty_msat - .saturating_add(channel_penalty_msat); - let new_graph_node = RouteGraphNode { - node_id: $src_node_id, - lowest_fee_to_node: total_fee_msat, - total_cltv_delta: hop_total_cltv_delta, - value_contribution_msat, - path_htlc_minimum_msat, - path_penalty_msat, - path_length_to_node, - }; - - // Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id), - // if this way is cheaper than the already known - // (considering the cost to "reach" this channel from the route destination, - // the cost of using this channel, - // and the cost of routing to the source node of this channel). - // Also, consider that htlc_minimum_msat_difference, because we might end up - // paying it. Consider the following exploit: - // we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path, - // and for the other one we picked a 1sat-fee path with htlc_minimum_msat of - // 1 BTC. Now, since the latter is more expensive, we gonna try to cut it - // by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC - // to this channel. - // Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here), - // but it may require additional tracking - we don't want to double-count - // the fees included in $next_hops_path_htlc_minimum_msat, but also - // can't use something that may decrease on future hops. - let old_cost = cmp::max(old_entry.total_fee_msat, old_entry.path_htlc_minimum_msat) - .saturating_add(old_entry.path_penalty_msat); - let new_cost = cmp::max(total_fee_msat, path_htlc_minimum_msat) - .saturating_add(path_penalty_msat); - - if !old_entry.was_processed && new_cost < old_cost { - targets.push(new_graph_node); - old_entry.next_hops_fee_msat = $next_hops_fee_msat; - old_entry.hop_use_fee_msat = hop_use_fee_msat; - old_entry.total_fee_msat = total_fee_msat; - old_entry.node_id = $dest_node_id.clone(); - old_entry.candidate = $candidate.clone(); - old_entry.fee_msat = 0; // This value will be later filled with hop_use_fee_msat of the following channel - old_entry.path_htlc_minimum_msat = path_htlc_minimum_msat; - old_entry.path_penalty_msat = path_penalty_msat; - #[cfg(all(not(ldk_bench), any(test, fuzzing)))] - { - old_entry.value_contribution_msat = value_contribution_msat; + // Ignore hops if augmenting the current path to them would put us over `max_total_routing_fee_msat` + let max_total_routing_fee_msat = route_params.max_total_routing_fee_msat.unwrap_or(u64::max_value()); + if total_fee_msat > max_total_routing_fee_msat { + if should_log_candidate { + log_trace!(logger, "Ignoring {} due to exceeding max total routing fee limit.", LoggedCandidateHop(&$candidate)); } - did_add_update_path_to_src_node = Some(value_contribution_msat); - } else if old_entry.was_processed && new_cost < old_cost { - #[cfg(all(not(ldk_bench), any(test, fuzzing)))] - { - // If we're skipping processing a node which was previously - // processed even though we found another path to it with a - // cheaper fee, check that it was because the second path we - // found (which we are processing now) has a lower value - // contribution due to an HTLC minimum limit. - // - // e.g. take a graph with two paths from node 1 to node 2, one - // through channel A, and one through channel B. Channel A and - // B are both in the to-process heap, with their scores set by - // a higher htlc_minimum than fee. - // Channel A is processed first, and the channels onwards from - // node 1 are added to the to-process heap. Thereafter, we pop - // Channel B off of the heap, note that it has a much more - // restrictive htlc_maximum_msat, and recalculate the fees for - // all of node 1's channels using the new, reduced, amount. - // - // This would be bogus - we'd be selecting a higher-fee path - // with a lower htlc_maximum_msat instead of the one we'd - // already decided to use. - debug_assert!(path_htlc_minimum_msat < old_entry.path_htlc_minimum_msat); - debug_assert!( - value_contribution_msat + path_penalty_msat < - old_entry.value_contribution_msat + old_entry.path_penalty_msat - ); + num_ignored_total_fee_limit += 1; + } else { + let channel_usage = ChannelUsage { + amount_msat: amount_to_transfer_over_msat, + inflight_htlc_msat: used_liquidity_msat, + effective_capacity, + }; + let channel_penalty_msat = scid_opt.map_or(0, + |scid| scorer.channel_penalty_msat(scid, &$src_node_id, &$dest_node_id, + channel_usage, score_params)); + let path_penalty_msat = $next_hops_path_penalty_msat + .saturating_add(channel_penalty_msat); + let new_graph_node = RouteGraphNode { + node_id: $src_node_id, + lowest_fee_to_node: total_fee_msat, + total_cltv_delta: hop_total_cltv_delta, + value_contribution_msat, + path_htlc_minimum_msat, + path_penalty_msat, + path_length_to_node, + }; + + // Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id), + // if this way is cheaper than the already known + // (considering the cost to "reach" this channel from the route destination, + // the cost of using this channel, + // and the cost of routing to the source node of this channel). + // Also, consider that htlc_minimum_msat_difference, because we might end up + // paying it. Consider the following exploit: + // we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path, + // and for the other one we picked a 1sat-fee path with htlc_minimum_msat of + // 1 BTC. Now, since the latter is more expensive, we gonna try to cut it + // by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC + // to this channel. + // Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here), + // but it may require additional tracking - we don't want to double-count + // the fees included in $next_hops_path_htlc_minimum_msat, but also + // can't use something that may decrease on future hops. + let old_cost = cmp::max(old_entry.total_fee_msat, old_entry.path_htlc_minimum_msat) + .saturating_add(old_entry.path_penalty_msat); + let new_cost = cmp::max(total_fee_msat, path_htlc_minimum_msat) + .saturating_add(path_penalty_msat); + + if !old_entry.was_processed && new_cost < old_cost { + targets.push(new_graph_node); + old_entry.next_hops_fee_msat = $next_hops_fee_msat; + old_entry.hop_use_fee_msat = hop_use_fee_msat; + old_entry.total_fee_msat = total_fee_msat; + old_entry.node_id = $dest_node_id.clone(); + old_entry.candidate = $candidate.clone(); + old_entry.fee_msat = 0; // This value will be later filled with hop_use_fee_msat of the following channel + old_entry.path_htlc_minimum_msat = path_htlc_minimum_msat; + old_entry.path_penalty_msat = path_penalty_msat; + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] + { + old_entry.value_contribution_msat = value_contribution_msat; + } + did_add_update_path_to_src_node = Some(value_contribution_msat); + } else if old_entry.was_processed && new_cost < old_cost { + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] + { + // If we're skipping processing a node which was previously + // processed even though we found another path to it with a + // cheaper fee, check that it was because the second path we + // found (which we are processing now) has a lower value + // contribution due to an HTLC minimum limit. + // + // e.g. take a graph with two paths from node 1 to node 2, one + // through channel A, and one through channel B. Channel A and + // B are both in the to-process heap, with their scores set by + // a higher htlc_minimum than fee. + // Channel A is processed first, and the channels onwards from + // node 1 are added to the to-process heap. Thereafter, we pop + // Channel B off of the heap, note that it has a much more + // restrictive htlc_maximum_msat, and recalculate the fees for + // all of node 1's channels using the new, reduced, amount. + // + // This would be bogus - we'd be selecting a higher-fee path + // with a lower htlc_maximum_msat instead of the one we'd + // already decided to use. + debug_assert!(path_htlc_minimum_msat < old_entry.path_htlc_minimum_msat); + debug_assert!( + value_contribution_msat + path_penalty_msat < + old_entry.value_contribution_msat + old_entry.path_penalty_msat + ); + } } } } @@ -2360,9 +2417,9 @@ where L::Target: Logger { } let num_ignored_total = num_ignored_value_contribution + num_ignored_path_length_limit + - num_ignored_cltv_delta_limit + num_ignored_previously_failed; + num_ignored_cltv_delta_limit + num_ignored_previously_failed + num_ignored_total_fee_limit; if num_ignored_total > 0 { - log_trace!(logger, "Ignored {} candidate hops due to insufficient value contribution, {} due to path length limit, {} due to CLTV delta limit, {} due to previous payment failure. Total: {} ignored candidates.", num_ignored_value_contribution, num_ignored_path_length_limit, num_ignored_cltv_delta_limit, num_ignored_previously_failed, num_ignored_total); + log_trace!(logger, "Ignored {} candidate hops due to insufficient value contribution, {} due to path length limit, {} due to CLTV delta limit, {} due to previous payment failure, {} due to maximum total fee limit. Total: {} ignored candidates.", num_ignored_value_contribution, num_ignored_path_length_limit, num_ignored_cltv_delta_limit, num_ignored_previously_failed, num_ignored_total_fee_limit, num_ignored_total); } // Step (5). @@ -2448,9 +2505,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(), @@ -2458,7 +2533,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, _)| { @@ -2483,13 +2561,21 @@ where L::Target: Logger { // Make sure we would never create a route with more paths than we allow. debug_assert!(paths.len() <= payment_params.max_path_count.into()); + // Make sure we would never create a route whose total fees exceed max_total_routing_fee_msat. + if let Some(max_total_routing_fee_msat) = route_params.max_total_routing_fee_msat { + if paths.iter().map(|p| p.fee_msat()).sum::() > max_total_routing_fee_msat { + return Err(LightningError{err: format!("Failed to find route that adheres to the maximum total fee limit of {}msat", + max_total_routing_fee_msat), action: ErrorAction::IgnoreError}); + } + } + if let Some(node_features) = payment_params.payee.node_features() { for path in paths.iter_mut() { path.hops.last_mut().unwrap().node_features = node_features.clone(); } } - let route = Route { paths, payment_params: Some(payment_params.clone()) }; + let route = Route { paths, route_params: Some(route_params.clone()) }; log_info!(logger, "Got route: {}", log_route!(route)); Ok(route) } @@ -5183,9 +5269,21 @@ mod tests { } else { panic!(); } } + { + // Attempt to route while setting max_total_routing_fee_msat to 149_999 results in a failure. + let route_params = RouteParameters { payment_params: payment_params.clone(), final_value_msat: 200_000, + max_total_routing_fee_msat: Some(149_999) }; + if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route( + &our_id, &route_params, &network_graph.read_only(), None, Arc::clone(&logger), + &scorer, &(), &random_seed_bytes) { + assert_eq!(err, "Failed to find a sufficient route to the given destination"); + } else { panic!(); } + } + { // Now, attempt to route 200 sats (exact amount we can route). - let route_params = RouteParameters::from_payment_params_and_value(payment_params, 200_000); + let route_params = RouteParameters { payment_params: payment_params.clone(), final_value_msat: 200_000, + max_total_routing_fee_msat: Some(150_000) }; let route = get_route(&our_id, &route_params, &network_graph.read_only(), None, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap(); assert_eq!(route.paths.len(), 2); @@ -5940,20 +6038,20 @@ 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 }], - payment_params: None, + route_params: None, }; assert_eq!(route.get_total_fees(), 250); @@ -5967,26 +6065,26 @@ 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 }], - payment_params: None, + route_params: None, }; assert_eq!(route.get_total_fees(), 200); @@ -5998,7 +6096,7 @@ mod tests { // In an earlier version of `Route::get_total_fees` and `Route::get_total_amount`, they // would both panic if the route was completely empty. We test to ensure they return 0 // here, even though its somewhat nonsensical as a route. - let route = Route { paths: Vec::new(), payment_params: None }; + let route = Route { paths: Vec::new(), route_params: None }; assert_eq!(route.get_total_fees(), 0); assert_eq!(route.get_total_amount(), 0); @@ -6582,6 +6680,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, @@ -6596,8 +6695,9 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 100, cltv_expiry_delta: 0, + maybe_announced_channel: true, }], blinded_tail: None }], - payment_params: None, + route_params: None, }; let encoded_route = route.encode(); let decoded_route: Route = Readable::read(&mut Cursor::new(&encoded_route[..])).unwrap(); @@ -6635,6 +6735,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, @@ -6643,6 +6744,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, @@ -6675,6 +6777,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, @@ -6683,6 +6786,7 @@ mod tests { channel_features: ChannelFeatures::empty(), fee_msat: 1, cltv_expiry_delta: 0, + maybe_announced_channel: false, } ], blinded_tail: Some(BlindedTail { @@ -6691,7 +6795,7 @@ mod tests { excess_final_cltv_expiry_delta: 0, final_value_msat: 200, }), - }], payment_params: None}; + }], route_params: None}; let payment_params = PaymentParameters::from_node_id(ln_test_utils::pubkey(47), 18); let (_, network_graph, _, _, _) = build_line_graph();