LDK
← All projectsLightning Dev Kit

rust-lightning

Composable Rust libraries for building Lightning wallets, nodes, and services.

BitcoinCryptographic librariesLightning NetworkNormal
Repository coverage

1478 commits in the local evidence base

Every captured commit receives deterministic security triage and a separate communication-quality score. Security candidates and broader second-pass signals receive full-patch Ollama analysis.

225security candidates208second-pass queue366AI analyses
63commits · 30 days
191commits · 60 days
647commits · 180 days
1475commits · 365 days
Backfill bands
Aug 5 → Feb 6819 seen18 candidatesComplete
Feb 6 → Jun 6468 seen16 candidatesComplete
Jun 6 → Jul 6128 seen8 candidatesComplete
Jul 6 → Aug 561 seen3 candidatesComplete
Commit communication

Does the history explain itself?

Message quality measures whether a commit identifies its scope, purpose, rationale, testing, and supporting references. It does not change the security-severity score.

69/100 average clarity
352Strong · 80–100
782Adequate · 60–79
285Thin · 40–59
59Opaque · 0–39
3security candidates with opaque commit messaging
Read the scoring rubric →
Developer activity

Who is changing the project?

Public Git author strings; identities are not independently verified.

DeveloperCommitsCandidatesAnalyzedHigh riskMessage avg.
Elias Rohrer1531532567
Matt Corallo3564779273
Jeffrey Czyz1774155168
Leo Nash1161354162
Valentine Wallace1351016169
Wilmer Paulino1493946069
Joost Jager1622428069
elnosh301318056
shaavan2266069
Carla Kirk-Cohen6533069
benthecarman1834071
Duncan Dean834057
Analysis record

Published AI watches

Last scanned 31 minutes ago

Low 47 AI analysisMessage 85 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Return `Err`s` instead of panicking on oversized messages

This commit changes how the Lightning networking code handles oversized encrypted messages. Previously, certain conditions would cause the program to crash with a panic. Now the code returns errors instead, which is a defensive improvement…

panic-to-error conversion for oversized message encryption/decryptiondenial-of-service hardening against oversized peer messagesdebug_assert retained to preserve test coverage of invariant violations
08f12bc7by Matt Corallo+68−313 files
Vendor flagged security relevance
High 74 AI analysisMessage 78 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Avoid oversized relayed failure messages

This patch fixes a crash bug in the Lightning Dev Kit's handling of HTLC failure messages. A downstream peer could send a maximally-sized failure message without attribution data. When the node added its own attribution data while relaying…

Denial-of-service via remote-triggered panic in message encryptionOversized message exceeding Noise/Lightning wire framing limitMissing length validation before adding attribution data during relay
6b1dfb1aby Matt Corallo+64−191 file
Vendor flagged security relevance
Moderate 64 AI analysisMessage 83 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Reject attempts to advance one-hop blinded forward paths

This commit fixes a denial-of-service bug in rust-lightning where a maliciously crafted one-hop blinded reply path could cause the node to panic when it tried to respond. The fix rejects paths with too few hops before advancing them, and a…

Denial-of-service vector via malformed blinded pathPanic in onion construction due to zero-hop pathUntrusted reply path input validation gap
969a40cfby Matt Corallo+49−14 files
Vendor flagged security relevance
Moderate 60 AI analysisMessage 88 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Allow filtered block rescans at the current tip

This commit fixes a bug where replaying the current blockchain block through a normal listener callback could crash two core Lightning components (ChannelManager and OutputSweeper) with a panic. The fix recognizes a same-block replay as a …

panic in chain listener callbacksame-block replay/rescan mishandlingassertion failure on valid chain input
686f9860by Elias Rohrer+118−123 files
Vendor flagged security relevance
Moderate 57 AI analysisMessage 78 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Avoid panic when reorged claims cannot merge

This commit fixes a crash bug in the Lightning Dev Kit's on-chain transaction handler. During a deep blockchain reorganization, a previously settled HTLC claim could be 'resurrected' at a block height where it could no longer be combined w…

Assertion/panic in reorg handling pathDeep blockchain reorg as trigger conditionHTLC claim resurrection after reorg
f1dc8487by Matt Corallo+219−52 files
Vendor flagged security relevance
Informational 15 AI analysisMessage 45 · Thin
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Update crate repository links to forgejo

This commit simply updates the 'repository' web links in 15 package metadata files from GitHub to a self-hosted Forgejo instance. It does not change any program code, build logic, dependencies, or security behavior. There is no security is…

eb77676dby benthecarman+15−1515 files
No security note in commit
Moderate 54 AI analysisMessage 73 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Retransmit splice_locked for 0-conf channels missing tx_signatures

This commit fixes a bug in the Lightning Dev Kit where, after a disconnection, a node could fail to retransmit a 'splice_locked' message to a peer that was still waiting for transaction signatures. Without this retransmission, the two peer…

Protocol state desynchronization between channel peers after reconnectionMissing retransmission of splice_locked for 0-conf splice channelsPotential channel unusability or stuck splice negotiation
5434015bby Wilmer Paulino+266−12 files
No security note in commit
Low 26 AI analysisMessage 90 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Include to_self_delay size in DelayedPaymentOutput weight calculation

This commit fixes a small accounting bug in how the Lightning wallet estimates the size (and therefore transaction fee) of a special Bitcoin transaction that sweeps funds back to the user after a channel closes. The old code always assumed…

debug assertion failure possible in development/testing buildstransaction weight/fee estimate overestimation up to 3 WUconstant replaced with per-descriptor length computation
e6652237by Matt Morehouse+97−83 files
No security note in commit
Informational 18 AI analysisMessage 65 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Correct docs on `ChannelSigner::get_per_commitment_point`

This commit only updates documentation comments for a Rust function called get_per_commitment_point. It removes an outdated warning that the method was non-asynchronous and that returning an error could cause a crash, and replaces it with …

Documentation-only changeRemoves outdated panic warningAdds retry/unblock guidance for signer errors
5057809bby Matt Corallo+6−31 file
No security note in commit
Informational 15 AI analysisMessage 63 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Require manual reviewer assignment

This commit changes the project's internal code-review workflow. It stops automatically assigning a human reviewer when a pull request is opened; instead, contributors must manually click a button to request a reviewer after first addressi…

9c1e5787by Joost Jager+21−232 files
No security note in commit
Informational 15 AI analysisMessage 28 · Opaque
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Format changed functions

This commit is purely a code-formatting cleanup. It removes `#[rustfmt::skip]` annotations and lets rustfmt reformat several functions in the routing/scoring module. No logic, behavior, or security properties of the code are changed.

05ce4204by Matt Corallo+44−251 file
No security note in commit
Moderate 60 AI analysisMessage 73 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Handle missing splice tx_signatures on reestablish

This commit fixes a bug in LDK's Lightning channel reconnection logic after a splice (a way to resize a channel's on-chain funds). If one peer had already received the splice signatures but the other had not, and then they disconnected and…

Protocol-state inconsistency on reconnection after splice signature exchangePotential channel stall/force-close due to quiescence not being exited before commitment updateFuzzer-discovered edge case in Lightning splicing retransmission
f93a7f0cby Wilmer Paulino+600−975 files
No security note in commit
Informational 19 AI analysisMessage 68 · Adequate
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

offers: Allow disabling invoice response MPP

This commit adds a new option for Lightning invoice creators to explicitly tell payers not to use multi-path payments (MPP) when paying an invoice. It does not change any enforcement rules; it only changes what feature bits are advertised …

New API surface for feature advertisement controlExplicit documentation that the method does not enforce single-HTLC receipt, shifting enforcement responsibility to callersNo removal or weakening of existing validation logic
00aabf81by Elias Rohrer+9−01 file
No security note in commit
Informational 15 AI analysisMessage 81 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Change assign-reviewer authorized integration token to a bot acct

This commit swaps the ID number used by an automated workflow that randomly assigns code reviewers. The old number pointed to a real person's account, so the workflow's assignments appeared to come from that person. The new number points t…

f734d1ebby Matt Corallo+1−11 file
No security note in commit
Informational 15 AI analysisMessage 35 · Opaque
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Remove taproot build check

This commit removes a separate CI build step that tested the project with a special 'taproot' compiler flag. It is a workflow cleanup change, not a code change. There is no indication of a security vulnerability.

81a7b82dby elnosh+0−81 file
No security note in commit
Informational 15 AI analysisMessage 45 · Thin
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Pin jobserver to 0.1.34 on pre-1.85 rustc

This commit adjusts the project's continuous integration (CI) test script to pin an older version of a build-time helper crate called `jobserver` when using older Rust compilers. It is a build compatibility fix, not a security patch, and d…

a4641403by Matt Corallo+3−01 file
No security note in commit
Informational 17 AI analysisMessage 50 · Thin
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Bump esplora-client to 0.13 to switch from `reqwest` to `bitreq`

This commit updates a dependency used to talk to Esplora blockchain servers from version 0.12 to 0.13, switching the underlying HTTP library from reqwest to bitreq. It also removes two CI workarounds that pinned older versions of idna_adap…

Dependency version bump (esplora-client 0.12 -> 0.13)HTTP backend switch (reqwest -> bitreq) in a transitive dependencyRemoval of MSRV pins for idna_adapter and hyper-rustls
5cd499e0by Matt Corallo+1−72 files
No security note in commit
Informational 15 AI analysisMessage 83 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Test cross-version serialization of pending splices

This commit only adds new test code. It exercises how a newer version of LDK exchanges saved channel data with the older LDK 0.2 release when a channel has a pending splice. There is no change to production logic, no bug fix, and no securi…

0beadb3bby Jeffrey Czyz+208−01 file
No security note in commit
Informational 18 AI analysisMessage 80 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Panic on unexpected chanmon monitor events

This change only affects an internal fuzz-testing harness, not production code. It makes the test harness crash with a clear error message if it encounters a ChannelMonitor event it doesn't know how to handle, instead of silently ignoring …

Test harness hardening onlyNo production code path modifiedNo cryptographic, network, or state-machine logic changed
3b46ec98by Joost Jager+9−31 file
No security note in commit
Low 25 AI analysisMessage 85 · Strong
LDK Lightning Dev Kitrust-lightning BitcoinCryptographic librariesLightning Network

Require `htlc_value_satoshis` in [pending] `HTLCUpdate`s

This commit removes the 'Option' wrapper from several HTLC amount fields, making them required instead of optional. It is a cleanup/refactoring change that simplifies the code by assuming the amount is always known. The commit message fram…

Removal of Option wrapper for financial amount fieldsSerialization format change from optional to required TLV fieldsLoss of backward compatibility with older serialized monitor/channel state
40957aadby Matt Corallo+24−284 files
No security note in commit
Repository ledger

Explore captured commits

Expand any commit for its author, full message, clarity score, changed files, triage signals, analysis, and source link.

Lower-priorityAllow cancellation of pending splice funding negotiationsby Wilmer Paulino · 554d833c · May 7, 2026 · 5 filesMessage 73 · AdequateTriage 0Details
Commit message · Wilmer Paulino

Allow cancellation of pending splice funding negotiations

A user may wish to cancel an in-flight funding negotiation for whatever
reason (e.g., mempool feerates have gone down, inability to sign, etc.),
so we should make it possible for them to do so. Note that this can only
be done for splice funding negotiations for which the user has made a
contribution to.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityProduce FundingInfo::Contribution variants in ChannelMonitorby Wilmer Paulino · 7e806f97 · May 7, 2026 · 5 filesMessage 73 · AdequateTriage 0Details
Commit message · Wilmer Paulino

Produce FundingInfo::Contribution variants in ChannelMonitor

Similar to the `ChannelManager`, we expose the contributed inputs and
outputs of a splice via `FundingInfo::Contribution` at the
`ChannelMonitor` level such that we don't lose the context when the
channel closes while a splice is still pending. This relies on tracking
the `FundingContribution` that was provided to the `ChannelManager`
prior to negotiating the new funding transaction. If no
`FundingContribution` exists, then we continue to emit the
`FundingInfo::OutPoint` variant.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityChange FundingInfo::Contribution to expose contributed output scriptsby Wilmer Paulino · b9d0eb74 · May 7, 2026 · 5 filesMessage 85 · StrongTriage 0Details
Commit message · Wilmer Paulino

Change FundingInfo::Contribution to expose contributed output scripts

Exposing the amounts for each output isn't very helpful because it's
possible that they vary across over multiple splice candidates due to
RBF. This commit changes `FundingInfo::Contribution` and several of the
helpers used to derive it to be based on output scripts instead.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Security candidateStrip Unicode `Cf` characters in `PrintableString`by Elias Rohrer · 1a01b5ae · May 7, 2026 · 1 fileMessage 86 · StrongHigh 72Details
Commit message · Elias Rohrer

Strip Unicode `Cf` characters in `PrintableString`

`PrintableString` is the sanitiser LDK uses to render untrusted strings
(node aliases, BOLT-12 invoice / offer text, `UntrustedString`, LSPS
messages, `lightning-invoice` descriptions) to logs and UI. It only
replaced `char::is_control` matches (Unicode general category `Cc`)
with U+FFFD, leaving the entire `Cf` (Format) category untouched.

That is the exact category covering the bidirectional override /
isolate codepoints (U+202A..U+202E, U+2066..U+2069) and zero-width
characters (U+200B..U+200D, U+FEFF) behind the "Trojan Source" attack
family (CVE-2021-42574): a peer can set its alias / invoice description
/ offer fields to e.g. `safe\u{202E}cipsxe.exe`, which previously
passed through verbatim while a human reader sees `safeexe.cips` —
defeating the threat model `PrintableString` exists to defend against.

Replace `Cf` codepoints alongside `Cc` ones. The `Cf` ranges are
inlined as a `matches!` table sourced from Unicode 16.0 to keep the
change `no_std`-friendly with no new dependencies.

Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>

86/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference✓ Names security-relevant behavior explicitly
Why it was queued
explicit security language
AI analysis · High 72/100

This commit fixes a security gap in LDK's string sanitizer, PrintableString, which is used to display untrusted text like node names and invoice descriptions in logs and user interfaces. Previously it only stripped traditional control characters (like newlines and tabs) but left behind Unicode 'format' characters, including invisible bidirectional override characters and zero-width spaces. These can trick a human reader into seeing a different string than what the software processes—an attack family known as 'Trojan Source.' The patch now replaces those format characters with the standard replacement symbol (), so spoofed strings render safely.

Lower-priorityExpose probe status in recent paymentsby Elias Rohrer · 419908da · May 7, 2026 · 2 filesMessage 76 · AdequateTriage 0Details
Commit message · Elias Rohrer

Expose probe status in recent payments

Previously, `ChannelManager::list_recent_payments` didn't give us the
means to discern 'real' payments from inflight probes. In
https://github.com/lightningdevkit/ldk-node/pull/815 we found that we
need a way to re-derive which probes are still pending so our accounting
of inflight probing amounts is still correct after restart.

To this end, we here let callers distinguish liquidity probes while they
are pending or abandoned.

Co-Authored-By: HAL 9000

Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>

76/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
Lower-priorityDerive DiscardFunding inputs and outputs from contributions on promotionby Jeffrey Czyz · 51e60798 · May 7, 2026 · 2 filesMessage 73 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Derive DiscardFunding inputs and outputs from contributions on promotion

When a splice funding is promoted, produce FundingInfo::Contribution
instead of FundingInfo::Tx for the discarded funding events. Each
contribution is filtered against the promoted funding transaction's
inputs and outputs, so only inputs and outputs unique to the discarded
round are reported.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityCheck can_initiate_rbf in stfu handler before sending tx_init_rbfby Jeffrey Czyz · ffbb8fe6 · May 7, 2026 · 4 filesMessage 85 · StrongTriage 0Details
Commit message · Jeffrey Czyz

Check can_initiate_rbf in stfu handler before sending tx_init_rbf

If splice_locked is sent between our outgoing STFU and the
counterparty's STFU response, the stfu() handler would proceed to
send tx_init_rbf for an already-confirmed splice. Guard against this
by re-checking can_initiate_rbf when entering quiescence. Disconnect
because there is no way to cancel quiescence after both sides have
exchanged STFU.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Lower-priorityAdd pending changelog for splice negotiation event changesby Jeffrey Czyz · b44076e0 · May 7, 2026 · 1 fileMessage 65 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Add pending changelog for splice negotiation event changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

65/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides an explanatory body
Why it was queued
documentation-only discount
Lower-priorityRemove unused NegotiationError and contributed_inputs_and_outputs methodsby Jeffrey Czyz · 367ffaa1 · May 7, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Remove unused NegotiationError and contributed_inputs_and_outputs methods

Now that splice_funding_failed_for! derives inputs and outputs from
FundingContribution directly, remove the unused NegotiationError struct
and into_negotiation_error methods from the interactive tx types, along
with the into/to_contributed_inputs_and_outputs methods on
ConstructedTransaction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityDerive SpliceFundingFailed inputs from FundingContributionby Jeffrey Czyz · db45c833 · May 7, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Derive SpliceFundingFailed inputs from FundingContribution

Replace the maybe_create_splice_funding_failed! macro and
splice_funding_failed_for method with a unified splice_funding_failed_for!
macro that derives contributed inputs and outputs from the
FundingContribution rather than extracting them from the negotiation
state.

Callers pass ident parameters for which PendingSplice filtering methods
to use: contributed_inputs/contributed_outputs when the current round's
contribution has been popped or was never pushed, and
prior_contributed_inputs/prior_contributed_outputs for the read-only
persistence path where the contribution is cloned instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityFix output filtering in into_unique_contributionsby Jeffrey Czyz · 9c6cca6b · May 7, 2026 · 2 filesMessage 68 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Fix output filtering in into_unique_contributions

Filter outputs by script_pubkey rather than full TxOut equality. Outputs
reusing the same address as a prior round are still considered committed
even if the value differs (e.g., different change amounts across RBF
rounds with different feerates).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Security candidateSimplify contribution pop in reset_pending_splice_stateby Jeffrey Czyz · 2eb939b1 · May 7, 2026 · 1 fileMessage 85 · StrongInformational 24Details
Commit message · Jeffrey Czyz

Simplify contribution pop in reset_pending_splice_state

The was_negotiated check is unnecessary because reset_pending_splice_state
only runs when funding_negotiation is present, meaning
on_tx_signatures_exchange hasn't been called yet. Since the feerate is
only recorded in last_funding_feerate_sat_per_1000_weight during
on_tx_signatures_exchange, the current round's feerate can never match
it. So the contribution can always be unconditionally popped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Why it was queued
signing boundary
AI analysis · Informational 24/100

This is a small code cleanup in the Lightning payment channel code that handles failed or aborted splice-in transactions. The change removes an unnecessary check when undoing a splice contribution, replacing it with an unconditional pop plus a debug-only sanity check. The commit message argues the old check could never trigger, so behavior should be unchanged. There is no direct evidence of a security bug, but any change to state-rollback logic in financial software warrants careful review because mistakes can leave funds in an inconsistent state.

AI review queuedRename SplicePending and SpliceFailed eventsby Jeffrey Czyz · cc7fb0f5 · May 7, 2026 · 10 filesMessage 68 · AdequateInformational 15Details
Commit message · Jeffrey Czyz

Rename SplicePending and SpliceFailed events

Rename Event::SplicePending to Event::SpliceNegotiated and
Event::SpliceFailed to Event::SpliceNegotiationFailed. These names
better reflect the per-round semantics: each negotiation attempt
resolves to one of these two outcomes, independent of the overall
splice lifecycle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit is a simple rename of two public event types in the Lightning Dev Kit Rust library. `Event::SplicePending` is renamed to `Event::SpliceNegotiated`, and `Event::SpliceFailed` is renamed to `Event::SpliceNegotiationFailed`. The change is purely cosmetic and intended to make the event names better match their meaning (a single negotiation round outcome, not the overall splice lifecycle). No logic, serialization format, or security behavior is changed.

Lower-priorityEmit DiscardFunding before SpliceFailedby Jeffrey Czyz · 14c68199 · May 7, 2026 · 3 filesMessage 70 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Emit DiscardFunding before SpliceFailed

Reverse the event ordering at all emission sites so that
Event::DiscardFunding is emitted before Event::SpliceFailed. If the
user retries the splice when handling SpliceFailed, the contributed
inputs would still be locked. A subsequent DiscardFunding would then
incorrectly unlock inputs that are now committed to the new attempt.
Emitting DiscardFunding first avoids this by ensuring inputs are
unlocked before any retry occurs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

70/100 · AdequateMessage clarity
✓ Descriptive subject✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Lower-priorityAdd FundingContribution to SpliceFailed eventby Jeffrey Czyz · 450eb645 · May 7, 2026 · 5 filesMessage 68 · AdequateTriage 0Details
Commit message · Jeffrey Czyz

Add FundingContribution to SpliceFailed event

Replace the abandoned_funding_txo and channel_type fields on
Event::SpliceFailed with an Option<FundingContribution> from the failed
round. Users can feed this back to funding_contributed to retry or use
it to inform a fresh attempt via splice_channel.

Also makes FundingContribution::feerate() public so users can inspect
the feerate when deciding whether to retry or bump.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
AI review queuedAdd NegotiationFailureReason to SpliceFailed eventby Jeffrey Czyz · f0a8cebb · May 7, 2026 · 5 filesMessage 85 · StrongInformational 21Details
Commit message · Jeffrey Czyz

Add NegotiationFailureReason to SpliceFailed event

Each splice negotiation round can fail for different reasons, but
Event::SpliceFailed previously gave no indication of what went wrong.
Add a NegotiationFailureReason enum so users can distinguish failures
and take appropriate action (e.g., retry with a higher feerate vs.
wait for the channel to become usable).

The reason is determined at each channelmanager emission site based on
context rather than threaded through channel.rs internals, since the
channelmanager knows the triggering context (disconnect, tx_abort,
shutdown, etc.) while channel.rs functions like abandon_quiescent_action
handle both splice and non-splice quiescent actions.

The one exception is QuiescentError::FailSplice, which carries a reason
alongside the SpliceFundingFailed. This is appropriate because FailSplice
is already splice-specific, and the channel.rs code that constructs it
(e.g., contribution validation, feerate checks) knows the specific
failure cause. A with_negotiation_failure_reason method on QuiescentError
allows callers to override the default when needed.

Older serializations that lack the reason field default to Unknown via
default_value in deserialization. The persistence reload path uses
PeerDisconnected since a reload implies the peer connection was lost.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Why it was queued
second-pass: broader security terminology
AI analysis · Informational 21/100

This commit is a user-facing diagnostic improvement, not a security fix. It adds a 'reason' field to the SpliceFailed event so Lightning node operators can tell why a splice negotiation failed (for example, peer disconnected, feerate too low, or counterparty aborted). It changes no cryptographic checks, access controls, or network behavior. The only code-level risk is a minor serialization compatibility change: old stored events without the new field default to 'Unknown', and the persistence reload path defaults to 'PeerDisconnected'.

Lower-priorityAttempt to unblock blocked monitor updates on startupby Matt Corallo · b0c312db · May 6, 2026 · 1 fileMessage 93 · StrongTriage 0Details
Commit message · Matt Corallo

Attempt to unblock blocked monitor updates on startup

When we make an MPP claim we push RAA blockers for each chanel to
ensure we don't allow any single channel to make too much progress
until all channels have the preimage durably on disk. We don't have
to store those RAA blockers on disk in the ChannelManager as
there's no point - if the ChannelManager gets to disk with the RAA
blockers it also brought with it the pending ChannelMonitorUpdates
that contain the preimages and will now be replayed, ensuring the
preimage makes it to all ChannelMonitors.

However, just because those RAA blockers dissapear on reload
doesn't mean the implications of them does too - if a later
ChannelMonitorUpdate was blocked in the channel we don't have logic
to unblock it on startup.

Here we add such logic, simply attempting to unblock all blocked
`ChannelMonitorUpdate`s that existed on startup.

Code written by Claude.

Fixes #4518

93/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Lower-priorityExpose additional FundingContribution accessorsby Jeffrey Czyz · 1d36f7bc · May 6, 2026 · 1 fileMessage 58 · ThinTriage 0Details
Commit message · Jeffrey Czyz

Expose additional FundingContribution accessors

Add public getters for `estimated_fee`, `inputs`, and `max_feerate`, and
elevate `feerate` from `pub(super)` to `pub`. Together with the existing
`value_added`, `outputs`, and `change_output`, this gives downstream
consumers of `TransactionType::Splice` (notably LDK Node, which updates
`PaymentDetails` from the broadcast callback) the data they need
without reaching into the raw transaction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

58/100 · ThinMessage clarity
✓ Descriptive subject✓ Provides detailed explanatory context
AI review queuedExpose interactive funding candidates on broadcastby Jeffrey Czyz · 0d2ac33e · May 6, 2026 · 6 filesMessage 73 · AdequateInformational 18Details
Commit message · Jeffrey Czyz

Expose interactive funding candidates on broadcast

Replace TransactionType::Splice with TransactionType::InteractiveFunding
so downstream consumers can update their own state tracking from the
broadcast callback. The local contribution data isn't recoverable from
the on-chain transaction, so the broadcast must surface it directly.
Each candidate carries the participating channels and their local
contributions; the broadcast lists every negotiated candidate — original
first, then each RBF replacement — letting downstream reconcile any
historical txid, not just the immediate predecessor.

The new variant is structured to be forward-compatible with batches and
V2 (dual-funded) channel establishment, neither of which is implemented
today. The new types are Writeable/Readable so downstream can persist
them directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 18/100

This commit is a routine API improvement for the Lightning Dev Kit. It changes the information reported when a splice (or future dual-funded) transaction is broadcast so that downstream wallet software can see all negotiated versions of the transaction and each party's contribution. There is no indication of a security bug being fixed; it is a feature/refactoring change to expose richer data to consumers of the library.

Lower-priorityRoll back composite sub-handlers when one rejects `peer_connected`by Elias Rohrer · 5455058e · May 6, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Elias Rohrer

Roll back composite sub-handlers when one rejects `peer_connected`

`composite_custom_message_handler!` expanded `peer_connected` to call
every sub-handler and remember the last error, but never undo the
already-succeeded ones. The `CustomMessageHandler::peer_connected`
contract is that `PeerManager` will *not* invoke `peer_disconnected`
when `peer_connected` returns `Err` — so any per-peer state allocated
by an earlier sub-handler that returned `Ok` was leaked permanently
once a later sub-handler returned `Err`.

A peer who can elicit `Err` from any sub-handler in the composite
(feature-bit gate, banlist, etc.) could repeatedly reconnect to grow
that leaked state without bound (slow resource DoS), and "currently
connected" predicates in the leaking sub-handler would lie about
peers that were actually rejected.

Mirror the rollback pattern `PeerManager` already uses for the four
built-in handlers (`peer_handler.rs:2149-2188`): record each
sub-handler's `peer_connected` result, and if any returned `Err`,
call `peer_disconnected` on the ones that succeeded before
propagating the failure.

Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Security candidateDrop local chacha20poly1305 implementationby Abeeujah · 964a84fc · May 5, 2026 · 4 filesMessage 50 · ThinInformational 12Details
Commit message · Abeeujah

Drop local chacha20poly1305 implementation

Complete the migration process from the local chacha20poly1305 to the
rust-bitcoin chacha20-poly1305 crate.

50/100 · ThinMessage clarity
✓ Descriptive subject✓ Provides an explanatory body
Why it was queued
cryptography-sensitive path
AI analysis · Informational 12/100

This commit removes the project's own implementations of the ChaCha20 stream cipher, Poly1305 message-authentication code, and the ChaCha20-Poly1305 combined encryption mode. It is described as the final step of migrating to the external 'rust-bitcoin chacha20-poly1305' crate. The change itself is a pure deletion of local code and module declarations; it does not add the replacement crate or change any call sites in this diff. There is no direct evidence in the commit that this fixes a security vulnerability.

Security candidateReplace local ChaCha20-Poly1305 with external crateby Abeeujah · a2cc67e7 · May 5, 2026 · 13 filesMessage 83 · StrongLow 36Details
Commit message · Abeeujah

Replace local ChaCha20-Poly1305 with external crate

Migrates ChaCha20-Poly1305 encryption from the local crypto
module to rust-bitcoin's `chacha20-poly1305` crate.

Integrated the crate across all modules (Router,
PeerStorage, Onion Utils, etc.).

Add the chacha20_poly1305_fuzz flag to fuzz config to after
implementing the fuzz logic upstream.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
fuzzing or regression evidencecryptography-sensitive pathsigning or wallet path
AI analysis · Low 36/100

This commit swaps out a home-grown ChaCha20-Poly1305 implementation for a widely reviewed external crate from the rust-bitcoin project. It is a routine refactoring/cryptographic-hardening change, not an obvious security fix. The diff shows careful translation of the old code to the new API, including fuzzing support and nonce handling. There is no direct evidence of a vulnerability being patched, but any crypto migration carries risk of subtle behavioral differences.

Lower-priorityRelease `OutputSweeper::pending_sweep` flag on future dropby Elias Rohrer · 6394d18b · May 5, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · Elias Rohrer

Release `OutputSweeper::pending_sweep` flag on future drop

`regenerate_and_broadcast_spend_if_necessary` used `pending_sweep:
AtomicBool` as a single-runner gate but only cleared the flag with an
unconditional `store(false)` *after* the inner future resolved. If the
caller's future was dropped while the inner await was `Pending` —
which `tokio::time::timeout`, `futures::select!`, manual
`JoinHandle::abort`, etc. all do — the reset never ran, leaving the
flag stuck `true` and every subsequent call to the function
short-circuiting with `Ok(())`.

Because `OutputSweeper` is what claims `SpendableOutputDescriptor`s
back to the user's wallet after channel closure (including HTLC
outputs with time-bounded recovery deadlines), a stuck flag turns
into fund-loss exposure: time-sensitive HTLC sweeps simply stop
happening, while every other code path keeps queueing new outputs to
sweep, until the process is restarted.

Replace the trailing `store(false)` with an RAII `PendingSweepGuard`
whose `Drop` impl always releases the flag — covering normal return,
error, and cancellation alike.

Co-Authored-By: HAL 9000

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Security candidateValidate Esplora merkle proof against the block header's merkle rootby Elias Rohrer · b64efcda · May 5, 2026 · 1 fileMessage 78 · AdequateCritical 88Details
Commit message · Elias Rohrer

Validate Esplora merkle proof against the block header's merkle root

`EsploraSyncClient::get_confirmed_tx` parsed the SPV proof returned by
the Esplora server but threw away the security check: the merkle root
computed by `PartialMerkleTree::extract_matches` was discarded
(`let _ = …`), and only the leaf-equality check (`matches[0] == txid`)
remained. Anyone can construct a single-leaf partial tree advertising
an arbitrary txid via `PartialMerkleTree::from_txids(&[txid], &[true])`,
so this gate was vacuous.

A malicious or compromised Esplora server could therefore convince
`EsploraSyncClient` that any transaction was confirmed in any block by
returning `MerkleBlock { header: real_header, txn: forged_partial_tree }`,
causing LDK to feed a synthesized `ConfirmedTx` into `Confirm`
implementations such as `ChannelManager` / `ChainMonitor`. From there,
the channel-funding / closing / HTLC flows would treat the transaction
as confirmed at an attacker-chosen height, with consequences ranging
from premature state transitions to force-close races.

Capture the merkle root returned by `extract_matches` and require it
to equal `block_header.merkle_root`, matching the validation the
Electrum sibling already performs via `validate_merkle_proof`.

Co-Authored-By: HAL 9000

78/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Names security-relevant behavior explicitly
Why it was queued
explicit security languagedefensive validationsigning or wallet path
AI analysis · Critical 88/100

This commit fixes a security bug in LDK's Esplora client. The client was supposed to verify that a transaction was really included in a Bitcoin block by checking a cryptographic proof (a merkle proof) from the Esplora server. But it only checked that the proof contained the right transaction ID, not that the proof actually connected to the real block header. Because a single-leaf proof can be forged for any transaction ID, a malicious or compromised Esplora server could trick LDK into believing any transaction was confirmed in any block. That could trigger wrong channel state changes, premature force-closes, or other fund-risking behavior. The fix makes the client compare the computed merkle root from the proof against the block header's merkle root, which is the same check the Electrum client already did.

Lower-priorityFix `StaticInvoice::is_offer_expired` to check the offer's expiryby Elias Rohrer · c005b11d · May 5, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Elias Rohrer

Fix `StaticInvoice::is_offer_expired` to check the offer's expiry

The std-only `StaticInvoice::is_offer_expired` accessor delegated to
`InvoiceContents::is_expired`, which compares `created_at +
relative_expiry` against the current time — that is the *invoice*'s
expiry, not the offer's. The `_no_std` sibling and `flow.rs::
enqueue_static_invoice` already treat the two as distinct checks.

A payer or forwarder using the std API to decide whether to honor a
static invoice would therefore get the wrong answer in either
direction: forwarding offers the issuer has already retired (when the
invoice is still fresh), or refusing offers that are still valid (when
the invoice has aged past its `relative_expiry` but the offer itself
has no `absolute_expiry`).

Route the std accessor through `InvoiceContents::is_offer_expired` so
both the std and no-std paths consult the offer's expiry.

Co-Authored-By: HAL 9000

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context