Files
wikideck/tests/calibration.test.ts
T

57 lines
3.9 KiB
TypeScript
Executable File

import test from 'node:test';
import assert from 'node:assert/strict';
import { execFileSync, spawnSync } from 'node:child_process';
import { CONSENSUS } from '../shared/testnet.ts';
import { MAX_TARGET, workFor } from '../server/testnet/consensus.ts';
import { calibrationReport, expectedHashes, idealCatchup, simulate, targetForHashrate } from '../server/analysis/calibration.ts';
test('calibration math uses inclusive target probability and bounded explicit hashrate assumptions',()=>{
assert.equal(expectedHashes(MAX_TARGET),16);
assert.equal(workFor(MAX_TARGET),16n);
assert.equal(targetForHashrate(1),((1n<<256n)/900n-1n).toString(16).padStart(64,'0'));
assert.ok(Math.abs(expectedHashes(targetForHashrate(100))-90000)<1e-8);
assert.equal(targetForHashrate(1,1),MAX_TARGET);
for(const value of [0,-1,NaN,Infinity,1.5,1e15])assert.throws(()=>targetForHashrate(value));
assert.throws(()=>expectedHashes('bad'));
});
test('deterministic traces preserve exact retarget boundaries and show asymmetric stall recovery',()=>{
const steady=simulate('steady'),rapid=simulate('rapid'),slow=simulate('slow'),stall=simulate('stall');
assert.deepEqual(simulate('rapid'),rapid);
assert.ok(steady.every(p=>p.target===MAX_TARGET));
assert.equal(rapid[8].nextTarget,MAX_TARGET);
assert.equal(BigInt(`0x${rapid[9].nextTarget}`),BigInt(`0x${MAX_TARGET}`)/4n);
assert.equal(rapid[10].target,rapid[9].nextTarget);
assert.ok(slow.every(p=>p.target===MAX_TARGET)); // Cannot ease above MAX_TARGET.
assert.equal(stall[20].wallTime-stall[19].wallTime,7*86400);
assert.equal(stall[20].target,MAX_TARGET); // No emergency wall-clock difficulty decay.
assert.equal(stall[20].nextTarget,MAX_TARGET);
assert.ok(BigInt(rapid.at(-1)!.cumulativeWork)>BigInt(steady.at(-1)!.cumulativeWork));
assert.throws(()=>simulate('rapid',1001));
});
test('median-minimum and future-edge traces are timestamp-policy inputs, not valid mined chains',()=>{
const minimum=simulate('median-minimum'),future=simulate('future-edge'),steady=simulate('steady');
assert.ok(minimum.at(-1)!.timestamp<steady.at(-1)!.timestamp);
assert.ok(BigInt(`0x${minimum.at(-1)!.target}`)<BigInt(`0x${MAX_TARGET}`));
assert.ok(future.every(p=>p.timestamp-p.wallTime===CONSENSUS.maxFutureSeconds));
assert.equal(future[9].nextTarget,MAX_TARGET); // Constant timestamp offset cancels in retarget differences.
const report=calibrationReport();assert.equal(report.consensusChanged,false);
assert.match(report.scope,/no valid blocks/i);assert.match(report.decision,/NO-GO/);
});
test('ideal catchup probabilities are explicitly conditioned on known current deficit',()=>{
assert.equal(idealCatchup(.5,10),1);assert.equal(idealCatchup(.9,10),1);
assert.equal(idealCatchup(.25,0),1);assert.equal(idealCatchup(0,10),0);
assert.ok(Math.abs(idealCatchup(.25,10)-(1/3)**10)<1e-15);
assert.ok(idealCatchup(.4,10)>idealCatchup(.25,10));
for(const q of [-1,NaN,Infinity,1.1])assert.throws(()=>idealCatchup(q,10));
});
test('analysis CLI is offline and benchmark refuses CPU work without consent',()=>{
const output=execFileSync(process.execPath,['--experimental-strip-types','scripts/consensus-analysis.ts'],{encoding:'utf8',timeout:30000});
assert.equal(JSON.parse(output).initialExpectedHashes,16);
const denied=spawnSync(process.execPath,['--experimental-strip-types','scripts/benchmark-randomx.ts'],{
encoding:'utf8',timeout:30000,env:{...process.env,RANDOMX_BINARY:'/nonexistent-no-engine-must-start'}});
assert.notEqual(denied.status,0);assert.match(denied.stderr,/consent required/);
const bad=spawnSync(process.execPath,['--experimental-strip-types','scripts/benchmark-randomx.ts','--consent','--hashes','1000000'],{
encoding:'utf8',timeout:30000,env:{...process.env,RANDOMX_BINARY:'/nonexistent'}});
assert.notEqual(bad.status,0);assert.match(bad.stderr,/Invalid --hashes/);
});