dgb-wallet/packages/p2p/scripts/header-sync-demo.ts
Digibyte.X d50286a9a5 DigiByte.X Wallet — recovery-first web wallet monorepo
Packages: core (BIP39/32/44/49/84/86 derivation, WIF), keystore (PBKDF2 +
AES-GCM), psbt, p2p (BIP157/158 SPV daemon, Dandelion++ broadcast with
relay-echo verification), blockbook, rpc, electrum, net, bns, web-ui
(React/Vite), mobile (Expo). ops/ holds the nginx vhost, systemd unit and
push.sh deploy script for digibyte.x/web.
2026-09-20 20:16:52 +02:00

104 lines
3.9 KiB
TypeScript

// Milestone A3 demo — download block headers from a real DGB peer,
// chain them by prev-hash, report tip height and hash.
//
// Scope note: this does NOT do PoW validation. That requires
// implementing the 5 DGB algos (SHA256/Scrypt/Skein/Qubit/Odocrypt)
// with per-algo difficulty targets (MultiShield). Separate milestone.
// For now we trust the peer's chain and validate only the prev-hash
// linkage — enough to prove the wire protocol works end-to-end.
import { PeerPool, HeaderChain, encodeGetHeaders, type BlockHeader } from '../src/index.js';
// DGB mainnet genesis block hash (chainparams.cpp). Verified via
// `digibyte-cli getblockhash 0` on a synced Core.
const DGB_GENESIS_HASH = '7497ea1b465eb39f1c8f507bc877078fe016d6fcb6dfad3a64c98dcc6e1e8496';
const RUN_MS = Number(process.argv[2]) || 60_000;
const TARGET_HEADERS = Number(process.argv[3]) || 20_000; // stop when we hit this many
console.log('\n=== DigiByte P2P Header Sync Demo ===\n');
console.log(`Runtime cap: ${RUN_MS / 1000}s`);
console.log(`Target: ${TARGET_HEADERS.toLocaleString()} headers\n`);
const pool = new PeerPool({ poolSize: 3, peerOpts: { handshakeTimeoutMs: 10_000 } });
const chain = new HeaderChain();
// Seed with a stub genesis (hash-only) so buildLocator() has an anchor.
// We don't actually have the 80-byte genesis header, but for chaining
// forward only the hash matters.
chain.appendGenesis(
{
hash: DGB_GENESIS_HASH,
prevBlock: '00'.repeat(32),
merkleRoot: '',
version: 0,
timestamp: 0,
bits: 0,
nonce: 0,
raw: Buffer.alloc(80),
},
0,
);
let startedRequest = false;
let received = 0;
let batches = 0;
const t0 = Date.now();
// Wait for at least one peer to be ready, then start syncing through it.
pool.on(
'connect',
({ host, port }: { host: string; port: number }) => {
if (startedRequest) return;
startedRequest = true;
console.log(`Using peer ${host}:${port} for header sync.\n`);
const peer = pool.pickReady()[0];
if (!peer) return;
peer.on('headers', (headers: BlockHeader[]) => {
batches++;
received += headers.length;
const res = chain.append(headers);
const tipStr = chain.tip ? chain.tip.hash.slice(0, 12) + '...' : '(none)';
console.log(
` batch #${batches}: got ${headers.length}, appended ${res.appended}, tip=${chain.tipHeight} ${tipStr}` +
(res.rejectedAt ? ` [REJECTED: ${res.reason}]` : ''),
);
if (chain.tipHeight >= TARGET_HEADERS) {
finish('target reached');
return;
}
// Request the next batch: locator = our current tip.
if (headers.length >= 2000) {
// Peer will send at most 2000 per batch; if it sent 2000 there
// are likely more. Request next.
peer.send('getheaders', encodeGetHeaders(70019, chain.buildLocator()));
} else {
finish(`peer sent short batch (${headers.length}) — at their tip`);
}
});
// Kick off the sync — locator = [genesis]. Peer sends 2000
// headers starting from block 1 forward.
peer.send('getheaders', encodeGetHeaders(70019, chain.buildLocator()));
},
);
const runTimer = setTimeout(() => finish('runtime cap reached'), RUN_MS);
function finish(reason: string): void {
clearTimeout(runTimer);
const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
const rate = received > 0 ? (received / (Date.now() - t0) * 1000).toFixed(0) : '0';
console.log('\n--- summary ---');
console.log(` reason: ${reason}`);
console.log(` elapsed: ${elapsed}s`);
console.log(` batches: ${batches}`);
console.log(` headers total: ${received.toLocaleString()}`);
console.log(` chain tip: ${chain.tipHeight.toLocaleString()}`);
console.log(` chain size: ${chain.size.toLocaleString()}`);
console.log(` effective rate: ${rate} headers/sec`);
if (chain.tip) console.log(` tip hash: ${chain.tip.hash}`);
pool.stop();
process.exit(0);
}