From 58231f1ff88217b7c12043c73d8420585232f0ae Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Mon, 20 Apr 2026 15:20:44 +0200 Subject: [PATCH 1/3] chanacceptor: map SIMPLE_TAPROOT_FINAL in rpc acceptor The feature-bits-to-lnrpc-enum switch in sendAcceptRequests covered every commitment type the RPC acceptor can be asked about, except the production taproot variant introduced alongside the prod-taproot-chans work. For a channel open using SimpleTaprootChannelsRequiredFinal (with any combination of the scid-alias / zero-conf modifiers), the switch fell through to the default branch, which logs a warning and leaves commitmentType at its zero value -- lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE. External acceptor clients then see UNKNOWN rather than the actual commitment type and either reject or misclassify the channel. Add the four missing cases so the new commitment type is reported to acceptor clients correctly. --- chanacceptor/rpcacceptor.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/chanacceptor/rpcacceptor.go b/chanacceptor/rpcacceptor.go index aff8c3dc701..1a06b659c55 100644 --- a/chanacceptor/rpcacceptor.go +++ b/chanacceptor/rpcacceptor.go @@ -356,6 +356,30 @@ func (r *RPCAcceptor) sendAcceptRequests(errChan chan error, ): commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + lnwire.ScidAliasRequired, + ): + commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + ): + commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + ): + commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + ): + commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + case channelFeatures.OnlyContains( lnwire.SimpleTaprootOverlayChansRequired, lnwire.ZeroConfRequired, From 6d95154801fe08a5572a78f82790b531567c2f7b Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Mon, 20 Apr 2026 15:20:50 +0200 Subject: [PATCH 2/3] server: do not auto-enable RBF coop close for overlay channels An earlier commit added an auto-enable that forces RbfCoopClose=true whenever either taproot channel flag is set. This breaks taproot-overlay channels, because the RBF coop close state machine in lnwallet/chancloser/rbf_coop_*.go does not integrate the AuxCloser (or any other aux) hook that overlay channels depend on to build aux-aware close transactions. A node that enables --protocol.simple-taproot-overlay-chans ends up with RBF force-on and its overlay channel closes silently fail, leaving the aux closer unable to finalize on-chain. Narrow the auto-enable so it only fires for TaprootChans (staging / final taproot) and explicitly skips it when TaprootOverlayChans is set. Operators that positively want RBF can still opt in via --protocol.rbf-coop-close; this change only removes the forced path that silently breaks overlay closes. --- server.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/server.go b/server.go index 9eddf92e691..09cb4858bdb 100644 --- a/server.go +++ b/server.go @@ -670,11 +670,18 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, "in a standalone lnd build") } - // If either taproot channel type is enabled, we also need to enable - // the RBF cooperative close protocol, as it is required for taproot - // channel interoperability. - if cfg.ProtocolOptions.TaprootChans || - cfg.ProtocolOptions.TaprootOverlayChans { + // If taproot channels are enabled, we also enable the RBF cooperative + // close protocol, as it is required for taproot channel + // interoperability. + // + // Exception: when taproot-overlay channels are enabled we do NOT + // auto-enable RBF, because the RBF coop close state machine does not + // yet thread through the AuxCloser hook that overlay channels rely on + // to build the aux-aware close transaction. Forcing RBF on for a + // node that holds overlay channels would silently break their coop + // closes. + if cfg.ProtocolOptions.TaprootChans && + !cfg.ProtocolOptions.TaprootOverlayChans { cfg.ProtocolOptions.RbfCoopClose = true } From 33f623c855b0f3631586965157f26c093b5b3b48 Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Mon, 20 Apr 2026 16:11:31 +0200 Subject: [PATCH 3/3] docs: add release note for SIMPLE_TAPROOT_FINAL follow-ups See https://github.com/lightningnetwork/lnd/pull/10763. --- docs/release-notes/release-notes-0.21.0.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/release-notes/release-notes-0.21.0.md b/docs/release-notes/release-notes-0.21.0.md index ea6b0a3aaee..23b93a0fd0d 100644 --- a/docs/release-notes/release-notes-0.21.0.md +++ b/docs/release-notes/release-notes-0.21.0.md @@ -78,6 +78,16 @@ subscriptions and the hodl queue, preventing orphaned subscriptions from blocking invoice resolution. +* [Fixed two follow-ups to the production taproot channels + work](https://github.com/lightningnetwork/lnd/pull/10763). The RPC channel + acceptor switch now maps `SIMPLE_TAPROOT_FINAL` (with every combination of + the `scid-alias` / `zero-conf` modifiers) so final-taproot opens are + reported to external acceptor clients with the correct commitment type + instead of `UNKNOWN_COMMITMENT_TYPE`. The taproot RBF cooperative-close + auto-enable is also narrowed to skip taproot-overlay channels, since the + RBF close state machine does not yet thread through the `AuxCloser` hook + that overlay channels rely on to build aux-aware close transactions. + # New Features - [Basic Support](https://github.com/lightningnetwork/lnd/pull/9868) for onion