fix: Restart the timer when reviving a timed-out TX-set acquisition - #8090
Open
bthomee wants to merge 1 commit into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes transaction-set acquisition revival by restarting the retry timer after timeout.
Changes:
- Documents revival behavior.
- Restarts timers only for failed acquisitions.
- Adds regression tests for revival and timer preservation.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Summary | Review findings |
|---|---|---|
src/xrpld/app/ledger/detail/TransactionAcquire.h |
Documents stillNeed() behavior. |
None. |
src/xrpld/app/ledger/detail/TransactionAcquire.cpp |
Clears failure state and restarts the timer when needed. | None. |
src/test/app/TransactionAcquire_test.cpp |
Tests revival and timer behavior. | Moderate (2 votes): test does not exercise timer exhaustion. Nit (2 votes): add “that” to the comment. |
Suppressed comments (1)
src/xrpld/app/ledger/detail/TransactionAcquire.cpp:287
failed_is also set for terminal map-invalid outcomes (for example whentrigger()observes an invalid SHAMap), not only for timeout exhaustion. Clearing it here lets a later consensus lookup re-arm an acquisition whose map is permanentlyInvalid, contrary to the SHAMap contract that such a map cannot be repaired by retrying; it can briefly process more peer data and schedule unnecessary work. Track timeout-origin failure separately, or gate revival on the timeout failure state, and only clearfailed_for that case.
if (!failed_)
return;
failed_ = false;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 23, 2026 23:45
eb45241 to
828e84f
Compare
bthomee
added a commit
that referenced
this pull request
Aug 24, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
2 times, most recently
from
August 24, 2026 14:32
828e84f to
534820c
Compare
bthomee
added a commit
that referenced
this pull request
Aug 24, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 24, 2026 15:00
534820c to
1c983bd
Compare
bthomee
added a commit
that referenced
this pull request
Aug 24, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 24, 2026 15:24
1c983bd to
45e0595
Compare
bthomee
added a commit
that referenced
this pull request
Aug 25, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 25, 2026 15:02
45e0595 to
55e1648
Compare
bthomee
added a commit
that referenced
this pull request
Aug 25, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 25, 2026 19:36
55e1648 to
9bd7f12
Compare
bthomee
added a commit
that referenced
this pull request
Aug 25, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 25, 2026 19:48
9bd7f12 to
6b0d788
Compare
bthomee
added a commit
that referenced
this pull request
Aug 25, 2026
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 25, 2026 21:08
6b0d788 to
56dd655
Compare
TransactionAcquire::stillNeed() now restarts the retry timer whenever it revives an acquisition, so a revived object resumes asking instead of waiting for a peer to send data unprompted; expires_after() cancels any pending wait, so this can't leave two timer chains running. It still returns early when there's nothing to revive, so a running acquisition keeps the wait it already has. Tested by driving a real timeout chain to failure - cancel() alone never arms a timer, so reviving from it wouldn't prove a timed-out chain restarts - and confirming stillNeed() causes a request to go out again. Addresses Copilot review feedback on PR #8090.
bthomee
force-pushed
the
bthomee/shamap-invalid-11-revive-timer
branch
from
August 25, 2026 21:58
56dd655 to
ad2d244
Compare
bthomee
marked this pull request as ready for review
August 26, 2026 00:20
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Part 11/16 of a stack. Base: part 10 (
bthomee/shamap-invalid-10-header-ledger-mutable).High Level Overview of Change
TransactionAcquire::stillNeed()now restarts the retry timer whenever it revives a timed-outacquisition, so a revived object actually resumes asking peers instead of silently waiting for
unprompted data.
Context of Change
TransactionAcquire::stillNeed()restarts the retry timer whenever it revives an acquisition, so arevived object resumes asking rather than waiting for a peer to send data unprompted. Restarting is what
resumes it: the timer chain is what drives
trigger(), and a timed-out acquisition has none pending.expires_after()cancels any pending wait, so this cannot leave two chains running.It also returns early when there is nothing to revive, so an acquisition that is still running keeps the
wait it already has. Consensus asks for a set it still needs once per round, and re-arming on every ask
would push the next tick back each time, so a set asked for more often than the interval would never
tick at all.
Two cases cover the halves. The first drives a real timeout chain to failure —
cancel()alone neverarms a timer, so reviving from a faked failure would only prove a timer starts, not that a timed-out one
restarts — then revives it and checks a request goes out and data is examined again. The restart is
observed through a candidate peer that can only be re-offered by
onTimer()'s broadcast:RequestCountingPeerSetdedups by tracked id like the real peer set, soaddPeers()never re-offers apeer already selected, and a request reaching it again after
stillNeed()is what distinguishes anarmed acquisition from one whose failure flag was merely cleared. The second asks again faster than the
interval, the way a short consensus round would, and checks a tick still gets through.
API Impact
None of the checkboxes below apply: this is an internal
xrpldcorrectness fix with nolibxrpl,public-API, or peer-protocol surface.