Skip to content

Commit 1e2d12f

Browse files
committed
Trampoline payload construction method.
1 parent ecff84f commit 1e2d12f

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,80 @@ pub(super) fn build_onion_payloads(
259259
Ok((res, cur_value_msat, cur_cltv))
260260
}
261261

262+
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
263+
pub(super) fn build_trampoline_payloads(
264+
path: &Path, total_msat: u64, recipient_onion: RecipientOnionFields,
265+
starting_htlc_offset: u32, keysend_preimage: &Option<PaymentPreimage>,
266+
) -> Result<(Vec<msgs::OutboundTrampolinePayload>, u64, u32), APIError> {
267+
let mut cur_value_msat = 0u64;
268+
let mut cur_cltv = starting_htlc_offset;
269+
let mut last_node_id = None;
270+
let mut res: Vec<msgs::OutboundTrampolinePayload> = Vec::with_capacity(
271+
path.trampoline_hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
272+
);
273+
274+
for (idx, hop) in path.trampoline_hops.iter().rev().enumerate() {
275+
// First hop gets special values so that it can check, on receipt, that everything is
276+
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
277+
// the intended recipient).
278+
let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
279+
let cltv = if cur_cltv == starting_htlc_offset {
280+
hop.cltv_expiry_delta + starting_htlc_offset
281+
} else {
282+
cur_cltv
283+
};
284+
if idx == 0 {
285+
let BlindedTail {
286+
blinding_point,
287+
hops,
288+
final_value_msat,
289+
excess_final_cltv_expiry_delta,
290+
..
291+
} = path.blinded_tail.as_ref().ok_or(APIError::InvalidRoute {
292+
err: "Trampoline payments must terminate in blinded tails.".to_owned(),
293+
})?;
294+
let mut blinding_point = Some(*blinding_point);
295+
for (i, blinded_hop) in hops.iter().enumerate() {
296+
if i == hops.len() - 1 {
297+
cur_value_msat += final_value_msat;
298+
res.push(msgs::OutboundTrampolinePayload::BlindedReceive {
299+
sender_intended_htlc_amt_msat: *final_value_msat,
300+
total_msat,
301+
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
302+
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
303+
intro_node_blinding_point: blinding_point.take(),
304+
keysend_preimage: *keysend_preimage,
305+
custom_tlvs: recipient_onion.custom_tlvs.clone(),
306+
});
307+
} else {
308+
res.push(msgs::OutboundTrampolinePayload::BlindedForward {
309+
encrypted_tlvs: blinded_hop.encrypted_payload.clone(),
310+
intro_node_blinding_point: blinding_point.take(),
311+
});
312+
}
313+
}
314+
} else {
315+
let payload = msgs::OutboundTrampolinePayload::Forward {
316+
amt_to_forward: value_msat,
317+
outgoing_cltv_value: cltv,
318+
outgoing_node_id: last_node_id
319+
.expect("outgoing node id cannot be None after last hop"),
320+
};
321+
res.insert(0, payload);
322+
}
323+
cur_value_msat += hop.fee_msat;
324+
if cur_value_msat >= 21000000 * 100000000 * 1000 {
325+
return Err(APIError::InvalidRoute { err: "Channel fees overflowed?".to_owned() });
326+
}
327+
cur_cltv += hop.cltv_expiry_delta as u32;
328+
if cur_cltv >= 500000000 {
329+
return Err(APIError::InvalidRoute { err: "Channel CLTV overflowed?".to_owned() });
330+
}
331+
last_node_id = Some(hop.pubkey);
332+
}
333+
Ok((res, cur_value_msat, cur_cltv))
334+
}
335+
262336
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now
263337
/// the hops can be of variable length.
264338
pub(crate) const ONION_DATA_LEN: usize = 20 * 65;

0 commit comments

Comments
 (0)