fix(sync): replenish bounded header lookahead before the backlog drains - #1034
evan-forbes wants to merge 4 commits into
Conversation
Analyzed one file, diff |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 646fbd3814
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Give the refill batch one name so the window gate and the publication trigger cannot drift apart. State that the batch bound applies to the window rather than to the grant. Outstanding claims can leave less than a batch free, and the reactor still sends that smaller top-up to keep the body backlog supplied. Move the closed-to-open capacity test into its own predicate.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c0f1c2bbe2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Self::request_header_prefix_remaining(old, claimed_before, target) == 0 | ||
| && Self::request_header_prefix_remaining(new, claimed_after, target) > 0 |
There was a problem hiding this comment.
Wake cached targets when repair retirement frees the peer
When the only supplier is occupied by a VCT repair while the window still has some numeric capacity (for example, 500 credits with a 401-header repair claim), its ordinary target is cached but cannot be staged because the peer is already active. The next verified-generation update retires that repair and frees both the peer and its claim, but this predicate sees a positive-to-positive capacity change and does not reconsider the target, delaying refill until another peer status arrives (30 seconds by default). This is distinct from the earlier claim-ordering case: the fresh failing condition is that peer availability changes while capacity never reaches zero, so retirement should also wake cached work when it frees an occupied peer.
Useful? React with 👍 / 👎.
| let target = status.selected_tip_height; | ||
| Self::request_header_prefix_remaining(old, claimed_before, target) == 0 | ||
| && Self::request_header_prefix_remaining(new, claimed_after, target) > 0 |
There was a problem hiding this comment.
Validate target height before using the partial-target wakeup
When an untrusted peer advertises selected_tip_height one block above the local tip while selected_tip_hash actually names a longer target, the partial-target exception grants one header even though the window lacks a full batch. After the peer returns a valid incomplete page and one body is verified, this predicate trusts the same unauthenticated height to wake the target again; the peer can therefore force repeated one-header preparation and durable-admission cycles instead of the intended 401-header coalescing. Validate the advertised height against the response ancestry when that inconsistency becomes observable, or exclude unverified partial targets from sub-batch wakeups.
AGENTS.md reference: AGENTS.md:L149-L149
Useful? React with 👍 / 👎.
…ns (#1136) * fix(sync): restore header continuation capacity as credits return (cherry picked from commit e9f47af) * docs: record header continuation capacity fix (cherry picked from commit 71aa7f9) * fix(sync): replenish bounded header lookahead before the backlog drains (cherry picked from commit 00d0429) * docs: record bounded header refill policy (cherry picked from commit 646fbd3) * refactor(sync): name the refill batch and the refill wake predicate Give the refill batch one name so the window gate and the publication trigger cannot drift apart. State that the batch bound applies to the window rather than to the grant. Outstanding claims can leave less than a batch free, and the reactor still sends that smaller top-up to keep the body backlog supplied. Move the closed-to-open capacity test into its own predicate. (cherry picked from commit 46c3879) * fix(sync): wake header refill after retiring repair claims (cherry picked from commit c0f1c2b) * docs: merge changelog fragments into #1136 Combine the #1032 and #1034 changelog fragments into one, named after the PR that supersedes them, and point the params.md row at #1136. * fix(sync): keep header capacity charged through local operations Address the v12 audit findings F-288244 and F-288245 and a review comment on the refill wakeup: - Prepare and apply operations now retain their capacity leases until their completion callbacks run, so a disconnected supplier cannot release credits while its local validation still holds the headers. - Port completion handling now observes the latest committed snapshot before the reactor handles another event, so another request cannot reuse released credits against the old header lead. - Snapshot refill wakeups now reconsider only the targets whose capacity reopened, instead of querying locators for every cached target. --------- Co-authored-by: Adam Tucker <adamleetucker@outlook.com>
Motivation
Header sync waits for admitted header lead to fall from 4,000 to 2,000 before refilling. In a traced checkpoint interval at heights 1.4M–1.5M, the node held 2,733 downloaded bodies against 2,856 admitted headers on average, despite keeping all 401 verifier submissions occupied. Most unused backlog capacity had no admitted header to download.
Keep the backlog supplied as block execution becomes faster. This change does not claim a measured throughput gain.
Solution
The active header graph is memory-resident. The design therefore retains explicit bounds rather than assuming disk-backed headers have negligible memory cost.
Stacked on #1032. This policy supersedes #1016's 2,000-header publication threshold; the combined stack must resolve that overlap explicitly and preserve its moving-headroom regression intent.
Testing
The current genesis run remains the baseline. More frequent header transitions may cost CPU. The experiment plan requires matched checkpoint-only comparisons, full backlog distributions, stage latency, RSS, graph growth, and a throughput regression gate before acceptance.
Specifications & References
Implementation and experiment plan
Follow-up Work
Integrate with the combined stack, resolve the #1016 policy overlap, and run the bounded-refill comparison after the baseline completes. The separate large-body delivery deficit still requires congestion and bandwidth diagnosis.