Skip to content

Fix Critical Error handling in HTLC interception #294

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mubarak23
Copy link
Contributor

@mubarak23 mubarak23 commented Jul 1, 2025

closes #272

TODO: This needed to be done.

Currently, when a CriticalError occurs during HTLC interception in handle_intercepted_htlc, the function immediately returns without waiting for other running interceptors to complete. This can leave interceptors in an inconsistent state and prevent proper cleanup.

Changes

  • Store critical errors instead of immediately returning, When a CriticalError occurs, store it in a local variable rather than returning immediately.
  • Send shutdown signal to all other running interceptors when a critical error is encountered
  • Added critical_error variable to store any CriticalError that occurs
  • Modified the Err(e) match arm to store the error and trigger shutdown instead of immediate return

Copy link
Collaborator

@elnosh elnosh left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the change.
Could you update the TODO comment at the top saying this needed to be done.

@carlaKC
Copy link
Contributor

carlaKC commented Jul 2, 2025

Change looks good - would be nice to add test coverage for this shutdown case

@mubarak23
Copy link
Contributor Author

Thanks for the feedback! 🙌 You're absolutely right — test coverage for the shutdown behavior is important. I will add a test to ensure that when a CriticalError occurs, the expected behavior happens

@mubarak23 mubarak23 requested a review from elnosh July 2, 2025 15:36
Copy link
Collaborator

@elnosh elnosh left a comment

Choose a reason for hiding this comment

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

heh sorry, with this Could you update the TODO comment at the top saying this needed to be done. I meant update the TODO comment in handle_intercepted_htlc

Comment on lines +2485 to +2513
async fn test_intercepted_htlc_critical_error() {
// Interceptor that will return a critical error.
let mut mock_interceptor = MockTestInterceptor::new();
mock_interceptor
.expect_intercept_htlc()
.returning(|_| Err(CriticalError::InterceptorError("critical failure".into())));
mock_interceptor
.expect_notify_resolution()
.returning(|_| Ok(()));

let (interceptor_trigger, interceptor_listener) = triggered::trigger();
let mock_request = create_intercept_request(interceptor_listener);

let mock_interceptor: Arc<dyn Interceptor> = Arc::new(mock_interceptor);
let interceptors = vec![mock_interceptor];
let (_, shutdown_listener) = triggered::trigger();

let result = handle_intercepted_htlc(
mock_request,
&interceptors,
interceptor_trigger,
shutdown_listener,
)
.await;

assert!(result.is_err());
let err_string = format!("{:?}", result.unwrap_err());
assert!(err_string.contains("critical failure"));
}
Copy link
Collaborator

@elnosh elnosh Jul 2, 2025

Choose a reason for hiding this comment

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

hmm this checks that the returned error is the one returned from interceptor but not sure if @carlaKC meant to add a case where other interceptors received a shutdown signal if a critical error was returned from another one. Although we are just mocking interceptors so I'm babbling here.

Copy link
Contributor

Choose a reason for hiding this comment

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

to add a case where other interceptors received a shutdown signal if a critical error was returned from another one

This is what I meant.

Sadly I don't think that we'll be able to mock the interceptors to check that each of them trigger shutdown. Was thinking of a very simple interceptor that just blocks until we get shutdown and then we add a timeout on the test to make sure that nothgin is blocking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so there is no way to get an interceptor to blocked until we got a shutdown

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure what you mean? You can implement an interceptor that listens on the shutdown listener for the purpose of the test and that should block?

We wait for all the interceptors to exit when we get the shutdown signal, so they should block if the trigger isn't hit by a critical error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok,
i will probably look into how mock interceptor are done i.e

create_intercept_request

then i will implement an interceptor that listens on the shutdown listener and mock it

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.

simln-lib: handle graceful shutdown during htlc interception
3 participants