Skip to content

Force-close can't confirm while the LSP is offline: hardcoded trusted_peers_no_reserve leaves no CPFP path — make anchor trust configurable #95

Description

@hash-money

Scenario

Downstream integrator (graduated-custody mobile wallet, sweep-everything Model A à la Phoenix). Product flow: an emergency unilateral exit while the LSP is unreachable. close_channels correctly branches to force_close_channel for the unusable channel — but the close can never confirm, so the funds sit in the commitment's to_local (not seed-recoverable) until the LSP returns.

On-device observation (Mutinynet, 2026-07-11)

  • Force-close initiated with the LSP down. The holder commitment was handed to the broadcaster and rebroadcast every ~30 s indefinitely — broadcast itself is fine.
  • It never entered the mempool: legacy-anchor commitments are built at the LDK fee floor (FEERATE_FLOOR_SATS_PER_KW = 253 ≈ 1.01 sat/vB), by design assuming a CPFP bump at close time.
  • The bump never comes (mechanism below), and nothing external can help: the local anchor is keyed (get_keyed_anchor_redeemscript), and the anyone-can-spend branch needs the commitment already confirmed 16 blocks — exactly what we can't get.

Mechanism (at a283d74)

orange-sdk/src/lightning_wallet.rs#L66-L69 unconditionally puts the LSP in AnchorChannelsConfig::trusted_peers_no_reserve. ldk-node's documented semantics for trusted peers: "we won't take any action to get the required channel closing transactions confirmed ourselves … potentially insecure as the channel may not be closed if they refuse to do so" — and its event handler skips the bump exactly there ("Ignoring BumpTransactionEvent::ChannelClose … due to trusted counterparty", event.rs).

Neither Tunables nor WalletConfig (nor the FFI surface) exposes any anchor/trust/reserve field, so an integrator cannot change this without carrying a fork.

Ask

Make the LSP's anchor trust configurable — e.g. a Tunables field (lsp_trusted_no_reserve: bool, default true, preserving current behavior) plumbed into the AnchorChannelsConfig. Happy to send this PR if you'd take it; we can validate the untrusted path end-to-end on our Mutinynet staging stack (scripted LSP-down harness, both ends instrumented).

The tradeoff, stated honestly

De-trusting the LSP re-introduces ldk-node's per-channel anchor reserve (25k sat default) — in real tension with a sweep-everything wallet whose on-chain balance is ~0 at steady state (without a reserve, CPFP coin selection finds no confirmed UTXO and aborts anyway). So this knob is the first-order fix that makes unilateral exit possible for integrators willing to hold a reserve; the reserve-free design (zero-fee-commitment channels + keyless P2A bump) is gated in ldk-node, and we're filing those exposure asks there separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions