Commit graph

20050 commits

Author SHA1 Message Date
ziggieXXX
05407c84ee
Merge pull request #11062 from ziggie1984/bump-v0.20.3-final
build: bump version to v0.20.3
2026-08-12 13:00:27 -03:00
ziggie
02c6ba46e4
build: bump version to v0.20.3 2026-08-12 12:18:53 -03:00
ziggieXXX
f1f8bb18ad
Merge pull request #11059 from lightningnetwork/backport-11057-to-v0.20.x-branch
[v0.20.x-branch] Backport #11057: scripts/keys: add pub key for boris
2026-08-11 08:37:44 -03:00
Boris Nagaev
6f7e524d85 scripts/keys: add pub key for boris
(cherry picked from commit 69176c5d18)
2026-08-11 05:24:02 +00:00
ziggieXXX
486b853149
Merge pull request #11053 from lightningnetwork/backport-10845-to-v0.20.x-branch
[v0.20.x-branch] Backport #10845: scripts: add tag-release.sh to safely cut release tags
2026-08-09 23:32:41 -03:00
ziggie
853a11663d
release: validate version in release CI
The release workflow runs from pushed version tags, but the build step
was setting SKIP_VERSION_CHECK=1. That made scripts/release.sh exit
before running check-tag, so CI did not compare the pushed tag with
the version reported from build/version.go.

Run the normal release target instead. This keeps release CI from
producing artifacts when the tag and embedded lnd version drift apart.

(cherry picked from commit e1f03b424f)
2026-08-09 22:01:34 -03:00
ziggie
2ac08a1352
scripts: add tag-release.sh to safely cut release tags
Adds a script that creates a signed annotated release tag only after
verifying:

  1. The requested tag name matches the version constants committed in
     HEAD:build/version.go. Catches the failure mode where a release
     branch is tagged before the version bump has been committed, which
     would otherwise leave the tagged commit reporting an old version
     string at runtime.

  2. The local HEAD is identical to the upstream lightningnetwork/lnd
     view of the release branch. A release tag must never point at a
     commit that has not been merged upstream yet.

The upstream remote is discovered by URL rather than by name, since
"origin" is conventionally the fork in a "gh repo fork" workflow. The
branch defaults to whichever one is currently checked out (typically a
release branch such as v0.21.x-branch) and can be overridden with
--branch.

The script deliberately does not push the tag or auto-bump version.go;
both remain explicit human steps.

(cherry picked from commit 5320aa0e36)
2026-08-09 22:01:21 -03:00
ziggieXXX
0ff59249d2
Merge pull request #11050 from lightningnetwork/backport-10940-to-v0.20.x-branch
[v0.20.x-branch] Backport #10940: Add public key for gijswijs
2026-08-09 17:05:19 -03:00
Gijs van Dam
b86fcc0873
scripts/keys: add pub key for gijswijs 2026-08-08 17:24:55 -03:00
ziggieXXX
40257f7c54
Merge pull request #11052 from lightningnetwork/backport-10586-to-v0.20.x-branch
[v0.20.x-branch] Backport #10586: scripts: add gpg key for georgetsagk
2026-08-08 17:20:00 -03:00
George Tsagkarelis
1a8cf49dfd scripts: add gpg key for georgetsagk
(cherry picked from commit 05d1df6de1)
2026-08-08 20:19:09 +00:00
ziggieXXX
1364c8b4c7
Merge pull request #11044 from ziggie1984/bump-v0.20.3
build: bump version to v0.20.3-beta.rc1
2026-08-07 13:02:02 -03:00
ziggie
ae1c701c56
build: bump version to v0.20.3-beta.rc1 2026-08-07 13:00:30 -03:00
ziggieXXX
f3d0f00358
Merge pull request #11045 from ziggie1984/fix-0.20.3-release-notes
docs: move post-0.20.2 entries into new 0.20.3 release notes
2026-08-07 12:29:02 -03:00
ziggie
1551b44d6d
docs: move post-0.20.2 entries into new 0.20.3 release notes
The v0.20.2-beta tag was cut on 2026-07-07 and published as a release
the following day, but the seven backports that landed on the release
branch afterwards all appended their entries to
release-notes-0.20.2.md, since no notes file existed for the next
patch release. The published 0.20.2 notes therefore advertised fixes
that are not in the 0.20.2 binaries.

Create release-notes-0.20.3.md and move those entries into it,
restoring release-notes-0.20.2.md to its content at the v0.20.2-beta
tag. The entry prose is carried over verbatim and matches the wording
already used for the same backports in release-notes-0.21.2.md on the
v0.21.x branch.
2026-08-07 09:53:15 -03:00
ziggieXXX
7611889fcb
Merge pull request #11030 from lightningnetwork/backport-11019-to-v0.20.x-branch
[v0.20.x-branch] Backport #11019: lnwallet/chancloser: fix data race in the legacy coop close state machine
2026-08-07 09:31:30 -03:00
ziggieXXX
b4724adf32
Merge pull request #11038 from lightningnetwork/backport-11028-to-v0.20.x-branch
[v0.20.x-branch] Backport #11028: htlcswitch: validate intercepted auto-fail height
2026-08-07 08:35:11 -03:00
Olaoluwa Osuntokun
23257e7253
docs: add release notes entry for the coop close fixes
Backport of the release note from PR #11019, retargeted from
release-notes-0.21.2.md to release-notes-0.20.2.md.
2026-08-07 00:09:02 -03:00
Olaoluwa Osuntokun
84ddced2b5
lnwallet/chancloser: record the remote close output only when accepted
In this commit, we hold off on recording the remote party's close output until
we've decided we can act on their Shutdown. ReceiveShutdown wrote the field
before it looked at the state, so a Shutdown that arrives at a point where we
have nothing to do with it, say once we've already finished the negotiation,
would still overwrite the output we settled on before being turned away with
ErrInvalidState. The output we report for the close then describes a message we
rejected.

Nothing acts on this today, as we hand the outputs to the caller only after
ClosingTx tells it the negotiation finished, but the field is what we report to
the party that asked for the close, so we may as well only fill it in from a
message we accepted.
2026-08-07 00:09:02 -03:00
Olaoluwa Osuntokun
2ca05213a2
peer+lnwallet/chancloser: advance the legacy closer from one goroutine
In this commit, we give the legacy ChanCloser a single owner, rather than
letting two goroutines advance it. The peer's channelManager drives the state
machine for the Shutdown and ClosingSigned messages that come off the wire, and
for local close requests. The link drives it as well: while we wait for the
channel to drain we register a flush hook, and the link invokes that hook from
its own goroutine, where it called BeginNegotiation directly. Nothing kept the
two apart, so the state field, the priorFeeOffers map, and the signing step
could all be touched at once. Under `go test -race` this shows up as a data race
on the state field.

Rather than reach for a lock, we route the flush through the channelManager. The
hook now only reports the channel ID over a new chanCloseFlushed channel, and
handleChanFlushed picks it up next to the close messages. Every transition, the
cached offer processing, the fee map, and the signing then happen on the one
goroutine, so the closer needs no synchronization of its own. We spell that out
on the type, since it's an invariant a new caller can break from the outside.

The report goes out from a fresh goroutine, which matters more than it looks.
The link may well be holding its own lock while it invokes the hook, and
channelManager reaches for that same lock in DisableAdds, so blocking on the
handoff would trade the race for a deadlock. The `go` in front of RemoveLink
just above it is there for the same reason.

We look the closer up with a plain map load rather than through
fetchActiveChanCloser, as that one builds a fresh closer when it doesn't find
an existing one, and a flush that lands after the negotiation was torn down has
no business starting a new negotiation.

One behavior change falls out of the move: the flush path now runs the same
finalization tail as the message path. It skipped that before, so a responder
that drained a cached offer would reach closeFinished and broadcast, but nothing
ran finalizeChanClosure until the next close message showed up, and having
already sent its final signature, there may not be one. The link == nil path
already ran the tail, so this makes all three paths agree.

The new test drives a close with a link that hands us the flush hook instead of
running it inline, so we can check that negotiation waits on the report, and
that a report for a channel we have no closer for is dropped.
2026-08-07 00:09:02 -03:00
Olaoluwa Osuntokun
f51ec036dc
lnwallet/chancloser: validate delivery scripts in the RBF closer
In this commit, we make the RBF co-op closer validate the remote party's
delivery script in all cases, matching what the negotiation closer already does.
Previously we only ran the check when we had an upfront shutdown script on record
for the peer, so a peer that never committed to an upfront script could hand us a
delivery script that we'd stash and carry through the rest of the close flow
without ever looking at it.

We now always call validateShutdownScript with the (possibly nil) upfront
script: a nil upfront script still runs the well-formedness check on the peer's
script, and a non-nil one additionally enforces the exact match, same as before.
We also require the script to be present. The wire format puts no lower bound on
the address length, and validateShutdownScript treats an absent peer script as
nothing to check, so an empty one passed validation by default rather than on its
merits. Both entry points now go through one helper that insists on a script
before running the usual checks over it, which also covers a CloserScript
swapped in mid-negotiation via ClosingComplete rather than letting that one go
unchecked.

The delivery-form coverage is spelled out in the tests: the spec dropped p2pkh
and p2sh for co-op closes to keep the dust calculations uniform, and we don't
implement the OP_RETURN form that option_simple_close allows, so all of those are
rejected along with an empty or malformed script.
2026-08-07 00:09:02 -03:00
Olaoluwa Osuntokun
8d4e34ec95
lnwallet: make DustLimitForSize total over the sizes it can be handed
In this commit, we have DustLimitForSize fall back to the generic witness dust
threshold for any script size that doesn't match one of the well-known
templates.

The size switch covered P2WPKH, P2WSH, P2SH, P2PKH, and the explicit
unknown-witness size, and treated every other length as unreachable. That's a
narrower assumption than the callers can actually make good on: a witness
program for versions 1 through 16 carries a program of anywhere from 2 to 40
bytes, so its serialized length won't always land on one of those exact values.

The dust calculation only needs a representative output of roughly the right
shape, and the unknown-witness pricing is the conservative choice among the
ones we have, so we make it the default. That leaves the helper well defined
across the whole range of sizes callers can pass it, including scripts carrying
witness versions we don't know about yet.
2026-08-07 00:09:01 -03:00
ziggie
93230c84e4
docs: add interceptor auto-fail height release note 2026-08-07 00:03:25 -03:00
ziggieXXX
d261654fb4
Merge pull request #11040 from lightningnetwork/backport-10637-to-v0.20.x-branch
[v0.20.x-branch] Backport #10637: Fix linter issue in brontide.go
2026-08-07 00:01:59 -03:00
Gijs van Dam
c4da213532 chore: fix linter issues in brontide.go
Post merge of #10089, a linter issues was introduced in `brontide.go`.
This commit fixes that issue.

(cherry picked from commit e8074935d9)
2026-08-07 03:01:05 +00:00
ziggie
316c2d936b htlcswitch: bound intercepted auto-fail height
The interceptor exposes its derived auto-fail height as an int32. Calculate
the height in int64 and fail forwards whose deadline cannot be represented
with expiry_too_far.

Add coverage for the range check and subsequent forward handling.

(cherry picked from commit ae3f4aff48)
2026-08-07 02:54:13 +00:00
ziggieXXX
d8ed6781d4
Merge pull request #11033 from lightningnetwork/backport-11032-to-v0.20.x-branch
[v0.20.x-branch] Backport #11032: contractcourt: retain deadline across contest resolution
2026-08-06 11:18:37 -03:00
ziggie
f93ca95481
docs: update release notes 2026-08-06 08:48:41 -03:00
ziggie
5ea52afa68 contractcourt: retain deadline across contest resolution
Forward the supplied incoming HTLC expiry from the outgoing contest resolver to its embedded timeout resolver. This keeps the deadline available when resolution transitions after the outgoing HTLC expires.

(cherry picked from commit f77606851f)
2026-08-06 11:24:09 +00:00
ziggieXXX
a041429e7b
Merge pull request #11026 from lightningnetwork/backport-11024-to-v0.20.x-branch
[v0.20.x-branch] Backport #11024: invoices: refine update handling
2026-08-05 15:29:18 -03:00
ziggie
fab4905aa5 docs: update 0.21.2 release notes
(cherry picked from commit 758bbb8e52)
2026-08-05 18:15:09 +00:00
ziggie
be784bd373 invoices: refine update handling
(cherry picked from commit 6be6350ec4)
2026-08-05 18:15:09 +00:00
Olaoluwa Osuntokun
821271e198
Merge pull request #11016 from lightningnetwork/backport-10992-to-v0.20.x-branch
[v0.20.x-branch] Backport #10992: discovery: bound channel range reply memory usage
2026-08-03 16:26:52 -07:00
Olaoluwa Osuntokun
e18a3428c5
discovery: bound channel range reply buffering
In this commit, we cap each QueryChannelRange response at 100,000 SCIDs
across all streamed replies. The existing reply-count limit did not track
the aggregate decoded working set, so memory use varied with the encoding
and composition of the reply stream.

We count raw SCIDs before timestamp filtering, charge replies using the
received encoding type, and release all accumulated range state on any
error. This bounds both memory and CPU work while still leaving headroom
above the current graph.

(cherry picked from commit ceff94fadd)
2026-08-03 18:07:22 -03:00
Olaoluwa Osuntokun
f5ccc922e2
lnwire: cap decoded short channel IDs
In this commit, we cap each decompressed short channel ID set at 100,000
entries, matching the aggregate range reply budget. The old zlib reader
bounded compressed input rather than decoded output, so the two working-set
limits could drift apart.

We retain compatibility with protocol-valid compressed replies, reject
truncated or corrupt zlib streams, and close the reader on every exit.
Boundary, compatibility, corruption, and property tests cover the
decoder.

(cherry picked from commit d162291941)
2026-08-03 18:01:58 -03:00
Olaoluwa Osuntokun
97abb6a083
Merge pull request #11009 from lightningnetwork/backport-10942-to-v0.20.x-branch
[v0.20.x-branch] Backport #10942: htlcswitch: forward blinded payments addressed by node_id
2026-08-03 13:46:04 -07:00
bitromortac
a08de6de32
docs: update release notes
Add the blinded node-ID forwarding changes to the v0.20.2 release notes.

(cherry picked from commit f42b429899)
2026-07-30 12:42:30 -03:00
bitromortac
229be2a83f
itest: cover blinded route next_node_id forwarding
Add integration tests for an lnd introduction node forwarding a blinded
payment whose non-final hops identify the next hop by node ID (next_node_id)
rather than a short channel ID, as produced by other implementations:

  - testBlindedRouteNextNodeID: the outgoing channel is public.
  - testBlindedRouteNextNodeIDPrivateChannel: the outgoing channel is
    private, so the node ID resolves to an SCID alias.
  - testBlindedRouteNextNodeIDRestart: the introduction node is restarted
    while the HTLC is in flight, exercising forwarding-package replay and
    re-decode of the node-ID blinded hop.

(cherry picked from commit da6a40c01d)
2026-07-30 12:40:55 -03:00
bitromortac
8989a1c851
witness beacon: report node-ID next hop to the on-chain HTLC interceptor
Extend the on-chain interceptor path in the witness beacon to expose a
node-ID next hop, mirroring the off-chain path. A node-ID next hop has no
outgoing channel of its own, so the beacon reports hop.Exit as the outgoing
channel (via ForwardingInfo.NextHopChannel().UnwrapOr) and the requested
next node's public key. The RPC boundary maps that to the NodeIDForwardSCID
sentinel so the forward is not misread as a final receive.

This is the requested next hop, not the channel eventually selected by
non-strict forwarding, so the beacon deliberately does not resolve it
against the circuit map.

(cherry picked from commit 9c4b8bfec2)
2026-07-30 12:40:36 -03:00
bitromortac
02f0f61cab
htlcswitch+lnrpc: report node-ID next hop to the off-chain HTLC interceptor
When the switch forwards a blinded hop identified by node ID, it has not
yet resolved a concrete outgoing channel at interception time. Expose the
next hop to the interceptor: InterceptedForward.Packet() reports the
packet's outgoing channel as-is (hop.Exit, since none is selected yet) and
carries the requested pubkey in OutgoingNodeID.

At the RPC boundary, forwardInterceptor.onIntercept maps a node-ID hop to
the reserved NodeIDForwardSCID sentinel in outgoing_requested_chan_id and
the pubkey in outgoing_requested_node_id, so a client switching on a zero
channel ID to detect the exit hop does not misread the forward as a final
receive. The sentinel is a wire-only concern, applied where the request is
built rather than in the switch's internal InterceptedPacket, which stays
truthful (OutgoingNodeID.IsSome() is the node-ID discriminator).

(cherry picked from commit 32373b76c7)
2026-07-30 12:39:22 -03:00
bitromortac
47a5449258
htlcswitch: classify a node-ID forward as a forward event
Now that the switch forwards blinded hops identified by node ID, a new
problem surfaces in the HTLC event stream. A node-ID next hop has no
outgoing short channel ID until non-strict forwarding selects one, so a
forward that fails before selection still carries outgoingChanID ==
hop.Exit. getEventType keys the exit hop off that sentinel, so it
misclassifies such a failed node-ID forward as a receive, mislabeling the
event streamed via SubscribeHtlcEvents (a forwarding failure reported as
a receive failure).

Two paths reach getEventType before an SCID is selected: the fail packet
built by failAddPacket and the resolution packet built by resolve, both
of which dropped the decoded next hop. Carry outgoingHop into both, and
classify a Right (node-ID) outgoingHop as a forward before the hop.Exit
check. A node-ID next hop is always a forward, never the exit hop.

(cherry picked from commit a4844ef522)
2026-07-30 12:39:22 -03:00
bitromortac
9a2c868665
htlcswitch: forward node-ID blinded hops via non-strict forwarding
Fixes lightningnetwork/lnd#10937: forward a blinded-route payment when the
recipient identifies the next hop by node ID rather than a short channel
ID. The htlcPacket carries the decoded next hop to the switch, whose
handlePacketAdd resolves the pubkey to the peer's links via getLinks() and
lets the existing non-strict forwarding logic load-balance across the
peer's channels.

outgoingChanID stays a ShortChannelID. It is the persisted CircuitKey and
is set to the selected channel after non-strict selection. The circular
route check filters candidate channels before selection.

(cherry picked from commit dbc5704070)
2026-07-30 12:39:22 -03:00
bitromortac
97200d5610
htlcswitch/hop: decode next_node_id blinded hops
Some implementations (e.g. Core Lightning) identify the next hop in a
blinded route by the next node's ID (next_node_id) instead of a short
channel ID. Decode such a hop into a node-ID next hop, the Right of
ForwardingInfo.NextHop, holding the next node's public key. The switch
resolves that key to one of our channels with the peer in a later commit.

BOLT 4 requires a non-final blinded hop to carry exactly one of
short_channel_id or next_node_id, so a hop that sets both is rejected.

(cherry picked from commit 4fd4289a08)
2026-07-30 12:39:22 -03:00
bitromortac
f8d8ba6d44
multi: represent the blinded forwarding next hop as an fn.Either
The forwarding next hop is currently always a short channel ID. To allow a
blinded route to identify the next hop by node ID instead, change
ForwardingInfo.NextHop to fn.Either[lnwire.ShortChannelID, [33]byte], where
the Left is the outgoing channel ID and the Right (wired up in a follow-up
commit) is the next node's public key.

This commit is a pure representational change with no behavioural effect:
every next hop is still a channel ID. The Either is encapsulated behind
ForwardingInfo methods so callers never destructure it directly: IsExit()
is the single source of truth for exit-hop detection (used by the link and
the contract court) and NextHopChannel() yields the outgoing SCID.

(cherry picked from commit d28a71765b)
2026-07-30 12:38:43 -03:00
bitromortac
9e1f98ed53
lnrpc/routerrpc: add outgoing_node_id to HTLC intercept request
A blinded route may identify the next hop by node ID (next_node_id) rather
than by channel, in which case there is no sender-specified outgoing channel
to report to an HTLC interceptor. Add an outgoing_node_id field to
ForwardHtlcInterceptRequest to carry the next hop's public key for these
forwards, and document that outgoing_requested_chan_id then holds a reserved
sentinel value so that clients switching on a zero channel ID to detect the
exit hop do not misclassify the forward as a final receive.

This commit only adds the schema and regenerated stubs; the fields are
populated by later commits.

(cherry picked from commit 14640a5016)
2026-07-30 12:36:50 -03:00
bitromortac
86eeacc3ae htlcswitch: key the aux traffic shaper on the evaluated channel
During non-strict forwarding, handlePacketAdd evaluates every candidate
channel to the next peer and calls CheckHtlcForward with the sender-requested
outgoing SCID (originalOutgoingChanID) for each candidate. That SCID flowed
through canSendHtlc into AuxTrafficShaper.ShouldHandleTraffic, so a
channel-keyed shaper was asked about the requested channel rather than the
candidate actually being evaluated. With parallel channels to a peer this
inspects the wrong channel.

Key the shaper on l.ShortChanID() (the channel under evaluation) instead.
originalScid is retained solely for createFailureWithUpdate / FailAliasUpdate,
so the alias-aware channel_update returned to the sender is unchanged and the
real SCID handed to the shaper never leaks onto the wire.

(cherry picked from commit b166780015)
2026-07-30 12:31:26 +00:00
ziggieXXX
c863397a4f
Merge pull request #10953 from ziggie1984/bump-v0.20.2-final
build: bump version to v0.20.2
2026-07-07 20:50:06 -03:00
ziggie
5e26b56067
build: bump version to v0.20.2 2026-07-07 07:08:59 -03:00
ziggieXXX
529bdb1a8b
Merge pull request #10935 from ziggie1984/bump-v0.20.2
build: bump version to 0.20.2-beta.rc1
2026-06-29 10:48:35 -03:00
ziggie
f4fa341e02
build: bump version to 0.20.2-beta.rc1 2026-06-29 07:51:35 -03:00