Skip to content

Batch JIT channel opens via batch_funding_transaction_generated to lower the minimum economical channel #249

Open

Description

@ConorOkus

Support batched JIT channel funding in the LSPS2 service

Motivation

We're running LDK Server's experimental LSPS2 service (#52) as an LSP backend, with an operator-policy layer on top. bLIP-52 / LSPS2 explicitly anticipates batching multiple JIT channel opens into a single funding transaction, and since on-chain fees dominate the cost of small JIT opens, batching is the main lever for lowering the minimum economical channel size an LSP can offer.

Current behavior

LDK Server / ldk-node funds one channel per transaction: on FundingGenerationReady, a single funding tx is built from the internal wallet and funding_transaction_generated is called. ChannelManager::batch_funding_transaction_generated exists in rust-lightning but is never surfaced, and the event handler isn't pluggable — so batching can't be layered on from outside without a fork.

Interaction with the LSPS2 trust model

The bound on any batching/accumulation window depends on client_trusts_lsp (see also the client-trusts-LSP flow discussion in ldk-node#479), and this shapes the API that would be needed:

  • client_trusts_lsp=true (our deployment): broadcast can be deferred until after clients claim, so the accumulation window is not bounded by settlement latency. However, batch composition freezes at the first preimage release: clients release preimages against zero-conf commitment transactions spending a specific funding outpoint, and rebuilding the batch tx would change the txid and invalidate outpoints that clients have already settled against. Nothing in LSPS2 supports re-negotiating funding with a client who has already given up a preimage. So: broadcast is deferrable, but eviction/rebuild only applies before any member settles.
  • client_trusts_lsp=false (spec default): the funding tx must be broadcast before asking any client to release a preimage, so the window is additionally bounded by the first payment that needs to settle.
  • Mixed batches: a single client_trusts_lsp=false member collapses the whole batch's window back to that member's settlement time, so the policy layer should segregate batches by trust mode.

Upstream API gap: batch_funding_transaction_generated, like its single-channel sibling, hands the tx to ChannelManager for broadcast once counterparty signatures arrive. The client_trusts_lsp=true flow needs a manual-broadcast variant — the batch analogue of unsafe_manual_funding_transaction_generated / FundingTxBroadcastSafe, which the single-channel LSPS2 service path already uses. As far as we can tell no batch equivalent exists, so this is really two pieces of work: surfacing batching in ldk-node / LDK Server, and a batch manual-broadcast API upstream in rust-lightning.

Other constraints we're aware of

  • LDK's batch funding API currently covers V1 opens only (no dual-funded/V2), and a batched V1 funding tx isn't RBF-able. Batch size is therefore a risk/latency knob as much as a fee knob.
  • Non-RBF + deliberately deferred broadcast means the feerate chosen at build time can be stale at broadcast time. The batch tx should always carry an LSP change output so CPFP is available, and a max-deferral deadline should force broadcast before the estimate degrades too far.
  • While broadcast is withheld, the funding inputs must be reserved so the LSP's own wallet can't accidentally double-spend them, and claimed-but-unbroadcast channels should count against the zero-conf exposure limit.

Activity

  1. joostjager commented on Jul 28, 2026

    @joostjager
    Contributor

    I am looking at this through the lens of helping drive adoption in the near term. A few questions I have:

    • What fee savings should an end user realistically expect, relative to the total cost of using the wallet? At current low on-chain feerates, it seems that the absolute saving per channel may be fairly small.
    • What level of user volume is needed to create meaningful batching opportunities? Since several JIT channel opens need to occur within a relatively short accumulation window, I wonder how often an early-stage LSP would produce batches larger than one or two channels.
    • How should we weigh the reliability tradeoffs? A shared funding transaction creates correlated failure risk, since one client aborting or failing can require the other channel opens in the batch to be restarted. Delayed broadcast and the lack of RBF may also make confirmation behavior less predictable.

    I agree that batching may become important at greater scale or during a higher-fee market. I am less certain that it is currently a significant driver of adoption, unless an operator already expects substantial concurrent JIT-channel volume.

  2. f3r10 commented on Jul 30, 2026

    @f3r10
    Contributor

    This is really relevant to a project I've been building (https://github.com/f3r10/lightning-ecommerce, a self-custodial JIT-channel checkout flow on top of LDK/LSPS2) — right now it is not possible to offer small-ticket items because the funding tx fee alone makes a small JIT channel uneconomical for the LSP side. So I'd love to understand this better, and eventually help if that's useful.

    A few things I'm trying to wrap my head around:

    • Looking at ldk-server, LSPS2 seems to be entirely delegated to ldk-node (LSPS2ServiceConfig is just passed through in ldk-server/src/util/config.rs), and the actual FundingGenerationReady handling lives in ldk-node's event.rs / liquidity/service/lsps2.rs. Is the expectation that this work mostly happens upstream in ldk-node (and rust-lightning for the batch broadcast-safe API), with ldk-server only needing to expose new config once that lands? Or is there ldk-server-specific work I'm not seeing?
    • I noticed ldk-node already has a per-channel deferred-broadcast path for client_trusts_lsp=true (funding_transaction_generated_manual_broadcast + a set_funding_tx_broadcast_safe-style call). Would batching for the client_trusts_lsp=false case (broadcast immediately, no new upstream API needed) be a reasonable smaller first step, separate from the harder deferred/batched-broadcast case for client_trusts_lsp=true?
    • For the "batch composition becomes immutable once any member settles" problem — is the idea that the LSP just accumulates FundingGenerationReady events over a fixed window or up to a max batch size before calling batch_funding_transaction_generated, and eats the latency cost for early joiners? Curious if there's already a preferred design here (or prior art from other LSP implementations) before someone goes and builds something that doesn't match what you have in mind.

    Happy to dig further and take a stab at an initial implementation (probably starting with the simpler client_trusts_lsp=false batching path in ldk-node) if that's a direction the maintainers want explored. @ConorOkus @benthecarman

  3. ConorOkus commented on Aug 6, 2026

    @ConorOkus
    Author

    Hi @f3r10, most of this work will happen upstream in ldk-node/rust-lightning. What solution do you feel makes most sense for your project? We have not looked into this in too much detail yet, so we are open to suggestions.

  4. f3r10 commented on Aug 10, 2026

    @f3r10
    Contributor

    Some context on why I care about this: I'm building lightning-ecommerce, a self-custodial payment library so merchants can accept Lightning payments without managing on-chain reserves or channels themselves — LSPS2 JIT channels are the core mechanism, opened on-demand when a customer's payment arrives. The problem is that small-ticket items break this in two separate ways: this issue (funding tx fee makes a small JIT channel uneconomical for the LSP to open at all), and a related one I filed after debugging it directly — ldk-node#913, where even a channel that does get opened can fail to forward the first HTLC because the default 1000-sat channel reserve eats most of the usable capacity on a minimal-size JIT channel. Both point at the same gap: JIT channels aren't really usable yet for small payments.

    For my use case specifically, client_trusts_lsp=false batching seems like the more sensible starting point: batch_funding_transaction_generated already exists and works today for the immediate-broadcast path, so this needs no new upstream primitive — just accumulation logic in ldk-node's event handling to group FundingGenerationReady events into one funding tx before calling it. client_trusts_lsp=true batching would need a new batch-aware manual-broadcast API (there's no batch_..._manual_broadcast equivalent upstream currently), and it couples settlement across customers — one slow-to-claim customer in the batch would stall broadcast, and therefore checkout completion, for everyone else in it. For a merchant checkout flow where speed matters, that coupling is a real cost, not just an implementation nuisance.

    Happy to take a first pass at the accumulation logic for the client_trusts_lsp=false path in ldk-node's event handling, if that's useful @ConorOkus

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    lsp-bossTracked by the lsp-boss LSP workstream

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions