// You may not use this file except in accordance with one or both of these
// licenses.
-//! The top-level routing/network map tracking logic lives here.
-//!
-//! You probably want to create a P2PGossipSync and use that as your RoutingMessageHandler and then
-//! interrogate it to get routes for your own payments.
+//! The router finds paths within a [`NetworkGraph`] for a payment.
use bitcoin::secp256k1::PublicKey;
use bitcoin::hashes::Hash;
use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
use crate::routing::scoring::{ChannelUsage, LockableScore, Score};
-use crate::util::ser::{Writeable, Readable, Writer};
+use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
use crate::util::logger::{Level, Logger};
use crate::util::chacha20::ChaCha20;
&random_seed_bytes
)
}
-
- fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
- self.scorer.lock().payment_path_failed(path, short_channel_id);
- }
-
- fn notify_payment_path_successful(&self, path: &[&RouteHop]) {
- self.scorer.lock().payment_path_successful(path);
- }
-
- fn notify_payment_probe_successful(&self, path: &[&RouteHop]) {
- self.scorer.lock().probe_successful(path);
- }
-
- fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) {
- self.scorer.lock().probe_failed(path, short_channel_id);
- }
}
/// A trait defining behavior for routing a payment.
) -> Result<Route, LightningError> {
self.find_route(payer, route_params, first_hops, inflight_htlcs)
}
- /// Lets the router know that payment through a specific path has failed.
- fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64);
- /// Lets the router know that payment through a specific path was successful.
- fn notify_payment_path_successful(&self, path: &[&RouteHop]);
- /// Lets the router know that a payment probe was successful.
- fn notify_payment_probe_successful(&self, path: &[&RouteHop]);
- /// Lets the router know that a payment probe failed.
- fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64);
}
/// [`Score`] implementation that factors in in-flight HTLC liquidity.
fn read<R: io::Read>(reader: &mut R) -> Result<Route, DecodeError> {
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
let path_count: u64 = Readable::read(reader)?;
+ if path_count == 0 { return Err(DecodeError::InvalidValue); }
let mut paths = Vec::with_capacity(cmp::min(path_count, 128) as usize);
+ let mut min_final_cltv_expiry_delta = u32::max_value();
for _ in 0..path_count {
let hop_count: u8 = Readable::read(reader)?;
- let mut hops = Vec::with_capacity(hop_count as usize);
+ let mut hops: Vec<RouteHop> = Vec::with_capacity(hop_count as usize);
for _ in 0..hop_count {
hops.push(Readable::read(reader)?);
}
+ if hops.is_empty() { return Err(DecodeError::InvalidValue); }
+ min_final_cltv_expiry_delta =
+ cmp::min(min_final_cltv_expiry_delta, hops.last().unwrap().cltv_expiry_delta);
paths.push(hops);
}
let mut payment_params = None;
read_tlv_fields!(reader, {
- (1, payment_params, option),
+ (1, payment_params, (option: ReadableArgs, min_final_cltv_expiry_delta)),
});
Ok(Route { paths, payment_params })
}
/// Parameters needed to find a [`Route`].
///
/// Passed to [`find_route`] and [`build_route_from_hops`], but also provided in
-/// [`Event::PaymentPathFailed`] for retrying a failed payment path.
+/// [`Event::PaymentPathFailed`].
///
/// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RouteParameters {
/// The parameters of the failed payment path.
pub payment_params: PaymentParameters,
/// The amount in msats sent on the failed payment path.
pub final_value_msat: u64,
+}
- /// The CLTV on the final hop of the failed payment path.
- pub final_cltv_expiry_delta: u32,
+impl Writeable for RouteParameters {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+ write_tlv_fields!(writer, {
+ (0, self.payment_params, required),
+ (2, self.final_value_msat, required),
+ // LDK versions prior to 0.0.114 had the `final_cltv_expiry_delta` parameter in
+ // `RouteParameters` directly. For compatibility, we write it here.
+ (4, self.payment_params.final_cltv_expiry_delta, required),
+ });
+ Ok(())
+ }
}
-impl_writeable_tlv_based!(RouteParameters, {
- (0, payment_params, required),
- (2, final_value_msat, required),
- (4, final_cltv_expiry_delta, required),
-});
+impl Readable for RouteParameters {
+ fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ _init_and_read_tlv_fields!(reader, {
+ (0, payment_params, (required: ReadableArgs, 0)),
+ (2, final_value_msat, required),
+ (4, final_cltv_expiry_delta, required),
+ });
+ let mut payment_params: PaymentParameters = payment_params.0.unwrap();
+ if payment_params.final_cltv_expiry_delta == 0 {
+ payment_params.final_cltv_expiry_delta = final_cltv_expiry_delta.0.unwrap();
+ }
+ Ok(Self {
+ payment_params,
+ final_value_msat: final_value_msat.0.unwrap(),
+ })
+ }
+}
/// Maximum total CTLV difference we allow for a full payment path.
pub const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008;
/// payment to fail. Future attempts for the same payment shouldn't be relayed through any of
/// these SCIDs.
pub previously_failed_channels: Vec<u64>,
+
+ /// The minimum CLTV delta at the end of the route. This value must not be zero.
+ pub final_cltv_expiry_delta: u32,
+}
+
+impl Writeable for PaymentParameters {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+ write_tlv_fields!(writer, {
+ (0, self.payee_pubkey, required),
+ (1, self.max_total_cltv_expiry_delta, required),
+ (2, self.features, option),
+ (3, self.max_path_count, required),
+ (4, self.route_hints, vec_type),
+ (5, self.max_channel_saturation_power_of_half, required),
+ (6, self.expiry_time, option),
+ (7, self.previously_failed_channels, vec_type),
+ (9, self.final_cltv_expiry_delta, required),
+ });
+ Ok(())
+ }
+}
+
+impl ReadableArgs<u32> for PaymentParameters {
+ fn read<R: io::Read>(reader: &mut R, default_final_cltv_expiry_delta: u32) -> Result<Self, DecodeError> {
+ _init_and_read_tlv_fields!(reader, {
+ (0, payee_pubkey, required),
+ (1, max_total_cltv_expiry_delta, (default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA)),
+ (2, features, option),
+ (3, max_path_count, (default_value, DEFAULT_MAX_PATH_COUNT)),
+ (4, route_hints, vec_type),
+ (5, max_channel_saturation_power_of_half, (default_value, 2)),
+ (6, expiry_time, option),
+ (7, previously_failed_channels, vec_type),
+ (9, final_cltv_expiry_delta, (default_value, default_final_cltv_expiry_delta)),
+ });
+ Ok(Self {
+ payee_pubkey: _init_tlv_based_struct_field!(payee_pubkey, required),
+ max_total_cltv_expiry_delta: _init_tlv_based_struct_field!(max_total_cltv_expiry_delta, (default_value, unused)),
+ features,
+ max_path_count: _init_tlv_based_struct_field!(max_path_count, (default_value, unused)),
+ route_hints: route_hints.unwrap_or(Vec::new()),
+ max_channel_saturation_power_of_half: _init_tlv_based_struct_field!(max_channel_saturation_power_of_half, (default_value, unused)),
+ expiry_time,
+ previously_failed_channels: previously_failed_channels.unwrap_or(Vec::new()),
+ final_cltv_expiry_delta: _init_tlv_based_struct_field!(final_cltv_expiry_delta, (default_value, unused)),
+ })
+ }
}
-impl_writeable_tlv_based!(PaymentParameters, {
- (0, payee_pubkey, required),
- (1, max_total_cltv_expiry_delta, (default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA)),
- (2, features, option),
- (3, max_path_count, (default_value, DEFAULT_MAX_PATH_COUNT)),
- (4, route_hints, vec_type),
- (5, max_channel_saturation_power_of_half, (default_value, 2)),
- (6, expiry_time, option),
- (7, previously_failed_channels, vec_type),
-});
impl PaymentParameters {
/// Creates a payee with the node id of the given `pubkey`.
- pub fn from_node_id(payee_pubkey: PublicKey) -> Self {
+ ///
+ /// The `final_cltv_expiry_delta` should match the expected final CLTV delta the recipient has
+ /// provided.
+ pub fn from_node_id(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32) -> Self {
Self {
payee_pubkey,
features: None,
max_path_count: DEFAULT_MAX_PATH_COUNT,
max_channel_saturation_power_of_half: 2,
previously_failed_channels: Vec::new(),
+ final_cltv_expiry_delta,
}
}
/// Creates a payee with the node id of the given `pubkey` to use for keysend payments.
- pub fn for_keysend(payee_pubkey: PublicKey) -> Self {
- Self::from_node_id(payee_pubkey).with_features(InvoiceFeatures::for_keysend())
+ ///
+ /// The `final_cltv_expiry_delta` should match the expected final CLTV delta the recipient has
+ /// provided.
+ pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32) -> Self {
+ Self::from_node_id(payee_pubkey, final_cltv_expiry_delta).with_features(InvoiceFeatures::for_keysend())
}
/// Includes the payee's features.
#[derive(Eq, PartialEq)]
struct RouteGraphNode {
node_id: NodeId,
- lowest_fee_to_peer_through_node: u64,
lowest_fee_to_node: u64,
total_cltv_delta: u32,
// The maximum value a yet-to-be-constructed payment path might flow through this node.
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)
+ let other_score = cmp::max(other.lowest_fee_to_node, other.path_htlc_minimum_msat)
.saturating_add(other.path_penalty_msat);
- let self_score = cmp::max(self.lowest_fee_to_peer_through_node, self.path_htlc_minimum_msat)
+ let self_score = cmp::max(self.lowest_fee_to_node, self.path_htlc_minimum_msat)
.saturating_add(self.path_penalty_msat);
other_score.cmp(&self_score).then_with(|| other.node_id.cmp(&self.node_id))
}
candidate: CandidateRouteHop<'a>,
fee_msat: u64,
- /// Minimal fees required to route to the source node of the current hop via any of its inbound channels.
- src_lowest_inbound_fees: RoutingFees,
/// All the fees paid *after* this channel on the way to the destination
next_hops_fee_msat: u64,
/// Fee paid for the use of the current channel (see candidate.fees()).
}
}
+#[inline(always)]
+/// Calculate the fees required to route the given amount over a channel with the given fees.
fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
- let proportional_fee_millions =
- amount_msat.checked_mul(channel_fees.proportional_millionths as u64);
- if let Some(new_fee) = proportional_fee_millions.and_then(|part| {
- (channel_fees.base_msat as u64).checked_add(part / 1_000_000) }) {
+ amount_msat.checked_mul(channel_fees.proportional_millionths as u64)
+ .and_then(|part| (channel_fees.base_msat as u64).checked_add(part / 1_000_000))
+}
- Some(new_fee)
- } else {
- // This function may be (indirectly) called without any verification,
- // with channel_fees provided by a caller. We should handle it gracefully.
- None
- }
+#[inline(always)]
+/// Calculate the fees required to route the given amount over a channel with the given fees,
+/// saturating to [`u64::max_value`].
+fn compute_fees_saturating(amount_msat: u64, channel_fees: RoutingFees) -> u64 {
+ amount_msat.checked_mul(channel_fees.proportional_millionths as u64)
+ .map(|prop| prop / 1_000_000).unwrap_or(u64::max_value())
+ .saturating_add(channel_fees.base_msat as u64)
}
/// The default `features` we assume for a node in a route, when no `features` are known about that
) -> Result<Route, LightningError>
where L::Target: Logger, GL::Target: Logger {
let graph_lock = network_graph.read_only();
+ let final_cltv_expiry_delta = route_params.payment_params.final_cltv_expiry_delta;
let mut route = get_route(our_node_pubkey, &route_params.payment_params, &graph_lock, first_hops,
- route_params.final_value_msat, route_params.final_cltv_expiry_delta, logger, scorer,
+ route_params.final_value_msat, final_cltv_expiry_delta, logger, scorer,
random_seed_bytes)?;
add_random_cltv_offset(&mut route, &route_params.payment_params, &graph_lock, random_seed_bytes);
Ok(route)
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});
}
+ // TODO: Remove the explicit final_cltv_expiry_delta parameter
+ debug_assert_eq!(final_cltv_expiry_delta, payment_params.final_cltv_expiry_delta);
+
// The general routing idea is the following:
// 1. Fill first/last hops communicated by the caller.
// 2. Attempt to construct a path from payer to payee for transferring
// 8. If our maximum channel saturation limit caused us to pick two identical paths, combine
// them so that we're not sending two HTLCs along the same path.
- // As for the actual search algorithm,
- // we do a payee-to-payer pseudo-Dijkstra's sorting by each node's distance from the payee
- // plus the minimum per-HTLC fee to get from it to another node (aka "shitty pseudo-A*").
+ // As for the actual search algorithm, we do a payee-to-payer Dijkstra's sorting by each node's
+ // distance from the payee
//
// We are not a faithful Dijkstra's implementation because we can change values which impact
// earlier nodes while processing later nodes. Specifically, if we reach a channel with a lower
// runtime for little gain. Specifically, the current algorithm rather efficiently explores the
// graph for candidate paths, calculating the maximum value which can realistically be sent at
// the same time, remaining generic across different payment values.
- //
- // TODO: There are a few tweaks we could do, including possibly pre-calculating more stuff
- // to use as the A* heuristic beyond just the cost to get one node further than the current
- // one.
let network_channels = network_graph.channels();
let network_nodes = network_graph.nodes();
}
}
- // The main heap containing all candidate next-hops sorted by their score (max(A* fee,
+ // The main heap containing all candidate next-hops sorted by their score (max(fee,
// htlc_minimum)). Ideally this would be a heap which allowed cheap score reduction instead of
// adding duplicate entries when we find a better path to a given node.
let mut targets: BinaryHeap<RouteGraphNode> = BinaryHeap::new();
// might violate htlc_minimum_msat on the hops which are next along the
// payment path (upstream to the payee). To avoid that, we recompute
// path fees knowing the final path contribution after constructing it.
- let path_htlc_minimum_msat = compute_fees($next_hops_path_htlc_minimum_msat, $candidate.fees())
- .and_then(|fee_msat| fee_msat.checked_add($next_hops_path_htlc_minimum_msat))
- .map(|fee_msat| cmp::max(fee_msat, $candidate.htlc_minimum_msat()))
- .unwrap_or_else(|| u64::max_value());
+ let path_htlc_minimum_msat = cmp::max(
+ compute_fees_saturating($next_hops_path_htlc_minimum_msat, $candidate.fees())
+ .saturating_add($next_hops_path_htlc_minimum_msat),
+ $candidate.htlc_minimum_msat());
let hm_entry = dist.entry($src_node_id);
let old_entry = hm_entry.or_insert_with(|| {
// If there was previously no known way to access the source node
// 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 = 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;
- }
PathBuildingHop {
node_id: $dest_node_id.clone(),
candidate: $candidate.clone(),
fee_msat: 0,
- src_lowest_inbound_fees: RoutingFees {
- base_msat: fee_base_msat,
- proportional_millionths: fee_proportional_millionths,
- },
next_hops_fee_msat: u64::max_value(),
hop_use_fee_msat: u64::max_value(),
total_fee_msat: u64::max_value(),
if should_process {
let mut hop_use_fee_msat = 0;
- let mut total_fee_msat = $next_hops_fee_msat;
+ let mut total_fee_msat: u64 = $next_hops_fee_msat;
// Ignore hop_use_fee_msat for channel-from-us as we assume all channels-from-us
// will have the same effective-fee
if $src_node_id != our_node_id {
- match compute_fees(amount_to_transfer_over_msat, $candidate.fees()) {
- // max_value means we'll always fail
- // the old_entry.total_fee_msat > total_fee_msat check
- None => total_fee_msat = u64::max_value(),
- Some(fee_msat) => {
- hop_use_fee_msat = fee_msat;
- total_fee_msat += hop_use_fee_msat;
- // When calculating the lowest inbound fees to a node, we
- // calculate fees here not based on the actual value we think
- // will flow over this channel, but on the minimum value that
- // we'll accept flowing over it. The minimum accepted value
- // is a constant through each path collection run, ensuring
- // consistent basis. Otherwise we may later find a
- // different path to the source node that is more expensive,
- // but which we consider to be cheaper because we are capacity
- // constrained and the relative fee becomes lower.
- match compute_fees(minimal_value_contribution_msat, old_entry.src_lowest_inbound_fees)
- .map(|a| a.checked_add(total_fee_msat)) {
- Some(Some(v)) => {
- total_fee_msat = v;
- },
- _ => {
- total_fee_msat = u64::max_value();
- }
- };
- }
- }
+ // Note that `u64::max_value` means we'll always fail the
+ // `old_entry.total_fee_msat > total_fee_msat` check below
+ hop_use_fee_msat = compute_fees_saturating(amount_to_transfer_over_msat, $candidate.fees());
+ total_fee_msat = total_fee_msat.saturating_add(hop_use_fee_msat);
}
let channel_usage = ChannelUsage {
.saturating_add(channel_penalty_msat);
let new_graph_node = RouteGraphNode {
node_id: $src_node_id,
- lowest_fee_to_peer_through_node: total_fee_msat,
- lowest_fee_to_node: $next_hops_fee_msat as u64 + hop_use_fee_msat,
+ lowest_fee_to_node: total_fee_msat,
total_cltv_delta: hop_total_cltv_delta,
value_contribution_msat,
path_htlc_minimum_msat,
let graph_lock = network_graph.read_only();
let mut route = build_route_from_hops_internal(
our_node_pubkey, hops, &route_params.payment_params, &graph_lock,
- route_params.final_value_msat, route_params.final_cltv_expiry_delta, logger, random_seed_bytes)?;
+ route_params.final_value_msat, route_params.payment_params.final_cltv_expiry_delta,
+ logger, random_seed_bytes)?;
add_random_cltv_offset(&mut route, &route_params.payment_params, &graph_lock, random_seed_bytes);
Ok(route)
}
#[cfg(test)]
mod tests {
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity};
+ use crate::routing::utxo::UtxoResult;
use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
- use crate::routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
+ use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
use crate::chain::transaction::OutPoint;
use crate::chain::keysinterface::EntropySource;
fn simple_route_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn invalid_first_hop_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn htlc_minimum_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features(&config));
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config));
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn disable_channels_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn disable_node_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let payment_params = PaymentParameters::from_node_id(nodes[2]);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn our_chans_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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 payment_params = PaymentParameters::from_node_id(nodes[0], 42);
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][2].channel_features.le_flags(), &id_to_feature_flags(3));
// 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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
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.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);
fn partial_route_hint_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let mut invalid_last_hops = last_hops_multi_private_channels(&nodes);
invalid_last_hops.push(invalid_last_hop);
{
- let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(invalid_last_hops);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(invalid_last_hops);
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_multi_private_channels(&nodes));
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);
fn ignores_empty_last_hops_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
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 = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(empty_last_hop(&nodes));
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
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 = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone());
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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.
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 = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone());
+ let scorer = ln_test_utils::TestScorer::new();
// Test through channels 2, 3, 0xff00, 0xff01.
// Test shows that multiple hop hints are considered.
fn last_hops_with_public_channel_test() {
let (secp_ctx, network_graph, _, _, 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_with_public_channel(&nodes));
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_with_public_channel(&nodes));
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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
fn our_chans_last_hop_connect_test() {
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone());
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);
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops);
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);
htlc_minimum_msat: None,
htlc_maximum_msat: last_hop_htlc_max,
}]);
- let payment_params = PaymentParameters::from_node_id(target_node_id).with_route_hints(vec![last_hops]);
+ let payment_params = PaymentParameters::from_node_id(target_node_id, 42).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 = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
let logger = ln_test_utils::TestLogger::new();
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let route = get_route(&source_node_id, &payment_params, &network_graph.read_only(),
Some(&our_chans.iter().collect::<Vec<_>>()), route_val, 42, &logger, &scorer, &random_seed_bytes);
route
let (secp_ctx, network_graph, mut gossip_sync, chain_monitor, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config));
// We will use a simple single-path route from
// our node to node2 via node0: channels {1, 3}.
.push_opcode(opcodes::all::OP_PUSHNUM_2)
.push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
- *chain_monitor.utxo_ret.lock().unwrap() = Ok(TxOut { value: 15, script_pubkey: good_script.clone() });
- gossip_sync.add_chain_access(Some(chain_monitor));
+ *chain_monitor.utxo_ret.lock().unwrap() =
+ UtxoResult::Sync(Ok(TxOut { value: 15, script_pubkey: good_script.clone() }));
+ gossip_sync.add_utxo_lookup(Some(chain_monitor));
add_channel(&gossip_sync, &secp_ctx, &privkeys[0], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 333);
update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
// one of the latter hops is limited.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 42).with_features(channelmanager::provided_invoice_features(&config));
// Path via {node7, node2, node4} is channels {12, 13, 6, 11}.
// {12, 13, 11} have the capacities of 100, {6} has a capacity of 50.
fn ignore_fee_first_hop_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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]);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
// Path via node0 is channels {1, 3}. Limit them to 100 and 50 sats (total limit 50).
update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
fn simple_mpp_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2])
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42)
.with_features(channelmanager::provided_invoice_features(&config));
// We need a route consisting of 3 paths:
fn long_mpp_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 42).with_features(channelmanager::provided_invoice_features(&config));
// We need a route consisting of 3 paths:
// From our node to node3 via {node0, node2}, {node7, node2, node4} and {node7, node2}.
fn mpp_cheaper_route_test() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 42).with_features(channelmanager::provided_invoice_features(&config));
// This test checks that if we have two cheaper paths and one more expensive path,
// so that liquidity-wise any 2 of 3 combination is sufficient,
// if the fee is not properly accounted for, the behavior is different.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[3]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 42).with_features(channelmanager::provided_invoice_features(&config));
// We need a route consisting of 2 paths:
// From our node to node3 via {node0, node2} and {node7, node2, node4}.
// This bug appeared in production in some specific channel configurations.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(PublicKey::from_slice(&[02; 33]).unwrap()).with_features(channelmanager::provided_invoice_features(&config))
+ let payment_params = PaymentParameters::from_node_id(PublicKey::from_slice(&[02; 33]).unwrap(), 42).with_features(channelmanager::provided_invoice_features(&config))
.with_route_hints(vec![RouteHint(vec![RouteHintHop {
src_node_id: nodes[2],
short_channel_id: 42,
// path finding we realize that we found more capacity than we need.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features(&config))
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config))
.with_max_channel_saturation_power_of_half(0);
// We need a route consisting of 3 paths:
// payment) htlc_minimum_msat. In the original algorithm, this resulted in node4's
// "previous hop" being set to node 3, creating a loop in the path.
let secp_ctx = Secp256k1::new();
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
let logger = Arc::new(ln_test_utils::TestLogger::new());
- let network = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger)));
+ let network = Arc::new(NetworkGraph::new(Network::Testnet, Arc::clone(&logger)));
let gossip_sync = P2PGossipSync::new(Arc::clone(&network), None, Arc::clone(&logger));
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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]);
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42);
add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6);
update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
// we calculated fees on a higher value, resulting in us ignoring such paths.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_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]);
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
// We modify the graph to set the htlc_maximum of channel 2 to below the value we wish to
// send.
// resulting in us thinking there is no possible path, even if other paths exist.
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config));
// We modify the graph to set the htlc_minimum of channel 2 and 4 as needed - channel 2
// gets an htlc_maximum_msat of 80_000 and channel 4 an htlc_minimum_msat of 90_000. We
// route over multiple channels with the same first hop.
let secp_ctx = Secp256k1::new();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
let logger = Arc::new(ln_test_utils::TestLogger::new());
- let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let network_graph = NetworkGraph::new(Network::Testnet, Arc::clone(&logger));
+ let scorer = ln_test_utils::TestScorer::new();
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[0]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[0], 42).with_features(channelmanager::provided_invoice_features(&config));
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
fn prefers_shorter_route_with_higher_fees() {
let (secp_ctx, network_graph, _, _, 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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes));
// Without penalizing each hop 100 msats, a longer path with lower fees is chosen.
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
// Applying a 100 msat penalty to each hop results in taking channels 7 and 10 to nodes[6]
// from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper.
- let scorer = ln_test_utils::TestScorer::with_penalty(100);
+ let scorer = FixedPenaltyScorer::with_penalty(100);
let route = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 100, 42,
Arc::clone(&logger), &scorer, &random_seed_bytes
fn avoids_routing_through_bad_channels_and_nodes() {
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).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 = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
// Make sure that generally there is at least one route available
let feasible_max_total_cltv_delta = 1008;
- let feasible_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
+ let feasible_payment_params = PaymentParameters::from_node_id(nodes[6], 0).with_route_hints(last_hops(&nodes))
.with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// But not if we exclude all paths on the basis of their accumulated CLTV delta
let fail_max_total_cltv_delta = 23;
- let fail_payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
+ let fail_payment_params = PaymentParameters::from_node_id(nodes[6], 0).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, 0, Arc::clone(&logger), &scorer, &random_seed_bytes)
{
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
- let mut payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes))
+ let scorer = ln_test_utils::TestScorer::new();
+ let mut payment_params = PaymentParameters::from_node_id(nodes[6], 0).with_route_hints(last_hops(&nodes))
.with_max_path_count(1);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
let network_graph = network.read_only();
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// First check we can actually create a long route on this graph.
- let feasible_payment_params = PaymentParameters::from_node_id(nodes[18]);
+ let feasible_payment_params = PaymentParameters::from_node_id(nodes[18], 0);
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!(path.len() == MAX_PATH_LENGTH_ESTIMATE.into());
// But we can't create a path surpassing the MAX_PATH_LENGTH_ESTIMATE limit.
- let fail_payment_params = PaymentParameters::from_node_id(nodes[19]);
+ let fail_payment_params = PaymentParameters::from_node_id(nodes[19], 0);
match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, 0,
Arc::clone(&logger), &scorer, &random_seed_bytes)
{
let (secp_ctx, network_graph, _, _, logger) = build_graph();
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
+ let scorer = ln_test_utils::TestScorer::new();
- let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops(&nodes));
+ let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes));
let keys_manager = ln_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();
let network_graph = network.read_only();
let network_nodes = network_graph.nodes();
let network_channels = network_graph.channels();
- let scorer = ln_test_utils::TestScorer::with_penalty(0);
- let payment_params = PaymentParameters::from_node_id(nodes[3]);
+ let scorer = ln_test_utils::TestScorer::new();
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let keys_manager = ln_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]);
+ let payment_params = PaymentParameters::from_node_id(nodes[3], 0);
let hops = [nodes[1], nodes[2], nodes[4], nodes[3]];
let route = build_route_from_hops_internal(&our_id, &hops, &payment_params,
&network_graph, 100, 0, Arc::clone(&logger), &random_seed_bytes).unwrap();
});
let config = UserConfig::default();
- let payment_params = PaymentParameters::from_node_id(nodes[2]).with_features(channelmanager::provided_invoice_features(&config));
+ let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config));
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// 100,000 sats is less than the available liquidity on each channel, set above.
'load_endpoints: for _ in 0..10 {
loop {
seed = seed.overflowing_mul(0xdeadbeef).0;
- let src = &PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let src = &PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
seed = seed.overflowing_mul(0xdeadbeef).0;
- let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
- let payment_params = PaymentParameters::from_node_id(dst);
+ let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let payment_params = PaymentParameters::from_node_id(dst, 42);
let amt = seed as u64 % 200_000_000;
let params = ProbabilisticScoringParameters::default();
let scorer = ProbabilisticScorer::new(params, &graph, &logger);
'load_endpoints: for _ in 0..10 {
loop {
seed = seed.overflowing_mul(0xdeadbeef).0;
- let src = &PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let src = &PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
seed = seed.overflowing_mul(0xdeadbeef).0;
- let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
- let payment_params = PaymentParameters::from_node_id(dst).with_features(channelmanager::provided_invoice_features(&config));
+ let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let payment_params = PaymentParameters::from_node_id(dst, 42).with_features(channelmanager::provided_invoice_features(&config));
let amt = seed as u64 % 200_000_000;
let params = ProbabilisticScoringParameters::default();
let scorer = ProbabilisticScorer::new(params, &graph, &logger);
assert_eq!(scorer.channel_penalty_msat(42, &NodeId::from_pubkey(&nodes[3]), &NodeId::from_pubkey(&nodes[4]), usage), 456);
// Then check we can get a normal route
- let payment_params = PaymentParameters::from_node_id(nodes[10]);
+ let payment_params = PaymentParameters::from_node_id(nodes[10], 42);
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes);
assert!(route.is_ok());
use std::fs::File;
/// Tries to open a network graph file, or panics with a URL to fetch it.
pub(crate) fn get_route_file() -> Result<std::fs::File, &'static str> {
- let res = File::open("net_graph-2021-05-31.bin") // By default we're run in RL/lightning
- .or_else(|_| File::open("lightning/net_graph-2021-05-31.bin")) // We may be run manually in RL/
+ let res = File::open("net_graph-2023-01-18.bin") // By default we're run in RL/lightning
+ .or_else(|_| File::open("lightning/net_graph-2023-01-18.bin")) // We may be run manually in RL/
.or_else(|_| { // Fall back to guessing based on the binary location
// path is likely something like .../rust-lightning/target/debug/deps/lightning-...
let mut path = std::env::current_exe().unwrap();
path.pop(); // debug
path.pop(); // target
path.push("lightning");
- path.push("net_graph-2021-05-31.bin");
+ path.push("net_graph-2023-01-18.bin");
eprintln!("{}", path.to_str().unwrap());
File::open(path)
})
- .map_err(|_| "Please fetch https://bitcoin.ninja/ldk-net_graph-v0.0.15-2021-05-31.bin and place it at lightning/net_graph-2021-05-31.bin");
+ .map_err(|_| "Please fetch https://bitcoin.ninja/ldk-net_graph-v0.0.113-2023-01-18.bin and place it at lightning/net_graph-2023-01-18.bin");
#[cfg(require_route_graph_test)]
return Ok(res.unwrap());
#[cfg(not(require_route_graph_test))]
'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();
+ let src = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
seed *= 0xdeadbeef;
- let dst = PublicKey::from_slice(nodes.keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
- let params = PaymentParameters::from_node_id(dst).with_features(features.clone());
+ let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let params = PaymentParameters::from_node_id(dst, 42).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, ¶ms, &graph.read_only(), Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes) {