fix(windows-miner): KeyError on attestation[nonce] posts every attestation unsigned, blocking enrollment#7979
Open
Vyacheslav-Tomashevskiy wants to merge 2 commits into
Conversation
…nonce The no-helpers signing branch read attestation["nonce"], but the Windows attestation dict only carries the nonce under report. That KeyError is caught by the enclosing except, so the miner posts an attestation with no signature, no public_key and no signature_type - and because the raise happens inside the CRYPTO_AVAILABLE branch, the legacy sha512 fallback never runs either. The node then stores no signing_pubkey for that miner, and enrollment fails closed with ENROLLMENT_SIGNING_KEY_REQUIRED (ENROLL_ALLOW_UNSIGNED_LEGACY defaults to 0), asking the miner to re-attest with a signature it cannot produce. The Linux miner carries a top-level nonce, which is why the shared helper tolerates either spelling and why only Windows is affected. Reading report[nonce] makes the fallback produce byte-identical output to build_pipe_sign_message. MINER_SHA256 in the bootstrap .bat is re-pinned to match the edited file.
Contributor
Author
|
/claim RTC: RTCd1554f0f35576faf01d386a6be1c947f560dd0b7 |
Contributor
|
Welcome to RustChain! Thanks for your first pull request. Before we review, please make sure:
Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150) A maintainer will review your PR soon. Thanks for contributing! |
setup_miner.py is the second place that pins the Windows miner digest (the bootstrap .bat is the first, already re-pinned in this branch). The nonce fix changed rustchain_windows_miner.py, so the setup_miner pin went stale: download_miner() fetches the file from main and verifies it against this constant, so a Windows install would abort on a checksum mismatch. tests/test_setup_miner_downloads.py caught it. Linux/Darwin pins are unaffected and left untouched.
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.
Problem
attest()builds the attestation with the nonce underreport— there is no top-level copy:The signing fallback then reads a key that does not exist:
The
exceptbelow it swallows theKeyErrorand falls through unsigned:Because the raise happens inside
if CRYPTO_AVAILABLE and self.keypair:, theelse:legacy-sha512 fallback never runs either — so the POST carries nosignature, nopublic_key, nosignature_typeat all.Why this is worse than a missing signature
The unsigned attest is accepted, but
record_attestation_success(..., signing_pubkey=pubkey_hex or None, ...)then stores nothing. Enrollment, meanwhile, signs fine (it never touchesattestation["nonce"]) and sendssignature+public_key— but the server looks up the stored pubkey, finds none, and withENROLL_ALLOW_UNSIGNED_LEGACYdefaulting to"0"fails closed:which is precisely what this miner structurally cannot do. The miner requires
status_code == 200, returns False, and never enrolls. A Windows miner in this state mines nothing, forever.Why only Windows, and why CI didn't catch it
The Linux miner sets a top-level
"nonce": noncealongsidereport["nonce"](miners/linux/rustchain_linux_miner.py:618), and macOS v2.5 sets both. That asymmetry is also whybuild_pipe_sign_messagereadsreport.get("nonce") or attestation["nonce"]— it tolerates either spelling, so the helper branch masks the bug. Only the Windows fallback hard-codes the spelling Windows doesn't use.And the fallback branch is the one a real install takes.
signing_helpers.pylives atminers/signing_helpers.py;rustchain_miner_setup.bat:7,10downloads onlyrustchain_windows_miner.pyandminer_crypto.pyinto a flat directory, and the PyInstaller spec shipshiddenimports=[]. So both imports fail,_SIGNING_HELPERS = False, and the broken branch runs. From a dev checkoutfrom miners.signing_helpers import ...resolves via implicit namespace packages, so it looks fine locally.The existing
test_windows_miner_signs_report_noncedoes not catch it because it setsminer_mod._SIGNING_HELPERS = True— it pins the masked path.requirements-miner.txtpinsPyNaCl>=1.5.0and the.batinstalls it, soCRYPTO_AVAILABLE and self.keypairis true on a default install: everyone lands in the broken branch.Fix
One line — read the nonce where this attestation actually keeps it:
This makes the fallback produce byte-identical output to
build_pipe_sign_messagefor the same attestation (both emitminer_id|miner|nonce|commitment), so the two branches can no longer drift. I did not add a top-levelnonceto match Linux: that would change the posted payload shape, and this keeps the diff to the defect. Happy to align the miners on one shape instead if you'd rather fix it at the source.Bootstrap hash
rustchain_miner_setup.batpinsMINER_SHA256of this exact file, verified both bycheck_bootstrap_hashes.pyin CI and by the installer itself at line 91 — an un-updated pin would make real installs refuse the fixed file. Re-pinned to1c25b32e…5d42;check_bootstrap_hashes.pyreports "Windows bootstrap hashes are in sync." The.batdiff is that one line, CRLF preserved.Tests
test_windows_miner_signs_when_signing_helpers_unavailable— the real-install branch (_SIGNING_HELPERS = False), assertingsignature/public_key/signature_typeare present and that the bytes match the node's reconstruction. Fails on main with the'nonce'warning above.test_windows_fallback_message_matches_shared_helper— pins the two branches to identical bytes on a Windows-shaped attestation.tests/test_attestation_signing_6798.py: 12 passed (was 11 + 1 failing).Severity, honestly
High impact but narrow scope: Windows miners only, and only against a node running the default
ENROLL_ALLOW_UNSIGNED_LEGACY=0. Linux/macOS/POWER8 are unaffected. The GUI installer copy underminers/windows/installer/src/is a separate, older copy without the signing refactor, so it is unaffected too — the blast radius is the.bat/build_windows_miner.ps1channel, which is live and CI-guarded. I have not tested against a running node; the enrollment chain above is read from the node source, so please sanity-check that half.RTC:
RTCd1554f0f35576faf01d386a6be1c947f560dd0b7