Sync main with upstream lightningdevkit/ldk-node (86 commits)#4
Open
tonible14012002 wants to merge 86 commits into
Open
Sync main with upstream lightningdevkit/ldk-node (86 commits)#4tonible14012002 wants to merge 86 commits into
tonible14012002 wants to merge 86 commits into
Conversation
Validate splice-out requests against outbound capacity after converting the requested satoshi amount to millisatoshis with overflow handling. This prevents values above the spendable channel balance from slipping past the guard due to a unit mismatch. Keep splice integration coverage aligned with the corrected capacity semantics by rejecting an amount one satoshi above outbound capacity and deriving the full-cycle splice-out amount from the channel's current spendable capacity. AI-Assisted-By: OpenAI Codex Co-Authored-By: HAL 9000 This finding was discovered by Project Loupe
A cancellable task spawned during shutdown could otherwise outlive the shutdown sequence instead of being cancelled with the rest of the cancellable runtime work. Reject late spawns while shutdown is draining tasks and reopen that path when a stopped node starts again. Co-Authored-By: HAL 9000 This finding was discovered by Project Loupe
Replace per-protocol single-LSP configuration `LSPS1Client` and `LSPS2Client` with a unified `Vec<LspNode>` model where users configure LSP nodes via `add_liquidity_source()` at build time or runtime and per-LSP protocol support is discovered via the LSPS0 `list_protocols`. - Introduce a per-LSP `trust_peer_0conf` flag to `LspConfig`/`LspNode` structs that controls whether 0-conf channels from that LSP are accepted - Add LSPS0 protocol discovery `discover_lsp_protocols` with event handling for `ListProtocolsResponse` - Update events to also use each LSP's `trust_peer_0conf` flag when deciding whether to allow 0-conf channels - Replace `set_liquidity_source_lsps1` and `set_liquidity_source_lsps2` builder methods with a single `add_liquidity_source()` that takes a `trust_peer_0conf` flag - Rename `set_liquidity_provider_lsps2` to `enable_liquidity_provider` - LSPS2 JIT channels now query all LSPS2-capable LSPs and automatically select the cheapest fee offer across all of them - Spawn background discovery task on `Node::start()` and expose a watch channel so dependent flows can wait for discovery to complete - Add a new `Liquidity` handler `Node::liquidity()` exposing `add_liquidity_source()` API for adding LSPs at runtime, and `lsps1()` for the existing LSPS1 surface
Remove the `Ignoring` variant now that the liquidity source is always built, so the enum and its match arms are now pure overhead. Replace it with a struct that holds the `LiquiditySource` directly and have each trait method delegate straight to `liquidity_manager()`.
…cellable-shutdown Prevent late cancellable runtime tasks during shutdown
…out-capacity-units Reject oversized splice-out amounts
Clarify that public APIs remain unstable before 1.0 while persisted node state is intended to remain readable by newer releases. Co-Authored-By: HAL 9000
Add a downgrade canary that writes current node state through the legacy v1 filesystem store and reopens it with ldk-node v0.7.0. This monitors whether serialized node, channel, and payment state remains usable by v0.7.0, including a restored channel and a post-restart payment. This does not assert that the current filesystem-store v2 IO layout can downgrade to v0.7.0's v1 layout. That IO-layer downgrade is unsupported: v2 stores empty namespaces under [empty], which v1 readers do not look up. Co-Authored-By: HAL 9000
…antees-downgrade-070 Document compat. guarantees, monitor serialization compat
Refactor liquidity source to support multiple LSP nodes
Electrum transaction sync now reuses the client already shared by BDK and direct Electrum calls. This avoids opening a second Electrum connection and completes the reuse intended by lightningdevkit#488. Co-Authored-By: HAL 9000
…ctrum-client-reuse Reuse Electrum client for transaction sync
Switches vss-client-ng to the crates.io 0.6 release. Generated with OpenAI Codex.
Move repeated VssStore construction logic into a shared build_vss_store() helper and have existing tests use it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the single-page VSS listing logic into a list_keys method that accepts page_token and page_size parameters. list_internal now drives the pagination loop itself, calling list_keys per page. This prepares for PaginatedKVStore support which will reuse list_keys for single-page queries. This also fixes a potential issue where if the VSS server returned None for the page token we could enter into an infinite loop. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Share the common BOLT11 payment send flow between fixed-amount and explicit-amount sends so follow-up API variants can reuse the same payment-store and error handling path. AI-Tool-Disclosure: Created with OpenAI Codex.
Add a BOLT11 payment API for sending less than the invoice amount while using the invoice amount as the declared total MPP value. Cover the path with an integration test where two nodes each pay half of one invoice and the receiver claims the full amount. AI-Tool-Disclosure: Created with OpenAI Codex.
Return InvalidAmount when converting the requested satoshi amount to millisatoshis would overflow. This keeps debug and release behavior consistent and avoids producing a URI whose on-chain amount differs from its Lightning payment amount. This commit was created with assistance from OpenAI Codex. This finding was discovered by Project Loupe
Use saturating arithmetic when accounting for skimmed JIT-channel fees while validating manually claimed payments. This prevents an oversized skimmed fee from underflowing the expected claimable amount. This commit was created with assistance from OpenAI Codex. This finding was discovered by Project Loupe
Track registered transaction IDs in a set so repeated filter registrations do not grow the collection or slow block-connected checks. This keeps the wallet's registered-transaction lookup bounded by unique transaction IDs. This commit was created with assistance from OpenAI Codex. This finding was discovered by Project Loupe
Fix trivial underflow/overflow issues
Keep pending payment namespace constants next to the primary payment store constants. This keeps related persistence keys discoverable together. Co-Authored-By: HAL 9000
Stop exporting the pending payment index record from the public payment module. The pending index is an internal persistence detail and should not become public API before this ships. Co-Authored-By: HAL 9000
RBF can spend fee increases from the original transaction's change output. Check the replacement fee increase against the current anchor-channel reserve before signing. This prevents high manual fee rates from consuming funds reserved for anchor spends. This finding was discovered by Project Loupe. Co-Authored-By: HAL 9000
…nsert-or-update Persist datastore changes before caching
DataStore persistence failure tests use FailingStore through DynStoreWrapper. That wrapper now requires paginated store support, so make the helper fail paginated listings the same way it fails the other store calls. Co-Authored-By: HAL 9000
…re-rebase-conflict Fix DataStore failing store pagination
This was unimplemented for the sqlite kv store. Useful if the user wants to migrate to a different database and also in tests so we don't have to re-init and setup a node. AI-assisted-by: OpenAI Codex
This was unimplemented for the postgres kv store. Useful if the user wants to migrate to a different database and also in tests so we don't have to re-init and setup a node. AI-assisted-by: OpenAI Codex
Extract the existing obfuscated key selection so later VSS listing changes can reuse it without changing the parsing behavior. AI-assisted-by: OpenAI Codex
This was unimplemented for the VSS kv store. Useful if the user wants to migrate to a different database and keeps VSS aligned with the other persistent stores. AI-assisted-by: OpenAI Codex
This was unimplemented for the in-memory kv store. Useful in tests so we can migrate data across all supported store implementations. AI-assisted-by: OpenAI Codex
…ment-store-followups Bump BDK, address pending payment store follow ups
On-chain payment records don't capture what a transaction was for -- a channel open, splice, close, sweep, or a plain send. Record that classification on each on-chain payment, derived from the type LDK reports when broadcasting the transaction, so it survives restarts alongside the payment. The tag keeps only which channels a transaction relates to; amounts and fees stay on the payment. Existing records keep decoding unchanged. Compatible with the on-chain transaction classification proposed in lightningdevkit#791. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record channel-open and splice funding transactions as on-chain payments at broadcast, and carry them to Succeeded through ANTI_REORG_DELAY confirmations like any other on-chain payment, instead of tying their status to the Lightning channel lifecycle. A splice's recorded amount and fee are this node's share of the funding contribution, which wallet sync preserves rather than overwriting with its own view of the (possibly multi-party) transaction. On-chain RBF of these payments is rejected: LDK drives funding and splice transactions, so replacing one would broadcast a transaction it isn't tracking and, for a splice, can't re-sign. Addresses review feedback to keep on-chain payment status confirmation- driven rather than gated on ChannelReady. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`create_payment_from_tx` duplicated the amount/fee/direction derivation that `onchain_payment_fields` already performs. Share it via a helper that operates on the already-locked wallet, so both paths agree by construction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A splice's funding transaction can be stuck at too low a fee rate with no way to raise it: on-chain RBF is rejected for funding transactions, and re-issuing splice_in / splice_out errors while a splice is already pending. Add bump_channel_funding_fee, which replaces the pending splice's funding transaction at a higher fee rate while preserving its amount and destination, and point the "a prior splice contribution is pending" errors at it. Replacing the transaction also requires signing a funding input the wallet already treats as spent by the splice being replaced, which it would otherwise skip after syncing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover the wallet-event-driven funding payment lifecycle end to end: a channel-open funding payment reaches Succeeded from wallet sync alone, asserted before any ChannelReady event is drained to show payment status no longer depends on the channel-ready signal; and a splice fee-bumped via RBF stays a single on-chain payment that follows the winning candidate while keeping its interactive-funding classification across the replacement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A splice funding payment can be fee-bumped via RBF, producing several candidate transactions with increasing fees. The payment recorded the last-broadcast candidate's amount and fee and kept them on confirmation, but the candidate that actually confirms need not be the last one broadcast — so an earlier, lower-fee candidate confirming left the payment over-reporting its fee. Record each candidate's amount and fee, keyed by txid, so that on confirmation the payment reflects the candidate that actually confirmed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
splice_channel only checked the splice-out fee; also assert it is recorded as a confirmed interactive-funding payment. Add a test that a confirmed splice payment returns to unconfirmed when its block is reorged out, exercising the unconfirm path for funding payments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributing to an already-pending splice — e.g. adding our funds to a counterparty-initiated splice via splice_in or splice_out — replaces the in-flight funding transaction, so the funding template requires at least the RBF minimum feerate. We passed our plain ChannelFunding feerate estimate, which can sit below that minimum (it does at the regtest floor), so the contribution was rejected with FeeRateBelowRbfMinimum. Raise the contribution feerate to the template's RBF minimum when one applies, capped by our max, so it can replace the pending splice. A node can therefore now contribute to a counterparty's pending splice; the rbf_splice_channel check that expected splice_out to fail while a splice was pending relied on this very bug and is dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 1.5x-of-estimate funding feerate ceiling was open-coded identically in splice_in and splice_out. Route both through a max_funding_feerate helper and keep it, alongside rbf_splice_feerates, in fee_estimator.rs so the splice funding-feerate policy lives in one place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In a splice, both channel parties broadcast the funding transaction, and the tests drive a single shared bitcoind, so the counterparty's broadcast can surface it to this node's wallet sync before this node's own funding classification has run. Under parallel test execution that classification can lag far enough behind for the sync to record the transaction as a plain on-chain payment, failing the funding-payment assertions. Wait for the funding broadcast to be classified before each affected splice test syncs its wallets. This is test-only: on a real node the classification runs locally, well ahead of a counterparty's broadcast arriving over the network, so the race does not occur. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Creates a node with LN and on-chain state and then randomly migrates through all the KV store options and checks it still has its state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ayment-using-tx-type Add splice RBF support
Add 60 minute timeout to CI jobs
Implement `MigratableKVStore` for all KV Stores
When a fresh node's bitcoind RPC/REST chain source fails to return the current chain tip, we previously silently fell back to the genesis block as the wallet birthday. The next successful startup would then force a full-history rescan of the whole chain. Instead, return a new BuildError::ChainTipFetchFailed on the first build so the misconfiguration surfaces immediately and no stale fresh state is persisted. Restarts with a previously-persisted wallet are unaffected: a transient chain source outage on an existing node still allows startup to proceed. Esplora/Electrum backends currently never expose a tip at build time so the guard only fires for bitcoind sources; the latent wallet-birthday-at-genesis issue on those backends is left for a follow-up. Co-Authored-By: HAL 9000
Allow Bitcoin Core RPC and REST chain-source configuration to specify the wallet birthday height used when creating a fresh wallet. This lets restored wallets rescan from a known height, including genesis, without overloading a global recovery toggle. Reject requested heights above the current chain tip with an explicit build error before wallet state is created. Existing wallets are not rewound by this option because a safe rewind must invalidate persisted wallet and LDK state before replaying blocks. Co-Authored-By: HAL 9000
Let Esplora and Electrum sync configs request BDK full scans until one succeeds. This keeps recovery scans retryable after transient sync failures while preserving normal incremental syncs once recovery has completed. Co-Authored-By: HAL 9000
…rst-startup-tip-fetch-failure Allow wallet imports from arbitrary heights, forcing full scans
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.
What
Fast-forwards `lamtuanvu/ldk-node:main` to the current upstream `lightningdevkit/ldk-node:main` (`f2e44fd`).
This is a clean fast-forward — `lamtuanvu/main` (`a2c34cb`) is a strict ancestor of upstream HEAD and carries no proprietary commits, so there are zero conflicts to resolve.
Why
The fork's `main` had drifted 86 commits behind upstream. Bringing it current is a prerequisite for cleanly rebasing feature branches (e.g. the `swaps` work) onto a modern base instead of the ~1-year-old July 2025 fork point.
What's included (upstream batch, newest first)
MigratableKVStorefor all KV Stores lightningdevkit/ldk-node#945)KVStorepersistence lightningdevkit/ldk-node#919) — removes blocking KV store support, BDK async wallet persister, shared store runtime wrapper86 commits total,
a2c34cb..f2e44fd.Verification