UNPKG

node-csfd-api

Version:

ČSFD API in JavaScript. Amazing NPM library for scrapping csfd.cz :)

1 lines 3.25 kB
{"version":3,"file":"proof-of-work.cjs","names":["sha256","toHex"],"sources":["../../src/anubis/proof-of-work.ts"],"sourcesContent":["import { sha256, toHex } from './sha256';\n\n// Hard bound on the search so an unexpected difficulty bump can never hang the\n// caller. Difficulty 4 takes ~0.1s and difficulty 5 ~2s; past that, failing\n// fast beats blocking a server for minutes.\nexport const DEFAULT_TIME_BUDGET_MS = 10_000;\n\n// ~8ms of hashing per slice, short enough to keep a server's latency sane.\nconst YIELD_INTERVAL = 4096;\n\n// setImmediate resumes on the next event loop tick; setTimeout is clamped to\n// ~1ms but exists everywhere. React Native polyfills the former, browsers not.\n// Read off globalThis so this file needs no Node type declarations.\nconst scheduleImmediate = (globalThis as { setImmediate?: (callback: () => void) => unknown })\n .setImmediate;\n\nconst yieldToEventLoop: () => Promise<void> = scheduleImmediate\n ? () => new Promise((resolve) => scheduleImmediate(() => resolve()))\n : () => new Promise((resolve) => setTimeout(() => resolve(), 0));\n\nexport interface ProofOfWork {\n hash: string;\n nonce: number;\n}\n\n/**\n * Find a nonce whose `sha256(data + nonce)` digest starts with `difficulty`\n * zero nibbles, mirroring Anubis' own worker: whole zero bytes first, then the\n * high nibble of the next byte when difficulty is odd.\n *\n * Resolves `null` if no nonce is found within the time budget.\n */\nexport const solveProofOfWork = async (\n data: string,\n difficulty: number,\n timeBudgetMs: number = DEFAULT_TIME_BUDGET_MS\n): Promise<ProofOfWork | null> => {\n const requiredZeroBytes = Math.floor(difficulty / 2);\n const isDifficultyOdd = difficulty % 2 !== 0;\n const deadline = Date.now() + timeBudgetMs;\n\n for (let nonce = 0; ; nonce++) {\n // The search runs on the caller's thread, so hand the event loop back at\n // intervals: a server has to stay responsive while we hunt for the nonce.\n if (nonce > 0 && nonce % YIELD_INTERVAL === 0) {\n if (Date.now() > deadline) {\n return null;\n }\n await yieldToEventLoop();\n }\n\n const digest = sha256(data + nonce);\n\n let valid = true;\n for (let i = 0; i < requiredZeroBytes; i++) {\n if (digest[i] !== 0) {\n valid = false;\n break;\n }\n }\n if (valid && isDifficultyOdd && digest[requiredZeroBytes] >> 4 !== 0) {\n valid = false;\n }\n if (valid) {\n return { hash: toHex(digest), nonce };\n }\n }\n};\n"],"mappings":";;AAKA,MAAa,yBAAyB;AAGtC,MAAM,iBAAiB;AAKvB,MAAM,oBAAqB,WACxB;AAEH,MAAM,mBAAwC,0BACpC,IAAI,SAAS,YAAY,wBAAwB,QAAQ,CAAC,CAAC,UAC3D,IAAI,SAAS,YAAY,iBAAiB,QAAQ,GAAG,CAAC,CAAC;;;;;;;;AAcjE,MAAa,mBAAmB,OAC9B,MACA,YACA,eAAuB,2BACS;CAChC,MAAM,oBAAoB,KAAK,MAAM,aAAa,CAAC;CACnD,MAAM,kBAAkB,aAAa,MAAM;CAC3C,MAAM,WAAW,KAAK,IAAI,IAAI;CAE9B,KAAK,IAAI,QAAQ,IAAK,SAAS;EAG7B,IAAI,QAAQ,KAAK,QAAQ,mBAAmB,GAAG;GAC7C,IAAI,KAAK,IAAI,IAAI,UACf,OAAO;GAET,MAAM,iBAAiB;EACzB;EAEA,MAAM,SAASA,eAAAA,OAAO,OAAO,KAAK;EAElC,IAAI,QAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,KACrC,IAAI,OAAO,OAAO,GAAG;GACnB,QAAQ;GACR;EACF;EAEF,IAAI,SAAS,mBAAmB,OAAO,sBAAsB,MAAM,GACjE,QAAQ;EAEV,IAAI,OACF,OAAO;GAAE,MAAMC,eAAAA,MAAM,MAAM;GAAG;EAAM;CAExC;AACF"}