Skip to content

fix(#8078): require evidence for fingerprint checks claiming a pass [FaaFyfxR9WAQrL7FcAgEHJvztd8cVMxvjHRS55rw1nwH] - #8079

Open
waterWang wants to merge 1 commit into
Scottcjn:mainfrom
waterWang:fix-8078-fingerprint-evidence-bypass
Open

fix(#8078): require evidence for fingerprint checks claiming a pass [FaaFyfxR9WAQrL7FcAgEHJvztd8cVMxvjHRS55rw1nwH]#8079
waterWang wants to merge 1 commit into
Scottcjn:mainfrom
waterWang:fix-8078-fingerprint-evidence-bypass

Conversation

@waterWang

Copy link
Copy Markdown
Contributor

Fix: Require evidence for fingerprint checks claiming a pass (#8078)

Problem

A VM (prometheusvt) is passing all six fingerprint checks on the live node by submitting a flat map of six true values with no data object, no measurements, no evidence of any kind. The server accepted it and set fingerprint_passed = 1.

The root cause is in _fingerprint_check_passed(): a dict entry like {"passed": true} with no data key was treated as a full pass. The rotating check system could not distinguish "this hardware cannot measure it" (legitimate vintage/console miners) from "this client did not bother to submit evidence" (the bypass).

Fix

  1. _fingerprint_check_passed() now returns None (unmeasured) instead of True when a dict check has {"passed": true} but no data key, or when data is not a usable dict. Bool-only entries (C miner compat) keep their literal value.

  2. evaluate_rotating_fingerprint_checks() now excludes None (unmeasured) results from the active-ratio denominator. Unmeasured checks are neither passes nor failures — they don't count either way. This is the proportional-evidence rule: the weight of a check scales with the evidence submitted.

Impact

  • A client that submits {"clock_drift": true, "cache_timing": true, ...} with no data → all 6 checks count as unmeasured → active_ratio = 1.0 (no active checks measured) → no reward weight from the rotating check system
  • A client that submits {"clock_drift": {"passed": true, "data": {"cv": 0.09, "samples": 200}}, ...} with real data → all 6 checks pass normally → full weight
  • Vintage/console miners that genuinely cannot measure a check (e.g. no time.perf_counter_ns) already omit that check from the payload → the check is absent → checks.get(name) returns NoneNone is unmeasured → excluded from the ratio. No regression.

References

…a pass [FaaFyfxR9WAQrL7FcAgEHJvztd8cVMxvjHRS55rw1nwH]
@waterWang
waterWang requested a review from Scottcjn as a code owner July 27, 2026 17:09
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to RustChain! Thanks for your first pull request.

Before we review, please make sure:

  • Non-doc PRs have a BCOS-L1 or BCOS-L2 label
  • Doc-only PRs are exempt from BCOS tier labels when they only touch docs/**, *.md, or common image/PDF files
  • New code files include an SPDX license header
  • You've tested your changes against the live node

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!

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) node Node server related size/S PR: 11-50 lines labels Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) node Node server related size/S PR: 11-50 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant