Skip to content

Commit e60adce

Browse files
committed
Handle Trampoline hops in error decryption
Rather than solely iterating over `RouteHop`s, we now also append the shared secrets from the inner onion containing `TrampolineHop`s.
1 parent 6863ebd commit e60adce

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,40 +976,68 @@ where
976976

977977
enum ErrorHop<'a> {
978978
RouteHop(&'a RouteHop),
979+
TrampolineHop(&'a TrampolineHop),
979980
}
980981

981982
impl<'a> ErrorHop<'a> {
982983
fn fee_msat(&self) -> u64 {
983984
match self {
984985
ErrorHop::RouteHop(rh) => rh.fee_msat,
986+
ErrorHop::TrampolineHop(th) => th.fee_msat,
985987
}
986988
}
987989

988990
fn pubkey(&self) -> &PublicKey {
989991
match self {
990992
ErrorHop::RouteHop(rh) => rh.node_pubkey(),
993+
ErrorHop::TrampolineHop(th) => th.node_pubkey(),
991994
}
992995
}
993996

994997
fn short_channel_id(&self) -> Option<u64> {
995998
match self {
996999
ErrorHop::RouteHop(rh) => Some(rh.short_channel_id),
1000+
ErrorHop::TrampolineHop(_) => None,
9971001
}
9981002
}
9991003
}
10001004

1005+
let outer_session_priv = path.has_trampoline_hops().then(|| {
1006+
// if we have Trampoline hops, the outer onion session_priv is a hash of the inner one
1007+
let session_priv_hash = Sha256::hash(&session_priv.secret_bytes()).to_byte_array();
1008+
SecretKey::from_slice(&session_priv_hash[..]).expect("You broke SHA-256!")
1009+
});
1010+
10011011
let mut onion_keys = Vec::with_capacity(path.hops.len());
10021012
construct_onion_keys_generic_callback(
10031013
secp_ctx,
10041014
&path.hops,
1005-
path.blinded_tail.as_ref(),
1006-
session_priv,
1015+
// if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1016+
if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() },
1017+
outer_session_priv.as_ref().unwrap_or(session_priv),
10071018
|shared_secret, _, _, route_hop_option: Option<&RouteHop>, _| {
10081019
onion_keys.push((route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret))
10091020
},
10101021
)
10111022
.expect("Route we used spontaneously grew invalid keys in the middle of it?");
10121023

1024+
if path.has_trampoline_hops() {
1025+
construct_onion_keys_generic_callback(
1026+
secp_ctx,
1027+
// Trampoline hops are part of the blinded tail, so this can never panic
1028+
&path.blinded_tail.as_ref().unwrap().trampoline_hops,
1029+
path.blinded_tail.as_ref(),
1030+
session_priv,
1031+
|shared_secret, _, _, trampoline_hop_option: Option<&TrampolineHop>, _| {
1032+
onion_keys.push((
1033+
trampoline_hop_option.map(|th| ErrorHop::TrampolineHop(th)),
1034+
shared_secret,
1035+
))
1036+
},
1037+
)
1038+
.expect("Route we used spontaneously grew invalid keys in the middle of it?");
1039+
}
1040+
10131041
let num_blinded_hops = path.blinded_tail.as_ref().map_or(0, |bt| bt.hops.len());
10141042

10151043
// Handle packed channel/node updates for passing back for the route handler

lightning/src/routing/router.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,11 @@ impl Path {
519519
None => self.hops.last().map(|hop| hop.cltv_expiry_delta)
520520
}
521521
}
522+
523+
/// True if this [`Path`] has at least one Trampoline hop.
524+
pub fn has_trampoline_hops(&self) -> bool {
525+
self.blinded_tail.as_ref().map_or(false, |bt| !bt.trampoline_hops.is_empty())
526+
}
522527
}
523528

524529
/// A route directs a payment from the sender (us) to the recipient. If the recipient supports MPP,

0 commit comments

Comments
 (0)