Skip to content

Commit 797a648

Browse files
committed
Merge branch '2022-02-fix-multi-hop-hint-panic' into 2022-02-0.0.105-sec
2 parents 82b8d85 + bd1b761 commit 797a648

File tree

1 file changed

+91
-25
lines changed

1 file changed

+91
-25
lines changed

lightning/src/routing/router.rs

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -893,8 +893,8 @@ where L::Target: Logger {
893893
// semi-dummy record just to compute the fees to reach the source node.
894894
// This will affect our decision on selecting short_channel_id
895895
// as a way to reach the $dest_node_id.
896-
let mut fee_base_msat = u32::max_value();
897-
let mut fee_proportional_millionths = u32::max_value();
896+
let mut fee_base_msat = 0;
897+
let mut fee_proportional_millionths = 0;
898898
if let Some(Some(fees)) = network_nodes.get(&$src_node_id).map(|node| node.lowest_inbound_channel_fees) {
899899
fee_base_msat = fees.base_msat;
900900
fee_proportional_millionths = fees.proportional_millionths;
@@ -1285,11 +1285,9 @@ where L::Target: Logger {
12851285
ordered_hops.last_mut().unwrap().1 = NodeFeatures::empty();
12861286
}
12871287
} else {
1288-
// We should be able to fill in features for everything except the last
1289-
// hop, if the last hop was provided via a BOLT 11 invoice (though we
1290-
// should be able to extend it further as BOLT 11 does have feature
1291-
// flags for the last hop node itself).
1292-
assert!(ordered_hops.last().unwrap().0.node_id == payee_node_id);
1288+
// We can fill in features for everything except hops which were
1289+
// provided via the invoice we're paying. We could guess based on the
1290+
// recipient's features but for now we simply avoid guessing at all.
12931291
}
12941292
}
12951293

@@ -1671,7 +1669,7 @@ mod tests {
16711669

16721670
fn get_nodes(secp_ctx: &Secp256k1<All>) -> (SecretKey, PublicKey, Vec<SecretKey>, Vec<PublicKey>) {
16731671
let privkeys: Vec<SecretKey> = (2..10).map(|i| {
1674-
SecretKey::from_slice(&hex::decode(format!("{:02}", i).repeat(32)).unwrap()[..]).unwrap()
1672+
SecretKey::from_slice(&hex::decode(format!("{:02x}", i).repeat(32)).unwrap()[..]).unwrap()
16751673
}).collect();
16761674

16771675
let pubkeys = privkeys.iter().map(|secret| PublicKey::from_secret_key(&secp_ctx, secret)).collect();
@@ -2697,14 +2695,16 @@ mod tests {
26972695
assert_eq!(route.paths[0][4].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
26982696
}
26992697

2700-
fn multi_hint_last_hops(nodes: &Vec<PublicKey>) -> Vec<RouteHint> {
2698+
/// Builds a trivial last-hop hint that passes through the two nodes given, with channel 0xff00
2699+
/// and 0xff01.
2700+
fn multi_hop_last_hops_hint(hint_hops: [PublicKey; 2]) -> Vec<RouteHint> {
27012701
let zero_fees = RoutingFees {
27022702
base_msat: 0,
27032703
proportional_millionths: 0,
27042704
};
27052705
vec![RouteHint(vec![RouteHintHop {
2706-
src_node_id: nodes[2],
2707-
short_channel_id: 5,
2706+
src_node_id: hint_hops[0],
2707+
short_channel_id: 0xff00,
27082708
fees: RoutingFees {
27092709
base_msat: 100,
27102710
proportional_millionths: 0,
@@ -2713,29 +2713,23 @@ mod tests {
27132713
htlc_minimum_msat: None,
27142714
htlc_maximum_msat: None,
27152715
}, RouteHintHop {
2716-
src_node_id: nodes[3],
2717-
short_channel_id: 8,
2716+
src_node_id: hint_hops[1],
2717+
short_channel_id: 0xff01,
27182718
fees: zero_fees,
27192719
cltv_expiry_delta: (8 << 4) | 1,
27202720
htlc_minimum_msat: None,
27212721
htlc_maximum_msat: None,
2722-
}]), RouteHint(vec![RouteHintHop {
2723-
src_node_id: nodes[5],
2724-
short_channel_id: 10,
2725-
fees: zero_fees,
2726-
cltv_expiry_delta: (10 << 4) | 1,
2727-
htlc_minimum_msat: None,
2728-
htlc_maximum_msat: None,
27292722
}])]
27302723
}
27312724

27322725
#[test]
27332726
fn multi_hint_last_hops_test() {
27342727
let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
27352728
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
2736-
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(multi_hint_last_hops(&nodes));
2729+
let last_hops = multi_hop_last_hops_hint([nodes[2], nodes[3]]);
2730+
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
27372731
let scorer = test_utils::TestScorer::with_penalty(0);
2738-
// Test through channels 2, 3, 5, 8.
2732+
// Test through channels 2, 3, 0xff00, 0xff01.
27392733
// Test shows that multiple hop hints are considered.
27402734

27412735
// Disabling channels 6 & 7 by flags=2
@@ -2782,14 +2776,86 @@ mod tests {
27822776
assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
27832777

27842778
assert_eq!(route.paths[0][2].pubkey, nodes[3]);
2785-
assert_eq!(route.paths[0][2].short_channel_id, 5);
2779+
assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
27862780
assert_eq!(route.paths[0][2].fee_msat, 0);
27872781
assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
27882782
assert_eq!(route.paths[0][2].node_features.le_flags(), &id_to_feature_flags(4));
2789-
assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new());
2783+
assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
2784+
2785+
assert_eq!(route.paths[0][3].pubkey, nodes[6]);
2786+
assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
2787+
assert_eq!(route.paths[0][3].fee_msat, 100);
2788+
assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
2789+
assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
2790+
assert_eq!(route.paths[0][3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
2791+
}
2792+
2793+
#[test]
2794+
fn private_multi_hint_last_hops_test() {
2795+
let (secp_ctx, network_graph, net_graph_msg_handler, _, logger) = build_graph();
2796+
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
2797+
2798+
let non_announced_privkey = SecretKey::from_slice(&hex::decode(format!("{:02x}", 0xf0).repeat(32)).unwrap()[..]).unwrap();
2799+
let non_announced_pubkey = PublicKey::from_secret_key(&secp_ctx, &non_announced_privkey);
2800+
2801+
let last_hops = multi_hop_last_hops_hint([nodes[2], non_announced_pubkey]);
2802+
let payment_params = PaymentParameters::from_node_id(nodes[6]).with_route_hints(last_hops.clone());
2803+
let scorer = test_utils::TestScorer::with_penalty(0);
2804+
// Test through channels 2, 3, 0xff00, 0xff01.
2805+
// Test shows that multiple hop hints are considered.
2806+
2807+
// Disabling channels 6 & 7 by flags=2
2808+
update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
2809+
chain_hash: genesis_block(Network::Testnet).header.block_hash(),
2810+
short_channel_id: 6,
2811+
timestamp: 2,
2812+
flags: 2, // to disable
2813+
cltv_expiry_delta: 0,
2814+
htlc_minimum_msat: 0,
2815+
htlc_maximum_msat: OptionalField::Absent,
2816+
fee_base_msat: 0,
2817+
fee_proportional_millionths: 0,
2818+
excess_data: Vec::new()
2819+
});
2820+
update_channel(&net_graph_msg_handler, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
2821+
chain_hash: genesis_block(Network::Testnet).header.block_hash(),
2822+
short_channel_id: 7,
2823+
timestamp: 2,
2824+
flags: 2, // to disable
2825+
cltv_expiry_delta: 0,
2826+
htlc_minimum_msat: 0,
2827+
htlc_maximum_msat: OptionalField::Absent,
2828+
fee_base_msat: 0,
2829+
fee_proportional_millionths: 0,
2830+
excess_data: Vec::new()
2831+
});
2832+
2833+
let route = get_route(&our_id, &payment_params, &network_graph, None, 100, 42, Arc::clone(&logger), &scorer).unwrap();
2834+
assert_eq!(route.paths[0].len(), 4);
2835+
2836+
assert_eq!(route.paths[0][0].pubkey, nodes[1]);
2837+
assert_eq!(route.paths[0][0].short_channel_id, 2);
2838+
assert_eq!(route.paths[0][0].fee_msat, 200);
2839+
assert_eq!(route.paths[0][0].cltv_expiry_delta, 65);
2840+
assert_eq!(route.paths[0][0].node_features.le_flags(), &id_to_feature_flags(2));
2841+
assert_eq!(route.paths[0][0].channel_features.le_flags(), &id_to_feature_flags(2));
2842+
2843+
assert_eq!(route.paths[0][1].pubkey, nodes[2]);
2844+
assert_eq!(route.paths[0][1].short_channel_id, 4);
2845+
assert_eq!(route.paths[0][1].fee_msat, 100);
2846+
assert_eq!(route.paths[0][1].cltv_expiry_delta, 81);
2847+
assert_eq!(route.paths[0][1].node_features.le_flags(), &id_to_feature_flags(3));
2848+
assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(4));
2849+
2850+
assert_eq!(route.paths[0][2].pubkey, non_announced_pubkey);
2851+
assert_eq!(route.paths[0][2].short_channel_id, last_hops[0].0[0].short_channel_id);
2852+
assert_eq!(route.paths[0][2].fee_msat, 0);
2853+
assert_eq!(route.paths[0][2].cltv_expiry_delta, 129);
2854+
assert_eq!(route.paths[0][2].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
2855+
assert_eq!(route.paths[0][2].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
27902856

27912857
assert_eq!(route.paths[0][3].pubkey, nodes[6]);
2792-
assert_eq!(route.paths[0][3].short_channel_id, 8);
2858+
assert_eq!(route.paths[0][3].short_channel_id, last_hops[0].0[1].short_channel_id);
27932859
assert_eq!(route.paths[0][3].fee_msat, 100);
27942860
assert_eq!(route.paths[0][3].cltv_expiry_delta, 42);
27952861
assert_eq!(route.paths[0][3].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet

0 commit comments

Comments
 (0)