-
Notifications
You must be signed in to change notification settings - Fork 371
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 for RAA #3150
Handle fallible per commitment point for RAA #3150
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #3150 +/- ##
==========================================
+ Coverage 89.74% 90.02% +0.27%
==========================================
Files 121 121
Lines 99858 103150 +3292
Branches 99858 103150 +3292
==========================================
+ Hits 89622 92863 +3241
- Misses 7561 7646 +85
+ Partials 2675 2641 -34 ☔ View full report in Codecov by Sentry. |
a079267
to
71cb518
Compare
(rebased after changes to #3149) |
Looks like the test code doesn't currently compile on this one. |
6bf0b5a
to
28f4678
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.
LGTM, feel free to squash we'll need to get a second review to glance.
log_trace!(logger, "Last revoke-and-ack pending in channel {} for sequence {} because the next per-commitment point is not available", | ||
&self.context.channel_id(), self.context.holder_commitment_point.transaction_number()); | ||
self.context.signer_pending_revoke_and_ack = 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.
It might be worth mentioning in a comment why we don't want to send an RAA here. If we have HolderCommitmentPoint::PendingNext
we still have current
and can in theory build a RevokeAndACK
, but if we send one immediately in response to a commitment_signed
we'll just get another commitment_signed
and be out of points anyway and unable to send a RevokeAndACK
, and avoiding sending the RAA is a neat way to avoid having to deal with ever actually not having the current point available. Obviously once we make release_commitment_secret
async we'll have to block on the signer anyway, so blocking here on a different signer operation doesnt add latency and simplifies our code by making our peer be blocked waiting on our signer, not just us.
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.
squashed + added a comment for this
28f4678
to
eb30c39
Compare
// in revoke_and_ack, which requires unblocking our signer and completing | ||
// the advance to the next point. So if we get here, either we've messed | ||
// up, or our counterparty has. | ||
debug_assert!(false, "We should be ready to advance our commitment point by the time we receive commitment_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.
To be clear, is this reachable with a misbehaving counterparty? Because we're currently closing the channel after advancing some state above like the latest monitor update id, may be worth adding some test coverage for this (maybe in follow-up)
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.
It shouldn't be. Without our commitment point provided in the last RAA our counterparty shouldn't be able to give us a CS that passes our signature checks.
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, i think maybe a way to handle this is to check self.holder_commitment_point.is_available()
with our checks above before we start updating state, then when we get here it's easier to know that this is unreachable?
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.
or maybe just move this to be the first thing we update?
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 don't feel strongly since Matt clarified that this should be unreachable. Could also update the comment to be more explicit about that, or what you suggested, up to you!
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.
just updated the last sentence of the comment to clarify this should be unreachable
self.get_last_commitment_update_for_send(logger).ok() | ||
} else { None }; | ||
if self.context.resend_order == RAACommitmentOrder::CommitmentFirst | ||
&& self.context.signer_pending_commitment_update && raa.is_some() { | ||
self.context.signer_pending_revoke_and_ack = true; | ||
raa = None; | ||
} | ||
if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst | ||
&& self.context.signer_pending_revoke_and_ack { | ||
self.context.signer_pending_commitment_update = 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.
Tests pass with this and the line below commented out
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.
added some test cases to cover here + the similar condition added in channel reestablish
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, tests still pass with these lines commented out. I don't wanna hold up the PR, though, so feel free to save this for follow-up.
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, are you running with RUSTFLAGS="--cfg=async_signing"
? they seem to fail when i comment out locally for me
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.
nvm you're right specifically commenting out the self.context.signer_pending_commitment_update = true;
still passes, will add coverage for this in a followup
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.
Oh you were right, I was using the cfg flag last review but not this one lol. But yeah sounds good!
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.
Need to revisit the last non-test commit tomorrow and I'm still somewhat playing catch-up with the past signer work but this should be close. Thanks for tackling async signing!
ce899fa
to
39da43c
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.
LGTM after squash. There are a few places missing test coverage but I'm good to save them for follow-up.
self.get_last_commitment_update_for_send(logger).ok() | ||
} else { None }; | ||
if self.context.resend_order == RAACommitmentOrder::CommitmentFirst | ||
&& self.context.signer_pending_commitment_update && raa.is_some() { | ||
self.context.signer_pending_revoke_and_ack = true; | ||
raa = None; | ||
} | ||
if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst | ||
&& self.context.signer_pending_revoke_and_ack { | ||
self.context.signer_pending_commitment_update = 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.
Hmm, tests still pass with these lines commented out. I don't wanna hold up the PR, though, so feel free to save this for follow-up.
let commitment_update = if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst | ||
&& self.context.signer_pending_revoke_and_ack { | ||
log_trace!(logger, "Reconnected channel {} with lost outbound RAA and lost remote commitment tx, but unable to send due to resend order, waiting on signer for revoke and ack", &self.context.channel_id()); | ||
self.context.signer_pending_commitment_update = 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.
Missing coverage here
39da43c
to
daa9baf
Compare
squashed with one small change updating the comment for this. Planning to add more test coverage in a follow up |
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 if CI's happy ✨
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.
Lets land it! We can do followups or whatever.
Includes simple changes to test util signers and tests, as well as handling the error case for get_per_commitment_point in HolderCommitmentPoint. This leaves a couple `.expect`s in places that will be addressed in a separate PR for handling funding.
Note: this does not test the CS -> RAA resend ordering, because this requires handling async get_per_commitment_point for channel reestablishment, which will be addressed in a follow up PR.
daa9baf
to
45c0a0f
Compare
failed rustfmt so i just fixed the nits |
Changes since @valentinewallace's ACK are pretty trivial, worst case we can hash them out in a followup: $ git diff-tree -U1 daa9baf 45c0a0f
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 2bed16bc5..be9d2d3ea 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -5499,5 +5499,5 @@ impl<SP: Deref> Channel<SP> where
- fn get_last_revoke_and_ack<L: Deref>(&mut self, _logger: &L) -> Option<msgs::RevokeAndACK> where L::Target: Logger {
+ fn get_last_revoke_and_ack<L: Deref>(&mut self, logger: &L) -> Option<msgs::RevokeAndACK> where L::Target: Logger {
debug_assert!(self.context.holder_commitment_point.transaction_number() <= INITIAL_COMMITMENT_NUMBER - 2);
- self.context.holder_commitment_point.try_resolve_pending(&self.context.holder_signer, &self.context.secp_ctx, _logger);
+ self.context.holder_commitment_point.try_resolve_pending(&self.context.holder_signer, &self.context.secp_ctx, logger);
let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.holder_commitment_point.transaction_number() + 2);
@@ -5523,3 +5523,3 @@ impl<SP: Deref> Channel<SP> where
// we're only ever waiting on one commitment point at a time.
- log_trace!(_logger, "Last revoke-and-ack pending in channel {} for sequence {} because the next per-commitment point is not available",
+ log_trace!(logger, "Last revoke-and-ack pending in channel {} for sequence {} because the next per-commitment point is not available",
&self.context.channel_id(), self.context.holder_commitment_point.transaction_number());
diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs
index 49f62a5bd..d684b4fe6 100644
--- a/lightning/src/sign/mod.rs
+++ b/lightning/src/sign/mod.rs
@@ -1358,4 +1358,5 @@ impl ChannelSigner for InMemorySigner {
let commitment_secret =
- SecretKey::from_slice(&chan_utils::build_commitment_secret(&self.commitment_seed, idx));
- commitment_secret.map(|secret| PublicKey::from_secret_key(secp_ctx, &secret)).map_err(|_| ())
+ SecretKey::from_slice(&chan_utils::build_commitment_secret(&self.commitment_seed, idx))
+ .unwrap();
+ Ok(PublicKey::from_secret_key(secp_ctx, &commitment_secret))
}
$ |
Builds on
#3149.This is the first PR to handle async
get_per_commitment_point
, and only handles theErr
cases for retrieving revoke_and_ack. We still need to handle this during funding (#3109) and channel reestablish (no PR yet) in upcoming PRs.For all async signing, we try to go about our normal business, and when we fail to get a signature from our signer, we pause our channel, and only unpause upon the user calling
ChannelManager::signer_unblocked
. With thesigner_pending_revoke_and_ack
flag being added in the prereq PR, we simply set the flag and allowget_last_revoke_and_ack
to return anOption
. We also make sure that in cases where we must send RAA then CS, that we defer sending a CS (even if it's available) until the signature for the RAA is unblocked.