Add outbound min/max to `ChannelCounterparty`
[rust-lightning] / lightning / src / routing / router.rs
index 65119f0f843a5266f248ed53f1a9cdd05653a99e..212ac2f10cae7d62695f032c6fd8ab0a4e523ffa 100644 (file)
@@ -18,9 +18,10 @@ use ln::channelmanager::ChannelDetails;
 use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
 use routing::scoring::Score;
-use routing::network_graph::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, NodeId, RoutingFees};
+use routing::network_graph::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, ReadOnlyNetworkGraph, NodeId, RoutingFees};
 use util::ser::{Writeable, Readable};
 use util::logger::{Level, Logger};
+use util::chacha20::ChaCha20;
 
 use io;
 use prelude::*;
@@ -176,6 +177,9 @@ impl_writeable_tlv_based!(RouteParameters, {
 /// Maximum total CTLV difference we allow for a full payment path.
 pub const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008;
 
+/// The median hop CLTV expiry delta currently seen in the network.
+const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40;
+
 /// The recipient of a payment.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct PaymentParameters {
@@ -258,7 +262,6 @@ impl PaymentParameters {
 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
 pub struct RouteHint(pub Vec<RouteHintHop>);
 
-
 impl Writeable for RouteHint {
        fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
                (self.0.len() as u64).write(writer)?;
@@ -329,11 +332,9 @@ struct RouteGraphNode {
 impl cmp::Ord for RouteGraphNode {
        fn cmp(&self, other: &RouteGraphNode) -> cmp::Ordering {
                let other_score = cmp::max(other.lowest_fee_to_peer_through_node, other.path_htlc_minimum_msat)
-                       .checked_add(other.path_penalty_msat)
-                       .unwrap_or_else(|| u64::max_value());
+                       .saturating_add(other.path_penalty_msat);
                let self_score = cmp::max(self.lowest_fee_to_peer_through_node, self.path_htlc_minimum_msat)
-                       .checked_add(self.path_penalty_msat)
-                       .unwrap_or_else(|| u64::max_value());
+                       .saturating_add(self.path_penalty_msat);
                other_score.cmp(&self_score).then_with(|| other.node_id.cmp(&self.node_id))
        }
 }
@@ -423,7 +424,7 @@ impl<'a> CandidateRouteHop<'a> {
 /// so that we can choose cheaper paths (as per Dijkstra's algorithm).
 /// Fee values should be updated only in the context of the whole path, see update_value_and_recompute_fees.
 /// These fee values are useful to choose hops as we traverse the graph "payee-to-payer".
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 struct PathBuildingHop<'a> {
        // Note that this should be dropped in favor of loading it from CandidateRouteHop, but doing so
        // is a larger refactor and will require careful performance analysis.
@@ -463,6 +464,22 @@ struct PathBuildingHop<'a> {
        value_contribution_msat: u64,
 }
 
+impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
+       fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
+               f.debug_struct("PathBuildingHop")
+                       .field("node_id", &self.node_id)
+                       .field("short_channel_id", &self.candidate.short_channel_id())
+                       .field("total_fee_msat", &self.total_fee_msat)
+                       .field("next_hops_fee_msat", &self.next_hops_fee_msat)
+                       .field("hop_use_fee_msat", &self.hop_use_fee_msat)
+                       .field("total_fee_msat - (next_hops_fee_msat + hop_use_fee_msat)", &(&self.total_fee_msat - (&self.next_hops_fee_msat + &self.hop_use_fee_msat)))
+                       .field("path_penalty_msat", &self.path_penalty_msat)
+                       .field("path_htlc_minimum_msat", &self.path_htlc_minimum_msat)
+                       .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta())
+                       .finish()
+       }
+}
+
 // Instantiated with a list of hops with correct data in them collected during path finding,
 // an instance of this struct should be further modified only via given methods.
 #[derive(Clone)]
@@ -476,6 +493,10 @@ impl<'a> PaymentPath<'a> {
                self.hops.last().unwrap().0.fee_msat
        }
 
+       fn get_path_penalty_msat(&self) -> u64 {
+               self.hops.first().map(|h| h.0.path_penalty_msat).unwrap_or(u64::max_value())
+       }
+
        fn get_total_fee_paid_msat(&self) -> u64 {
                if self.hops.len() < 1 {
                        return 0;
@@ -490,6 +511,10 @@ impl<'a> PaymentPath<'a> {
                return result;
        }
 
+       fn get_cost_msat(&self) -> u64 {
+               self.get_total_fee_paid_msat().saturating_add(self.get_path_penalty_msat())
+       }
+
        // If the amount transferred by the path is updated, the fees should be adjusted. Any other way
        // to change fees may result in an inconsistency.
        //
@@ -577,6 +602,17 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
        }
 }
 
+/// The default `features` we assume for a node in a route, when no `features` are known about that
+/// specific node.
+///
+/// Default features are:
+/// * variable_length_onion_optional
+fn default_node_features() -> NodeFeatures {
+       let mut features = NodeFeatures::empty();
+       features.set_variable_length_onion_optional();
+       features
+}
+
 /// 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`.
@@ -607,19 +643,26 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
 /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 pub fn find_route<L: Deref, S: Score>(
        our_node_pubkey: &PublicKey, route_params: &RouteParameters, network: &NetworkGraph,
-       first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S
+       first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
-       get_route(
-               our_node_pubkey, &route_params.payment_params, network, first_hops, route_params.final_value_msat,
-               route_params.final_cltv_expiry_delta, logger, scorer
-       )
+       let network_graph = network.read_only();
+       match get_route(
+               our_node_pubkey, &route_params.payment_params, &network_graph, first_hops, route_params.final_value_msat,
+               route_params.final_cltv_expiry_delta, logger, scorer, random_seed_bytes
+       ) {
+               Ok(mut route) => {
+                       add_random_cltv_offset(&mut route, &route_params.payment_params, &network_graph, random_seed_bytes);
+                       Ok(route)
+               },
+               Err(err) => Err(err),
+       }
 }
 
 pub(crate) fn get_route<L: Deref, S: Score>(
-       our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network: &NetworkGraph,
-       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32, 
-       logger: L, scorer: &S
+       our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph,
+       first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
+       logger: L, scorer: &S, random_seed_bytes: &[u8; 32]
 ) -> Result<Route, LightningError>
 where L::Target: Logger {
        let payee_node_id = NodeId::from_pubkey(&payment_params.payee_pubkey);
@@ -644,6 +687,9 @@ where L::Target: Logger {
                        }
                }
        }
+       if payment_params.max_total_cltv_expiry_delta <= final_cltv_expiry_delta {
+               return Err(LightningError{err: "Can't find a route where the maximum total CLTV expiry delta is below the final CLTV expiry.".to_owned(), action: ErrorAction::IgnoreError});
+       }
 
        // The general routing idea is the following:
        // 1. Fill first/last hops communicated by the caller.
@@ -656,12 +702,13 @@ where L::Target: Logger {
        //    - OR if we could not construct a new path. Any next attempt will fail too.
        //    Otherwise, repeat step 2.
        // 4. See if we managed to collect paths which aggregately are able to transfer target value
-       //    (not recommended value). If yes, proceed. If not, fail routing.
-       // 5. Randomly combine paths into routes having enough to fulfill the payment. (TODO: knapsack)
-       // 6. Of all the found paths, select only those with the lowest total fee.
-       // 7. The last path in every selected route is likely to be more than we need.
+       //    (not recommended value).
+       // 5. If yes, proceed. If not, fail routing.
+       // 6. Randomly combine paths into routes having enough to fulfill the payment. (TODO: knapsack)
+       // 7. Of all the found paths, select only those with the lowest total fee.
+       // 8. The last path in every selected route is likely to be more than we need.
        //    Reduce its value-to-transfer and recompute fees.
-       // 8. Choose the best route by the lowest total fee.
+       // 9. Choose the best route by the lowest total fee.
 
        // As for the actual search algorithm,
        // we do a payee-to-payer pseudo-Dijkstra's sorting by each node's distance from the payee
@@ -705,7 +752,6 @@ where L::Target: Logger {
        // to use as the A* heuristic beyond just the cost to get one node further than the current
        // one.
 
-       let network_graph = network.read_only();
        let network_channels = network_graph.channels();
        let network_nodes = network_graph.nodes();
 
@@ -719,8 +765,9 @@ where L::Target: Logger {
                        node_info.features.supports_basic_mpp()
                } else { false }
        } else { false };
-       log_trace!(logger, "Searching for a route from payer {} to payee {} {} MPP", our_node_pubkey,
-               payment_params.payee_pubkey, if allow_mpp { "with" } else { "without" });
+       log_trace!(logger, "Searching for a route from payer {} to payee {} {} MPP and {} first hops {}overriding the network graph", our_node_pubkey,
+               payment_params.payee_pubkey, if allow_mpp { "with" } else { "without" },
+               first_hops.map(|hops| hops.len()).unwrap_or(0), if first_hops.is_some() { "" } else { "not " });
 
        // Step (1).
        // Prepare the data we'll use for payee-to-payer search by
@@ -781,6 +828,29 @@ where L::Target: Logger {
        // - when we want to stop looking for new paths.
        let mut already_collected_value_msat = 0;
 
+       for (_, channels) in first_hop_targets.iter_mut() {
+               // Sort the first_hops channels to the same node(s) in priority order of which channel we'd
+               // most like to use.
+               //
+               // First, if channels are below `recommended_value_msat`, sort them in descending order,
+               // preferring larger channels to avoid splitting the payment into more MPP parts than is
+               // required.
+               //
+               // Second, because simply always sorting in descending order would always use our largest
+               // available outbound capacity, needlessly fragmenting our available channel capacities,
+               // sort channels above `recommended_value_msat` in ascending order, preferring channels
+               // which have enough, but not too much, capacity for the payment.
+               channels.sort_unstable_by(|chan_a, chan_b| {
+                       if chan_b.outbound_capacity_msat < recommended_value_msat || chan_a.outbound_capacity_msat < recommended_value_msat {
+                               // Sort in descending order
+                               chan_b.outbound_capacity_msat.cmp(&chan_a.outbound_capacity_msat)
+                       } else {
+                               // Sort in ascending order
+                               chan_a.outbound_capacity_msat.cmp(&chan_b.outbound_capacity_msat)
+                       }
+               });
+       }
+
        log_trace!(logger, "Building path from {} (payee) to {} (us/payer) for value {} msat.", payment_params.payee_pubkey, our_node_pubkey, final_value_msat);
 
        macro_rules! add_entry {
@@ -803,7 +873,7 @@ where L::Target: Logger {
                                        .entry(short_channel_id)
                                        .or_insert_with(|| $candidate.effective_capacity().as_msat());
 
-                               // It is tricky to substract $next_hops_fee_msat from available liquidity here.
+                               // It is tricky to subtract $next_hops_fee_msat from available liquidity here.
                                // It may be misleading because we might later choose to reduce the value transferred
                                // over these channels, and the channel which was insufficient might become sufficient.
                                // Worst case: we drop a good channel here because it can't cover the high following
@@ -836,10 +906,14 @@ where L::Target: Logger {
                                        let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
 
                                        // Do not consider candidates that exceed the maximum total cltv expiry limit.
-                                       let max_total_cltv_expiry_delta = payment_params.max_total_cltv_expiry_delta;
+                                       // In order to already account for some of the privacy enhancing random CLTV
+                                       // expiry delta offset we add on top later, we subtract a rough estimate
+                                       // (2*MEDIAN_HOP_CLTV_EXPIRY_DELTA) here.
+                                       let max_total_cltv_expiry_delta = (payment_params.max_total_cltv_expiry_delta - final_cltv_expiry_delta)
+                                               .checked_sub(2*MEDIAN_HOP_CLTV_EXPIRY_DELTA)
+                                               .unwrap_or(payment_params.max_total_cltv_expiry_delta - final_cltv_expiry_delta);
                                        let hop_total_cltv_delta = ($next_hops_cltv_delta as u32)
-                                               .checked_add($candidate.cltv_expiry_delta())
-                                               .unwrap_or(u32::max_value());
+                                               .saturating_add($candidate.cltv_expiry_delta());
                                        let doesnt_exceed_cltv_delta_limit = hop_total_cltv_delta <= max_total_cltv_expiry_delta;
 
                                        let value_contribution_msat = cmp::min(available_value_contribution_msat, $next_hops_value_contribution);
@@ -853,14 +927,20 @@ where L::Target: Logger {
                                        let over_path_minimum_msat = amount_to_transfer_over_msat >= $candidate.htlc_minimum_msat() &&
                                                amount_to_transfer_over_msat >= $next_hops_path_htlc_minimum_msat;
 
+                                       #[allow(unused_comparisons)] // $next_hops_path_htlc_minimum_msat is 0 in some calls so rustc complains
+                                       let may_overpay_to_meet_path_minimum_msat =
+                                               ((amount_to_transfer_over_msat < $candidate.htlc_minimum_msat() &&
+                                                 recommended_value_msat > $candidate.htlc_minimum_msat()) ||
+                                                (amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
+                                                 recommended_value_msat > $next_hops_path_htlc_minimum_msat));
+
                                        // If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
-                                       // bother considering this channel.
-                                       // Since we're choosing amount_to_transfer_over_msat as maximum possible, it can
-                                       // be only reduced later (not increased), so this channel should just be skipped
-                                       // as not sufficient.
-                                       if !over_path_minimum_msat && doesnt_exceed_cltv_delta_limit {
+                                       // bother considering this channel. If retrying with recommended_value_msat may
+                                       // allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go
+                                       // around again with a higher amount.
+                                       if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit && may_overpay_to_meet_path_minimum_msat {
                                                hit_minimum_limit = true;
-                                       } else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit {
+                                       } else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit && over_path_minimum_msat {
                                                // Note that low contribution here (limited by available_liquidity_msat)
                                                // might violate htlc_minimum_msat on the hops which are next along the
                                                // payment path (upstream to the payee). To avoid that, we recompute
@@ -876,8 +956,8 @@ where L::Target: Logger {
                                                        // semi-dummy record just to compute the fees to reach the source node.
                                                        // This will affect our decision on selecting short_channel_id
                                                        // as a way to reach the $dest_node_id.
-                                                       let mut fee_base_msat = u32::max_value();
-                                                       let mut fee_proportional_millionths = u32::max_value();
+                                                       let mut fee_base_msat = 0;
+                                                       let mut fee_proportional_millionths = 0;
                                                        if let Some(Some(fees)) = network_nodes.get(&$src_node_id).map(|node| node.lowest_inbound_channel_fees) {
                                                                fee_base_msat = fees.base_msat;
                                                                fee_proportional_millionths = fees.proportional_millionths;
@@ -946,9 +1026,9 @@ where L::Target: Logger {
                                                                }
                                                        }
 
-                                                       let path_penalty_msat = $next_hops_path_penalty_msat.checked_add(
-                                                               scorer.channel_penalty_msat(short_channel_id, amount_to_transfer_over_msat, *available_liquidity_msat,
-                                                                       &$src_node_id, &$dest_node_id)).unwrap_or_else(|| u64::max_value());
+                                                       let path_penalty_msat = $next_hops_path_penalty_msat.saturating_add(
+                                                               scorer.channel_penalty_msat(short_channel_id, amount_to_transfer_over_msat,
+                                                                       *available_liquidity_msat, &$src_node_id, &$dest_node_id));
                                                        let new_graph_node = RouteGraphNode {
                                                                node_id: $src_node_id,
                                                                lowest_fee_to_peer_through_node: total_fee_msat,
@@ -976,11 +1056,9 @@ where L::Target: Logger {
                                                        // 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)
-                                                               .checked_add(old_entry.path_penalty_msat)
-                                                               .unwrap_or_else(|| u64::max_value());
+                                                               .saturating_add(old_entry.path_penalty_msat);
                                                        let new_cost = cmp::max(total_fee_msat, path_htlc_minimum_msat)
-                                                               .checked_add(path_penalty_msat)
-                                                               .unwrap_or_else(|| u64::max_value());
+                                                               .saturating_add(path_penalty_msat);
 
                                                        if !old_entry.was_processed && new_cost < old_cost {
                                                                targets.push(new_graph_node);
@@ -1034,7 +1112,8 @@ where L::Target: Logger {
                } }
        }
 
-       let empty_node_features = NodeFeatures::empty();
+       let default_node_features = default_node_features();
+
        // Find ways (channels with destination) to reach a given node and store them
        // in the corresponding data structures (routing graph etc).
        // $fee_to_target_msat represents how much it costs to reach to this node from the payee,
@@ -1065,7 +1144,7 @@ where L::Target: Logger {
                                let features = if let Some(node_info) = $node.announcement_info.as_ref() {
                                        &node_info.features
                                } else {
-                                       &empty_node_features
+                                       &default_node_features
                                };
 
                                if !features.requires_unknown_bits() {
@@ -1164,12 +1243,10 @@ where L::Target: Logger {
                                                .unwrap_or_else(|| CandidateRouteHop::PrivateHop { hint: hop });
                                        let capacity_msat = candidate.effective_capacity().as_msat();
                                        aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
-                                               .checked_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, capacity_msat, &source, &target))
-                                               .unwrap_or_else(|| u64::max_value());
+                                               .saturating_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, capacity_msat, &source, &target));
 
                                        aggregate_next_hops_cltv_delta = aggregate_next_hops_cltv_delta
-                                               .checked_add(hop.cltv_expiry_delta as u32)
-                                               .unwrap_or_else(|| u32::max_value());
+                                               .saturating_add(hop.cltv_expiry_delta as u32);
 
                                        if !add_entry!(candidate, source, target, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta) {
                                                // If this hop was not used then there is no use checking the preceding hops
@@ -1247,7 +1324,7 @@ where L::Target: Logger {
                        // traversing the graph and arrange the path out of what we found.
                        if node_id == our_node_id {
                                let mut new_entry = dist.remove(&our_node_id).unwrap();
-                               let mut ordered_hops = vec!((new_entry.clone(), NodeFeatures::empty()));
+                               let mut ordered_hops = vec!((new_entry.clone(), default_node_features.clone()));
 
                                'path_walk: loop {
                                        let mut features_set = false;
@@ -1265,14 +1342,12 @@ where L::Target: Logger {
                                                        if let Some(node_info) = node.announcement_info.as_ref() {
                                                                ordered_hops.last_mut().unwrap().1 = node_info.features.clone();
                                                        } else {
-                                                               ordered_hops.last_mut().unwrap().1 = NodeFeatures::empty();
+                                                               ordered_hops.last_mut().unwrap().1 = default_node_features.clone();
                                                        }
                                                } else {
-                                                       // We should be able to fill in features for everything except the last
-                                                       // hop, if the last hop was provided via a BOLT 11 invoice (though we
-                                                       // should be able to extend it further as BOLT 11 does have feature
-                                                       // flags for the last hop node itself).
-                                                       assert!(ordered_hops.last().unwrap().0.node_id == payee_node_id);
+                                                       // We can fill in features for everything except hops which were
+                                                       // provided via the invoice we're paying. We could guess based on the
+                                                       // recipient's features but for now we simply avoid guessing at all.
                                                }
                                        }
 
@@ -1294,13 +1369,13 @@ where L::Target: Logger {
                                        // so that fees paid for a HTLC forwarding on the current channel are
                                        // associated with the previous channel (where they will be subtracted).
                                        ordered_hops.last_mut().unwrap().0.fee_msat = new_entry.hop_use_fee_msat;
-                                       ordered_hops.push((new_entry.clone(), NodeFeatures::empty()));
+                                       ordered_hops.push((new_entry.clone(), default_node_features.clone()));
                                }
                                ordered_hops.last_mut().unwrap().0.fee_msat = value_contribution_msat;
                                ordered_hops.last_mut().unwrap().0.hop_use_fee_msat = 0;
 
-                               log_trace!(logger, "Found a path back to us from the target with {} hops contributing up to {} msat: {:?}",
-                                       ordered_hops.len(), value_contribution_msat, ordered_hops);
+                               log_trace!(logger, "Found a path back to us from the target with {} hops contributing up to {} msat: \n {:#?}",
+                                       ordered_hops.len(), value_contribution_msat, ordered_hops.iter().map(|h| &(h.0)).collect::<Vec<&PathBuildingHop>>());
 
                                let mut payment_path = PaymentPath {hops: ordered_hops};
 
@@ -1337,7 +1412,7 @@ where L::Target: Logger {
                                        // If we weren't capped by hitting a liquidity limit on a channel in the path,
                                        // we'll probably end up picking the same path again on the next iteration.
                                        // Decrease the available liquidity of a hop in the middle of the path.
-                                       let victim_scid = payment_path.hops[(payment_path.hops.len() - 1) / 2].0.candidate.short_channel_id();
+                                       let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
                                        log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
                                        let victim_liquidity = bookkept_channels_liquidity_available_msat.get_mut(&victim_scid).unwrap();
                                        *victim_liquidity = 0;
@@ -1409,24 +1484,31 @@ where L::Target: Logger {
        }
 
        // Sort by total fees and take the best paths.
-       payment_paths.sort_by_key(|path| path.get_total_fee_paid_msat());
+       payment_paths.sort_unstable_by_key(|path| path.get_total_fee_paid_msat());
        if payment_paths.len() > 50 {
                payment_paths.truncate(50);
        }
 
        // Draw multiple sufficient routes by randomly combining the selected paths.
        let mut drawn_routes = Vec::new();
-       for i in 0..payment_paths.len() {
+       let mut prng = ChaCha20::new(random_seed_bytes, &[0u8; 12]);
+       let mut random_index_bytes = [0u8; ::core::mem::size_of::<usize>()];
+
+       let num_permutations = payment_paths.len();
+       for _ in 0..num_permutations {
                let mut cur_route = Vec::<PaymentPath>::new();
                let mut aggregate_route_value_msat = 0;
 
                // Step (6).
-               // TODO: real random shuffle
-               // Currently just starts with i_th and goes up to i-1_th in a looped way.
-               let cur_payment_paths = [&payment_paths[i..], &payment_paths[..i]].concat();
+               // Do a Fisher-Yates shuffle to create a random permutation of the payment paths
+               for cur_index in (1..payment_paths.len()).rev() {
+                       prng.process_in_place(&mut random_index_bytes);
+                       let random_index = usize::from_be_bytes(random_index_bytes).wrapping_rem(cur_index+1);
+                       payment_paths.swap(cur_index, random_index);
+               }
 
                // Step (7).
-               for payment_path in cur_payment_paths {
+               for payment_path in &payment_paths {
                        cur_route.push(payment_path.clone());
                        aggregate_route_value_msat += payment_path.get_value_msat();
                        if aggregate_route_value_msat > final_value_msat {
@@ -1436,12 +1518,16 @@ where L::Target: Logger {
                                // also makes routing more reliable.
                                let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat;
 
-                               // First, drop some expensive low-value paths entirely if possible.
-                               // Sort by value so that we drop many really-low values first, since
-                               // fewer paths is better: the payment is less likely to fail.
-                               // TODO: this could also be optimized by also sorting by feerate_per_sat_routed,
-                               // so that the sender pays less fees overall. And also htlc_minimum_msat.
-                               cur_route.sort_by_key(|path| path.get_value_msat());
+                               // First, we drop some expensive low-value paths entirely if possible, since fewer
+                               // paths is better: the payment is less likely to fail. In order to do so, we sort
+                               // by value and fall back to total fees paid, i.e., in case of equal values we
+                               // prefer lower cost paths.
+                               cur_route.sort_unstable_by(|a, b| {
+                                       a.get_value_msat().cmp(&b.get_value_msat())
+                                               // Reverse ordering for cost, so we drop higher-cost paths first
+                                               .then_with(|| b.get_cost_msat().cmp(&a.get_cost_msat()))
+                               });
+
                                // We should make sure that at least 1 path left.
                                let mut paths_left = cur_route.len();
                                cur_route.retain(|path| {
@@ -1465,13 +1551,14 @@ where L::Target: Logger {
                                assert!(cur_route.len() > 0);
 
                                // Step (8).
-                               // Now, substract the overpaid value from the most-expensive path.
+                               // Now, subtract the overpaid value from the most-expensive path.
                                // TODO: this could also be optimized by also sorting by feerate_per_sat_routed,
                                // so that the sender pays less fees overall. And also htlc_minimum_msat.
-                               cur_route.sort_by_key(|path| { path.hops.iter().map(|hop| hop.0.candidate.fees().proportional_millionths as u64).sum::<u64>() });
+                               cur_route.sort_unstable_by_key(|path| { path.hops.iter().map(|hop| hop.0.candidate.fees().proportional_millionths as u64).sum::<u64>() });
                                let expensive_payment_path = cur_route.first_mut().unwrap();
-                               // We already dropped all the small channels above, meaning all the
-                               // remaining channels are larger than remaining overpaid_value_msat.
+
+                               // We already dropped all the small value paths above, meaning all the
+                               // remaining paths are larger than remaining overpaid_value_msat.
                                // Thus, this can't be negative.
                                let expensive_path_new_value_msat = expensive_payment_path.get_value_msat() - overpaid_value_msat;
                                expensive_payment_path.update_value_and_recompute_fees(expensive_path_new_value_msat);
@@ -1482,8 +1569,8 @@ where L::Target: Logger {
        }
 
        // Step (9).
-       // Select the best route by lowest total fee.
-       drawn_routes.sort_by_key(|paths| paths.iter().map(|path| path.get_total_fee_paid_msat()).sum::<u64>());
+       // Select the best route by lowest total cost.
+       drawn_routes.sort_unstable_by_key(|paths| paths.iter().map(|path| path.get_cost_msat()).sum::<u64>());
        let mut selected_paths = Vec::<Vec<Result<RouteHop, LightningError>>>::new();
        for payment_path in drawn_routes.first().unwrap() {
                let mut path = payment_path.hops.iter().map(|(payment_hop, node_features)| {
@@ -1520,17 +1607,105 @@ where L::Target: Logger {
        Ok(route)
 }
 
+// When an adversarial intermediary node observes a payment, it may be able to infer its
+// destination, if the remaining CLTV expiry delta exactly matches a feasible path in the network
+// graph. In order to improve privacy, this method obfuscates the CLTV expiry deltas along the
+// payment path by adding a randomized 'shadow route' offset to the final hop.
+fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph, random_seed_bytes: &[u8; 32]) {
+       let network_channels = network_graph.channels();
+       let network_nodes = network_graph.nodes();
+
+       for path in route.paths.iter_mut() {
+               let mut shadow_ctlv_expiry_delta_offset: u32 = 0;
+
+               // Remember the last three nodes of the random walk and avoid looping back on them.
+               // Init with the last three nodes from the actual path, if possible.
+               let mut nodes_to_avoid: [NodeId; 3] = [NodeId::from_pubkey(&path.last().unwrap().pubkey),
+                       NodeId::from_pubkey(&path.get(path.len().saturating_sub(2)).unwrap().pubkey),
+                       NodeId::from_pubkey(&path.get(path.len().saturating_sub(3)).unwrap().pubkey)];
+
+               // Choose the last publicly known node as the starting point for the random walk.
+               let mut cur_hop: Option<NodeId> = None;
+               let mut path_nonce = [0u8; 12];
+               if let Some(starting_hop) = path.iter().rev()
+                       .find(|h| network_nodes.contains_key(&NodeId::from_pubkey(&h.pubkey))) {
+                               cur_hop = Some(NodeId::from_pubkey(&starting_hop.pubkey));
+                               path_nonce.copy_from_slice(&cur_hop.unwrap().as_slice()[..12]);
+               }
+
+               // Init PRNG with the path-dependant nonce, which is static for private paths.
+               let mut prng = ChaCha20::new(random_seed_bytes, &path_nonce);
+               let mut random_path_bytes = [0u8; ::core::mem::size_of::<usize>()];
+
+               // Pick a random path length in [1 .. 3]
+               prng.process_in_place(&mut random_path_bytes);
+               let random_walk_length = usize::from_be_bytes(random_path_bytes).wrapping_rem(3).wrapping_add(1);
+
+               for random_hop in 0..random_walk_length {
+                       // If we don't find a suitable offset in the public network graph, we default to
+                       // MEDIAN_HOP_CLTV_EXPIRY_DELTA.
+                       let mut random_hop_offset = MEDIAN_HOP_CLTV_EXPIRY_DELTA;
+
+                       if let Some(cur_node_id) = cur_hop {
+                               if let Some(cur_node) = network_nodes.get(&cur_node_id) {
+                                       // Randomly choose the next unvisited hop.
+                                       prng.process_in_place(&mut random_path_bytes);
+                                       if let Some(random_channel) = usize::from_be_bytes(random_path_bytes)
+                                               .checked_rem(cur_node.channels.len())
+                                               .and_then(|index| cur_node.channels.get(index))
+                                               .and_then(|id| network_channels.get(id)) {
+                                                       random_channel.as_directed_from(&cur_node_id).map(|(dir_info, next_id)| {
+                                                               if !nodes_to_avoid.iter().any(|x| x == next_id) {
+                                                                       nodes_to_avoid[random_hop] = *next_id;
+                                                                       dir_info.direction().map(|channel_update_info| {
+                                                                               random_hop_offset = channel_update_info.cltv_expiry_delta.into();
+                                                                               cur_hop = Some(*next_id);
+                                                                       });
+                                                               }
+                                                       });
+                                               }
+                               }
+                       }
+
+                       shadow_ctlv_expiry_delta_offset = shadow_ctlv_expiry_delta_offset
+                               .checked_add(random_hop_offset)
+                               .unwrap_or(shadow_ctlv_expiry_delta_offset);
+               }
+
+               // Limit the total offset to reduce the worst-case locked liquidity timevalue
+               const MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET: u32 = 3*144;
+               shadow_ctlv_expiry_delta_offset = cmp::min(shadow_ctlv_expiry_delta_offset, MAX_SHADOW_CLTV_EXPIRY_DELTA_OFFSET);
+
+               // Limit the offset so we never exceed the max_total_cltv_expiry_delta. To improve plausibility,
+               // we choose the limit to be the largest possible multiple of MEDIAN_HOP_CLTV_EXPIRY_DELTA.
+               let path_total_cltv_expiry_delta: u32 = path.iter().map(|h| h.cltv_expiry_delta).sum();
+               let mut max_path_offset = payment_params.max_total_cltv_expiry_delta - path_total_cltv_expiry_delta;
+               max_path_offset = cmp::max(
+                       max_path_offset - (max_path_offset % MEDIAN_HOP_CLTV_EXPIRY_DELTA),
+                       max_path_offset % MEDIAN_HOP_CLTV_EXPIRY_DELTA);
+               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(last_hop) = path.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);
+               }
+       }
+}
+
 #[cfg(test)]
 mod tests {
-       use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters, Score};
        use routing::network_graph::{NetworkGraph, NetGraphMsgHandler, NodeId};
-       use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees};
+       use routing::router::{get_route, add_random_cltv_offset, default_node_features, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA};
+       use routing::scoring::Score;
        use chain::transaction::OutPoint;
+       use chain::keysinterface::KeysInterface;
        use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
        use ln::msgs::{ErrorAction, LightningError, OptionalField, UnsignedChannelAnnouncement, ChannelAnnouncement, RoutingMessageHandler,
           NodeAnnouncement, UnsignedNodeAnnouncement, ChannelUpdate, UnsignedChannelUpdate};
        use ln::channelmanager;
        use util::test_utils;
+       use util::chacha20::ChaCha20;
        use util::ser::Writeable;
        #[cfg(c_bindings)]
        use util::ser::Writer;
@@ -1560,9 +1735,13 @@ mod tests {
                                node_id,
                                unspendable_punishment_reserve: 0,
                                forwarding_info: None,
+                               outbound_htlc_minimum_msat: None,
+                               outbound_htlc_maximum_msat: None,
                        },
                        funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
+                       channel_type: None,
                        short_channel_id,
+                       inbound_scid_alias: None,
                        channel_value_satoshis: 0,
                        user_channel_id: 0,
                        balance_msat: 0,
@@ -1573,6 +1752,8 @@ mod tests {
                        force_close_spend_delay: None,
                        is_outbound: true, is_funding_locked: true,
                        is_usable: true, is_public: true,
+                       inbound_htlc_minimum_msat: None,
+                       inbound_htlc_maximum_msat: None,
                }
        }
 
@@ -1654,7 +1835,7 @@ mod tests {
 
        fn get_nodes(secp_ctx: &Secp256k1<All>) -> (SecretKey, PublicKey, Vec<SecretKey>, Vec<PublicKey>) {
                let privkeys: Vec<SecretKey> = (2..10).map(|i| {
-                       SecretKey::from_slice(&hex::decode(format!("{:02}", i).repeat(32)).unwrap()[..]).unwrap()
+                       SecretKey::from_slice(&hex::decode(format!("{:02x}", i).repeat(32)).unwrap()[..]).unwrap()
                }).collect();
 
                let pubkeys = privkeys.iter().map(|secret| PublicKey::from_secret_key(&secp_ctx, secret)).collect();
@@ -1998,14 +2179,16 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Simple route to 2 via 1
 
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 0, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Cannot send a payment of 0 msat");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2029,16 +2212,19 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Simple route to 2 via 1
 
                let our_chans = vec![get_channel_details(Some(2), our_id, InitFeatures::from_le_bytes(vec![0b11]), 100000)];
 
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) =
+                       get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "First hop cannot have our_node_pubkey as a destination.");
                } else { panic!(); }
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
        }
 
@@ -2048,6 +2234,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Simple route to 2 via 1
 
@@ -2144,7 +2332,7 @@ mod tests {
                });
 
                // Not possible to send 199_999_999, because the minimum on channel=2 is 200_000_000.
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 199_999_999, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
@@ -2163,7 +2351,7 @@ mod tests {
                });
 
                // A payment above the minimum should pass
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 199_999_999, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
        }
 
@@ -2173,6 +2361,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // A route to node#2 via two paths.
                // One path allows transferring 35-40 sats, another one also allows 35-40 sats.
@@ -2242,7 +2432,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Overpay fees to hit htlc_minimum_msat.
                let overpaid_fees = route.paths[0][0].fee_msat + route.paths[1][0].fee_msat;
                // TODO: this could be better balanced to overpay 10k and not 15k.
@@ -2287,14 +2477,14 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Fine to overpay for htlc_minimum_msat if it allows us to save fee.
                assert_eq!(route.paths.len(), 1);
                assert_eq!(route.paths[0][0].short_channel_id, 12);
                let fees = route.paths[0][0].fee_msat;
                assert_eq!(fees, 5_000);
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                // Not fine to overpay for htlc_minimum_msat if it requires paying more than fee on
                // the other channel.
                assert_eq!(route.paths.len(), 1);
@@ -2309,6 +2499,8 @@ mod tests {
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // // Disable channels 4 and 12 by flags=2
                update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
@@ -2337,13 +2529,13 @@ mod tests {
                });
 
                // If all the channels require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2367,21 +2559,24 @@ mod tests {
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Disable nodes 1, 2, and 8 by requiring unknown feature bits
-               let unknown_features = NodeFeatures::known().set_unknown_feature_required();
+               let mut unknown_features = NodeFeatures::known();
+               unknown_features.set_unknown_feature_required();
                add_or_update_node(&net_graph_msg_handler, &secp_ctx, &privkeys[0], unknown_features.clone(), 1);
                add_or_update_node(&net_graph_msg_handler, &secp_ctx, &privkeys[1], unknown_features.clone(), 1);
                add_or_update_node(&net_graph_msg_handler, &secp_ctx, &privkeys[7], unknown_features.clone(), 1);
 
                // If all nodes require some features we don't understand, route should fail
-               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+               if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                        assert_eq!(err, "Failed to find a path to the given destination");
                } else { panic!(); }
 
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2408,10 +2603,12 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Route to 1 via 2 and 3 because our channel to 1 is disabled
                let payment_params = PaymentParameters::from_node_id(nodes[0]);
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 3);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2438,7 +2635,7 @@ mod tests {
                // If we specify a channel to node7, that overrides our local channel view and that gets used
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
                let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[7]);
@@ -2537,6 +2734,8 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Simple test across 2, 3, 5, and 4 via a last_hop channel
                // Tests the behaviour when the RouteHint contains a suboptimal hop.
@@ -2559,13 +2758,13 @@ mod tests {
                invalid_last_hops.push(invalid_last_hop);
                {
                        let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(invalid_last_hops);
-                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer) {
+                       if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Route hint cannot have the payee as the source.");
                        } else { panic!(); }
                }
 
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops_multi_private_channels(&nodes));
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2602,7 +2801,7 @@ mod tests {
                assert_eq!(route.paths[0][4].short_channel_id, 8);
                assert_eq!(route.paths[0][4].fee_msat, 100);
                assert_eq!(route.paths[0][4].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][4].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
@@ -2636,10 +2835,12 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(empty_last_hop(&nodes));
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // Test handling of an empty RouteHint passed in Invoice.
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2676,18 +2877,20 @@ mod tests {
                assert_eq!(route.paths[0][4].short_channel_id, 8);
                assert_eq!(route.paths[0][4].fee_msat, 100);
                assert_eq!(route.paths[0][4].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][4].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
-       fn multi_hint_last_hops(nodes: &Vec<PublicKey>) -> Vec<RouteHint> {
+       /// Builds a trivial last-hop hint that passes through the two nodes given, with channel 0xff00
+       /// and 0xff01.
+       fn multi_hop_last_hops_hint(hint_hops: [PublicKey; 2]) -> Vec<RouteHint> {
                let zero_fees = RoutingFees {
                        base_msat: 0,
                        proportional_millionths: 0,
                };
                vec![RouteHint(vec![RouteHintHop {
-                       src_node_id: nodes[2],
-                       short_channel_id: 5,
+                       src_node_id: hint_hops[0],
+                       short_channel_id: 0xff00,
                        fees: RoutingFees {
                                base_msat: 100,
                                proportional_millionths: 0,
@@ -2696,19 +2899,12 @@ mod tests {
                        htlc_minimum_msat: None,
                        htlc_maximum_msat: None,
                }, RouteHintHop {
-                       src_node_id: nodes[3],
-                       short_channel_id: 8,
+                       src_node_id: hint_hops[1],
+                       short_channel_id: 0xff01,
                        fees: zero_fees,
                        cltv_expiry_delta: (8 << 4) | 1,
                        htlc_minimum_msat: None,
                        htlc_maximum_msat: None,
-               }]), RouteHint(vec![RouteHintHop {
-                       src_node_id: nodes[5],
-                       short_channel_id: 10,
-                       fees: zero_fees,
-                       cltv_expiry_delta: (10 << 4) | 1,
-                       htlc_minimum_msat: None,
-                       htlc_maximum_msat: None,
                }])]
        }
 
@@ -2716,9 +2912,12 @@ mod tests {
        fn multi_hint_last_hops_test() {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(multi_hint_last_hops(&nodes));
+               let last_hops = multi_hop_last_hops_hint([nodes[2], nodes[3]]);
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
                let scorer = test_utils::TestScorer::with_penalty(0);
-               // Test through channels 2, 3, 5, 8.
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               // Test through channels 2, 3, 0xff00, 0xff01.
                // Test shows that multiple hop hints are considered.
 
                // Disabling channels 6 & 7 by flags=2
@@ -2747,7 +2946,7 @@ mod tests {
                        excess_data: Vec::new()
                });
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 4);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2765,17 +2964,89 @@ mod tests {
                assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
 
                assert_eq!(route.paths[0][2].pubkey, nodes[3]);
-               assert_eq!(route.paths[0][2].short_channel_id, 5);
+               assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
                assert_eq!(route.paths[0][2].fee_msat, 0);
                assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
                assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags(4));
-               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new());
+               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                assert_eq!(route.paths[0][3].pubkey, nodes[6]);
-               assert_eq!(route.paths[0][3].short_channel_id, 8);
+               assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
                assert_eq!(route.paths[0][3].fee_msat, 100);
                assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][3].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
+       }
+
+       #[test]
+       fn private_multi_hint_last_hops_test() {
+               let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
+               let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
+
+               let non_announced_privkey = SecretKey::from_slice(&hex::decode(format!("{:02x}", 0xf0).repeat(32)).unwrap()[..]).unwrap();
+               let non_announced_pubkey = PublicKey::from_secret_key(&secp_ctx, &non_announced_privkey);
+
+               let last_hops = multi_hop_last_hops_hint([nodes[2], non_announced_pubkey]);
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
+               let scorer = test_utils::TestScorer::with_penalty(0);
+               // Test through channels 2, 3, 0xff00, 0xff01.
+               // Test shows that multiple hop hints are considered.
+
+               // Disabling channels 6 & 7 by flags=2
+               update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 6,
+                       timestamp: 2,
+                       flags: 2, // to disable
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: OptionalField::Absent,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+               update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 7,
+                       timestamp: 2,
+                       flags: 2, // to disable
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: OptionalField::Absent,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &[42u8; 32]).unwrap();
+               assert_eq!(route.paths[0].len(), 4);
+
+               assert_eq!(route.paths[0][0].pubkey, nodes[1]);
+               assert_eq!(route.paths[0][0].short_channel_id, 2);
+               assert_eq!(route.paths[0][0].fee_msat, 200);
+               assert_eq!(route.paths[0][0].cltv_expiry_delta, 65);
+               assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags(2));
+               assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags(2));
+
+               assert_eq!(route.paths[0][1].pubkey, nodes[2]);
+               assert_eq!(route.paths[0][1].short_channel_id, 4);
+               assert_eq!(route.paths[0][1].fee_msat, 100);
+               assert_eq!(route.paths[0][1].cltv_expiry_delta, 81);
+               assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags(3));
+               assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
+
+               assert_eq!(route.paths[0][2].pubkey, non_announced_pubkey);
+               assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
+               assert_eq!(route.paths[0][2].fee_msat, 0);
+               assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
+               assert_eq!(route.paths[0][2].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
+
+               assert_eq!(route.paths[0][3].pubkey, nodes[6]);
+               assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
+               assert_eq!(route.paths[0][3].fee_msat, 100);
+               assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
+               assert_eq!(route.paths[0][3].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
@@ -2824,10 +3095,12 @@ mod tests {
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops_with_public_channel(&nodes));
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                // This test shows that public routes can be present in the invoice
                // which would be handled in the same manner.
 
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2864,7 +3137,7 @@ mod tests {
                assert_eq!(route.paths[0][4].short_channel_id, 8);
                assert_eq!(route.paths[0][4].fee_msat, 100);
                assert_eq!(route.paths[0][4].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][4].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
@@ -2873,12 +3146,14 @@ mod tests {
                let (secp_ctx, network_graph, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // 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)];
                let mut last_hops = last_hops(&nodes);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
-               let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 2);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[3]);
@@ -2892,14 +3167,14 @@ mod tests {
                assert_eq!(route.paths[0][1].short_channel_id, 8);
                assert_eq!(route.paths[0][1].fee_msat, 100);
                assert_eq!(route.paths[0][1].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][1].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][1].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][1].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                last_hops[0].0[0].fees.base_msat = 1000;
 
                // Revert to via 6 as the fee on 8 goes up
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops);
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 4);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2929,11 +3204,11 @@ mod tests {
                assert_eq!(route.paths[0][3].short_channel_id, 10);
                assert_eq!(route.paths[0][3].fee_msat, 100);
                assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][3].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
 
                // ...but still use 8 for larger payments as 6 has a variable feerate
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 2000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths[0].len(), 5);
 
                assert_eq!(route.paths[0][0].pubkey, nodes[1]);
@@ -2970,7 +3245,7 @@ mod tests {
                assert_eq!(route.paths[0][4].short_channel_id, 8);
                assert_eq!(route.paths[0][4].fee_msat, 2000);
                assert_eq!(route.paths[0][4].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][4].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][4].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
        }
 
@@ -2994,7 +3269,10 @@ mod tests {
                let payment_params = PaymentParameters::from_node_id(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 = test_utils::TestScorer::with_penalty(0);
-               get_route(&source_node_id, &payment_params, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &test_utils::TestLogger::new(), &scorer)
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               get_route(&source_node_id, &payment_params, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()).read_only(),
+                               Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes)
        }
 
        #[test]
@@ -3019,7 +3297,7 @@ mod tests {
                assert_eq!(route.paths[0][1].short_channel_id, 8);
                assert_eq!(route.paths[0][1].fee_msat, 1000000);
                assert_eq!(route.paths[0][1].cltv_expiry_delta, 42);
-               assert_eq!(route.paths[0][1].node_features.le_flags(), &[0; 0]); // We dont pass flags in from invoices yet
+               assert_eq!(route.paths[0][1].node_features.le_flags(), default_node_features().le_flags()); // We dont pass flags in from invoices yet
                assert_eq!(route.paths[0][1].channel_features.le_flags(), &[0; 0]); // We can't learn any flags from invoices, sadly
        }
 
@@ -3048,6 +3326,8 @@ mod tests {
                let (secp_ctx, network_graph, mut net_graph_msg_handler, chain_monitor, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We will use a simple single-path route from
@@ -3112,14 +3392,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 250_000_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, 42, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 250_000_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3148,14 +3428,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, 42, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3195,14 +3475,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 15_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, 42, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 15_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3265,14 +3545,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 15_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 15_001, 42, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 15_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3297,14 +3577,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 10_001, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 10_001, 42, 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 an exact amount we have should be fine.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 10_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let path = route.paths.last().unwrap();
                        assert_eq!(path.len(), 2);
@@ -3320,6 +3600,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
 
                // Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
@@ -3406,14 +3688,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 60_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 60_000, 42, 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 49 sats (just a bit below the capacity).
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 49_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3426,7 +3708,7 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3443,6 +3725,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
 
                // Path via node0 is channels {1, 3}. Limit them to 100 and 50 sats (total limit 50).
@@ -3472,7 +3756,7 @@ mod tests {
                });
 
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 50_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3489,6 +3773,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -3582,7 +3868,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 300_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -3590,7 +3876,7 @@ mod tests {
                {
                        // Now, attempt to route 250 sats (just a bit below the capacity).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 250_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3603,7 +3889,7 @@ mod tests {
 
                {
                        // Attempt to route an exact amount is also fine
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 290_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 290_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -3620,6 +3906,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -3756,7 +4044,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 350_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 350_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -3764,7 +4052,7 @@ mod tests {
                {
                        // Now, attempt to route 300 sats (exact amount we can route).
                        // Our algorithm should provide us with these 3 paths, 100 sats each.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 300_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
 
                        let mut total_amount_paid_msat = 0;
@@ -3782,6 +4070,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
 
                // This test checks that if we have two cheaper paths and one more expensive path,
@@ -3922,7 +4212,7 @@ mod tests {
                {
                        // Now, attempt to route 180 sats.
                        // Our algorithm should provide us with these 2 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 180_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_value_transferred_msat = 0;
@@ -3949,6 +4239,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 2 paths:
@@ -4090,14 +4382,14 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 210_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 210_000, 42, 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 = get_route(&our_id, &payment_params, &network_graph, None, 200_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
 
                        let mut total_amount_paid_msat = 0;
@@ -4128,6 +4420,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(PublicKey::from_slice(&[02; 33]).unwrap()).with_features(InvoiceFeatures::known())
                        .with_route_hints(vec![RouteHint(vec![RouteHintHop {
                                src_node_id: nodes[2],
@@ -4194,7 +4488,7 @@ mod tests {
 
                // Get a route for 100 sats and check that we found the MPP route no problem and didn't
                // overpay at all.
-               let route = get_route(&our_id, &payment_params, &network_graph, None, 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                assert_eq!(route.paths.len(), 2);
                // Paths are somewhat randomly ordered, but:
                // * the first is channel 2 (1 msat fee) -> channel 4 -> channel 42
@@ -4216,6 +4510,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We need a route consisting of 3 paths:
@@ -4308,7 +4604,7 @@ mod tests {
                {
                        // Attempt to route more than available results in a failure.
                        if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
-                                       &our_id, &payment_params, &network_graph, None, 150_000, 42, Arc::clone(&logger), &scorer) {
+                                       &our_id, &payment_params, &network_graph.read_only(), None, 150_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes) {
                                assert_eq!(err, "Failed to find a sufficient route to the given destination");
                        } else { panic!(); }
                }
@@ -4316,7 +4612,7 @@ mod tests {
                {
                        // Now, attempt to route 125 sats (just a bit below the capacity of 3 channels).
                        // Our algorithm should provide us with these 3 paths.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 125_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 3);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4329,7 +4625,7 @@ mod tests {
 
                {
                        // Attempt to route without the last small cheap channel
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        let mut total_amount_paid_msat = 0;
                        for path in &route.paths {
@@ -4369,10 +4665,12 @@ mod tests {
                // "previous hop" being set to node 3, creating a loop in the path.
                let secp_ctx = Secp256k1::new();
                let logger = Arc::new(test_utils::TestLogger::new());
-               let network_graph = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
-               let net_graph_msg_handler = NetGraphMsgHandler::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
+               let network = Arc::new(NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()));
+               let net_graph_msg_handler = NetGraphMsgHandler::new(Arc::clone(&network), None, Arc::clone(&logger));
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[6]);
 
                add_channel(&net_graph_msg_handler, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
@@ -4466,7 +4764,7 @@ mod tests {
 
                {
                        // Now ensure the route flows simply over nodes 1 and 4 to 6.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 10_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 3);
 
@@ -4502,6 +4800,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]);
 
                // We modify the graph to set the htlc_maximum of channel 2 to below the value we wish to
@@ -4535,7 +4835,7 @@ mod tests {
                {
                        // Now, attempt to route 90 sats, which is exactly 90 sats at the last hop, plus the
                        // 200% fee charged channel 13 in the 1-to-2 direction.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 2);
 
@@ -4564,6 +4864,8 @@ mod tests {
                let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
                let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(InvoiceFeatures::known());
 
                // We modify the graph to set the htlc_minimum of channel 2 and 4 as needed - channel 2
@@ -4598,7 +4900,7 @@ mod tests {
                        // Now, attempt to route 90 sats, hitting the htlc_minimum on channel 4, but
                        // overshooting the htlc_maximum on channel 2. Thus, we should pick the (absurdly
                        // expensive) channels 12-13 path.
-                       let route = get_route(&our_id, &payment_params, &network_graph, None, 90_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 2);
 
@@ -4632,12 +4934,14 @@ mod tests {
                let network_graph = NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash());
                let scorer = test_utils::TestScorer::with_penalty(0);
                let payment_params = PaymentParameters::from_node_id(nodes[0]).with_features(InvoiceFeatures::known());
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&[
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 200_000),
                                &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 10_000),
-                       ]), 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       ]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 1);
                        assert_eq!(route.paths[0].len(), 1);
 
@@ -4646,10 +4950,10 @@ mod tests {
                        assert_eq!(route.paths[0][0].fee_msat, 100_000);
                }
                {
-                       let route = get_route(&our_id, &payment_params, &network_graph, Some(&[
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
                                &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
                                &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
-                       ]), 100_000, 42, Arc::clone(&logger), &scorer).unwrap();
+                       ]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                        assert_eq!(route.paths.len(), 2);
                        assert_eq!(route.paths[0].len(), 1);
                        assert_eq!(route.paths[1].len(), 1);
@@ -4662,6 +4966,32 @@ mod tests {
                        assert_eq!(route.paths[1][0].short_channel_id, 2);
                        assert_eq!(route.paths[1][0].fee_msat, 50_000);
                }
+
+               {
+                       // If we have a bunch of outbound channels to the same node, where most are not
+                       // sufficient to pay the full payment, but one is, we should default to just using the
+                       // one single channel that has sufficient balance, avoiding MPP.
+                       //
+                       // If we have several options above the 3xpayment value threshold, we should pick the
+                       // smallest of them, avoiding further fragmenting our available outbound balance to
+                       // this node.
+                       let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
+                               &get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(5), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(6), nodes[0], InitFeatures::known(), 300_000),
+                               &get_channel_details(Some(7), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(8), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(9), nodes[0], InitFeatures::known(), 50_000),
+                               &get_channel_details(Some(4), nodes[0], InitFeatures::known(), 1_000_000),
+                       ]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+                       assert_eq!(route.paths.len(), 1);
+                       assert_eq!(route.paths[0].len(), 1);
+
+                       assert_eq!(route.paths[0][0].pubkey, nodes[0]);
+                       assert_eq!(route.paths[0][0].short_channel_id, 6);
+                       assert_eq!(route.paths[0][0].fee_msat, 100_000);
+               }
        }
 
        #[test]
@@ -4672,9 +5002,11 @@ mod tests {
 
                // Without penalizing each hop 100 msats, a longer path with lower fees is chosen.
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let route = get_route(
-                       &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       &our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4686,8 +5018,8 @@ mod tests {
                // from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper.
                let scorer = test_utils::TestScorer::with_penalty(100);
                let route = get_route(
-                       &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       &our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4733,15 +5065,18 @@ mod tests {
 
        #[test]
        fn avoids_routing_through_bad_channels_and_nodes() {
-               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (secp_ctx, network, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
                let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
+               let network_graph = network.read_only();
 
                // A path to nodes[6] exists when no penalties are applied to any channel.
                let scorer = test_utils::TestScorer::with_penalty(0);
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
                let route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4753,7 +5088,7 @@ mod tests {
                let scorer = BadChannelScorer { short_channel_id: 6 };
                let route = get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
 
@@ -4765,7 +5100,7 @@ mod tests {
                let scorer = BadNodeScorer { node_id: NodeId::from_pubkey(&nodes[2]) };
                match get_route(
                        &our_id, &payment_params, &network_graph, None, 100, 42,
-                       Arc::clone(&logger), &scorer
+                       Arc::clone(&logger), &scorer, &random_seed_bytes
                ) {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -4847,8 +5182,9 @@ mod tests {
 
        #[test]
        fn limits_total_cltv_delta() {
-               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (secp_ctx, network, _, _, logger) = build_graph();
                let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
 
                let scorer = test_utils::TestScorer::with_penalty(0);
 
@@ -4856,7 +5192,9 @@ mod tests {
                let feasible_max_total_cltv_delta = 1008;
                let feasible_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
                        .with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
-               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, 0, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
                let path = route.paths[0].iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
                assert_ne!(path.len(), 0);
 
@@ -4864,7 +5202,7 @@ mod tests {
                let fail_max_total_cltv_delta = 23;
                let fail_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
                        .with_max_total_cltv_expiry_delta(fail_max_total_cltv_delta);
-               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer)
+               match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, 0, Arc::clone(&logger), &scorer, &random_seed_bytes)
                {
                        Err(LightningError { err, .. } ) => {
                                assert_eq!(err, "Failed to find a path to the given destination");
@@ -4873,6 +5211,106 @@ mod tests {
                }
        }
 
+       #[test]
+       fn adds_and_limits_cltv_offset() {
+               let (secp_ctx, network_graph, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+
+               let scorer = test_utils::TestScorer::with_penalty(0);
+
+               let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+               let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               assert_eq!(route.paths.len(), 1);
+
+               let cltv_expiry_deltas_before = route.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+
+               // Check whether the offset added to the last hop by default is in [1 .. DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA]
+               let mut route_default = route.clone();
+               add_random_cltv_offset(&mut route_default, &payment_params, &network_graph.read_only(), &random_seed_bytes);
+               let cltv_expiry_deltas_default = route_default.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+               assert_eq!(cltv_expiry_deltas_before.split_last().unwrap().1, cltv_expiry_deltas_default.split_last().unwrap().1);
+               assert!(cltv_expiry_deltas_default.last() > cltv_expiry_deltas_before.last());
+               assert!(cltv_expiry_deltas_default.last().unwrap() <= &DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA);
+
+               // Check that no offset is added when we restrict the max_total_cltv_expiry_delta
+               let mut route_limited = route.clone();
+               let limited_max_total_cltv_expiry_delta = cltv_expiry_deltas_before.iter().sum();
+               let limited_payment_params = payment_params.with_max_total_cltv_expiry_delta(limited_max_total_cltv_expiry_delta);
+               add_random_cltv_offset(&mut route_limited, &limited_payment_params, &network_graph.read_only(), &random_seed_bytes);
+               let cltv_expiry_deltas_limited = route_limited.paths[0].iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
+               assert_eq!(cltv_expiry_deltas_before, cltv_expiry_deltas_limited);
+       }
+
+       #[test]
+       fn adds_plausible_cltv_offset() {
+               let (secp_ctx, network, _, _, logger) = build_graph();
+               let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
+               let network_graph = network.read_only();
+               let network_nodes = network_graph.nodes();
+               let network_channels = network_graph.channels();
+               let scorer = test_utils::TestScorer::with_penalty(0);
+               let payment_params = PaymentParameters::from_node_id(nodes[3]);
+               let keys_manager = test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               let mut route = get_route(&our_id, &payment_params, &network_graph, None, 100, 0,
+                                                                 Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+               add_random_cltv_offset(&mut route, &payment_params, &network_graph, &random_seed_bytes);
+
+               let mut path_plausibility = vec![];
+
+               for p in route.paths {
+                       // 1. Select random observation point
+                       let mut prng = ChaCha20::new(&random_seed_bytes, &[0u8; 12]);
+                       let mut random_bytes = [0u8; ::core::mem::size_of::<usize>()];
+
+                       prng.process_in_place(&mut random_bytes);
+                       let random_path_index = usize::from_be_bytes(random_bytes).wrapping_rem(p.len());
+                       let observation_point = NodeId::from_pubkey(&p.get(random_path_index).unwrap().pubkey);
+
+                       // 2. Calculate what CLTV expiry delta we would observe there
+                       let observed_cltv_expiry_delta: u32 = p[random_path_index..].iter().map(|h| h.cltv_expiry_delta).sum();
+
+                       // 3. Starting from the observation point, find candidate paths
+                       let mut candidates: VecDeque<(NodeId, Vec<u32>)> = VecDeque::new();
+                       candidates.push_back((observation_point, vec![]));
+
+                       let mut found_plausible_candidate = false;
+
+                       'candidate_loop: while let Some((cur_node_id, cur_path_cltv_deltas)) = candidates.pop_front() {
+                               if let Some(remaining) = observed_cltv_expiry_delta.checked_sub(cur_path_cltv_deltas.iter().sum::<u32>()) {
+                                       if remaining == 0 || remaining.wrapping_rem(40) == 0 || remaining.wrapping_rem(144) == 0 {
+                                               found_plausible_candidate = true;
+                                               break 'candidate_loop;
+                                       }
+                               }
+
+                               if let Some(cur_node) = network_nodes.get(&cur_node_id) {
+                                       for channel_id in &cur_node.channels {
+                                               if let Some(channel_info) = network_channels.get(&channel_id) {
+                                                       if let Some((dir_info, next_id)) = channel_info.as_directed_from(&cur_node_id) {
+                                                               if let Some(channel_update_info) = dir_info.direction() {
+                                                                       let next_cltv_expiry_delta = channel_update_info.cltv_expiry_delta as u32;
+                                                                       if cur_path_cltv_deltas.iter().sum::<u32>()
+                                                                               .saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta {
+                                                                               let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone();
+                                                                               new_path_cltv_deltas.push(next_cltv_expiry_delta);
+                                                                               candidates.push_back((*next_id, new_path_cltv_deltas));
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       path_plausibility.push(found_plausible_candidate);
+               }
+               assert!(path_plausibility.iter().all(|x| *x));
+       }
+
        #[cfg(not(feature = "no-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.
@@ -4887,6 +5325,8 @@ mod tests {
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes() {
+               use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+
                let mut d = match super::test_utils::get_route_file() {
                        Ok(f) => f,
                        Err(e) => {
@@ -4895,6 +5335,8 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4909,7 +5351,7 @@ mod tests {
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
                                let scorer = ProbabilisticScorer::new(params, &graph);
-                               if get_route(src, &payment_params, &graph, None, amt, 42, &test_utils::TestLogger::new(), &scorer).is_ok() {
+                               if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
                                }
                        }
@@ -4919,6 +5361,8 @@ mod tests {
        #[test]
        #[cfg(not(feature = "no-std"))]
        fn generate_routes_mpp() {
+               use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+
                let mut d = match super::test_utils::get_route_file() {
                        Ok(f) => f,
                        Err(e) => {
@@ -4927,6 +5371,8 @@ mod tests {
                        },
                };
                let graph = NetworkGraph::read(&mut d).unwrap();
+               let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut seed = random_init_seed() as usize;
@@ -4941,7 +5387,7 @@ mod tests {
                                let amt = seed as u64 % 200_000_000;
                                let params = ProbabilisticScoringParameters::default();
                                let scorer = ProbabilisticScorer::new(params, &graph);
-                               if get_route(src, &payment_params, &graph, None, amt, 42, &test_utils::TestLogger::new(), &scorer).is_ok() {
+                               if get_route(src, &payment_params, &graph.read_only(), None, amt, 42, &test_utils::TestLogger::new(), &scorer, &random_seed_bytes).is_ok() {
                                        continue 'load_endpoints;
                                }
                        }
@@ -4982,6 +5428,7 @@ mod benches {
        use bitcoin::hashes::Hash;
        use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
        use chain::transaction::OutPoint;
+       use chain::keysinterface::{KeysManager,KeysInterface};
        use ln::channelmanager::{ChannelCounterparty, ChannelDetails};
        use ln::features::{InitFeatures, InvoiceFeatures};
        use routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters, Scorer};
@@ -5013,11 +5460,15 @@ mod benches {
                                node_id,
                                unspendable_punishment_reserve: 0,
                                forwarding_info: None,
+                               outbound_htlc_minimum_msat: None,
+                               outbound_htlc_maximum_msat: None,
                        },
                        funding_txo: Some(OutPoint {
                                txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
                        }),
+                       channel_type: None,
                        short_channel_id: Some(1),
+                       inbound_scid_alias: None,
                        channel_value_satoshis: 10_000_000,
                        user_channel_id: 0,
                        balance_msat: 10_000_000,
@@ -5030,6 +5481,8 @@ mod benches {
                        is_funding_locked: true,
                        is_usable: true,
                        is_public: true,
+                       inbound_htlc_minimum_msat: None,
+                       inbound_htlc_maximum_msat: None,
                }
        }
 
@@ -5082,12 +5535,14 @@ mod benches {
        ) {
                let nodes = graph.read_only().nodes().clone();
                let payer = payer_pubkey();
+               let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
 
                // First, get 100 (source, destination) pairs for which route-getting actually succeeds...
                let mut routes = Vec::new();
                let mut route_endpoints = Vec::new();
                let mut seed: usize = 0xdeadbeef;
-               'load_endpoints: for _ in 0..100 {
+               'load_endpoints: for _ in 0..150 {
                        loop {
                                seed *= 0xdeadbeef;
                                let src = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
@@ -5096,7 +5551,7 @@ mod benches {
                                let params = PaymentParameters::from_node_id(dst).with_features(features.clone());
                                let first_hop = first_hop(src);
                                let amt = seed as u64 % 1_000_000;
-                               if let Ok(route) = get_route(&payer, &params, &graph, Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer) {
+                               if let Ok(route) = get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes) {
                                        routes.push(route);
                                        route_endpoints.push((first_hop, params, amt));
                                        continue 'load_endpoints;
@@ -5119,11 +5574,20 @@ mod benches {
                        }
                }
 
+               // Because we've changed channel scores, its possible we'll take different routes to the
+               // selected destinations, possibly causing us to fail because, eg, the newly-selected path
+               // requires a too-high CLTV delta.
+               route_endpoints.retain(|(first_hop, params, amt)| {
+                       get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok()
+               });
+               route_endpoints.truncate(100);
+               assert_eq!(route_endpoints.len(), 100);
+
                // ...then benchmark finding paths between the nodes we learned.
                let mut idx = 0;
                bench.iter(|| {
                        let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()];
-                       assert!(get_route(&payer, params, &graph, Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer).is_ok());
+                       assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok());
                        idx += 1;
                });
        }