Repository navigation
Cut v0.7.1 release - #1158
Merged
tnull merged 29 commits intoOct 12, 2026
Merged
Cut v0.7.1 release#1158
Conversation
Previously, seed files were created using `fs::File::create()` which inherits the default umask, potentially making the sensitive seed material world-readable on Unix systems. This change: - Creates seed files with mode 0o400 (owner read only) on Unix - Uses `create_new` instead of `create` to atomically fail if the file already exists, providing defense-in-depth against TOCTOU race conditions Co-Authored-By: Claude AI Backport of e93844a Conflicts Resolved in src/io/utils.rs
Move the GC pass from after insertion to before, so that stale entries are reclaimed before allocating a new bucket. This avoids unnecessary growth of the user map between GC cycles. AI tools were used in preparing this commit. Backport of 818cccd
Previously, we'd attempt to decode any hex string even if it had an odd number of input characters. Here, we check the length and return `None` in case it's odd. Signed-off-by: Elias Rohrer <dev@tnull.de> Backport of 8189984
The check that an LSP didn't withhold more than the agreed-upon JIT channel fee only ran for inbound payments we already had a record for. BOLT12 offer and spontaneous payments only get their record created inside the claim handler, so they skipped the check entirely and were claimed no matter how much the counterparty skimmed. Refuse any withheld fee for payments without a stored record, as we never authorized a skim for them. This matches the behavior on main, where the check moved to the authenticated BOLT11 payment metadata. Only this part of the upstream change is backported. Backport of 44146f9 Conflicts Resolved in src/event.rs Co-Authored-By: HAL 9000
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 Backport of ca4d4c3
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 Backport of 9ab2106 Conflicts Resolved in src/payment/unified_qr.rs, tests/integration_tests_rust.rs
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 Backport of 187056b
Build the updated object separately and persist it before replacing the cached entry, so failed writes leave memory aligned with storage. This finding was discovered by Project Loupe AI-Assisted-By: OpenAI Codex Backport of 6560dff Conflicts Resolved in src/data_store.rs
Apply updates to a cloned object and only replace the cached entry after the backing store write succeeds. This finding was discovered by Project Loupe AI-Assisted-By: OpenAI Codex Backport of e3793b8 Conflicts Resolved in src/data_store.rs
Check for the object first, remove it from the backing store, and only then delete it from the in-memory map. This finding was discovered by Project Loupe AI-Assisted-By: OpenAI Codex Backport of 531d52d Conflicts Resolved in src/data_store.rs
We stop requiring that splice-ins leave an anchor reserve for an additional anchor channel on top of the existing set of anchor channels; after splice-ins, our anchor reserve only needs to cover the existing set of anchor channels. Backport of 4c8ecb2 Conflicts Resolved in src/lib.rs
When we are preparing to open a channel to a peer, we should reserve onchain funds for an anchor channel when the peer's init features signals anchor channels as optional, as channel negotiation with such a peer can result in an anchor channel. Tests written with codex. Backport of 2c2c287 Conflicts Resolved in src/lib.rs, src/liquidity.rs, tests/integration_tests_rust.rs
Backport of 0757faa Conflicts Resolved in src/chain/bitcoind.rs
Bitcoin Core's REST headers endpoint cannot serve headers from a stale branch. This prevented REST-backed nodes from finding a common ancestor and following the replacement chain after a reorg. In lightningdevkit#1006 we enabled bitcoind REST chain source support in CI, which exposed this failure. Co-Authored-By: HAL 9000 Backport of 66d48d2 Conflicts Resolved in src/chain/bitcoind.rs, tests/reorg_test.rs
Payment preimages are proof-of-payment and correlation material. The INFO log previously included the full preimage after a successful outbound payment, exposing it to log collectors and anyone with log access. Remove the preimage from the 'Successfully sent payment' log message in src/event.rs, retaining only the payment hash for diagnostics. The preimage remains accessible via the PaymentSuccessful event and payment store APIs. Backport of 8828e52 Conflicts Resolved in src/event.rs
`ElectrumRuntimeStatus::stop` reset itself to `Stopped` with empty pending registration vectors, dropping the `ElectrumRuntimeClient` and, with it, the `ElectrumSyncClient` that owns the registered transactions and outputs. `start` then drained the pending vectors, so nothing survived even a single cycle. As `ChannelMonitor`s only register their watched transactions and outputs while being loaded in `Builder::build`, a `stop`/`start` cycle that doesn't rebuild the node left the chain source with no registrations at all, i.e., the node would no longer learn about confirmations or spends of, e.g., its funding outputs. Note we can't simply re-register from `ChannelMonitor::load_outputs_to_watch` on `start` either, as, e.g., the `OutputSweeper` also registers outputs it wants to see spent. Here we therefore keep a canonical, deduplicated registration inventory in `ElectrumRuntimeStatus` that is maintained whether we're started or not: `register_tx`/`register_output` always record the entry and additionally forward it to the client if one is live, `start` replays the inventory to the fresh client without consuming it, and `stop` merely drops the client. This also restores parity with the Esplora chain source, whose `tx_sync` is long-lived and hence never loses its registrations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Backport of af634d3 Conflicts Resolved in src/chain/electrum.rs
Only a missing ChannelManager should create a fresh node. Propagate other storage errors so transient failures cannot replace live channel state with an empty manager. Fixes lightningdevkit#1026 Co-Authored-By: HAL 9000 Backport of 03dafa9 Conflicts Resolved in src/builder.rs
Mempool reconciliation checks every cached transaction against the raw mempool response. Using a Vec to store the raw mempool txids makes each membership check linear and the retention pass quadratic. Store the txids in a HashSet to make membership checks expected constant time and reconciliation expected linear. Co-Authored-By: HAL 9000 Backport of 8c632e5 Conflicts Resolved in src/chain/bitcoind.rs
…ayments UnifiedPayment::send previously treated any error from the BOLT11 leg of a unified payment as non-terminal and fell through to the on-chain payment method. This meant a retried BOLT11 payment that returns Error::DuplicatePayment would still result in an on-chain transaction being broadcast for the same invoice — a duplicate payment. Error::DuplicatePayment is now terminal in UnifiedPayment::send: the unified payment aborts instead of falling back to on-chain. Fixes lightningdevkit#1033. unified_send_receive_bip21_uri already funds two nodes, opens a channel, and sends a successful BOLT11 payment via uri_str_without_offer partway through. Add the regression assertion right there — retry the same uri_str_without_offer and assert DuplicatePayment, not a new on-chain payment — instead of duplicating that setup in a standalone test. Backport of 9c271d7 Conflicts Resolved in src/payment/unified_qr.rs, tests/integration_tests_rust.rs
In UnifiedPayment::send, the BOLT11 leg's bolt11_invoice.send only returns Err(PersistenceFailed) *after* pay_for_bolt11_invoice has already succeeded and the Lightning payment is in-flight. The previous match treated every remaining error as a fall-through to the next payment method, so a persistence failure after initiation would broadcast an on-chain transaction for the same URI — a duplicate payment. Err(Error::PersistenceFailed) on the BOLT11 leg is now terminal, mirroring how DuplicatePayment is handled, and aborts the unified payment instead of falling back to on-chain. This is a regression hazard raised during review of the DuplicatePayment fix (PR lightningdevkit#1038). It is pre-existing and orthogonal to lightningdevkit#1033; tracked here as the unified variant of the broader post-commit persistence hazard. Per review discussion: rather than a dedicated node/channel fixture, build unified_send_receive_bip21_uri's node_a on a PaymentFailingStore (inert until armed) from the start, and add a PersistenceFailed assertion at the end of that test using a fresh BOLT11-only URI. This reuses the funding/channel/announcement setup and the successful-send flow the test already has, rather than duplicating it. Adds PaymentFailingStore (a KVStore wrapper that fails writes to the payments namespace on demand) and setup_two_nodes_with_failing_store_a (mirrors setup_two_nodes, but node_a is built on PaymentFailingStore). Backport of d7ee094 Conflicts Resolved in src/payment/unified_qr.rs, tests/common/mod.rs, tests/integration_tests_rust.rs
Estimating the maximum funding amount, the maximum splice-in amount, or a send-all payment builds a temporary drain transaction whose anchor reserve output pays to the wallet's first internal address, then cancels it as though it were a real transaction. A drain transaction never reserves a change address, so the cancel has nothing of its own to undo and instead clears the usage mark on that internal address. If a pending channel funding or splice contribution had reserved the same address for its change, the wallet could hand it out again until the pending transaction is synced, causing address reuse. Fee estimates now leave the wallet untouched, since BDK neither marks an address nor locks an input for a transaction that drains to a fixed script. Co-Authored-By: Claude <noreply@anthropic.com> Backport of 7880030 Conflicts Resolved in src/wallet/mod.rs
…istenceFailed errors The BOLT12 arm used .map_err() + if let Ok, so DuplicatePayment and PersistenceFailed fell through to BOLT11/onchain — risking double payment. Now treats both as terminal, mirroring the BOLT11 fix in lightningdevkit#1038. Fixes: lightningdevkit#1060 AI-assisted: generated by Sera (Hermes Agent), verified manually. Signed-off-by: Bartok9 <259807879+Bartok9@users.noreply.github.com> Backport of 3c98b1c Conflicts Resolved in src/payment/unified_qr.rs
Ignore PaymentFailed when an outbound Lightning payment has already succeeded. Check and update the record atomically, preserving its metadata and suppressing the contradictory failure notification. Continue emitting failure events for unchanged or missing records so replay can recover from event-queue persistence failures. Developed with assistance from OpenAI Codex. Backport of 1bb6aa3 Conflicts Resolved in src/event.rs, src/payment/store.rs
Conservatively include channels whose type is not yet known when calculating the anchor reserve. Otherwise, opening or accepting new channels, or splicing funds into existing channels, can leave too little reserved for channels still being negotiated. Do not count channels with unknown channel types when assessing whether 0FC support is required from the chain source. This part is all user-controlled, and we do not want to require the chain source to support 0FC if startup happens with an in-flight channel open, and no other 0FC chain source support predicates are true. Reported by Project Loupe Backport of 87c3182 Conflicts Resolved in src/lib.rs
If we have sent an outbound payment with a given `payment_hash` and we receive an inbound payment with a matching `payment_hash`, its possible this is an indication of a payment loop, but its also possible its simply a random HTLC with the same hash. We should, thus, not update the outbound payment's status, as it might still be pending and complete. We can detect the payment's failure when the HTLC failure comes back to us as the sender. Backport of c49b86d Conflicts Resolved in src/event.rs
If we have already received a payment and marked it as `PaymentStatus::Succeeded` before receiving a second HTLC with the same `payment_hash`, we should leave the payment at `PaymentStatus::Succeeded` rather than reverting it to failed. Backport of a176d51 Conflicts Resolved in src/event.rs
`ChannelManager::claim_funds` fails if there are any custom even TLVs. While this is documented, its somewhat deadly for swap services - they might release the preimage in response to a `PaymentClaimable` event and assume they can definitely claim the payment, but LDK will refuse to do so. The `lightning` crate really needs to fix this API for the next release, but for now we should avoid having such an obvious API hole in `ldk-node`. Backport of 8dd1c91 Conflicts Resolved in src/event.rs
BOLT11 JIT invoices did not enforce their advertised amount at the recipient. A sender could bypass the LSP's intercept SCID and have a smaller payment accepted over an existing channel. Require the full sender-declared invoice amount for generated and caller-supplied payment hashes. Preserve negotiated LSP fee deductions and cover both invoice paths with an underpayment regression. Fixes lightningdevkit#609 Co-Authored-By: HAL 9000 Backport of b5c731d Conflicts Resolved in src/liquidity.rs, tests/integration_tests_rust.rs
Bump the crate and bindings version numbers to v0.7.1 and add a CHANGELOG section listing the fixes backported for this patch release. Co-Authored-By: HAL 9000
|
👋 Thanks for assigning @joostjager as a reviewer! |
joostjager
approved these changes
Oct 12, 2026
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.
We add a bunch of backports and security hardening fixes and cut v0.7.1 patch release.