Each block range is streamed over one gRPC connection into a channel
that a worker thread drains, encodes, and scans. That channel was
unbounded, so when the server delivered blocks faster than the
scanner consumed them the backlog piled up in memory with no ceiling
- on a fast link against a large range it could grow without limit.
- The channel is now a bounded synchronous channel holding at most
2048 blocks. When it fills, the fetch side waits, applying
backpressure up the stream instead of buffering endlessly, so peak
memory is capped no matter how far ahead the server runs.
- The batch size is untouched: it still streams a whole range over a
single connection, which is what keeps the connection count low
enough to avoid socket-buffer exhaustion on Windows. Only the
in-flight depth between fetch and scan is now bounded.
The same blocks are fetched and scanned in the same order, so the
resulting wallet is byte-identical, verified against the differential
harness. The wallet file format is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>