Skip to content

Commit 67100ce

Browse files
committed
Construct Trampoline component in create_payment_onion
1 parent 94c1d6a commit 67100ce

File tree

2 files changed

+79
-14
lines changed

2 files changed

+79
-14
lines changed

lightning/src/ln/msgs.rs

Lines changed: 0 additions & 1 deletion
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

Lines changed: 79 additions & 13 deletions
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)]
@@ -350,12 +350,18 @@ pub(super) fn build_onion_payloads<'a>(
350350
let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
351351
path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
352352
);
353-
let blinded_tail_with_hop_iter = 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-
});
353+
354+
// don't include blinded tail when Trampoline hops are present
355+
let blinded_tail_with_hop_iter = if path.trampoline_hops.is_empty() {
356+
path.blinded_tail.as_ref().map(|bt| BlindedTailHopIter {
357+
hops: bt.hops.iter(),
358+
blinding_point: bt.blinding_point,
359+
final_value_msat: bt.final_value_msat,
360+
excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
361+
})
362+
} else {
363+
None
364+
};
359365

360366
let (value_msat, cltv) = build_onion_payloads_callback(
361367
path.hops.iter(),
@@ -587,7 +593,6 @@ pub(super) fn construct_onion_packet(
587593
)
588594
}
589595

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

0 commit comments

Comments
 (0)