Skip to content

tests: xfail repro for stuck CLOSINGD_COMPLETE#9103

Open
ksedgwic wants to merge 2 commits into
ElementsProject:masterfrom
ksedgwic:test-closing-stuck
Open

tests: xfail repro for stuck CLOSINGD_COMPLETE#9103
ksedgwic wants to merge 2 commits into
ElementsProject:masterfrom
ksedgwic:test-closing-stuck

Conversation

@ksedgwic
Copy link
Copy Markdown
Collaborator

When a mutual close negotiation completes on a channel whose funding
tx never confirmed, the channel state is stuck. The signed close tx
is permanently invalid — its input is a 2-of-2 funding output that
does not exist on chain — so the state machine has no path from
CLOSINGD_COMPLETE to FUNDING_SPEND_SEEN / ONCHAIN. The channel
sits indefinitely with no cleanup.

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

reproduces #9102

@ksedgwic
Copy link
Copy Markdown
Collaborator Author

related to ksedgwic/clboss#312

…t funding

When mutual close negotiation completes on a channel whose funding tx
never confirms, the channel state is stuck. The signed close tx is
permanently invalid (its input is a 2-of-2 funding output that does not
exist on chain), so the state machine has no path from CLOSINGD_COMPLETE
to FUNDING_SPEND_SEEN / ONCHAIN. The channel sits indefinitely with no
cleanup.

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

Changelog-None
…inputs

The existing CLOSINGD_COMPLETE reproducer (test_closingd_complete_stuck_no_funding)
demonstrates the channel record stays in CLOSINGD_COMPLETE while the
funding tx is merely unmined (in-mempool but prioritised below the
block-min-fee).

That leaves a loophole in the policy argument: as long as the
funding inputs remain unspent, the funding tx could in principle still
confirm if reprioritised, so the state-machine wait is defensible.

This new test removes that loophole.  After both sides reach
CLOSINGD_COMPLETE we:

  1. Capture the funding tx hex via the proxy mock (it never reaches
     bitcoind's mempool).
  2. Force-unreserve the funding inputs (the funding-tx reservation
     is ~2016 blocks, so we explicitly pass a large reserve= value
     to push reserved_til below current height).
  3. Spend the same UTXOs in a separate withdraw tx that DOES land
     on chain (the proxy mock forwards non-funding-tx broadcasts).
  4. Mature the double-spend 100 blocks past confirmation, matching
     Bitcoin's coinbase maturity rule (the canonical reorg-safe depth).

At this point the funding tx is provably and permanently invalid;
no Bitcoin convention treats the spend as still reversible.  Yet
CLN keeps the channel record stuck in CLOSINGD_COMPLETE on both
sides.

The test is marked xfail-strict, like its sibling.  Once a fix
exists, removing the marker will turn an xpass into a hard failure
to alert the developer to clean up the marker.

Reproduces ElementsProject#9102 with a stronger demonstration than the existing
test.

Verified locally: both CLOSINGD_COMPLETE reproducers xfail in 100s
total (test_closingd_complete_stuck_no_funding 47s,
test_closingd_complete_stuck_funding_inputs_double_spent 54s).
@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 ...

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.

1 participant