Move the final CLTV delta to PaymentParameters from RouteParams

`PaymentParams` is all about the parameters for a payment, i.e. the
parameters which are static across all the paths of a paymet.
`RouteParameters` is about the information specific to a given
`Route` (i.e. a set of paths, among multiple potential sets of
paths for a payment). The CLTV delta thus doesn't belong in
`RouterParameters` but instead in `PaymentParameters`.

Worse, because `RouteParameters` is built from the information in
the last hops of a `Route`, when we deliberately inflate the CLTV
delta in path-finding, retries of the payment will have the final
CLTV delta double-inflated as it inflates starting from the final
CLTV delta used in the last attempt.

By moving the CLTV delta to `PaymentParameters` we avoid this
issue, leaving only the sought amount in the `RouteParameters`.
This commit is contained in:
Matt Corallo 2023-01-27 19:24:52 +00:00
parent d4de913ae7
commit fbc08477e8
13 changed files with 143 additions and 113 deletions

View file

@ -512,7 +512,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
},
4 => {
let final_value_msat = slice_to_be24(get_slice!(3)) as u64;
let payment_params = PaymentParameters::from_node_id(get_pubkey!());
let payment_params = PaymentParameters::from_node_id(get_pubkey!(), 42);
let params = RouteParameters {
payment_params,
final_value_msat,
@ -536,7 +536,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
},
15 => {
let final_value_msat = slice_to_be24(get_slice!(3)) as u64;
let payment_params = PaymentParameters::from_node_id(get_pubkey!());
let payment_params = PaymentParameters::from_node_id(get_pubkey!(), 42);
let params = RouteParameters {
payment_params,
final_value_msat,

View file

@ -263,10 +263,13 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let scorer = FixedPenaltyScorer::with_penalty(0);
let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32];
for target in node_pks.iter() {
let final_value_msat = slice_to_be64(get_slice!(8));
let final_cltv_expiry_delta = slice_to_be32(get_slice!(4));
let route_params = RouteParameters {
payment_params: PaymentParameters::from_node_id(*target).with_route_hints(last_hops.clone()),
final_value_msat: slice_to_be64(get_slice!(8)),
final_cltv_expiry_delta: slice_to_be32(get_slice!(4)),
payment_params: PaymentParameters::from_node_id(*target, final_cltv_expiry_delta)
.with_route_hints(last_hops.clone()),
final_value_msat,
final_cltv_expiry_delta,
};
let _ = find_route(&our_pubkey, &route_params, &net_graph,
first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),

View file

@ -422,7 +422,8 @@ where
};
let payment_secret = Some(invoice.payment_secret().clone());
let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(),
invoice.min_final_cltv_expiry_delta() as u32)
.with_expiry_time(expiry_time_from_unix_epoch(&invoice).as_secs())
.with_route_hints(invoice.route_hints());
if let Some(features) = invoice.features() {
@ -486,7 +487,7 @@ where
};
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(pubkey),
payment_params: PaymentParameters::for_keysend(pubkey, final_cltv_expiry_delta),
final_value_msat: amount_msats,
final_cltv_expiry_delta,
};
@ -1377,7 +1378,7 @@ mod tests {
assert_eq!(*payer.attempts.borrow(), 1);
let retry = RouteParameters {
payment_params: PaymentParameters::for_keysend(pubkey),
payment_params: PaymentParameters::for_keysend(pubkey, final_cltv_expiry_delta),
final_value_msat,
final_cltv_expiry_delta,
};
@ -1655,7 +1656,8 @@ mod tests {
}
fn retry_for_invoice(invoice: &Invoice) -> RouteParameters {
let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
let mut payment_params = PaymentParameters::from_node_id(
invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry_delta() as u32)
.with_expiry_time(expiry_time_from_unix_epoch(invoice).as_secs())
.with_route_hints(invoice.route_hints());
if let Some(features) = invoice.features() {
@ -2071,7 +2073,7 @@ mod tests {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 100)),
};
let router = ManualRouter(RefCell::new(VecDeque::new()));
router.expect_find_route(Ok(route.clone()));
@ -2114,7 +2116,7 @@ mod tests {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 100)),
};
let router = ManualRouter(RefCell::new(VecDeque::new()));
router.expect_find_route(Ok(route.clone()));
@ -2194,7 +2196,7 @@ mod tests {
cltv_expiry_delta: 100,
}]
],
payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 100)),
};
let router = ManualRouter(RefCell::new(VecDeque::new()));
router.expect_find_route(Ok(route.clone()));

View file

@ -724,7 +724,8 @@ mod test {
assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan.inbound_htlc_minimum_msat);
assert_eq!(invoice.route_hints()[0].0[0].htlc_maximum_msat, chan.inbound_htlc_maximum_msat);
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(),
invoice.min_final_cltv_expiry_delta() as u32)
.with_features(invoice.features().unwrap().clone())
.with_route_hints(invoice.route_hints());
let route_params = RouteParameters {
@ -1087,7 +1088,8 @@ mod test {
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
assert!(!invoice.features().unwrap().supports_basic_mpp());
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(),
invoice.min_final_cltv_expiry_delta() as u32)
.with_features(invoice.features().unwrap().clone())
.with_route_hints(invoice.route_hints());
let params = RouteParameters {

View file

@ -7871,7 +7871,7 @@ mod tests {
// Next, attempt a keysend payment and make sure it fails.
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id()),
payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV),
final_value_msat: 100_000,
final_cltv_expiry_delta: TEST_FINAL_CLTV,
};
@ -7964,7 +7964,7 @@ mod tests {
let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
final_value_msat: 10_000,
final_cltv_expiry_delta: 40,
};
@ -8009,7 +8009,7 @@ mod tests {
let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
final_value_msat: 10_000,
final_cltv_expiry_delta: 40,
};
@ -8574,7 +8574,7 @@ pub mod bench {
macro_rules! send_payment {
($node_a: expr, $node_b: expr) => {
let usable_channels = $node_a.list_usable_channels();
let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id())
let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id(), TEST_FINAL_CLTV)
.with_features($node_b.invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let seed = [3u8; 32];

View file

@ -1484,7 +1484,7 @@ macro_rules! get_route {
#[macro_export]
macro_rules! get_route_and_payment_hash {
($send_node: expr, $recv_node: expr, $recv_value: expr) => {{
let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id())
let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features($recv_node.node.invoice_features());
$crate::get_route_and_payment_hash!($send_node, $recv_node, payment_params, $recv_value, TEST_FINAL_CLTV)
}};
@ -2096,7 +2096,7 @@ pub fn claim_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route:
pub const TEST_FINAL_CLTV: u32 = 70;
pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) {
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(expected_route.last().unwrap().node.invoice_features());
let route = get_route!(origin_node, payment_params, recv_value, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.paths.len(), 1);
@ -2110,7 +2110,7 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route:
}
pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) {
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(expected_route.last().unwrap().node.invoice_features());
let network_graph = origin_node.network_graph.read_only();
let scorer = test_utils::TestScorer::with_penalty(0);

View file

@ -1802,7 +1802,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
// attempt to send amt_msat > their_max_htlc_value_in_flight_msat
{
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[2].node.invoice_features()).with_max_channel_saturation_power_of_half(0);
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, recv_value_0, TEST_FINAL_CLTV);
route.paths[0].last_mut().unwrap().fee_msat += 1;
@ -1827,7 +1827,7 @@ fn test_channel_reserve_holding_cell_htlcs() {
break;
}
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[2].node.invoice_features()).with_max_channel_saturation_power_of_half(0);
let route = get_route!(nodes[0], payment_params, recv_value_0, TEST_FINAL_CLTV).unwrap();
let (payment_preimage, ..) = send_along_route(&nodes[0], route, &[&nodes[1], &nodes[2]], recv_value_0);
@ -4716,7 +4716,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
// We reduce the final CLTV here by a somewhat arbitrary constant to keep it under the one-byte
// script push size limit so that the below script length checks match
// ACCEPTED_HTLC_SCRIPT_WEIGHT.
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id(), TEST_FINAL_CLTV - 40)
.with_features(nodes[3].node.invoice_features());
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[3], payment_params, 800_000, TEST_FINAL_CLTV - 40);
send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2], &nodes[3]]], 800_000, duplicate_payment_hash, payment_secret);
@ -6009,7 +6009,7 @@ fn test_update_add_htlc_bolt2_sender_cltv_expiry_too_high() {
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 0);
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 0)
.with_features(nodes[1].node.invoice_features());
let (mut route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], payment_params, 100000000, 0);
route.paths[0].last_mut().unwrap().cltv_expiry_delta = 500000001;
@ -6927,7 +6927,7 @@ fn test_check_htlc_underpaying() {
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(nodes[1].node.invoice_features());
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV).with_features(nodes[1].node.invoice_features());
let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
let (_, our_payment_hash, _) = get_payment_preimage_hash!(nodes[0]);
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None).unwrap();
@ -7068,7 +7068,7 @@ fn test_bump_penalty_txn_on_revoked_commitment() {
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000);
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), 30)
.with_features(nodes[0].node.invoice_features());
let (route,_, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_params, 3000000, 30);
send_along_route(&nodes[1], route, &vec!(&nodes[0])[..], 3000000);
@ -7174,13 +7174,13 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 59000000);
// Lock HTLC in both directions (using a slightly lower CLTV delay to provide timely RBF bumps)
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(nodes[1].node.invoice_features());
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), 50).with_features(nodes[1].node.invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None,
3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
let payment_preimage = send_along_route(&nodes[0], route, &[&nodes[1]], 3_000_000).0;
let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(nodes[0].node.invoice_features());
let payment_params = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), 50).with_features(nodes[0].node.invoice_features());
let route = get_route(&nodes[1].node.get_our_node_id(), &payment_params, &nodes[1].network_graph.read_only(), None,
3_000_000, 50, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
send_along_route(&nodes[1], route, &[&nodes[0]], 3_000_000);
@ -8976,7 +8976,7 @@ fn do_test_dup_htlc_second_rejected(test_for_second_fail_panic: bool) {
let _chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001);
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[1].node.invoice_features());
let route = get_route!(nodes[0], payment_params, 10_000, TEST_FINAL_CLTV).unwrap();
@ -9081,7 +9081,7 @@ fn test_inconsistent_mpp_params() {
create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 100_000, 0);
let chan_2_3 =create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 100_000, 0);
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[3].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[3].node.invoice_features());
let mut route = get_route!(nodes[0], payment_params, 15_000_000, TEST_FINAL_CLTV).unwrap();
assert_eq!(route.paths.len(), 2);
@ -9182,7 +9182,7 @@ fn test_keysend_payments_to_public_node() {
let payer_pubkey = nodes[0].node.get_our_node_id();
let payee_pubkey = nodes[1].node.get_our_node_id();
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
final_value_msat: 10000,
final_cltv_expiry_delta: 40,
};
@ -9215,7 +9215,7 @@ fn test_keysend_payments_to_private_node() {
let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
let route_params = RouteParameters {
payment_params: PaymentParameters::for_keysend(payee_pubkey),
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
final_value_msat: 10000,
final_cltv_expiry_delta: 40,
};
@ -9603,7 +9603,7 @@ fn do_payment_with_custom_min_final_cltv_expiry(valid_delta: bool, use_user_hash
create_chan_between_nodes(&nodes[0], &nodes[1]);
let payment_parameters = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id());
let payment_parameters = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), final_cltv_expiry_delta as u32);
let (payment_hash, payment_preimage, payment_secret) = if use_user_hash {
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1],
Some(recv_value), Some(min_final_cltv_expiry_delta));

View file

@ -655,7 +655,7 @@ fn do_test_onion_failure_stale_channel_update(announced_channel: bool) {
htlc_maximum_msat: None,
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(*channel_to_update_counterparty)
let payment_params = PaymentParameters::from_node_id(*channel_to_update_counterparty, TEST_FINAL_CLTV)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(hop_hints);
get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, PAYMENT_AMT, TEST_FINAL_CLTV)
@ -802,7 +802,7 @@ fn test_always_create_tlv_format_onion_payloads() {
create_announced_chan_between_nodes(&nodes, 0, 1);
create_announced_chan_between_nodes(&nodes, 1, 2);
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(InvoiceFeatures::empty());
let (route, _payment_hash, _payment_preimage, _payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 40000, TEST_FINAL_CLTV);
@ -902,7 +902,7 @@ macro_rules! get_phantom_route {
($nodes: expr, $amt: expr, $channel: expr) => {{
let phantom_pubkey = $nodes[1].keys_manager.get_node_id(Recipient::PhantomNode).unwrap();
let phantom_route_hint = $nodes[1].node.get_phantom_route_hints();
let payment_params = PaymentParameters::from_node_id(phantom_pubkey)
let payment_params = PaymentParameters::from_node_id(phantom_pubkey, TEST_FINAL_CLTV)
.with_features($nodes[1].node.invoice_features())
.with_route_hints(vec![RouteHint(vec![
RouteHintHop {

View file

@ -1149,8 +1149,9 @@ mod tests {
let past_expiry_time = std::time::SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() - 2;
let payment_params = PaymentParameters::from_node_id(
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()))
.with_expiry_time(past_expiry_time);
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()),
0
).with_expiry_time(past_expiry_time);
let expired_route_params = RouteParameters {
payment_params,
final_value_msat: 0,
@ -1187,7 +1188,7 @@ mod tests {
router.expect_find_route(Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }));
let payment_params = PaymentParameters::from_node_id(
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()));
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0);
let route_params = RouteParameters {
payment_params,
final_value_msat: 0,

View file

@ -919,7 +919,7 @@ fn get_ldk_payment_preimage() {
let expiry_secs = 60 * 60;
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(amt_msat), expiry_secs, None).unwrap();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[1].node.invoice_features());
let scorer = test_utils::TestScorer::with_penalty(0);
let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
@ -1033,7 +1033,7 @@ fn failed_probe_yields_event() {
create_announced_chan_between_nodes(&nodes, 0, 1);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 100000, 90000000);
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id());
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42);
let (route, _, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[2], &payment_params, 9_998_000, 42);
@ -1080,7 +1080,7 @@ fn onchain_failed_probe_yields_event() {
let chan_id = create_announced_chan_between_nodes(&nodes, 0, 1).2;
create_announced_chan_between_nodes(&nodes, 1, 2);
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id());
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42);
// Send a dust HTLC, which will be treated as if it timed out once the channel hits the chain.
let (route, _, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[2], &payment_params, 1_000, 42);
@ -1425,7 +1425,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
let amt_msat = 100_000;
let intercept_scid = nodes[1].node.get_intercept_scid();
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_route_hints(vec![
RouteHint(vec![RouteHintHop {
src_node_id: nodes[1].node.get_our_node_id(),
@ -1623,7 +1623,7 @@ fn do_automatic_retries(test: AutoRetry) {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -1805,7 +1805,7 @@ fn auto_retry_partial_failure() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -1844,7 +1844,7 @@ fn auto_retry_partial_failure() {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
let retry_1_route = Route {
paths: vec![
@ -1865,7 +1865,7 @@ fn auto_retry_partial_failure() {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
let retry_2_route = Route {
paths: vec![
@ -1878,7 +1878,7 @@ fn auto_retry_partial_failure() {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
nodes[0].router.expect_find_route(Ok(send_route));
nodes[0].router.expect_find_route(Ok(retry_1_route));
@ -2001,7 +2001,7 @@ fn auto_retry_zero_attempts_send_error() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -2039,7 +2039,7 @@ fn fails_paying_after_rejected_by_payee() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -2094,7 +2094,7 @@ fn retry_multi_path_single_failed_payment() {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
nodes[0].router.expect_find_route(Ok(route.clone()));
// On retry, split the payment across both channels.
@ -2112,7 +2112,7 @@ fn retry_multi_path_single_failed_payment() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -2149,7 +2149,7 @@ fn immediate_retry_on_failure() {
cltv_expiry_delta: 100,
}],
],
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
nodes[0].router.expect_find_route(Ok(route.clone()));
// On retry, split the payment across both channels.
@ -2169,7 +2169,7 @@ fn immediate_retry_on_failure() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {
@ -2241,7 +2241,7 @@ fn no_extra_retries_on_back_to_back_fail() {
cltv_expiry_delta: 100,
}]
],
payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())),
payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
};
nodes[0].router.expect_find_route(Ok(route.clone()));
// On retry, we'll only be asked for one path
@ -2258,7 +2258,7 @@ fn no_extra_retries_on_back_to_back_fail() {
invoice_features.set_variable_length_onion_required();
invoice_features.set_payment_secret_required();
invoice_features.set_basic_mpp_optional();
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_expiry_time(payment_expiry_secs as u64)
.with_features(invoice_features);
let route_params = RouteParameters {

View file

@ -66,7 +66,7 @@ fn test_priv_forwarding_rejection() {
htlc_maximum_msat: None,
}]);
let last_hops = vec![route_hint];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(last_hops);
let (route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 10_000, TEST_FINAL_CLTV);
@ -233,7 +233,7 @@ fn test_routed_scid_alias() {
htlc_maximum_msat: None,
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(hop_hints);
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 100_000, 42);
@ -388,7 +388,7 @@ fn test_inbound_scid_privacy() {
htlc_maximum_msat: None,
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(hop_hints.clone());
let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 100_000, 42);
@ -403,7 +403,7 @@ fn test_inbound_scid_privacy() {
// what channel we're talking about.
hop_hints[0].0[0].short_channel_id = last_hop[0].short_channel_id.unwrap();
let payment_params_2 = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params_2 = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(hop_hints);
let (route_2, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params_2, 100_000, 42);
@ -454,7 +454,7 @@ fn test_scid_alias_returned() {
htlc_maximum_msat: None,
htlc_minimum_msat: None,
}])];
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id())
let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), 42)
.with_features(nodes[2].node.invoice_features())
.with_route_hints(hop_hints);
let (mut route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], payment_params, 10_000, 42);

View file

@ -93,9 +93,9 @@ fn updates_shutdown_wait() {
let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[0]);
let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(nodes[1].node.invoice_features());
let payment_params_1 = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV).with_features(nodes[1].node.invoice_features());
let route_1 = get_route(&nodes[0].node.get_our_node_id(), &payment_params_1, &nodes[0].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id()).with_features(nodes[0].node.invoice_features());
let payment_params_2 = PaymentParameters::from_node_id(nodes[0].node.get_our_node_id(), TEST_FINAL_CLTV).with_features(nodes[0].node.invoice_features());
let route_2 = get_route(&nodes[1].node.get_our_node_id(), &payment_params_2, &nodes[1].network_graph.read_only(), None, 100000, TEST_FINAL_CLTV, &logger, &scorer, &random_seed_bytes).unwrap();
unwrap_send_err!(nodes[0].node.send_payment(&route_1, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)), true, APIError::ChannelUnavailable {..}, {});
unwrap_send_err!(nodes[1].node.send_payment(&route_2, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)), true, APIError::ChannelUnavailable {..}, {});

View file

@ -372,6 +372,9 @@ pub struct RouteParameters {
pub final_value_msat: u64,
/// The CLTV on the final hop of the failed payment path.
///
/// This field is deprecated, [`PaymentParameters::final_cltv_expiry_delta`] should be used
/// instead, if available.
pub final_cltv_expiry_delta: u32,
}
@ -452,6 +455,11 @@ pub struct PaymentParameters {
/// 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 field should always be set to `Some` and may be required in a future release.
pub final_cltv_expiry_delta: Option<u32>,
}
impl_writeable_tlv_based!(PaymentParameters, {
@ -463,11 +471,15 @@ impl_writeable_tlv_based!(PaymentParameters, {
(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, option),
});
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,
@ -477,12 +489,16 @@ impl PaymentParameters {
max_path_count: DEFAULT_MAX_PATH_COUNT,
max_channel_saturation_power_of_half: 2,
previously_failed_channels: Vec::new(),
final_cltv_expiry_delta: Some(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.
@ -948,8 +964,11 @@ pub fn find_route<L: Deref, GL: Deref, S: Score>(
) -> Result<Route, LightningError>
where L::Target: Logger, GL::Target: Logger {
let graph_lock = network_graph.read_only();
let final_cltv_expiry_delta =
if let Some(delta) = route_params.payment_params.final_cltv_expiry_delta { delta }
else { route_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)
@ -986,6 +1005,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});
}
if let Some(delta) = payment_params.final_cltv_expiry_delta {
debug_assert_eq!(delta, final_cltv_expiry_delta);
}
// The general routing idea is the following:
// 1. Fill first/last hops communicated by the caller.
@ -2165,7 +2187,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2198,7 +2220,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2220,7 +2242,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2348,7 +2370,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config));
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2486,7 +2508,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2546,7 +2568,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2596,7 +2618,7 @@ mod tests {
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);
@ -2622,7 +2644,7 @@ mod tests {
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);
@ -2746,13 +2768,13 @@ mod tests {
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);
@ -2822,7 +2844,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(empty_last_hop(&nodes));
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2902,7 +2924,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone());
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -2976,7 +2998,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone());
let scorer = ln_test_utils::TestScorer::with_penalty(0);
// Test through channels 2, 3, 0xff00, 0xff01.
// Test shows that multiple hop hints are considered.
@ -3082,7 +3104,7 @@ mod tests {
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 payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_with_public_channel(&nodes));
let scorer = ln_test_utils::TestScorer::with_penalty(0);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
@ -3141,7 +3163,7 @@ mod tests {
// 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);
@ -3162,7 +3184,7 @@ mod tests {
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);
@ -3255,7 +3277,7 @@ mod tests {
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 keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
@ -3322,7 +3344,7 @@ mod tests {
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}.
@ -3597,7 +3619,7 @@ mod tests {
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.
@ -3722,7 +3744,7 @@ mod tests {
let scorer = ln_test_utils::TestScorer::with_penalty(0);
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 {
@ -3771,7 +3793,7 @@ mod tests {
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:
@ -3931,7 +3953,7 @@ mod tests {
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}.
@ -4096,7 +4118,7 @@ mod tests {
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,
@ -4266,7 +4288,7 @@ mod tests {
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}.
@ -4448,7 +4470,7 @@ mod tests {
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,
@ -4540,7 +4562,7 @@ mod tests {
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:
@ -4701,7 +4723,7 @@ mod tests {
let scorer = ln_test_utils::TestScorer::with_penalty(0);
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 {
@ -4832,7 +4854,7 @@ mod tests {
let scorer = ln_test_utils::TestScorer::with_penalty(0);
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.
@ -4897,7 +4919,7 @@ mod tests {
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
@ -4966,7 +4988,7 @@ mod tests {
let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger));
let scorer = ln_test_utils::TestScorer::with_penalty(0);
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();
@ -5032,7 +5054,7 @@ mod tests {
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);
@ -5105,7 +5127,7 @@ mod tests {
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.
@ -5228,7 +5250,7 @@ mod tests {
// 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();
@ -5238,7 +5260,7 @@ mod tests {
// 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)
{
@ -5258,7 +5280,7 @@ mod tests {
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 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();
@ -5289,14 +5311,14 @@ mod tests {
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)
{
@ -5314,7 +5336,7 @@ mod tests {
let scorer = ln_test_utils::TestScorer::with_penalty(0);
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();
@ -5347,7 +5369,7 @@ mod tests {
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 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();
@ -5414,7 +5436,7 @@ mod tests {
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();
@ -5460,7 +5482,7 @@ mod tests {
});
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.
@ -5507,7 +5529,7 @@ mod tests {
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.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
let payment_params = PaymentParameters::from_node_id(dst);
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);
@ -5545,7 +5567,7 @@ mod tests {
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.unordered_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 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);
@ -5578,7 +5600,7 @@ mod tests {
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());
@ -5745,7 +5767,7 @@ mod benches {
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.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
let params = PaymentParameters::from_node_id(dst).with_features(features.clone());
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, &params, &graph.read_only(), Some(&[&first_hop]), amt, 42, &DummyLogger{}, &scorer, &random_seed_bytes) {