igneum/tools/harness/lib/report.mjs
igneum-labs 87df9eac9d Harness: consensus attack catalogue runner and first results
tools/harness runs the standard consensus-attack catalogue against a private
test network of our own igneumd nodes (127.0.0.1 ports 27200+, /tmp/igneum-harness,
never the live devnet or the PC node), with a pass criterion per scenario from the
spec and a measured result each. Built on the node fork's own crates
(igneum-harness-sim on kaspa_utils::sim as simpa does; igneum-p2p-probe for the
wire). Scenarios: 1 withholding, 2 timestamp edges and drift, 3 partition and heal,
4 eclipse, 5 malformed and boundary inputs on every p2p and RPC surface, 6 resource
exhaustion, 7 fast-miner flood. Finality and difficulty-controller scenarios are
stubs with their criteria written.

bench-log: one dated entry, a row per scenario (criterion, measured, pass or fail).
First run: 19 of 20 measured rows pass. Findings recorded in the entry: scenario 5
reproduces ledger M15 on HEAD (bogus past-day or DAA headers build a 256 MiB cache
before rejection; the r3-fixes branch removes it); scenario 1 at 45% hash with
burst withholding shows a selfish-mining blue-share gain (50.7% of blues), the one
failing row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 22:17:37 +00:00

45 lines
1.5 KiB
JavaScript

// Results: one JSON per scenario run under /tmp/igneum-harness/results, and one dated bench-log entry with a row per
// scenario (criterion, result, pass or fail). `run.mjs` calls writeBenchLog once at the end of a batch.
import { mkdirSync, writeFileSync, readFileSync, appendFileSync, existsSync } from 'node:fs';
import { ROOT, TMP } from './net.mjs';
export const RESULTS = `${TMP}/results`;
export function saveResult(name, data) {
mkdirSync(RESULTS, { recursive: true });
const file = `${RESULTS}/${name}.json`;
writeFileSync(file, JSON.stringify(data, null, 2));
return file;
}
export function loadResults(names) {
const out = {};
for (const n of names) {
const f = `${RESULTS}/${n}.json`;
if (existsSync(f)) out[n] = JSON.parse(readFileSync(f, 'utf8'));
}
return out;
}
/// rows: [{ scenario, criterion, result, pass: true|false|null }]
export function benchLogEntry({ date, title, machine, rows, notes = [] }) {
const lines = [];
lines.push('', `## ${date}, ${title}`, '');
lines.push(machine);
lines.push('');
lines.push('| Scenario | Criterion (spec) | Measured | Pass |');
lines.push('|---|---|---|---|');
for (const r of rows) {
const pass = r.pass === true ? 'pass' : r.pass === false ? 'FAIL' : 'stub';
lines.push(`| ${r.scenario} | ${r.criterion} | ${r.result} | ${pass} |`);
}
for (const n of notes) { lines.push(''); lines.push(n); }
return lines.join('\n') + '\n';
}
export function appendBenchLog(text) {
const f = `${ROOT}docs/bench-log.md`;
appendFileSync(f, text);
return f;
}