Skip to content

Hold times for successful payments #3801

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 12 commits into
base: main
Choose a base branch
from

Conversation

joostjager
Copy link
Contributor

@joostjager joostjager commented May 26, 2025

Apply the hold time reporting mechanism as implemented in #2256 to the success case. Spec in lightning/bolts#1044

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented May 26, 2025

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

@joostjager joostjager changed the title Successful payment hold times Hold times for successful payments May 26, 2025
@joostjager joostjager force-pushed the fulfill-hold-times branch 7 times, most recently from badc803 to e913312 Compare May 27, 2025 09:52
@joostjager joostjager force-pushed the fulfill-hold-times branch from e913312 to 69a99b4 Compare May 27, 2025 11:53
Copy link

codecov bot commented May 27, 2025

Codecov Report

Attention: Patch coverage is 85.88710% with 210 lines in your changes missing coverage. Please review.

Project coverage is 88.82%. Comparing base (257ebad) to head (5519b4c).

Files with missing lines Patch % Lines
lightning/src/ln/channelmanager.rs 84.72% 116 Missing and 7 partials ⚠️
lightning/src/ln/channel.rs 84.44% 75 Missing and 11 partials ⚠️
lightning/src/ln/payment_tests.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3801      +/-   ##
==========================================
- Coverage   88.82%   88.82%   -0.01%     
==========================================
  Files         165      165              
  Lines      119075   119955     +880     
  Branches   119075   119955     +880     
==========================================
+ Hits       105769   106550     +781     
- Misses      10986    11101     +115     
+ Partials     2320     2304      -16     

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

@joostjager joostjager force-pushed the fulfill-hold-times branch from 69a99b4 to 1f56e04 Compare May 27, 2025 12:24
@joostjager joostjager force-pushed the fulfill-hold-times branch 8 times, most recently from bace463 to 1c64a50 Compare June 26, 2025 13:52
@joostjager joostjager marked this pull request as ready for review June 26, 2025 14:16
@joostjager joostjager marked this pull request as draft June 26, 2025 14:17
@joostjager joostjager marked this pull request as draft June 26, 2025 14:17
@joostjager joostjager self-assigned this Jun 26, 2025
@joostjager joostjager force-pushed the fulfill-hold-times branch 2 times, most recently from 233cbfc to f5668f5 Compare June 30, 2025 09:36
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

Still going through a first pass, made it to fcc1a8c

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

@joostjager
Copy link
Contributor Author

joostjager commented Jul 2, 2025

First batch of comments addressed diff. Push below is just a rebase.

@joostjager joostjager force-pushed the fulfill-hold-times branch from 5b219eb to d6985fd Compare July 2, 2025 11:08
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

Finished a pass, will take another look tomorrow! Lot to take in here having not reviewed the previous PRs


// Create new attribution data as the final hop. Always report a zero hold time, because reporting a
// non-zero value will not make a difference in the penalty that may be applied by the sender.
let attribution_data = process_fulfill_attribution_data(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: to me a clearer name would be add_hold_time_from_fulfill?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to keep the name somewhat in line with process_failure_packet. In your suggestion, what does "from fulfill" mean exactly?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah okay. Currently sounds to me like something the recipient would call when they receive the final update_fulfill_htlc to extract the hold times. It's a pretty similar name to process_onion_success atm.

what does "from fulfill" mean exactly?

Basically meant from_update_fulfill_htlc. ISTM we're not really processing the attribution data, more like adding to it? I get wanting to be consistent with the other pre-existing method though.

Copy link
Contributor Author

@joostjager joostjager Jul 4, 2025

Choose a reason for hiding this comment

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

Of course "process" is the vaguest possible word. Now renamed process_onion_success to decode_fulfill_attribution_data. Not consistent with the existing failure case naming, but I think more descriptive within the scope of this PR.

let mut holding_cell_failures =
holding_cell_htlc_updates.iter_mut().filter_map(|upd| {
if let HTLCUpdateAwaitingACK::FailHTLC {
holding_cell_htlc_updates.iter_mut().filter_map(|upd| match upd {
Copy link
Contributor

Choose a reason for hiding this comment

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

Honestly this ser code makes me nervous. Is it possible to test a round-trip ser with some failures and some claims, or extend an existing test around holding cell htlcs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The test do_channel_holding_cell_serialize is hitting these two match arms. I don't see a simple round-trip test for FundedChannel. Looked into it, but that would require a lot of instantiation of all the fields inside FundedChannel. Let's discuss what the best move is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Extended blinding_point_skimmed_fee_malformed_ser with None and Some attribution_data.

// Shift attribution data to prepare for processing the next hop.
attribution_data.shift_left();
} else {
log_debug!(
Copy link
Contributor

Choose a reason for hiding this comment

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

We hit this in a bunch of places in tests, should that be the case / why is that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've looked at the tests that hit this and it looks to be a mix of onchain resolution (where there is no attribution data), and restart / data loss (where we also may not recover attribution data because it is not critical).

route_hop_idx
);

break;
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like we'll return a subset of the hold times in this case? Would it be better to continue and get the hold times that we can? I'm wondering if one node on the path can cause us to miss parsing some hold times here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would only work in the specific case where an upstream node correctly shifted and encrypted and also didn't corrupt any of the received data, but added invalid hmacs. I think that would need to be a software bug? I thought it is not worth doing Option just for that. But open to different views.

let (_, path_events) =
claim_payment_along_route(ClaimAlongRouteArgs::new(&nodes[0], route, preimage.unwrap()));

// If we've delayed, check that this is reflected in the hold times.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also check that the hold times are decreasing along the path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.


// Create new attribution data as the final hop. Always report a zero hold time, because reporting a
// non-zero value will not make a difference in the penalty that may be applied by the sender.
let attribution_data = process_fulfill_attribution_data(
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah okay. Currently sounds to me like something the recipient would call when they receive the final update_fulfill_htlc to extract the hold times. It's a pretty similar name to process_onion_success atm.

what does "from fulfill" mean exactly?

Basically meant from_update_fulfill_htlc. ISTM we're not really processing the attribution data, more like adding to it? I get wanting to be consistent with the other pre-existing method though.

joostjager added 10 commits July 4, 2025 09:58
Preparation for reuse of the logic.
Need to store AttributionData as part of the inbound HTLC removal reason
so that it can be used in the upstream UpdateFulfillHTLC message.
Necessary to preserve attribution data when the HTLC is in the holding
cell.
Adds hold time reporting for the final and intermediate nodes.
AttributionData is needed as part of the outbound HTLC outcome when
revoke_and_ack has happened and the AttributionData is decoded to get
the hold times for inclusion in the PaymentPathSuccessful event.
Prepare for inspecting hold times in PaymentPathSuccessful.
@joostjager joostjager force-pushed the fulfill-hold-times branch from 5519b4c to 3aed96e Compare July 4, 2025 08:08
@joostjager
Copy link
Contributor Author

joostjager commented Jul 4, 2025

Comments addressed diff

Hold times are surfaced via the PaymentPathSuccessful event.
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @valentinewallace @carlaKC! 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 @valentinewallace @carlaKC! 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.

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

Successfully merging this pull request may close these issues.

3 participants