Context
Since the multi-source block ingestion redesign (PR), MultiSource fans new-height announcements from N core endpoints into one channel, and the Listener fetches each block from the source that announced the height first (GetSignedBlockFrom). Announce speed is used as a per-height freshness signal for "most responsive peer". There is deliberately no fallback inside the fetch: a failed fetch stores nothing, so the duplicate announcement of the same height from another source retries it (resilience is a property of the fan-in).
This works well when announce speed correlates with serve speed. The hole is a source where it doesn't.
Problem
A source can be the fastest to announce (low RTT to the bridge) while being slow or unable
to serve blocks (overloaded, rate-limited, flaky transport). Routing follows the announcement,
so every height is first attempted against the bad source:
t=0.0 source Y announces H (always first - lowest RTT)
t=0.05 source X announces H (duplicate, queued)
t=0.0 listener fetches H from Y ...
t=10.0 ... blockFetchTimeout, nothing stored
t=10.0 listener picks up X's duplicate, fetch succeeds in ~0.2s
→ ~10.2s per height at 6s block time
t=6.0 meanwhile Y has already announced H+1 — first again
The per-height retry works, but the system never learns: the next height routes to the same
bad source again. The listener is sequential, so each height costs up to blockFetchTimeout
(10s) before the healthy duplicate is even read.
Context
Since the multi-source block ingestion redesign (PR),
MultiSourcefans new-height announcements from N core endpoints into one channel, and the Listener fetches each block from the source that announced the height first (GetSignedBlockFrom). Announce speed is used as a per-height freshness signal for "most responsive peer". There is deliberately no fallback inside the fetch: a failed fetch stores nothing, so the duplicate announcement of the same height from another source retries it (resilience is a property of the fan-in).This works well when announce speed correlates with serve speed. The hole is a source where it doesn't.
Problem
A source can be the fastest to announce (low RTT to the bridge) while being slow or unable
to serve blocks (overloaded, rate-limited, flaky transport). Routing follows the announcement,
so every height is first attempted against the bad source:
t=0.0 source Y announces H (always first - lowest RTT)
t=0.05 source X announces H (duplicate, queued)
t=0.0 listener fetches H from Y ...
t=10.0 ... blockFetchTimeout, nothing stored
t=10.0 listener picks up X's duplicate, fetch succeeds in ~0.2s
→ ~10.2s per height at 6s block time
t=6.0 meanwhile Y has already announced H+1 — first again
The per-height retry works, but the system never learns: the next height routes to the same
bad source again. The listener is sequential, so each height costs up to
blockFetchTimeout(10s) before the healthy duplicate is even read.