@fluffylabs/anan-as 1.1.6 → 1.2.0-1c29182
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 +186 -53
- package/dist/bin/src/fuzz.js +1 -1
- package/dist/bin/src/test-json.js +2 -6
- package/dist/bin/src/trace-replay.js +8 -4
- 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 +63 -112
- package/dist/build/debug-raw.js +86 -139
- package/dist/build/debug-raw.wasm +0 -0
- package/dist/build/debug.d.ts +63 -112
- package/dist/build/debug.js +91 -147
- package/dist/build/debug.wasm +0 -0
- package/dist/build/js/assembly/api-debugger.d.ts +55 -0
- package/dist/build/js/assembly/api-debugger.js +245 -0
- package/dist/build/js/assembly/api-internal.d.ts +13 -0
- package/dist/build/js/assembly/api-internal.js +191 -0
- package/dist/build/js/assembly/api-types.d.ts +45 -0
- package/dist/build/js/assembly/api-types.js +52 -0
- package/dist/build/js/assembly/api-utils.d.ts +79 -0
- package/dist/build/js/assembly/api-utils.js +221 -0
- package/dist/build/js/assembly/arguments.d.ts +44 -0
- package/dist/build/js/assembly/arguments.js +164 -0
- package/dist/build/js/assembly/codec.d.ts +24 -0
- package/dist/build/js/assembly/codec.js +139 -0
- package/dist/build/js/assembly/gas.d.ts +11 -0
- package/dist/build/js/assembly/gas.js +33 -0
- package/dist/build/js/assembly/index-shared.d.ts +4 -0
- package/dist/build/js/assembly/index-shared.js +4 -0
- package/dist/build/js/assembly/instructions/bit.d.ts +11 -0
- package/dist/build/js/assembly/instructions/bit.js +53 -0
- package/dist/build/js/assembly/instructions/branch.d.ts +17 -0
- package/dist/build/js/assembly/instructions/branch.js +120 -0
- package/dist/build/js/assembly/instructions/jump.d.ts +5 -0
- package/dist/build/js/assembly/instructions/jump.js +21 -0
- package/dist/build/js/assembly/instructions/load.d.ts +17 -0
- package/dist/build/js/assembly/instructions/load.js +134 -0
- package/dist/build/js/assembly/instructions/logic.d.ts +10 -0
- package/dist/build/js/assembly/instructions/logic.js +47 -0
- package/dist/build/js/assembly/instructions/math.d.ts +28 -0
- package/dist/build/js/assembly/instructions/math.js +225 -0
- package/dist/build/js/assembly/instructions/misc.d.ts +6 -0
- package/dist/build/js/assembly/instructions/misc.js +22 -0
- package/dist/build/js/assembly/instructions/mov.d.ts +6 -0
- package/dist/build/js/assembly/instructions/mov.js +35 -0
- package/dist/build/js/assembly/instructions/outcome.d.ts +30 -0
- package/dist/build/js/assembly/instructions/outcome.js +88 -0
- package/dist/build/js/assembly/instructions/rot.d.ts +15 -0
- package/dist/build/js/assembly/instructions/rot.js +66 -0
- package/dist/build/js/assembly/instructions/set.d.ts +7 -0
- package/dist/build/js/assembly/instructions/set.js +36 -0
- package/dist/build/js/assembly/instructions/shift.d.ts +19 -0
- package/dist/build/js/assembly/instructions/shift.js +121 -0
- package/dist/build/js/assembly/instructions/store.d.ts +17 -0
- package/dist/build/js/assembly/instructions/store.js +101 -0
- package/dist/build/js/assembly/instructions/utils.d.ts +25 -0
- package/dist/build/js/assembly/instructions/utils.js +91 -0
- package/dist/build/js/assembly/instructions-exe.d.ts +2 -0
- package/dist/build/js/assembly/instructions-exe.js +245 -0
- package/dist/build/js/assembly/instructions.d.ts +10 -0
- package/dist/build/js/assembly/instructions.js +252 -0
- package/dist/build/js/assembly/interpreter.d.ts +28 -0
- package/dist/build/js/assembly/interpreter.js +221 -0
- package/dist/build/js/assembly/math.d.ts +6 -0
- package/dist/build/js/assembly/math.js +22 -0
- package/dist/build/js/assembly/memory-page.d.ts +36 -0
- package/dist/build/js/assembly/memory-page.js +74 -0
- package/dist/build/js/assembly/memory.d.ts +83 -0
- package/dist/build/js/assembly/memory.js +482 -0
- package/dist/build/js/assembly/portable.d.ts +24 -0
- package/dist/build/js/assembly/portable.js +363 -0
- package/dist/build/js/assembly/program-build.d.ts +2 -0
- package/dist/build/js/assembly/program-build.js +104 -0
- package/dist/build/js/assembly/program.d.ts +85 -0
- package/dist/build/js/assembly/program.js +340 -0
- package/dist/build/js/assembly/registers.d.ts +6 -0
- package/dist/build/js/assembly/registers.js +9 -0
- package/dist/build/js/assembly/spi.d.ts +92 -0
- package/dist/build/js/assembly/spi.js +152 -0
- package/dist/build/js/portable/bootstrap.d.ts +1 -0
- package/dist/build/js/portable/bootstrap.js +5 -0
- package/dist/build/js/portable/index.d.ts +4 -0
- package/dist/build/js/portable/index.js +6 -0
- package/dist/build/js/portable-bundle.js +4496 -0
- package/dist/build/release-inline.js +1 -1
- package/dist/build/release-mini-inline.js +1 -1
- package/dist/build/release-mini.d.ts +63 -112
- package/dist/build/release-mini.js +91 -147
- package/dist/build/release-mini.wasm +0 -0
- package/dist/build/release-stub-inline.js +1 -1
- package/dist/build/release-stub.d.ts +63 -112
- package/dist/build/release-stub.js +91 -147
- package/dist/build/release-stub.wasm +0 -0
- package/dist/build/release.d.ts +63 -112
- package/dist/build/release.js +91 -147
- 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-w3f-common.js +125 -0
- package/dist/test/test-w3f-portable.js +5 -0
- package/dist/test/test-w3f.js +3 -120
- package/package.json +24 -12
package/dist/bin/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
-
import
|
|
4
|
-
import { disassemble, HasMetadata, InputKind, prepareProgram, pvmDestroy, pvmResume, pvmSetRegisters, pvmStart, } from "../build/release.js";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
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() {
|
|
@@ -52,16 +59,19 @@ function main() {
|
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
function handleDisassemble(args) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
const { values, positionals: files } = parseArgs({
|
|
63
|
+
args,
|
|
64
|
+
allowPositionals: true,
|
|
65
|
+
options: {
|
|
66
|
+
spi: { type: "boolean", default: false },
|
|
67
|
+
"no-metadata": { type: "boolean", default: false },
|
|
68
|
+
help: { type: "boolean", short: "h", default: false },
|
|
69
|
+
},
|
|
59
70
|
});
|
|
60
|
-
if (
|
|
71
|
+
if (values.help) {
|
|
61
72
|
console.log(HELP_TEXT);
|
|
62
73
|
return;
|
|
63
74
|
}
|
|
64
|
-
const files = parsed._;
|
|
65
75
|
if (files.length === 0) {
|
|
66
76
|
console.error("Error: No file provided for disassemble command.");
|
|
67
77
|
console.error("Usage: anan-as disassemble [--spi] [--no-metadata] <file.(jam|pvm|spi|bin)>");
|
|
@@ -87,32 +97,41 @@ function handleDisassemble(args) {
|
|
|
87
97
|
console.error("Supported extensions: .jam, .pvm, .spi, .bin");
|
|
88
98
|
process.exit(1);
|
|
89
99
|
}
|
|
90
|
-
const kind =
|
|
91
|
-
const hasMetadata =
|
|
100
|
+
const kind = values.spi ? InputKind.SPI : InputKind.Generic;
|
|
101
|
+
const hasMetadata = values["no-metadata"] ? HasMetadata.No : HasMetadata.Yes;
|
|
92
102
|
const f = readFileSync(file);
|
|
93
103
|
const name = kind === InputKind.Generic ? "generic PVM" : "JAM SPI";
|
|
94
104
|
console.log(`🤖 Assembly of ${file} (as ${name})`);
|
|
95
105
|
console.log(disassemble(Array.from(f), kind, hasMetadata));
|
|
96
106
|
}
|
|
97
107
|
function handleRun(args) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
const { values, positionals: files } = parseArgs({
|
|
109
|
+
args,
|
|
110
|
+
allowPositionals: true,
|
|
111
|
+
options: {
|
|
112
|
+
spi: { type: "boolean", default: false },
|
|
113
|
+
"no-logs": { type: "boolean", default: false },
|
|
114
|
+
"no-metadata": { type: "boolean", default: false },
|
|
115
|
+
"no-log-host-call": { type: "boolean", default: false },
|
|
116
|
+
help: { type: "boolean", short: "h", default: false },
|
|
117
|
+
pc: { type: "string" },
|
|
118
|
+
gas: { type: "string" },
|
|
119
|
+
regs: { type: "string" },
|
|
120
|
+
pages: { type: "string" },
|
|
121
|
+
mem: { type: "string" },
|
|
122
|
+
dump: { type: "string" },
|
|
123
|
+
},
|
|
104
124
|
});
|
|
105
|
-
if (
|
|
125
|
+
if (values.help) {
|
|
106
126
|
console.log(HELP_TEXT);
|
|
107
127
|
return;
|
|
108
128
|
}
|
|
109
|
-
const files = parsed._;
|
|
110
129
|
if (files.length === 0) {
|
|
111
130
|
console.error("Error: No file provided for run command.");
|
|
112
131
|
console.error("Usage: anan-as run [--spi] [--no-logs] [--no-metadata] [--pc <number>] [--gas <number>] <file.jam> [spi-args.bin]");
|
|
113
132
|
process.exit(1);
|
|
114
133
|
}
|
|
115
|
-
const kind =
|
|
134
|
+
const kind = values.spi ? InputKind.SPI : InputKind.Generic;
|
|
116
135
|
let programFile;
|
|
117
136
|
let spiArgsStr;
|
|
118
137
|
if (kind === InputKind.SPI) {
|
|
@@ -136,19 +155,24 @@ function handleRun(args) {
|
|
|
136
155
|
}
|
|
137
156
|
// Validate SPI args file if provided
|
|
138
157
|
const spiArgs = parseSpiArgs(spiArgsStr);
|
|
139
|
-
const logs =
|
|
140
|
-
const logHostCall =
|
|
141
|
-
const hasMetadata =
|
|
158
|
+
const logs = !values["no-logs"];
|
|
159
|
+
const logHostCall = !values["no-log-host-call"];
|
|
160
|
+
const hasMetadata = values["no-metadata"] ? HasMetadata.No : HasMetadata.Yes;
|
|
142
161
|
// Parse and validate PC and gas options
|
|
143
|
-
const initialPc = parsePc(
|
|
144
|
-
const initialGas = parseGas(
|
|
162
|
+
const initialPc = parsePc(values.pc);
|
|
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);
|
|
145
168
|
const programCode = Array.from(readFileSync(programFile));
|
|
146
169
|
const name = kind === InputKind.Generic ? "generic PVM" : "JAM SPI";
|
|
147
170
|
console.log(`🚀 Running ${programFile} (as ${name})`);
|
|
148
171
|
try {
|
|
149
172
|
const preallocateMemoryPages = 128;
|
|
150
|
-
const
|
|
151
|
-
const
|
|
173
|
+
const useBlockGas = true;
|
|
174
|
+
const program = prepareProgram(kind, hasMetadata, programCode, initialRegisters, initialPages, initialMemory, spiArgs, preallocateMemoryPages, useBlockGas);
|
|
175
|
+
const id = pvmStart(program);
|
|
152
176
|
let gas = initialGas;
|
|
153
177
|
let pc = initialPc;
|
|
154
178
|
for (;;) {
|
|
@@ -171,6 +195,24 @@ function handleRun(args) {
|
|
|
171
195
|
break;
|
|
172
196
|
}
|
|
173
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
|
+
}
|
|
174
216
|
const result = pvmDestroy(id);
|
|
175
217
|
console.log(`Status: ${result?.status}`);
|
|
176
218
|
console.log(`Exit code: ${result?.exitCode}`);
|
|
@@ -185,16 +227,21 @@ function handleRun(args) {
|
|
|
185
227
|
}
|
|
186
228
|
}
|
|
187
229
|
function handleReplayTrace(args) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
230
|
+
const { values, positionals: files } = parseArgs({
|
|
231
|
+
args,
|
|
232
|
+
allowPositionals: true,
|
|
233
|
+
options: {
|
|
234
|
+
"no-metadata": { type: "boolean", default: false },
|
|
235
|
+
"no-verify": { type: "boolean", default: false },
|
|
236
|
+
"no-logs": { type: "boolean", default: false },
|
|
237
|
+
"no-log-host-call": { type: "boolean", default: false },
|
|
238
|
+
help: { type: "boolean", short: "h", default: false },
|
|
239
|
+
},
|
|
192
240
|
});
|
|
193
|
-
if (
|
|
241
|
+
if (values.help) {
|
|
194
242
|
console.log(HELP_TEXT);
|
|
195
243
|
return;
|
|
196
244
|
}
|
|
197
|
-
const files = parsed._;
|
|
198
245
|
if (files.length === 0) {
|
|
199
246
|
console.error("Error: No trace file provided for replay-trace command.");
|
|
200
247
|
console.error("Usage: anan-as replay-trace [--no-metadata] [--no-verify] [--no-logs] <trace.log>");
|
|
@@ -206,10 +253,10 @@ function handleReplayTrace(args) {
|
|
|
206
253
|
process.exit(1);
|
|
207
254
|
}
|
|
208
255
|
const file = files[0];
|
|
209
|
-
const hasMetadata =
|
|
210
|
-
const verify =
|
|
211
|
-
const logs =
|
|
212
|
-
const logHostCall =
|
|
256
|
+
const hasMetadata = values["no-metadata"] ? HasMetadata.No : HasMetadata.Yes;
|
|
257
|
+
const verify = !values["no-verify"];
|
|
258
|
+
const logs = !values["no-logs"];
|
|
259
|
+
const logHostCall = !values["no-log-host-call"];
|
|
213
260
|
try {
|
|
214
261
|
const summary = replayTraceFile(file, {
|
|
215
262
|
logs,
|
|
@@ -227,16 +274,10 @@ function handleReplayTrace(args) {
|
|
|
227
274
|
process.exit(1);
|
|
228
275
|
}
|
|
229
276
|
}
|
|
230
|
-
function parseGas(
|
|
231
|
-
if (
|
|
277
|
+
function parseGas(gasStr) {
|
|
278
|
+
if (gasStr === undefined) {
|
|
232
279
|
return BigInt(10_000);
|
|
233
280
|
}
|
|
234
|
-
// Ensure it's a string/number, not boolean
|
|
235
|
-
if (typeof parsed.gas === "boolean") {
|
|
236
|
-
console.error("Error: --gas requires a value.");
|
|
237
|
-
process.exit(1);
|
|
238
|
-
}
|
|
239
|
-
const gasStr = String(parsed.gas);
|
|
240
281
|
// Reject floats and non-integer strings
|
|
241
282
|
if (gasStr.includes(".") || !/^-?\d+$/.test(gasStr)) {
|
|
242
283
|
console.error("Error: --gas must be a valid integer.");
|
|
@@ -269,16 +310,10 @@ function parseSpiArgs(spiArgsStr) {
|
|
|
269
310
|
return Array.from(readFileSync(spiArgsStr));
|
|
270
311
|
}
|
|
271
312
|
}
|
|
272
|
-
function parsePc(
|
|
273
|
-
if (
|
|
313
|
+
function parsePc(pcStr) {
|
|
314
|
+
if (pcStr === undefined) {
|
|
274
315
|
return 0;
|
|
275
316
|
}
|
|
276
|
-
// Ensure it's a string/number, not boolean
|
|
277
|
-
if (typeof parsed.pc === "boolean") {
|
|
278
|
-
console.error("Error: --pc requires a value.");
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
const pcStr = String(parsed.pc);
|
|
282
317
|
// Reject floats and non-integer strings
|
|
283
318
|
if (pcStr.includes(".") || !/^-?\d+$/.test(pcStr)) {
|
|
284
319
|
console.error("Error: --pc must be a valid integer.");
|
|
@@ -291,3 +326,101 @@ function parsePc(parsed) {
|
|
|
291
326
|
}
|
|
292
327
|
return pcValue;
|
|
293
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.substring(0, colonIdx).trim();
|
|
384
|
+
let hexStr = spec.substring(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.substring(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 byte = parseInt(hexStr.substring(j, j + 2), 16);
|
|
399
|
+
if (Number.isNaN(byte)) {
|
|
400
|
+
throw new Error(`--mem entry ${i} has invalid hex byte at position ${j}: "${hexStr.substring(j, j + 2)}".`);
|
|
401
|
+
}
|
|
402
|
+
data.push(byte);
|
|
403
|
+
}
|
|
404
|
+
return { address, data };
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function parseDump(dumpStr) {
|
|
408
|
+
if (dumpStr === undefined) {
|
|
409
|
+
return [];
|
|
410
|
+
}
|
|
411
|
+
// Format: "addr:len;addr:len"
|
|
412
|
+
// Example: "0x20000:64;0x20100:32"
|
|
413
|
+
const specs = dumpStr.split(";").filter((s) => s.trim().length > 0);
|
|
414
|
+
return specs.map((spec, i) => {
|
|
415
|
+
const parts = spec.split(":");
|
|
416
|
+
if (parts.length !== 2) {
|
|
417
|
+
throw new Error(`--dump entry ${i} ("${spec}") must be "addr:len".`);
|
|
418
|
+
}
|
|
419
|
+
const address = parseNum(parts[0]);
|
|
420
|
+
const length = parseNum(parts[1]);
|
|
421
|
+
if (Number.isNaN(address) || Number.isNaN(length) || length <= 0) {
|
|
422
|
+
throw new Error(`--dump entry ${i} ("${spec}") has invalid address or length.`);
|
|
423
|
+
}
|
|
424
|
+
return { address, length };
|
|
425
|
+
});
|
|
426
|
+
}
|
package/dist/bin/src/fuzz.js
CHANGED
|
@@ -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
4
|
import { ARGS_SEGMENT_START, 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,10 +14,12 @@ 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 {
|