Skip to content

Commit 52497a2

Browse files
committed
f: test blinded Trampoline path failure
1 parent 5d39f1a commit 52497a2

File tree

1 file changed

+168
-1
lines changed

1 file changed

+168
-1
lines changed

lightning/src/ln/blinded_payment_tests.rs

+168-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub fn fail_blinded_htlc_backwards(
130130
let unblinded_node_updates = get_htlc_update_msgs!(nodes[i], nodes[i-1].node.get_our_node_id());
131131
assert_eq!(unblinded_node_updates.update_fail_htlcs.len(), 1);
132132
nodes[i-1].node.handle_update_fail_htlc(
133-
nodes[i].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[i-1]
133+
nodes[i].node.get_our_node_id(), &unblinded_node_updates.update_fail_htlcs[0]
134134
);
135135
do_commitment_signed_dance(&nodes[i-1], &nodes[i], &unblinded_node_updates.commitment_signed, false, false);
136136
},
@@ -2061,3 +2061,170 @@ fn test_successful_trampoline_single_hop_receive() {
20612061
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], amt_msat, payment_hash, payment_secret);
20622062
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
20632063
}
2064+
2065+
#[test]
2066+
#[cfg(trampoline)]
2067+
fn test_trampoline_blinded_decoding_failure() {
2068+
// Simulate a payment failure of A (0) -> B (1) -> C(Trampoline (blinded forward)) (2)
2069+
2070+
const TOTAL_NODE_COUNT: usize = 3;
2071+
let secp_ctx = Secp256k1::new();
2072+
2073+
let chanmon_cfgs = create_chanmon_cfgs(TOTAL_NODE_COUNT);
2074+
let node_cfgs = create_node_cfgs(TOTAL_NODE_COUNT, &chanmon_cfgs);
2075+
let node_chanmgrs = create_node_chanmgrs(TOTAL_NODE_COUNT, &node_cfgs, &vec![None; TOTAL_NODE_COUNT]);
2076+
let mut nodes = create_network(TOTAL_NODE_COUNT, &node_cfgs, &node_chanmgrs);
2077+
2078+
let (_, _, chan_id_alice_bob, _) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
2079+
let (_, _, chan_id_bob_carol, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0);
2080+
2081+
for i in 0..TOTAL_NODE_COUNT { // connect all nodes' blocks
2082+
connect_blocks(&nodes[i], (TOTAL_NODE_COUNT as u32) * CHAN_CONFIRM_DEPTH + 1 - nodes[i].best_block_info().1);
2083+
}
2084+
2085+
let alice_node_id = nodes[0].node().get_our_node_id();
2086+
let bob_node_id = nodes[1].node().get_our_node_id();
2087+
let carol_node_id = nodes[2].node().get_our_node_id();
2088+
2089+
let alice_bob_scid = nodes[0].node().list_channels().iter().find(|c| c.channel_id == chan_id_alice_bob).unwrap().short_channel_id.unwrap();
2090+
let bob_carol_scid = nodes[1].node().list_channels().iter().find(|c| c.channel_id == chan_id_bob_carol).unwrap().short_channel_id.unwrap();
2091+
2092+
let amt_msat = 1000;
2093+
let (payment_preimage, payment_hash, _) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
2094+
let payee_tlvs = blinded_path::payment::TrampolineForwardTlvs {
2095+
next_trampoline: alice_node_id,
2096+
payment_constraints: PaymentConstraints {
2097+
max_cltv_expiry: u32::max_value(),
2098+
htlc_minimum_msat: amt_msat,
2099+
},
2100+
features: BlindedHopFeatures::empty(),
2101+
payment_relay: PaymentRelay {
2102+
cltv_expiry_delta: 0,
2103+
fee_proportional_millionths: 0,
2104+
fee_base_msat: 0,
2105+
},
2106+
next_blinding_override: None,
2107+
};
2108+
2109+
let carol_unblinded_tlvs = payee_tlvs.encode();
2110+
let path = [(carol_node_id, WithoutLength(&carol_unblinded_tlvs))];
2111+
let carol_alice_trampoline_session_priv = secret_from_hex("a0f4b8d7b6c2d0ffdfaf718f76e9decaef4d9fb38a8c4addb95c4007cc3eee03");
2112+
let carol_blinding_point = PublicKey::from_secret_key(&secp_ctx, &carol_alice_trampoline_session_priv);
2113+
let carol_blinded_hops = blinded_path::utils::construct_blinded_hops(
2114+
&secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv
2115+
).unwrap();
2116+
2117+
let route = Route {
2118+
paths: vec![Path {
2119+
hops: vec![
2120+
// Bob
2121+
RouteHop {
2122+
pubkey: bob_node_id,
2123+
node_features: NodeFeatures::empty(),
2124+
short_channel_id: alice_bob_scid,
2125+
channel_features: ChannelFeatures::empty(),
2126+
fee_msat: 1000,
2127+
cltv_expiry_delta: 48,
2128+
maybe_announced_channel: false,
2129+
},
2130+
2131+
// Carol
2132+
RouteHop {
2133+
pubkey: carol_node_id,
2134+
node_features: NodeFeatures::empty(),
2135+
short_channel_id: bob_carol_scid,
2136+
channel_features: ChannelFeatures::empty(),
2137+
fee_msat: 0,
2138+
cltv_expiry_delta: 48,
2139+
maybe_announced_channel: false,
2140+
}
2141+
],
2142+
blinded_tail: Some(BlindedTail {
2143+
trampoline_hops: vec![
2144+
// Carol
2145+
TrampolineHop {
2146+
pubkey: carol_node_id,
2147+
node_features: Features::empty(),
2148+
fee_msat: amt_msat,
2149+
cltv_expiry_delta: 24,
2150+
},
2151+
],
2152+
hops: carol_blinded_hops,
2153+
blinding_point: carol_blinding_point,
2154+
excess_final_cltv_expiry_delta: 39,
2155+
final_value_msat: amt_msat,
2156+
})
2157+
}],
2158+
route_params: None,
2159+
};
2160+
2161+
nodes[0].node.send_payment_with_route(route.clone(), payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0)).unwrap();
2162+
2163+
let replacement_onion = {
2164+
// create a substitute onion where the last Trampoline hop is a forward
2165+
let trampoline_secret_key = secret_from_hex("0134928f7b7ca6769080d70f16be84c812c741f545b49a34db47ce338a205799");
2166+
let prng_seed = secret_from_hex("fe02b4b9054302a3ddf4e1e9f7c411d644aebbd295218ab009dca94435f775a9");
2167+
let recipient_onion_fields = RecipientOnionFields::spontaneous_empty();
2168+
2169+
let mut blinded_tail = route.paths[0].blinded_tail.clone().unwrap();
2170+
2171+
// append some dummy blinded hop so the intro hop looks like a forward
2172+
blinded_tail.hops.push(BlindedHop {
2173+
blinded_node_id: alice_node_id,
2174+
encrypted_payload: vec![],
2175+
});
2176+
2177+
let (mut trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) = onion_utils::build_trampoline_onion_payloads(&blinded_tail, amt_msat, &recipient_onion_fields, 32, &None).unwrap();
2178+
2179+
// pop the last dummy hop
2180+
trampoline_payloads.pop();
2181+
2182+
let trampoline_onion_keys = onion_utils::construct_trampoline_onion_keys(&secp_ctx, &route.paths[0].blinded_tail.as_ref().unwrap(), &trampoline_secret_key).unwrap();
2183+
let trampoline_packet = onion_utils::construct_trampoline_onion_packet(
2184+
trampoline_payloads,
2185+
trampoline_onion_keys,
2186+
prng_seed.secret_bytes(),
2187+
&payment_hash,
2188+
None,
2189+
).unwrap();
2190+
2191+
let outer_session_priv = secret_from_hex("e52c20461ed7acd46c4e7b591a37610519179482887bd73bf3b94617f8f03677");
2192+
2193+
let (outer_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], outer_total_msat, &recipient_onion_fields, outer_starting_htlc_offset, &None, None, Some(trampoline_packet)).unwrap();
2194+
let outer_onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.clone().paths[0], &outer_session_priv).unwrap();
2195+
let outer_packet = onion_utils::construct_onion_packet(
2196+
outer_payloads,
2197+
outer_onion_keys,
2198+
prng_seed.secret_bytes(),
2199+
&payment_hash,
2200+
).unwrap();
2201+
2202+
outer_packet
2203+
};
2204+
2205+
check_added_monitors!(&nodes[0], 1);
2206+
2207+
// Check that we've queued the HTLCs of the async keysend payment.
2208+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
2209+
assert_eq!(events.len(), 1);
2210+
let mut first_message_event = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
2211+
let mut update_message = match first_message_event {
2212+
MessageSendEvent::UpdateHTLCs { ref mut updates, .. } => {
2213+
assert_eq!(updates.update_add_htlcs.len(), 1);
2214+
updates.update_add_htlcs.get_mut(0)
2215+
},
2216+
_ => panic!()
2217+
};
2218+
update_message.map(|msg| {
2219+
msg.onion_routing_packet = replacement_onion.clone();
2220+
});
2221+
2222+
let route: &[&Node] = &[&nodes[1], &nodes[2]];
2223+
let args = PassAlongPathArgs::new(&nodes[0], route, amt_msat, payment_hash, first_message_event)
2224+
.with_payment_preimage(payment_preimage)
2225+
.without_claimable_event()
2226+
.expect_failure(HTLCDestination::InvalidOnion);
2227+
do_pass_along_path(args);
2228+
2229+
fail_blinded_htlc_backwards(payment_hash, 1, &[&nodes[0], &nodes[1], &nodes[2]], false);
2230+
}

0 commit comments

Comments
 (0)