Qortal-Hub/src/chatComputePow.worker.js
2024-11-23 10:58:04 +02:00

105 lines
3.0 KiB
JavaScript

import { Sha256 } from 'asmcrypto.js';
import wasmInit from './memory-pow.wasm?init';
let compute; // Exported compute function from Wasm
let memory; // WebAssembly.Memory instance
let heap; // Uint8Array view of the memory buffer
let brk = 512 * 1024; // Initial brk set to 512 KiB
const allocations = new Map(); // Track allocations by pointer
let workBufferPtr = null; // Reuse work buffer
const workBufferLength = 8 * 1024 * 1024; // 8 MiB
// Load the WebAssembly module
async function loadWasm() {
try {
memory = new WebAssembly.Memory({ initial: 256, maximum: 256 }); // 16 MiB
heap = new Uint8Array(memory.buffer);
const importObject = {
env: {
memory, // Pass memory to Wasm
abort: () => { throw new Error('Wasm abort called'); }, // Handle abort calls from Wasm
},
};
const wasmModule = await wasmInit(importObject);
compute = wasmModule.exports.compute2;
console.log('Wasm loaded successfully:', compute);
} catch (error) {
console.error('Error loading Wasm:', error);
throw error;
}
}
// Memory allocation function
function sbrk(size) {
const old = brk;
// If a previous allocation exists for this size, reuse it
if (allocations.has(size)) {
return allocations.get(size);
}
brk += size;
// Grow memory if needed
if (brk > memory.buffer.byteLength) {
const pagesNeeded = Math.ceil((brk - memory.buffer.byteLength) / (64 * 1024)); // 64 KiB per page
try {
memory.grow(pagesNeeded);
heap = new Uint8Array(memory.buffer); // Update heap view
} catch (e) {
console.error('Failed to grow memory:', e);
throw new RangeError('WebAssembly.Memory.grow(): Maximum memory size exceeded');
}
}
allocations.set(size, old); // Track the allocation
return old;
}
// Proof-of-Work computation function
async function computePow(chatBytes, difficulty) {
if (!compute) {
throw new Error('WebAssembly module not initialized. Call loadWasm first.');
}
const chatBytesArray = Uint8Array.from(Object.values(chatBytes));
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
// Allocate memory for the hash
const hashPtr = sbrk(32);
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
// Reuse the work buffer if already allocated
if (!workBufferPtr) {
workBufferPtr = sbrk(workBufferLength);
}
const nonce = compute(hashPtr, workBufferPtr, workBufferLength, difficulty);
return { nonce, chatBytesArray };
}
// Worker event listener
self.addEventListener('message', async (e) => {
const { chatBytes, difficulty } = e.data;
try {
// Initialize Wasm if not already done
if (!compute) {
await loadWasm();
}
// Perform the POW computation
const result = await computePow(chatBytes, difficulty);
// Send the result back to the main thread
self.postMessage(result);
} catch (error) {
console.error('Error in worker:', error);
self.postMessage({ error: error.message });
}
});