Skip to content

Commit d219c89

Browse files
committed
Parse Trampoline onion payloads
We will be using the same logic for decoding onion payloads for outer and for Trampoline onions. To accommodate the Trampoline payloads, we parse a next node ID rather than an SCID.
1 parent a8c3bb0 commit d219c89

File tree

2 files changed

+239
-2
lines changed

2 files changed

+239
-2
lines changed

lightning/src/blinded_path/payment.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,26 @@ pub struct ForwardTlvs {
297297
pub next_blinding_override: Option<PublicKey>,
298298
}
299299

300+
/// Data to construct a [`BlindedHop`] for forwarding a Trampoline payment.
301+
#[cfg(trampoline)]
302+
#[derive(Clone, Debug)]
303+
pub struct TrampolineForwardTlvs {
304+
/// The node id to which the trampoline node must find a route.
305+
pub next_trampoline: NodeId,
306+
/// Payment parameters for relaying over [`Self::next_trampoline`].
307+
pub payment_relay: PaymentRelay,
308+
/// Payment constraints for relaying over [`Self::next_trampoline`].
309+
pub payment_constraints: PaymentConstraints,
310+
/// Supported and required features when relaying a payment onion containing this object's
311+
/// corresponding [`BlindedHop::encrypted_payload`].
312+
///
313+
/// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload
314+
pub features: BlindedHopFeatures,
315+
/// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the
316+
/// [`BlindedPaymentPath::blinding_point`] of the appended blinded path.
317+
pub next_blinding_override: Option<PublicKey>,
318+
}
319+
300320
/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
301321
/// may not be valid if received by another lightning implementation.
302322
///
@@ -348,6 +368,17 @@ pub(crate) enum BlindedPaymentTlvs {
348368
Receive(ReceiveTlvs),
349369
}
350370

371+
/// Data to construct a [`BlindedHop`] for sending a Trampoline payment over.
372+
///
373+
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
374+
#[cfg(trampoline)]
375+
pub(crate) enum BlindedTrampolineTlvs {
376+
/// This blinded payment data is for a forwarding node.
377+
Forward(TrampolineForwardTlvs),
378+
/// This blinded payment data is for the receiving node.
379+
Receive(ReceiveTlvs),
380+
}
381+
351382
// Used to include forward and receive TLVs in the same iterator for encoding.
352383
enum BlindedPaymentTlvsRef<'a> {
353384
Forward(&'a ForwardTlvs),
@@ -559,6 +590,49 @@ impl Readable for BlindedPaymentTlvs {
559590
}
560591
}
561592

593+
#[cfg(trampoline)]
594+
impl Readable for BlindedTrampolineTlvs {
595+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
596+
_init_and_read_tlv_stream!(r, {
597+
(1, _padding, option),
598+
(8, next_blinding_override, option),
599+
(10, payment_relay, option),
600+
(12, payment_constraints, required),
601+
(14, next_trampoline, option),
602+
(14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
603+
(65536, payment_secret, option),
604+
(65537, payment_context, option),
605+
(65539, authentication, option),
606+
});
607+
let _padding: Option<utils::Padding> = _padding;
608+
609+
if let Some(next_trampoline) = next_trampoline {
610+
if payment_secret.is_some() {
611+
return Err(DecodeError::InvalidValue);
612+
}
613+
Ok(BlindedTrampolineTlvs::Forward(TrampolineForwardTlvs {
614+
next_trampoline,
615+
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
616+
payment_constraints: payment_constraints.0.unwrap(),
617+
next_blinding_override,
618+
features: features.unwrap_or_else(BlindedHopFeatures::empty),
619+
}))
620+
} else {
621+
if payment_relay.is_some() || features.is_some() {
622+
return Err(DecodeError::InvalidValue);
623+
}
624+
Ok(BlindedTrampolineTlvs::Receive(ReceiveTlvs {
625+
tlvs: UnauthenticatedReceiveTlvs {
626+
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
627+
payment_constraints: payment_constraints.0.unwrap(),
628+
payment_context: payment_context.ok_or(DecodeError::InvalidValue)?,
629+
},
630+
authentication: authentication.ok_or(DecodeError::InvalidValue)?,
631+
}))
632+
}
633+
}
634+
}
635+
562636
/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
563637
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
564638
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,

lightning/src/ln/msgs.rs

Lines changed: 165 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ use bitcoin::script::ScriptBuf;
3232
use bitcoin::hash_types::Txid;
3333

3434
use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs, UnauthenticatedReceiveTlvs};
35+
#[cfg(trampoline)]
36+
use crate::blinded_path::payment::{BlindedTrampolineTlvs, TrampolineForwardTlvs};
3537
use crate::ln::channelmanager::Verification;
3638
use crate::ln::types::ChannelId;
3739
use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -1794,6 +1796,8 @@ mod fuzzy_internal_msgs {
17941796
use bitcoin::secp256k1::PublicKey;
17951797
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, PaymentRelay};
17961798
use crate::offers::invoice_request::InvoiceRequest;
1799+
#[cfg(trampoline)]
1800+
use crate::routing::gossip::NodeId;
17971801
use crate::types::payment::{PaymentPreimage, PaymentSecret};
17981802
use crate::types::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
17991803
use super::{FinalOnionHopData, TrampolineOnionPacket};
@@ -1812,10 +1816,11 @@ mod fuzzy_internal_msgs {
18121816
}
18131817

18141818
#[cfg(trampoline)]
1819+
#[cfg_attr(trampoline, allow(unused))]
18151820
pub struct InboundTrampolineEntrypointPayload {
18161821
pub amt_to_forward: u64,
18171822
pub outgoing_cltv_value: u32,
1818-
pub multipath_trampoline_data: Option<FinalOnionHopData>,
1823+
pub multipath_trampoline_data: FinalOnionHopData,
18191824
pub trampoline_packet: TrampolineOnionPacket,
18201825
/// The blinding point this hop needs to decrypt its Trampoline onion.
18211826
/// This is used for Trampoline hops that are not the blinded path intro hop.
@@ -1854,12 +1859,42 @@ mod fuzzy_internal_msgs {
18541859
pub enum InboundOnionPayload {
18551860
Forward(InboundOnionForwardPayload),
18561861
#[cfg(trampoline)]
1862+
#[cfg_attr(trampoline, allow(unused))]
18571863
TrampolineEntrypoint(InboundTrampolineEntrypointPayload),
18581864
Receive(InboundOnionReceivePayload),
18591865
BlindedForward(InboundOnionBlindedForwardPayload),
18601866
BlindedReceive(InboundOnionBlindedReceivePayload),
18611867
}
18621868

1869+
#[cfg(trampoline)]
1870+
#[cfg_attr(trampoline, allow(unused))]
1871+
pub struct InboundTrampolineForwardPayload {
1872+
pub next_trampoline: NodeId,
1873+
/// The value, in msat, of the payment after this hop's fee is deducted.
1874+
pub amt_to_forward: u64,
1875+
pub outgoing_cltv_value: u32,
1876+
}
1877+
1878+
#[cfg(trampoline)]
1879+
#[cfg_attr(trampoline, allow(unused))]
1880+
pub struct InboundTrampolineBlindedForwardPayload {
1881+
pub next_trampoline: NodeId,
1882+
pub payment_relay: PaymentRelay,
1883+
pub payment_constraints: PaymentConstraints,
1884+
pub features: BlindedHopFeatures,
1885+
pub intro_node_blinding_point: Option<PublicKey>,
1886+
pub next_blinding_override: Option<PublicKey>,
1887+
}
1888+
1889+
#[cfg(trampoline)]
1890+
#[cfg_attr(trampoline, allow(unused))]
1891+
pub enum InboundTrampolinePayload {
1892+
Forward(InboundTrampolineForwardPayload),
1893+
BlindedForward(InboundTrampolineBlindedForwardPayload),
1894+
Receive(InboundOnionReceivePayload),
1895+
BlindedReceive(InboundOnionBlindedReceivePayload),
1896+
}
1897+
18631898
pub(crate) enum OutboundOnionPayload<'a> {
18641899
Forward {
18651900
short_channel_id: u64,
@@ -3008,7 +3043,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
30083043
return Ok(Self::TrampolineEntrypoint(InboundTrampolineEntrypointPayload {
30093044
amt_to_forward: amt.ok_or(DecodeError::InvalidValue)?,
30103045
outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
3011-
multipath_trampoline_data: payment_data,
3046+
multipath_trampoline_data: payment_data.ok_or(DecodeError::InvalidValue)?,
30123047
trampoline_packet: trampoline_onion_packet,
30133048
current_path_key: intro_node_blinding_point,
30143049
}))
@@ -3097,6 +3132,134 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
30973132
}
30983133
}
30993134

3135+
#[cfg(trampoline)]
3136+
impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundTrampolinePayload where NS::Target: NodeSigner {
3137+
fn read<R: Read>(r: &mut R, args: (Option<PublicKey>, NS)) -> Result<Self, DecodeError> {
3138+
let (update_add_blinding_point, node_signer) = args;
3139+
3140+
let mut amt = None;
3141+
let mut cltv_value = None;
3142+
let mut payment_data: Option<FinalOnionHopData> = None;
3143+
let mut encrypted_tlvs_opt: Option<WithoutLength<Vec<u8>>> = None;
3144+
let mut intro_node_blinding_point = None;
3145+
let mut next_trampoline: Option<NodeId> = None;
3146+
let mut payment_metadata: Option<WithoutLength<Vec<u8>>> = None;
3147+
let mut total_msat = None;
3148+
let mut keysend_preimage: Option<PaymentPreimage> = None;
3149+
let mut invoice_request: Option<InvoiceRequest> = None;
3150+
let mut custom_tlvs = Vec::new();
3151+
3152+
let tlv_len = BigSize::read(r)?;
3153+
let mut rd = FixedLengthReader::new(r, tlv_len.0);
3154+
decode_tlv_stream_with_custom_tlv_decode!(&mut rd, {
3155+
(2, amt, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
3156+
(4, cltv_value, (option, encoding: (u32, HighZeroBytesDroppedBigSize))),
3157+
(8, payment_data, option),
3158+
(10, encrypted_tlvs_opt, option),
3159+
(12, intro_node_blinding_point, option),
3160+
(14, next_trampoline, option),
3161+
(16, payment_metadata, option),
3162+
(18, total_msat, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
3163+
(77_777, invoice_request, option),
3164+
// See https://github.com/lightning/blips/blob/master/blip-0003.md
3165+
(5482373484, keysend_preimage, option)
3166+
}, |msg_type: u64, msg_reader: &mut FixedLengthReader<_>| -> Result<bool, DecodeError> {
3167+
if msg_type < 1 << 16 { return Ok(false) }
3168+
let mut value = Vec::new();
3169+
msg_reader.read_to_limit(&mut value, u64::MAX)?;
3170+
custom_tlvs.push((msg_type, value));
3171+
Ok(true)
3172+
});
3173+
3174+
if amt.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
3175+
if intro_node_blinding_point.is_some() && update_add_blinding_point.is_some() {
3176+
return Err(DecodeError::InvalidValue)
3177+
}
3178+
3179+
if let Some(blinding_point) = intro_node_blinding_point.or(update_add_blinding_point) {
3180+
if next_trampoline.is_some() || payment_data.is_some() || payment_metadata.is_some() {
3181+
return Err(DecodeError::InvalidValue)
3182+
}
3183+
let enc_tlvs = encrypted_tlvs_opt.ok_or(DecodeError::InvalidValue)?.0;
3184+
let enc_tlvs_ss = node_signer.ecdh(Recipient::Node, &blinding_point, None)
3185+
.map_err(|_| DecodeError::InvalidValue)?;
3186+
let rho = onion_utils::gen_rho_from_shared_secret(&enc_tlvs_ss.secret_bytes());
3187+
let mut s = Cursor::new(&enc_tlvs);
3188+
let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64);
3189+
match ChaChaPolyReadAdapter::read(&mut reader, rho)? {
3190+
ChaChaPolyReadAdapter { readable: BlindedTrampolineTlvs::Forward(TrampolineForwardTlvs {
3191+
next_trampoline, payment_relay, payment_constraints, features, next_blinding_override
3192+
})} => {
3193+
if amt.is_some() || cltv_value.is_some() || total_msat.is_some() ||
3194+
keysend_preimage.is_some() || invoice_request.is_some()
3195+
{
3196+
return Err(DecodeError::InvalidValue)
3197+
}
3198+
Ok(Self::BlindedForward(InboundTrampolineBlindedForwardPayload {
3199+
next_trampoline,
3200+
payment_relay,
3201+
payment_constraints,
3202+
features,
3203+
intro_node_blinding_point,
3204+
next_blinding_override,
3205+
}))
3206+
},
3207+
ChaChaPolyReadAdapter { readable: BlindedTrampolineTlvs::Receive(receive_tlvs) } => {
3208+
let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs;
3209+
let expanded_key = node_signer.get_inbound_payment_key();
3210+
if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() {
3211+
return Err(DecodeError::InvalidValue);
3212+
}
3213+
3214+
let UnauthenticatedReceiveTlvs {
3215+
payment_secret, payment_constraints, payment_context,
3216+
} = tlvs;
3217+
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
3218+
Ok(Self::BlindedReceive(InboundOnionBlindedReceivePayload {
3219+
sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
3220+
total_msat: total_msat.ok_or(DecodeError::InvalidValue)?,
3221+
cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
3222+
payment_secret,
3223+
payment_constraints,
3224+
payment_context,
3225+
intro_node_blinding_point,
3226+
keysend_preimage,
3227+
invoice_request,
3228+
custom_tlvs,
3229+
}))
3230+
},
3231+
}
3232+
} else if let Some(next_trampoline) = next_trampoline {
3233+
if payment_data.is_some() || payment_metadata.is_some() || encrypted_tlvs_opt.is_some() ||
3234+
total_msat.is_some() || invoice_request.is_some()
3235+
{ return Err(DecodeError::InvalidValue) }
3236+
Ok(Self::Forward(InboundTrampolineForwardPayload {
3237+
next_trampoline,
3238+
amt_to_forward: amt.ok_or(DecodeError::InvalidValue)?,
3239+
outgoing_cltv_value: cltv_value.ok_or(DecodeError::InvalidValue)?,
3240+
}))
3241+
} else {
3242+
if encrypted_tlvs_opt.is_some() || total_msat.is_some() || invoice_request.is_some() {
3243+
return Err(DecodeError::InvalidValue)
3244+
}
3245+
if let Some(data) = &payment_data {
3246+
if data.total_msat > MAX_VALUE_MSAT {
3247+
return Err(DecodeError::InvalidValue);
3248+
}
3249+
}
3250+
Ok(Self::Receive(InboundOnionReceivePayload {
3251+
payment_data,
3252+
payment_metadata: payment_metadata.map(|w| w.0),
3253+
keysend_preimage,
3254+
sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,
3255+
cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?,
3256+
custom_tlvs,
3257+
}))
3258+
}
3259+
}
3260+
}
3261+
3262+
31003263
impl Writeable for Ping {
31013264
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
31023265
self.ponglen.write(w)?;

0 commit comments

Comments
 (0)