@fluffylabs/anan-as 1.2.0-ef04361 → 1.3.0-0eb791a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/index.js +138 -5
- package/dist/bin/src/fuzz.js +2 -2
- package/dist/bin/src/test-json.js +2 -6
- package/dist/bin/src/trace-parse.js +1 -0
- package/dist/bin/src/trace-replay.js +14 -9
- package/dist/bin/src/tracer.js +16 -13
- package/dist/bin/src/utils.js +2 -2
- package/dist/build/compiler-inline.js +1 -1
- package/dist/build/compiler.d.ts +17 -13
- package/dist/build/compiler.js +13 -21
- package/dist/build/compiler.wasm +0 -0
- package/dist/build/debug-inline.js +1 -1
- package/dist/build/debug-raw-inline.js +1 -1
- package/dist/build/debug-raw.d.ts +34 -32
- package/dist/build/debug-raw.js +62 -69
- package/dist/build/debug-raw.wasm +0 -0
- package/dist/build/debug.d.ts +34 -32
- package/dist/build/debug.js +63 -70
- package/dist/build/debug.wasm +0 -0
- package/dist/build/js/assembly/api-debugger.d.ts +4 -4
- package/dist/build/js/assembly/api-debugger.js +6 -6
- package/dist/build/js/assembly/api-internal.d.ts +1 -1
- package/dist/build/js/assembly/api-internal.js +2 -3
- package/dist/build/js/assembly/api-types.d.ts +4 -4
- package/dist/build/js/assembly/api-types.js +3 -4
- package/dist/build/js/assembly/api-utils.d.ts +14 -6
- package/dist/build/js/assembly/api-utils.js +28 -13
- package/dist/build/js/assembly/arguments.d.ts +4 -4
- package/dist/build/js/assembly/arguments.js +10 -10
- package/dist/build/js/assembly/gas.d.ts +8 -13
- package/dist/build/js/assembly/gas.js +17 -7
- package/dist/build/js/assembly/instructions/bit.js +22 -22
- package/dist/build/js/assembly/instructions/branch.js +56 -56
- package/dist/build/js/assembly/instructions/jump.js +10 -10
- package/dist/build/js/assembly/instructions/load.js +41 -41
- package/dist/build/js/assembly/instructions/logic.js +20 -20
- package/dist/build/js/assembly/instructions/math.js +105 -105
- package/dist/build/js/assembly/instructions/misc.js +10 -10
- package/dist/build/js/assembly/instructions/mov.js +16 -16
- package/dist/build/js/assembly/instructions/outcome.d.ts +7 -7
- package/dist/build/js/assembly/instructions/outcome.js +63 -38
- package/dist/build/js/assembly/instructions/rot.js +18 -18
- package/dist/build/js/assembly/instructions/set.js +18 -18
- package/dist/build/js/assembly/instructions/shift.js +59 -59
- package/dist/build/js/assembly/instructions/store.js +29 -29
- package/dist/build/js/assembly/instructions/utils.d.ts +6 -4
- package/dist/build/js/assembly/instructions/utils.js +32 -16
- package/dist/build/js/assembly/instructions.d.ts +2 -3
- package/dist/build/js/assembly/instructions.js +4 -4
- package/dist/build/js/assembly/interpreter.d.ts +0 -1
- package/dist/build/js/assembly/interpreter.js +30 -38
- package/dist/build/js/assembly/math.d.ts +6 -8
- package/dist/build/js/assembly/math.js +21 -13
- package/dist/build/js/assembly/memory-page.d.ts +2 -4
- package/dist/build/js/assembly/memory-page.js +13 -7
- package/dist/build/js/assembly/memory.d.ts +1 -0
- package/dist/build/js/assembly/memory.js +119 -23
- package/dist/build/js/assembly/portable.js +1 -0
- package/dist/build/js/assembly/program-build.js +4 -4
- package/dist/build/js/assembly/program.d.ts +15 -8
- package/dist/build/js/assembly/program.js +95 -39
- package/dist/build/js/assembly/spi.d.ts +1 -1
- package/dist/build/js/assembly/spi.js +2 -2
- package/dist/build/js/portable/bootstrap.js +1 -0
- package/dist/build/js/portable-bundle.js +829 -641
- package/dist/build/release-inline.js +1 -1
- package/dist/build/release-mini-inline.js +1 -1
- package/dist/build/release-mini.d.ts +34 -32
- package/dist/build/release-mini.js +63 -70
- package/dist/build/release-mini.wasm +0 -0
- package/dist/build/release-stub-inline.js +1 -1
- package/dist/build/release-stub.d.ts +34 -32
- package/dist/build/release-stub.js +63 -70
- package/dist/build/release-stub.wasm +0 -0
- package/dist/build/release.d.ts +34 -32
- package/dist/build/release.js +63 -70
- package/dist/build/release.wasm +0 -0
- package/dist/build/test-inline.js +1 -1
- package/dist/build/test.wasm +0 -0
- package/dist/test/test-gas-cost.js +2 -3
- package/dist/test/test-trace-format.js +166 -0
- package/dist/test/test-w3f-common.js +1 -2
- package/package.json +14 -10
- package/dist/build/js/assembly/gas-costs.d.ts +0 -6
- package/dist/build/js/assembly/gas-costs.js +0 -39
package/dist/bin/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
-
import { disassemble, HasMetadata, InputKind, prepareProgram, pvmDestroy, pvmResume, pvmSetRegisters, pvmStart, } from "../build/release.js";
|
|
4
|
+
import { disassemble, HasMetadata, InputKind, prepareProgram, pvmDestroy, pvmReadMemory, pvmResume, pvmSetRegisters, pvmStart, } from "../build/release.js";
|
|
5
5
|
import { LOG_GAS_COST, LOG_HOST_CALL_INDEX, printLogHostCall, WHAT } from "./src/log-host-call.js";
|
|
6
6
|
import { STATUS } from "./src/trace-parse.js";
|
|
7
7
|
import { replayTraceFile } from "./src/trace-replay.js";
|
|
8
8
|
import { hexDecode, hexEncode } from "./src/utils.js";
|
|
9
|
+
// Page access modes (matches assembly/memory-page.ts Access enum)
|
|
10
|
+
const ACCESS_READ = 1;
|
|
11
|
+
const ACCESS_WRITE = 2;
|
|
9
12
|
const HELP_TEXT = `Usage:
|
|
10
13
|
anan-as disassemble [--spi] [--no-metadata] <file.(jam|pvm|spi|bin)>
|
|
11
|
-
anan-as run [--spi] [--no-logs] [--no-metadata] [--no-log-host-call] [--pc <number>] [--gas <number>] <file.jam> [spi-args.bin or hex]
|
|
14
|
+
anan-as run [--spi] [--no-logs] [--no-metadata] [--no-log-host-call] [--pc <number>] [--gas <number>] [--regs <r0,r1,...,r12>] <file.jam> [spi-args.bin or hex]
|
|
12
15
|
anan-as replay-trace [--no-metadata] [--no-verify] [--no-logs] [--no-log-host-call] <trace.log>
|
|
13
16
|
|
|
14
17
|
Commands:
|
|
@@ -24,6 +27,10 @@ Flags:
|
|
|
24
27
|
--no-verify Skip verification against trace data (replay-trace only)
|
|
25
28
|
--pc <number> Set initial program counter (default: 0)
|
|
26
29
|
--gas <number> Set initial gas amount (default: 10_000)
|
|
30
|
+
--regs <values> Set initial registers (comma-separated, 13 values: r0,r1,...,r12; supports decimal and 0x hex)
|
|
31
|
+
--pages <specs> Add memory pages (semicolon-separated: "addr:size;addr:size:ro"; append ":r" or ":ro" for read-only)
|
|
32
|
+
--mem <specs> Initialize memory (semicolon-separated: "addr:hex_bytes;addr:hex_bytes")
|
|
33
|
+
--dump <specs> Dump memory after execution (semicolon-separated: "addr:len;addr:len")
|
|
27
34
|
--help, -h Show this help message`;
|
|
28
35
|
main();
|
|
29
36
|
function main() {
|
|
@@ -84,7 +91,7 @@ function handleDisassemble(args) {
|
|
|
84
91
|
console.error("Supported extensions: .jam, .pvm, .spi, .bin");
|
|
85
92
|
process.exit(1);
|
|
86
93
|
}
|
|
87
|
-
const ext = file.
|
|
94
|
+
const ext = file.slice(dotIndex);
|
|
88
95
|
if (!validExtensions.includes(ext)) {
|
|
89
96
|
console.error(`Error: Invalid file extension '${ext}' for disassemble command.`);
|
|
90
97
|
console.error("Supported extensions: .jam, .pvm, .spi, .bin");
|
|
@@ -109,6 +116,10 @@ function handleRun(args) {
|
|
|
109
116
|
help: { type: "boolean", short: "h", default: false },
|
|
110
117
|
pc: { type: "string" },
|
|
111
118
|
gas: { type: "string" },
|
|
119
|
+
regs: { type: "string" },
|
|
120
|
+
pages: { type: "string" },
|
|
121
|
+
mem: { type: "string" },
|
|
122
|
+
dump: { type: "string" },
|
|
112
123
|
},
|
|
113
124
|
});
|
|
114
125
|
if (values.help) {
|
|
@@ -150,13 +161,18 @@ function handleRun(args) {
|
|
|
150
161
|
// Parse and validate PC and gas options
|
|
151
162
|
const initialPc = parsePc(values.pc);
|
|
152
163
|
const initialGas = parseGas(values.gas);
|
|
164
|
+
const initialRegisters = parseRegs(values.regs);
|
|
165
|
+
const initialPages = parsePages(values.pages);
|
|
166
|
+
const initialMemory = parseMem(values.mem);
|
|
167
|
+
const dumpRegions = parseDump(values.dump);
|
|
153
168
|
const programCode = Array.from(readFileSync(programFile));
|
|
154
169
|
const name = kind === InputKind.Generic ? "generic PVM" : "JAM SPI";
|
|
155
170
|
console.log(`🚀 Running ${programFile} (as ${name})`);
|
|
156
171
|
try {
|
|
157
172
|
const preallocateMemoryPages = 128;
|
|
158
|
-
const
|
|
159
|
-
const
|
|
173
|
+
const useBlockGas = true;
|
|
174
|
+
const program = prepareProgram(kind, hasMetadata, programCode, initialRegisters, initialPages, initialMemory, spiArgs, preallocateMemoryPages, useBlockGas);
|
|
175
|
+
const id = pvmStart(program);
|
|
160
176
|
let gas = initialGas;
|
|
161
177
|
let pc = initialPc;
|
|
162
178
|
for (;;) {
|
|
@@ -179,6 +195,24 @@ function handleRun(args) {
|
|
|
179
195
|
break;
|
|
180
196
|
}
|
|
181
197
|
}
|
|
198
|
+
// Dump memory regions before destroying the VM
|
|
199
|
+
for (const region of dumpRegions) {
|
|
200
|
+
const data = pvmReadMemory(id, region.address, region.length);
|
|
201
|
+
const addrHex = `0x${region.address.toString(16)}`;
|
|
202
|
+
if (data) {
|
|
203
|
+
console.log(`\nMemory @ ${addrHex} (${region.length} bytes):`);
|
|
204
|
+
for (let off = 0; off < data.length; off += 16) {
|
|
205
|
+
const addr = region.address + off;
|
|
206
|
+
const slice = Array.from(data.slice(off, Math.min(off + 16, data.length)));
|
|
207
|
+
const hex = slice.map((b) => b.toString(16).padStart(2, "0")).join(" ");
|
|
208
|
+
const ascii = slice.map((b) => (b >= 0x20 && b < 0x7f ? String.fromCharCode(b) : ".")).join("");
|
|
209
|
+
console.log(` ${addr.toString(16).padStart(8, "0")}: ${hex.padEnd(47)} ${ascii}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
console.log(`\nMemory @ ${addrHex}: <page fault>`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
182
216
|
const result = pvmDestroy(id);
|
|
183
217
|
console.log(`Status: ${result?.status}`);
|
|
184
218
|
console.log(`Exit code: ${result?.exitCode}`);
|
|
@@ -292,3 +326,102 @@ function parsePc(pcStr) {
|
|
|
292
326
|
}
|
|
293
327
|
return pcValue;
|
|
294
328
|
}
|
|
329
|
+
function parseRegs(regsStr) {
|
|
330
|
+
if (regsStr === undefined) {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
const parts = regsStr.split(",");
|
|
334
|
+
if (parts.length !== 13) {
|
|
335
|
+
throw new Error(`--regs must have exactly 13 comma-separated values (got ${parts.length}).\nFormat: --regs r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12`);
|
|
336
|
+
}
|
|
337
|
+
return parts.map((s, i) => {
|
|
338
|
+
try {
|
|
339
|
+
return BigInt.asUintN(64, BigInt(s.trim()));
|
|
340
|
+
}
|
|
341
|
+
catch (_e) {
|
|
342
|
+
throw new Error(`--regs value at index ${i} ("${s.trim()}") is not a valid integer.`);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function parseNum(s) {
|
|
347
|
+
return Number(s.trim());
|
|
348
|
+
}
|
|
349
|
+
function parsePages(pagesStr) {
|
|
350
|
+
if (pagesStr === undefined) {
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
353
|
+
// Format: "addr:size;addr:size" — all pages are writable
|
|
354
|
+
// Or "addr:size:ro" (or "addr:size:r") for read-only
|
|
355
|
+
const specs = pagesStr.split(";").filter((s) => s.trim().length > 0);
|
|
356
|
+
return specs.map((spec, i) => {
|
|
357
|
+
const parts = spec.split(":");
|
|
358
|
+
if (parts.length < 2 || parts.length > 3) {
|
|
359
|
+
throw new Error(`--pages entry ${i} ("${spec}") must be "addr:size" or "addr:size:ro" (or "addr:size:r").`);
|
|
360
|
+
}
|
|
361
|
+
const address = parseNum(parts[0]);
|
|
362
|
+
const length = parseNum(parts[1]);
|
|
363
|
+
const flag = parts[2]?.trim();
|
|
364
|
+
const access = flag === "ro" || flag === "r" ? ACCESS_READ : ACCESS_WRITE;
|
|
365
|
+
if (Number.isNaN(address) || Number.isNaN(length) || length <= 0) {
|
|
366
|
+
throw new Error(`--pages entry ${i} ("${spec}") has invalid address or size.`);
|
|
367
|
+
}
|
|
368
|
+
return { address, length, access };
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
function parseMem(memStr) {
|
|
372
|
+
if (memStr === undefined) {
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
375
|
+
// Format: "addr:hexbytes;addr:hexbytes"
|
|
376
|
+
// Example: "0x20000:0500000000000000;0x20008:0300000000000000"
|
|
377
|
+
const specs = memStr.split(";").filter((s) => s.trim().length > 0);
|
|
378
|
+
return specs.map((spec, i) => {
|
|
379
|
+
const colonIdx = spec.indexOf(":");
|
|
380
|
+
if (colonIdx === -1) {
|
|
381
|
+
throw new Error(`--mem entry ${i} ("${spec}") must be "addr:hexbytes".`);
|
|
382
|
+
}
|
|
383
|
+
const addrStr = spec.slice(0, colonIdx).trim();
|
|
384
|
+
let hexStr = spec.slice(colonIdx + 1).trim();
|
|
385
|
+
const address = parseNum(addrStr);
|
|
386
|
+
if (Number.isNaN(address)) {
|
|
387
|
+
throw new Error(`--mem entry ${i} has invalid address "${addrStr}".`);
|
|
388
|
+
}
|
|
389
|
+
// Strip 0x prefix from hex data
|
|
390
|
+
if (hexStr.startsWith("0x") || hexStr.startsWith("0X")) {
|
|
391
|
+
hexStr = hexStr.slice(2);
|
|
392
|
+
}
|
|
393
|
+
if (hexStr.length % 2 !== 0) {
|
|
394
|
+
throw new Error(`--mem entry ${i} hex data has odd length.`);
|
|
395
|
+
}
|
|
396
|
+
const data = [];
|
|
397
|
+
for (let j = 0; j < hexStr.length; j += 2) {
|
|
398
|
+
const pair = hexStr.slice(j, j + 2);
|
|
399
|
+
if (!/^[0-9a-fA-F]{2}$/.test(pair)) {
|
|
400
|
+
throw new Error(`--mem entry ${i} has invalid hex byte at position ${j}: "${pair}".`);
|
|
401
|
+
}
|
|
402
|
+
const byte = parseInt(pair, 16);
|
|
403
|
+
data.push(byte);
|
|
404
|
+
}
|
|
405
|
+
return { address, data };
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function parseDump(dumpStr) {
|
|
409
|
+
if (dumpStr === undefined) {
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
// Format: "addr:len;addr:len"
|
|
413
|
+
// Example: "0x20000:64;0x20100:32"
|
|
414
|
+
const specs = dumpStr.split(";").filter((s) => s.trim().length > 0);
|
|
415
|
+
return specs.map((spec, i) => {
|
|
416
|
+
const parts = spec.split(":");
|
|
417
|
+
if (parts.length !== 2) {
|
|
418
|
+
throw new Error(`--dump entry ${i} ("${spec}") must be "addr:len".`);
|
|
419
|
+
}
|
|
420
|
+
const address = parseNum(parts[0]);
|
|
421
|
+
const length = parseNum(parts[1]);
|
|
422
|
+
if (Number.isNaN(address) || Number.isNaN(length) || length <= 0) {
|
|
423
|
+
throw new Error(`--dump entry ${i} ("${spec}") has invalid address or length.`);
|
|
424
|
+
}
|
|
425
|
+
return { address, length };
|
|
426
|
+
});
|
|
427
|
+
}
|
package/dist/bin/src/fuzz.js
CHANGED
|
@@ -8,7 +8,7 @@ const runNumber = 0;
|
|
|
8
8
|
export function fuzz(data) {
|
|
9
9
|
const gas = 200n;
|
|
10
10
|
const pc = 0;
|
|
11
|
-
const vm = new
|
|
11
|
+
const vm = Interpreter.new();
|
|
12
12
|
const program = wrapAsProgram(new Uint8Array(data));
|
|
13
13
|
if (program.length > 100) {
|
|
14
14
|
return;
|
|
@@ -21,7 +21,7 @@ export function fuzz(data) {
|
|
|
21
21
|
.join(",")
|
|
22
22
|
.split(",")
|
|
23
23
|
.map(() => BigInt(0));
|
|
24
|
-
const exe = prepareProgram(InputKind.Generic, HasMetadata.No, Array.from(program), registers, [], [], [], 0);
|
|
24
|
+
const exe = prepareProgram(InputKind.Generic, HasMetadata.No, Array.from(program), registers, [], [], [], 0, false);
|
|
25
25
|
const output = runProgram(exe, gas, pc, printDebugInfo);
|
|
26
26
|
const vmRegisters = decodeRegistersFromTypeberry(vm);
|
|
27
27
|
collectErrors((assertFn) => {
|
|
@@ -16,18 +16,14 @@ export function run(processJson, options) {
|
|
|
16
16
|
args.shift();
|
|
17
17
|
options.isDebug = true;
|
|
18
18
|
}
|
|
19
|
-
else if (args[0] === "--sbrk-gas") {
|
|
20
|
-
args.shift();
|
|
21
|
-
options.useSbrkGas = true;
|
|
22
|
-
}
|
|
23
19
|
else {
|
|
24
20
|
break;
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
23
|
if (args.length === 0) {
|
|
28
24
|
console.error("Error: No JSON files provided.");
|
|
29
|
-
console.error("Usage: index.js [--debug]
|
|
30
|
-
console.error("read from stdin: index.js [--debug]
|
|
25
|
+
console.error("Usage: index.js [--debug] <file1.json> [file2.json ...]");
|
|
26
|
+
console.error("read from stdin: index.js [--debug] -");
|
|
31
27
|
process.exit(1);
|
|
32
28
|
}
|
|
33
29
|
if (args[0] === "-") {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import
|
|
2
|
+
import * as defaultPvm from "../../build/release.js";
|
|
3
3
|
import { LOG_HOST_CALL_INDEX, printLogHostCall } from "./log-host-call.js";
|
|
4
|
-
import {
|
|
4
|
+
import { buildInitialChunks, buildInitialPages, encodeRegistersFromDump, extractSpiArgs, isSpiTrace, parseTrace, STATUS, statusToTermination, } from "./trace-parse.js";
|
|
5
5
|
import { ConsoleTracer } from "./tracer.js";
|
|
6
6
|
import { hexEncode } from "./utils.js";
|
|
7
7
|
export function replayTraceFile(filePath, options) {
|
|
8
|
+
const pvm = options.pvm ?? defaultPvm;
|
|
9
|
+
const { prepareProgram, pvmStart, pvmDestroy, pvmResume, pvmReadMemory, pvmWriteMemory, pvmSetRegisters, InputKind } = pvm;
|
|
8
10
|
const input = readFileSync(filePath, "utf8");
|
|
9
11
|
const trace = parseTrace(input);
|
|
10
12
|
const { program, initialMemWrites, start, ecalliEntries, termination } = trace;
|
|
@@ -12,20 +14,23 @@ export function replayTraceFile(filePath, options) {
|
|
|
12
14
|
const useSpi = isSpiTrace(start, initialMemWrites);
|
|
13
15
|
const programInput = Array.from(program);
|
|
14
16
|
const spiArgs = Array.from(extractSpiArgs(start, initialMemWrites));
|
|
17
|
+
const preallocateMemoryPages = 128;
|
|
18
|
+
const useBlockGas = options.useBlockGas ?? false;
|
|
15
19
|
const preparedProgram = useSpi
|
|
16
|
-
? prepareProgram(InputKind.SPI, hasMetadata, programInput, [], [], [], spiArgs,
|
|
17
|
-
: prepareProgram(InputKind.Generic, hasMetadata, programInput, encodeRegistersFromDump(start.registers), buildInitialPages(initialMemWrites), buildInitialChunks(initialMemWrites), [],
|
|
18
|
-
const id = pvmStart(preparedProgram
|
|
20
|
+
? prepareProgram(InputKind.SPI, hasMetadata, programInput, [], [], [], spiArgs, preallocateMemoryPages, useBlockGas)
|
|
21
|
+
: prepareProgram(InputKind.Generic, hasMetadata, programInput, encodeRegistersFromDump(start.registers), buildInitialPages(initialMemWrites), buildInitialChunks(initialMemWrites), [], preallocateMemoryPages, useBlockGas);
|
|
22
|
+
const id = pvmStart(preparedProgram);
|
|
19
23
|
const initialEcalliCount = ecalliEntries.length;
|
|
20
24
|
const tracer = options.tracer ?? new ConsoleTracer();
|
|
21
25
|
try {
|
|
22
26
|
let gas = start.gas;
|
|
23
27
|
let pc = start.pc;
|
|
24
|
-
// Print start
|
|
25
|
-
tracer.
|
|
26
|
-
|
|
27
|
-
tracer.
|
|
28
|
+
// Print prelude: program, initial memwrites, start
|
|
29
|
+
tracer.program(program);
|
|
30
|
+
for (const write of initialMemWrites) {
|
|
31
|
+
tracer.memwrite(write.address, write.data);
|
|
28
32
|
}
|
|
33
|
+
tracer.start(pc, gas, start.registers);
|
|
29
34
|
for (;;) {
|
|
30
35
|
const pause = pvmResume(id, gas, pc, options.logs);
|
|
31
36
|
if (!pause) {
|
package/dist/bin/src/tracer.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
// Trace output format: https://github.com/FluffyLabs/jam-ecalli-trace/blob/main/ecalli-trace-jip.md
|
|
2
2
|
export class ConsoleTracer {
|
|
3
|
+
program(data) {
|
|
4
|
+
console.log(`program ${formatHex(data)}`);
|
|
5
|
+
}
|
|
3
6
|
start(pc, gas, registers) {
|
|
4
7
|
console.log(`start pc=${pc} gas=${gas} ${formatRegisters(registers)}`);
|
|
5
8
|
}
|
|
6
|
-
spiArgs(address, data) {
|
|
7
|
-
console.log(` memwrite ${address} len=${data.length} <- ${hexEncode(data)}`);
|
|
8
|
-
}
|
|
9
9
|
ecalli(index, pc, gas, registers) {
|
|
10
|
-
console.log(
|
|
10
|
+
console.log(`ecalli=${index} pc=${pc} gas=${gas} ${formatRegisters(registers)}`);
|
|
11
11
|
}
|
|
12
12
|
memread(address, data) {
|
|
13
|
-
console.log(`
|
|
13
|
+
console.log(` memread ${formatAddress(address)} len=${data.length} -> ${formatHex(data)}`);
|
|
14
14
|
}
|
|
15
15
|
memwrite(address, data) {
|
|
16
|
-
console.log(`
|
|
16
|
+
console.log(` memwrite ${formatAddress(address)} len=${data.length} <- ${formatHex(data)}`);
|
|
17
17
|
}
|
|
18
18
|
setreg(index, value) {
|
|
19
|
-
console.log(`
|
|
19
|
+
console.log(` setreg r${index.toString().padStart(2, "0")} <- 0x${value.toString(16)}`);
|
|
20
20
|
}
|
|
21
21
|
setgas(gas) {
|
|
22
|
-
console.log(`
|
|
22
|
+
console.log(` setgas <- ${gas}`);
|
|
23
23
|
}
|
|
24
24
|
termination(type, exitCode, pc, gas, registers) {
|
|
25
|
-
let termLine =
|
|
26
|
-
if (type === "PANIC"
|
|
25
|
+
let termLine = `${type}`;
|
|
26
|
+
if (type === "PANIC") {
|
|
27
27
|
termLine += `=${exitCode}`;
|
|
28
28
|
}
|
|
29
29
|
termLine += ` pc=${pc} gas=${gas} ${formatRegisters(registers)}`;
|
|
@@ -31,8 +31,8 @@ export class ConsoleTracer {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
export class NoOpTracer {
|
|
34
|
+
program() { }
|
|
34
35
|
start() { }
|
|
35
|
-
spiArgs() { }
|
|
36
36
|
ecalli() { }
|
|
37
37
|
memread() { }
|
|
38
38
|
memwrite() { }
|
|
@@ -56,9 +56,12 @@ function formatRegisters(registers) {
|
|
|
56
56
|
}
|
|
57
57
|
return entries
|
|
58
58
|
.sort((a, b) => a.idx - b.idx)
|
|
59
|
-
.map((e) => `r${e.idx}=0x${e.val.toString(16)}`)
|
|
59
|
+
.map((e) => `r${e.idx.toString().padStart(2, "0")}=0x${e.val.toString(16)}`)
|
|
60
60
|
.join(" ");
|
|
61
61
|
}
|
|
62
|
+
function formatAddress(address) {
|
|
63
|
+
return `0x${Number(address).toString(16).padStart(8, "0")}`;
|
|
64
|
+
}
|
|
62
65
|
function formatHex(data) {
|
|
63
66
|
return `0x${Buffer.from(data).toString("hex")}`;
|
|
64
67
|
}
|
package/dist/bin/src/utils.js
CHANGED
|
@@ -6,14 +6,14 @@ export function hexDecode(data) {
|
|
|
6
6
|
if (!data.startsWith("0x")) {
|
|
7
7
|
throw new Error("hex input must start with 0x");
|
|
8
8
|
}
|
|
9
|
-
const hex = data.
|
|
9
|
+
const hex = data.slice(2);
|
|
10
10
|
const len = hex.length;
|
|
11
11
|
if (len % 2 === 1) {
|
|
12
12
|
throw new Error("Odd number of nibbles");
|
|
13
13
|
}
|
|
14
14
|
const bytes = new Uint8Array(len / 2);
|
|
15
15
|
for (let i = 0; i < len; i += 2) {
|
|
16
|
-
const c = hex.
|
|
16
|
+
const c = hex.slice(i, i + 2);
|
|
17
17
|
const byteIndex = i / 2;
|
|
18
18
|
if (!/^[0-9a-fA-F]{2}$/.test(c)) {
|
|
19
19
|
throw new Error(`hexDecode: invalid hex pair "${c}" in data "${data}" for bytes[${byteIndex}]`);
|