Skip to content

Commit 29c67d5

Browse files
Pathfinding: ignore blinded route hints where we are the intro node
See tests, but the fuzzer found several panics from not fully ignoring these hints. We should support these route hints eventually, but it will involve some reworking of the Path/BlindedTail structs.
1 parent b16d6a1 commit 29c67d5

File tree

1 file changed

+110
-1
lines changed

1 file changed

+110
-1
lines changed

lightning/src/routing/router.rs

+110-1
Original file line numberDiff line numberDiff line change
@@ -2083,7 +2083,7 @@ where L::Target: Logger {
20832083
// in the regular network graph.
20842084
first_hop_targets.get(&intro_node_id).is_some() ||
20852085
network_nodes.get(&intro_node_id).is_some();
2086-
if !have_intro_node_in_graph { continue }
2086+
if !have_intro_node_in_graph || our_node_id == intro_node_id { continue }
20872087
let candidate = if hint.1.blinded_hops.len() == 1 {
20882088
CandidateRouteHop::OneHopBlinded { hint, hint_idx }
20892089
} else { CandidateRouteHop::Blinded { hint, hint_idx } };
@@ -7170,6 +7170,115 @@ mod tests {
71707170
assert_eq!(route.get_total_fees(), blinded_payinfo.fee_base_msat as u64);
71717171
assert_eq!(route.get_total_amount(), amt_msat);
71727172
}
7173+
7174+
#[test]
7175+
fn we_are_intro_node_candidate_hops() {
7176+
// This previously led to a panic in the router because we'd generate a Path with only a
7177+
// BlindedTail and 0 unblinded hops, due to the only candidate hops being blinded route hints
7178+
// where the origin node is the intro node. We now fully disallow considering candidate hops
7179+
// where the origin node is the intro node.
7180+
let (secp_ctx, network_graph, _, _, logger) = build_graph();
7181+
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
7182+
let scorer = ln_test_utils::TestScorer::new();
7183+
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
7184+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
7185+
let config = UserConfig::default();
7186+
7187+
// Values are taken from the fuzz input that uncovered this panic.
7188+
let amt_msat = 21_7020_5185_1423_0019;
7189+
7190+
let blinded_path = BlindedPath {
7191+
introduction_node_id: our_id,
7192+
blinding_point: ln_test_utils::pubkey(42),
7193+
blinded_hops: vec![
7194+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
7195+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
7196+
],
7197+
};
7198+
let blinded_payinfo = BlindedPayInfo {
7199+
fee_base_msat: 5052_9027,
7200+
fee_proportional_millionths: 0,
7201+
htlc_minimum_msat: 21_7020_5185_1423_0019,
7202+
htlc_maximum_msat: 1844_6744_0737_0955_1615,
7203+
cltv_expiry_delta: 0,
7204+
features: BlindedHopFeatures::empty(),
7205+
};
7206+
let mut blinded_hints = vec![
7207+
(blinded_payinfo.clone(), blinded_path.clone()),
7208+
(blinded_payinfo.clone(), blinded_path.clone()),
7209+
];
7210+
blinded_hints[1].1.introduction_node_id = nodes[6];
7211+
7212+
let bolt12_features: Bolt12InvoiceFeatures = channelmanager::provided_invoice_features(&config).to_context();
7213+
let payment_params = PaymentParameters::blinded(blinded_hints.clone())
7214+
.with_bolt12_features(bolt12_features.clone()).unwrap();
7215+
7216+
let netgraph = network_graph.read_only();
7217+
let route_params = RouteParameters::from_payment_params_and_value(
7218+
payment_params, amt_msat);
7219+
if let Err(LightningError { err, .. }) = get_route(
7220+
&our_id, &route_params, &netgraph, None, Arc::clone(&logger), &scorer, &(), &random_seed_bytes
7221+
) {
7222+
assert_eq!(err, "Failed to find a path to the given destination");
7223+
} else { panic!() }
7224+
}
7225+
7226+
#[test]
7227+
fn we_are_intro_node_bp_in_final_path_fee_calc() {
7228+
// This previously led to a debug panic in the router because we'd find an invalid Path with
7229+
// 0 unblinded hops and a blinded tail, leading to the generation of a final
7230+
// PaymentPathHop::fee_msat that included both the blinded path fees and the final value of
7231+
// the payment, when it was intended to only include the final value of the payment.
7232+
let (secp_ctx, network_graph, _, _, logger) = build_graph();
7233+
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
7234+
let scorer = ln_test_utils::TestScorer::new();
7235+
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
7236+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
7237+
let config = UserConfig::default();
7238+
7239+
// Values are taken from the fuzz input that uncovered this panic.
7240+
let amt_msat = 21_7020_5185_1423_0019;
7241+
7242+
let blinded_path = BlindedPath {
7243+
introduction_node_id: our_id,
7244+
blinding_point: ln_test_utils::pubkey(42),
7245+
blinded_hops: vec![
7246+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
7247+
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
7248+
],
7249+
};
7250+
let blinded_payinfo = BlindedPayInfo {
7251+
fee_base_msat: 10_4425_1395,
7252+
fee_proportional_millionths: 0,
7253+
htlc_minimum_msat: 21_7301_9934_9094_0931,
7254+
htlc_maximum_msat: 1844_6744_0737_0955_1615,
7255+
cltv_expiry_delta: 0,
7256+
features: BlindedHopFeatures::empty(),
7257+
};
7258+
let mut blinded_hints = vec![
7259+
(blinded_payinfo.clone(), blinded_path.clone()),
7260+
(blinded_payinfo.clone(), blinded_path.clone()),
7261+
(blinded_payinfo.clone(), blinded_path.clone()),
7262+
];
7263+
blinded_hints[1].0.fee_base_msat = 5052_9027;
7264+
blinded_hints[1].0.htlc_minimum_msat = 21_7020_5185_1423_0019;
7265+
blinded_hints[1].0.htlc_maximum_msat = 1844_6744_0737_0955_1615;
7266+
7267+
blinded_hints[2].1.introduction_node_id = nodes[6];
7268+
7269+
let bolt12_features: Bolt12InvoiceFeatures = channelmanager::provided_invoice_features(&config).to_context();
7270+
let payment_params = PaymentParameters::blinded(blinded_hints.clone())
7271+
.with_bolt12_features(bolt12_features.clone()).unwrap();
7272+
7273+
let netgraph = network_graph.read_only();
7274+
let route_params = RouteParameters::from_payment_params_and_value(
7275+
payment_params, amt_msat);
7276+
if let Err(LightningError { err, .. }) = get_route(
7277+
&our_id, &route_params, &netgraph, None, Arc::clone(&logger), &scorer, &(), &random_seed_bytes
7278+
) {
7279+
assert_eq!(err, "Failed to find a path to the given destination");
7280+
} else { panic!() }
7281+
}
71737282
}
71747283

71757284
#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))]

0 commit comments

Comments
 (0)