-
Notifications
You must be signed in to change notification settings - Fork 418
Support splice shared input signing #4024
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?
Conversation
The `handle_channel_resumption` path is reachable from both channel reestablish and monitor update completion. Since we only want to sign once we know the monitor update has completed, it's possible we could have unintentionally attempted to sign if we were still pending the monitor update but had a channel reestablish occur.
This is reachable if the event doesn't get handled and a channel reestablish occurs.
This commit tracks all data related to the shared input of a splice, such that a valid witness can be formed upon the splice transaction finalization.
We get async for free since the user already has to call back into LDK via `funding_transaction_signed`. If the signer fails to sign, they can simply retry the call once it is available.
👋 Thanks for assigning @jkczyz as a reviewer! |
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, aside from the last commit.
&self.context.secp_ctx, | ||
) | ||
.map_err(|_| APIError::ChannelUnavailable { | ||
err: "Signer unavailable".to_string(), |
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, so the user can't just call signer_available
(which is the usual async-signing API) they have to cache their funding tx sigs and call signed again? I don't think this is the right API and would prefer to just wait to do splice-async-signing until we can do it right.
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.
Well we have to handle the error here anyway so I figured why not. They will have to cache the transaction in the interim, though we can drop that requirement once we do "proper" async.
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.
Honestly I figure we should just not? Doing it this way means we need to go document it, and users might try to implement it and then change it again later? Its not that much work to cache the local sigs, so if you want to go for it, sure, but doing it wrong seems worse than not at all.
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.
Caching the sigs on our end seems worse, they would call funding_transaction_signed
with empty witnesses? If you don't like this then either we remove the Result
from the method signature or we try to do it the right way now.
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.
My point is that if a signing method fails, the user needs to be able to call signer_unblocked
(and only signer_unblocked
) to kick the channel into gear. Making them call funding_transaction_signed
is pretty annoying (the async signing API is already a bit annoying to use by having to call signer_unblocked
, having to now also track exactly which method they need to call to kick the channel seems like we're just asking for trouble).
Also CI is sad. |
@@ -7969,9 +7981,9 @@ where | |||
} | |||
|
|||
pub fn funding_transaction_signed( | |||
&mut self, witnesses: Vec<Witness>, | |||
&mut self, funding_txid_signed: Txid, witnesses: Vec<Witness>, |
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.
CI is failing because this parameter is passed in the first commit before later being added here.
.zip(witnesses) | ||
.for_each(|(input, witness)| input.witness = witness); | ||
} | ||
|
||
pub fn holder_is_initiator(&self) -> bool { | ||
self.holder_is_initiator | ||
} | ||
|
||
pub fn shared_input_index(&self) -> Option<u32> { | ||
self.shared_input_index.clone() |
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.
clone
is unnecessary
This also addresses follow-ups from #3889.