Counter ASIC 3.0 items 4 and 5: the epoch common factor is the median over steady core ids
The mean over every present id let one paused-and-resumed card (the Mac, a 178% step) push every other residual the same way in the epochs it was off, which read as an r = 0.94 edge between two honest 5090 keys on the merged tree (window 41 to 46). The factor is now the median over ids that are steady and present in every window epoch (median over all present when the core is under 3): the same window reads max r 0.10. README: the three calibration readings (the edge, the factor-of-two from identities=2, the unsteady Mac) answered. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
9db5ba1914
commit
3150fc0507
2 changed files with 21 additions and 3 deletions
|
|
@ -98,10 +98,20 @@ Epochs 39 to 45 are the PC 1 outage (the Ember Tune quit, 22:31 UTC on 5 October
|
|||
| 8fafda27 | M5 Max | 4,133 | 25.35 | 6.5% | 3.8% | 5.2% | 9.8% | 16.9 / 10.8 | 0.496 | M5 Max/1 |
|
||||
| 4c022439 | Intel UHD | 265 | 1.59 | 13.4% | 15.2% | 0% | 9.1% | 20.2 / 26.0 | 0.512 | Intel UHD/1 |
|
||||
|
||||
Correlation: 6 pairs, max r 0.53 (the two keys of PC 2's card), no edge at 0.8, no group, no flag, no alert. Over all 28 ids with 32 or more nonces in the 24-hour table (40,550 blocks with `detail`): chi-square maximum 26.8 (n = 38) and 26.0 (n = 793), KS maximum 0.232 at n = 42 (p = 0.01 critical 0.251), increasing fraction 0.438 to 0.520; `nonce mod 32` over all blocks chi-square 22.1 at 31 degrees of freedom. So the honest nonce is uniform over the full 64 bits: the serve protocol hands each job a 32-aligned 64-bit `nonce_start` (`proto-cuda/nvrtc/worker.cpp` lines 17 and 1175) and the kernel adds the lane index; the start is drawn at random per job. The 3-epoch window 36 to 38 (22 ids, PC 1 ramping down) had 4 of 28 pairs over r = 0.9: with 3 points a correlation is noise, which is why 5 shared epochs are the minimum. Card bands from the intake (6 hours of STATUS lines, p5 / p50 / p95): 5090 112.6 / 114.8 / 121.7 MH/s (n 781; the bench's 136 to 137 is the card to itself, the app's live rate shares it with the node and the prover); M5 Max 26.5 / 27.3 / 28.5 (674); Intel UHD 1.7 / 1.8 / 2.0 (754); from the 30-hour sample while PC 1 ran: RX 9070 XT 16.8 / 17.0 / 19.1 (355), gfx1036 2.6 / 2.8 / 3.4, M4 Max laptop 8.4 / 19.8 / 21.9 (478).
|
||||
Correlation: 6 pairs, max r 0.53 with the mean factor of the first commit (0.10 to 0.53 with the median core factor of the second), no edge at 0.8, no group, no flag, no alert. Over all 28 ids with 32 or more nonces in the 24-hour table (40,550 blocks with `detail`): chi-square maximum 26.8 (n = 38) and 26.0 (n = 793), KS maximum 0.232 at n = 42 (p = 0.01 critical 0.251), increasing fraction 0.438 to 0.520; `nonce mod 32` over all blocks chi-square 22.1 at 31 degrees of freedom. So the honest nonce is uniform over the full 64 bits: the serve protocol hands each job a 32-aligned 64-bit `nonce_start` (`proto-cuda/nvrtc/worker.cpp` lines 17 and 1175) and the kernel adds the lane index; the start is drawn at random per job. The 3-epoch window 36 to 38 (22 ids, PC 1 ramping down) had 4 of 28 pairs over r = 0.9: with 3 points a correlation is noise, which is why 5 shared epochs are the minimum. Card bands from the intake (6 hours of STATUS lines, p5 / p50 / p95): 5090 112.6 / 114.8 / 121.7 MH/s (n 781; the bench's 136 to 137 is the card to itself, the app's live rate shares it with the node and the prover); M5 Max 26.5 / 27.3 / 28.5 (674); Intel UHD 1.7 / 1.8 / 2.0 (754); from the 30-hour sample while PC 1 ran: RX 9070 XT 16.8 / 17.0 / 19.1 (355), gfx1036 2.6 / 2.8 / 3.4, M4 Max laptop 8.4 / 19.8 / 21.9 (478).
|
||||
|
||||
The honest population, in one line: excess per-program spread 0 to 5.2% on three card models (the census's 0.8 to 3.2% six-era spread plus the Mac's own load), first-tenth share 9.1 to 10.7%, nonces uniform, pairwise residual correlation under 0.55.
|
||||
|
||||
### Calibration on the merged tree, 09:2x UTC (window epochs 41 to 46, PC 1 back from 07:2x UTC, 20 ids, 4 correlated)
|
||||
|
||||
Three readings the coordinator raised, reproduced read-only and answered:
|
||||
|
||||
| Reading | Cause | Rule |
|
||||
|---|---|---|
|
||||
| The two PC 2 keys 00cec3ae and 9915d263 at r 0.94 (one edge, no group, held 0) | not the rate rule: an id's rate is its blue blocks' summed `calc_work(bits)` over the epoch's wall seconds, never a share of a network estimate, so nothing divides two ids by the same moving number. It was the epoch common factor: the mean over every id present let the Mac (paused and resumed, a 178% step) push every other residual the same way in the epochs it was off, and the two 5090 keys, each at Poisson sd 2.7%, moved together with it. The factor is now the median over the core ids (steady, present in every window epoch; the median over all present when the core is under 3): the same window reads max r 0.10, no edge. A residue of real co-movement stays between two keys of one card (PC 2's 5090 is shared with the prover, so both keys dip together), which is the `machine_group` case and needs k = 3 ids; two ids never form a group | changed in `analyse` (commit 2 on ca3-detector); the false-positive statement below stands, and the devnet's max pairwise r is now 0.10 to 0.53 across the two windows run |
|
||||
| Each 5090 key at about 50 MH/s against the fleet band 99.4 / 115.6 / 123.1 | PC 2's worker runs the card under 2 vote keys (`STATUS ... identities=2 accepted_by_identity=8044/8009`), so 2 x 50.4 = 100.8 MH/s on chain against the card's own 115.6 median: 0.87x, the same ratio the network shows (125 to 131 MH/s on chain against 143.9 of STATUS: reds, pending blocks and template latency are not chain work). Not the hours off (every epoch of the window has PC 2 on) and not a share against total blocks (the rate is work, not a share) | the `/2` is the app's identity count (`detect.rs`: 1, 2 or 8); the band test is calibrated to the app and an unknown miner under another key count, or a pool, reads `band` or `band_high`, which are evidence only and never the alert by themselves. A testnet miner's key count belongs in the coinbase tag beside its card model (owed, 0.3.12) |
|
||||
| The Mac 8fafda27 unsteady (spread 70%, step 178%) | the Mac was paused and resumed inside the window | by design `unsteady` only withholds the `spread` flag (a pause is not a program); the id stays in the correlation set, because a pause shared by several ids is exactly what identifies one machine's keys (`machine_group`), and it cannot become a `design_candidate` without a design flag. What changed: an unsteady id no longer enters the epoch common factor (above), so its pause cannot correlate other ids with each other |
|
||||
|
||||
### False positives, and what the public testnet's first week must add (history check 2)
|
||||
|
||||
Under the null (independent residuals, n = 6 epochs) one pair reads r over 0.8 with p about 0.028 (t = 2.67 on 4 degrees of freedom) and over 0.9 with p about 0.007; chance 3-cliques per window are about C(m, 3) p^3: 0.09 at m = 30 ids, about 100 at m = 300. So the clique alone is never the alert; the candidate also needs a design flag on a member (chance per id: `nonce` about 0.002, `late_start` about 1e-6, `spread` unknown until the per-model baseline exists; the devnet's maximum excess is 5.2% against the 10% line) and 6 net windows. At n = 12 (`DETECTOR_WINDOW_EPOCHS=12`) p(r over 0.8) is about 0.001 and chance 3-cliques at m = 300 are about 0.005 per window: set 12 once the testnet has over 100 ids. The first week must add: (1) the excess spread per card model over 12 or more epochs (the devnet has three models over 6); (2) the nonce layout of third-party miners and pools (a stratum extranonce in the high word is honest and non-uniform, so until each software is baselined a `nonce` flag is evidence, not an alert); (3) bands for cards the project does not own, which needs the card model in the coinbase tag; (4) the `machine_group` count, to see what an 8-key card looks like at scale.
|
||||
|
|
|
|||
|
|
@ -174,9 +174,17 @@ export function analyse(agg, opts = {}, bands = [], prev = null, tipDaa = null)
|
|||
band, flags, notes,
|
||||
});
|
||||
}
|
||||
// two-way residuals: id mean and the epoch common factor over the ids present in it, clipped
|
||||
// two-way residuals: id mean and the epoch common factor, clipped. The factor is the MEDIAN over the core ids (steady
|
||||
// and present in every epoch of the window); the mean over everyone present let one paused-and-resumed card (the Mac,
|
||||
// 6 October, a 178% step) push every other id's residual the same way in the epochs it was off, which read as an
|
||||
// r = 0.94 edge between two honest keys. Fewer than 3 core ids: the median over all present ids.
|
||||
const idMean = new Map([...logRate].map(([id, lr]) => [id, lr.size ? mean([...lr.values()]) : 0]));
|
||||
const epochFactor = new Map(W.map(e => { const devs = ids.filter(id => logRate.get(id).has(e)).map(id => logRate.get(id).get(e) - idMean.get(id)); return [e, devs.length ? mean(devs) : 0]; }));
|
||||
const core = ids.filter(id => miners.get(id).steady && W.every(e => logRate.get(id).has(e)));
|
||||
const epochFactor = new Map(W.map(e => {
|
||||
const pool = core.length >= 3 ? core : ids.filter(id => logRate.get(id).has(e));
|
||||
const devs = pool.filter(id => logRate.get(id).has(e)).map(id => logRate.get(id).get(e) - idMean.get(id));
|
||||
return [e, devs.length ? median(devs) : 0];
|
||||
}));
|
||||
const resid = new Map(ids.map(id => [id, new Map([...logRate.get(id)].map(([e, v]) => [e, Math.max(-o.winsor, Math.min(o.winsor, v - idMean.get(id) - epochFactor.get(e)))]))]));
|
||||
// correlation graph
|
||||
const corrIds = ids.filter(id => resid.get(id).size >= o.minEpochsCorr);
|
||||
|
|
|
|||
Loading…
Reference in a new issue