Provide payment retry data when an MPP payment failed partially
[rust-lightning] / lightning / src / routing / router.rs
index 099661bb7f7347429534cfd86903950a2df10550..c035b4547cc78f2e8448fe45747154304e060404 100644 (file)
@@ -70,19 +70,34 @@ pub struct Route {
        /// given path is variable, keeping the length of any path to less than 20 should currently
        /// ensure it is viable.
        pub paths: Vec<Vec<RouteHop>>,
+       /// The `payee` parameter passed to [`find_route`].
+       /// This is used by `ChannelManager` to track information which may be required for retries,
+       /// provided back to you via [`Event::PaymentPathFailed`].
+       ///
+       /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
+       pub payee: Option<Payee>,
+}
+
+pub(crate) trait RoutePath {
+       /// Gets the fees for a given path, excluding any excess paid to the recipient.
+       fn get_path_fees(&self) -> u64;
+}
+impl RoutePath for Vec<RouteHop> {
+       fn get_path_fees(&self) -> u64 {
+               // Do not count last hop of each path since that's the full value of the payment
+               self.split_last().map(|(_, path_prefix)| path_prefix).unwrap_or(&[])
+                       .iter().map(|hop| &hop.fee_msat)
+                       .sum()
+       }
 }
 
 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 [`get_route`]'s `final_value_msat`.
+       /// the amount passed to [`find_route`]'s `params.final_value_msat`.
        pub fn get_total_fees(&self) -> u64 {
-               // Do not count last hop of each path since that's the full value of the payment
-               return self.paths.iter()
-                       .flat_map(|path| path.split_last().map(|(_, path_prefix)| path_prefix).unwrap_or(&[]))
-                       .map(|hop| &hop.fee_msat)
-                       .sum();
+               self.paths.iter().map(|path| path.get_path_fees()).sum()
        }
 
        /// Returns the total amount paid on this [`Route`], excluding the fees.
@@ -106,7 +121,9 @@ impl Writeable for Route {
                                hop.write(writer)?;
                        }
                }
-               write_tlv_fields!(writer, {});
+               write_tlv_fields!(writer, {
+                       (1, self.payee, option),
+               });
                Ok(())
        }
 }
@@ -124,18 +141,22 @@ impl Readable for Route {
                        }
                        paths.push(hops);
                }
-               read_tlv_fields!(reader, {});
-               Ok(Route { paths })
+               let mut payee = None;
+               read_tlv_fields!(reader, {
+                       (1, payee, option),
+               });
+               Ok(Route { paths, payee })
        }
 }
 
-/// Parameters needed to re-compute a [`Route`] for retrying a failed payment path.
+/// Parameters needed to find a [`Route`] for paying a [`Payee`].
 ///
-/// Provided in [`Event::PaymentPathFailed`] and passed to [`get_retry_route`].
+/// Passed to [`find_route`] and also provided in [`Event::PaymentPathFailed`] for retrying a failed
+/// payment path.
 ///
 /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 #[derive(Clone, Debug)]
-pub struct PaymentPathRetry {
+pub struct RouteParameters {
        /// The recipient of the failed payment path.
        pub payee: Payee,
 
@@ -146,14 +167,14 @@ pub struct PaymentPathRetry {
        pub final_cltv_expiry_delta: u32,
 }
 
-impl_writeable_tlv_based!(PaymentPathRetry, {
+impl_writeable_tlv_based!(RouteParameters, {
        (0, payee, required),
        (2, final_value_msat, required),
        (4, final_cltv_expiry_delta, required),
 });
 
 /// The recipient of a payment.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct Payee {
        /// The node id of the payee.
        pub pubkey: PublicKey,
@@ -168,12 +189,16 @@ pub struct Payee {
 
        /// Hints for routing to the payee, containing channels connecting the payee to public nodes.
        pub route_hints: Vec<RouteHint>,
+
+       /// Expiration of a payment to the payee, in seconds relative to the UNIX epoch.
+       pub expiry_time: Option<u64>,
 }
 
 impl_writeable_tlv_based!(Payee, {
        (0, pubkey, required),
        (2, features, option),
        (4, route_hints, vec_type),
+       (6, expiry_time, option),
 });
 
 impl Payee {
@@ -183,6 +208,7 @@ impl Payee {
                        pubkey,
                        features: None,
                        route_hints: vec![],
+                       expiry_time: None,
                }
        }
 
@@ -204,6 +230,11 @@ impl Payee {
        pub fn with_route_hints(self, route_hints: Vec<RouteHint>) -> Self {
                Self { route_hints, ..self }
        }
+
+       /// Includes a payment expiration in seconds relative to the UNIX epoch.
+       pub fn with_expiry_time(self, expiry_time: u64) -> Self {
+               Self { expiry_time: Some(expiry_time), ..self }
+       }
 }
 
 /// A list of hops along a payment path terminating with a channel to the recipient.
@@ -468,59 +499,46 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
        }
 }
 
-/// Gets a keysend route from us (payer) to the given target node (payee). This is needed because
-/// keysend payments do not have an invoice from which to pull the payee's supported features, which
-/// makes it tricky to otherwise supply the `payee` parameter of `get_route`.
-pub fn get_keysend_route<L: Deref, S: routing::Score>(
-       our_node_pubkey: &PublicKey, network: &NetworkGraph, payee: &PublicKey,
-       first_hops: Option<&[&ChannelDetails]>, last_hops: &[&RouteHint], final_value_msat: u64,
-       final_cltv_expiry_delta: u32, logger: L, scorer: &S
-) -> Result<Route, LightningError>
-where L::Target: Logger {
-       let route_hints = last_hops.iter().map(|hint| (*hint).clone()).collect();
-       let payee = Payee::for_keysend(*payee).with_route_hints(route_hints);
-       get_route(
-               our_node_pubkey, &payee, network, first_hops, final_value_msat, final_cltv_expiry_delta,
-               logger, scorer
-       )
-}
-
-/// Gets a route suitable for retrying a failed payment path.
+/// Finds a route from us (payer) to the given target node (payee).
+///
+/// If the payee provided features in their invoice, they should be provided via `params.payee`.
+/// Without this, MPP will only be used if the payee's features are available in the network graph.
+///
+/// Private routing paths between a public node and the target may be included in `params.payee`.
+///
+/// If some channels aren't announced, it may be useful to fill in `first_hops` with the results
+/// from [`ChannelManager::list_usable_channels`]. If it is filled in, the view of our local
+/// channels from [`NetworkGraph`] will be ignored, and only those in `first_hops` will be used.
+///
+/// The fees on channels from us to the next hop are ignored as they are assumed to all be equal.
+/// However, the enabled/disabled bit on such channels as well as the `htlc_minimum_msat` /
+/// `htlc_maximum_msat` *are* checked as they may change based on the receiving node.
+///
+/// # Note
+///
+/// May be used to re-compute a [`Route`] when handling a [`Event::PaymentPathFailed`]. Any
+/// adjustments to the [`NetworkGraph`] and channel scores should be made prior to calling this
+/// function.
 ///
-/// Used to re-compute a [`Route`] when handling a [`Event::PaymentPathFailed`]. Any adjustments to
-/// the [`NetworkGraph`] and channel scores should be made prior to calling this function.
+/// # Panics
 ///
+/// Panics if first_hops contains channels without short_channel_ids;
+/// [`ChannelManager::list_usable_channels`] will never include such channels.
+///
+/// [`ChannelManager::list_usable_channels`]: crate::ln::channelmanager::ChannelManager::list_usable_channels
 /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
-pub fn get_retry_route<L: Deref, S: routing::Score>(
-       our_node_pubkey: &PublicKey, retry: &PaymentPathRetry, network: &NetworkGraph,
+pub fn find_route<L: Deref, S: routing::Score>(
+       our_node_pubkey: &PublicKey, params: &RouteParameters, network: &NetworkGraph,
        first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
        get_route(
-               our_node_pubkey, &retry.payee, network, first_hops, retry.final_value_msat,
-               retry.final_cltv_expiry_delta, logger, scorer
+               our_node_pubkey, &params.payee, network, first_hops, params.final_value_msat,
+               params.final_cltv_expiry_delta, logger, scorer
        )
 }
 
-/// Gets a route from us (payer) to the given target node (payee).
-///
-/// If the payee provided features in their invoice, they should be provided via `payee`.  Without
-/// this, MPP will only be used if the payee's features are available in the network graph.
-///
-/// Private routing paths between a public node and the target may be included in `payee`.
-///
-/// If some channels aren't announced, it may be useful to fill in a first_hops with the
-/// results from a local ChannelManager::list_usable_channels() call. If it is filled in, our
-/// view of our local channels (from net_graph_msg_handler) will be ignored, and only those
-/// in first_hops will be used.
-///
-/// Panics if first_hops contains channels without short_channel_ids
-/// (ChannelManager::list_usable_channels will never include such channels).
-///
-/// The fees on channels from us to next-hops are ignored (as they are assumed to all be
-/// equal), however the enabled/disabled bit on such channels as well as the
-/// htlc_minimum_msat/htlc_maximum_msat *are* checked as they may change based on the receiving node.
-pub fn get_route<L: Deref, S: routing::Score>(
+pub(crate) fn get_route<L: Deref, S: routing::Score>(
        our_node_pubkey: &PublicKey, payee: &Payee, network: &NetworkGraph,
        first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
        logger: L, scorer: &S
@@ -1442,7 +1460,10 @@ where L::Target: Logger {
                }
        }
 
-       let route = Route { paths: selected_paths.into_iter().map(|path| path.into_iter().collect()).collect::<Result<Vec<_>, _>>()? };
+       let route = Route {
+               paths: selected_paths.into_iter().map(|path| path.into_iter().collect()).collect::<Result<Vec<_>, _>>()?,
+               payee: Some(payee.clone()),
+       };
        log_info!(logger, "Got route to {}: {}", payee.pubkey, log_route!(route));
        Ok(route)
 }
@@ -1916,7 +1937,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Simple route to 2 via 1
 
@@ -1947,7 +1968,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Simple route to 2 via 1
 
@@ -1966,7 +1987,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Simple route to 2 via 1
 
@@ -2091,7 +2112,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]).with_features(InvoiceFeatures::known());
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // A route to node#2 via two paths.
                // One path allows transferring 35-40 sats, another one also allows 35-40 sats.
@@ -2227,7 +2248,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // // Disable channels 4 and 12 by flags=2
                update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
@@ -2285,7 +2306,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[2]);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Disable nodes 1, 2, and 8 by requiring unknown feature bits
                let unknown_features = NodeFeatures::known().set_unknown_feature_required();
@@ -2326,7 +2347,7 @@ mod tests {
        fn our_chans_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Route to 1 via 2 and 3 because our channel to 1 is disabled
                let payee = Payee::new(nodes[0]);
@@ -2455,7 +2476,7 @@ mod tests {
        fn partial_route_hint_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Simple test across 2, 3, 5, and 4 via a last_hop channel
                // Tests the behaviour when the RouteHint contains a suboptimal hop.
@@ -2554,7 +2575,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[6]).with_route_hints(empty_last_hop(&nodes));
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Test handling of an empty RouteHint passed in Invoice.
 
@@ -2636,7 +2657,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[6]).with_route_hints(multi_hint_last_hops(&nodes));
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                // Test through channels 2, 3, 5, 8.
                // Test shows that multiple hop hints are considered.
 
@@ -2742,7 +2763,7 @@ mod tests {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payee = Payee::new(nodes[6]).with_route_hints(last_hops_with_public_channel(&nodes));
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                // This test shows that public routes can be present in the invoice
                // which would be handled in the same manner.
 
@@ -2791,7 +2812,7 @@ mod tests {
        fn our_chans_last_hop_connect_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // Simple test with outbound channel to 4 to test that last_hops and first_hops connect
                let our_chans = vec![get_channel_details(Some(42), nodes[3].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
@@ -2912,7 +2933,7 @@ mod tests {
                }]);
                let payee = Payee::new(target_node_id).with_route_hints(vec![last_hops]);
                let our_chans = vec![get_channel_details(Some(42), middle_node_id, InitFeatures::from_le_bytes(vec![0b11]), outbound_capacity_msat)];
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                get_route(&source_node_id, &payee, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &test_utils::TestLogger::new(), &scorer)
        }
 
@@ -2966,7 +2987,7 @@ mod tests {
 
                let (secp_ctx, mut net_graph_msg_handler, chain_monitor, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We will use a simple single-path route from
@@ -3238,7 +3259,7 @@ mod tests {
                // one of the latter hops is limited.
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[3]).with_features(InvoiceFeatures::known());
 
                // Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
@@ -3361,7 +3382,7 @@ mod tests {
        fn ignore_fee_first_hop_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]);
 
                // Path via node0 is channels {1, 3}. Limit them to 100 and 50 sats (total limit 50).
@@ -3407,7 +3428,7 @@ mod tests {
        fn simple_mpp_route_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -3538,7 +3559,7 @@ mod tests {
        fn long_mpp_route_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -3700,7 +3721,7 @@ mod tests {
        fn mpp_cheaper_route_test() {
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[3]).with_features(InvoiceFeatures::known());
 
                // This test checks that if we have two cheaper paths and one more expensive path,
@@ -3867,7 +3888,7 @@ mod tests {
                // if the fee is not properly accounted for, the behavior is different.
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 2 paths:
@@ -4036,7 +4057,7 @@ mod tests {
                // path finding we realize that we found more capacity than we need.
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -4193,7 +4214,7 @@ mod tests {
                let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
                let net_graph_msg_handler = NetGraphMsgHandler::new(network_graph, None, Arc::clone(&logger));
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[6]);
 
                add_channel(&net_graph_msg_handler, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
@@ -4322,7 +4343,7 @@ mod tests {
                // we calculated fees on a higher value, resulting in us ignoring such paths.
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]);
 
                // We modify the graph to set the htlc_maximum of channel 2 to below the value we wish to
@@ -4384,7 +4405,7 @@ mod tests {
                // resulting in us thinking there is no possible path, even if other paths exist.
                let (secp_ctx, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We modify the graph to set the htlc_minimum of channel 2 and 4 as needed - channel 2
@@ -4451,7 +4472,7 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let logger = Arc::new(test_utils::TestLogger::new());
                let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let payee = Payee::new(nodes[0]).with_features(InvoiceFeatures::known());
 
                {
@@ -4492,7 +4513,7 @@ mod tests {
                let payee = Payee::new(nodes[6]).with_route_hints(last_hops(&nodes));
 
                // Without penalizing each hop 100 msats, a longer path with lower fees is chosen.
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let route = get_route(
                        &our_id, &payee, &net_graph_msg_handler.network_graph, None, 100, 42,
                        Arc::clone(&logger), &scorer
@@ -4505,7 +4526,7 @@ mod tests {
 
                // Applying a 100 msat penalty to each hop results in taking channels 7 and 10 to nodes[6]
                // from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper.
-               let scorer = Scorer::new(100);
+               let scorer = Scorer::with_fixed_penalty(100);
                let route = get_route(
                        &our_id, &payee, &net_graph_msg_handler.network_graph, None, 100, 42,
                        Arc::clone(&logger), &scorer
@@ -4525,6 +4546,8 @@ mod tests {
                fn channel_penalty_msat(&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId) -> u64 {
                        if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
                }
+
+               fn payment_path_failed(&mut self, _path: &Vec<RouteHop>, _short_channel_id: u64) {}
        }
 
        struct BadNodeScorer {
@@ -4535,6 +4558,8 @@ mod tests {
                fn channel_penalty_msat(&self, _short_channel_id: u64, _source: &NodeId, target: &NodeId) -> u64 {
                        if *target == self.node_id { u64::max_value() } else { 0 }
                }
+
+               fn payment_path_failed(&mut self, _path: &Vec<RouteHop>, _short_channel_id: u64) {}
        }
 
        #[test]
@@ -4544,7 +4569,7 @@ mod tests {
                let payee = Payee::new(nodes[6]).with_route_hints(last_hops(&nodes));
 
                // A path to nodes[6] exists when no penalties are applied to any channel.
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
                let route = get_route(
                        &our_id, &payee, &net_graph_msg_handler.network_graph, None, 100, 42,
                        Arc::clone(&logger), &scorer
@@ -4600,6 +4625,7 @@ mod tests {
                                        short_channel_id: 0, fee_msat: 225, cltv_expiry_delta: 0
                                },
                        ]],
+                       payee: None,
                };
 
                assert_eq!(route.get_total_fees(), 250);
@@ -4632,6 +4658,7 @@ mod tests {
                                        short_channel_id: 0, fee_msat: 150, cltv_expiry_delta: 0
                                },
                        ]],
+                       payee: None,
                };
 
                assert_eq!(route.get_total_fees(), 200);
@@ -4643,7 +4670,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() };
+               let route = Route { paths: Vec::new(), payee: None };
 
                assert_eq!(route.get_total_fees(), 0);
                assert_eq!(route.get_total_amount(), 0);
@@ -4671,7 +4698,7 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4702,7 +4729,7 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4768,7 +4795,7 @@ mod benches {
                let mut d = test_utils::get_route_file().unwrap();
                let graph = NetworkGraph::read(&mut d).unwrap();
                let nodes = graph.read_only().nodes().clone();
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut path_endpoints = Vec::new();
@@ -4803,7 +4830,7 @@ mod benches {
                let mut d = test_utils::get_route_file().unwrap();
                let graph = NetworkGraph::read(&mut d).unwrap();
                let nodes = graph.read_only().nodes().clone();
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut path_endpoints = Vec::new();