Skip to content

LSPS5 implementation #3662

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

Merged
merged 12 commits into from
Jul 24, 2025
Merged

LSPS5 implementation #3662

merged 12 commits into from
Jul 24, 2025

Conversation

martinsaposnic
Copy link
Contributor

@martinsaposnic martinsaposnic commented Mar 11, 2025

A complete implementation for LSPS5 (spec defined here lightning/blips#55)

Reviewing commit by commit is recommended (~40% of the added lines are tests)

Notes:

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Mar 11, 2025

👋 Thanks for assigning @TheBlueMatt 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.

@martinsaposnic
Copy link
Contributor Author

martinsaposnic commented Mar 11, 2025

This is a huge PR, but it wasn’t obvious to me how to split it in a way that would still make sense (I did split it into small commits to make it easier to review.). I’m open to suggestions if you have ideas on how this could be structured differently.

Copy link

codecov bot commented Mar 11, 2025

Codecov Report

Attention: Patch coverage is 86.38596% with 194 lines in your changes missing coverage. Please review.

Project coverage is 88.92%. Comparing base (65d518b) to head (18fe164).
Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
lightning-liquidity/src/lsps5/msgs.rs 76.84% 81 Missing and 16 partials ⚠️
lightning-liquidity/src/lsps5/client.rs 90.59% 30 Missing and 3 partials ⚠️
lightning-liquidity/src/lsps5/service.rs 91.16% 20 Missing and 5 partials ⚠️
lightning-liquidity/src/lsps0/ser.rs 79.16% 3 Missing and 17 partials ⚠️
lightning-liquidity/src/lsps5/url_utils.rs 94.87% 1 Missing and 5 partials ⚠️
lightning-liquidity/src/manager.rs 93.84% 2 Missing and 2 partials ⚠️
lightning-liquidity/src/lsps5/validator.rs 95.83% 0 Missing and 3 partials ⚠️
lightning/src/util/test_utils.rs 50.00% 3 Missing ⚠️
lightning/src/ln/blinded_payment_tests.rs 0.00% 2 Missing ⚠️
lightning-liquidity/src/lsps0/msgs.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3662      +/-   ##
==========================================
- Coverage   88.95%   88.92%   -0.04%     
==========================================
  Files         168      173       +5     
  Lines      121974   123393    +1419     
  Branches   121974   123393    +1419     
==========================================
+ Hits       108502   109723    +1221     
- Misses      11072    11216     +144     
- Partials     2400     2454      +54     
Flag Coverage Δ
fuzzing 22.31% <2.12%> (-0.38%) ⬇️
tests 88.74% <86.38%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ldk-reviews-bot ldk-reviews-bot requested a review from arik-so March 11, 2025 20:22
@tnull tnull self-requested a review March 11, 2025 20:37
@wpaulino wpaulino removed the request for review from arik-so March 11, 2025 20:39
Copy link
Contributor

@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.

Wow, thank you for looking into this! I did a first pass, and it looks pretty amazing already!

Before going too much into further details, here are a few general comments upfront:

  1. I'm generally no fan of introducing additional dependencies here, an in particular not reqwest and tokio. I think following the pattern so far BroadcastNotifications could be a request that the user handles with any HTTP client they want and then could call back into LSPS5ServiceHandler. Alternatively, we could also use a trait similar to the current HTTPClient, but I don't think we want to keep the default implementation. Note that the blocking reqwest variant wraps a tokio runtime internally, and therefore should never (1, 2, ...) be used together. I guess technically we could consider a default async version of the trait that uses async reqwest, but I would prefer to simply have well-documented trait on our end that the user can implement however they choose to. Also note that stacking tokio runtimes is heavily discouraged in general, so assuming our users would themselves use a tokio runtime, we shouldn't wrap one in LSPS5ServiceHandler.

  2. Note that lightning-liquidity is optionally no-std compliant, so please don't rely on std wherever possible, often it's just a matter of using core instead and importing the respective types from crate::prelude. If you really find yourselves needing to use std, make sure it's feature gated behind feature = "std" and we provide an alternative for users that don't support it.

  3. Minor: Regarding formatting we're using tabs, not spaces. Feel free to run ./contrib/run-rustfmt.sh after each commit to run our formatting scripts.

  4. This PR in its current scope is great, just want to note that eventually we need to add persistence for the state. As we haven't fully fleshed out the persistence strategy for lightning-liquidity in general yet, it's actually preferred to defer this to a follow-up, but just wanted to mention it. Also note that some changes to MessageQueue/EventQueue will happen in #3509, but will ping you to rebase once that has been merged. (just sidenotes here).

I hope these initial points make sense, let me know if you have any questions, or once you made corresponding changes and think this is ready for the next round of review!

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@tnull
Copy link
Contributor

tnull commented Mar 13, 2025

This is a huge PR, but it wasn’t obvious to me how to split it in a way that would still make sense (I did split it into small commits to make it easier to review.). I’m open to suggestions if you have ideas on how this could be structured differently.

Thanks for asking! I'm totally fine to keep this (with its current scope) in a single PR, as long as we keep the commit history pretty clean to allow continuing review to happen commit-by-commit. To this end, please make sure add any fixup commits clearly marked (e.g. via a f or fixup prefix in the commit message header) directly under the commit they belong to, so they can cleanly be squashed into the respective feature commits in-between review rounds.

@tnull
Copy link
Contributor

tnull commented Mar 13, 2025

Btw, I'm not sure if you're familiar with the previous attempt of implementing LSPS5: #3499

Given this is a clean slate, not sure how much there is to learn, but still might be worth a look. Also not sure if @johncantrell97 would be interested in reviewing this PR, too, as he's familiar with the codebase and LSPS5.

@martinsaposnic martinsaposnic marked this pull request as draft March 14, 2025 14:49
@martinsaposnic martinsaposnic force-pushed the lsps5 branch 2 times, most recently from 1d4b47c to edf5346 Compare March 14, 2025 16:31
@martinsaposnic martinsaposnic marked this pull request as ready for review March 14, 2025 16:31
@martinsaposnic
Copy link
Contributor Author

martinsaposnic commented Mar 14, 2025

@tnull, ready for the next review round!

  • Removed reqwest and tokio.
  • HttpClient is now a generic trait, allowing users to pass any implementation.
  • Removed std.
  • Small refactor on client and service to be able to delete some silly / unnecessary code.
  • Ran formatting on every commit.
  • All new changes are in commits prefixed with fixup:.

CI is failing because of the usage of the url crate (which I guess does not support rust 1.63?), which I need for validating the webhook URL. A new commit will come addressing that shortly

@martinsaposnic martinsaposnic requested a review from tnull March 14, 2025 17:12
@martinsaposnic martinsaposnic force-pushed the lsps5 branch 7 times, most recently from 9809682 to af5929e Compare March 16, 2025 14:24
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @tnull @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @tnull @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@martinsaposnic
Copy link
Contributor Author

@TheBlueMatt just pushed a few commits addressing your comments. let me know what you think

Copy link
Contributor

@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.

One last improvement suggestion on the fixups (add a link), otherwise fixups are fine by me and would be good for squashing.

/// Sign an arbitrary message with the node's secret key.
///
/// Creates a digital signature of a message given the node's secret. The message is prefixed
/// with "Lightning Signed Message:" before signing.
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

looks good 2cb5743
image

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

I think I'm happy with this as it is, needs squash, though (I think the need for rebase will go away after squash, but maybe not).

This will be used to allow disabling time-dependent functionality.
'time' is included in the features default.
Introduce new_from_duration_since_epoch constructor from Duration. Also
add abs_diff function to use on client / service. Also do feature='time'
instead of feature='std' on time related functionality
Allows validating webhook URLs without depending on the external url crate.
Define LSPSMessage request, response and error types.
Also introduce LSPS5AppName, LSPS5WebhookUrl, WebhookNotification types
Introduce SendWebhookNotification event for LSPS5/service, and also
WebhookRegistered, WebhookRegistrationFailed, WebhooksListed,
WebhookRemoved and WebhookRemovalFailed events for LSPS5/client.
Implements the LSPS5 webhook registration service that
allows LSPs to notify clients of important events via webhooks.
This service handles webhook registration, listing, removal,
and notification delivery according to the LSPS5 specification.
Implements the client-side functionality for LSPS5 webhook registration,
allowing clients to register, list, and remove webhooks with LSPs.
…ions from an LSP.

As context, this utility started as part of the client, but was extracted
in favor of having it separated, so it's clear that this functions should not
be used by the client, but by the proxy server that has to forward the notifications
Fully integrates the LSPS5 webhook components into the
lightning-liquidity framework, enabling usage through the LiquidityManager.
@martinsaposnic
Copy link
Contributor Author

martinsaposnic commented Jul 23, 2025

conflicts fixed and fixups squashed!

Copy link
Contributor

@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.

Alright, since Matt said he's happy I'm gonna land this to reduce the risk of the branch getting stale yet again. We have quite a few follow-ups planned anyways, so can always still iterate on it if we found we missed something.

@tnull tnull merged commit ff279d6 into lightningdevkit:main Jul 24, 2025
27 of 28 checks passed
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Did another brief skim through and found a few more things its probably worth following up on.

"Received unexpected request message from {}",
counterparty_node_id
),
action: ErrorAction::IgnoreAndLog(Level::Info),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oops, we shouldn't log at INFO a peer (any peer, might not be "our LSP") sending us garbage.

};
let mut result: Result<(), LightningError> = Err(LightningError {
err: format!("Received LSPS5 response from unknown peer: {}", counterparty_node_id),
action: ErrorAction::IgnoreAndLog(Level::Error),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, we shouldn't be logging at ERROR a peer sending us garbage.

} else {
result = Err(LightningError {
err: format!("Received response for unknown request ID: {}", request_id.0),
action: ErrorAction::IgnoreAndLog(Level::Info),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here.

pub struct LSPS5ServiceConfig {
/// Maximum number of webhooks allowed per client.
pub max_webhooks_per_client: u32,
/// Minimum time between sending the same notification type in hours (default: 24)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be, like, 30 seconds, not a full day? If a user receives two payments over the course of an hour we definitely want to send two notifications, not eat the second.

lsps5_client_handler.handle_message(msg, sender_node_id)?;
},
None => {
return Err(LightningError { err: format!("Received LSPS5 response message without LSPS5 client handler configured. From node = {:?}", sender_node_id), action: ErrorAction::IgnoreAndLog(Level::Info)});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here and in the logs above we also shouldn't be logging this at INFO level.

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.

4 participants