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_rpcis 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_DISABLEDkeeps its normal meaning for the bifrost process itself.- Minimal compose fix:
bifrost-cat/fox/piggain the- solanadepends_onentry the mainbifrostservice already has — they inheritBIFROST_CHAINS_SOL_RPC_HOSTthrough 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
waitForInitialSlotunit 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 configvalidates for both themocknetandmocknet-clusterprofiles.- The entrypoint change is deletion-only;
bash -nclean; no references towait_for_solana_rpcremain 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-privateis not accessible to a fork's CI token), so a failed fork pipeline reflects infrastructure, not this change.