733ecd2681
Add root Cargo workspace with 9 crates: salvium-crypto (extended), salvium-types, salvium-consensus, salvium-wallet, salvium-tx, salvium-rpc, salvium-miner (extended), salvium-cli, salvium-multisig. New modules: chain_state, block_weight, alt_chain, validation, offline signing, stake lifecycle, wallet sync/query/encryption/utxo, randomx utilities, and full multisig crate with CARROT support. Delete 188 JS test/helper/debug files; archive integration test scripts to test/legacy-js/ for live testnet use. Testnet integration tests (transfer, stake, burn, convert, sweep) remain as #[ignore]- gated Rust tests runnable with --ignored against a live daemon.
178 lines
5.5 KiB
JavaScript
178 lines
5.5 KiB
JavaScript
/**
|
|
* Debug full mode worker - run in main thread
|
|
*/
|
|
|
|
import { randomx_init_cache, randomx_superscalarhash, randomx_machine_id } from '../src/randomx/vendor/index.js';
|
|
import { RANDOMX_DATASET_ITEM_COUNT } from '../src/randomx/full-mode.js';
|
|
|
|
const VM_WASM_PAGES = 33;
|
|
const SCRATCH_SIZE = 16 * 1024;
|
|
const JIT_BASELINE = 0;
|
|
const JIT_RELAXED_SIMD = 1;
|
|
const JIT_FMA = 2;
|
|
|
|
const TEST_SEED = '33d64e8899b07bcc1234567890abcdef1234567890abcdef1234567890abcdef';
|
|
|
|
function detectJitFeature() {
|
|
const machineId = randomx_machine_id();
|
|
if (machineId.includes('+fma')) return JIT_FMA | JIT_RELAXED_SIMD;
|
|
if (machineId.includes('+relaxed-simd')) return JIT_RELAXED_SIMD;
|
|
return JIT_BASELINE;
|
|
}
|
|
|
|
function hexToBytes(hex) {
|
|
if (hex.startsWith('0x')) hex = hex.slice(2);
|
|
const bytes = new Uint8Array(hex.length / 2);
|
|
for (let i = 0; i < bytes.length; i++) {
|
|
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
async function main() {
|
|
console.log('=== Full Mode Debug Test ===\n');
|
|
|
|
// Initialize cache
|
|
console.log('Initializing cache...');
|
|
const seedBytes = Buffer.from(TEST_SEED, 'hex');
|
|
const cache = randomx_init_cache(seedBytes);
|
|
const ssHash = randomx_superscalarhash(cache);
|
|
console.log('Cache ready');
|
|
|
|
// Create small dataset (1000 items)
|
|
console.log('Creating dataset (1000 items)...');
|
|
const TEST_ITEMS = 1000;
|
|
const datasetSize = RANDOMX_DATASET_ITEM_COUNT * 8 * 8;
|
|
const sharedBuffer = new SharedArrayBuffer(datasetSize);
|
|
const datasetView = new BigInt64Array(sharedBuffer);
|
|
|
|
for (let i = 0; i < TEST_ITEMS; i++) {
|
|
const item = ssHash(BigInt(i));
|
|
const offset = i * 8;
|
|
for (let j = 0; j < 8; j++) {
|
|
datasetView[offset + j] = item[j];
|
|
}
|
|
}
|
|
console.log('Dataset ready');
|
|
|
|
// Create VM
|
|
console.log('Creating VM...');
|
|
const jitFeature = detectJitFeature();
|
|
console.log('JIT feature:', jitFeature);
|
|
|
|
try {
|
|
const memory = new WebAssembly.Memory({ initial: VM_WASM_PAGES, maximum: VM_WASM_PAGES });
|
|
console.log('Memory created');
|
|
|
|
const vmImports = { env: { memory } };
|
|
const vmInstance = new WebAssembly.Instance(cache.vm, vmImports);
|
|
console.log('VM instance created');
|
|
|
|
const vmExports = vmInstance.exports;
|
|
const scratchPtr = vmExports.i(jitFeature);
|
|
console.log('Scratch ptr:', scratchPtr);
|
|
|
|
const scratch = new Uint8Array(memory.buffer, scratchPtr, SCRATCH_SIZE);
|
|
|
|
// Dataset lookup that falls back to ssHash for items beyond our test range
|
|
const datasetLookup = (itemIndex) => {
|
|
const idx = Number(itemIndex);
|
|
if (idx < TEST_ITEMS) {
|
|
const offset = idx * 8;
|
|
return [
|
|
datasetView[offset],
|
|
datasetView[offset + 1],
|
|
datasetView[offset + 2],
|
|
datasetView[offset + 3],
|
|
datasetView[offset + 4],
|
|
datasetView[offset + 5],
|
|
datasetView[offset + 6],
|
|
datasetView[offset + 7]
|
|
];
|
|
}
|
|
// Fall back to superscalar for items beyond test range
|
|
return ssHash(itemIndex);
|
|
};
|
|
|
|
const jitImports = {
|
|
e: {
|
|
m: memory,
|
|
d: datasetLookup
|
|
}
|
|
};
|
|
|
|
// Hash function
|
|
const hashFn = (input, isHex) => {
|
|
if (typeof input === 'string') {
|
|
input = new TextEncoder().encode(input);
|
|
}
|
|
vmExports.I(isHex);
|
|
if (input.length <= SCRATCH_SIZE) {
|
|
scratch.set(input);
|
|
vmExports.H(input.length);
|
|
} else {
|
|
let p = 0;
|
|
while (p < input.length) {
|
|
const chunk = input.subarray(p, p + SCRATCH_SIZE);
|
|
p += SCRATCH_SIZE;
|
|
scratch.set(chunk);
|
|
vmExports.H(chunk.length);
|
|
}
|
|
}
|
|
let jitSize;
|
|
while (true) {
|
|
jitSize = vmExports.R();
|
|
if (jitSize === 0) break;
|
|
const jitModule = new WebAssembly.Module(scratch.subarray(0, jitSize));
|
|
const jitInstance = new WebAssembly.Instance(jitModule, jitImports);
|
|
jitInstance.exports.d();
|
|
}
|
|
};
|
|
|
|
const vm = {
|
|
calculate_hash: (input) => {
|
|
hashFn(input, false);
|
|
return new Uint8Array(scratch.subarray(0, 32));
|
|
}
|
|
};
|
|
|
|
console.log('VM created successfully\n');
|
|
|
|
// Test hashing with a real job blob
|
|
const testBlob = '0707a5e28db705ede4b8bef6e9dbf2f0d2e2d0d0e5d0d4b8e0d5d0c8c0d0d4b8e5e0c0d0d0c0b8e0e0d0d0b8c0e0d4d0b8';
|
|
console.log('Testing hash with blob:', testBlob.substring(0, 32) + '...');
|
|
|
|
const blobBytes = hexToBytes(testBlob);
|
|
console.log('Blob bytes length:', blobBytes.length);
|
|
|
|
console.log('Computing hash...');
|
|
const startTime = performance.now();
|
|
const hash = vm.calculate_hash(blobBytes);
|
|
const elapsed = performance.now() - startTime;
|
|
|
|
console.log('Hash computed in', elapsed.toFixed(2), 'ms');
|
|
console.log('Hash:', Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join(''));
|
|
|
|
// Test multiple hashes
|
|
console.log('\nComputing 5 hashes...');
|
|
const start = performance.now();
|
|
for (let i = 0; i < 5; i++) {
|
|
const template = new Uint8Array(blobBytes);
|
|
const view = new DataView(template.buffer);
|
|
view.setUint32(39, i, true); // Set nonce
|
|
vm.calculate_hash(template);
|
|
console.log(' Hash', i+1, 'done');
|
|
}
|
|
const total = performance.now() - start;
|
|
console.log('5 hashes in', total.toFixed(2), 'ms');
|
|
console.log('Average:', (total / 5).toFixed(2), 'ms/hash');
|
|
console.log('Hashrate:', (5 / (total / 1000)).toFixed(2), 'H/s');
|
|
|
|
} catch (err) {
|
|
console.error('Error:', err);
|
|
console.error('Stack:', err.stack);
|
|
}
|
|
}
|
|
|
|
main().catch(console.error);
|