Skip to content

Commit e81c46e

Browse files
committed
Consider trampoline hops for onion payload.
1 parent c05595b commit e81c46e

File tree

5 files changed

+108
-67
lines changed

5 files changed

+108
-67
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) {
299299
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
300300
let cur_height = nodes[0].best_block_info().1;
301301
let (mut onion_payloads, ..) = onion_utils::build_onion_payloads(
302-
&route.paths[0], amt_msat, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
302+
&route.paths[0], amt_msat, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
303303
// Remove the receive payload so the blinded forward payload is encoded as a final payload
304304
// (i.e. next_hop_hmac == [0; 32])
305305
onion_payloads.pop();
@@ -873,7 +873,7 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
873873
let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
874874
let cur_height = nodes[0].best_block_info().1;
875875
let (mut onion_payloads, ..) = onion_utils::build_onion_payloads(
876-
&route.paths[0], amt_msat, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
876+
&route.paths[0], amt_msat, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
877877

878878
let update_add = &mut payment_event_1_2.msgs[0];
879879
onion_payloads.last_mut().map(|p| {

lightning/src/ln/functional_tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ fn test_fee_spike_violation_fails_htlc() {
14051405

14061406
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
14071407
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0],
1408-
3460001, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap();
1408+
3460001, RecipientOnionFields::secret_only(payment_secret).into(), cur_height, &None).unwrap();
14091409
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
14101410
let msg = msgs::UpdateAddHTLC {
14111411
channel_id: chan.2,
@@ -1602,7 +1602,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
16021602
let cur_height = nodes[1].node.best_block.read().unwrap().height + 1;
16031603
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
16041604
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0],
1605-
700_000, RecipientOnionFields::secret_only(payment_secret), cur_height, &None).unwrap();
1605+
700_000, RecipientOnionFields::secret_only(payment_secret).into(), cur_height, &None).unwrap();
16061606
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
16071607
let msg = msgs::UpdateAddHTLC {
16081608
channel_id: chan.2,
@@ -1781,7 +1781,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
17811781
let cur_height = nodes[0].node.best_block.read().unwrap().height + 1;
17821782
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
17831783
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(
1784-
&route_2.paths[0], recv_value_2, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
1784+
&route_2.paths[0], recv_value_2, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
17851785
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1).unwrap();
17861786
let msg = msgs::UpdateAddHTLC {
17871787
channel_id: chan.2,
@@ -3505,7 +3505,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
35053505
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
35063506
let current_height = nodes[1].node.best_block.read().unwrap().height + 1;
35073507
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(
3508-
&route.paths[0], 50_000, RecipientOnionFields::secret_only(payment_secret), current_height, &None).unwrap();
3508+
&route.paths[0], 50_000, RecipientOnionFields::secret_only(payment_secret).into(), current_height, &None).unwrap();
35093509
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
35103510
let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
35113511

@@ -6491,7 +6491,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
64916491
let cur_height = nodes[0].node.best_block.read().unwrap().height + 1;
64926492
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
64936493
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(
6494-
&route.paths[0], send_amt, RecipientOnionFields::secret_only(our_payment_secret), cur_height, &None).unwrap();
6494+
&route.paths[0], send_amt, RecipientOnionFields::secret_only(our_payment_secret).into(), cur_height, &None).unwrap();
64956495
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap();
64966496

64976497
let mut msg = msgs::UpdateAddHTLC {
@@ -8223,7 +8223,7 @@ fn test_onion_value_mpp_set_calculation() {
82238223
let session_priv = SecretKey::from_slice(&session_priv).unwrap();
82248224
let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
82258225
let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], 100_000,
8226-
RecipientOnionFields::secret_only(our_payment_secret), height + 1, &None).unwrap();
8226+
RecipientOnionFields::secret_only(our_payment_secret).into(), height + 1, &None).unwrap();
82278227
// Edit amt_to_forward to simulate the sender having set
82288228
// the final amount and the routing node taking less fee
82298229
if let msgs::OutboundOnionPayload::Receive {

lightning/src/ln/onion_payment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ mod tests {
531531
let path = Path { hops, trampoline_hops: vec![], blinded_tail: None, };
532532
let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap();
533533
let (onion_payloads, ..) = super::onion_utils::build_onion_payloads(
534-
&path, total_amt_msat, recipient_onion, cur_height + 1, &Some(keysend_preimage)
534+
&path, total_amt_msat, recipient_onion.into(), cur_height + 1, &Some(keysend_preimage)
535535
).unwrap();
536536

537537
assert!(super::onion_utils::construct_onion_packet(

lightning/src/ln/onion_route_tests.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ fn test_onion_failure() {
358358
let cur_height = nodes[0].best_block_info().1 + 1;
359359
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
360360
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(
361-
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
361+
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
362362
let mut new_payloads = Vec::new();
363363
for payload in onion_payloads.drain(..) {
364364
new_payloads.push(BogusOnionHopData::new(payload));
@@ -376,7 +376,7 @@ fn test_onion_failure() {
376376
let cur_height = nodes[0].best_block_info().1 + 1;
377377
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
378378
let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(
379-
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
379+
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
380380
let mut new_payloads = Vec::new();
381381
for payload in onion_payloads.drain(..) {
382382
new_payloads.push(BogusOnionHopData::new(payload));
@@ -613,7 +613,7 @@ fn test_onion_failure() {
613613
route.paths[0].hops[1].cltv_expiry_delta += CLTV_FAR_FAR_AWAY + route.paths[0].hops[0].cltv_expiry_delta + 1;
614614
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
615615
let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads(
616-
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), height, &None).unwrap();
616+
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty().into(), height, &None).unwrap();
617617
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap();
618618
msg.cltv_expiry = htlc_cltv;
619619
msg.onion_routing_packet = onion_packet;
@@ -949,7 +949,7 @@ fn test_always_create_tlv_format_onion_payloads() {
949949

950950
let cur_height = nodes[0].best_block_info().1 + 1;
951951
let (onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(
952-
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty(), cur_height, &None).unwrap();
952+
&route.paths[0], 40000, RecipientOnionFields::spontaneous_empty().into(), cur_height, &None).unwrap();
953953

954954
match onion_payloads[0] {
955955
msgs::OutboundOnionPayload::Forward {..} => {},
@@ -1323,7 +1323,7 @@ fn test_phantom_invalid_onion_payload() {
13231323
let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap();
13241324
let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(
13251325
&route.paths[0], msgs::MAX_VALUE_MSAT + 1,
1326-
RecipientOnionFields::secret_only(payment_secret), height + 1, &None).unwrap();
1326+
RecipientOnionFields::secret_only(payment_secret).into(), height + 1, &None).unwrap();
13271327
// We only want to construct the onion packet for the last hop, not the entire route, so
13281328
// remove the first hop's payload and its keys.
13291329
onion_keys.remove(0);

lightning/src/ln/onion_utils.rs

Lines changed: 94 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,24 @@ pub(super) fn construct_trampoline_keys<T: secp256k1::Signing>(
269269

270270
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
271271
pub(super) fn build_onion_payloads(
272-
path: &Path, total_msat: u64, mut recipient_onion: RecipientOnionFields,
273-
starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>,
272+
path: &Path, total_msat: u64, mut recipient_onion: RecipientOnion, starting_htlc_offset: u32,
273+
keysend_preimage: &Option<PaymentPreimage>,
274274
) -> Result<(Vec<msgs::OutboundOnionPayload>, u64, u32), APIError> {
275275
let mut cur_value_msat = 0u64;
276276
let mut cur_cltv = starting_htlc_offset;
277277
let mut last_short_channel_id = 0;
278-
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
279-
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
280-
);
281278

282-
for (idx, hop) in path.hops.iter().rev().enumerate() {
279+
let blinded_path_length =
280+
if let (RecipientOnion::Final(_), Some(tail)) = (&recipient_onion, &path.blinded_tail) {
281+
// the blinded path is only applicable if the outer onion isn't wrapping a Trampoline onion
282+
tail.hops.len()
283+
} else {
284+
0
285+
};
286+
let mut res: Vec<msgs::OutboundOnionPayload> =
287+
Vec::with_capacity(path.hops.len() + blinded_path_length);
288+
289+
if let Some(hop) = path.hops.last() {
283290
// First hop gets special values so that it can check, on receipt, that everything is
284291
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
285292
// the intended recipient).
@@ -289,55 +296,89 @@ pub(super) fn build_onion_payloads(
289296
} else {
290297
cur_cltv
291298
};
292-
if idx == 0 {
293-
if let Some(BlindedTail {
294-
blinding_point,
295-
hops,
296-
final_value_msat,
297-
excess_final_cltv_expiry_delta,
298-
..
299-
}) = &path.blinded_tail
300-
{
301-
let mut blinding_point = Some(*blinding_point);
302-
for (i, blinded_hop) in hops.iter().enumerate() {
303-
if i == hops.len() - 1 {
304-
cur_value_msat += final_value_msat;
305-
res.push(msgs::OutboundOnionPayload::BlindedReceive {
306-
sender_intended_htlc_amt_msat: *final_value_msat,
307-
total_msat,
308-
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
309-
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
310-
intro_node_blinding_point: blinding_point.take(),
311-
});
312-
} else {
313-
res.push(msgs::OutboundOnionPayload::BlindedForward {
314-
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
315-
intro_node_blinding_point: blinding_point.take(),
316-
});
299+
300+
match recipient_onion {
301+
RecipientOnion::TrampolineEntry(mut trampoline_entry_fields) => {
302+
res.push(msgs::OutboundOnionPayload::TrampolineEntrypoint {
303+
amt_to_forward: value_msat,
304+
outgoing_cltv_value: cltv,
305+
multipath_trampoline_data: None,
306+
trampoline_packet: trampoline_entry_fields.trampoline_packet,
307+
});
308+
},
309+
RecipientOnion::Final(mut recipient_onion_fields) => {
310+
if let Some(BlindedTail {
311+
blinding_point,
312+
hops,
313+
final_value_msat,
314+
excess_final_cltv_expiry_delta,
315+
..
316+
}) = &path.blinded_tail
317+
{
318+
let mut blinding_point = Some(*blinding_point);
319+
for (i, blinded_hop) in hops.iter().enumerate() {
320+
if i == hops.len() - 1 {
321+
cur_value_msat += final_value_msat;
322+
res.push(msgs::OutboundOnionPayload::BlindedReceive {
323+
sender_intended_htlc_amt_msat: *final_value_msat,
324+
total_msat,
325+
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
326+
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
327+
intro_node_blinding_point: blinding_point.take(),
328+
});
329+
} else {
330+
res.push(msgs::OutboundOnionPayload::BlindedForward {
331+
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
332+
intro_node_blinding_point: blinding_point.take(),
333+
});
334+
}
317335
}
336+
} else {
337+
res.push(msgs::OutboundOnionPayload::Receive {
338+
payment_data: if let Some(secret) =
339+
recipient_onion_fields.payment_secret.take()
340+
{
341+
Some(msgs::FinalOnionHopData { payment_secret: secret, total_msat })
342+
} else {
343+
None
344+
},
345+
payment_metadata: recipient_onion_fields.payment_metadata.take(),
346+
keysend_preimage: *keysend_preimage,
347+
custom_tlvs: recipient_onion_fields.custom_tlvs.clone(),
348+
sender_intended_htlc_amt_msat: value_msat,
349+
cltv_expiry_height: cltv,
350+
});
318351
}
319-
} else {
320-
res.push(msgs::OutboundOnionPayload::Receive {
321-
payment_data: if let Some(secret) = recipient_onion.payment_secret.take() {
322-
Some(msgs::FinalOnionHopData { payment_secret: secret, total_msat })
323-
} else {
324-
None
325-
},
326-
payment_metadata: recipient_onion.payment_metadata.take(),
327-
keysend_preimage: *keysend_preimage,
328-
custom_tlvs: recipient_onion.custom_tlvs.clone(),
329-
sender_intended_htlc_amt_msat: value_msat,
330-
cltv_expiry_height: cltv,
331-
});
332-
}
333-
} else {
334-
let payload = msgs::OutboundOnionPayload::Forward {
335-
short_channel_id: last_short_channel_id,
336-
amt_to_forward: value_msat,
337-
outgoing_cltv_value: cltv,
338-
};
339-
res.insert(0, payload);
352+
},
353+
}
354+
355+
cur_value_msat += hop.fee_msat;
356+
if cur_value_msat >= 21000000 * 100000000 * 1000 {
357+
return Err(APIError::InvalidRoute { err: "Channel fees overflowed?".to_owned() });
358+
}
359+
cur_cltv += hop.cltv_expiry_delta as u32;
360+
if cur_cltv >= 500000000 {
361+
return Err(APIError::InvalidRoute { err: "Channel CLTV overflowed?".to_owned() });
340362
}
363+
last_short_channel_id = hop.short_channel_id;
364+
}
365+
366+
for hop in path.hops.iter().rev().skip(1) {
367+
// First hop gets special values so that it can check, on receipt, that everything is
368+
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
369+
// the intended recipient).
370+
let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
371+
let cltv = if cur_cltv == starting_htlc_offset {
372+
hop.cltv_expiry_delta + starting_htlc_offset
373+
} else {
374+
cur_cltv
375+
};
376+
let payload = msgs::OutboundOnionPayload::Forward {
377+
short_channel_id: last_short_channel_id,
378+
amt_to_forward: value_msat,
379+
outgoing_cltv_value: cltv,
380+
};
381+
res.insert(0, payload);
341382
cur_value_msat += hop.fee_msat;
342383
if cur_value_msat >= 21000000 * 100000000 * 1000 {
343384
return Err(APIError::InvalidRoute { err: "Channel fees overflowed?".to_owned() });
@@ -1265,7 +1306,7 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
12651306
let (onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
12661307
&path,
12671308
total_msat,
1268-
recipient_onion,
1309+
recipient_onion.into(),
12691310
cur_block_height,
12701311
keysend_preimage,
12711312
)?;

0 commit comments

Comments
 (0)