Phase 6: live-miner verification + integration-bug fixes

Summary

Phase 6 end-to-end verification: stand up the full miner + telemetry stack against the docker chain, run for multiple blocks, and assert state stays correct. The act of doing so surfaced three integration bugs that the mocked unit tests couldn't see; this MR fixes them alongside the new tests.

Bug fixes

  • SubstrateClient concurrency: substrate-interface 1.8.1 isn't safe against concurrent calls from multiple tasks — the decoder corrupts mid-call and surfaces as No decoding class found for 'DigestItem' on /api/v1/status. Added an asyncio.Lock around every blocking call. The standalone faucet already used this pattern; lifting it into SubstrateClient covers the controller + telemetry server too.

  • Block JSON serialization: /api/v1/block/latest returned 500 with Object of type scale_info::17 is not JSON serializable because substrate-interface's get_block leaves raw ScaleType objects in the decoded dict. Added _to_jsonable walker in telemetry_api.

  • MinerCore stats wiring: controller had no link to MinerCore, so /api/v1/stats's total_blocks_attempted / total_blocks_won / wins_per_miner were stuck at zero in production. Added an optional core arg to the controller; quip_cli wires it.

  • Force-reseed difficulty: the chain's runtime tightens diversity / energy thresholds as proofs land. Long-haul tests fail after the smoke test mines its first block. Added BootstrapConfig.force_reseed_difficulty (default False) so tests can reset to the relaxed seed each run while the production CLI stays idempotent.

New tests

  • test_controller_long_haul_multi_block — mines ≥3 proofs, asserts no fatal errors and a non-zero MinerInfo.proofs_submitted on chain.
  • test_telemetry_reflects_live_miner_state — MinerCore + controller
    • TelemetryApiServer running together; polls every REST route and asserts both the legacy MinerCore fields and the new controller substats update once a proof has landed.

The existing test_controller_submits_proof_end_to_end was refactored to use a shared _live_controller async context manager.

Test plan

  • pytest tests/test_substrate_miner_controller.py -v — 12 passed
  • pytest tests/test_telemetry_live_miner.py -v — 1 passed
  • pytest tests/test_substrate_faucet.py -v — 4 passed (Phase 7 hybrid path)
  • Full suite: 304 passed, 3 unrelated metal_yielding flakes (environment-dependent GPU idle checks)

Merge request reports

Loading