7730b6993f
- Create assembly/vm.ts with full RandomX VM implementation
- 256 instructions, 2048 iterations per hash
- Native u64/f64 operations in WebAssembly
- Full mode dataset lookups (2GB pre-computed)
- Update miner to use WASM VM for full mode
- mining-worker-asm.js uses pre-compiled WASM
- ~32 H/s per thread (4x faster than light mode)
- 8 threads achieves ~260 H/s
- Clean up redundant code
- Remove mining-worker-full.js (old JIT approach)
- Consolidate 'asm' mode into 'full' mode
84 lines
3.0 KiB
JavaScript
84 lines
3.0 KiB
JavaScript
/**
|
|
* Debug: Compare superscalar program hash with C++ reference
|
|
*
|
|
* C++ Instruction struct layout (8 bytes):
|
|
* uint8_t opcode; // offset 0
|
|
* uint8_t dst; // offset 1
|
|
* uint8_t src; // offset 2
|
|
* uint8_t mod; // offset 3
|
|
* uint32_t imm32; // offset 4-7 (little-endian)
|
|
*
|
|
* Expected hash for program 0: d3a4a6623738756f77e6104469102f082eff2a3e60be7ad696285ef7dfc72a61
|
|
*/
|
|
|
|
import { blake2b } from '../src/blake2b.js';
|
|
import { Blake2Generator, generateSuperscalar, SuperscalarInstructionType } from '../src/randomx/superscalar.js';
|
|
|
|
function bytesToHex(bytes) {
|
|
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
// Serialize program to bytes matching C++ layout
|
|
function serializeProgram(prog) {
|
|
const bytes = new Uint8Array(prog.instructions.length * 8);
|
|
|
|
for (let i = 0; i < prog.instructions.length; i++) {
|
|
const instr = prog.instructions[i];
|
|
const offset = i * 8;
|
|
|
|
bytes[offset + 0] = instr.opcode & 0xff;
|
|
bytes[offset + 1] = instr.dst & 0xff;
|
|
bytes[offset + 2] = instr.src & 0xff;
|
|
bytes[offset + 3] = instr.mod & 0xff;
|
|
|
|
// imm32 as little-endian
|
|
const imm = instr.imm32 >>> 0;
|
|
bytes[offset + 4] = imm & 0xff;
|
|
bytes[offset + 5] = (imm >> 8) & 0xff;
|
|
bytes[offset + 6] = (imm >> 16) & 0xff;
|
|
bytes[offset + 7] = (imm >> 24) & 0xff;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
console.log('=== Superscalar Program Hash Debug ===\n');
|
|
|
|
const key = new TextEncoder().encode('test key 000');
|
|
const gen = new Blake2Generator(key);
|
|
|
|
// Expected hashes from C++ tests.cpp
|
|
const expectedHashes = [
|
|
'd3a4a6623738756f77e6104469102f082eff2a3e60be7ad696285ef7dfc72a61',
|
|
'f5e7e0bbc7e93c609003d6359208688070afb4a77165a552ff7be63b38dfbc86',
|
|
'85ed8b11734de5b3e9836641413a8f36e99e89694f419c8cd25c3f3f16c40c5a',
|
|
'5dd956292cf5d5704ad99e362d70098b2777b2a1730520be52f772ca48cd3bc0',
|
|
'6f14018ca7d519e9b48d91af094c0f2d7e12e93af0228782671a8640092af9e5',
|
|
'134be097c92e2c45a92f23208cacd89e4ce51f1009a0b900dbe83b38de11d791',
|
|
'268f9392c20c6e31371a5131f82bd7713d3910075f2f0468baafaa1abd2f3187',
|
|
'c668a05fd909714ed4a91e8d96d67b17e44329e88bc71e0672b529a3fc16be47',
|
|
'99739351315840963011e4c5d8e90ad0bfed3facdcb713fe8f7138fbf01c4c94',
|
|
'14ab53d61880471f66e80183968d97effd5492b406876060e595fcf9682f9295'
|
|
];
|
|
|
|
// Generate and hash all 10 programs
|
|
let allMatch = true;
|
|
for (let progIdx = 0; progIdx < 10; progIdx++) {
|
|
const prog = generateSuperscalar(gen);
|
|
const progBytes = serializeProgram(prog);
|
|
const hash = blake2b(progBytes, 32);
|
|
const hashHex = bytesToHex(hash);
|
|
const match = hashHex === expectedHashes[progIdx];
|
|
|
|
console.log(`Program ${progIdx}: size=${prog.instructions.length.toString().padStart(3)} addrReg=${prog.addressRegister} hash=${hashHex.slice(0, 16)}... ${match ? '✓' : '✗'}`);
|
|
|
|
if (!match) {
|
|
allMatch = false;
|
|
console.log(` Expected: ${expectedHashes[progIdx]}`);
|
|
console.log(` Got: ${hashHex}`);
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
console.log(allMatch ? 'All 10 program hashes match!' : 'Some program hashes do not match.');
|