Skip to content

Conversation

chuksys
Copy link

@chuksys chuksys commented Sep 5, 2025

This PR makes it possible to configure LDK-Node as a DNS resolver for other nodes.

Changes

  • Added a bool flag named is_hrn_resolver to Config.
  • Based on the value of is_hrn_resolver, a new node either has the ability to send payments to HRNs or do DNS resolution for other nodes.
  • Expanded setup_two_nodes in the integration test suite to allow configuring a node to act as a DNS resolver for other nodes.
  • Added an end-to-end test-case asserting that sending to HRNs works.

This PR fixes #436

This rename reflects that this module is a unified payment interface for both QR code payments and HRN payments passed in as a string without scanning a QR code
…UnifiedPaymentResult

These renamings are necessary to reflect the expanded responsibilities for this module.
This commit adds a HRN Resolver to the Node struct which will be useful for resolving HRNs when making BIP 353 payments. It also passes the HRN Resolver into UnifiedPayment.
This commit allows us to enable our node to either be able to send HRN resolution requests or acts as a resolver for 3rd party nodes

We also pass HRNResolver as an optional parameter to Node
This commit will be dropped later
This commit adds an end-to-end test that asserts that HRNs are properly parsed and resolved, and sending to the corresponding offer works
@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Sep 5, 2025

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@chuksys
Copy link
Author

chuksys commented Sep 5, 2025

This PR builds upon #607. It is currently opened in draft because the end-to-end test I added runs indefinitely without resolving or timing out.

Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First look at the additional changes here, had to cut the review round short though.

vss-client = "0.3"
prost = { version = "0.11.6", default-features = false}
bitcoin-payment-instructions = { version = "0.5" }
lightning-dns-resolver = "0.2.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this above to the group(s) of lightning-* imports (also the commented-out ones) and follow the scheme there.

u64 probing_liquidity_limit_multiplier;
AnchorChannelsConfig? anchor_channels_config;
SendingParameters? sending_parameters;
boolean is_hrn_resolver;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think over at the first PR we discussed to introduce a dedicated config for HRN-related things, also to specify default resolvers, for example? Probably this should be part of such a config?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we did - I'll re-introduce the dedicated config for HRN-related things.

let hrn_resolver = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));
let resolver = if config.is_hrn_resolver {
Resolver::DNS(Arc::new(OMDomainResolver::ignoring_incoming_proofs(
"8.8.8.8:53".parse().map_err(|_| BuildError::DNSResolverSetupFailed)?,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to make the DNS server used configurable via the config?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that makes sense - will do.

Error::HrnResolverNotConfigured
})?;

println!("Parsing instructions...");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, please remove any printlns.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - will do, just left this here because I am still debugging the issue with the end-to-end test not resolving HRNs, erroring out or timing out.

peer_manager_clone.process_events();
}));
let hrn_resolver = match resolver {
Resolver::DNS(_) => None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, so if we're resolving for others, we won't be able to send to HRNs ourselves?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, it seems this is the case. The onion messenger can take only one type of dns_resolver at a time - either the one sending out the query or the one handling the query and responding with the proof. If our node is configured to resolve for others, we'd have to pass the appropriate resolver to the onion messenger, preventing us from sending to HRNs ourselves.

@tnull tnull self-requested a review September 17, 2025 11:11
Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was able to reproduce the behavior you were running into (see below).

// Sleep one more sec to make sure the node announcement propagates.
std::thread::sleep(std::time::Duration::from_secs(1));

let hrn = "chuks@peepswire.com";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was now able to reproduce the infinite loop you were seeing, and it seems that this HRN doesn't have a valid DNSSEC proof attached (i.e., we hit the else clause of this case in the DNS resolver: https://github.com/lightningdevkit/rust-lightning/blob/674861d06fb333222cff9c2caaeb3783728672a1/lightning-dns-resolver/src/lib.rs#L134). If I plug in matt@mattcorallo.com the resolution actually succeeds, however, it of course doesn't have any suitable regtest payment instructions attached. I'm not fully sure if there are any plans for local-testing end-to-end lightning-dns-resolver (cc @TheBlueMatt ?), but we may indeed need to spin up our own DNS server (instead of using 8.8.8.8) and publish a correct DNSSEC proof to make the test fully work end-to-end in regtest.

Also opened an issue here: rust-bitcoin/bitcoin-payment-instructions#11

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have end-to-end tests in lightning-dns-resolver tho they are a bit awkward. The hook ChanelManager::testing_dnssec_proof_offer_resolution_override but then do a totally normal resolution (which must pass DNSSEC validation) and then swap out the returned offer, see https://github.com/lightningdevkit/rust-lightning/blob/main/lightning-dns-resolver/src/lib.rs#L387

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @tnull and @TheBlueMatt - I'll look into ChannelManager::testing_dnssec_proof_offer_resolution_override and also explore spinning up our own DNS server to publish a correct DNSSEC proof.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, probably good to just use matt@mattcorallo.com as the test string, let it do DNS resolution, then have a similar override hook in ldk-node.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks.

println!("Parsing instructions...");

let instructions =
PaymentInstructions::parse(uri_str, self.config.network, resolver.as_ref(), false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We def. need to wrap this in a tokio::timeout to abandon the future if it never returns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for resolving HumanReadableNames
4 participants