Skip to content

Commit 901f72d

Browse files
authored
Merge pull request #3808 from elnosh/payer-note-hrn
Allow setting a `payer_note` on `pay_for_offer_from_human_readable_name`
2 parents 36fe491 + 91cedd1 commit 901f72d

File tree

4 files changed

+124
-19
lines changed

4 files changed

+124
-19
lines changed

ci/ci-tests.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ for DIR in "${WORKSPACE_MEMBERS[@]}"; do
7474
cargo doc -p "$DIR" --document-private-items
7575
done
7676

77+
echo -e "\n\nChecking and testing lightning with features"
78+
cargo test -p lightning --verbose --color always --features dnssec
79+
cargo check -p lightning --verbose --color always --features dnssec
80+
cargo doc -p lightning --document-private-items --features dnssec
81+
7782
echo -e "\n\nChecking and testing Block Sync Clients with features"
7883

7984
cargo test -p lightning-block-sync --verbose --color always --features rest-client

lightning-dns-resolver/src/lib.rs

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ mod test {
182182
commitment_signed_dance, expect_payment_claimed, expect_pending_htlcs_forwardable,
183183
get_htlc_update_msgs,
184184
};
185+
use lightning_types::string::UntrustedString;
185186

186187
use std::ops::Deref;
187188
use std::sync::Mutex;
@@ -396,7 +397,7 @@ mod test {
396397
// When we get the proof back, override its contents to an offer from nodes[1]
397398
let bs_offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
398399
let proof_override = &nodes[0].node.testing_dnssec_proof_offer_resolution_override;
399-
proof_override.lock().unwrap().insert(name.clone(), bs_offer);
400+
proof_override.lock().unwrap().insert(name.clone(), bs_offer.clone());
400401

401402
let payment_id = PaymentId([42; 32]);
402403
let resolvers = vec![Destination::Node(resolver_id)];
@@ -405,7 +406,86 @@ mod test {
405406
let params = RouteParametersConfig::default();
406407
nodes[0]
407408
.node
408-
.pay_for_offer_from_human_readable_name(name, amt, payment_id, retry, params, resolvers)
409+
.pay_for_offer_from_human_readable_name(
410+
name.clone(),
411+
amt,
412+
payment_id,
413+
None,
414+
retry,
415+
params,
416+
resolvers.clone(),
417+
)
418+
.unwrap();
419+
420+
let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap();
421+
resolver_messenger.get_om().handle_onion_message(payer_id, &query);
422+
423+
assert!(resolver_messenger.get_om().next_onion_message_for_peer(payer_id).is_none());
424+
let start = Instant::now();
425+
let response = loop {
426+
tokio::time::sleep(Duration::from_millis(10)).await;
427+
if let Some(msg) = resolver_messenger.get_om().next_onion_message_for_peer(payer_id) {
428+
break msg;
429+
}
430+
assert!(start.elapsed() < Duration::from_secs(10), "Resolution took too long");
431+
};
432+
433+
nodes[0].onion_messenger.handle_onion_message(resolver_id, &response);
434+
435+
let invreq = nodes[0].onion_messenger.next_onion_message_for_peer(payee_id).unwrap();
436+
nodes[1].onion_messenger.handle_onion_message(payer_id, &invreq);
437+
438+
let inv = nodes[1].onion_messenger.next_onion_message_for_peer(payer_id).unwrap();
439+
nodes[0].onion_messenger.handle_onion_message(payee_id, &inv);
440+
441+
check_added_monitors(&nodes[0], 1);
442+
let updates = get_htlc_update_msgs!(nodes[0], payee_id);
443+
nodes[1].node.handle_update_add_htlc(payer_id, &updates.update_add_htlcs[0]);
444+
commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
445+
expect_pending_htlcs_forwardable!(nodes[1]);
446+
447+
let claimable_events = nodes[1].node.get_and_clear_pending_events();
448+
assert_eq!(claimable_events.len(), 1);
449+
let our_payment_preimage;
450+
if let Event::PaymentClaimable { purpose, amount_msat, .. } = &claimable_events[0] {
451+
assert_eq!(*amount_msat, amt);
452+
if let PaymentPurpose::Bolt12OfferPayment {
453+
payment_preimage, payment_context, ..
454+
} = purpose
455+
{
456+
our_payment_preimage = payment_preimage.unwrap();
457+
nodes[1].node.claim_funds(our_payment_preimage);
458+
let payment_hash: PaymentHash = our_payment_preimage.into();
459+
expect_payment_claimed!(nodes[1], payment_hash, amt);
460+
assert_eq!(payment_context.invoice_request.payer_note_truncated, None);
461+
} else {
462+
panic!();
463+
}
464+
} else {
465+
panic!();
466+
}
467+
468+
check_added_monitors(&nodes[1], 1);
469+
let updates = get_htlc_update_msgs!(nodes[1], payer_id);
470+
nodes[0].node.handle_update_fulfill_htlc(payee_id, &updates.update_fulfill_htlcs[0]);
471+
commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
472+
473+
expect_payment_sent(&nodes[0], our_payment_preimage, None, true, true);
474+
475+
// Pay offer with payer_note
476+
let proof_override = &nodes[0].node.testing_dnssec_proof_offer_resolution_override;
477+
proof_override.lock().unwrap().insert(name.clone(), bs_offer);
478+
nodes[0]
479+
.node
480+
.pay_for_offer_from_human_readable_name(
481+
name,
482+
amt,
483+
PaymentId([21; 32]),
484+
Some("foo".into()),
485+
retry,
486+
params,
487+
resolvers,
488+
)
409489
.unwrap();
410490

411491
let query = nodes[0].onion_messenger.next_onion_message_for_peer(resolver_id).unwrap();
@@ -440,11 +520,18 @@ mod test {
440520
let our_payment_preimage;
441521
if let Event::PaymentClaimable { purpose, amount_msat, .. } = &claimable_events[0] {
442522
assert_eq!(*amount_msat, amt);
443-
if let PaymentPurpose::Bolt12OfferPayment { payment_preimage, .. } = purpose {
523+
if let PaymentPurpose::Bolt12OfferPayment {
524+
payment_preimage, payment_context, ..
525+
} = purpose
526+
{
444527
our_payment_preimage = payment_preimage.unwrap();
445528
nodes[1].node.claim_funds(our_payment_preimage);
446529
let payment_hash: PaymentHash = our_payment_preimage.into();
447530
expect_payment_claimed!(nodes[1], payment_hash, amt);
531+
assert_eq!(
532+
payment_context.invoice_request.payer_note_truncated,
533+
Some(UntrustedString("foo".into()))
534+
);
448535
} else {
449536
panic!();
450537
}

lightning/src/ln/channelmanager.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4876,7 +4876,7 @@ where
48764876
///
48774877
/// # Custom Routing Parameters
48784878
/// Users can customize routing parameters via [`RouteParametersConfig`].
4879-
/// To use default settings, call the function with `RouteParametersConfig::default()`.
4879+
/// To use default settings, call the function with [`RouteParametersConfig::default`].
48804880
pub fn pay_for_bolt11_invoice(
48814881
&self, invoice: &Bolt11Invoice, payment_id: PaymentId, amount_msats: Option<u64>,
48824882
route_params_config: RouteParametersConfig, retry_strategy: Retry
@@ -10390,8 +10390,10 @@ where
1039010390
/// - `amount_msats` if overpaying what is required for the given `quantity` is desired, and
1039110391
/// - `payer_note` for [`InvoiceRequest::payer_note`].
1039210392
///
10393-
/// If `max_total_routing_fee_msat` is not specified, The default from
10394-
/// [`RouteParameters::from_payment_params_and_value`] is applied.
10393+
/// # Custom Routing Parameters
10394+
///
10395+
/// Users can customize routing parameters via [`RouteParametersConfig`].
10396+
/// To use default settings, call the function with [`RouteParametersConfig::default`].
1039510397
///
1039610398
/// # Payment
1039710399
///
@@ -10545,15 +10547,17 @@ where
1054510547
}
1054610548

1054710549
/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
10548-
/// resolver(s) at `dns_resolvers` which resolve names according to bLIP 32.
10550+
/// resolver(s) at `dns_resolvers` which resolve names according to [bLIP 32].
1054910551
///
1055010552
/// If the wallet supports paying on-chain schemes, you should instead use
1055110553
/// [`OMNameResolver::resolve_name`] and [`OMNameResolver::handle_dnssec_proof_for_uri`] (by
1055210554
/// implementing [`DNSResolverMessageHandler`]) directly to look up a URI and then delegate to
1055310555
/// your normal URI handling.
1055410556
///
10555-
/// If `max_total_routing_fee_msat` is not specified, the default from
10556-
/// [`RouteParameters::from_payment_params_and_value`] is applied.
10557+
/// # Custom Routing Parameters
10558+
///
10559+
/// Users can customize routing parameters via [`RouteParametersConfig`].
10560+
/// To use default settings, call the function with [`RouteParametersConfig::default`].
1055710561
///
1055810562
/// # Payment
1055910563
///
@@ -10563,40 +10567,46 @@ where
1056310567
///
1056410568
/// To revoke the request, use [`ChannelManager::abandon_payment`] prior to receiving the
1056510569
/// invoice. If abandoned, or an invoice isn't received in a reasonable amount of time, the
10566-
/// payment will fail with an [`Event::InvoiceRequestFailed`].
10570+
/// payment will fail with an [`PaymentFailureReason::UserAbandoned`] or
10571+
/// [`PaymentFailureReason::InvoiceRequestExpired`], respectively.
1056710572
///
1056810573
/// # Privacy
1056910574
///
1057010575
/// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
10571-
/// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
10576+
/// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the
1057210577
/// docs of the parameterized [`Router`], which implements [`MessageRouter`].
1057310578
///
1057410579
/// # Limitations
1057510580
///
1057610581
/// Requires a direct connection to the given [`Destination`] as well as an introduction node in
10577-
/// [`Offer::paths`] or to [`Offer::signing_pubkey`], if empty. A similar restriction applies to
10582+
/// [`Offer::paths`] or to [`Offer::issuer_signing_pubkey`], if empty. A similar restriction applies to
1057810583
/// the responding [`Bolt12Invoice::payment_paths`].
1057910584
///
1058010585
/// # Errors
1058110586
///
1058210587
/// Errors if:
1058310588
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
1058410589
///
10590+
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
10591+
/// [bLIP 32]: https://github.com/lightning/blips/blob/master/blip-0032.md
1058510592
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
1058610593
/// [`OMNameResolver::resolve_name`]: crate::onion_message::dns_resolution::OMNameResolver::resolve_name
1058710594
/// [`OMNameResolver::handle_dnssec_proof_for_uri`]: crate::onion_message::dns_resolution::OMNameResolver::handle_dnssec_proof_for_uri
1058810595
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
10596+
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
10597+
/// [`PaymentFailureReason::UserAbandoned`]: crate::events::PaymentFailureReason::UserAbandoned
10598+
/// [`PaymentFailureReason::InvoiceRequestRejected`]: crate::events::PaymentFailureReason::InvoiceRequestRejected
1058910599
#[cfg(feature = "dnssec")]
1059010600
pub fn pay_for_offer_from_human_readable_name(
10591-
&self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
10601+
&self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId, payer_note: Option<String>,
1059210602
retry_strategy: Retry, route_params_config: RouteParametersConfig,
1059310603
dns_resolvers: Vec<Destination>,
1059410604
) -> Result<(), ()> {
1059510605
let (onion_message, context) =
1059610606
self.flow.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
1059710607

1059810608
let expiration = StaleExpiration::TimerTicks(1);
10599-
self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, route_params_config, amount_msats)?;
10609+
self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, route_params_config, amount_msats, payer_note)?;
1060010610

1060110611
self.flow.enqueue_dns_onion_message(
1060210612
onion_message, context, dns_resolvers,
@@ -12463,9 +12473,9 @@ where
1246312473
// offer, but tests can deal with that.
1246412474
offer = replacement_offer;
1246512475
}
12466-
if let Ok(amt_msats) = self.pending_outbound_payments.amt_msats_for_payment_awaiting_offer(payment_id) {
12476+
if let Ok((amt_msats, payer_note)) = self.pending_outbound_payments.params_for_payment_awaiting_offer(payment_id) {
1246712477
let offer_pay_res =
12468-
self.pay_for_offer_intern(&offer, None, Some(amt_msats), None, payment_id, Some(name),
12478+
self.pay_for_offer_intern(&offer, None, Some(amt_msats), payer_note, payment_id, Some(name),
1246912479
|invoice_request, nonce| {
1247012480
let retryable_invoice_request = RetryableInvoiceRequest {
1247112481
invoice_request: invoice_request.clone(),

lightning/src/ln/outbound_payment.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub(crate) enum PendingOutboundPayment {
6767
/// Human Readable Names-originated payments should always specify an explicit amount to
6868
/// send up-front, which we track here and enforce once we receive the offer.
6969
amount_msats: u64,
70+
payer_note: Option<String>
7071
},
7172
AwaitingInvoice {
7273
expiration: StaleExpiration,
@@ -1775,7 +1776,7 @@ impl OutboundPayments {
17751776
#[cfg(feature = "dnssec")]
17761777
pub(super) fn add_new_awaiting_offer(
17771778
&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry,
1778-
route_params_config: RouteParametersConfig, amount_msats: u64,
1779+
route_params_config: RouteParametersConfig, amount_msats: u64, payer_note: Option<String>
17791780
) -> Result<(), ()> {
17801781
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
17811782
match pending_outbounds.entry(payment_id) {
@@ -1786,6 +1787,7 @@ impl OutboundPayments {
17861787
retry_strategy,
17871788
route_params_config,
17881789
amount_msats,
1790+
payer_note,
17891791
});
17901792

17911793
Ok(())
@@ -1794,10 +1796,10 @@ impl OutboundPayments {
17941796
}
17951797

17961798
#[cfg(feature = "dnssec")]
1797-
pub(super) fn amt_msats_for_payment_awaiting_offer(&self, payment_id: PaymentId) -> Result<u64, ()> {
1799+
pub(super) fn params_for_payment_awaiting_offer(&self, payment_id: PaymentId) -> Result<(u64, Option<String>), ()> {
17981800
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
17991801
hash_map::Entry::Occupied(entry) => match entry.get() {
1800-
PendingOutboundPayment::AwaitingOffer { amount_msats, .. } => Ok(*amount_msats),
1802+
PendingOutboundPayment::AwaitingOffer { amount_msats, payer_note, .. } => Ok((*amount_msats, payer_note.clone())),
18011803
_ => Err(()),
18021804
},
18031805
_ => Err(()),
@@ -2583,6 +2585,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
25832585
)
25842586
))),
25852587
(6, amount_msats, required),
2588+
(7, payer_note, option),
25862589
},
25872590
);
25882591

0 commit comments

Comments
 (0)