Consensus calibration
This commit is contained in:
Executable
+48
@@ -0,0 +1,48 @@
|
||||
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;i<args.length;i++) {
|
||||
if(!known.has(args[i]))throw new Error('Unknown option');
|
||||
if(args[i]==='--hashes'||args[i]==='--network-hps')i++;
|
||||
}
|
||||
if(!args.includes('--consent'))throw new Error('Explicit --consent required: native RandomX consumes CPU, energy and ~256 MiB light / >2.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)||value<min||value>max)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;i<count;i++) {
|
||||
blob.writeBigUInt64LE(BigInt(i+1),32);const t=performance.now();await engine.hash(key,blob);samples.push(performance.now()-t);
|
||||
}
|
||||
const warmMs=performance.now()-start,warmHps=count/(warmMs/1000);
|
||||
start=performance.now();await engine.hash(otherKey,blob);const epochSwitchMs=performance.now()-start;
|
||||
samples.sort((a,b)=>a-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);}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
import { calibrationReport } from '../server/analysis/calibration.ts';
|
||||
|
||||
if (process.argv.slice(2).length) throw new Error('No options accepted. This deterministic analysis never selects launch parameters.');
|
||||
console.log(JSON.stringify(calibrationReport(),null,2));
|
||||
Reference in New Issue
Block a user