Skip to content

Commit c881538

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 12c3a24 commit c881538

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

lightning/src/blinded_path/payment.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub struct ReceiveTlvs {
5353
pub payment_secret: PaymentSecret,
5454
/// Constraints for the receiver of this payment.
5555
pub payment_constraints: PaymentConstraints,
56+
/// Context for the receiver of this payment.
57+
pub payment_context: PaymentContext,
5658
}
5759

5860
/// Data to construct a [`BlindedHop`] for sending a payment over.
@@ -97,6 +99,27 @@ pub struct PaymentConstraints {
9799
pub htlc_minimum_msat: u64,
98100
}
99101

102+
/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`]
103+
/// and surfaced in [`PaymentPurpose`].
104+
///
105+
/// [`BlindedPath`]: crate::blinded_path::BlindedPath
106+
/// [`PaymentPurpose`]: crate::events::PaymentPurpose
107+
#[derive(Clone, Debug)]
108+
pub enum PaymentContext {
109+
/// The payment context was unknown.
110+
Unknown(UnknownPaymentContext),
111+
}
112+
113+
/// An unknown payment context.
114+
#[derive(Clone, Debug)]
115+
pub struct UnknownPaymentContext(());
116+
117+
impl PaymentContext {
118+
pub(crate) fn unknown() -> Self {
119+
PaymentContext::Unknown(UnknownPaymentContext(()))
120+
}
121+
}
122+
100123
impl TryFrom<CounterpartyForwardingInfo> for PaymentRelay {
101124
type Error = ();
102125

@@ -137,7 +160,8 @@ impl Writeable for ReceiveTlvs {
137160
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
138161
encode_tlv_stream!(w, {
139162
(12, self.payment_constraints, required),
140-
(65536, self.payment_secret, required)
163+
(65536, self.payment_secret, required),
164+
(65537, self.payment_context, required)
141165
});
142166
Ok(())
143167
}
@@ -163,11 +187,14 @@ impl Readable for BlindedPaymentTlvs {
163187
(12, payment_constraints, required),
164188
(14, features, option),
165189
(65536, payment_secret, option),
190+
(65537, payment_context, (default_value, PaymentContext::unknown())),
166191
});
167192
let _padding: Option<utils::Padding> = _padding;
168193

169194
if let Some(short_channel_id) = scid {
170-
if payment_secret.is_some() { return Err(DecodeError::InvalidValue) }
195+
if payment_secret.is_some() {
196+
return Err(DecodeError::InvalidValue)
197+
}
171198
Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
172199
short_channel_id,
173200
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
@@ -179,6 +206,7 @@ impl Readable for BlindedPaymentTlvs {
179206
Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
180207
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
181208
payment_constraints: payment_constraints.0.unwrap(),
209+
payment_context: payment_context.0.unwrap(),
182210
}))
183211
}
184212
}
@@ -309,10 +337,27 @@ impl Readable for PaymentConstraints {
309337
}
310338
}
311339

340+
impl_writeable_tlv_based_enum!(PaymentContext,
341+
;
342+
(0, Unknown),
343+
);
344+
345+
impl Writeable for UnknownPaymentContext {
346+
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), io::Error> {
347+
Ok(())
348+
}
349+
}
350+
351+
impl Readable for UnknownPaymentContext {
352+
fn read<R: io::Read>(_r: &mut R) -> Result<Self, DecodeError> {
353+
Ok(UnknownPaymentContext(()))
354+
}
355+
}
356+
312357
#[cfg(test)]
313358
mod tests {
314359
use bitcoin::secp256k1::PublicKey;
315-
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, ReceiveTlvs, PaymentConstraints, PaymentRelay};
360+
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, ReceiveTlvs, PaymentConstraints, PaymentContext, PaymentRelay};
316361
use crate::ln::PaymentSecret;
317362
use crate::ln::features::BlindedHopFeatures;
318363
use crate::ln::functional_test_utils::TEST_FINAL_CLTV;
@@ -361,6 +406,7 @@ mod tests {
361406
max_cltv_expiry: 0,
362407
htlc_minimum_msat: 1,
363408
},
409+
payment_context: PaymentContext::unknown(),
364410
};
365411
let htlc_maximum_msat = 100_000;
366412
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap();
@@ -379,6 +425,7 @@ mod tests {
379425
max_cltv_expiry: 0,
380426
htlc_minimum_msat: 1,
381427
},
428+
payment_context: PaymentContext::unknown(),
382429
};
383430
let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap();
384431
assert_eq!(blinded_payinfo.fee_base_msat, 0);
@@ -432,6 +479,7 @@ mod tests {
432479
max_cltv_expiry: 0,
433480
htlc_minimum_msat: 3,
434481
},
482+
payment_context: PaymentContext::unknown(),
435483
};
436484
let htlc_maximum_msat = 100_000;
437485
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap();
@@ -482,6 +530,7 @@ mod tests {
482530
max_cltv_expiry: 0,
483531
htlc_minimum_msat: 1,
484532
},
533+
payment_context: PaymentContext::unknown(),
485534
};
486535
let htlc_minimum_msat = 3798;
487536
assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err());
@@ -536,6 +585,7 @@ mod tests {
536585
max_cltv_expiry: 0,
537586
htlc_minimum_msat: 1,
538587
},
588+
payment_context: PaymentContext::unknown(),
539589
};
540590

541591
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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
1111
use crate::blinded_path::BlindedPath;
12-
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs};
12+
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
1313
use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PaymentFailureReason};
1414
use crate::ln::PaymentSecret;
1515
use crate::ln::channelmanager;
@@ -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: PaymentContext::unknown(),
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: PaymentContext::unknown(),
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: PaymentContext::unknown(),
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,
@@ -1281,6 +1284,7 @@ fn custom_tlvs_to_blinded_path() {
12811284
max_cltv_expiry: u32::max_value(),
12821285
htlc_minimum_msat: chan_upd.htlc_minimum_msat,
12831286
},
1287+
payment_context: PaymentContext::unknown(),
12841288
};
12851289
let mut secp_ctx = Secp256k1::new();
12861290
let blinded_path = BlindedPath::one_hop_for_payment(

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use bitcoin::secp256k1::Secp256k1;
3232
use bitcoin::{secp256k1, Sequence};
3333

3434
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
35-
use crate::blinded_path::payment::{PaymentConstraints, ReceiveTlvs};
35+
use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs};
3636
use crate::chain;
3737
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
3838
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -8995,6 +8995,7 @@ where
89958995
max_cltv_expiry,
89968996
htlc_minimum_msat: 1,
89978997
},
8998+
payment_context: PaymentContext::unknown(),
89988999
};
89999000
self.router.create_blinded_payment_paths(
90009001
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
@@ -2713,7 +2713,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, &NS)> for InboundOnionPayload w
27132713
})
27142714
},
27152715
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
2716-
payment_secret, payment_constraints
2716+
payment_secret, payment_constraints, payment_context: _
27172717
})} => {
27182718
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
27192719
Ok(Self::BlindedReceive {

0 commit comments

Comments
 (0)