-
Notifications
You must be signed in to change notification settings - Fork 366
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
Handle fallible per commitment point in channel establishment #3109
base: main
Are you sure you want to change the base?
Handle fallible per commitment point in channel establishment #3109
Conversation
3fbf2e6
to
1e5b210
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3109 +/- ##
==========================================
+ Coverage 89.65% 89.92% +0.27%
==========================================
Files 126 126
Lines 102546 105339 +2793
Branches 102546 105339 +2793
==========================================
+ Hits 91935 94725 +2790
- Misses 7890 7974 +84
+ Partials 2721 2640 -81 ☔ View full report in Codecov by Sentry. |
1e5b210
to
07991fa
Compare
the commits from #3115 are second from the end, will rebase on top later this week, but generally most of the stuff here is in place |
07991fa
to
744f2ca
Compare
73583e7
to
b798ffa
Compare
0bdd4cc
to
0ac4ad8
Compare
When we get back to this, please address the comments from #3152 (review) |
7ea6d3f
to
c109e18
Compare
This also needs rebase now. |
df8902b
to
50b1d88
Compare
Will probably squash some of these commits together at some point but just kept them separate for now |
rebased and force pushed with the new approach. Previous branch is still here if it's helpful to see |
// `current_point` will become optional when async signing is implemented. | ||
let cur_holder_commitment_point = Some(self.context.holder_commitment_point.current_point()); | ||
let next_holder_commitment_point = self.context.holder_commitment_point.next_point(); | ||
let cur_holder_commitment_point = Some(self.holder_commitment_point.current_point()); | ||
let next_holder_commitment_point = self.holder_commitment_point.next_point(); |
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.
when reading, now that this will never be optional, can we unwrap/expect the value (or return a DecodeError on None)? what's the right way to handle this
50b1d88
to
760b055
Compare
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.
Nice, this is looking great. A few nits here and there but basically this LGTM.
{ | ||
self.context.maybe_downgrade_channel_features(fee_estimator)?; | ||
Ok(self.get_open_channel(chain_hash)) | ||
self.get_open_channel(chain_hash, logger).ok_or(()) |
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.
Sadly I think we need to duplicate this code in the v2 pipeline (get_open_channel_v2
)
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.
still need to get to this
} else { | ||
log_debug!(logger, "Not producing channel_ready: the holder commitment point is not available."); | ||
self.context.signer_pending_channel_ready = true; | ||
None |
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 think after this we are missing an update to get_announcement_sigs
to replay it (can come in a followup, but right now if you do an async signer it will always be forced to be a non-public channel).
// We make sure to set the channel ready flag here so that we try to | ||
// generate a channel ready for 0conf channels once our signer unblocked | ||
// for funding. | ||
self.context.signer_pending_channel_ready = true; |
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.
This is a confusing way to update the need_channel_ready
s in funding_signed
an funding_created
:). Instead, why don't we just update those to check if we want a channel_ready
whether we're ready to send one or not?
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.
Sorta confused here, are you saying we could just drop this since we already set need_channel_ready
in funding_created/signed
?
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 funding_signed
and funding_created
, need_channel_ready
are set by calling check_get_channel_ready
which is used to store whether we need to send a channel_ready
in the 0conf case. We now can fail check_get_channel_ready
even though we do need to send a channel_ready
(when the monitor update persist finishes) but have to handle checking signer_pending_channel_ready
now too, when we could instead just set need_channel_ready
because we do need a channel_ready
, and just possibly fail to send when we actually go to do the send.
@@ -31,7 +31,59 @@ use crate::util::test_channel_signer::SignerOp; | |||
use crate::util::logger::Logger; | |||
|
|||
#[test] | |||
fn test_async_commitment_signature_for_funding_created() { | |||
fn test_open_channel() { |
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.
Since it uses a different path, mind adding a test/variant that tests 0conf opens?
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.
done!
@@ -82,7 +138,12 @@ fn test_async_commitment_signature_for_funding_created() { | |||
} | |||
|
|||
#[test] | |||
fn test_async_commitment_signature_for_funding_signed() { | |||
fn test_funding_signed() { | |||
do_test_funding_signed(vec![SignerOp::SignCounterpartyCommitment, SignerOp::GetPerCommitmentPoint]); |
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.
If we're gonna run the test twice to test enabling ops in different orders can we check that the message we're looking for is only generated after the op we expect to generate the message?
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.
done!
Also CI is very sad |
Finally, if you get a chance, can you flesh out your commit messages more? Describe why we're doing each commit, what considerations went into the approach, and what risks we might have in the design we took, even just a few sentences may be helpful in the future when someone is looking at old code for what we were thinking when we made changes. |
We are choosing to move the `HolderCommitmentPoint` (the struct that tracks commitment points retrieved from the signer + the commitment number) to handle channel establishment, where we have no commitment point at all. Previously we introduced this struct to track when we were pending a commitment point (because of an async signer) during normal channel operation, which assumed we always had a commitment point to start out with. Intiially we tried to add an `Uninitialized` variant that held no points, but that meant that we needed to handle that case everywhere which left a bunch of scary/unnecessary unwraps/expects. Instead, we just hold an optional `HolderCommitmentPoint` struct on our unfunded channels, and a non-optional `HolderCommitmentPoint` for funded channels. This commit starts that transition. A following commit will remove the holder commitment point from the current `ChannelContext`. This also makes small fixups to the comments on the HolderCommitmentPoint variants.
Following a previous commit adding `HolderCommitmentPoint` elsewhere, we make the transition to use those commitment points and remove the existing one.
In the event that a signer cannot provide a commitment point immediately, we set a flag to remember we're waiting for this before we can send `open_channel`. We make sure to get the first two commitment points, so when we advance commitments, we always have a commitment point available.
This also slightly refactors get_funding_signed_msg to match the logic more similarly, as well as removes a log to fix a nit from lightningdevkit#3152.
Similar to `open_channel`, if a signer cannot provide a commitment point immediately, we set a flag to remember we're waiting for a point to send `accept_channel`. We make sure to get the first two points before moving on, so when we advance our commitment we always have a point available.
Here we handle the case where our signer is pending the next commitment point when we try to send channel ready. We set a flag to remember to send this message when our signer is unblocked. This follows the same general pattern as everywhere else where we're waiting on a commitment point from the signer in order to send a message.
760b055
to
140441e
Compare
140441e
to
ab345cd
Compare
CI still looks to be failing. |
Handles fallible
get_per_commitment_point
signer method (except for channel reestablish).We make
get_per_commitment_point
return a result type so that in theErr
case, we (LDK) can resume operation while an async signer fetches the commitment point. This will typically block sending out a message, but otherwise most state updates will occur. When the signature arrives, the user is expected to callChannelManager::signer_unblocked
and we will retryget_per_commitment_point
however this time the signer will return the commitment point withOk
, and we'll send out our message.This PR implements this flow for channel establishment, i.e.
open_channel
,accept_channel
, andchannel_ready
.Rough outline of how our
HolderCommitmentPoint
advances and gets new signatures:open_channel
- creates new outbound channel, immediately requests the first commit point, waits to have the first 2 commit points to be unblocked to send the messageaccept_channel
- same ^funding_created
- no op regarding commit pointsfunding_created
- uses point to verify first commitment, then advances commitment, requesting next pointfunding_signed
- no opfunding_signed
- same as above, verifies, advances, requests next pointchannel_ready
- waits to have the next commit point ready, then once unblocked sends the current point in thechannel_ready
message