Skip to content

tests: add xfail-strict reproducer for funder-side stuck CHANNELD_AWAITING_LOCKIN#9113

Open
ksedgwic wants to merge 1 commit into
ElementsProject:masterfrom
ksedgwic:stuck-awaiting-lockin-test
Open

tests: add xfail-strict reproducer for funder-side stuck CHANNELD_AWAITING_LOCKIN#9113
ksedgwic wants to merge 1 commit into
ElementsProject:masterfrom
ksedgwic:stuck-awaiting-lockin-test

Conversation

@ksedgwic

@ksedgwic ksedgwic commented May 5, 2026

Copy link
Copy Markdown
Collaborator

When a node is the funder of a channel whose funding tx never confirms (broadcast rejected at ATMP, evicted from mempool, or simply never broadcast), the channel record stays in CHANNELD_AWAITING_LOCKIN indefinitely. CLN already implements the BOLT 2 fundee-side forget rule (PR #1468, --max-funding-unconfirmed-blocks, default 2016) but has no equivalent on the funder side.

The test asserts the desired post-fix behavior (state has moved beyond CHANNELD_AWAITING_LOCKIN) and is marked @pytest.mark.xfail(strict=True) so:

  • CI reports XFAIL today (acceptable; documents the open bug)
  • When the bug is fixed, the test reports XPASS, which strict=True promotes to a hard failure to alert the dev to remove the marker.

Reproduces #9112

@ksedgwic

ksedgwic commented May 5, 2026

Copy link
Copy Markdown
Collaborator Author

Adds a second xfail-strict reproducer for the same root cause:
test_funder_stuck_close_before_funding_confirm.

If the operator (or an automation like CLBOSS's spenderp) issues
close while the funder is in CHANNELD_AWAITING_LOCKIN with an
unbroadcastable funding tx, the channel transitions to
AWAITING_UNILATERAL and CLN tries to broadcast a commitment tx that
spends the (non-existent) funding output. That commit tx can never
confirm either, so the channel record sits stuck in
AWAITING_UNILATERAL indefinitely.

Same setup as the first test (mock_rpc on sendrawtransaction +
dev-max-funding-unconfirmed-blocks=10); diverges by stopping l2 and
calling close with unilateraltimeout=1 to force AWAITING_UNILATERAL,
then asserts the channel is no longer in that state after THRESHOLD+5
blocks.

Kept as a separate commit so it can be split off if maintainers prefer
to address the two stuck states independently.

@ksedgwic

Copy link
Copy Markdown
Collaborator Author

@ddustin added the "double-spent funding tx" modification we discussed, channel is stuck even though the funding can never commit ...

…ITING_LOCKIN

A user can be left with a channel wedged in a state that provably will never
resolve, with no transition to a sensible end state. On the funder side this
happens two ways, and CLN cleans up neither.

How it gets stuck: the node funds a channel and the funding tx never confirms
(rejected at broadcast for too low a fee, evicted from the mempool, or never
relayed). The channel sits in CHANNELD_AWAITING_LOCKIN. CLN implements the
BOLT 2 fundee forget rule (2016 blocks) but has no funder-side equivalent, and
the funder always has funds at stake, so it cannot simply time the channel out.
If the operator then closes the still-unlocked channel, CLN drops to chain and
moves to AWAITING_UNILATERAL with a commitment tx whose only input is the
never-existing funding output, so it sits stuck there instead.

Why the state is held until a funding input is double-spent: while the funding
inputs are unspent the funding tx can still confirm (e.g. if rebroadcast at a
higher fee), and if it does the channel becomes live (or the commitment tx
becomes valid and the close resolves), so the channel must be kept until the
funding is known dead.

Why it is safe to clear once the double-spend is buried: when a funding input
is spent by another tx and that spend is buried deep enough that a reorg will
not reverse it, the funding tx can never confirm. The funding output will never
exist, so the channel can never make progress and can move to a clean end state.

This adds two xfail-strict reproducers, one for each stuck state
(CHANNELD_AWAITING_LOCKIN and AWAITING_UNILATERAL). Each drives the funder into
the stuck state behind a never-confirming funding tx, double-spends a funding
input, and asserts both edges: the channel must stay stuck while the
double-spend is shallow, and must reach a resolved state once the spend is
reorg-safe. The markers should be removed once a fix exists.

Reproduces ElementsProject#9112.

Changelog-None
@ksedgwic ksedgwic force-pushed the stuck-awaiting-lockin-test branch from cbbaaff to c1decec Compare June 22, 2026 22:14
@ksedgwic

Copy link
Copy Markdown
Collaborator Author

rebased and simplified

@ksedgwic ksedgwic mentioned this pull request Jun 22, 2026
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants