Skip to content

feat(archiver): bind the API before the source handshake; wire fallback RPC URLs - #1348

Open
DylanVerstraete wants to merge 2 commits into
fix/archiver-liveness-dfrom
fix/archiver-liveness-e
Open

DylanVerstraete wants to merge 2 commits into
fix/archiver-liveness-dfrom
fix/archiver-liveness-e

Conversation

@DylanVerstraete

Copy link
Copy Markdown
Contributor

Fifth PR of the archiver liveness audit (finding 8). Stacked on #1347#1346#1345#1344; retarget to usc-dev as those merge.

Changes

  • API up before any network handshake. The HTTP API and the health tracker bind right after the sled store opens, ahead of the ws/http/Creditcoin handshake, the canonical-anchor check and --backfill (which can run for hours). Probes and /roots* readers see the process the whole time. /ready answers 503 with source chain handshake not complete until the source identity is verified and pinned; chain_id and finalization_lag in /status are null until then (Health::set_source, OnceLock, second call ignored).
  • --rpc-fallback-urls (RPC_FALLBACK_URLS, comma-separated) feeds eth::Client::new_with_fallbacks on every dial: startup ws/http, backfill, reconnect. Block fetches then walk [primary, fallbacks…] on "not found" / transport errors, as the proof-gen server already does. If any fallback is unreachable (or on another chain) at dial time the archiver warns and continues with the primary alone, so a dead backup can never block startup or recovery.
  • Docs: the README and flag help no longer claim blocks are fetched over HTTP. The WS client carries both the newHeads subscription and the block/receipt fetches; the HTTP endpoint is used for head tracking and the anchor check.

Verification

  • cargo test -p archiver -p continuity (36 archiver tests, 1 new: not ready before the handshake even with a fresh head, ready after set_source, second set_source ignored), clippy -D warnings, fmt.
  • Fake RPC whose WS eth_chainId takes 20 s: during the handshake /status → 200 {chain_id: null, ready: false, not_ready_reasons: ["source chain handshake not complete", "source head never observed"]}, /ready → 503, /roots/latest{"latest_block": null}.
  • reth --dev with --rpc-fallback-urls http://127.0.0.1:1,http://127.0.0.1:18845: dial with fallback RPCs failed, retrying with the primary only: Failed to connect to fallback RPC URL #0 …, then starting archiver and normal archiving. With only the live fallback: starts cleanly, anchor check passes.

@cursor

cursor Bot commented Sep 11, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes startup ordering and readiness semantics operators rely on, and adds multi-endpoint RPC dialing with timeout/retry behavior on every connect path.

Overview
Starts the HTTP API immediately after opening the sled store, before WS/HTTP/Creditcoin handshake, canonical anchor, or --backfill, so /status and /roots* stay reachable during long startup. /ready stays 503 with source chain handshake not complete until chain identity is pinned and finalization lag is known; chain_id and finalization_lag in /status are null until then via Health::set_source and a one-time OnceLock.

Adds --rpc-fallback-urls / RPC_FALLBACK_URLS: a shared dial() helper (with rpc-timeout-secs) uses fallback RPCs on startup, backfill, and reconnect; if fallback dial fails, it warns and retries primary only so bad backups cannot block startup. README/flag help now state blocks/receipts load on WebSocket (with fallbacks on not-found/transport errors); HTTP is for head tracking and anchor checks.

Reviewed by Cursor Bugbot for commit 407204c. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 19ddb4e. Configure here.

Comment thread archiver/src/main.rs Outdated
Comment thread archiver/src/main.rs
…ck RPC URLs

Audit finding 8.

- The HTTP API and the health tracker now come up right after the store
  opens, before the ws/http/Creditcoin handshake, the anchor check and
  --backfill. Probes and /roots readers can see the process during all of
  those (a backfill can run for hours). /ready answers 503 with
  'source chain handshake not complete' until the source identity is
  verified and pinned; chain_id / finalization_lag in /status are null
  until then.
- --rpc-fallback-urls (RPC_FALLBACK_URLS, comma-separated) feeds
  eth::Client::new_with_fallbacks for every dial: startup ws/http,
  backfill and reconnect. If any fallback is unreachable at dial time the
  archiver warns and continues with the primary alone, so a dead backup
  can never block startup or recovery.
- README/flag docs no longer claim blocks are fetched over HTTP: the WS
  client carries both the subscription and the block/receipt fetches; HTTP
  is for head tracking and the anchor check.

Verified: against a fake RPC whose WS eth_chainId takes 20 s, /status is
200 (ready=false, reasons: handshake not complete, head never observed),
/ready 503 and /roots/latest answers during the handshake. Against
reth --dev with --rpc-fallback-urls http://127.0.0.1:1,<live>: warning
'retrying with the primary only', archiver starts and archives.
…nder a deadline

Bugbot follow-ups on #1348:
- health.set_source now runs as soon as the identity is verified, pinned
  and the finalization lag is known, before the anchor check and a
  possibly hours-long --backfill. Probes see the real startup phase (lag
  against the head) instead of a stale 'handshake not complete'.
- dial() runs both the with-fallbacks and the primary-only attempt under
  --rpc-timeout-secs. Alloy transports have no default timeout, so a
  black-holed fallback previously hung the handshake or a reconnect
  attempt forever. Verified with an unroutable fallback and a 3 s
  deadline: 'timed out after 3s dialing … with fallbacks', then primary
  only, archiver starts.
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.

1 participant