lnwallet/chancloser: remove dead code and wrap errors
What changed, and why it matters
This is a small code cleanup in LND's cooperative channel-closing logic. It removes a redundant safety check that could never fail and adds more descriptive error messages when closing a Lightning channel. There is no direct security vulnerability being fixed, and no exploit path is introduced or removed.
No immediate action required. Treat as routine refactoring. If reviewing, verify that IsTaproot() indeed guarantees RemoteMusigSession is non-nil in all call paths to confirm the removed nil check was truly unreachable.
Security signals we found
Dead-code removal in Taproot/Musig2 cooperative close path
Error-message wrapping for debugging; no behavioral change
No bounds, input validation, or cryptographic changes
No vendor security framing or incident attribution
Evidence from the diff
The commit refactors lnwallet/chancloser/rbf_coop_transitions.go. In sendShutdownEvents, the guard IsTaproot() already requires both LocalMusigSession and RemoteMusigSession to be non-nil, so the inner remoteMusig != nil branch was always taken; the patch removes that dead branch and calls env.RemoteMusigSession.ClosingNonce() directly. In LocalOfferSent and RemoteCloseStart ProcessEvent methods, four bare return nil, err returns are wrapped with fmt.Errorf context strings. No cryptographic, consensus, or network behavior changes are visible.
Changed components
lnwallet/chancloser/rbf_coop_transitions.goLND RBF cooperative channel close state machineInspect captured patch +15 / −17
diff --git a/lnwallet/chancloser/rbf_coop_transitions.go b/lnwallet/chancloser/rbf_coop_transitions.go
index 9ca47ed..f31099c 100644
--- a/lnwallet/chancloser/rbf_coop_transitions.go
+++ b/lnwallet/chancloser/rbf_coop_transitions.go
@@ -58,20 +58,14 @@ func sendShutdownEvents(chanID lnwire.ChannelID, chanPoint wire.OutPoint,
// RemoteMusigSession, as that'll set our localNonce, we'll
// receive their remoteNonce for this session once we get their
// ClosingComplete message.
- remoteMusig := env.RemoteMusigSession
- if remoteMusig != nil {
- closeeNonces, err := remoteMusig.ClosingNonce()
- if err != nil {
- return nil, none, fmt.Errorf("unable "+
- "to generate closee "+
- "nonce: %w", err)
- }
- localCloseeNonce = fn.Some(
- lnwire.Musig2Nonce(
- closeeNonces.PubNonce,
- ),
- )
+ closeeNonces, err := env.RemoteMusigSession.ClosingNonce()
+ if err != nil {
+ return nil, none, fmt.Errorf("unable to generate "+
+ "closee nonce: %w", err)
}
+ localCloseeNonce = fn.Some(
+ lnwire.Musig2Nonce(closeeNonces.PubNonce),
+ )
}
// If we have a closee nonce, then make sure to include it in the
@@ -1584,7 +1578,8 @@ func (l *LocalOfferSent) ProcessEvent(event ProtocolEvent, env *Environment,
env, l, msg, sig, closeOpts,
)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("LocalOfferSent: unable "+
+ "to prepare closing sigs: %w", err)
}
closeOpts = append(closeOpts, musigOpts...)
@@ -1595,7 +1590,8 @@ func (l *LocalOfferSent) ProcessEvent(event ProtocolEvent, env *Environment,
l.RemoteDeliveryScript, l.ProposedFee, closeOpts...,
)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("LocalOfferSent: unable "+
+ "to complete coop close: %w", err)
}
// Invalidate the closer nonce now that the round is complete.
@@ -2065,7 +2061,8 @@ func (l *RemoteCloseStart) ProcessEvent(event ProtocolEvent, env *Environment,
l.RemoteDeliveryScript, chanOpts,
)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("RemoteCloseStart: unable "+
+ "to create closee sig: %w", err)
}
// With our signature created, we'll now attempt to finalize the
@@ -2076,7 +2073,8 @@ func (l *RemoteCloseStart) ProcessEvent(event ProtocolEvent, env *Environment,
chanOpts...,
)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("RemoteCloseStart: unable "+
+ "to complete coop close: %w", err)
}
chancloserLog.Infof("ChannelPoint(%v): received sig (fee=%v "+
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.