Skip to content

Commit 28fd617

Browse files
committed
Add a method to expire specific resolutions from OMNameResolver
In `bitcoin-payment-instructions` we can figure out when a lookup has timed out by looking at if the `Future` was dropped. However, while we can clean up internal state in `bitcoin-payment-instructions` we'd leave stale entries in `OMNameResolver` (at least until they time out). Instead, here we add a method to explicitly time out a lookup.
1 parent 40e9174 commit 28fd617

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

lightning/src/onion_message/dns_resolution.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,30 @@ impl OMNameResolver {
344344
});
345345
}
346346

347+
/// Removes any pending resolutions for the given `name` and `payment_id`.
348+
///
349+
/// Any future calls to [`Self::handle_dnssec_proof_for_offer`] or
350+
/// [`Self::handle_dnssec_proof_for_uri`] will no longer return a result for the given
351+
/// resolution.
352+
pub fn expire_pending_resolution(&self, name: &HumanReadableName, payment_id: PaymentId) {
353+
let dns_name =
354+
Name::try_from(format!("{}.user._bitcoin-payment.{}.", name.user(), name.domain()));
355+
debug_assert!(
356+
dns_name.is_ok(),
357+
"The HumanReadableName constructor shouldn't allow names which are too long"
358+
);
359+
if let Ok(name) = dns_name {
360+
let mut pending_resolves = self.pending_resolves.lock().unwrap();
361+
if let hash_map::Entry::Occupied(mut entry) = pending_resolves.entry(name) {
362+
let resolutions = entry.get_mut();
363+
resolutions.retain(|resolution| resolution.payment_id != payment_id);
364+
if resolutions.is_empty() {
365+
entry.remove();
366+
}
367+
}
368+
}
369+
}
370+
347371
/// Begins the process of resolving a BIP 353 Human Readable Name.
348372
///
349373
/// Returns a [`DNSSECQuery`] onion message and a [`DNSResolverContext`] which should be sent
@@ -483,7 +507,7 @@ impl OMNameResolver {
483507

484508
#[cfg(test)]
485509
mod tests {
486-
use super::HumanReadableName;
510+
use super::*;
487511

488512
#[test]
489513
fn test_hrn_display_format() {
@@ -500,4 +524,43 @@ mod tests {
500524
"HumanReadableName display format mismatch"
501525
);
502526
}
527+
528+
#[test]
529+
#[cfg(feature = "dnssec")]
530+
fn test_expiry() {
531+
let keys = crate::sign::KeysManager::new(&[33; 32], 0, 0);
532+
let resolver = OMNameResolver::new(42, 42);
533+
let name = HumanReadableName::new("user", "example.com").unwrap();
534+
535+
// Queue up a resolution
536+
resolver.resolve_name(PaymentId([0; 32]), name.clone(), &keys).unwrap();
537+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
538+
// and check that it expires after two blocks
539+
resolver.new_best_block(44, 42);
540+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 0);
541+
542+
// Queue up another resolution
543+
resolver.resolve_name(PaymentId([1; 32]), name.clone(), &keys).unwrap();
544+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
545+
// it won't expire after one block
546+
resolver.new_best_block(45, 42);
547+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
548+
assert_eq!(resolver.pending_resolves.lock().unwrap().iter().next().unwrap().1.len(), 1);
549+
// and queue up a second and third resolution of the same name
550+
resolver.resolve_name(PaymentId([2; 32]), name.clone(), &keys).unwrap();
551+
resolver.resolve_name(PaymentId([3; 32]), name.clone(), &keys).unwrap();
552+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
553+
assert_eq!(resolver.pending_resolves.lock().unwrap().iter().next().unwrap().1.len(), 3);
554+
// after another block the first will expire, but the second and third won't
555+
resolver.new_best_block(46, 42);
556+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
557+
assert_eq!(resolver.pending_resolves.lock().unwrap().iter().next().unwrap().1.len(), 2);
558+
// Check manual expiry
559+
resolver.expire_pending_resolution(&name, PaymentId([3; 32]));
560+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 1);
561+
assert_eq!(resolver.pending_resolves.lock().unwrap().iter().next().unwrap().1.len(), 1);
562+
// after one more block all the requests will have expired
563+
resolver.new_best_block(47, 42);
564+
assert_eq!(resolver.pending_resolves.lock().unwrap().len(), 0);
565+
}
503566
}

0 commit comments

Comments
 (0)