[v0.20.x-branch] Backport #11163: htlcswitch: reconcile resumed forward replays - #11187
Conversation
|
Please cherry-pick the changes locally and resolve any conflicts. git fetch origin backport-11163-to-v0.20.x-branch
git worktree add --checkout .worktree/backport-11163-to-v0.20.x-branch backport-11163-to-v0.20.x-branch
cd .worktree/backport-11163-to-v0.20.x-branch
git reset --hard HEAD^
git cherry-pick -x 5040780870ffe9f538c1e838e85c7bb22b46e131 a8662b58624bb3bb718ec46849da9fca658688af bb916e5f9ddd855802fee998e94d47c8218946ff
git push --force-with-lease |
In this commit, we let the switch reconcile replayed adds whose incoming circuit has already been committed. Once the interceptor resumes a forward, the switch commits its incoming circuit and removes the packet from the held set. If the incoming link then replays that add before the return packet is committed, the packet can be offered to the interceptor a second time. The circuit map still distinguishes in-memory duplicates from circuits restored during recovery. Fresh packets continue through the normal interception path. (cherry picked from commit 5040780)
In this commit, we recognize held duplicates before applying the current-height expiry check. The original held forward keeps its resolution handle and auto-fail deadline. This prevents a near-expiry replay from failing upstream while the interceptor can still resume the outgoing HTLC. The regression test verifies that the original handle opens and settles exactly one circuit. (cherry picked from commit a8662b5)
In this commit, we add the public PR to the 0.20.5 and 0.21.4 release notes. The note calls out that incoming-link replays are reconciled after the interceptor resumes a forward, so operators know the duplicate interception behavior is fixed. (cherry picked from commit bb916e5)
4ed9002 to
e903ccf
Compare
Re-applied the backport cleanlyThe previous state of this branch was a single squashed
I force-pushed a re-applied version: all three upstream commits cherry-picked What applied cleanly vs. what needed resolution
8 of 10 file-changes applied cleanly. The two conflicts are detailed below so Conflict 1 —
|
🔴 PR Severity: CRITICAL
🔴 Critical (1 file)
🟢 Low (6 files)
AnalysisThis is a backport of a fix to Given this touches the interceptor's replay/resume handling directly, it To override, add a |
Backport of #11163
Change Description
In this PR, we make resumed forward-interceptor HTLCs idempotent across
incoming-link replays.
Once an interceptor resumes a forward, the switch commits its incoming circuit
and removes the packet from the held set. If the incoming link restarts before
the return packet is committed, it can replay the add. Treating that replay as a
new intercepted forward can fail the incoming HTLC while the original outgoing
HTLC remains live.
For replayed adds that already have a circuit, we now pass the add back through
the switch and wait for the circuit map to classify it before releasing the
incoming link. Fresh adds and unresolved replays still use the asynchronous
interceptor path, so a blocked interceptor callback doesn't stall the link.
We also check the held set before applying the current-height expiry cutoff. A
held replay keeps the original resolution handle and auto-fail height instead of
making a second expiry decision.
Steps to Test
Run the focused forward-interceptor tests:
Run the package tests and vet with the development build tag:
go test -tags dev ./htlcswitch -count=1 go vet -tags dev ./htlcswitchRun the two replay regressions under the race detector:
Pull Request Checklist
Testing
Code Style and Documentation
lnclicommands.