Skip to content

fix(network): route block-pinned requests to a fallback that has the block - #27

Closed
shpookas wants to merge 4 commits into
feat/websocket-supportfrom
fix/tip-leader-fallback-routing
Closed

shpookas wants to merge 4 commits into
feat/websocket-supportfrom
fix/tip-leader-fallback-routing

Conversation

@shpookas

@shpookas shpookas commented Sep 29, 2026 •

Copy link
Copy Markdown

Closed.

…block

When a request is pinned to a block above every routed upstream's known
head, try the tier:fallback upstreams whose head already reached it first,
then the routed list. A fallback's newHeads subscription keeps its poller
current, so it is often the source that announced the block to clients.
Without this the routed upstreams answer missing data first and the request
only reaches the fallback through the escape, if at all.

Uses the per-request escalation, so the escape does not fire again. No-op
when any routed head is unknown or already at the block, for consensus, and
when failover is off. Counted in erpc_network_tip_leader_route_total.
…calation

The hedge keeper kept an ErrUpstreamsExhausted whose causes are all missing
data, on the basis that no sibling leg can do better. Once the request has
escalated to the fallbacks that no longer holds: the escalated leg may still
be waiting on a fallback that has the data, while a later leg, with the
escalation already spent, only re-sweeps the routed upstreams, misses again,
and cancels it. Seen as "missing data" errors with hedges:1 on chains where
a fallback announces heads first.

Keep racing when the request escalated and no fallback appears among the
causes yet. If every leg finishes this way the hedge still returns the last
result.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Leader selection can bypass routing constraints or leave fallbacks untried, and a hedge can still cancel a successful fallback attempt.

Review effort: Balanced
Findings: 4 Medium severity

Open (4)
What changed in this PR

This PR aims to serve block-pinned EVM requests from a fallback that has reached the requested block before trying lagging routed upstreams. It also changes hedge handling so a missing-data result does not prematurely end a fallback attempt.

Changes:

  • Add tip-leader routing and a metric for its use.
  • Adjust hedge handling and add failover tests.
  • Document the routing behavior and metric.
File Description
telemetry/​metrics.go Defines the tip-leader routing counter.
erpc/​networks.go Selects ahead-of-tip fallbacks before routed upstreams.
erpc/​networks_tip_leader_test.go Tests leader routing and hedge behavior.
erpc/​networks_failover_escape_test.go Updates the escape fixture and test scenario.
erpc/​network_executor.go Changes which missing-data hedge results are kept.
docs/​pages/​reference/​metrics.mdx Lists the new counter.
docs/​pages/​config/​projects/​networks.mdx Describes tip-leader routing.
common/​request.go Exposes the request’s fallback-escalation state.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread erpc/network_executor.go Outdated
Comment thread erpc/networks.go
Comment thread erpc/networks.go Outdated
Comment thread erpc/networks.go Outdated
- Hedge keeper: once the request escalated, never keep an all-missing
  result. ErrorsByUpstream is request-wide, so a fallback that already
  missed does not mean none is still working; the hedge still returns the
  last result if every leg misses.
- Tip-leader routing no longer closes the escape: the sweep that took the
  escalation for its leaders still escapes, once, to the fallbacks it has
  not tried (e.g. an HTTP fallback whose 5m poller trails the block).
- Check every routed upstream's head, fallback-tier ones included, and drop
  the default-tier count guard.
- Only fallbacks allowed by the request's use-upstream selector can lead.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

A future-block short-circuit can still return null before a ready fallback is tried, and the concurrent routing change warrants final human review.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
Resolved since last review (4)

Comment thread erpc/networks.go
Comment thread docs/pages/config/projects/networks.mdx Outdated
With served-tip on, tryShortCircuitFutureBlock answers a numbered
eth_getBlockByNumber above every eligible head with null before the sweep.
A fallback the policy keeps out of that set can already have the block (the
tip-leader case), so with failover on, skip the short-circuit when a
selector-allowed fallback's head has reached it. Shares the fallback lookup
with tip-leader routing.

Docs: the sweep that routes to tip leaders still escapes once to untried
fallbacks; only other legs and retries do not.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The future-block exception can bypass a valid null for consensus requests or for fallbacks whose configured availability excludes the block.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (2)

Comment thread erpc/networks.go
}
// A fallback the sweep can still reach may already have it while the
// policy keeps it out of the eligible set.
if n.cfg.Failover.Enabled() && len(n.fallbacksAtBlock(ctx, req, method, bn, nil)) > 0 {
Comment thread erpc/networks.go
Comment on lines +3764 to +3766
if _, ok := skip[fb.Id()]; ok || upstreamLatestBlock(fb) < bn {
continue
}
@shpookas shpookas closed this Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants