Skip to content

Commit af1818b

Browse files
committed
Construct Trampoline component in create_payment_onion
1 parent 9f2928b commit af1818b

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)]
@@ -301,12 +301,18 @@ pub(super) fn build_onion_payloads<'a>(
301301
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
302302
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
303303
);
304-
let blinded_tail_with_hop_iter = path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
305-
hops: bt.hops.iter(),
306-
blinding_point: bt.blinding_point,
307-
final_value_msat: bt.final_value_msat,
308-
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
309-
});
304+
305+
// don't include blinded tail when Trampoline hops are present
306+
let blinded_tail_with_hop_iter = if path.trampoline_hops.is_empty() {
307+
path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
308+
hops: bt.hops.iter(),
309+
blinding_point: bt.blinding_point,
310+
final_value_msat: bt.final_value_msat,
311+
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
312+
})
313+
} else {
314+
None
315+
};
310316

311317
let (value_msat, cltv) = build_onion_payloads_callback(
312318
path.hops.iter(),
@@ -538,7 +544,6 @@ pub(super) fn construct_onion_packet(
538544
)
539545
}
540546

541-
#[allow(unused)]
542547
pub(super) fn construct_trampoline_onion_packet(
543548
payloads: Vec<msgs::OutboundTrampolinePayload>, onion_keys: Vec<OnionKeys>,
544549
prng_seed: [u8; 32], associated_data: &PaymentHash, length: Option<u16>,
@@ -1302,17 +1307,73 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13021307
keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
13031308
prng_seed: [u8; 32],
13041309
) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
1305-
let onion_keys = construct_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1306-
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1307-
})?;
1308-
let (onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
1310+
let mut trampoline_payloads = vec![];
1311+
let mut outer_total_msat = total_msat;
1312+
let mut outer_starting_htlc_offset = cur_block_height;
1313+
let outer_session_priv = session_priv;
1314+
1315+
if !path.trampoline_hops.is_empty() {
1316+
(trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1317+
build_trampoline_onion_payloads(
1318+
path,
1319+
total_msat,
1320+
recipient_onion,
1321+
cur_block_height,
1322+
keysend_preimage,
1323+
)?;
1324+
}
1325+
1326+
let (mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
13091327
&path,
13101328
total_msat,
13111329
recipient_onion,
13121330
cur_block_height,
13131331
keysend_preimage,
13141332
invoice_request,
13151333
)?;
1334+
1335+
if !path.trampoline_hops.is_empty() {
1336+
let onion_keys = construct_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1337+
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1338+
})?;
1339+
let trampoline_packet = construct_trampoline_onion_packet(
1340+
trampoline_payloads,
1341+
onion_keys,
1342+
prng_seed,
1343+
payment_hash,
1344+
None,
1345+
)
1346+
.map_err(|_| APIError::InvalidRoute {
1347+
err: "Route size too large considering onion data".to_owned(),
1348+
})?;
1349+
1350+
let last_payload = onion_payloads.pop().ok_or(APIError::InvalidRoute {
1351+
err: "Non-Trampoline path needs at least one hop".to_owned(),
1352+
})?;
1353+
1354+
match last_payload {
1355+
OutboundOnionPayload::Receive { .. } => {
1356+
onion_payloads.push(OutboundOnionPayload::TrampolineEntrypoint {
1357+
amt_to_forward: outer_total_msat,
1358+
outgoing_cltv_value: outer_starting_htlc_offset,
1359+
multipath_trampoline_data: None,
1360+
trampoline_packet,
1361+
});
1362+
},
1363+
_ => {
1364+
return Err(APIError::InvalidRoute {
1365+
err: "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1366+
.to_owned(),
1367+
});
1368+
},
1369+
};
1370+
1371+
// TODO: replace outer_session_priv with hash-based derivation
1372+
}
1373+
1374+
let onion_keys = construct_onion_keys(&secp_ctx, &path, &outer_session_priv).map_err(|_| {
1375+
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1376+
})?;
13161377
let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
13171378
.map_err(|_| APIError::InvalidRoute {
13181379
err: "Route size too large considering onion data".to_owned(),

0 commit comments

Comments
 (0)