Skip to content

bcli: retry a failed gettxout instead of answering that the output is spent - #9718

Open
nepet wants to merge 1 commit into
ElementsProject:masterfrom
nepet:bcli-getutxout-retry
Open

nepet wants to merge 1 commit into
ElementsProject:masterfrom
nepet:bcli-getutxout-retry

Conversation

@nepet

@nepet nepet commented Nov 8, 2026 •

Copy link
Copy Markdown
Member

Checklist

Before submitting the PR, ensure the following tasks are completed. If an item is not applicable to your PR, please mark it as checked:

  • The changelog has been updated in the relevant commit(s) according to the guidelines.
  • Tests have been added or modified to reflect the changes.
  • Documentation has been reviewed and updated as needed.
  • Related issues have been listed and linked, including any that this PR closes.
  • Important All PRs must consider how to reverse any persistent changes for tools/lightning-downgrade

Fixes #9714.

getutxout answered {"amount": null, "script": null} both when bitcoind says the output is spent or unknown (gettxout exits 0 with no output) and when the bitcoin-cli gettxout call fails, e.g. because bitcoind is unreachable or still starting up. lightningd takes a null answer as "spent", and some callers act on it: gossip leaves the output out of the filtered block it stores, so the channel announcement stays rejected, and fundchannel_cancel forgets a channel whose funding tx another wallet has broadcast.

This retries a failed gettxout every second until bitcoin-retry-timeout, as getrawblockbyheight already does for getblock, and then returns an error. Only an exit 0 with no output still answers null.

After the timeout lightningd still aborts on that error, as it does on any bcli error (#9573). #9574 would let lightningd ride out transient backend errors, starting with getchaininfo. getutxout's callers could follow. Until then this never turns a failed call into a wrong "spent". Like the getblock retry, the loop holds up bcli's other calls while it runs, which only happens while bitcoind is failing anyway.

The tests make the bitcoind proxy fail gettxout twice and then answer: getutxout returns the real output, and fundchannel_cancel refuses to forget a channel whose funding tx bitcoind broadcast. With gettxout failing for good, getutxout fails after bitcoin-retry-timeout. Both tests fail on master.

… spent

getutxout answered {"amount": null, "script": null} both when bitcoind
said the output is spent or unknown (exit 0, no output) and when the
bitcoin-cli gettxout call failed, e.g. because bitcoind was unreachable
or still starting up. lightningd can't tell the two apart, and acts on a
"spent": gossip leaves the output out of the filtered block it stores,
so the channel announcement stays rejected, and fundchannel_cancel
forgets a channel whose funding tx another wallet has broadcast.

Retry a failed call every second until bitcoin-retry-timeout, as
getrawblockbyheight does for getblock, and then fail. lightningd still
aborts on that error, as it does for every bcli error, but it no longer
acts on a wrong "spent".

Fixes: ElementsProject#9714
Changelog-Fixed: bcli: `getutxout` retries a failed `gettxout` (e.g. while bitcoind starts up) until `bitcoin-retry-timeout`, instead of reporting the output as spent.

This branch has not been deployed

No deployments
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.

bcli: a failed gettxout reads as "spent", and gossip and fundchannel_cancel act on it

1 participant