import { createHash } from 'node:crypto'; import { readFile } from 'node:fs/promises'; import { resolve } from 'node:path'; import { arch, platform } from 'node:os'; import { RandomX } from '../server/testnet/randomx.ts'; import { MAX_TARGET, sha256 } from '../server/testnet/consensus.ts'; import { expectedHashes, targetForHashrate } from '../server/analysis/calibration.ts'; const args=process.argv.slice(2),known=new Set(['--consent','--fast','--hashes','--network-hps']); for(let i=0;i2.3 GiB fast. No chain/network access.'); const number=(name:string,fallback:number,min:number,max:number)=>{ const i=args.indexOf(name),text=i<0?String(fallback):args[i+1]; const value=Number(text); if(!text||!/^\d+$/.test(text)||!Number.isSafeInteger(value)||valuemax)throw new Error(`Invalid ${name}`); return value; }; const count=number('--hashes',32,4,256),networkHps=number('--network-hps',1,1,1_000_000_000_000); const binary=resolve(process.env.RANDOMX_BINARY??`native/build/wikideck-randomx${process.platform==='win32'?'.exe':''}`); // Fingerprint the exact executable; it must come from the trusted pinned build, never a download URL. const binarySha256=createHash('sha256').update(await readFile(binary)).digest('hex'); const engine=new RandomX({binary,fast:args.includes('--fast')}); const stop=()=>engine.close();process.once('SIGINT',stop);process.once('SIGTERM',stop); const deadline=setTimeout(stop,60000);deadline.unref(); try { const key=sha256('wikideck-offline-benchmark-epoch-a'),otherKey=sha256('wikideck-offline-benchmark-epoch-b'); const blob=Buffer.alloc(40);Buffer.from(sha256('wikideck-offline-benchmark-blob'),'hex').copy(blob); let start=performance.now();const first=await engine.hash(key,blob);const coldMs=performance.now()-start; start=performance.now();if(await engine.hash(key,blob)!==first)throw new Error('Repeated reference hash differs'); const repeatMs=performance.now()-start; const samples:number[]=[];start=performance.now(); for(let i=0;ia-b); console.log(JSON.stringify({schema:'wikideck-randomx-benchmark-v1',mode:args.includes('--fast')?'fast':'light', platform:platform(),arch:arch(),node:process.version,binarySha256,hashes:count,coldMs,repeatMs,warmMs,warmHashesPerSecond:warmHps, p50HashMs:samples[Math.floor(samples.length*.5)],p95HashMs:samples[Math.min(samples.length-1,Math.floor(samples.length*.95))],epochSwitchMs, currentInitialExpectedHashes:expectedHashes(MAX_TARGET),currentInitialExpectedSecondsAtMeasuredSingleWorker:expectedHashes(MAX_TARGET)/warmHps, assumedNetworkHashesPerSecond:networkHps,illustrativeTargetForAssumedNetwork:targetForHashrate(networkHps), note:'Local single-worker IPC-inclusive warm hash benchmark, not a network/miner-throughput estimate. Cold includes initialization; epoch switch is one cache change. Network H/s is an explicit assumption, not extrapolated from this machine.', consensusChanged:false,productionReady:false},null,2)); } finally {clearTimeout(deadline);engine.close();process.off('SIGINT',stop);process.off('SIGTERM',stop);}