-
Notifications
You must be signed in to change notification settings - Fork 409
LSPS2: Add error handling events for failed client requests #3804
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
base: main
Are you sure you want to change the base?
Conversation
👋 Thanks for assigning @joostjager as a reviewer! |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3804 +/- ##
==========================================
+ Coverage 89.74% 89.83% +0.09%
==========================================
Files 159 159
Lines 128906 128933 +27
Branches 128906 128933 +27
==========================================
+ Hits 115681 115833 +152
+ Misses 10520 10404 -116
+ Partials 2705 2696 -9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Thanks! Mostly looks good, just some comments.
Will review the test changes closer once #3712 landed and we rebased, as the same refactoring is happening there.
code: LSPS0_CLIENT_REJECTED_ERROR_CODE, | ||
message: "Reached maximum number of pending requests. Please try again later." |
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.
No, it was very intentional that we hardcoded a standardized response here, because while we want to log the full details, the counterparty shouldn't learn anything about our rate limits.
Could you expand what else you mean with "incorrect error response types"?
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.
Could you expand what else you mean with "incorrect error response types"?
insert_pending_request
is called by handle_get_info_request
and handle_buy_request
but it always returns BuyError
, even if the request type is GetInfo
. Now it returns GetInfoError
for GetInfo
requests and BuyError
for Buy
requests.
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.
Ah, right, that difference got lost in the diff here. Yes, then let's still keep returning the hardcoded error strings to the counterparties, but just make sure the right response type is returned.
👋 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. |
✅ Added second reviewer: @joostjager |
service_node.liquidity_manager.handle_custom_message(get_info_request, client_node_id).unwrap(); | ||
|
||
let get_info_event = service_node.liquidity_manager.next_event().unwrap(); | ||
match get_info_event { |
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.
With something like this, you can keep the happy flow unindented for improved readability.
let LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::GetInfo {
request_id,
counterparty_node_id,
token,
}) = service_node.liquidity_manager.next_event().unwrap() else {
panic!("Unexpected event");
};
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.
Let-else bindings are only stabilized since rustc 1.65, so we can't use them currently due to our 1.63 MSRV.
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.
Hmm too bad. Still if let
can I think remove one level of indent?
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.
found a few places where indentation is reduced so I did the if let
there 👍
"Peer {} reached maximum number of total pending requests: {}", | ||
if self.total_pending_requests.load(Ordering::Relaxed) >= MAX_TOTAL_PENDING_REQUESTS { | ||
let error_message = format!( | ||
"reached maximum number of total pending requests {}: {}", |
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.
Not capitalized anymore?
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.
Is it useful to have counterparty_node_id in this message when the total is exceeded?
@@ -1226,45 +1226,43 @@ where | |||
&self, peer_state_lock: &mut MutexGuard<'a, PeerState>, request_id: LSPSRequestId, | |||
counterparty_node_id: PublicKey, request: LSPS2Request, | |||
) -> (Result<(), LightningError>, Option<LSPSMessage>) { |
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.
Pre-existing but shouldn't the type be Result<(), (LightningError, LSPSMessage>)
?
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.
No, the method returns either Ok(())
or an error, and optionally a message that needs to be sent to the counterparty.
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 thought that in this fn, it's indeed either Ok(()), or an error always accompanied by a msg (not optional). But maybe this is a useful type further up the call stack?
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.
But the rest of the API follows the same pattern of returning Result<(), LightningError>
. Changing the result type in this way here would mean we'd get an Err
variant that we can't just bubble up at the callsite but rather awkwardly need to map, etc.
Also note that we chose that if let Some(msg)
pattern to ensure we're able to drop all locks (in particular peer_state_lock
) before enqueuing messages, which might lead to reentry when PeerManager
processes the enqueued messages. I.e., it was exactly introduced to avoid handling/enqueing the messages in the match
.
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 Err variant is already not just bubbled up. Both call sites do a match on the result already?
I was indeed wondering why the lock had to be dropped before enqueueing. Could be worthy of a comment.
This thread is mostly out of curiosity / to learn. No changes requested.
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 Err variant is already not just bubbled up
Yes it is, essentially at all callsites?
I was indeed wondering why the lock had to be dropped before enqueueing. Could be worthy of a comment.
Well, it's also best practice in general. But yeah. At some point we could even consider a refactoring that would make it infeasible to enqueue while still holding the lock.
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 it is, essentially at all callsites?
There is still a match at the call sites.
Well, it's also best practice in general.
You mean best practice to not hold the lock longer than necessary? Or not queueing while holding the lock?
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.
You mean best practice to not hold the lock longer than necessary? Or not queueing while holding the lock?
The latter.
e80ef0d
to
f1c95fc
Compare
@tnull @joostjager thank you for your reviews! Comments are addressed on
Rebase with #3712 is done |
The build macos-latest 1.63.0 failed with error I don't think it's related to my PR but will take a closer look tomorrow |
assert_eq!(counterparty_node_id, service_node_id); | ||
assert_eq!(error.code, 1); // LSPS0_CLIENT_REJECTED_ERROR_CODE | ||
}, | ||
_ => panic!("Expected LSPS2ClientEvent::BuyRequestFailed event"), |
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.
nit: more indent removal possible using if let? Also further up there are blocks.
Yeah, no, this is unrelated as they unfortunately bumped the MSRV on a patch release. CI fix is here: #3812 |
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.
/// `max(min_fee_msat, proportional*(payment_size_msat/1_000_000))`. | ||
/// `max(min_fee_msat, proportional * (payment_size_msat / 1_000_000))`. | ||
/// | ||
/// Returns the used [`LSPSRequestId`], which will be returned via [`InvoiceParametersReady`]. |
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.
nit: Returns .. which will be returned via
is kind of a confusing formulation. So where will it be returned now?
Maybe just "Returns the used LSPSRequestId that was used for the buy request" or similar?
@@ -50,7 +55,7 @@ fn setup_test_lsps2( | |||
}; | |||
|
|||
let (service_node, client_node) = | |||
create_service_and_client_nodes("webhook_registration_flow", service_config, client_config); | |||
create_service_and_client_nodes("default_persist_dir", service_config, client_config); |
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 make this a parameter of setup_test_lsps2
and create test-specific persist dirs? This would be helpful as otherwise all tests might run on the same persisted directories, which would break going forward once we actually persist something.
Add GetInfoFailed and BuyRequestFailed event variants to LSPS2ClientEvent to handle LSP error responses, similar to the OrderRequestFailed event added to LSPS1. Fixes lightningdevkit#3459
Update handle_get_info_error and handle_buy_error to: - Emit GetInfoFailed and BuyRequestFailed events to notify users - Return LightningError instead of Ok() to properly signal failures - Use the actual error parameter instead of ignoring it This ensures consistent error handling behavior across LSPS implementations.
Replace hardcoded BuyError responses with appropriate error types based on the actual request (GetInfo vs Buy) when rate limiting is triggered. This fixes incorrect error response types and provides an easy way to test the error event handling added in this PR.
Add tests for the new error events: - Test per-peer request limit rejection (GetInfoFailed) - Test global request limit rejection (BuyRequestFailed) - Test invalid token handling (GetInfoFailed) These tests verify that error events are properly emitted when LSP requests fail, ensuring the error handling behavior works end-to-end.
🔔 1st Reminder Hey @tnull @joostjager! This PR has been waiting for your review. |
1 similar comment
🔔 1st Reminder Hey @tnull @joostjager! This PR has been waiting for your review. |
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 fixups.
Fixes #3459
Add GetInfoFailed and BuyRequestFailed event variants to LSPS2ClientEvent
to handle LSP error responses, similar to the OrderRequestFailed event
added to LSPS1.