-
Couldn't load subscription status.
- Fork 2.2k
Aux Closer: Move coop-close aux finalization to chain watcher #10289
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: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1061,6 +1061,76 @@ func (c *chainWatcher) toSelfAmount(tx *wire.MsgTx) btcutil.Amount { | |
| return btcutil.Amount(fn.Sum(vals)) | ||
| } | ||
|
|
||
| // finalizeCoopClose calls the aux closer to finalize a cooperative close | ||
| // transaction that has been confirmed on-chain. | ||
| func (c *chainWatcher) finalizeCoopClose(aux AuxChanCloser, | ||
| closeTx *wire.MsgTx) error { | ||
|
|
||
| chanState := c.cfg.chanState | ||
|
|
||
| // Get the shutdown info to extract the local delivery script. | ||
| shutdown, err := chanState.ShutdownInfo() | ||
| if err != nil { | ||
| return fmt.Errorf("get shutdown info: %w", err) | ||
| } | ||
|
|
||
| // TODO(roasbeef): Extract the internal key if this is a taproot | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? |
||
| // channel. For now, we leave it as None since we don't persist it | ||
| // separately from the delivery script. | ||
| var internalKey fn.Option[btcec.PublicKey] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the existing call site, this is always properly set. |
||
|
|
||
| // Build the AuxShutdownReq. | ||
| req := AuxShutdownReq{ | ||
| ChanPoint: chanState.FundingOutpoint, | ||
| ShortChanID: chanState.ShortChanID(), | ||
| InternalKey: internalKey, | ||
| Initiator: chanState.IsInitiator, | ||
| CommitBlob: chanState.LocalCommitment.CustomBlob, | ||
| FundingBlob: chanState.CustomBlob, | ||
| } | ||
|
|
||
| // Extract close outputs from the transaction. We need to identify | ||
| // which outputs belong to local vs remote parties. | ||
| var localCloseOutput, remoteCloseOutput fn.Option[CloseOutput] | ||
|
|
||
| // Get the delivery scripts for both parties. | ||
| var localDeliveryScript lnwire.DeliveryAddress | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment says both parties, but lonly extracts this script for a single party. |
||
| shutdown.WhenSome(func(s channeldb.ShutdownInfo) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC this must be set at this point. We can encode this invariant by returning an error if it isn't available. |
||
| localDeliveryScript = s.DeliveryScript.Val | ||
| }) | ||
|
|
||
| // Scan through the close transaction outputs to identify local and | ||
| // remote outputs. | ||
| for _, out := range closeTx.TxOut { | ||
| if len(localDeliveryScript) > 0 && | ||
| slices.Equal(out.PkScript, localDeliveryScript) { | ||
|
|
||
| localCloseOutput = fn.Some(CloseOutput{ | ||
| Amt: btcutil.Amount(out.Value), | ||
| PkScript: out.PkScript, | ||
| DustLimit: chanState.LocalChanCfg.DustLimit, | ||
| }) | ||
| } else { | ||
| // This must be the remote output. | ||
| remoteCloseOutput = fn.Some(CloseOutput{ | ||
| Amt: btcutil.Amount(out.Value), | ||
| PkScript: out.PkScript, | ||
| DustLimit: chanState.RemoteChanCfg.DustLimit, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // Build the AuxCloseDesc. | ||
| desc := AuxCloseDesc{ | ||
| AuxShutdownReq: req, | ||
| LocalCloseOutput: localCloseOutput, | ||
| RemoteCloseOutput: remoteCloseOutput, | ||
| } | ||
Roasbeef marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Call FinalizeClose on the aux closer. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Superflous comments here and above. |
||
| return aux.FinalizeClose(desc, closeTx) | ||
| } | ||
|
|
||
| // dispatchCooperativeClose processed a detect cooperative channel closure. | ||
| // We'll use the spending transaction to locate our output within the | ||
| // transaction, then clean up the database state. We'll also dispatch a | ||
|
|
@@ -1111,6 +1181,17 @@ func (c *chainWatcher) dispatchCooperativeClose(commitSpend *chainntnfs.SpendDet | |
| ChannelCloseSummary: closeSummary, | ||
| } | ||
|
|
||
| // If we have an aux closer, finalize the cooperative close now that | ||
| // it's confirmed. | ||
| err = fn.MapOptionZ( | ||
| c.cfg.auxCloser, func(aux AuxChanCloser) error { | ||
| return c.finalizeCoopClose(aux, broadcastTx) | ||
| }, | ||
| ) | ||
| if err != nil { | ||
| return fmt.Errorf("finalize coop close: %w", err) | ||
| } | ||
|
|
||
| // With the event processed, we'll now notify all subscribers of the | ||
| // event. | ||
| c.Lock() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -970,33 +970,6 @@ func (c *ChanCloser) ReceiveClosingSigned( //nolint:funlen | |
| } | ||
| c.closingTx = closeTx | ||
|
|
||
| // If there's an aux chan closer, then we'll finalize with it | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: is there value in leaving this code? This PR introduces more robust handling of the aux closer finalization by moving the hook call site from In case our peer stays online this would lead to a faster finalization which in turn maybe is a better user experience. |
||
| // before we write to disk. | ||
| err = fn.MapOptionZ( | ||
| c.cfg.AuxCloser, func(aux AuxChanCloser) error { | ||
| channel := c.cfg.Channel | ||
| //nolint:ll | ||
| req := AuxShutdownReq{ | ||
| ChanPoint: c.chanPoint, | ||
| ShortChanID: c.cfg.Channel.ShortChanID(), | ||
| InternalKey: c.localInternalKey, | ||
| Initiator: channel.IsInitiator(), | ||
| CommitBlob: channel.LocalCommitmentBlob(), | ||
| FundingBlob: channel.FundingBlob(), | ||
| } | ||
| desc := AuxCloseDesc{ | ||
| AuxShutdownReq: req, | ||
| LocalCloseOutput: c.localCloseOutput, | ||
| RemoteCloseOutput: c.remoteCloseOutput, | ||
| } | ||
|
|
||
| return aux.FinalizeClose(desc, closeTx) | ||
| }, | ||
| ) | ||
| if err != nil { | ||
| return noClosing, err | ||
| } | ||
|
|
||
| // Before publishing the closing tx, we persist it to the | ||
| // database, such that it can be republished if something goes | ||
| // wrong. | ||
|
|
||
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.
Why is this a todo specifically for roasbeef and not for @GeorgeTsagk?
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 todo was meant for @GeorgeTsagk , but realized now it is not needed at all. Will update comments accordingly