dgb-wallet/packages/p2p/scripts/pow-vectors.ts
Digibyte.X 93cd8b4bf4 daemon: verify proof-of-work on every synced header; fork choice by work
DigiByte is multi-algorithm, so this brings in six hash functions:
SHA256d and Scrypt in JS, and Qubit, Skein, Groestl and Odocrypt from
DigiByte Core's own C sources compiled to WebAssembly (packages/p2p/native,
emscripten via docker). Each header is checked against its nBits target and
the network powLimit before it can enter the chain; a peer serving an
invalid or future-dated header is benched. Competing branches are accepted
only when they carry more accumulated work than what they replace.

npm run pow:test -w @dgb-wallet/p2p verifies real mainnet headers of all
six algorithms and that a tampered header fails.
2026-10-02 18:37:31 +02:00

38 lines
1.8 KiB
TypeScript

// Verify the multi-algo PoW implementation against real mainnet headers.
//
// npx tsx packages/p2p/scripts/pow-vectors.ts [vectors.json]
//
// vectors.json: [{ h, algo, version, bits, time, raw(hex), hash }] — one
// or more headers per algorithm, taken from a synced header chain. Every
// header must pass checkProofOfWork, and a header with its nonce flipped
// must fail (proves the hash is actually being compared, not waved
// through).
import { readFileSync } from 'node:fs';
import { checkProofOfWork, algoOf, powHash, targetFromBits } from '../src/pow.js';
import { decodeHeader } from '../src/messages/headers.js';
const file = process.argv[2] ?? new URL('../test/pow-vectors.json', import.meta.url);
const vectors = JSON.parse(readFileSync(file, 'utf8')) as Array<{ h: number; algo: string; raw: string; bits: string }>;
let fails = 0;
for (const v of vectors) {
const raw = Buffer.from(v.raw, 'hex');
const hdr = decodeHeader(raw);
const algo = algoOf(hdr.version);
const t0 = performance.now();
const res = checkProofOfWork(hdr);
const ms = (performance.now() - t0).toFixed(1);
// Tamper: flip one nonce bit → must fail.
const bad = Buffer.from(raw); bad[76] ^= 1;
const badRes = checkProofOfWork(decodeHeader(bad));
const ok = res.ok && algo === v.algo && !badRes.ok;
if (!ok) fails++;
const hash = powHash(raw, algo!, hdr.timestamp);
console.log(
`${ok ? 'PASS' : 'FAIL'} h=${v.h} ${String(v.algo).padEnd(7)} ${ms.padStart(6)}ms ` +
`pow=${Buffer.from(hash).reverse().toString('hex').slice(0, 24)}… target=${targetFromBits(hdr.bits).target.toString(16).padStart(64, '0').slice(0, 24)}…` +
`${res.ok ? '' : ` (${res.reason})`}${badRes.ok ? ' TAMPERED HEADER PASSED!' : ''}`,
);
}
console.log(fails === 0 ? `all ${vectors.length} vectors pass` : `${fails} FAILURES`);
process.exit(fails === 0 ? 0 : 1);