fix(network): add block sync congestion control#288
Conversation
4119bd9 to
b06c085
Compare
6195c51 to
224c828
Compare
b06c085 to
18eac76
Compare
224c828 to
96789ea
Compare
96789ea to
6a23ba8
Compare
6a23ba8 to
00fe3fd
Compare
18eac76 to
a7e79f3
Compare
|
fixing conflicts now |
|
@evan-forbes sorry, saw your message later and frontran you a bit |
|
all good! thanks |
p0mvn
left a comment
There was a problem hiding this comment.
LGTM. Focused on grasping the concepts and dependencies in this review as opposed to bug-finding
| download_floor: block::Height, | ||
| start_height: block::Height, | ||
| ) -> RequestPriority { | ||
| if start_height <= floor_rescue_high(download_floor) { |
There was a problem hiding this comment.
Why is this <= and not ==?
Can't we be rescuing bodies that have already been downloaded?
There was a problem hiding this comment.
ahh no inherently a rescue means we haven't downloaded the block. we got a timeout and need to re-request from someone else
floor_rescue_high(download_floor) is download_floor + 1 and download_floor means we've already downloaded
| /// [`MAX_BS_INFLIGHT_REQUESTS`]) only after sustained error-free responses (see | ||
| /// the streak-gated cubic ramp on `DownloadWindow`). In a homogeneous fleet this | ||
| /// is the per-peer concurrency ceiling every peer offers. | ||
| pub const DEFAULT_BS_MAX_INFLIGHT: u32 = 32000; |
There was a problem hiding this comment.
Why is this value so high? Is it even realistic?
There was a problem hiding this comment.
yeah totally, so the reasoning was our timeout here is 8s. with congestion control we're ideally maximizing a peer's throughput to the point where they have 8s of congestion at any moment. so our buffer is ~4k blocks. if we want to keep the buffer filled over 8s then that's 32k. that's at least the reasoning.
I've seen it hit 22-26k before
| /// | ||
| /// This is the hard ceiling the default advertisement ([`DEFAULT_BS_MAX_INFLIGHT`] | ||
| /// = 32,000) is clamped to, and also the per-peer outstanding-request safety bound | ||
| /// (`EFFECTIVE_BS_OUTBOUND_INFLIGHT_PER_PEER`). It bounds how many concurrent | ||
| /// requests a remote peer can make us hold against it, so it doubles as a DoS bound. | ||
| pub const MAX_BS_INFLIGHT_REQUESTS: u32 = 32_768; |
There was a problem hiding this comment.
Why not have a single DEFAULT_BS_MAX_INFLIGHT? Is 768 value difference between them meaningful?
There was a problem hiding this comment.
having a bit of overflow here is good just in case we're completely maxed out and need to rescue. its a good point though perhaps it should be even bit higher
| pub const DEFAULT_BS_REQUEST_TIMEOUT: Duration = Duration::from_secs(8); | ||
| /// Default central floor-watchdog cadence. | ||
| pub const DEFAULT_BS_FLOOR_WATCHDOG_TICK: Duration = Duration::from_secs(1); |
There was a problem hiding this comment.
Big fan of reducing dependency on timeouts in the upcoming work
Follow-ups from review of the merged block-sync throughput stack (#284, #286, #287, #288, #289): - sequencer: drop the redundant 500ms timer-driven floor-starvation shed. Floor rescue is already demand-driven (inline after each accepted body, plus the synchronous FundFloorReservation path), so the periodic backstop was a pure fixed-cadence poll. - reactor: make the floor watchdog event-driven. Arm a sleep to the earliest outstanding floor-claim deadline instead of polling on a fixed tick, mirroring the per-peer routine's own-timeout arm. Removes the floor_watchdog_tick config knob. - consensus/state: rename consensus.disable_vct_fast_sync -> consensus.vct_fast_sync (default true) to remove the double negative. Mirror updated in state config, docs, and CHANGELOG. - work_queue: debug_assert the take_in_range_budgeted precondition (positive count, low <= high) instead of silently returning empty. - block_sync: reword refactor-historical comments ("ported from", "verbatim", "matches the previous", "used to") to describe current behavior. AI-assisted: implemented with Claude Code (Opus 4.8).
Motivation
This is the fifth block-sync PR in the stack. It adds the admission, queueing, and transport budget controls needed to keep block-sync scheduling bounded under pressure.
Solution
Scope boundary:
Tests
Passed locally on the rebuilt split stack:
git diff --check origin/review/headersync-roots..review/blocksync-throughput-defaultscargo fmt --all -- --checkcargo test -p zebra-network zakura::block_sync --lib(146 passedon the final stack tip)cargo test -p zebra-network p2p_v2_block_sync_config_validation_rejects_degenerate_values --libAttempted but blocked by the local toolchain before test execution:
cargo test -p zebrad --test acceptance latest_config_is_stored -- --nocapturelibrocksdb-sysC++ compilation fails on RocksDB headers usinguint64_twithout<cstdint>.Specifications & References
Stack context:
review/blocksync-floor-priorityFollow-up Work
Throughput-default tuning is stacked above this PR. Sequencer-owned apply remains for the later refactor PR.
AI Disclosure
PR Checklist
type(scope): description