Skip to content

Commit 73aedd4

Browse files
committed
Add PaymentContext to payment::ReceiveTlvs
Providing LDK-specific data in a BlindedPath allows for the data to be received with the corresponding payment. This is useful as it can then be surfaced in PaymentClaimable events where the user may correlated with an Offer, for instance. Define a PaymentContext enum for including various context (e.g., offer, refund, static invoice).
1 parent f28f919 commit 73aedd4

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

lightning/src/blinded_path/payment.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::ln::channelmanager::CounterpartyForwardingInfo;
1212
use crate::ln::features::BlindedHopFeatures;
1313
use crate::ln::msgs::DecodeError;
1414
use crate::offers::invoice::BlindedPayInfo;
15+
use crate::offers::offer::OfferId;
1516
use crate::prelude::*;
1617
use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
1718

@@ -53,6 +54,8 @@ pub struct ReceiveTlvs {
5354
pub payment_secret: PaymentSecret,
5455
/// Constraints for the receiver of this payment.
5556
pub payment_constraints: PaymentConstraints,
57+
/// Context for the receiver of this payment.
58+
pub payment_context: Option<PaymentContext>,
5659
}
5760

5861
/// Data to construct a [`BlindedHop`] for sending a payment over.
@@ -97,6 +100,24 @@ pub struct PaymentConstraints {
97100
pub htlc_minimum_msat: u64,
98101
}
99102

103+
/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`]
104+
/// and surfaced in [`Event::PaymentClaimable`].
105+
///
106+
/// [`BlindedPath`]: crate::blinded_path::BlindedPath
107+
/// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
108+
#[derive(Clone, Debug)]
109+
pub enum PaymentContext {
110+
/// The payment was made for an invoice requested from a BOLT 12 [`Offer`].
111+
///
112+
/// [`Offer`]: crate::offers::offer::Offer
113+
Bolt12Offer {
114+
/// The identifier of the [`Offer`].
115+
///
116+
/// [`Offer`]: crate::offers::offer::Offer
117+
offer_id: OfferId,
118+
},
119+
}
120+
100121
impl TryFrom<CounterpartyForwardingInfo> for PaymentRelay {
101122
type Error = ();
102123

@@ -137,7 +158,8 @@ impl Writeable for ReceiveTlvs {
137158
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
138159
encode_tlv_stream!(w, {
139160
(12, self.payment_constraints, required),
140-
(65536, self.payment_secret, required)
161+
(65536, self.payment_secret, required),
162+
(65537, self.payment_context, option)
141163
});
142164
Ok(())
143165
}
@@ -163,11 +185,14 @@ impl Readable for BlindedPaymentTlvs {
163185
(12, payment_constraints, required),
164186
(14, features, option),
165187
(65536, payment_secret, option),
188+
(65537, payment_context, upgradable_option),
166189
});
167190
let _padding: Option<utils::Padding> = _padding;
168191

169192
if let Some(short_channel_id) = scid {
170-
if payment_secret.is_some() { return Err(DecodeError::InvalidValue) }
193+
if payment_secret.is_some() || payment_context.is_some() {
194+
return Err(DecodeError::InvalidValue)
195+
}
171196
Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
172197
short_channel_id,
173198
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
@@ -179,6 +204,7 @@ impl Readable for BlindedPaymentTlvs {
179204
Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
180205
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
181206
payment_constraints: payment_constraints.0.unwrap(),
207+
payment_context: payment_context,
182208
}))
183209
}
184210
}
@@ -309,6 +335,12 @@ impl Readable for PaymentConstraints {
309335
}
310336
}
311337

338+
impl_writeable_tlv_based_enum_upgradable!(PaymentContext,
339+
(0, Bolt12Offer) => {
340+
(0, offer_id, required),
341+
},
342+
);
343+
312344
#[cfg(test)]
313345
mod tests {
314346
use bitcoin::secp256k1::PublicKey;
@@ -361,6 +393,7 @@ mod tests {
361393
max_cltv_expiry: 0,
362394
htlc_minimum_msat: 1,
363395
},
396+
payment_context: None,
364397
};
365398
let htlc_maximum_msat = 100_000;
366399
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap();
@@ -379,6 +412,7 @@ mod tests {
379412
max_cltv_expiry: 0,
380413
htlc_minimum_msat: 1,
381414
},
415+
payment_context: None,
382416
};
383417
let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap();
384418
assert_eq!(blinded_payinfo.fee_base_msat, 0);
@@ -432,6 +466,7 @@ mod tests {
432466
max_cltv_expiry: 0,
433467
htlc_minimum_msat: 3,
434468
},
469+
payment_context: None,
435470
};
436471
let htlc_maximum_msat = 100_000;
437472
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap();
@@ -482,6 +517,7 @@ mod tests {
482517
max_cltv_expiry: 0,
483518
htlc_minimum_msat: 1,
484519
},
520+
payment_context: None,
485521
};
486522
let htlc_minimum_msat = 3798;
487523
assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err());
@@ -536,6 +572,7 @@ mod tests {
536572
max_cltv_expiry: 0,
537573
htlc_minimum_msat: 1,
538574
},
575+
payment_context: None,
539576
};
540577

541578
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, 10_000, TEST_FINAL_CLTV as u16).unwrap();

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ fn blinded_payment_path(
6363
htlc_minimum_msat:
6464
intro_node_min_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_minimum_msat),
6565
},
66+
payment_context: None,
6667
};
6768
let mut secp_ctx = Secp256k1::new();
6869
BlindedPath::new_for_payment(
@@ -108,6 +109,7 @@ fn do_one_hop_blinded_path(success: bool) {
108109
max_cltv_expiry: u32::max_value(),
109110
htlc_minimum_msat: chan_upd.htlc_minimum_msat,
110111
},
112+
payment_context: None,
111113
};
112114
let mut secp_ctx = Secp256k1::new();
113115
let blinded_path = BlindedPath::one_hop_for_payment(
@@ -151,6 +153,7 @@ fn mpp_to_one_hop_blinded_path() {
151153
max_cltv_expiry: u32::max_value(),
152154
htlc_minimum_msat: chan_upd_1_3.htlc_minimum_msat,
153155
},
156+
payment_context: None,
154157
};
155158
let blinded_path = BlindedPath::one_hop_for_payment(
156159
nodes[3].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8149,6 +8149,7 @@ where
81498149
max_cltv_expiry,
81508150
htlc_minimum_msat: 1,
81518151
},
8152+
payment_context: None,
81528153
};
81538154
self.router.create_blinded_payment_paths(
81548155
payee_node_id, first_hops, payee_tlvs, amount_msats, secp_ctx

lightning/src/ln/msgs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2666,7 +2666,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
26662666
})
26672667
},
26682668
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
2669-
payment_secret, payment_constraints
2669+
payment_secret, payment_constraints, payment_context: _
26702670
})} => {
26712671
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
26722672
Ok(Self::BlindedReceive {

0 commit comments

Comments
 (0)