Skip to content

Commit ee68783

Browse files
committed
Construct Trampoline component in create_payment_onion
1 parent 3441f4e commit ee68783

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

lightning/src/ln/msgs.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,6 @@ mod fuzzy_internal_msgs {
18011801
amt_to_forward: u64,
18021802
outgoing_cltv_value: u32,
18031803
},
1804-
#[allow(unused)]
18051804
TrampolineEntrypoint {
18061805
amt_to_forward: u64,
18071806
outgoing_cltv_value: u32,

lightning/src/ln/onion_utils.rs

+74-13
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
3333
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
3434

3535
use crate::io::{Cursor, Read};
36-
use core::ops::Deref;
37-
36+
use crate::ln::msgs::OutboundOnionPayload;
3837
#[allow(unused_imports)]
3938
use crate::prelude::*;
39+
use core::ops::Deref;
4040

4141
pub(crate) struct OnionKeys {
4242
#[cfg(test)]
@@ -367,12 +367,18 @@ pub(super) fn build_onion_payloads<'a>(
367367
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
368368
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
369369
);
370-
let blinded_tail_with_hop_iter = path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
371-
hops: bt.hops.iter(),
372-
blinding_point: bt.blinding_point,
373-
final_value_msat: bt.final_value_msat,
374-
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
375-
});
370+
371+
// don't include blinded tail when Trampoline hops are present
372+
let blinded_tail_with_hop_iter = if path.trampoline_hops.is_empty() {
373+
path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
374+
hops: bt.hops.iter(),
375+
blinding_point: bt.blinding_point,
376+
final_value_msat: bt.final_value_msat,
377+
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
378+
})
379+
} else {
380+
None
381+
};
376382

377383
let (value_msat, cltv) = build_onion_payloads_callback(
378384
path.hops.iter(),
@@ -604,7 +610,6 @@ pub(super) fn construct_onion_packet(
604610
)
605611
}
606612

607-
#[allow(unused)]
608613
pub(super) fn construct_trampoline_onion_packet(
609614
payloads: Vec<msgs::OutboundTrampolinePayload>, onion_keys: Vec<OnionKeys>,
610615
prng_seed: [u8; 32], associated_data: &PaymentHash, length: Option<u16>,
@@ -1361,17 +1366,73 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13611366
keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
13621367
prng_seed: [u8; 32],
13631368
) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
1364-
let onion_keys = construct_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1365-
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1366-
})?;
1367-
let (onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
1369+
let mut trampoline_payloads = vec![];
1370+
let mut outer_total_msat = total_msat;
1371+
let mut outer_starting_htlc_offset = cur_block_height;
1372+
let outer_session_priv = session_priv;
1373+
1374+
if !path.trampoline_hops.is_empty() {
1375+
(trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1376+
build_trampoline_onion_payloads(
1377+
path,
1378+
total_msat,
1379+
recipient_onion,
1380+
cur_block_height,
1381+
keysend_preimage,
1382+
)?;
1383+
}
1384+
1385+
let (mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
13681386
&path,
13691387
total_msat,
13701388
recipient_onion,
13711389
cur_block_height,
13721390
keysend_preimage,
13731391
invoice_request,
13741392
)?;
1393+
1394+
if !path.trampoline_hops.is_empty() {
1395+
let onion_keys = construct_trampoline_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1396+
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1397+
})?;
1398+
let trampoline_packet = construct_trampoline_onion_packet(
1399+
trampoline_payloads,
1400+
onion_keys,
1401+
prng_seed,
1402+
payment_hash,
1403+
None,
1404+
)
1405+
.map_err(|_| APIError::InvalidRoute {
1406+
err: "Route size too large considering onion data".to_owned(),
1407+
})?;
1408+
1409+
let last_payload = onion_payloads.pop().ok_or(APIError::InvalidRoute {
1410+
err: "Non-Trampoline path needs at least one hop".to_owned(),
1411+
})?;
1412+
1413+
match last_payload {
1414+
OutboundOnionPayload::Receive { .. } => {
1415+
onion_payloads.push(OutboundOnionPayload::TrampolineEntrypoint {
1416+
amt_to_forward: outer_total_msat,
1417+
outgoing_cltv_value: outer_starting_htlc_offset,
1418+
multipath_trampoline_data: None,
1419+
trampoline_packet,
1420+
});
1421+
},
1422+
_ => {
1423+
return Err(APIError::InvalidRoute {
1424+
err: "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1425+
.to_owned(),
1426+
});
1427+
},
1428+
};
1429+
1430+
// TODO: replace outer_session_priv with hash-based derivation
1431+
}
1432+
1433+
let onion_keys = construct_onion_keys(&secp_ctx, &path, &outer_session_priv).map_err(|_| {
1434+
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1435+
})?;
13751436
let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
13761437
.map_err(|_| APIError::InvalidRoute {
13771438
err: "Route size too large considering onion data".to_owned(),

0 commit comments

Comments
 (0)