fix: isolate proof submits onto a dedicated validator connection

Problem (gh-18 / QUI-829)

A colocated single-validator miner mined valid solutions but landed none — every submit_proof failed, proofs_won stuck, all health signals green.

The submit broadcast (pool_client.submit_signed_extrinsic) shared the ValidatorPool active handle with the get_mining_snapshot poll that runs on every new head. The single-URL pool fast-reconnects on any transient socket blip (rc43, 65a4fb4), so a snapshot-driven swap shut the active handle down while a submit was in flight, cancelling it. A submit spans the ~90s watch-timeout while the connection swaps every 1–2 min, so every submit crossed a swap and died; replay re-entered the same window → 0 wins.

Fix

  • Route submit_signed_extrinsic through a dedicated write handle (ValidatorPool.send_write) that read-path (snapshot) swaps never touch.
  • Submits are rare, so the write handle is created lazily and its idle/stale socket is health-reconnected on demand; writes serialize on a write lock. A connection failure during the submit still raises ValidatorSwapped so the caller re-signs with a fresh nonce.
  • Add pool.last_successful_submission, surfaced on /api/v1/status, so a node that mines but never lands a proof is diagnosable instead of silently reporting is_mining=true.

Tests

  • 4 new tests in test_validator_pool.py, including test_read_swap_does_not_teardown_inflight_write which reproduces the QUI-829 race (concurrent read swap while a submit is in flight) and asserts the submit survives.
  • 30 pool + 203 submit/controller/telemetry tests pass; ruff clean.

Closes gh-18 / QUI-829.

Merge request reports

Loading