fix: don't feed external miners stale jobs during initial sync - #669
Merged
Conversation
At startup is_major_syncing() is still false and the offline check had a 30s grace period, so the mining loop broadcast a job built on the stale local best block before sync engaged. The protocol has no cancel message and the stored job was never cleared, so external miners — including ones connecting mid-sync — ground that job at full hashrate for the entire sync, with every result discarded as stale. Pause mining immediately when the node has no peers (the grace period is what opened the startup window; with external mining a pause is nearly free), and clear the stored job when pausing for major sync so miners connecting during the sync receive no work until a fresh post-sync job is broadcast.
n13
commented
Aug 14, 2026
n13
left a comment
Collaborator
Author
There was a problem hiding this comment.
Verdict: APPROVE (opinion; GitHub does not permit approving one's own PR).
No blocking findings.
The zero-peer gate now prevents the normal startup window from broadcasting a stale local candidate, and the major-sync path clears the stored server job once the worker invalidates the active build. I traced the worker-version transition through handle_external_mining, confirmed stale results remain rejected and seal submission remains re-verified under the build lock, and checked the documented limitation that the current wire protocol cannot cancel work already held by connected miners.
Validation:
cargo +nightly fmt --all -- --check— passed.SKIP_WASM_BUILD=1 cargo test --locked -p quantus-node miner_server -- --nocapture— passed, 10 tests (includingclearing_the_current_job_stops_serving_it_to_new_miners).SKIP_WASM_BUILD=1 cargo clippy --locked -p quantus-node --all-targets --no-deps— passed; only existing unrelated workspace warnings were emitted.git diff --check 37ac3db8...2908c749— passed.- Live CI at
2908c74950c1e8e763161460dd71f75cefa85886— format, Linux/macOS check-and-test matrix, and Clippy/doc jobs all successful.
illuzen
approved these changes
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human overview
Fixes bug where miner runs at 100% capacity the entire time a node is syncing (on a stale / invalid job that's never canceled)
Error mode
A GUI/CLI miner shows a full, real hashrate while its node is still deep in major sync (e.g. block 51k of 878k). It is not a test mode — the miner is genuinely hashing, but on a job that can never produce a block:
is_major_syncing(), but at startup that is stillfalsebefore the first peers connect, and the no-peers check had a 30-second grace period that let mining proceed. The loop therefore broadcast job 1 — built on whatever stale local best block the node had — one second after spawn (⛏️ Broadcasting job 1right after⛏️ QPoW Mining task spawned).Ready/NewJob/JobResult. When sync engages the node just stops sending new jobs, so miners grind the last job indefinitely at full hashrate.MinerServerstores the last broadcast job and hands it to every newly connecting miner; it was never cleared, so a miner connecting mid-sync immediately received the pre-sync job.Every seal found this way is discarded (
Received stale result from miner … ignoring, plus the seal re-verification under the build lock), so the only damage is hours of wasted work — but it makes syncing nodes look like they are mining.Fix (minimal)
offline_since/OFFLINE_GRACE_PERIODmachinery (net −16 lines).MinerServer::clear_current_job), so miners connecting during a sync receive no work until the first post-sync broadcast.Already-connected miners that hold a job when a sync begins still grind it until superseded — stopping them would need a cancel message in the wire protocol (ALPN bump), out of scope here.
Testing
clearing_the_current_job_stops_serving_it_to_new_miners.cargo test -p quantus-nodeminer_server suite passes;cargo +nightly fmt --checkclean.