@@ -75,6 +75,7 @@ use crate::offers::signer;
75
75
#[cfg(async_payments)]
76
76
use crate::offers::static_invoice::StaticInvoice;
77
77
use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler};
78
+ use crate::onion_message::dns_resolution::HumanReadableName;
78
79
use crate::onion_message::messenger::{Destination, MessageRouter, Responder, ResponseInstruction, MessageSendInstructions};
79
80
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
80
81
use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
@@ -87,6 +88,11 @@ use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, Maybe
87
88
use crate::util::logger::{Level, Logger, WithContext};
88
89
use crate::util::errors::APIError;
89
90
91
+ #[cfg(feature = "dnssec")]
92
+ use crate::blinded_path::message::DNSResolverContext;
93
+ #[cfg(feature = "dnssec")]
94
+ use crate::onion_message::dns_resolution::{DNSResolverMessage, DNSResolverMessageHandler, DNSSECQuery, DNSSECProof, OMNameResolver};
95
+
90
96
#[cfg(not(c_bindings))]
91
97
use {
92
98
crate::offers::offer::DerivedMetadata,
@@ -2563,6 +2569,11 @@ where
2563
2569
/// [`ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee`] estimate.
2564
2570
last_days_feerates: Mutex<VecDeque<(u32, u32)>>,
2565
2571
2572
+ #[cfg(feature = "dnssec")]
2573
+ hrn_resolver: OMNameResolver,
2574
+ #[cfg(feature = "dnssec")]
2575
+ pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
2576
+
2566
2577
entropy_source: ES,
2567
2578
node_signer: NS,
2568
2579
signer_provider: SP,
@@ -3386,6 +3397,11 @@ where
3386
3397
signer_provider,
3387
3398
3388
3399
logger,
3400
+
3401
+ #[cfg(feature = "dnssec")]
3402
+ hrn_resolver: OMNameResolver::new(current_timestamp, params.best_block.height),
3403
+ #[cfg(feature = "dnssec")]
3404
+ pending_dns_onion_messages: Mutex::new(Vec::new()),
3389
3405
}
3390
3406
}
3391
3407
@@ -9460,6 +9476,26 @@ where
9460
9476
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
9461
9477
payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
9462
9478
max_total_routing_fee_msat: Option<u64>
9479
+ ) -> Result<(), Bolt12SemanticError> {
9480
+ self.pay_for_offer_intern(offer, quantity, amount_msats, payer_note, payment_id, None, |invoice_request, nonce| {
9481
+ let expiration = StaleExpiration::TimerTicks(1);
9482
+ let retryable_invoice_request = RetryableInvoiceRequest {
9483
+ invoice_request: invoice_request.clone(),
9484
+ nonce,
9485
+ };
9486
+ self.pending_outbound_payments
9487
+ .add_new_awaiting_invoice(
9488
+ payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9489
+ Some(retryable_invoice_request)
9490
+ )
9491
+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
9492
+ })
9493
+ }
9494
+
9495
+ fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>>(
9496
+ &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
9497
+ payer_note: Option<String>, payment_id: PaymentId,
9498
+ human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
9463
9499
) -> Result<(), Bolt12SemanticError> {
9464
9500
let expanded_key = &self.inbound_payment_key;
9465
9501
let entropy = &*self.entropy_source;
@@ -9483,6 +9519,10 @@ where
9483
9519
None => builder,
9484
9520
Some(payer_note) => builder.payer_note(payer_note),
9485
9521
};
9522
+ let builder = match human_readable_name {
9523
+ None => builder,
9524
+ Some(hrn) => builder.sourced_from_human_readable_name(hrn),
9525
+ };
9486
9526
let invoice_request = builder.build_and_sign()?;
9487
9527
9488
9528
let hmac = payment_id.hmac_for_offer_payment(nonce, expanded_key);
@@ -9494,17 +9534,7 @@ where
9494
9534
9495
9535
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
9496
9536
9497
- let expiration = StaleExpiration::TimerTicks(1);
9498
- let retryable_invoice_request = RetryableInvoiceRequest {
9499
- invoice_request: invoice_request.clone(),
9500
- nonce,
9501
- };
9502
- self.pending_outbound_payments
9503
- .add_new_awaiting_invoice(
9504
- payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9505
- Some(retryable_invoice_request)
9506
- )
9507
- .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
9537
+ create_pending_payment(&invoice_request, nonce)?;
9508
9538
9509
9539
self.enqueue_invoice_request(invoice_request, reply_paths)
9510
9540
}
@@ -9645,6 +9675,73 @@ where
9645
9675
}
9646
9676
}
9647
9677
9678
+ /// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
9679
+ /// resolver(s) at `dns_resolvers` which resolve names according to bLIP 32.
9680
+ ///
9681
+ /// If the wallet supports paying on-chain schemes, you should instead use
9682
+ /// [`OMNameResolver::resolve_name`] and [`OMNameResolver::handle_dnssec_proof_for_uri`] (by
9683
+ /// implementing [`DNSResolverMessageHandler`]) directly to look up a URI and then delegate to
9684
+ /// your normal URI handling.
9685
+ ///
9686
+ /// If `max_total_routing_fee_msat` is not specified, the default from
9687
+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
9688
+ ///
9689
+ /// # Payment
9690
+ ///
9691
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the request
9692
+ /// when received. See [Avoiding Duplicate Payments] for other requirements once the payment has
9693
+ /// been sent.
9694
+ ///
9695
+ /// To revoke the request, use [`ChannelManager::abandon_payment`] prior to receiving the
9696
+ /// invoice. If abandoned, or an invoice isn't received in a reasonable amount of time, the
9697
+ /// payment will fail with an [`Event::InvoiceRequestFailed`].
9698
+ ///
9699
+ /// # Privacy
9700
+ ///
9701
+ /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
9702
+ /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
9703
+ /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
9704
+ ///
9705
+ /// # Limitations
9706
+ ///
9707
+ /// Requires a direct connection to the given [`Destination`] as well as an introduction node in
9708
+ /// [`Offer::paths`] or to [`Offer::signing_pubkey`], if empty. A similar restriction applies to
9709
+ /// the responding [`Bolt12Invoice::payment_paths`].
9710
+ ///
9711
+ /// # Errors
9712
+ ///
9713
+ /// Errors if:
9714
+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
9715
+ ///
9716
+ /// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
9717
+ /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
9718
+ #[cfg(feature = "dnssec")]
9719
+ pub fn pay_for_offer_from_human_readable_name(
9720
+ &self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
9721
+ retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>,
9722
+ dns_resolvers: Vec<Destination>,
9723
+ ) -> Result<(), ()> {
9724
+ let (onion_message, context) =
9725
+ self.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
9726
+ let reply_paths = self.create_blinded_paths(MessageContext::DNSResolver(context))?;
9727
+ let expiration = StaleExpiration::TimerTicks(1);
9728
+ self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, max_total_routing_fee_msat, amount_msats)?;
9729
+ let message_params = dns_resolvers
9730
+ .iter()
9731
+ .flat_map(|destination| reply_paths.iter().map(move |path| (path, destination)))
9732
+ .take(OFFERS_MESSAGE_REQUEST_LIMIT);
9733
+ for (reply_path, destination) in message_params {
9734
+ self.pending_dns_onion_messages.lock().unwrap().push((
9735
+ DNSResolverMessage::DNSSECQuery(onion_message.clone()),
9736
+ MessageSendInstructions::WithSpecifiedReplyPath {
9737
+ destination: destination.clone(),
9738
+ reply_path: reply_path.clone(),
9739
+ },
9740
+ ));
9741
+ }
9742
+ Ok(())
9743
+ }
9744
+
9648
9745
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
9649
9746
/// to pay us.
9650
9747
///
@@ -10272,6 +10369,10 @@ where
10272
10369
payment_secrets.retain(|_, inbound_payment| {
10273
10370
inbound_payment.expiry_time > header.time as u64
10274
10371
});
10372
+ #[cfg(feature = "dnssec")] {
10373
+ let timestamp = self.highest_seen_timestamp.load(Ordering::Relaxed) as u32;
10374
+ self.hrn_resolver.new_best_block(height, timestamp);
10375
+ }
10275
10376
}
10276
10377
10277
10378
fn get_relevant_txids(&self) -> Vec<(Txid, u32, Option<BlockHash>)> {
@@ -11522,6 +11623,62 @@ where
11522
11623
}
11523
11624
}
11524
11625
11626
+ #[cfg(feature = "dnssec")]
11627
+ impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
11628
+ DNSResolverMessageHandler for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
11629
+ where
11630
+ M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
11631
+ T::Target: BroadcasterInterface,
11632
+ ES::Target: EntropySource,
11633
+ NS::Target: NodeSigner,
11634
+ SP::Target: SignerProvider,
11635
+ F::Target: FeeEstimator,
11636
+ R::Target: Router,
11637
+ MR::Target: MessageRouter,
11638
+ L::Target: Logger,
11639
+ {
11640
+ fn handle_dnssec_query(
11641
+ &self, _message: DNSSECQuery, _responder: Option<Responder>,
11642
+ ) -> Option<(DNSResolverMessage, ResponseInstruction)> {
11643
+ None
11644
+ }
11645
+
11646
+ fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext) {
11647
+ let offer_opt = self.hrn_resolver.handle_dnssec_proof_for_offer(message, context);
11648
+ if let Some((completed_requests, offer)) = offer_opt {
11649
+ for (name, payment_id) in completed_requests {
11650
+ if let Ok(amt_msats) = self.pending_outbound_payments.amt_msats_for_payment_awaiting_offer(payment_id) {
11651
+ let offer_pay_res =
11652
+ self.pay_for_offer_intern(&offer, None, Some(amt_msats), None, payment_id, Some(name),
11653
+ |invoice_request, nonce| {
11654
+ let retryable_invoice_request = RetryableInvoiceRequest {
11655
+ invoice_request: invoice_request.clone(),
11656
+ nonce,
11657
+ };
11658
+ self.pending_outbound_payments
11659
+ .received_offer(payment_id, Some(retryable_invoice_request))
11660
+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
11661
+ });
11662
+ if offer_pay_res.is_err() {
11663
+ // The offer we tried to pay is the canonical current offer for the name we
11664
+ // wanted to pay. If we can't pay it, there's no way to recover so fail the
11665
+ // payment.
11666
+ // Note that the PaymentFailureReason should be ignored for an
11667
+ // AwaitingInvoice payment.
11668
+ self.pending_outbound_payments.abandon_payment(
11669
+ payment_id, PaymentFailureReason::RouteNotFound, &self.pending_events,
11670
+ );
11671
+ }
11672
+ }
11673
+ }
11674
+ }
11675
+ }
11676
+
11677
+ fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
11678
+ core::mem::take(&mut self.pending_dns_onion_messages.lock().unwrap())
11679
+ }
11680
+ }
11681
+
11525
11682
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
11526
11683
NodeIdLookUp for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
11527
11684
where
@@ -13207,6 +13364,11 @@ where
13207
13364
13208
13365
logger: args.logger,
13209
13366
default_configuration: args.default_config,
13367
+
13368
+ #[cfg(feature = "dnssec")]
13369
+ hrn_resolver: OMNameResolver::new(highest_seen_timestamp, best_block_height),
13370
+ #[cfg(feature = "dnssec")]
13371
+ pending_dns_onion_messages: Mutex::new(Vec::new()),
13210
13372
};
13211
13373
13212
13374
for (_, monitor) in args.channel_monitors.iter() {
0 commit comments