Files
Matt Hess 733ecd2681 Migrate all JS tests to Rust: 9-crate workspace, 703 tests, 0 JS remaining
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.
2026-02-17 23:09:35 +00:00

120 lines
3.7 KiB
JavaScript

#!/usr/bin/env bun
// Debug transaction byte structure - find correct RCT offset
import { createDaemonRPC } from '../src/rpc/index.js';
import { hexToBytes, bytesToHex } from '../src/address.js';
const daemon = createDaemonRPC({ url: 'http://seed01.salvium.io:19081', timeout: 30000 });
function decodeVarint(data, offset) {
let value = 0n;
let shift = 0n;
let bytesRead = 0;
while (offset + bytesRead < data.length) {
const byte = data[offset + bytesRead];
bytesRead++;
value |= BigInt(byte & 0x7f) << shift;
if ((byte & 0x80) === 0) break;
shift += 7n;
if (shift >= 70n) throw new Error('Varint overflow');
}
return { value: Number(value), bytesRead };
}
async function test() {
const txHash = 'a5e85d03e9200229a72fc3cfe94e5b139c8c2ad982dc3fd174898be63269e670';
const resp = await daemon.getTransactions([txHash], { decode_as_json: true });
const txData = resp.result?.txs?.[0];
const data = hexToBytes(txData.as_hex);
console.log('TX size:', data.length, 'bytes');
console.log('Daemon says: type=6, inputs=9, outputs=2\n');
let offset = 0;
// Version
const version = decodeVarint(data, offset);
console.log(`Version: ${version.value} at offset 0`);
offset += version.bytesRead;
// Unlock time
const unlockTime = decodeVarint(data, offset);
console.log(`Unlock time: ${unlockTime.value}`);
offset += unlockTime.bytesRead;
// Number of inputs
const numInputs = decodeVarint(data, offset);
console.log(`\nInputs: ${numInputs.value}`);
offset += numInputs.bytesRead;
// Skip inputs (simplified - just find pattern)
for (let i = 0; i < numInputs.value; i++) {
const inputType = data[offset++];
if (inputType === 0x02) { // txin_to_key
const amount = decodeVarint(data, offset);
offset += amount.bytesRead;
const numOffsets = decodeVarint(data, offset);
offset += numOffsets.bytesRead;
for (let j = 0; j < numOffsets.value; j++) {
const ko = decodeVarint(data, offset);
offset += ko.bytesRead;
}
offset += 32; // key image
}
}
console.log(`After inputs: offset ${offset}`);
// Number of outputs
const numOutputs = decodeVarint(data, offset);
console.log(`\nOutputs: ${numOutputs.value}`);
offset += numOutputs.bytesRead;
// Skip outputs
for (let i = 0; i < numOutputs.value; i++) {
const amount = decodeVarint(data, offset);
offset += amount.bytesRead;
const outputType = data[offset++];
if (outputType === 0x02) { // txout_to_key
offset += 32; // public key
} else if (outputType === 0x03) { // txout_to_tagged_key
offset += 32; // public key
offset += 1; // view tag
}
}
console.log(`After outputs: offset ${offset}`);
// Extra
const extraLen = decodeVarint(data, offset);
console.log(`\nExtra length: ${extraLen.value}`);
offset += extraLen.bytesRead;
offset += extraLen.value; // Skip extra bytes
console.log(`\n=== RCT section starts at offset ${offset} ===`);
console.log(`Remaining bytes: ${data.length - offset}`);
// Show first 50 bytes of RCT
console.log(`\nFirst 50 RCT bytes: ${bytesToHex(data.slice(offset, offset + 50))}`);
// Search for SAL marker from RCT start
let salOffset = -1;
for (let i = offset; i < Math.min(offset + 200, data.length - 4); i++) {
if (data[i] === 0x03 && data[i+1] === 0x53 && data[i+2] === 0x41 && data[i+3] === 0x4c) {
salOffset = i;
console.log(`\nFound SAL marker at offset ${i} (${i - offset} bytes into RCT)`);
break;
}
}
if (salOffset === -1) {
console.log('\nNo SAL marker found - checking raw RCT type byte');
const rawType = data[offset];
console.log(`Raw type byte at RCT start: 0x${rawType.toString(16)} (${rawType})`);
}
}
test().catch(console.error);