Skip to content

Commit 3adb9cc

Browse files
committed
Introduce custom_tlvs field in payer-facing functions
With internal support for custom TLVs now in place, this commit extends that capability to all payer-facing entry points, from `create_refund_builder` to the various `pay_for_offer` functions. This brings the full Bolt12 payer API in line with the Bolt11 flow and ensures that callers can attach custom metadata consistently across all payment flows.
1 parent 0c3a235 commit 3adb9cc

File tree

5 files changed

+145
-79
lines changed

5 files changed

+145
-79
lines changed

lightning-dns-resolver/src/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ mod test {
380380
nodes: &[Node<'a, 'b, 'c>], resolver_messenger: &impl AOnionMessenger,
381381
resolver_id: PublicKey, payer_id: PublicKey, payee_id: PublicKey, offer: Offer,
382382
name: HumanReadableName, payment_id: PaymentId, payer_note: Option<String>,
383-
resolvers: Vec<Destination>,
383+
custom_tlvs: Vec<(u64, Vec<u8>)>, resolvers: Vec<Destination>,
384384
) {
385385
// Override contents to offer provided
386386
let proof_override = &nodes[0].node.testing_dnssec_proof_offer_resolution_override;
@@ -391,7 +391,7 @@ mod test {
391391
#[allow(deprecated)]
392392
nodes[0]
393393
.node
394-
.pay_for_offer_from_human_readable_name(name, amt, payment_id, opts, resolvers)
394+
.pay_for_offer_from_human_readable_name(name, amt, payment_id, custom_tlvs, opts, resolvers)
395395
.unwrap();
396396

397397
let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap();
@@ -499,6 +499,7 @@ mod test {
499499
name.clone(),
500500
PaymentId([42; 32]),
501501
None,
502+
vec![],
502503
resolvers.clone(),
503504
)
504505
.await;
@@ -510,11 +511,12 @@ mod test {
510511
resolver_id,
511512
payer_id,
512513
payee_id,
513-
bs_offer,
514-
name,
514+
bs_offer.clone(),
515+
name.clone(),
515516
PaymentId([21; 32]),
516517
Some("foo".into()),
517-
resolvers,
518+
vec![],
519+
resolvers.clone(),
518520
)
519521
.await;
520522
}

lightning/src/ln/async_payments_tests.rs

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,10 @@ fn build_async_offer_and_init_payment(
547547

548548
let offer = recipient.node.get_async_receive_offer().unwrap();
549549
let payment_id = PaymentId([1; 32]);
550-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
550+
sender
551+
.node
552+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
553+
.unwrap();
551554

552555
// Forward invreq to server, pass static invoice back
553556
let (peer_id, invreq_om) = extract_invoice_request_om(sender, &[sender_lsp, invoice_server]);
@@ -705,7 +708,10 @@ fn static_invoice_unknown_required_features() {
705708
// unknown required features.
706709
let amt_msat = 5000;
707710
let payment_id = PaymentId([1; 32]);
708-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
711+
nodes[0]
712+
.node
713+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
714+
.unwrap();
709715

710716
// Don't forward the invreq since the invoice was created outside of the normal flow, instead
711717
// manually construct the response.
@@ -777,7 +783,10 @@ fn ignore_unexpected_static_invoice() {
777783

778784
let amt_msat = 5000;
779785
let payment_id = PaymentId([1; 32]);
780-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
786+
nodes[0]
787+
.node
788+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
789+
.unwrap();
781790

782791
let invreq_om = nodes[0]
783792
.onion_messenger
@@ -906,7 +915,10 @@ fn ignore_duplicate_invoice() {
906915
let offer = async_recipient.node.get_async_receive_offer().unwrap();
907916
let amt_msat = 5000;
908917
let payment_id = PaymentId([1; 32]);
909-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
918+
sender
919+
.node
920+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
921+
.unwrap();
910922

911923
let sender_node_id = sender.node.get_our_node_id();
912924
let always_online_node_id = always_online_node.node.get_our_node_id();
@@ -1004,7 +1016,10 @@ fn ignore_duplicate_invoice() {
10041016

10051017
// Now handle case where the sender pays regular invoice and ignores static invoice.
10061018
let payment_id = PaymentId([2; 32]);
1007-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1019+
sender
1020+
.node
1021+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1022+
.unwrap();
10081023

10091024
let invreq_om =
10101025
sender.onion_messenger.next_onion_message_for_peer(always_online_node_id).unwrap();
@@ -1110,7 +1125,10 @@ fn async_receive_flow_success() {
11101125
let offer = nodes[2].node.get_async_receive_offer().unwrap();
11111126
let amt_msat = 5000;
11121127
let payment_id = PaymentId([1; 32]);
1113-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1128+
nodes[0]
1129+
.node
1130+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1131+
.unwrap();
11141132
let release_held_htlc_om = pass_async_payments_oms(
11151133
static_invoice.clone(),
11161134
&nodes[0],
@@ -1170,7 +1188,10 @@ fn expired_static_invoice_fail() {
11701188

11711189
let amt_msat = 5000;
11721190
let payment_id = PaymentId([1; 32]);
1173-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1191+
nodes[0]
1192+
.node
1193+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1194+
.unwrap();
11741195

11751196
let invreq_om = nodes[0]
11761197
.onion_messenger
@@ -1253,7 +1274,10 @@ fn timeout_unreleased_payment() {
12531274

12541275
let amt_msat = 5000;
12551276
let payment_id = PaymentId([1; 32]);
1256-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1277+
sender
1278+
.node
1279+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1280+
.unwrap();
12571281

12581282
let invreq_om =
12591283
sender.onion_messenger.next_onion_message_for_peer(server.node.get_our_node_id()).unwrap();
@@ -1347,7 +1371,10 @@ fn async_receive_mpp() {
13471371

13481372
let amt_msat = 15_000_000;
13491373
let payment_id = PaymentId([1; 32]);
1350-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1374+
nodes[0]
1375+
.node
1376+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1377+
.unwrap();
13511378
let release_held_htlc_om_3_0 = pass_async_payments_oms(
13521379
static_invoice,
13531380
&nodes[0],
@@ -1445,7 +1472,10 @@ fn amount_doesnt_match_invreq() {
14451472

14461473
let amt_msat = 5000;
14471474
let payment_id = PaymentId([1; 32]);
1448-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1475+
nodes[0]
1476+
.node
1477+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1478+
.unwrap();
14491479
let release_held_htlc_om_3_0 = pass_async_payments_oms(
14501480
static_invoice,
14511481
&nodes[0],
@@ -1688,7 +1718,10 @@ fn invalid_async_receive_with_retry<F1, F2>(
16881718
let static_invoice = invoice_flow_res.invoice;
16891719
let offer = nodes[2].node.get_async_receive_offer().unwrap();
16901720

1691-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1721+
nodes[0]
1722+
.node
1723+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1724+
.unwrap();
16921725
let release_held_htlc_om_2_0 = pass_async_payments_oms(
16931726
static_invoice,
16941727
&nodes[0],
@@ -1782,7 +1815,10 @@ fn expired_static_invoice_message_path() {
17821815

17831816
let amt_msat = 5000;
17841817
let payment_id = PaymentId([1; 32]);
1785-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
1818+
nodes[0]
1819+
.node
1820+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
1821+
.unwrap();
17861822

17871823
// While the invoice is unexpired, respond with release_held_htlc.
17881824
let (held_htlc_available_om, _release_held_htlc_om) = pass_async_payments_oms(
@@ -1897,7 +1933,7 @@ fn expired_static_invoice_payment_path() {
18971933
let payment_id = PaymentId([1; 32]);
18981934
let mut params: OptionalOfferPaymentParams = Default::default();
18991935
params.retry_strategy = Retry::Attempts(0);
1900-
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, params).unwrap();
1936+
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], params).unwrap();
19011937
let release_held_htlc_om = pass_async_payments_oms(
19021938
static_invoice,
19031939
&nodes[0],
@@ -2341,7 +2377,10 @@ fn refresh_static_invoices_for_used_offers() {
23412377
let offer = recipient.node.get_async_receive_offer().unwrap();
23422378
let amt_msat = 5000;
23432379
let payment_id = PaymentId([1; 32]);
2344-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
2380+
sender
2381+
.node
2382+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
2383+
.unwrap();
23452384

23462385
let release_held_htlc_om = pass_async_payments_oms(
23472386
updated_invoice.clone(),
@@ -2673,7 +2712,10 @@ fn invoice_server_is_not_channel_peer() {
26732712
let offer = recipient.node.get_async_receive_offer().unwrap();
26742713
let amt_msat = 5000;
26752714
let payment_id = PaymentId([1; 32]);
2676-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
2715+
sender
2716+
.node
2717+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
2718+
.unwrap();
26772719

26782720
// Do the held_htlc_available --> release_held_htlc dance.
26792721
let release_held_htlc_om = pass_async_payments_oms(
@@ -2735,7 +2777,10 @@ fn invoice_request_forwarded_to_async_recipient() {
27352777
let offer = async_recipient.node.get_async_receive_offer().unwrap();
27362778
let amt_msat = 5000;
27372779
let payment_id = PaymentId([1; 32]);
2738-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
2780+
sender
2781+
.node
2782+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
2783+
.unwrap();
27392784

27402785
let sender_node_id = sender.node.get_our_node_id();
27412786

@@ -2836,7 +2881,10 @@ fn async_payment_e2e() {
28362881

28372882
let amt_msat = 5000;
28382883
let payment_id = PaymentId([1; 32]);
2839-
sender.node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
2884+
sender
2885+
.node
2886+
.pay_for_offer(&offer, Some(amt_msat), payment_id, vec![], Default::default())
2887+
.unwrap();
28402888

28412889
// Forward invreq to server, pass static invoice back, check that htlc was locked in/monitor was
28422890
// added

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,9 +2374,12 @@ where
23742374
/// # channel_manager: T, offer: &Offer, amount_msats: Option<u64>,
23752375
/// # ) {
23762376
/// # let channel_manager = channel_manager.get_cm();
2377-
/// let payment_id = PaymentId([42; 32]);
2377+
/// # let payment_id = PaymentId([42; 32]);
2378+
/// # let custom_tlvs = vec![
2379+
/// # (343493u64, b"hello".to_vec()),
2380+
/// # ];
23782381
/// match channel_manager.pay_for_offer(
2379-
/// offer, amount_msats, payment_id, Default::default(),
2382+
/// offer, amount_msats, payment_id, custom_tlvs, Default::default(),
23802383
/// ) {
23812384
/// Ok(()) => println!("Requesting invoice for offer"),
23822385
/// Err(e) => println!("Unable to request invoice for offer: {:?}", e),
@@ -2431,10 +2434,13 @@ where
24312434
/// # route_params_config: RouteParametersConfig
24322435
/// # ) -> Result<(), Bolt12SemanticError> {
24332436
/// # let channel_manager = channel_manager.get_cm();
2434-
/// let payment_id = PaymentId([42; 32]);
2437+
/// # let payment_id = PaymentId([42; 32]);
2438+
/// # let custom_tlvs = vec![
2439+
/// # (343493u64, b"hello".to_vec()),
2440+
/// # ];
24352441
/// let refund = channel_manager
24362442
/// .create_refund_builder(
2437-
/// amount_msats, absolute_expiry, payment_id, retry, route_params_config
2443+
/// amount_msats, absolute_expiry, payment_id, custom_tlvs, retry, route_params_config
24382444
/// )?
24392445
/// # ;
24402446
/// # // Needed for compiling for c_bindings
@@ -12874,7 +12880,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1287412880
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
1287512881
pub fn create_refund_builder(
1287612882
&$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
12877-
retry_strategy: Retry, route_params_config: RouteParametersConfig
12883+
custom_tlvs: Vec<(u64, Vec<u8>)>, retry_strategy: Retry,
12884+
route_params_config: RouteParametersConfig
1287812885
) -> Result<$builder, Bolt12SemanticError> {
1287912886
let entropy = &*$self.entropy_source;
1288012887

@@ -12888,7 +12895,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1288812895
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
1288912896
$self.pending_outbound_payments
1289012897
.add_new_awaiting_invoice(
12891-
payment_id, vec![], expiration, retry_strategy, route_params_config, None,
12898+
payment_id, custom_tlvs, expiration, retry_strategy, route_params_config, None,
1289212899
)
1289312900
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
1289412901

@@ -12915,7 +12922,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1291512922
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
1291612923
pub fn create_refund_builder_using_router<ME: Deref>(
1291712924
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
12918-
retry_strategy: Retry, route_params_config: RouteParametersConfig
12925+
custom_tlvs: Vec<(u64, Vec<u8>)>, retry_strategy: Retry,
12926+
route_params_config: RouteParametersConfig
1291912927
) -> Result<$builder, Bolt12SemanticError>
1292012928
where
1292112929
ME::Target: MessageRouter,
@@ -12932,7 +12940,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1293212940
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
1293312941
$self.pending_outbound_payments
1293412942
.add_new_awaiting_invoice(
12935-
payment_id, vec![], expiration, retry_strategy, route_params_config, None,
12943+
payment_id, custom_tlvs, expiration, retry_strategy, route_params_config, None,
1293612944
)
1293712945
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
1293812946

@@ -13048,13 +13056,13 @@ where
1304813056
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
1304913057
pub fn pay_for_offer(
1305013058
&self, offer: &Offer, amount_msats: Option<u64>, payment_id: PaymentId,
13051-
optional_params: OptionalOfferPaymentParams,
13059+
custom_tlvs: Vec<(u64, Vec<u8>)>, optional_params: OptionalOfferPaymentParams,
1305213060
) -> Result<(), Bolt12SemanticError> {
1305313061
let create_pending_payment_fn = |retryable_invoice_request: RetryableInvoiceRequest| {
1305413062
self.pending_outbound_payments
1305513063
.add_new_awaiting_invoice(
1305613064
payment_id,
13057-
vec![],
13065+
custom_tlvs,
1305813066
StaleExpiration::TimerTicks(1),
1305913067
optional_params.retry_strategy,
1306013068
optional_params.route_params_config,
@@ -13078,13 +13086,13 @@ where
1307813086
/// identical to [`Self::pay_for_offer`].
1307913087
pub fn pay_for_offer_from_hrn(
1308013088
&self, offer: &OfferFromHrn, amount_msats: u64, payment_id: PaymentId,
13081-
optional_params: OptionalOfferPaymentParams,
13089+
custom_tlvs: Vec<(u64, Vec<u8>)>, optional_params: OptionalOfferPaymentParams,
1308213090
) -> Result<(), Bolt12SemanticError> {
1308313091
let create_pending_payment_fn = |retryable_invoice_request: RetryableInvoiceRequest| {
1308413092
self.pending_outbound_payments
1308513093
.add_new_awaiting_invoice(
1308613094
payment_id,
13087-
vec![],
13095+
custom_tlvs,
1308813096
StaleExpiration::TimerTicks(1),
1308913097
optional_params.retry_strategy,
1309013098
optional_params.route_params_config,
@@ -13121,13 +13129,14 @@ where
1312113129
/// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
1312213130
pub fn pay_for_offer_with_quantity(
1312313131
&self, offer: &Offer, amount_msats: Option<u64>, payment_id: PaymentId,
13124-
optional_params: OptionalOfferPaymentParams, quantity: u64,
13132+
custom_tlvs: Vec<(u64, Vec<u8>)>, optional_params: OptionalOfferPaymentParams,
13133+
quantity: u64,
1312513134
) -> Result<(), Bolt12SemanticError> {
1312613135
let create_pending_payment_fn = |retryable_invoice_request: RetryableInvoiceRequest| {
1312713136
self.pending_outbound_payments
1312813137
.add_new_awaiting_invoice(
1312913138
payment_id,
13130-
vec![],
13139+
custom_tlvs,
1313113140
StaleExpiration::TimerTicks(1),
1313213141
optional_params.retry_strategy,
1313313142
optional_params.route_params_config,
@@ -13283,15 +13292,16 @@ where
1328313292
#[deprecated(note = "Use bitcoin-payment-instructions and pay_for_offer_from_hrn instead")]
1328413293
pub fn pay_for_offer_from_human_readable_name(
1328513294
&self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
13286-
optional_params: OptionalOfferPaymentParams, dns_resolvers: Vec<Destination>,
13295+
custom_tlvs: Vec<(u64, Vec<u8>)>, optional_params: OptionalOfferPaymentParams,
13296+
dns_resolvers: Vec<Destination>,
1328713297
) -> Result<(), ()> {
1328813298
let (onion_message, context) =
1328913299
self.flow.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
1329013300

1329113301
let expiration = StaleExpiration::TimerTicks(1);
1329213302
self.pending_outbound_payments.add_new_awaiting_offer(
1329313303
payment_id,
13294-
vec![],
13304+
custom_tlvs,
1329513305
expiration,
1329613306
optional_params.retry_strategy,
1329713307
optional_params.route_params_config,

lightning/src/ln/max_payment_path_len_tests.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,13 @@ fn bolt12_invoice_too_large_blinded_paths() {
519519
let payment_id = PaymentId([1; 32]);
520520
nodes[0]
521521
.node
522-
.pay_for_offer(&offer, Some(5000), payment_id, OptionalOfferPaymentParams::default())
522+
.pay_for_offer(
523+
&offer,
524+
Some(5000),
525+
payment_id,
526+
vec![],
527+
OptionalOfferPaymentParams::default(),
528+
)
523529
.unwrap();
524530
let invreq_om = nodes[0]
525531
.onion_messenger

0 commit comments

Comments
 (0)