feat(cycles): manual-route circular self-payment (superset of PR #3 swaps)#5
Open
tonible14012002 wants to merge 10 commits into
Open
feat(cycles): manual-route circular self-payment (superset of PR #3 swaps)#5tonible14012002 wants to merge 10 commits into
tonible14012002 wants to merge 10 commits into
Conversation
The ChannelFunding confirmation target resolved to a 12-block fee tier, which during normal mempool congestion maps to a rate low enough that funding transactions can sit unconfirmed for hours. The channel never reaches channel_ready and the UI is stuck on `sync`. Lower the target to ~3 blocks (mempool's "fast" tier) so funding txs are mined promptly. The fee is still sourced from the chain source's recommended estimates (esplora get_fee_estimates / electrum estimatefee / bitcoind estimatesmartfee) — only the targeted confirmation window changes, and only for funding transactions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…yte order getrawtransaction wants the txid in RPC/display (big-endian) order (Txid Display), but serialize_hex(txid) emits internal little-endian (reversed) bytes → bitcoind returns -5, mapped to Ok(None)=NotFound. The native swap watcher therefore never saw a confirmed opening tx on the bitcoind backend, so the CSV/confirmation ladder never armed and swaps wedged at AWAIT_CONFIRM/AWAIT_CLAIM_PAYMENT. Fix: pass txid.to_string() (display order). Proven on regtest (display txid=10 confs, reversed=-5). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…swaps` feature Add the on-chain building blocks the native PeerSwap engine (modules/ldk-node in the consumer) needs, all gated behind a new `swaps` cargo feature so the default build is byte-for-byte unaffected: - B1–B3 funding: create_swap_funding_tx (P2WSH HTLC opening, signed, not broadcast), swap_list_confirmed_utxos, swap_sign_psbt (wallet/mod.rs). - B4 broadcast: broadcast_swap_tx over the bounded broadcast queue (tx_broadcaster.rs). - B5 reorg-aware per-txid confirmation tracking: watch_txid + get_tx_confirmations → TxStatus/ChainStatus + derive_tx_status, with a swap_query_tx backed by whichever chain source is configured (Esplora/Electrum/Bitcoind) and FAIL-CLOSED (NoChainSource) when it cannot answer (chain/mod.rs, chain/electrum.rs). - B6 feerate: estimate_onchain_feerate → source-bearing FeerateQuote so callers can refuse a stale/fallback estimate (fee_estimator.rs). - B7 discovery: swap-capability custom gossip plumbing (custom_gossip.rs). - Builder wiring (builder.rs), public surface (lib.rs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…feature Adds the cooperative cycle-balance primitive: `Node::send_along_route(route, amount_msat, payment_hash, preimage)` sends a spontaneous payment along a caller-supplied route back to self, recorded as `PaymentKind::Rebalance` (TLV type 12, ungated for record compatibility). The `PaymentClaimable` handler scopes the circular-payment and spontaneous-duplicate guards to exclude Rebalance records and claims the looped HTLC inline with the locally-held preimage, marking the single outbound record Succeeded — settlement is observed by polling the payment store, no user-facing event is emitted. Only the `Node` method is gated behind the new `cycles` feature; the default build is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…aim amount send_along_route sent the final onion with RecipientOnionFields:: spontaneous_empty() and no keysend TLV, so lightning's final-hop parser (create_recv_pending_htlc_info) failed every looped HTLC with "We require payment_secrets" BEFORE PaymentClaimable could fire — the patched claim path was unreachable and no cycle could ever settle (fail-safe, but feature-dead). Fix: register the hash with the ChannelManager's STATELESS inbound-payment verifier (create_inbound_payment_for_hash, min_value_msat = amount) and send secret_only(payment_secret). No payment-store record is created, so the scoped circular guard still sees only the single Outbound Rebalance record; the secret never leaves the onion we build, so nobody else can construct a claimable HTLC for the hash. event.rs: belt-and-braces amount pin in the Rebalance claim — never claim_funds (= reveal the preimage) for less than the recorded loop amount; fail the HTLC backwards instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on PR #3 (native PeerSwap
swapsprimitives B1–B7 + bitcoind txid byte-order fix) and adds thecyclesfeature: the manual-route circular self-payment primitive required by the cooperative cycle-balance engine.Same base branch as PR #3 (
custom-gossip-data), so this PR contains all of PR #3's changes plus the two cycle commits — it is a superset and can supersede PR #3.New commits on top of PR #3
f16ef0bfeat(cycles): manual-route circular self-payment behind thecyclesfeature630e5e1fix(cycles): make the rebalance loop actually receivable + pin the claim amountWhat the
cyclesfeature adds (all#[cfg(feature = "cycles")], default OFF)Node::send_along_route(route, amount_msat, payment_hash, preimage)(src/lib.rs) — sends a Lightning payment along a caller-suppliedRoute(no pathfinding, no route hints) and registers the hash with the stateless inbound-payment verifier (create_inbound_payment_for_hash,min_value = amount) so the looped HTLC is receivable at the final hop without creating an inbound payment-store record (LDK's circular-payment guard still sees only the single Outbound record).PaymentKind::Rebalance { hash, preimage }(src/payment/store.rs) — a new TLV enum variant at type12, additive and forward/backward-compatible. Ungated so the serialization stays stable; only ever written bysend_along_route.PaymentClaimablefall-through + inline self-claim (src/event.rs) — the circular-payment and duplicate/spontaneous refusals gain&& !info.is_rebalance(), and a Rebalance loop is claimed immediately with the record-carried preimage (belt-and-braces amount pin: never reveal the preimage for less than the recorded loop amount).Compatibility
lightning-crate version bump —ChannelMonitor/KVStore/ wallet persistence format unchanged.swapsandcyclesare empty Cargo features, default OFF → the stock build is byte-for-byte unaffected.The preimage is generated natively, held only in the fork's payment record, and never crosses FFI, is never logged, and never appears in any payload. No BOLT11 invoice is minted.