@fluffylabs/anan-as 1.2.0 → 1.3.0-1ebcf8f

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.
Files changed (110) hide show
  1. package/dist/bin/index.js +138 -5
  2. package/dist/bin/src/fuzz.js +2 -2
  3. package/dist/bin/src/test-json.js +2 -6
  4. package/dist/bin/src/trace-parse.js +1 -0
  5. package/dist/bin/src/trace-replay.js +14 -9
  6. package/dist/bin/src/tracer.js +16 -13
  7. package/dist/bin/src/utils.js +2 -2
  8. package/dist/build/compiler-inline.js +1 -1
  9. package/dist/build/compiler.d.ts +17 -13
  10. package/dist/build/compiler.js +13 -21
  11. package/dist/build/compiler.wasm +0 -0
  12. package/dist/build/debug-inline.js +1 -1
  13. package/dist/build/debug-raw-inline.js +1 -1
  14. package/dist/build/debug-raw.d.ts +50 -112
  15. package/dist/build/debug-raw.js +78 -139
  16. package/dist/build/debug-raw.wasm +0 -0
  17. package/dist/build/debug.d.ts +50 -112
  18. package/dist/build/debug.js +81 -147
  19. package/dist/build/debug.wasm +0 -0
  20. package/dist/build/js/assembly/api-debugger.d.ts +55 -0
  21. package/dist/build/js/assembly/api-debugger.js +245 -0
  22. package/dist/build/js/assembly/api-internal.d.ts +13 -0
  23. package/dist/build/js/assembly/api-internal.js +191 -0
  24. package/dist/build/js/assembly/api-types.d.ts +45 -0
  25. package/dist/build/js/assembly/api-types.js +52 -0
  26. package/dist/build/js/assembly/api-utils.d.ts +79 -0
  27. package/dist/build/js/assembly/api-utils.js +221 -0
  28. package/dist/build/js/assembly/arguments.d.ts +44 -0
  29. package/dist/build/js/assembly/arguments.js +164 -0
  30. package/dist/build/js/assembly/codec.d.ts +24 -0
  31. package/dist/build/js/assembly/codec.js +139 -0
  32. package/dist/build/js/assembly/gas.d.ts +11 -0
  33. package/dist/build/js/assembly/gas.js +33 -0
  34. package/dist/build/js/assembly/index-shared.d.ts +4 -0
  35. package/dist/build/js/assembly/index-shared.js +4 -0
  36. package/dist/build/js/assembly/instructions/bit.d.ts +11 -0
  37. package/dist/build/js/assembly/instructions/bit.js +53 -0
  38. package/dist/build/js/assembly/instructions/branch.d.ts +17 -0
  39. package/dist/build/js/assembly/instructions/branch.js +120 -0
  40. package/dist/build/js/assembly/instructions/jump.d.ts +5 -0
  41. package/dist/build/js/assembly/instructions/jump.js +21 -0
  42. package/dist/build/js/assembly/instructions/load.d.ts +17 -0
  43. package/dist/build/js/assembly/instructions/load.js +134 -0
  44. package/dist/build/js/assembly/instructions/logic.d.ts +10 -0
  45. package/dist/build/js/assembly/instructions/logic.js +47 -0
  46. package/dist/build/js/assembly/instructions/math.d.ts +28 -0
  47. package/dist/build/js/assembly/instructions/math.js +225 -0
  48. package/dist/build/js/assembly/instructions/misc.d.ts +6 -0
  49. package/dist/build/js/assembly/instructions/misc.js +22 -0
  50. package/dist/build/js/assembly/instructions/mov.d.ts +6 -0
  51. package/dist/build/js/assembly/instructions/mov.js +35 -0
  52. package/dist/build/js/assembly/instructions/outcome.d.ts +30 -0
  53. package/dist/build/js/assembly/instructions/outcome.js +88 -0
  54. package/dist/build/js/assembly/instructions/rot.d.ts +15 -0
  55. package/dist/build/js/assembly/instructions/rot.js +66 -0
  56. package/dist/build/js/assembly/instructions/set.d.ts +7 -0
  57. package/dist/build/js/assembly/instructions/set.js +36 -0
  58. package/dist/build/js/assembly/instructions/shift.d.ts +19 -0
  59. package/dist/build/js/assembly/instructions/shift.js +121 -0
  60. package/dist/build/js/assembly/instructions/store.d.ts +17 -0
  61. package/dist/build/js/assembly/instructions/store.js +101 -0
  62. package/dist/build/js/assembly/instructions/utils.d.ts +25 -0
  63. package/dist/build/js/assembly/instructions/utils.js +91 -0
  64. package/dist/build/js/assembly/instructions-exe.d.ts +2 -0
  65. package/dist/build/js/assembly/instructions-exe.js +245 -0
  66. package/dist/build/js/assembly/instructions.d.ts +10 -0
  67. package/dist/build/js/assembly/instructions.js +252 -0
  68. package/dist/build/js/assembly/interpreter.d.ts +28 -0
  69. package/dist/build/js/assembly/interpreter.js +221 -0
  70. package/dist/build/js/assembly/math.d.ts +6 -0
  71. package/dist/build/js/assembly/math.js +22 -0
  72. package/dist/build/js/assembly/memory-page.d.ts +36 -0
  73. package/dist/build/js/assembly/memory-page.js +74 -0
  74. package/dist/build/js/assembly/memory.d.ts +83 -0
  75. package/dist/build/js/assembly/memory.js +482 -0
  76. package/dist/build/js/assembly/portable.d.ts +24 -0
  77. package/dist/build/js/assembly/portable.js +363 -0
  78. package/dist/build/js/assembly/program-build.d.ts +2 -0
  79. package/dist/build/js/assembly/program-build.js +104 -0
  80. package/dist/build/js/assembly/program.d.ts +85 -0
  81. package/dist/build/js/assembly/program.js +340 -0
  82. package/dist/build/js/assembly/registers.d.ts +6 -0
  83. package/dist/build/js/assembly/registers.js +9 -0
  84. package/dist/build/js/assembly/spi.d.ts +92 -0
  85. package/dist/build/js/assembly/spi.js +152 -0
  86. package/dist/build/js/portable/bootstrap.d.ts +1 -0
  87. package/dist/build/js/portable/bootstrap.js +6 -0
  88. package/dist/build/js/portable/index.d.ts +4 -0
  89. package/dist/build/js/portable/index.js +6 -0
  90. package/dist/build/js/portable-bundle.js +4497 -0
  91. package/dist/build/release-inline.js +1 -1
  92. package/dist/build/release-mini-inline.js +1 -1
  93. package/dist/build/release-mini.d.ts +50 -112
  94. package/dist/build/release-mini.js +81 -147
  95. package/dist/build/release-mini.wasm +0 -0
  96. package/dist/build/release-stub-inline.js +1 -1
  97. package/dist/build/release-stub.d.ts +50 -112
  98. package/dist/build/release-stub.js +81 -147
  99. package/dist/build/release-stub.wasm +0 -0
  100. package/dist/build/release.d.ts +50 -112
  101. package/dist/build/release.js +81 -147
  102. package/dist/build/release.wasm +0 -0
  103. package/dist/build/test-inline.js +1 -1
  104. package/dist/build/test.wasm +0 -0
  105. package/dist/test/test-gas-cost.js +2 -3
  106. package/dist/test/test-trace-format.js +166 -0
  107. package/dist/test/test-w3f-common.js +125 -0
  108. package/dist/test/test-w3f-portable.js +5 -0
  109. package/dist/test/test-w3f.js +3 -120
  110. package/package.json +22 -11
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.substring(dotIndex);
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 program = prepareProgram(kind, hasMetadata, programCode, [], [], [], spiArgs, preallocateMemoryPages);
159
- const id = pvmStart(program, false);
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
+ }
@@ -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 Interpreter();
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] [--sbrk-gas] <file1.json> [file2.json ...]");
30
- console.error("read from stdin: index.js [--debug] [--sbrk-gas] -");
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,3 +1,4 @@
1
+ // Trace format: https://github.com/FluffyLabs/jam-ecalli-trace/blob/main/ecalli-trace-jip.md
1
2
  const NO_OF_REGISTERS = 13;
2
3
  // Access.Write = 2 from assembly/memory-page.ts
3
4
  const ACCESS_WRITE = 2;
@@ -1,10 +1,12 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { InputKind, prepareProgram, pvmDestroy, pvmReadMemory, pvmResume, pvmSetRegisters, pvmStart, pvmWriteMemory, } from "../../build/release.js";
2
+ import * as defaultPvm from "../../build/release.js";
3
3
  import { LOG_HOST_CALL_INDEX, printLogHostCall } from "./log-host-call.js";
4
- import { ARGS_SEGMENT_START, buildInitialChunks, buildInitialPages, encodeRegistersFromDump, extractSpiArgs, isSpiTrace, parseTrace, STATUS, statusToTermination, } from "./trace-parse.js";
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, 0)
17
- : prepareProgram(InputKind.Generic, hasMetadata, programInput, encodeRegistersFromDump(start.registers), buildInitialPages(initialMemWrites), buildInitialChunks(initialMemWrites), [], 0);
18
- const id = pvmStart(preparedProgram, true);
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 line
25
- tracer.start(pc, gas, start.registers);
26
- if (spiArgs.length > 0) {
27
- tracer.spiArgs(ARGS_SEGMENT_START, spiArgs);
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) {
@@ -1,29 +1,29 @@
1
- import { hexEncode } from "./utils.js";
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(`\necalli=${index} pc=${pc} gas=${gas} ${formatRegisters(registers)}`);
10
+ console.log(`ecalli=${index} pc=${pc} gas=${gas} ${formatRegisters(registers)}`);
11
11
  }
12
12
  memread(address, data) {
13
- console.log(` memread 0x${address.toString(16)} len=${data.length} -> ${formatHex(data)}`);
13
+ console.log(` memread ${formatAddress(address)} len=${data.length} -> ${formatHex(data)}`);
14
14
  }
15
15
  memwrite(address, data) {
16
- console.log(` memwrite 0x${address.toString(16)} len=${data.length} <- ${formatHex(data)}`);
16
+ console.log(` memwrite ${formatAddress(address)} len=${data.length} <- ${formatHex(data)}`);
17
17
  }
18
18
  setreg(index, value) {
19
- console.log(` setreg r${index.toString().padStart(2, "0")} <- 0x${value.toString(16)}`);
19
+ console.log(` setreg r${index.toString().padStart(2, "0")} <- 0x${value.toString(16)}`);
20
20
  }
21
21
  setgas(gas) {
22
- console.log(` setgas <- ${gas}`);
22
+ console.log(` setgas <- ${gas}`);
23
23
  }
24
24
  termination(type, exitCode, pc, gas, registers) {
25
- let termLine = `\n------\n${type}`;
26
- if (type === "PANIC" && exitCode !== 0) {
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
  }
@@ -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.substring(2);
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.substring(i, i + 2);
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}]`);