@@ -74,6 +74,7 @@ use crate::offers::signer;
74
74
#[cfg(async_payments)]
75
75
use crate::offers::static_invoice::StaticInvoice;
76
76
use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler};
77
+ use crate::onion_message::dns_resolution::HumanReadableName;
77
78
use crate::onion_message::messenger::{Destination, MessageRouter, Responder, ResponseInstruction, MessageSendInstructions};
78
79
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
79
80
use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
@@ -86,6 +87,11 @@ use crate::util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, Maybe
86
87
use crate::util::logger::{Level, Logger, WithContext};
87
88
use crate::util::errors::APIError;
88
89
90
+ #[cfg(feature = "dnssec")]
91
+ use crate::blinded_path::message::DNSResolverContext;
92
+ #[cfg(feature = "dnssec")]
93
+ use crate::onion_message::dns_resolution::{DNSResolverMessage, DNSResolverMessageHandler, DNSSECQuery, DNSSECProof, OMNameResolver};
94
+
89
95
#[cfg(not(c_bindings))]
90
96
use {
91
97
crate::offers::offer::DerivedMetadata,
@@ -2428,6 +2434,11 @@ where
2428
2434
/// [`ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee`] estimate.
2429
2435
last_days_feerates: Mutex<VecDeque<(u32, u32)>>,
2430
2436
2437
+ #[cfg(feature = "dnssec")]
2438
+ dns_resolver: OMNameResolver,
2439
+ #[cfg(feature = "dnssec")]
2440
+ pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
2441
+
2431
2442
entropy_source: ES,
2432
2443
node_signer: NS,
2433
2444
signer_provider: SP,
@@ -3251,6 +3262,11 @@ where
3251
3262
signer_provider,
3252
3263
3253
3264
logger,
3265
+
3266
+ #[cfg(feature = "dnssec")]
3267
+ dns_resolver: OMNameResolver::new(current_timestamp, params.best_block.height),
3268
+ #[cfg(feature = "dnssec")]
3269
+ pending_dns_onion_messages: Mutex::new(Vec::new()),
3254
3270
}
3255
3271
}
3256
3272
@@ -9304,6 +9320,26 @@ where
9304
9320
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
9305
9321
payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
9306
9322
max_total_routing_fee_msat: Option<u64>
9323
+ ) -> Result<(), Bolt12SemanticError> {
9324
+ self.pay_for_offer_intern(offer, quantity, amount_msats, payer_note, payment_id, None, |invoice_request, nonce| {
9325
+ let expiration = StaleExpiration::TimerTicks(1);
9326
+ let retryable_invoice_request = RetryableInvoiceRequest {
9327
+ invoice_request: invoice_request.clone(),
9328
+ nonce,
9329
+ };
9330
+ self.pending_outbound_payments
9331
+ .add_new_awaiting_invoice(
9332
+ payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9333
+ Some(retryable_invoice_request)
9334
+ )
9335
+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
9336
+ })
9337
+ }
9338
+
9339
+ fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>>(
9340
+ &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
9341
+ payer_note: Option<String>, payment_id: PaymentId,
9342
+ human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
9307
9343
) -> Result<(), Bolt12SemanticError> {
9308
9344
let expanded_key = &self.inbound_payment_key;
9309
9345
let entropy = &*self.entropy_source;
@@ -9327,6 +9363,10 @@ where
9327
9363
None => builder,
9328
9364
Some(payer_note) => builder.payer_note(payer_note),
9329
9365
};
9366
+ let builder = match human_readable_name {
9367
+ None => builder,
9368
+ Some(hrn) => builder.sourced_from_human_readable_name(hrn),
9369
+ };
9330
9370
let invoice_request = builder.build_and_sign()?;
9331
9371
9332
9372
let hmac = payment_id.hmac_for_offer_payment(nonce, expanded_key);
@@ -9338,17 +9378,7 @@ where
9338
9378
9339
9379
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
9340
9380
9341
- let expiration = StaleExpiration::TimerTicks(1);
9342
- let retryable_invoice_request = RetryableInvoiceRequest {
9343
- invoice_request: invoice_request.clone(),
9344
- nonce,
9345
- };
9346
- self.pending_outbound_payments
9347
- .add_new_awaiting_invoice(
9348
- payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
9349
- Some(retryable_invoice_request)
9350
- )
9351
- .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
9381
+ create_pending_payment(&invoice_request, nonce)?;
9352
9382
9353
9383
self.enqueue_invoice_request(invoice_request, reply_paths)
9354
9384
}
@@ -9489,6 +9519,73 @@ where
9489
9519
}
9490
9520
}
9491
9521
9522
+ /// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
9523
+ /// resolver which resolves names according to bLIP 32 at the `dns_resolver` [`Destination`].
9524
+ ///
9525
+ /// If the wallet supports paying on-chain schemes, you should instead use
9526
+ /// [`OMNameResolver::resolve_name`] and [`OMNameResolver::handle_dnssec_proof_for_uri`] (by
9527
+ /// implementing [`DNSResolverMessageHandler`]) directly to look up a URI and then delegate to
9528
+ /// your normal URI handling.
9529
+ ///
9530
+ /// If `max_total_routing_fee_msat` is not specified, The default from
9531
+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
9532
+ ///
9533
+ /// # Payment
9534
+ ///
9535
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the request
9536
+ /// when received. See [Avoiding Duplicate Payments] for other requirements once the payment has
9537
+ /// been sent.
9538
+ ///
9539
+ /// To revoke the request, use [`ChannelManager::abandon_payment`] prior to receiving the
9540
+ /// invoice. If abandoned, or an invoice isn't received in a reasonable amount of time, the
9541
+ /// payment will fail with an [`Event::InvoiceRequestFailed`].
9542
+ ///
9543
+ /// # Privacy
9544
+ ///
9545
+ /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
9546
+ /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
9547
+ /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
9548
+ ///
9549
+ /// # Limitations
9550
+ ///
9551
+ /// Requires a direct connection to the given [`Destination`] as well as an introduction node in
9552
+ /// [`Offer::paths`] or to [`Offer::signing_pubkey`], if empty. A similar restriction applies to
9553
+ /// the responding [`Bolt12Invoice::payment_paths`].
9554
+ ///
9555
+ /// # Errors
9556
+ ///
9557
+ /// Errors if:
9558
+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
9559
+ ///
9560
+ /// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
9561
+ /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
9562
+ #[cfg(feature = "dnssec")]
9563
+ pub fn pay_for_offer_from_human_readable_name(
9564
+ &self, name: HumanReadableName, amount_msats: u64, payment_id: PaymentId,
9565
+ retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>,
9566
+ dns_resolvers: Vec<Destination>,
9567
+ ) -> Result<(), ()> {
9568
+ let (onion_message, context) =
9569
+ self.dns_resolver.resolve_name(payment_id, name, &*self.entropy_source)?;
9570
+ let reply_paths = self.create_blinded_paths(MessageContext::DNSResolver(context))?;
9571
+ let expiration = StaleExpiration::TimerTicks(2);
9572
+ self.pending_outbound_payments.add_new_awaiting_offer(payment_id, expiration, retry_strategy, max_total_routing_fee_msat, amount_msats)?;
9573
+ let message_params = dns_resolvers
9574
+ .iter()
9575
+ .flat_map(|destination| reply_paths.iter().map(move |path| (path, destination)))
9576
+ .take(OFFERS_MESSAGE_REQUEST_LIMIT);
9577
+ for (reply_path, destination) in message_params {
9578
+ self.pending_dns_onion_messages.lock().unwrap().push((
9579
+ DNSResolverMessage::DNSSECQuery(onion_message.clone()),
9580
+ MessageSendInstructions::WithSpecifiedReplyPath {
9581
+ destination: destination.clone(),
9582
+ reply_path: reply_path.clone(),
9583
+ },
9584
+ ));
9585
+ }
9586
+ Ok(())
9587
+ }
9588
+
9492
9589
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
9493
9590
/// to pay us.
9494
9591
///
@@ -10116,6 +10213,10 @@ where
10116
10213
payment_secrets.retain(|_, inbound_payment| {
10117
10214
inbound_payment.expiry_time > header.time as u64
10118
10215
});
10216
+ #[cfg(feature = "dnssec")] {
10217
+ let timestamp = self.highest_seen_timestamp.load(Ordering::Relaxed) as u32;
10218
+ self.dns_resolver.new_best_block(height, timestamp);
10219
+ }
10119
10220
}
10120
10221
10121
10222
fn get_relevant_txids(&self) -> Vec<(Txid, u32, Option<BlockHash>)> {
@@ -11341,6 +11442,62 @@ where
11341
11442
}
11342
11443
}
11343
11444
11445
+ #[cfg(feature = "dnssec")]
11446
+ impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
11447
+ DNSResolverMessageHandler for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
11448
+ where
11449
+ M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
11450
+ T::Target: BroadcasterInterface,
11451
+ ES::Target: EntropySource,
11452
+ NS::Target: NodeSigner,
11453
+ SP::Target: SignerProvider,
11454
+ F::Target: FeeEstimator,
11455
+ R::Target: Router,
11456
+ MR::Target: MessageRouter,
11457
+ L::Target: Logger,
11458
+ {
11459
+ fn handle_dnssec_query(
11460
+ &self, _message: DNSSECQuery, _responder: Option<Responder>,
11461
+ ) -> Option<(DNSResolverMessage, ResponseInstruction)> {
11462
+ None
11463
+ }
11464
+
11465
+ fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext) {
11466
+ let offer_opt = self.dns_resolver.handle_dnssec_proof_for_offer(message, context);
11467
+ if let Some((completed_requests, offer)) = offer_opt {
11468
+ for (name, payment_id) in completed_requests {
11469
+ if let Ok(amt_msats) = self.pending_outbound_payments.amt_msats_for_payment_awaiting_offer(payment_id) {
11470
+ let offer_pay_res =
11471
+ self.pay_for_offer_intern(&offer, None, Some(amt_msats), None, payment_id, Some(name),
11472
+ |invoice_request, nonce| {
11473
+ let retryable_invoice_request = RetryableInvoiceRequest {
11474
+ invoice_request: invoice_request.clone(),
11475
+ nonce,
11476
+ };
11477
+ self.pending_outbound_payments
11478
+ .received_offer(payment_id, Some(retryable_invoice_request))
11479
+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
11480
+ });
11481
+ if offer_pay_res.is_err() {
11482
+ // The offer we tried to pay is the canonical current offer for the name we
11483
+ // wanted to pay. If we can't pay it, there's no way to recover so fail the
11484
+ // payment.
11485
+ // Note that the PaymentFailureReason should be ignored for an
11486
+ // AwaitingInvoice payment.
11487
+ self.pending_outbound_payments.abandon_payment(
11488
+ payment_id, PaymentFailureReason::RouteNotFound, &self.pending_events,
11489
+ );
11490
+ }
11491
+ }
11492
+ }
11493
+ }
11494
+ }
11495
+
11496
+ fn release_pending_messages(&self) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
11497
+ core::mem::take(&mut self.pending_dns_onion_messages.lock().unwrap())
11498
+ }
11499
+ }
11500
+
11344
11501
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>
11345
11502
NodeIdLookUp for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
11346
11503
where
@@ -13079,6 +13236,11 @@ where
13079
13236
13080
13237
logger: args.logger,
13081
13238
default_configuration: args.default_config,
13239
+
13240
+ #[cfg(feature = "dnssec")]
13241
+ dns_resolver: OMNameResolver::new(highest_seen_timestamp, best_block_height),
13242
+ #[cfg(feature = "dnssec")]
13243
+ pending_dns_onion_messages: Mutex::new(Vec::new()),
13082
13244
};
13083
13245
13084
13246
for htlc_source in failed_htlcs.drain(..) {
0 commit comments