Files
neuron-tai/packages/validator
Dobromir Popov 9abe83b5f4 feat(alpha): complete hardening backlog
Complete the alpha-hardening Ralph task set, including tracker billing/accounting guards, validator fraud-audit primitives, wallet binding proof support, documentation runbooks, and updated tests.

Verification: .venv/bin/python -m compileall -q packages tests; .venv/bin/python -m pytest -q --tb=short (313 passed, 3 skipped, 1 failed: tests/test_mining_cli.py::test_legacy_start_without_port_uses_next_available_port because meshnet-node pid 1263451 is already listening on port 7000).
2026-07-05 21:47:23 +03:00
..

meshnet-validator

Optimistic fraud detection (ADR-0003, penalty amended by ADR-0015): the validator re-runs a random ~5% sample of completed inference requests against a trusted reference node. Audit-capable events are checked by teacher-forcing the claimed token sequence through the reference node and verifying the claimed TOPLOC activation proof. Legacy events without TOPLOC metadata still fall back to text comparison until node-side proof capture lands.

Why the penalty deters cheating

There is no upfront stake. Settlement is periodic (US-033), so a node always has an unpaid pending balance — that balance is the collateral.

At a sampling rate p, a cheater who gains G per fraudulent job and loses L when caught has expected value:

(1 - p) * G - p * L < 0
L > ((1 - p) / p) * G        # p = 0.05  ->  L > 19 x G

With the production settlement period of 24h, the pending balance at any moment approximates a full day's earnings — hundreds to thousands of jobs — which is far above the 19× bar. Each catch also records a strike; three strikes ban the wallet (registration rejected, excluded from routes, unpaid pending never settled), and the probationary period (first N jobs unpaid) makes re-entry with a fresh wallet costly.

TOPLOC audit contract

The validator expects audit-capable events to carry:

  • claimed_token_ids: the final token sequence claimed by the prover.
  • toploc_proof: compact TOPLOC proof data built from prover activations.

On audit the validator calls the reference node's POST /v1/audit/toploc endpoint with the original messages plus claimed_token_ids. The reference node must run a teacher-forced prefill over exactly that token sequence and return the activations for TOPLOC verification. It must not free-generate a second answer for audit.

Canonical audit parameters for the current alpha preset are:

dtype = "bfloat16"
quantization = "bfloat16"
decode_batching_size = 32
topk = 8
skip_prefill = true
encoding = "base64"

Production audit thresholds remain gated on the honest-noise calibration corpus in issue 21.

Two operational notes:

  • Shortening the settlement period shrinks the collateral. Period changes must weigh chain overhead against deterrence.
  • A cheater immediately after a payout has little to forfeit — the strike/ban ladder covers that window.

Usage

ValidatorProcess(
    contracts=contracts,          # registry/validation boundary
    billing=ledger,               # BillingLedger — enables forfeiture
    reference_node_url="http://...",
    sample_rate=0.05,
)

Remote validators can instead call the tracker's privileged POST /v1/billing/forfeit endpoint (non-empty Authorization header).

Reputation-weighted audit rate (ADR-0018 §1, §6-7)

sample_rate is a flat coin flip: every wallet audited at the same rate. Pass audit_sampler=AdaptiveAuditSampler(...) instead to make the audit probability a function of each wallet's tenure and reputation — newcomers and low-reputation wallets sampled at 2030%, veterans in good standing floor at ≥2% — while a running budget balance keeps the fleet-wide realized rate anchored to AuditRateConfig.target_rate (default 5%) regardless of the wallet mix. Passive tripwires (detect_output_tripwire) bump only that one request's odds; they never strike, ban, or affect other wallets' rates.

from meshnet_validator import AdaptiveAuditSampler, detect_output_tripwire

ValidatorProcess(
    contracts=contracts,
    reference_node_url="http://...",
    audit_sampler=AdaptiveAuditSampler(random_seed=42),
)

When audit_sampler is set, sample_rate is ignored — the sampler decides per event, keyed on whichever route wallet has the lowest reputation.