Skip to content

Commit dc679c0

Browse files
committed
Construct Trampoline component in create_payment_onion
1 parent f7e08e3 commit dc679c0

File tree

2 files changed

+80
-14
lines changed

2 files changed

+80
-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

+80-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)]
@@ -347,12 +347,18 @@ pub(super) fn build_onion_payloads<'a>(
347347
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
348348
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
349349
);
350-
let blinded_tail_with_hop_iter = path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
351-
hops: bt.hops.iter(),
352-
blinding_point: bt.blinding_point,
353-
final_value_msat: bt.final_value_msat,
354-
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
355-
});
350+
351+
// don't include blinded tail when Trampoline hops are present
352+
let blinded_tail_with_hop_iter = if path.trampoline_hops.is_empty() {
353+
path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
354+
hops: bt.hops.iter(),
355+
blinding_point: bt.blinding_point,
356+
final_value_msat: bt.final_value_msat,
357+
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
358+
})
359+
} else {
360+
None
361+
};
356362

357363
let (value_msat, cltv) = build_onion_payloads_callback(
358364
path.hops.iter(),
@@ -584,7 +590,6 @@ pub(super) fn construct_onion_packet(
584590
)
585591
}
586592

587-
#[allow(unused)]
588593
pub(super) fn construct_trampoline_onion_packet(
589594
payloads: Vec<msgs::OutboundTrampolinePayload>, onion_keys: Vec<OnionKeys>,
590595
prng_seed: [u8; 32], associated_data: &PaymentHash, length: Option<u16>,
@@ -1347,17 +1352,79 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13471352
keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
13481353
prng_seed: [u8; 32],
13491354
) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
1350-
let onion_keys = construct_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1351-
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1352-
})?;
1353-
let (onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
1355+
let mut trampoline_payloads = vec![];
1356+
let mut outer_total_msat = total_msat;
1357+
let mut outer_starting_htlc_offset = cur_block_height;
1358+
let mut outer_session_priv_override = None;
1359+
1360+
if !path.trampoline_hops.is_empty() {
1361+
(trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1362+
build_trampoline_onion_payloads(
1363+
path,
1364+
total_msat,
1365+
recipient_onion,
1366+
cur_block_height,
1367+
keysend_preimage,
1368+
)?;
1369+
}
1370+
1371+
let (mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
13541372
&path,
13551373
total_msat,
13561374
recipient_onion,
13571375
cur_block_height,
13581376
keysend_preimage,
13591377
invoice_request,
13601378
)?;
1379+
1380+
if !path.trampoline_hops.is_empty() {
1381+
let onion_keys =
1382+
construct_trampoline_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| {
1383+
APIError::InvalidRoute {
1384+
err: "Pubkey along hop was maliciously selected".to_owned(),
1385+
}
1386+
})?;
1387+
let trampoline_packet = construct_trampoline_onion_packet(
1388+
trampoline_payloads,
1389+
onion_keys,
1390+
prng_seed,
1391+
payment_hash,
1392+
None,
1393+
)
1394+
.map_err(|_| APIError::InvalidRoute {
1395+
err: "Route size too large considering onion data".to_owned(),
1396+
})?;
1397+
1398+
let last_payload = onion_payloads.pop().ok_or(APIError::InvalidRoute {
1399+
err: "Non-Trampoline path needs at least one hop".to_owned(),
1400+
})?;
1401+
1402+
match last_payload {
1403+
OutboundOnionPayload::Receive { .. } => {
1404+
onion_payloads.push(OutboundOnionPayload::TrampolineEntrypoint {
1405+
amt_to_forward: outer_total_msat,
1406+
outgoing_cltv_value: outer_starting_htlc_offset,
1407+
multipath_trampoline_data: None,
1408+
trampoline_packet,
1409+
});
1410+
},
1411+
_ => {
1412+
return Err(APIError::InvalidRoute {
1413+
err: "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1414+
.to_owned(),
1415+
});
1416+
},
1417+
};
1418+
1419+
let session_priv_hash = Sha256::hash(&session_priv.secret_bytes()).to_byte_array();
1420+
outer_session_priv_override =
1421+
Some(SecretKey::from_slice(&session_priv_hash[..]).expect("You broke SHA-256!"));
1422+
}
1423+
1424+
let outer_session_priv = outer_session_priv_override.as_ref().unwrap_or(session_priv);
1425+
let onion_keys = construct_onion_keys(&secp_ctx, &path, outer_session_priv).map_err(|_| {
1426+
APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() }
1427+
})?;
13611428
let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
13621429
.map_err(|_| APIError::InvalidRoute {
13631430
err: "Route size too large considering onion data".to_owned(),

0 commit comments

Comments
 (0)