Skip to content

multi: stop opening legacy channels - #11212

Merged
ziggie1984 merged 8 commits into
lightningnetwork:masterfrom
ziggie1984:disable-legacy-channels
Sep 24, 2026
Merged

ziggie1984 merged 8 commits into
lightningnetwork:masterfrom
ziggie1984:disable-legacy-channels

Conversation

@ziggie1984

@ziggie1984 ziggie1984 commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

Change Description

In this PR, we stop opening and accepting new channels that use the legacy
commitment type. Channels that already use it are untouched: they keep working,
and can be operated, force closed and cooperatively closed exactly as before.
Only opening new ones is refused. The code that drives the type stays in place
and gets removed separately in 0.22, which keeps this small enough to backport
to 0.21 and 0.20.

Fixes #11195.

The legacy type was removed from the
spec

in 2024, and lnd is the last implementation still creating them. Its tweaked
to_remote output is why funds in such a channel cannot be recovered
unilaterally after data loss, which is the actual harm reported in the issue.

Where this sits

Channel commitments have gone through four generations, each superseding the
one before it:

LEGACY  ->  static remote key  ->  anchors  ->  taproot

LEGACY tweaks the to_remote output with a per-commitment point. Static
remote key (option_static_remotekey) leaves that output untweaked, which is
what makes it recoverable from the seed alone. Anchors
(option_anchors_zero_fee_htlc_tx) adds the anchor outputs that allow fee
bumping after a force close. Taproot moves the funding output to musig2.

This PR removes the first generation from the set we will open, and nothing
else. The second is dealt with in #11216.

The hole

An empty channel_type TLV in open_channel asks for exactly the legacy type,
and the branch handling it performed no feature check whatsoever, since the
type predates feature bits entirely. Any peer could obtain a legacy channel
from us regardless of what either side signalled, and we would do the same to
them. That is what TestFundingManagerRejectLegacyChanType now covers,
adapted from the reproduction in #11195: a peer advertising both
option_static_remotekey and option_anchors_zero_fee_htlc_tx sends an empty
channel type, and we reply with an error instead of echoing it back in
accept_channel.

negotiateCommitmentType in funding/commitment_type_negotiation.go is the
only place a commitment type for a new channel gets chosen, for both the
initiator (handleInitFundingMsg) and the responder
(fundeeProcessOpenChannel), so the change lives there. Implicit negotiation
still falls back to the static remote key type and only fails once there is
nothing left below it.

We also found that the funding manager's own test nodes signalled no features
at all, which means they had been negotiating legacy channels among
themselves. They now default to static remote key.

Scope

Only the legacy type. The static remote key type is still spec-valid, it is
what replaced legacy, and its to_remote is untweaked so the recovery problem
above does not apply to it. Refusing it as well would mean refusing channels
from any peer that cannot do anchors, which is not something to do in a patch
release. That belongs with the code removal in 0.22.

The rejection is a lnwire.FundingError (ErrChanTypeDeprecated) rather than
a plain error, because failFundingFlow only forwards the text of whitelisted
error types and flattens everything else into "funding failed due to internal
error", which would tell the remote nothing. Its string is kept as terse as
the ones beside it: what the remote needs to know is that the type is not
acceptable, and naming our replacement on the wire would only add another
fingerprint.

OpenChannel rejects commitment_type LEGACY up front so the caller gets a
clear error before we touch the wallet or the peer. The enum value itself has
to stay, since CommitmentType is also the reporting type for ListChannels,
ClosedChannels, PendingChannels and the channel acceptor, and channels we
already have still report it.

The restriction is documented on the API itself: the LEGACY enum value notes
that it is only reported for channels that already exist, and the
commitment_type fields of OpenChannelRequest and BatchOpenChannel note
that it is turned down as an input. The regenerated code carries no change
beyond the comments.

The dev build only protocol.legacy.committweak option is deprecated and made
a no-op. It stopped the node from signalling option_static_remotekey, which
now leaves no commitment type left to negotiate at all.

See each commit message for a detailed description w.r.t the incremental
changes.

Steps to Test

Three code paths could produce a legacy channel, and each has a test:

Path Test
Responder: peer sends an empty channel_type TestFundingManagerRejectLegacyChanType
Initiator, implicit fall back TestCommitmentTypeNegotiation/default_legacy_rejected
Initiator, explicit RPC request itest legacy_chan_type_rejected, TestCommitmentTypeNegotiation/explicit_legacy_rejected
go test ./funding/...
make itest-only icase="legacy_chan_type_rejected" backend=btcd

Two tests used to open legacy channels and now use static remote key instead.
The watchtower one opted in deliberately; the remote signer one did not, and
was itself an instance of the bug above. Both produce the same commitment
shape and the same fees, so no assertion moved. Re-ran those plus everything
else the funding path touches:

make itest-only icase='(legacy_chan_type_rejected|revoked_close_retribution_altruist|psbt_outbound|basic_flow|batch_channel_funding|channel_fundmax_error)' backend=btcd

All nine pass. make lint is clean, unit tests pass, and each commit builds on
its own under both the default and dev build tags.

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from 0e630a8 to de8dcb6 Compare September 21, 2026 15:57
@ziggie1984 ziggie1984 self-assigned this Sep 21, 2026
@ziggie1984 ziggie1984 added backport-v0.20.x-branch This label is used to trigger the creation of a backport PR to the branch `v0.20.x-branch`. backport-v0.21.x-branch This label triggers a backport to branch `v0.21.x-branch ` labels Sep 21, 2026
@ziggie1984 ziggie1984 added this to v0.21 Sep 21, 2026
@ziggie1984 ziggie1984 moved this to In progress in v0.21 Sep 21, 2026
@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from de8dcb6 to b3994cf Compare September 21, 2026 16:43
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Sep 21, 2026
@github-actions

Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

file classification | 13 files | 218 lines changed (excluding tests)

🔴 Critical (5 files)
  • funding/commitment_type_negotiation.go - core logic that decides the commitment type for new channels (initiator and responder paths)
  • funding/manager.go - funding manager entry points into commitment type negotiation
  • lnwire/error.go - adds new wire-level funding error code for rejected deprecated channel types
  • rpcserver.go - OpenChannel RPC now rejects deprecated commitment_type values
  • server.go - server-level wiring of the new protocol enforcement option
🟡 Medium (3 files)
  • cmd/commands/cmd_open_channel.go - CLI: removes tweakless from --channel_type (client-side only)
  • lncfg/protocol.go - new --protocol.no-deprecated-chan-types flag, deprecates --protocol.no-anchors
  • lncfg/protocol_integration.go - integration-build-only flag wiring
🟢 Low (5 files)
  • docs/release-notes/release-notes-0.20.5.md - release notes
  • docs/release-notes/release-notes-0.21.4.md - release notes
  • funding/commitment_type_negotiation_test.go - test-only changes
  • itest/lnd_funding_test.go - test-only changes
  • sample-lnd.conf - sample config comment updates

Analysis

This PR changes how lnd negotiates channel commitment types on open, touching the core funding negotiation path (funding/commitment_type_negotiation.go, funding/manager.go), the peer-facing wire error surface (lnwire/error.go), and the OpenChannel RPC validation (rpcserver.go), plus related server.go wiring. These are all CRITICAL-tier packages (funding workflow, lnwire protocol, and core server/RPC coordination), so the PR is classified CRITICAL and warrants expert review of the negotiation logic and its interaction with existing legacy/static-remote-key channels. File and line counts (13 non-test files, ~218 lines excluding tests) are well below the automatic-bump thresholds, so no additional escalation applies.


To override, add a severity-override-{critical,high,medium,low} label.

@ziggie1984 ziggie1984 moved this from In progress to In review in v0.21 Sep 21, 2026
@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from b3994cf to 5828b7f Compare September 21, 2026 19:49

@Lrifton92 Lrifton92 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read through the negotiation change and its call sites; this looks right to me.

A few things I checked:

  • negotiateCommitmentType really is the only place a new channel's type gets picked: its only callers are fundeeProcessOpenChannel and handleInitFundingMsg, and OpenChannel, OpenChannelSync and BatchOpenChannel all go through parseOpenChannelReq, so the RPC check covers every way in.
  • ErrNoAnchorSupport being a plain error rather than a FundingError is fine: the responder already rejects an open without channel_type with ErrChanTypeRequired (manager.go:1578), so implicit negotiation, and with it this error, can only happen on the initiator side, where it goes back to our own caller.
  • The explicit table has exactly two pre-anchor branches, StaticRemoteKey alone and the empty vector, and both are gated now. Every other branch requires anchors or taproot.
  • --protocol.no-anchors: configToFlatMap flags a hidden field only when it's non-zero, so the startup warning fires only for configs that actually set it. legacy.committweak is still dev-only, so production can't drop below anchors any more.

go test ./funding -run TestCommitmentTypeNegotiation passes locally.

One small test gap: the new cases cover "default no downgrade to tweakless", but not the case where neither side signals static remote key. The noDeprecated check comes before both fallbacks, so the code already handles it; a case with that feature vector would just make sure the legacy fallback can't come back unnoticed if the check is ever moved.

@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from 5828b7f to 2fb854a Compare September 21, 2026 21:52
@ziggie1984 ziggie1984 changed the title multi: stop opening legacy and static remote key channels multi: stop opening legacy channels Sep 21, 2026

@Roasbeef Roasbeef left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

))

return &chanType, lnwallet.CommitmentTypeTweakless
return &chanType, lnwallet.CommitmentTypeTweakless, nil

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to go further and also start rejecting non anchor chans?

@starius starius left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits.

I propose to add this historical context of channel generations to the PR description somewhere:
LEGACY → static remote key → anchors → taproot.

Should we test continued operation of existing legacy channels after upgrading? Itests switch to static remote key. That makes sense for creating new channels, but removes their legacy integration coverage. An older-version or persisted-state fixture should exercise reconnection, payments, closure, and watchtower protection using an already-created legacy channel. Including a pending legacy channel across restart would also protect the upgrade boundary. Lower-level legacy tests remain, so this is a coverage limitation, not evidence those operations are broken.

using the legacy commitment type, which was
[removed](https://github.com/lightning/bolts/commit/91f4bd2383cc2fc7a0a43b697e209f9eb9f5183c)
from the spec in 2024. Its tweaked `to_remote` output is why funds in such a
channel cannot be recovered after data loss.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It cannot be recovered unilaterally. If the peer supplies the appropriate commitment point, it is still possible.

Comment thread lnwire/error.go Outdated

// ErrChanTypeDeprecated is returned by a remote peer that receives a
// FundingOpen request for a channel type it no longer opens, namely
// the legacy and the static remote key commitment types. It is kept

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and the static remote key commitment types

This PR continues accepting static remote key. This appears to be leftover wording from the broader proposal.

Comment thread funding/commitment_type_negotiation.go Outdated
Comment on lines 38 to 39
// The returned ChannelType is always non-nil and is always signaled on the
// wire. An error is only returned if desiredChanType is not supported.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this part needs updating.

Suggested comment:

// On success, the returned ChannelType is non-nil and is signaled on the
// wire. An error is returned if the requested type is unsupported or
// deprecated, or if no supported default type can be selected.

Comment thread rpcserver.go
case lnrpc.CommitmentType_LEGACY:
channelType = new(lnwire.ChannelType)
*channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector())
return nil, funding.ErrDeprecatedChanType

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also document this restriction in lightning.proto? The LEGACY enum and the commitment_type fields in OpenChannelRequest and BatchOpenChannel don't mention that legacy is now rejected for new openings. The enum should remain for reporting existing channels, but callers should be able to discover the input restriction from the API documentation.

Comment thread funding/commitment_type_negotiation.go Outdated
Comment on lines +490 to +493
// The only type left to fall back on is the legacy one, which we never
// open. This is reachable when we do not signal static remote key
// ourselves, which no released configuration can produce any more.
return nil, 0, ErrDeprecatedChanType

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch is also reachable when we advertise static remote key but the peer does not. Could we describe the condition as a lack of mutually supported channel types? The current wording focuses on a local configuration that is no longer possible, which makes this look unreachable in production.

Comment thread funding/commitment_type_negotiation.go Outdated
Comment on lines +17 to +19
// ErrDeprecatedChanType is returned when the caller of our own RPC asks
// for the legacy commitment type. We keep operating the legacy channels
// we already have, but no longer open new ones.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectDefaultChannelType also returns this error when automatic selection would otherwise fall back to legacy, even if the caller requested no particular type. Could we mention that case here and adjust "who asked for the type" below? The distinction between the operator-facing error and the wire error still makes sense.

Comment on lines +287 to +296
// With no static remote key on either side there is
// nothing left to fall back on but the legacy type.
name: "default legacy rejected",
channelFeatures: nil,
localFeatures: lnwire.NewRawFeatureVector(),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
),
expectsCommitType: lnwallet.CommitmentTypeLegacy,
expectsChanType: (*lnwire.ChannelType)(
lnwire.NewRawFeatureVector(),
),
expectsErr: nil,
expectsErr: ErrDeprecatedChanType,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one side lacks static-remote-key support in this test; the other advertises both static remote key and anchors. Could this say "Without mutual support for static remote key, there is nothing left to fall back on but legacy"? That also describes the reversed peer ordering exercised by the test.

@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from 2fb854a to 6c96f1d Compare September 22, 2026 11:37
@ziggie1984

Copy link
Copy Markdown
Collaborator Author

Should we test continued operation of existing legacy channels after upgrading?

Good question, so I went and checked what was actually there before this PR.

There was exactly one deliberate end to end legacy test: the LEGACY subcase of
testRevokedCloseRetributionAltruistWatchtower. Both nodes run with
--protocol.legacy.committweak, so neither signals option_static_remotekey
and the channel really is legacy. It covers open, pay, breach, justice sweep.
That is the one this PR moves over to static remote key.

Three other places look like legacy coverage but are not:

  • lnd_coop_close_with_htlcs_test.go:304 passes LEGACY to
    AssertClosingTxInMempool, which only feeds it to CommitTypeHasAnchors to
    decide whether to expect one or two txs in the mempool. It means "no anchors",
    not "legacy channel".
  • The LEGACY branches in runBasicFundingTest were dead code, since
    allFundingTypes never contained it.
  • lntest/utils.go:161 is just the node args mapping.

lnd_remote_signer_test.go:617 did create a legacy channel, but not on purpose.
Neither of its nodes runs with committweak, so both support static remote key.
The channel only came out legacy because the empty channel_type was accepted
with no feature check at all, which is the bug this PR fixes. It was an instance
of the problem rather than coverage of it. The funding manager unit tests were
in the same boat: testNode signalled no features whatsoever, so all of them
were quietly negotiating legacy channels among themselves. Both are fixed here.

The lower level coverage you mention is untouched, and it is where the real
testing lives. TestBackupTask parametrizes over all four generations including
SingleFunderBit, and contractcourt/chain_watcher_test.go,
lnwallet/channel_test.go, lnwallet/transactions_test.go,
channeldb/channel_test.go and input/size_test.go all exercise the tweaked
to_remote path.

So the scenarios you list, reconnection, payments, closure, watchtower
protection on an already created channel, and a pending channel across a
restart, were never covered at the itest level, before this PR or after it. What
you are asking for is net new coverage rather than restoring something this PR
removed. I agree it is worth having, and I think it belongs in its own PR rather
than a backport. Happy to open an issue for it.

I also added the generation history to the PR description, thanks for the
suggestion.

In this commit, we add ErrChanTypeDeprecated so that a peer whose channel
type we reject learns the actual reason. failFundingFlow only forwards the
text of whitelisted error types and flattens everything else into a generic
"funding failed due to internal error", which tells the remote nothing.

The string is kept as terse as the ones around it. What the remote needs to
know is that the type isn't acceptable; which type to use instead is our
local policy, and spelling it out on the wire would only add another
fingerprint for no gain.
In this commit, we turn the dev build only committweak option into a no-op.
It stopped the node from signalling option_static_remotekey, which left the
legacy commitment type as the only one it could negotiate. Since we no
longer open channels of that type, such a node would be unable to negotiate
any commitment type at all.

The field is kept so that configs which still set it continue to parse.
@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from 6c96f1d to 4510e69 Compare September 22, 2026 11:51

@Lrifton92 Lrifton92 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at 4510e69 (a rebase of 6c96f1d; range-diff shows only the release-notes contributor list changed), since my earlier approval was on 5828b7f, before the scope was narrowed to legacy only.

  • Legacy is now refused unconditionally on both paths: an explicit LEGACY in parseOpenChannelReq, an empty channel_type from the peer (ErrChanTypeDeprecated on the wire), and the default selection when there is no mutually supported type above legacy (ErrDeprecatedChanType). Static remote key stays negotiable, and --channel_type tweakless is back in lncli, which matches that.
  • No leftovers from the broader proposal: ErrNoAnchorSupport, NoDeprecatedChanTypes and the "legacy and static remote key" wording are all gone.
  • Locally: go vet (incl. -tags="integration dev" on itest/lntest) is clean; ./funding, ./lnwire, ./lncfg pass, including TestCommitmentTypeNegotiation and the TestFundingManagerReject{Legacy,Missing}ChanType cases.

LGTM.

@ziggie1984
ziggie1984 requested a review from starius September 22, 2026 17:37
@ziggie1984

Copy link
Copy Markdown
Collaborator Author

@Lrifton92 could you please stop spamming the repos with your bot!

@Lrifton92

Copy link
Copy Markdown

Understood, and sorry for the noise. I'll stop posting reviews on this and the other lightningnetwork repos.

@starius starius left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🎉

In PR description:

funds in such a channel cannot be recovered after data loss,

Should be "cannot be recovered unilaterally"

Also the same fix is needed to commit "funding: never open a legacy channel" description.

In this commit, we stop opening and accepting new channels using the legacy
commitment type, which was removed from the spec in 2024. Its tweaked
to_remote output is why funds in such a channel cannot be recovered
unilaterally after data loss. Channels that already use it are untouched:
they keep working and can be operated, force closed and cooperatively closed
exactly as before.

An empty channel_type asks for precisely this type, and that branch performed
no feature check whatsoever, since the type predates feature bits entirely.
Any peer could obtain a legacy channel from us no matter what either side
signalled, which is what TestFundingManagerRejectLegacyChanType now covers.

Implicit negotiation keeps falling back to the static remote key type, and
only fails once there is nothing left below it.

The funding manager's own test nodes signalled no features at all, which
means they were negotiating legacy channels among themselves. They now
default to static remote key.
In this commit, we turn down a request for the legacy commitment type before
we touch the wallet or the peer, so the caller gets a clear error instead of
one from deep inside the funding flow.

The LEGACY enum value itself has to stay: CommitmentType is also the
reporting type for ListChannels, ClosedChannels, PendingChannels and the
channel acceptor, and channels we already have still report it.
In this commit, we move the two tests that still opened legacy channels over
to static remote key. Both produce the same commitment shape and the same
fees, so no assertion moves.

The watchtower case opted into legacy deliberately. The remote signer one did
not: neither of its nodes runs with committweak, so both support static
remote key, and the channel only came out legacy because an empty
channel_type was accepted without any check. That is the bug this PR fixes,
sitting in our own suite.

The legacy node arguments and the unreferenced CfgLegacy go away with them,
since committweak no longer does anything.
In this commit, we spell out that existing legacy channels are not affected
and can still be operated and closed, since that is the question an operator
reading these notes will have. Only opening new ones is refused.
In this commit, we add the same entries as the 0.20.5 notes, kept in a commit
of their own so that each backport carries only the release notes of the
branch it lands on.
In this commit, we document the restriction on the API itself, so callers
can discover it without reading the release notes. The LEGACY enum value
notes that it is only ever reported for channels that already exist, and the
commitment_type fields of OpenChannelRequest and BatchOpenChannel note that
it is turned down as an input.

Worth spelling out on those fields that an empty channel type on the wire
asks for the legacy type as well, so there is no way to request it at all.

The generated code carries no change beyond the comments.
@ziggie1984
ziggie1984 force-pushed the disable-legacy-channels branch from 4510e69 to 9b634bf Compare September 23, 2026 22:38
@ziggie1984
ziggie1984 merged commit 112cb5f into lightningnetwork:master Sep 24, 2026
39 of 40 checks passed
@github-actions

Copy link
Copy Markdown

Created backport PR for v0.20.x-branch:

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin backport-11212-to-v0.20.x-branch
git worktree add --checkout .worktree/backport-11212-to-v0.20.x-branch backport-11212-to-v0.20.x-branch
cd .worktree/backport-11212-to-v0.20.x-branch
git reset --hard HEAD^
git cherry-pick -x 1e3b0747d9b640e817b02a2062b73313f8da15e6 98a0d345a2301629c73c473450864aeeee5d646e 6ea22314c3ad5cc246471e93eb1e6f4856451867 a03747961b0b97ca12bae39452383116cf4ad5ec 03d8b09dca48caf5a6361d05c40c46672853d35e 76c18acbd63bf2868be7663f15d4d30f9471ac70 a5556e0525c2a105778d7e515faf161f535dcd93 9b634bfd0929ecc0f0e0ddc0b6aa85a5234a06b6
git push --force-with-lease

@github-actions

Copy link
Copy Markdown

Created backport PR for v0.21.x-branch:

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin backport-11212-to-v0.21.x-branch
git worktree add --checkout .worktree/backport-11212-to-v0.21.x-branch backport-11212-to-v0.21.x-branch
cd .worktree/backport-11212-to-v0.21.x-branch
git reset --hard HEAD^
git cherry-pick -x 1e3b0747d9b640e817b02a2062b73313f8da15e6 98a0d345a2301629c73c473450864aeeee5d646e 6ea22314c3ad5cc246471e93eb1e6f4856451867 a03747961b0b97ca12bae39452383116cf4ad5ec 03d8b09dca48caf5a6361d05c40c46672853d35e 76c18acbd63bf2868be7663f15d4d30f9471ac70 a5556e0525c2a105778d7e515faf161f535dcd93 9b634bfd0929ecc0f0e0ddc0b6aa85a5234a06b6
git push --force-with-lease

@ziggie1984 ziggie1984 removed the backport-v0.20.x-branch This label is used to trigger the creation of a backport PR to the branch `v0.20.x-branch`. label Sep 24, 2026
ziggie1984 added a commit that referenced this pull request Sep 24, 2026
…21.x-branch

[v0.21.x-branch] Backport #11212: multi: stop opening legacy channels
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-v0.21.x-branch This label triggers a backport to branch `v0.21.x-branch ` severity-critical Requires expert review - security/consensus critical

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Reject new legacy channels

4 participants