Skip to content

Bump main - #1

Merged
erickcestari merged 873 commits into
mainfrom
bump-main
Jul 29, 2026
Merged

Bump main#1
erickcestari merged 873 commits into
mainfrom
bump-main

Conversation

@erickcestari

Copy link
Copy Markdown
Member

No description provided.

wpaulino and others added 30 commits June 9, 2026 11:08
LDK and the chanmon_consistency fuzz target have grown in complexity
recently and thus require more iterations than previously assumed to
fully settle the state of all active channels.
If we have pending updates to send to our counterparty on
reestablishment, while also pending a `splice_locked` send, then we must
send our `splice_locked` first as the pending updates are considering
the post-splice-locked state.
A stale ChannelManager can be reloaded after a monitor update has
already completed in a prior runtime and released its post-update
messages to the counterparty. The latest ChannelMonitor is not stale,
but the serialized manager may still contain the old in-flight monitor
state and `monitor_pending_*` resend flags from before the completion
action ran.

This becomes observable when startup monitor-completion background
events are interleaved with splice promotion. On reload, the completed
monitor update is queued as a background event. If a splice confirmation
is processed before that background event fully resumes the channel,
splice promotion can create a new `RenegotiatedFundingLocked` monitor
update. The old completion is then blocked behind the new in-flight
splice update. Once the channel reconnects and the splice update
completes, `monitor_updating_restored` may consume the stale
`monitor_pending_revoke_and_ack` / `monitor_pending_commitment_signed`
flags and release a duplicate `revoke_and_ack` or `commitment_signed`.

The peer's `channel_reestablish` commitment numbers are authoritative
for this case. If `next_remote_commitment_number` says the peer is not
waiting for a `revoke_and_ack`, clear `monitor_pending_revoke_and_ack`.
Likewise, if `next_local_commitment_number` says the peer already has
our latest `commitment_signed`, clear
`monitor_pending_commitment_signed`.
…eestablish-fixes

`splice_locked` + `channel_reestablish` bug fixes
LSPS5 resets notification cooldowns when a peer reconnects so clients
can receive prompt wake-ups after coming online. A peer can otherwise
churn connections to clear the webhook cooldown repeatedly, turning the
LSP into an amplification source for registered notification URLs.

Rate-limit how often peer lifecycle events may clear notification
cooldowns while keeping the first reset immediate. Also make
LSPSDateTime elapsed-time calculation directional so backwards clock
movement does not make future timestamps look expired.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
AnchorDescriptor::previous_utxo is used for coin selection and PSBT witness_utxo metadata. For keyed anchors it should describe the on-chain P2WSH anchor output instead of the witness script so wallets can validate and sign the package.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
get_supportable_anchor_channels estimates how much each reserve UTXO can contribute after spending fees. Include the base input weight in that fee so UTXOs just below the public per-channel reserve are not counted as supporting another anchor channel.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
When a used async receive offer's refreshed static invoice is persisted,
advance the recorded invoice creation time. This keeps the refresh
threshold anchored to the newest invoice instead of making the offer
look stale on every timer tick.

Add coverage that a used offer does not enqueue another
ServeStaticInvoice immediately after the server confirms the refresh.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
When a JIT channel open fails, release queued intercepted HTLCs through the intercept API so they are not held until expiry. Keep resetting the LSPS2 state if an intercept has already been released.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
Reserve write versions while holding the per-path lock map mutex so
cleanup cannot remove the version state between version allocation and
lock reference acquisition.

Add a regression test for the ordering invariant.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
…hannel-open-failed

Release LSPS2 intercepted HTLCs on open failure
…erve-input-weight

Account for UTXO base weight in anchor reserve checks
Introduce fields `pending_fee_msat` for `RecentPaymentDetails::Pending`
and `fee_paid_msat` for `RecentPaymentDetails::Fulfilled`.
…vious-utxo-p2wsh

Return P2WSH script pubkey for keyed anchor prevouts
Move the version-allocation ordering note to the allocation it
describes so the cleanup invariant is easier to follow.

Co-Authored-By: HAL 9000
Exercise the stale-write race through the stored filesystem bytes so the
regression test covers the user-visible overwrite bug.

Co-Authored-By: HAL 9000
…ntity-check

Reject quantity of 0 for offers with bounded quantity
InvoiceRequest and Refund have payer metadata consisting of an
encrypted payment id and, originally, a nonce used to derive the payer
signing keys and authenticate any corresponding invoices. The nonce was
elided to save space once it was included in the OffersContext of
blinded reply paths, but that means verifying a Bolt12Invoice requires
state outside the invoice itself. Upcoming payment proofs (lightningdevkit#4297) need
the invoice signing keys derivable from the invoice request alone, so
include the nonce in the payer metadata again and verify invoices using
it rather than the context's nonce.

This breaks verification of invoices for invoice requests and refunds
with blinded paths created by prior versions, as their payer metadata
lacks the nonce; such payments will fail and must be retried with a new
payment id. Refunds without blinded paths are unaffected, as their
metadata always included the nonce.

Co-Authored-By: Claude <noreply@anthropic.com>
…consistency-fixes

Splice fixes for `chanmon_consistency` fuzz target
Allow integrations to intercept blinded onion-message hops that identify
the next node by short channel id, so LSPS-style protocols can resolve
those hops out of band instead of dropping the message.

Co-Authored-By: HAL 9000
When the OnionMessenger intercepts an onion message to forward, it now reports
which peer sent us the message via a new `prev_hop` field, so handlers can
apply source-based policy when deciding whether to forward.

`prev_hop` is `None` when the forward is enqueued by a message handler (the
BOLT 12 static-invoice-server flow), which isn't given the sending node;
otherwise it is the node we received the message from.

Co-Authored-By: Claude <noreply@anthropic.com>
…-invoice-refresh

Avoid repeated refreshes for persisted async invoices
Route chanmon broadcasts through an explicit harness mempool so relay,
mining, wallet updates, and chain delivery share one path. This lets
broadcast transactions enter the mempool before a modeled block confirms
them.

On restart, sync loaded monitors and managers from their own persisted
best blocks so raw monitors catch up without rewinding ChannelManager
state. Cap modeled mining before unresolved HTLC timeout deadlines
and use the LDK anti-reorg depth for setup confirmations.
…sage-origin

Report the sending peer in `Event::OnionMessageIntercepted`
The owned `Waker` wake method assumed it had the only reference to
the sender as the `Waker` is owned at that point, however our
`Waker`s can be `clone`d, leaving multiple references to the inner
`Sender` (held in an `Arc`).

Thus, the `&mut` cast is technically undefined behavior. However,
as this patch demonstrates, its only use is in calling an `&self`
method which derefs an internal `Arc` in tokio, so its highly
unlikely to lead to miscompilation.

Reported by Project Loupe.
…aliasing

Remove unnecessary (and incorrect) `&mut` cast in net-tokio
Now that the payer nonce is included in the payer metadata of
InvoiceRequest and Refund, Bolt12Invoice verification no longer needs
the nonce from the blinded path's OffersContext. Remove it from
OffersContext::OutboundPaymentForOffer and
OffersContext::OutboundPaymentForRefund, along with
enqueue_invoice_request's nonce parameter, which only existed to supply
it. The nonce in RetryableInvoiceRequest is no longer used either but
is still persisted -- and retained when reading state written by prior
versions -- so that such versions can retry the payment and verify the
resulting invoice after a downgrade.

The payment_id is kept in both variants, however. While no longer needed
to confirm the invoice is for an invoice request or refund we created,
it is checked against the payment id recovered from a received
Bolt12Invoice's payer metadata to ensure the invoice arrived over the
blinded path created for that payment. This prevents an attacker from
reusing the blinded path of one of our payments to deliver another
payment's invoice and correlate the two as ours.

Co-Authored-By: Claude <noreply@anthropic.com>
`Borrow`'d values are required to `Hash` identically to the
original object so that a `Borrow`ed key can be used in place of an
owned one in a `HashMap` lookup.

We'd violated this on our `Payment*` types, which we fix here. Note
that changing the `Hash` implementation is generally not considered
an API-breaking change and this seems like a useful fix.

Reported by Project Loupe.
In ae62fa3 we removed an incorrect
`&mut`, but failed to actually resolve the mut aliasing bug - there
remained a deref of a `*mut` which is similarly invalid. Here we
actually fix the bug and also DRY up code marginally.

Reported by Project Loupe.
…ayer-nonce

Include `Nonce` in `payer_metadata` again
TheBlueMatt and others added 29 commits July 24, 2026 20:38
In the previous commit we started handling the new `DNSSECError`
onion messages and using them to expose when a BIP 353 resolution
over onion messages should be considered failed due to all of our
queries having filed. However, queries can also fail if all of our
queries either errored or returned bogus proofs, or if we received
a valid proof which proved there is no BIP 353 record or `Offer`.

Here we consider such failures and expose them as well.
lightning/blips#71 updated the DNSSEC
resolution bLIP to include an explicit error message when DNS(SEC)
resolution was attempted but failed, allowing for faster fallback
to LN-Address (for clients that do) and faster payment failure.

Here we add service-side support for generating the error messages,
informing requesters that their resolutions have failed.

Largely written by an LLM
We intended to apply DNSSEC proof validity tests to constrain them
to within two hours of the latest block header time, but the code
landed with a two minute gap instead.

Given DNSSEC proof validity is usually many hours and grace periods
are used to ensure records close to expiry aren't used, this is
somewhat unlikely to have bitten anyone.
This better captures what the method actually does.
from block-connection-logging into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4813
Reviewed-by: Matt Corallo <matt@noreply.gitea.bitcoin.ninja>
…sed resolution' (#4814)

from 2026-07-353-errs into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4814
Reviewed-by: Val Wallace <val@noreply.gitea.bitcoin.ninja>
…th ways

When selecting a channel to reference a compact (DirectedShortChannelId)
introduction node, only consider channels that are enabled in both
directions. Disabled channels cannot be used to reach the introduction
node, and such channels may linger in the local network graph long after
being disabled or even closed (e.g., when sourcing gossip from rapid
gossip sync, which never removes closed channels). Previously, the
oldest channel of the introduction node was selected unconditionally,
which could produce blinded paths that senders cannot resolve or route
to, silently breaking long-lived paths such as those embedded in BOLT 12
offers.

If no enabled channel is found, the NodeId encoding is kept.

Fixes #4826.
…806)

from outbound-htlc-forward-correlation into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4806
Reviewed-by: jkczyz <jkczyz@noreply.gitea.bitcoin.ninja>
Build direct, forwarded, and MPP routes from a shared per-path hop
description. Derive route fees and node metadata from that description,
and increase the CLTV delta by 100 for each successive hop.

Later failure tracking needs to describe the exact route that was sent.
Keeping route construction and bookkeeping on one representation
prevents them from drifting and prepares the tracker to retain more
per-hop failure context.
Rename the send-state query and local variables to describe whether LDK
still has pending work. Route the existing pending-payment registration
through one helper without changing which sends are tracked.

Later payment invariants must apply consistently to direct, forwarded,
and MPP sends. Centralizing this lifecycle decision keeps tracking
changes from diverging between send helpers.
Register every send as pending, then move immediate outcomes through
one strict pending-to-resolved transition. Reuse that transition for
terminal events and manager rollback, while handling repeated terminal
events only after confirming the payment was already resolved.

Keep abandoned payments pending while they still have outbound HTLC
state, including holding-cell HTLCs. Later success checks need complete
tracker state and must reject terminal events for payments the harness
never recorded.
Carry each send's minimum final CLTV expiry into payment
registration. Thread PaymentTracker through HTLC message delivery and
separate PaymentFailed from ProbeFailed dispatch.

A later invariant commit uses this context to classify failure roots.
Keeping the plumbing separate reduces its behavioral review even though
the minimum expiry remains temporarily unread.
Keep each hop ChannelId beside its SCID and retain the complete set
of paths while a payment is pending. This is mechanical preparation;
the new fields are intentionally not interpreted yet.

SCIDs remain the route-building input, while explicit closes identify
channels by ChannelId. Carrying both representations in one path model
lets a later force-close allowance match affected payments without
reconstructing routes or maintaining parallel bookkeeping.
Start pending payments at MustSucceed and require every tracked
PaymentFailed to follow an observed failure source. Cover receiver
rejection, corruption, local send failure, local inbound forwarding
failures, and the receive-side CLTV buffer.

Local inbound failures are classified when forwarding leaves an
inbound HTLC waiting for its removal revoke, before the failure can
reach the payer. For relayed failures, use
OutboundHTLCDetails::source to retain exact inbound channel and HTLC
IDs with the payment hash. This prevents same-hash MPP parts from
being mistaken for a local failure root.
The chanmon harness can now force-close a target channel as long
as that channel itself has no pending HTLCs, even when another
channel still carries an in-flight payment. When an explicit close
succeeds, mark pending payments that routed over the closed channel
as allowed to fail.

This is the narrowest extension beyond globally HTLC-free closes. It
covers a payment that crossed one hop before its next, still-empty
channel is closed, without yet modeling force closes of channels that
themselves contain HTLCs. Route-aware failure tracking limits the
allowance to affected payments.
…enabled both ways' (#4828)

from fix-offer-compact-intro-node into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4828
Reviewed-by: Matt Corallo <matt@noreply.git.rust-bitcoin.org>
…(#4829)

from 2026-07-4197-doc-updates into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4829
Reviewed-by: wpaulino <wpaulino@noreply.git.rust-bitcoin.org>
…ccessors + tweak bounds handling' (#4824)

from 2026-07-prob-access-debug-assert into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4824
Reviewed-by: Val Wallace <val@noreply.git.rust-bitcoin.org>
SpendableOutputDescriptor::create_spendable_outputs_psbt estimated the
witness weight of a to_local (DelayedPaymentOutput) input using
MAX_WITNESS_LENGTH, which assumes the maximum 4-byte OP_CSV push of
to_self_delay in the redeemscript.  The real push can be as small as 1
byte for small to_self_delays, causing the estimate to overshoot by up
to 3 WU.  If this overshoot occurred in addition to a short signature,
the max-overshoot debug_assert in KeysManager::spend_spendable_outputs
would fail.

Add DelayedPaymentOutput::max_witness_length, which computes the witness
length from the descriptor's actual to_self_delay, and use it in place
of the MAX_WITNESS_LENGTH constant.  This produces a more accurate
weight estimate so that the debug_assert in spend_spendable_outputs
never fails.

This bug was discovered using Smite.
from fuzz-force-close-inflight-no-target-htlc into main

Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4800
Reviewed-by: wpaulino <wpaulino@noreply.git.rust-bitcoin.org>
@erickcestari
erickcestari merged commit e2fa4de into main Jul 29, 2026
2 of 16 checks passed
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.