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.
38 lines
1.8 KiB
TypeScript
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);
|