Skip to content

Add non-paying circular route quotes constrained to exact local channels - #1220

Open
hudhaifahz wants to merge 3 commits into
lightningdevkit:mainfrom
hudhaifahz:codex/upstream-exact-channel-rebalance
Open

hudhaifahz wants to merge 3 commits into
lightningdevkit:mainfrom
hudhaifahz:codex/upstream-exact-channel-rebalance

Conversation

@hudhaifahz

@hudhaifahz hudhaifahz commented Nov 6, 2026 •

Copy link
Copy Markdown

Applications planning a channel rebalance need to choose the outgoing and returning channels, including when several channels connect to the same peer. This adds Bolt11Payment::quote_circular_route and Rust/UniFFI quote records exposing the estimated paths and fees for that exact pair. Quoting creates no invoice, probe, HTLC, or payment-store entry.

Approach

The router receives only the selected outgoing channel as a first hop and a route hint for the selected incoming channel. Since ordinary LDK pathfinding rejects payer == payee, the search targets a fresh synthetic recipient behind the incoming peer. Before returning a quote, every path is checked against both endpoint channel IDs and peer identities; only the terminal synthetic identity is then replaced with the local node. Synthetic payment parameters are discarded.

Routing configuration is applied through upstream's shared apply_route_parameters_config helper. The search uses the local node's BOLT11 feature support, current in-flight HTLCs, channel capacities, incoming forwarding policy, and routing configuration. This permits multipart estimates while keeping the same selected first and last channel on every path. An unset fee cap preserves LDK's default; an explicit zero cap stays zero. Ambiguous user channel IDs are rejected. A quote is an estimate, not a liquidity reservation or a guarantee of payment success.

Scope and provenance

This extracts the route-quotation work from getAlby/ldk-node#115, source commit 70965f2e58936c0893c48ee0cc1788b84164a4e2, and adapts it to upstream main 4a8fb7f39d0fe75e9ad863ec038a9571f464587d.

There are no payment-storage changes, new dependencies, swaps, UI changes, or automatic rebalancing in this PR. It does not enable circular sending. The older fork's durable preparation, exact receiving-channel enforcement, and restart recovery are deferred for a separate design review. Opaque serialized routes are deliberately absent from the public quote API so this PR does not establish an execution or durable serialization contract.

Validation

  • Six new routing tests cover real LDK pathfinding with parallel channels, private aliases, multipart paths, explicit fee limits, invalid/ambiguous selections, and endpoint mismatch rejection. ChannelManager serialization is unchanged by a successful quote in the functional test.
  • The existing unstarted-node API regression test now covers quotation.
  • cargo +1.91.1 test --lib: 393 passed (with CI cycle-test configuration).
  • cargo +1.91.1 test --no-default-features --features uniffi-default --lib: 392 passed.
  • Both force-close variants passed on each of Bitcoin Core RPC, Bitcoin Core REST, Electrum, and Esplora (8 integration cases, CI cycle-test configuration).
  • Stable formatting check and the repository's production Clippy policy passed in both configurations.
  • Documentation built with RUSTDOCFLAGS=-D warnings on the original contribution.
  • CodeRabbit CLI reviewed the updated six-file diff and reported zero findings.

Checks ran on macOS ARM64. Formatting used the repository-pinned nightly-2026-09-22.

The new pathfinding tests use LDK's in-process functional network. They do not send real payments. The full cross-platform CI matrix is also exercised by upstream CI.

CI repair after updating from main

The import conflict is resolved against current upstream, reusing its routing-configuration helper. The original macOS beta failure was in the existing force-close settlement helper, which immediately rejected the valid intermediate PendingBroadcast state. The quote API is not called by that test. The helper now uses the existing bounded polling utility to wait for sweep generation, then observes the exact spending transaction in the backend before mining its confirmation. Terminal balance assertions remain unchanged. No production force-close or wallet behavior is changed.

The original failure was intermittent: an isolated current-main run passed. The diagnosis follows the failed CI location, the pending-sweep enum variants, and the asynchronous event/broadcast ordering; it does not claim a deterministic local reproduction.

CI status after repair

At 2026-11-12 22:30:29 UTC on head c7c35bd1db2a6486f9621e50ee9712d50312f6e0:

  • Ten complete workflows passed, including Kotlin, Swift, Python, SemVer, and all GitHub-hosted integration workflows.
  • All six GitHub-hosted Rust jobs passed. Each macOS toolchain (stable, beta, and Rust 1.85.0) passed 393 library tests and all 97 Rust integration tests, including both force-close variants. The previously failing beta job is green.
  • Full CI is pending, not yet green: seven Rust-workflow jobs plus 0FC, HRN, and benchmarks remain queued for upstream self-hosted runners. The same checks are also queued on upstream main and other PRs. No started job failed. No CI requirements were disabled or bypassed.

Review focus

Is Bolt11Payment the preferred location for this quote-only API, and is the synthetic-destination route-hint approach acceptable as an initial circular-routing primitive? The intent is to contribute this functionality to shared upstream ownership before proposing the larger payment lifecycle.

AI disclosure: implementation, adaptation, tests, and this description were prepared with OpenAI Codex. CodeRabbit CLI was used for automated review; its findings are assessed rather than treated as a security audit.

Extract non-paying route quotation from getAlby#115 and adapt
it to current upstream. Pin both local endpoints, preserve fee limits,
and expose estimates through Rust and UniFFI without payment-store or
execution changes. Test parallel channels, aliases, and multipart routes.

AI disclosure: prepared with OpenAI Codex; CodeRabbit CLI assisted review.
@ldk-reviews-bot

ldk-reviews-bot commented Nov 6, 2026 •

Copy link
Copy Markdown

I've assigned @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@hudhaifahz
hudhaifahz marked this pull request as ready for review November 6, 2026 05:38
@ldk-reviews-bot
ldk-reviews-bot requested a review from tnull November 6, 2026 05:48
Resolve the payment-module import conflict against upstream 4a8fb7f.
Use upstream apply_route_parameters_config for circular quotes instead
of retaining a separate fee/config implementation.

AI disclosure: prepared and validated with OpenAI Codex.
SpendableOutputs registration can follow sync_wallets sweep generation,
leaving a valid PendingBroadcast state. Poll with the existing bounded
helper, then observe the exact spending transaction before mining.
Keep the terminal balance and confirmation assertions intact.

AI disclosure: prepared and validated with OpenAI Codex;
CodeRabbit CLI assisted review.
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