bifrost: retry the SOL scanner's initial slot fetch; drop the entrypoint Solana wait

Supersedes !4998 (closed)

Problem

wait_for_solana_rpc in build/scripts/bifrost.sh blocks bifrost startup until the configured Solana endpoint answers getSlot, in an until curl … sleep 1 loop with no timeout. It keys on BIFROST_CHAINS_SOL_RPC_HOST, which production sets, so the gate runs on every real deployment.

That gives one chain's RPC endpoint the power to take down all of bifrost: the loop only exits on a response containing "result", so an endpoint that is down, unreachable, or returning any error response blocks identically. While that holds, any bifrost that restarts for whatever reason sits at Waiting for Solana RPC: indefinitely and observes no chain at all. A Solana-only degradation escalates into missed observations on every connected chain, until the endpoint returns or an operator sets BIFROST_CHAINS_SOL_DISABLED: "true". Externally this is hard to diagnose: the process is up but never binds :6040, so gateways report 502 and per-chain health has no series to alert on.

What the wait was covering for

Two things, and they deserve different fixes.

A real defect in the SOL scanner. SOLScanner.Start() fetched the initial slot once and returned on error. Start runs once as a goroutine and nothing restarts it — so without the entrypoint wait, a bifrost that starts while the Solana RPC is briefly unavailable silently loses SOL observation for the life of the process: one log line, every other chain running normally. This is unlike every other chain client (constructors make no fatal network calls, and scanners retry at runtime), and it is presumably why the entrypoint gate felt necessary: an unbounded global wait sat in front of a silent per-chain death.

A mocknet orchestration race. The wait was introduced in !4696 (merged) alongside that MR's mocknet compose and e2e work: mocknet runs a local solana test-validator container that bifrost races at compose-up, and the wait de-flaked that race. A real need — but it belongs to mocknet's orchestration, not to the production entrypoint.

Changes

  • SOLScanner.Start() retries the initial slot fetch on its scan interval until the RPC answers or the scanner is stopped (waitForInitialSlot, unit tested). An unavailable RPC at startup now behaves like an unavailable RPC at runtime — retried, not fatal — matching every other chain client. A down Solana endpoint then degrades exactly like any other chain outage: SOL alone goes unhealthy and recovers when the endpoint does.
  • wait_for_solana_rpc is deleted from the entrypoint (deletion-only there). With the scanner retrying, the wait serves no purpose in any environment: mocknet bifrost simply begins scanning when the local test validator comes up, exactly as it already does for every other mocknet daemon. BIFROST_CHAINS_SOL_DISABLED keeps its normal meaning for the bifrost process itself.
  • Minimal compose fix: bifrost-cat/fox/pig gain the - solana depends_on entry the main bifrost service already has — they inherit BIFROST_CHAINS_SOL_RPC_HOST through the environment anchor but never depended on the service at all. Plain start-ordering, list form; no healthcheck or condition semantics introduced.

wait_for_tss_bootstrap_peer is deliberately untouched: production renders it a no-op (PEER is set empty there, and the config falls back to bootstrapping TSS p2p from the seed list), and mocknet-cluster still uses it (PEER: bifrost).

Testing

  • waitForInitialSlot unit tests are executed and passing: immediate success makes exactly one call with no delay; transient failures retry until success (call count asserted); a stop signal during the backoff aborts promptly and reports not-ok.
  • docker compose config validates for both the mocknet and mocknet-cluster profiles.
  • The entrypoint change is deletion-only; bash -n clean; no references to wait_for_solana_rpc remain in the tree.
  • The e2e suites are the authoritative test for mocknet startup behavior and can only run in this project's CI. Note on the pipeline: the fork-validation job cannot run for outside contributors (no runners on the fork, and tss-lib-private is not accessible to a fork's CI token), so a failed fork pipeline reflects infrastructure, not this change.
Edited by Dwarf

Merge request reports

Loading
Loading