-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the core functionality required to resolve Human Readable Names #3179
Add the core functionality required to resolve Human Readable Names #3179
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3179 +/- ##
==========================================
- Coverage 89.68% 89.55% -0.13%
==========================================
Files 126 127 +1
Lines 103168 103300 +132
Branches 103168 103300 +132
==========================================
- Hits 92522 92511 -11
- Misses 7934 8070 +136
- Partials 2712 2719 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
7203f95
to
51c74d9
Compare
I'd love to pickup review on the series. Mind opening a tracking issue for the series of PRs that would allow to keep track where we're at, on what which parts are blocked, and which PRs we (reviewers) can still expect to be opened, etc.? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While BIP353 will (hopefully) be an integral part of Lightning payments soon, it still seems all the DNS stuff is more a utility. I'm wondering if in terms of code organization it would be beneficial to have this live as part of an lightning-dns-resolution
crate or similar? Doing this might also allow users to reuse some of the logic without pulling in the full LDK dependency? Or do you think the logic will end up being so integral to and intertwined with other parts of LDK, that having it live it a separate crate would just be cumbersome?
51c74d9
to
66017a7
Compare
I wanted to do this, but it creates a circular reference. That crazy has to depend on The stuff that is here is the API that folks will have to use if they want to do DNSSEC resolution over onion messages and resolve to a bitcoin: URI, but I have a branch that does the full integration at https://git.bitcoin.ninja/index.cgi?p=rust-lightning;a=shortlog;h=refs/heads/2024-07-human-readable-names-resolution for offers resolution specifically. |
I mean I can, but its only two PRs, at least after the above issue. The full branch I considered making one big PR, but it seemed like it could go in two. The second is linked above. |
66017a7
to
12a8d39
Compare
080de8d
to
fb54dd4
Compare
Rebased. |
5e594b7
to
41627c6
Compare
With the lightning-types crate, would the circular reference still be an issue? |
Yea, its a separate issue. In theory we could move the BIP 353 Onion Message Handler trait out to |
41627c6
to
083a572
Compare
// (we assume no more than two hours, though the actual limits are rather | ||
// complicated). | ||
// Thus, we have to let the proof times be rather fuzzy. | ||
if validated_rrs.valid_from > block_time + 60 * 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be a constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its basically a consensus rule assumption, so not sure its worth it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good, just a few questions and nits.
I think the main question is whether we could use timer ticks rather than block connections to timeout pending requests to avoid piling onto the stack of things that we need to do on block connection, increasingly risking load spikes.
/// block. | ||
/// | ||
/// This will call back to resolve some pending queries which have timed out. | ||
pub fn new_best_block(&self, height: u32, time: u32) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mh, no big fan of doing more and more stuff exactly on block connection. Given that we call OnionMessenger::timer_tick_occured
in BP anyways, couldn't we use that here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is we need the current time here (to validate proofs), not just a timer. We could have both a timer and accept new best block info, but that seems kinda wasteful?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhh, true. I think we discussed that before, but would it work to just use SystemTime
for std
and otherwise introduce a timer trait that non-std
users would need to use? FWIW, we need something like this in lightning-liquidity
also when validating requests against wallclock (on non-std
we currently just omit validating this part, but we should lightningdevkit/lightning-liquidity#54). If we bring the liquidity crate into rust-lightning
soon, it might make sense to share an interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we discussed that before, but would it work to just use SystemTime for std and otherwise introduce a timer trait that non-std users would need to use?
I think adding such a trait would just be a massive footgun - users would implement against the std
interface then forget to call the other trait when switching to/building for no-std
. Generally, we try to avoid any material interface differences as much as possible to avoid things like this.
FWIW, we need something like this in lightning-liquidity also when validating requests against wallclock (on non-std we currently just omit validating this part, but we should lightningdevkit/lightning-liquidity#54). If we bring the liquidity crate into rust-lightning soon, it might make sense to share an interface?
Meh, if the parameters are stale the LSP can just reject, right? Not checking seems...fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, if the parameters are stale the LSP can just reject, right? Not checking seems...fine?
This is on the LSP-side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is on the LSP-side.
Ah, right....well if LSPs are fine with +/- two hours you can always use block time. And, probably they are fine with that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhh, yeah, but as mentioned above I'd really prefer to get away from piling everything onto block connection to avoid the ensuing load spike(s). Could we consider building an LDK-internal clock that is synchronized on block connection, but otherwise driven by timing_tick_occured
? Having such an internal interface/utility would solve these issues that we reguarly see re-emerging, and would allow us to schedule things somewhere in the huge interval between block connections?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhh, yeah, but as mentioned above I'd really prefer to get away from piling everything onto block connection to avoid the ensuing load spike(s).
Hmm, is there much load spike now that we don't persist ChannelMonitor
s every block?
Could we consider building an LDK-internal clock that is synchronized on block connection, but otherwise driven by timing_tick_occured? Having such an internal interface/utility would solve these issues that we reguarly see re-emerging, and would allow us to schedule things somewhere in the huge interval between block connections?
I'm not sure what issues we see here? There's some timeouts that we don't allow to be very granular, but for the most part that's not a big deal, is it?
/// [`Self::resolve_name`] are returned. | ||
pub fn handle_dnssec_proof_for_offer( | ||
&self, msg: DNSSECProof, context: DNSResolverContext, | ||
) -> Option<(Vec<(HumanReadableName, PaymentId)>, Offer)> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we introduce struct
s for the return type here and the one from handle_dnssec_proof_for_uri
to make them a bit more ... human readable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need it? I'm not sure how a list of (HumanReadableName, PaymentId)
s and an Offer
is confusing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean it's an option of a tuple of a list of a tuple of a human readable name and a payment id, and an offer.
Just accessing all that data in the return type could have a bit simpler API, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how we'd clean it up, is my point. If we put it in a struct it'd be
struct Thing {
payments: Vec<(HumanReadableName, PaymentId)>,
offer: Offer,
}
the offer
name is obviously totally useless just based on the type, and the payments
name is similarly not that interesting given each payment has a PaymentId
attached to it? It might improve callsites marginally cause they can access return_value.payments
, but mostly they should be doing let (payments, offer) = ...
instead, which gives the same impact (and its not like we can misuse any of this cause the types are pretty strict).
08d4d52
to
03406f7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit 6b760e7 could be fold in the previous one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, all the commits that start with f
are intended to be squashed prior to merge. They exist to aid reviewers in comparing a previous version of the PR to the new one by leaving existing commits unchanged and only adding new "fixup" commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I start adding comments on the git history but I think we did not rework it yet.
@@ -32,6 +32,8 @@ unsafe_revoked_tx_signing = [] | |||
no-std = ["hashbrown", "possiblyrandom", "libm"] | |||
std = [] | |||
|
|||
dnssec = ["dnssec-prover/validation"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thinking if we can make the dnssec-prover
dependencies optional and included just when this feature is specified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We maybe could, but it seems nice to use the types from it, and the crate weighs basically nothing if we just pull the types from it and don't enable the validation feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, and I agree. I was thinking that maybe the dnssec
will be a popular feature that we want enabled most of the time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, it likely is (and maybe we should make it default, even), but I think even still we can use the types from it no matter what.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Feel free to squash the fixups, IMO.
Going forward, will the client and the resolver always be modal, or can we think of a scenario where both need to be active at the same time (i.e., allowing to resolve locally for others, but also to query other nodes)?
03406f7
to
2be90aa
Compare
Yea, I anticipate this will definitely happen sometimes. Certainly ldk-sample/"simple" LDK routing nodes will want to support both. I'll update the server-side logic to optionally act as a wrapper. Rebased and squashed down all the fixups, also addressing the minor comments from @tnull above. |
When we make a DNSSEC query with a reply path, we don't want to allow the DNS resolver to attempt to respond to various nodes to try to detect (through timining or other analysis) whether we were the one who made the query. Thus, we need to include a nonce in the context in our reply path, which we set up here by creating a new context type for DNS resolutions.
This creates the initial DNSSEC proof and query messages in a new module in `onion_message`, as well as a new message handler to handle them. In the coming commits, a default implementation will be added which verifies DNSSEC proofs which can be used to resolve BIP 353 URIs without relying on anything outside of the lightning network.
This adds the requisite message parsing and handling code for the new DNSSEC messages to `OnionMessenger`.
BIP 353 `HumanReadableName`s are represented as `₿user@domain` and can be resolved using DNS into a `bitcoin:` URI. In the next commit, we will add such a resolver using onion messages to fetch records from the DNS, which will rely on this new type to get name information from outside LDK.
2be90aa
to
e999c63
Compare
These are perfectly fine and are relied on by BIP 353, so we need to ensure we allow them.
This adds a new utility struct, `OMNameResolver`, which implements the core functionality required to resolve Human Readable Names, namely generating `DNSSECQuery` onion messages, tracking the state of requests, and ultimately receiving and verifying `DNSSECProof` onion messages. It tracks pending requests with a `PaymentId`, allowing for easy integration into `ChannelManager` in a coming commit - mapping received proofs to `PaymentId`s which we can then complete by handing them `Offer`s to pay. It does not, directly, implement `DNSResolverMessageHandler`, but an implementation of `DNSResolverMessageHandler` becomes trivial with `OMNameResolver` handling the inbound messages and creating the messages to send.
e999c63
to
9335c9b
Compare
This adds new onion messages and a new onion message handler for bLIP 32 messages. It also adds a utility which verifies the proofs and turns them into URIs or Offers. I have a followup ready which wires it all up in
ChannelManager
as well as a message handler that does the resolver end of bLIP 32, but the latter is blocked on #3178 and I kinda want to land them at the same time so we have some tests. Sadly this PR also adds some code that's not really testable without that, but its pretty straightforward.