-
Notifications
You must be signed in to change notification settings - Fork 438
Dedup InboundUpdateAdd::Forwarded data; fix PaymentForwarded fields
#4405
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?
Dedup InboundUpdateAdd::Forwarded data; fix PaymentForwarded fields
#4405
Conversation
|
👋 Thanks for assigning @joostjager as a reviewer! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4405 +/- ##
==========================================
+ Coverage 86.05% 86.06% +0.01%
==========================================
Files 156 156
Lines 103384 103431 +47
Branches 103384 103431 +47
==========================================
+ Hits 88964 89021 +57
+ Misses 11905 11899 -6
+ Partials 2515 2511 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Useful when using these macros in lightning-tests/upgrade_downgrade_tests
In the next commit, we want to dedup fields between the InboundUpdateAdd::Forwarded's HTLCPreviousHopData and the outer InboundHTLCOutput/Channel structs, since many fields are duplicated in both places at the moment. As part of doing this cleanly, we first refactor the method that retrieves these InboundUpdateAdds for reconstructing the set of pending HTLCs during ChannelManager deconstruction. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Previously, the InboundUpdateAdd::Forwarded enum variant contained an HTLCPreviousHopData, which had a lot of fields that were redundant with the outer InboundHTLCOutput/Channel structs. Here we dedup those fields, which is important because the pending InboundUpdateAdds are persisted whenever the ChannelManager is persisted.
0d38512 to
94cb95d
Compare
|
Still need to finalize what manager version to write (#4303 (comment)), but otherwise this should be good to go. |
InboundUpdateAdd::Forwarded data with outer structsInboundUpdateAdd::Forwarded data; fix PaymentForwarded fields
TheBlueMatt
left a comment
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.
Didn't review the test changes but otherwise basically lgtm.
joostjager
left a comment
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.
Clean PR.
The PR description motivates the dedup as important for reducing persistence size, how much is actually saved? Claude says 153 bytes per HTLC.
Given that the number of in-flight forwarded HTLCs is typically low, the net persistence savings seem marginal.
| // Each 1M sat outbound channel has 100M msat max in-flight, so 150M msat requires splitting. | ||
| let amt_msat = 150_000_000; | ||
| let (route, payment_hash, payment_preimage, payment_secret) = | ||
| get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat); |
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.
In other tests, I've seen the routes being constructed in the test, for full control. Also a bit more self-documenting perhaps.
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 prefer it this way, it's more concise and looks less janky IMO.
|
One concern with reconstructing forwarding state from channel monitors: will trampoline make this significantly harder? Today a forward is a 1-to-1 link between two channels, but with trampoline a single logical forward can involve multiple inbound and multiple outbound HTLCs across different channels (MPP on both sides). Reconstructing that M-to-N relationship from individual monitors, without any explicit record tying them together, seems pretty complicated? |
|
It should be relatively doable - we need to assign a "trampoline id" for a trampoline anyway so that the outbound edges know where to go to update state/claim (in the |
|
The id seems helpful indeed. But even with that, reconstruction adds complexity on top of what's already a non-trivial trampoline state machine. And also it is already hard to get the current reconstruction right. I am still not fully sold that the idea of storing all state in the monitors one way or another, and the performance benefit that that might give us, is worth it at the current stage of the lightning game. I guess we'll find out. |
Makes an upcoming commit cleaner: when we add a next_hop variable we want to distinguish it from the previous hop.
Adds support for passing user_channel_id into the pending_claims_to_replay vec, which is used by the ChannelManager on startup. For now user_channel_id is always set to None, but in upcoming commits we will set it to Some when the downstream channel is still open (this is currently a bug). Separated out here for reviewability.
We need these fields to generate a correct PaymentForwarded event if we need to claim this inbound HTLC backwards after restart and it's already been claimed and removed on the outbound edge.
Previously, we were spuriously using the upstream channel's info when we should've been using the downstream channel's.
Previously, if a forwarding node reloaded mid-HTLC-forward with a preimage in the outbound edge monitor and the outbound edge channel still open, and subsequently reclaimed the inbound HTLC backwards, the PaymentForwarded event would be missing the next_user_channel_id field.
Test that if we restart and had two inbound MPP-part HTLCs received over the same channel in the holding cell prior to shutdown, and we lost the holding cell prior to restart, those HTLCs will still be claimed backwards. Test largely written by Claude
We previously had 5 due to wanting some flexibility to bump versions in between, but eventually concluded that wasn't necessary.
58edcb2 to
ab0ba65
Compare
It could potentially add up, especially for a node like c=, given how often we persist the manager. If 153 bytes is correct and all slots are filled then a single channel could have an additional ~73kib (Matt previously said his entire node is ~255kib, cc #4227 (comment)). Also nice to not have the potential for data to be inconsistent, of course, as you previously pointed out. |
|
Even after the dedup, the total per-HTLC storage for a forwarded-but-unresolved HTLC is still around 600 bytes (Clauded) across both channel sides. Matt's 255 kb node size also depends heavily on how busy the node is. Not sure if that is a useful baseline number. Also 483 htlcs in flight is an extreme case. Happy that the potential for inconsistencies has been fixed though! |
joostjager
left a comment
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.
Much better with the struct extracted!
Previously, the
InboundUpdateAdd::Forwardedenum variant contained anHTLCPreviousHopData, which had a lot of fields that were redundant with theouter
InboundHTLCOutput/Channelstructs. Here we dedup those fields, which isimportant because the pending
InboundUpdateAddsare persisted whenever theChannelManageris persisted.Based on #4303Partially addresses #4286