@@ -75,6 +75,7 @@ use crate::offers::signer;
7575#[cfg(async_payments)]
7676use crate::offers::static_invoice::StaticInvoice;
7777use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler};
78+ use crate::onion_message::dns_resolution::HumanReadableName;
7879use crate::onion_message::messenger::{Destination, MessageRouter, Responder, ResponseInstruction, MessageSendInstructions};
7980use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
8081use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
@@ -87,6 +88,11 @@ use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, Maybe
8788use crate::util::logger::{Level, Logger, WithContext};
8889use crate::util::errors::APIError;
8990
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+
9096#[cfg(not(c_bindings))]
9197use {
9298 crate::offers::offer::DerivedMetadata,
@@ -2564,6 +2570,11 @@ where
25642570 /// [`ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee`] estimate.
25652571 last_days_feerates: Mutex<VecDeque<(u32, u32)>>,
25662572
2573+ #[cfg(feature = "dnssec")]
2574+ hrn_resolver: OMNameResolver,
2575+ #[cfg(feature = "dnssec")]
2576+ pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
2577+
25672578 entropy_source: ES,
25682579 node_signer: NS,
25692580 signer_provider: SP,
@@ -3386,6 +3397,11 @@ where
33863397 signer_provider,
33873398
33883399 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()),
33893405 }
33903406 }
33913407
@@ -9579,6 +9595,26 @@ where
95799595 &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
95809596 payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
95819597 max_total_routing_fee_msat: Option<u64>
9598+ ) -> Result<(), Bolt12SemanticError> {
9599+ self.pay_for_offer_intern(offer, quantity, amount_msats, payer_note, payment_id, None, |invoice_request, nonce| {
9600+ let expiration = StaleExpiration::TimerTicks(1);
9601+ let retryable_invoice_request = RetryableInvoiceRequest {
9602+ invoice_request: invoice_request.clone(),
9603+ nonce,
9604+ };
9605+ self.pending_outbound_payments
9606+ .add_new_awaiting_invoice(
9607+ payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9608+ Some(retryable_invoice_request)
9609+ )
9610+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
9611+ })
9612+ }
9613+
9614+ fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>>(
9615+ &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
9616+ payer_note: Option<String>, payment_id: PaymentId,
9617+ human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
95829618 ) -> Result<(), Bolt12SemanticError> {
95839619 let expanded_key = &self.inbound_payment_key;
95849620 let entropy = &*self.entropy_source;
@@ -9602,6 +9638,10 @@ where
96029638 None => builder,
96039639 Some(payer_note) => builder.payer_note(payer_note),
96049640 };
9641+ let builder = match human_readable_name {
9642+ None => builder,
9643+ Some(hrn) => builder.sourced_from_human_readable_name(hrn),
9644+ };
96059645 let invoice_request = builder.build_and_sign()?;
96069646
96079647 let hmac = payment_id.hmac_for_offer_payment(nonce, expanded_key);
@@ -9613,17 +9653,7 @@ where
96139653
96149654 let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
96159655
9616- let expiration = StaleExpiration::TimerTicks(1);
9617- let retryable_invoice_request = RetryableInvoiceRequest {
9618- invoice_request: invoice_request.clone(),
9619- nonce,
9620- };
9621- self.pending_outbound_payments
9622- .add_new_awaiting_invoice(
9623- payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9624- Some(retryable_invoice_request)
9625- )
9626- .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
9656+ create_pending_payment(&invoice_request, nonce)?;
96279657
96289658 self.enqueue_invoice_request(invoice_request, reply_paths)
96299659 }
@@ -9764,6 +9794,73 @@ where
97649794 }
97659795 }
97669796
9797+ /// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
9798+ /// resolver(s) at `dns_resolvers` which resolve names according to bLIP 32.
9799+ ///
9800+ /// If the wallet supports paying on-chain schemes, you should instead use
9801+ /// [`OMNameResolver::resolve_name`] and [`OMNameResolver::handle_dnssec_proof_for_uri`] (by
9802+ /// implementing [`DNSResolverMessageHandler`]) directly to look up a URI and then delegate to
9803+ /// your normal URI handling.
9804+ ///
9805+ /// If `max_total_routing_fee_msat` is not specified, the default from
9806+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
9807+ ///
9808+ /// # Payment
9809+ ///
9810+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the request
9811+ /// when received. See [Avoiding Duplicate Payments] for other requirements once the payment has
9812+ /// been sent.
9813+ ///
9814+ /// To revoke the request, use [`ChannelManager::abandon_payment`] prior to receiving the
9815+ /// invoice. If abandoned, or an invoice isn't received in a reasonable amount of time, the
9816+ /// payment will fail with an [`Event::InvoiceRequestFailed`].
9817+ ///
9818+ /// # Privacy
9819+ ///
9820+ /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
9821+ /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
9822+ /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
9823+ ///
9824+ /// # Limitations
9825+ ///
9826+ /// Requires a direct connection to the given [`Destination`] as well as an introduction node in
9827+ /// [`Offer::paths`] or to [`Offer::signing_pubkey`], if empty. A similar restriction applies to
9828+ /// the responding [`Bolt12Invoice::payment_paths`].
9829+ ///
9830+ /// # Errors
9831+ ///
9832+ /// Errors if:
9833+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
9834+ ///
9835+ /// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
9836+ /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
9837+ #[cfg(feature = "dnssec")]
9838+ pub fn pay_for_offer_from_human_readable_name(
9839+ &self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
9840+ retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>,
9841+ dns_resolvers: Vec<Destination>,
9842+ ) -> Result<(), ()> {
9843+ let (onion_message, context) =
9844+ self.hrn_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
9845+ let reply_paths = self.create_blinded_paths(MessageContext::DNSResolver(context))?;
9846+ let expiration = StaleExpiration::TimerTicks(1);
9847+ self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, max_total_routing_fee_msat, amount_msats)?;
9848+ let message_params = dns_resolvers
9849+ .iter()
9850+ .flat_map(|destination| reply_paths.iter().map(move |path| (path, destination)))
9851+ .take(OFFERS_MESSAGE_REQUEST_LIMIT);
9852+ for (reply_path, destination) in message_params {
9853+ self.pending_dns_onion_messages.lock().unwrap().push((
9854+ DNSResolverMessage::DNSSECQuery(onion_message.clone()),
9855+ MessageSendInstructions::WithSpecifiedReplyPath {
9856+ destination: destination.clone(),
9857+ reply_path: reply_path.clone(),
9858+ },
9859+ ));
9860+ }
9861+ Ok(())
9862+ }
9863+
97679864 /// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
97689865 /// to pay us.
97699866 ///
@@ -10387,6 +10484,10 @@ where
1038710484 }
1038810485 }
1038910486 max_time!(self.highest_seen_timestamp);
10487+ #[cfg(feature = "dnssec")] {
10488+ let timestamp = self.highest_seen_timestamp.load(Ordering::Relaxed) as u32;
10489+ self.hrn_resolver.new_best_block(height, timestamp);
10490+ }
1039010491 }
1039110492
1039210493 fn get_relevant_txids(&self) -> Vec<(Txid, u32, Option<BlockHash>)> {
@@ -11637,6 +11738,62 @@ where
1163711738 }
1163811739}
1163911740
11741+ #[cfg(feature = "dnssec")]
11742+ impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
11743+ DNSResolverMessageHandler for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
11744+ where
11745+ M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
11746+ T::Target: BroadcasterInterface,
11747+ ES::Target: EntropySource,
11748+ NS::Target: NodeSigner,
11749+ SP::Target: SignerProvider,
11750+ F::Target: FeeEstimator,
11751+ R::Target: Router,
11752+ MR::Target: MessageRouter,
11753+ L::Target: Logger,
11754+ {
11755+ fn handle_dnssec_query(
11756+ &self, _message: DNSSECQuery, _responder: Option<Responder>,
11757+ ) -> Option<(DNSResolverMessage, ResponseInstruction)> {
11758+ None
11759+ }
11760+
11761+ fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext) {
11762+ let offer_opt = self.hrn_resolver.handle_dnssec_proof_for_offer(message, context);
11763+ if let Some((completed_requests, offer)) = offer_opt {
11764+ for (name, payment_id) in completed_requests {
11765+ if let Ok(amt_msats) = self.pending_outbound_payments.amt_msats_for_payment_awaiting_offer(payment_id) {
11766+ let offer_pay_res =
11767+ self.pay_for_offer_intern(&offer, None, Some(amt_msats), None, payment_id, Some(name),
11768+ |invoice_request, nonce| {
11769+ let retryable_invoice_request = RetryableInvoiceRequest {
11770+ invoice_request: invoice_request.clone(),
11771+ nonce,
11772+ };
11773+ self.pending_outbound_payments
11774+ .received_offer(payment_id, Some(retryable_invoice_request))
11775+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
11776+ });
11777+ if offer_pay_res.is_err() {
11778+ // The offer we tried to pay is the canonical current offer for the name we
11779+ // wanted to pay. If we can't pay it, there's no way to recover so fail the
11780+ // payment.
11781+ // Note that the PaymentFailureReason should be ignored for an
11782+ // AwaitingInvoice payment.
11783+ self.pending_outbound_payments.abandon_payment(
11784+ payment_id, PaymentFailureReason::RouteNotFound, &self.pending_events,
11785+ );
11786+ }
11787+ }
11788+ }
11789+ }
11790+ }
11791+
11792+ fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
11793+ core::mem::take(&mut self.pending_dns_onion_messages.lock().unwrap())
11794+ }
11795+ }
11796+
1164011797impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
1164111798NodeIdLookUp for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
1164211799where
@@ -13321,6 +13478,11 @@ where
1332113478
1332213479 logger: args.logger,
1332313480 default_configuration: args.default_config,
13481+
13482+ #[cfg(feature = "dnssec")]
13483+ hrn_resolver: OMNameResolver::new(highest_seen_timestamp, best_block_height),
13484+ #[cfg(feature = "dnssec")]
13485+ pending_dns_onion_messages: Mutex::new(Vec::new()),
1332413486 };
1332513487
1332613488 for (_, monitor) in args.channel_monitors.iter() {
0 commit comments