@fluffylabs/anan-as 1.2.0 → 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 +50 -112
- package/dist/build/debug-raw.js +78 -139
- package/dist/build/debug-raw.wasm +0 -0
- package/dist/build/debug.d.ts +50 -112
- package/dist/build/debug.js +81 -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 +6 -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 +4497 -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 +50 -112
- package/dist/build/release-mini.js +81 -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 +50 -112
- package/dist/build/release-stub.js +81 -147
- package/dist/build/release-stub.wasm +0 -0
- package/dist/build/release.d.ts +50 -112
- package/dist/build/release.js +81 -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-trace-format.js +166 -0
- 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 +22 -11
package/dist/build/test.wasm
CHANGED
|
Binary file
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import "json-bigint-patch";
|
|
3
3
|
import * as assert from "node:assert";
|
|
4
4
|
import { ERR, OK, read, run } from "../bin/src/test-json.js";
|
|
5
|
-
import { disassemble,
|
|
5
|
+
import { disassemble, getBlockGasCosts, HasMetadata, InputKind } from "../build/release.js";
|
|
6
6
|
// Run the CLI application
|
|
7
7
|
main();
|
|
8
8
|
// Main function
|
|
@@ -10,7 +10,6 @@ function main() {
|
|
|
10
10
|
const options = {
|
|
11
11
|
isDebug: false,
|
|
12
12
|
isSilent: false,
|
|
13
|
-
useSbrkGas: false,
|
|
14
13
|
};
|
|
15
14
|
run(processGasCost, options);
|
|
16
15
|
}
|
|
@@ -29,7 +28,7 @@ function processGasCost(data, options, filePath) {
|
|
|
29
28
|
console.info(assembly);
|
|
30
29
|
console.info("\n^^^^^^^^^^^\n");
|
|
31
30
|
}
|
|
32
|
-
const result = asMap(
|
|
31
|
+
const result = asMap(getBlockGasCosts(input.program, InputKind.Generic, HasMetadata.No));
|
|
33
32
|
// silent mode - just put our vals into expected (comparison done externally)
|
|
34
33
|
if (options.isSilent) {
|
|
35
34
|
data.block_gas_costs = result;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as assert from "node:assert";
|
|
3
|
+
import { parseTrace } from "../bin/src/trace-parse.js";
|
|
4
|
+
// Test: round-trip parse of a spec-compliant trace
|
|
5
|
+
{
|
|
6
|
+
const input = [
|
|
7
|
+
"program 0x0102aabbccddeeff",
|
|
8
|
+
"memwrite 0x00001000 len=8 <- 0x0000000000000001",
|
|
9
|
+
"start pc=0 gas=10000 r07=0x10 r09=0x10000",
|
|
10
|
+
"",
|
|
11
|
+
"ecalli=10 pc=42 gas=9980 r01=0x1 r03=0x1000",
|
|
12
|
+
"memread 0x00001000 len=4 -> 0x01020304",
|
|
13
|
+
"memread 0x00001020 len=8 -> 0x0000000000000040",
|
|
14
|
+
"memwrite 0x00002000 len=2 <- 0xffee",
|
|
15
|
+
"setreg r00 <- 0x100",
|
|
16
|
+
"setreg r02 <- 0x4",
|
|
17
|
+
"setgas <- 9950",
|
|
18
|
+
"",
|
|
19
|
+
"HALT pc=42 gas=9920 r00=0x100 r02=0x4",
|
|
20
|
+
].join("\n");
|
|
21
|
+
const trace = parseTrace(input);
|
|
22
|
+
// Program
|
|
23
|
+
assert.deepStrictEqual(Array.from(trace.program), [0x01, 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff], "program bytes");
|
|
24
|
+
// Initial memwrite
|
|
25
|
+
assert.strictEqual(trace.initialMemWrites.length, 1, "one initial memwrite");
|
|
26
|
+
assert.strictEqual(trace.initialMemWrites[0].address, 0x00001000, "memwrite address");
|
|
27
|
+
assert.strictEqual(trace.initialMemWrites[0].data.length, 8, "memwrite data length");
|
|
28
|
+
// Start
|
|
29
|
+
assert.strictEqual(trace.start.pc, 0, "start pc");
|
|
30
|
+
assert.strictEqual(trace.start.gas, 10000n, "start gas");
|
|
31
|
+
assert.strictEqual(trace.start.registers.get(7), 0x10n, "start r07");
|
|
32
|
+
assert.strictEqual(trace.start.registers.get(9), 0x10000n, "start r09");
|
|
33
|
+
assert.strictEqual(trace.start.registers.has(0), false, "start r00 omitted (zero)");
|
|
34
|
+
// Ecalli
|
|
35
|
+
assert.strictEqual(trace.ecalliEntries.length, 1, "one ecalli");
|
|
36
|
+
const ecalli = trace.ecalliEntries[0];
|
|
37
|
+
assert.strictEqual(ecalli.index, 10, "ecalli index");
|
|
38
|
+
assert.strictEqual(ecalli.pc, 42, "ecalli pc");
|
|
39
|
+
assert.strictEqual(ecalli.gas, 9980n, "ecalli gas");
|
|
40
|
+
assert.strictEqual(ecalli.registers.get(1), 0x1n, "ecalli r01");
|
|
41
|
+
assert.strictEqual(ecalli.registers.get(3), 0x1000n, "ecalli r03");
|
|
42
|
+
// Memreads
|
|
43
|
+
assert.strictEqual(ecalli.memReads.length, 2, "two memreads");
|
|
44
|
+
assert.strictEqual(ecalli.memReads[0].address, 0x00001000, "memread 0 address");
|
|
45
|
+
assert.strictEqual(ecalli.memReads[0].data.length, 4, "memread 0 length");
|
|
46
|
+
assert.strictEqual(ecalli.memReads[1].address, 0x00001020, "memread 1 address");
|
|
47
|
+
// Memwrites
|
|
48
|
+
assert.strictEqual(ecalli.memWrites.length, 1, "one ecalli memwrite");
|
|
49
|
+
assert.strictEqual(ecalli.memWrites[0].address, 0x00002000, "ecalli memwrite address");
|
|
50
|
+
// Setregs
|
|
51
|
+
assert.strictEqual(ecalli.setRegs.length, 2, "two setregs");
|
|
52
|
+
assert.strictEqual(ecalli.setRegs[0].index, 0, "setreg 0 index");
|
|
53
|
+
assert.strictEqual(ecalli.setRegs[0].value, 0x100n, "setreg 0 value");
|
|
54
|
+
assert.strictEqual(ecalli.setRegs[1].index, 2, "setreg 1 index");
|
|
55
|
+
assert.strictEqual(ecalli.setRegs[1].value, 0x4n, "setreg 1 value");
|
|
56
|
+
// Setgas
|
|
57
|
+
assert.strictEqual(ecalli.setGas, 9950n, "setgas");
|
|
58
|
+
// Termination
|
|
59
|
+
assert.strictEqual(trace.termination.type, "HALT", "termination type");
|
|
60
|
+
assert.strictEqual(trace.termination.pc, 42, "termination pc");
|
|
61
|
+
assert.strictEqual(trace.termination.gas, 9920n, "termination gas");
|
|
62
|
+
assert.strictEqual(trace.termination.registers.get(0), 0x100n, "termination r00");
|
|
63
|
+
assert.strictEqual(trace.termination.registers.get(2), 0x4n, "termination r02");
|
|
64
|
+
console.log("PASS: spec example round-trip");
|
|
65
|
+
}
|
|
66
|
+
// Test: PANIC=0 (argument must always be present)
|
|
67
|
+
{
|
|
68
|
+
const input = ["program 0x00", "start pc=0 gas=100", "PANIC=0 pc=5 gas=50 r00=0x1"].join("\n");
|
|
69
|
+
const trace = parseTrace(input);
|
|
70
|
+
assert.strictEqual(trace.termination.type, "PANIC", "panic type");
|
|
71
|
+
assert.strictEqual(trace.termination.panicArg, 0, "panic arg is 0");
|
|
72
|
+
assert.strictEqual(trace.termination.pc, 5, "panic pc");
|
|
73
|
+
assert.strictEqual(trace.termination.gas, 50n, "panic gas");
|
|
74
|
+
console.log("PASS: PANIC=0");
|
|
75
|
+
}
|
|
76
|
+
// Test: PANIC with non-zero argument
|
|
77
|
+
{
|
|
78
|
+
const input = ["program 0x00", "start pc=0 gas=100", "PANIC=42 pc=10 gas=0"].join("\n");
|
|
79
|
+
const trace = parseTrace(input);
|
|
80
|
+
assert.strictEqual(trace.termination.panicArg, 42, "panic arg 42");
|
|
81
|
+
assert.strictEqual(trace.termination.registers.size, 0, "no registers");
|
|
82
|
+
console.log("PASS: PANIC=42");
|
|
83
|
+
}
|
|
84
|
+
// Test: OOG termination
|
|
85
|
+
{
|
|
86
|
+
const input = ["program 0x00", "start pc=0 gas=100", "OOG pc=99 gas=0"].join("\n");
|
|
87
|
+
const trace = parseTrace(input);
|
|
88
|
+
assert.strictEqual(trace.termination.type, "OOG", "OOG type");
|
|
89
|
+
assert.strictEqual(trace.termination.gas, 0n, "OOG gas is 0");
|
|
90
|
+
console.log("PASS: OOG");
|
|
91
|
+
}
|
|
92
|
+
// Test: lines with log prefixes are handled (extractPayload)
|
|
93
|
+
{
|
|
94
|
+
const input = [
|
|
95
|
+
"TRACE [ecalli] program 0xaa",
|
|
96
|
+
"TRACE [ecalli] start pc=0 gas=500 r00=0x1",
|
|
97
|
+
"TRACE [ecalli] HALT pc=10 gas=400",
|
|
98
|
+
].join("\n");
|
|
99
|
+
const trace = parseTrace(input);
|
|
100
|
+
assert.deepStrictEqual(Array.from(trace.program), [0xaa], "prefixed program");
|
|
101
|
+
assert.strictEqual(trace.start.registers.get(0), 0x1n, "prefixed start r00");
|
|
102
|
+
assert.strictEqual(trace.termination.type, "HALT", "prefixed halt");
|
|
103
|
+
console.log("PASS: log-prefixed lines");
|
|
104
|
+
}
|
|
105
|
+
// Test: comment lines are ignored
|
|
106
|
+
{
|
|
107
|
+
const input = [
|
|
108
|
+
"comment implementation typeberry 0.8.3",
|
|
109
|
+
"comment chain-id fluffy-testnet",
|
|
110
|
+
"program 0xbb",
|
|
111
|
+
"comment accumulate",
|
|
112
|
+
"start pc=0 gas=100",
|
|
113
|
+
"HALT pc=5 gas=90",
|
|
114
|
+
].join("\n");
|
|
115
|
+
const trace = parseTrace(input);
|
|
116
|
+
assert.deepStrictEqual(Array.from(trace.program), [0xbb], "comment lines ignored");
|
|
117
|
+
console.log("PASS: comment lines ignored");
|
|
118
|
+
}
|
|
119
|
+
// Test: zero-padded register indices in register dump
|
|
120
|
+
{
|
|
121
|
+
const input = ["program 0x00", "start pc=0 gas=100 r00=0xff r12=0x1", "HALT pc=5 gas=90 r00=0xff r12=0x1"].join("\n");
|
|
122
|
+
const trace = parseTrace(input);
|
|
123
|
+
assert.strictEqual(trace.start.registers.get(0), 0xffn, "r00 parsed");
|
|
124
|
+
assert.strictEqual(trace.start.registers.get(12), 0x1n, "r12 parsed");
|
|
125
|
+
console.log("PASS: zero-padded register indices");
|
|
126
|
+
}
|
|
127
|
+
// Test: empty register dump (all zeros)
|
|
128
|
+
{
|
|
129
|
+
const input = ["program 0x00", "start pc=0 gas=100", "HALT pc=5 gas=90"].join("\n");
|
|
130
|
+
const trace = parseTrace(input);
|
|
131
|
+
assert.strictEqual(trace.start.registers.size, 0, "empty register dump");
|
|
132
|
+
assert.strictEqual(trace.termination.registers.size, 0, "empty termination registers");
|
|
133
|
+
console.log("PASS: empty register dump");
|
|
134
|
+
}
|
|
135
|
+
// Test: multiple ecalli entries
|
|
136
|
+
{
|
|
137
|
+
const input = [
|
|
138
|
+
"program 0x00",
|
|
139
|
+
"start pc=0 gas=10000",
|
|
140
|
+
"ecalli=1 pc=10 gas=9000 r00=0x1",
|
|
141
|
+
"setreg r00 <- 0x2",
|
|
142
|
+
"ecalli=2 pc=20 gas=8000 r00=0x2",
|
|
143
|
+
"memwrite 0x00001000 len=1 <- 0xff",
|
|
144
|
+
"setgas <- 7900",
|
|
145
|
+
"HALT pc=30 gas=7800",
|
|
146
|
+
].join("\n");
|
|
147
|
+
const trace = parseTrace(input);
|
|
148
|
+
assert.strictEqual(trace.ecalliEntries.length, 2, "two ecalli entries");
|
|
149
|
+
assert.strictEqual(trace.ecalliEntries[0].index, 1, "first ecalli index");
|
|
150
|
+
assert.strictEqual(trace.ecalliEntries[0].setRegs.length, 1, "first ecalli setregs");
|
|
151
|
+
assert.strictEqual(trace.ecalliEntries[0].setGas, undefined, "first ecalli no setgas");
|
|
152
|
+
assert.strictEqual(trace.ecalliEntries[1].index, 2, "second ecalli index");
|
|
153
|
+
assert.strictEqual(trace.ecalliEntries[1].memWrites.length, 1, "second ecalli memwrites");
|
|
154
|
+
assert.strictEqual(trace.ecalliEntries[1].setGas, 7900n, "second ecalli setgas");
|
|
155
|
+
console.log("PASS: multiple ecalli entries");
|
|
156
|
+
}
|
|
157
|
+
// Test: missing program throws
|
|
158
|
+
assert.throws(() => parseTrace("start pc=0 gas=100\nHALT pc=5 gas=90"), /Missing program/, "missing program");
|
|
159
|
+
console.log("PASS: missing program throws");
|
|
160
|
+
// Test: missing start throws
|
|
161
|
+
assert.throws(() => parseTrace("program 0x00\nHALT pc=5 gas=90"), /Missing start/, "missing start");
|
|
162
|
+
console.log("PASS: missing start throws");
|
|
163
|
+
// Test: missing termination throws
|
|
164
|
+
assert.throws(() => parseTrace("program 0x00\nstart pc=0 gas=100"), /Missing termination/, "missing termination");
|
|
165
|
+
console.log("PASS: missing termination throws");
|
|
166
|
+
console.log("\nAll trace format tests passed.");
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import "json-bigint-patch";
|
|
2
|
+
import * as assert from "node:assert";
|
|
3
|
+
import { ERR, OK, read, run } from "../bin/src/test-json.js";
|
|
4
|
+
const ignored = [
|
|
5
|
+
"inst_load_u8_nok",
|
|
6
|
+
"inst_store_imm_indirect_u16_with_offset_nok",
|
|
7
|
+
"inst_store_imm_indirect_u32_with_offset_nok",
|
|
8
|
+
"inst_store_imm_indirect_u64_with_offset_nok",
|
|
9
|
+
"inst_store_imm_indirect_u8_with_offset_nok",
|
|
10
|
+
"inst_store_imm_u8_trap_inaccessible",
|
|
11
|
+
"inst_store_imm_u8_trap_read_only",
|
|
12
|
+
"inst_store_indirect_u16_with_offset_nok",
|
|
13
|
+
"inst_store_indirect_u32_with_offset_nok",
|
|
14
|
+
"inst_store_indirect_u64_with_offset_nok",
|
|
15
|
+
"inst_store_indirect_u8_with_offset_nok",
|
|
16
|
+
"inst_store_u8_trap_inaccessible",
|
|
17
|
+
"inst_store_u8_trap_read_only",
|
|
18
|
+
];
|
|
19
|
+
export function runW3fTests(pvm) {
|
|
20
|
+
const options = {
|
|
21
|
+
isDebug: false,
|
|
22
|
+
isSilent: false,
|
|
23
|
+
};
|
|
24
|
+
run((data, opts, filePath) => processW3f(pvm, data, opts, filePath), options);
|
|
25
|
+
}
|
|
26
|
+
function processW3f(pvm, data, options, _filePath) {
|
|
27
|
+
if (options.isDebug) {
|
|
28
|
+
console.debug(`🤖 Running ${data.name}`);
|
|
29
|
+
}
|
|
30
|
+
if (ignored.includes(data.name)) {
|
|
31
|
+
if (options.isDebug) {
|
|
32
|
+
console.info(`⏭️ Skipping ${data.name}`);
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
// input
|
|
37
|
+
const input = {
|
|
38
|
+
registers: read(data, "initial-regs").map((x) => BigInt(x)),
|
|
39
|
+
pc: read(data, "initial-pc"),
|
|
40
|
+
pageMap: asPageMap(read(data, "initial-page-map")),
|
|
41
|
+
memory: asChunks(read(data, "initial-memory")),
|
|
42
|
+
gas: BigInt(read(data, "initial-gas")),
|
|
43
|
+
program: read(data, "program"),
|
|
44
|
+
};
|
|
45
|
+
if (options.isDebug) {
|
|
46
|
+
const assembly = pvm.disassemble(input.program, pvm.InputKind.Generic, pvm.HasMetadata.No);
|
|
47
|
+
console.info("===========");
|
|
48
|
+
console.info(assembly);
|
|
49
|
+
console.info("\n^^^^^^^^^^^\n");
|
|
50
|
+
}
|
|
51
|
+
const exe = pvm.prepareProgram(pvm.InputKind.Generic, pvm.HasMetadata.No, input.program, input.registers, input.pageMap, input.memory, [], 16);
|
|
52
|
+
const result = pvm.runProgram(exe, input.gas, input.pc, options.isDebug, true);
|
|
53
|
+
const status = statusAsString(result.status);
|
|
54
|
+
// Normalize registers to plain unsigned BigInt array for comparison.
|
|
55
|
+
// The portable build may store signed BigInts or plain numbers in registers.
|
|
56
|
+
result.registers = Array.from(result.registers).map((v) => typeof v === "bigint" ? BigInt.asUintN(64, v) : BigInt(v));
|
|
57
|
+
result.gas = typeof result.gas === "bigint" ? result.gas : BigInt(result.gas);
|
|
58
|
+
// Normalize memory chunks to plain objects for comparison.
|
|
59
|
+
// The portable build returns class instances; WASM returns plain objects.
|
|
60
|
+
result.memory = result.memory.map((chunk) => ({
|
|
61
|
+
address: chunk.address,
|
|
62
|
+
data: Array.from(chunk.data),
|
|
63
|
+
}));
|
|
64
|
+
// silent mode - just put our vals into expected (comparison done externally)
|
|
65
|
+
if (options.isSilent) {
|
|
66
|
+
data["expected-pc"] = result.pc;
|
|
67
|
+
data["expected-gas"] = result.gas;
|
|
68
|
+
data["expected-status"] = status;
|
|
69
|
+
data["expected-regs"] = result.registers;
|
|
70
|
+
data["expected-page-fault-address"] = result.exitCode;
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
// compare with expected values
|
|
74
|
+
const expected = {
|
|
75
|
+
// just copy JAM-output result field
|
|
76
|
+
result: result.result,
|
|
77
|
+
status: read(data, "expected-status"),
|
|
78
|
+
registers: read(data, "expected-regs").map((x) => BigInt(x)),
|
|
79
|
+
pc: read(data, "expected-pc"),
|
|
80
|
+
memory: asChunks(read(data, "expected-memory")),
|
|
81
|
+
gas: BigInt(read(data, "expected-gas")),
|
|
82
|
+
exitCode: read(data, "expected-page-fault-address", 0),
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
assert.deepStrictEqual({
|
|
86
|
+
...result,
|
|
87
|
+
status,
|
|
88
|
+
}, expected);
|
|
89
|
+
console.log(`${OK} ${data.name}`);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
console.log(`${ERR} ${data.name}`);
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
function asChunks(chunks) {
|
|
98
|
+
return chunks.map((chunk) => {
|
|
99
|
+
chunk.data = read(chunk, "contents");
|
|
100
|
+
delete chunk.contents;
|
|
101
|
+
return chunk;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
var Access;
|
|
105
|
+
(function (Access) {
|
|
106
|
+
Access[Access["Read"] = 1] = "Read";
|
|
107
|
+
Access[Access["Write"] = 2] = "Write";
|
|
108
|
+
})(Access || (Access = {}));
|
|
109
|
+
function asPageMap(pages) {
|
|
110
|
+
return pages.map((page) => {
|
|
111
|
+
page.access = read(page, "is-writable") ? Access.Write : Access.Read;
|
|
112
|
+
return page;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function statusAsString(status) {
|
|
116
|
+
const map = {
|
|
117
|
+
255: "ok",
|
|
118
|
+
0: "halt",
|
|
119
|
+
1: "panic",
|
|
120
|
+
2: "page-fault",
|
|
121
|
+
3: "host",
|
|
122
|
+
4: "oog",
|
|
123
|
+
};
|
|
124
|
+
return map[status] || `unknown(${status})`;
|
|
125
|
+
}
|
package/dist/test/test-w3f.js
CHANGED
|
@@ -1,121 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import { disassemble, HasMetadata, InputKind, prepareProgram, runProgram } from "../build/release.js";
|
|
6
|
-
const ignored = [
|
|
7
|
-
"inst_load_u8_nok",
|
|
8
|
-
"inst_store_imm_indirect_u16_with_offset_nok",
|
|
9
|
-
"inst_store_imm_indirect_u32_with_offset_nok",
|
|
10
|
-
"inst_store_imm_indirect_u64_with_offset_nok",
|
|
11
|
-
"inst_store_imm_indirect_u8_with_offset_nok",
|
|
12
|
-
"inst_store_imm_u8_trap_inaccessible",
|
|
13
|
-
"inst_store_imm_u8_trap_read_only",
|
|
14
|
-
"inst_store_indirect_u16_with_offset_nok",
|
|
15
|
-
"inst_store_indirect_u32_with_offset_nok",
|
|
16
|
-
"inst_store_indirect_u64_with_offset_nok",
|
|
17
|
-
"inst_store_indirect_u8_with_offset_nok",
|
|
18
|
-
"inst_store_u8_trap_inaccessible",
|
|
19
|
-
"inst_store_u8_trap_read_only",
|
|
20
|
-
];
|
|
21
|
-
// Run the CLI application
|
|
22
|
-
main();
|
|
23
|
-
// Main function
|
|
24
|
-
function main() {
|
|
25
|
-
const options = {
|
|
26
|
-
isDebug: false,
|
|
27
|
-
isSilent: false,
|
|
28
|
-
useSbrkGas: false,
|
|
29
|
-
};
|
|
30
|
-
run(processW3f, options);
|
|
31
|
-
}
|
|
32
|
-
function processW3f(data, options) {
|
|
33
|
-
if (options.isDebug) {
|
|
34
|
-
console.debug(`🤖 Running ${data.name}`);
|
|
35
|
-
}
|
|
36
|
-
if (ignored.includes(data.name)) {
|
|
37
|
-
if (options.isDebug) {
|
|
38
|
-
console.info(`⏭️ Skipping ${data.name}`);
|
|
39
|
-
}
|
|
40
|
-
return data;
|
|
41
|
-
}
|
|
42
|
-
// input
|
|
43
|
-
const input = {
|
|
44
|
-
registers: read(data, "initial-regs").map((x) => BigInt(x)),
|
|
45
|
-
pc: read(data, "initial-pc"),
|
|
46
|
-
pageMap: asPageMap(read(data, "initial-page-map")),
|
|
47
|
-
memory: asChunks(read(data, "initial-memory")),
|
|
48
|
-
gas: BigInt(read(data, "initial-gas")),
|
|
49
|
-
program: read(data, "program"),
|
|
50
|
-
};
|
|
51
|
-
if (options.isDebug) {
|
|
52
|
-
const assembly = disassemble(input.program, InputKind.Generic, HasMetadata.No);
|
|
53
|
-
console.info("===========");
|
|
54
|
-
console.info(assembly);
|
|
55
|
-
console.info("\n^^^^^^^^^^^\n");
|
|
56
|
-
}
|
|
57
|
-
const exe = prepareProgram(InputKind.Generic, HasMetadata.No, input.program, input.registers, input.pageMap, input.memory, [], 16);
|
|
58
|
-
const result = runProgram(exe, input.gas, input.pc, options.isDebug, options.useSbrkGas, true);
|
|
59
|
-
const status = statusAsString(result.status);
|
|
60
|
-
// silent mode - just put our vals into expected (comparison done externally)
|
|
61
|
-
if (options.isSilent) {
|
|
62
|
-
data["expected-pc"] = result.pc;
|
|
63
|
-
data["expected-gas"] = result.gas;
|
|
64
|
-
data["expected-status"] = status;
|
|
65
|
-
data["expected-regs"] = result.registers;
|
|
66
|
-
data["expected-page-fault-address"] = result.exitCode;
|
|
67
|
-
return data;
|
|
68
|
-
}
|
|
69
|
-
// compare with expected values
|
|
70
|
-
const expected = {
|
|
71
|
-
// just copy JAM-output result field
|
|
72
|
-
result: result.result,
|
|
73
|
-
status: read(data, "expected-status"),
|
|
74
|
-
registers: read(data, "expected-regs").map((x) => BigInt(x)),
|
|
75
|
-
pc: read(data, "expected-pc"),
|
|
76
|
-
memory: asChunks(read(data, "expected-memory")),
|
|
77
|
-
gas: BigInt(read(data, "expected-gas")),
|
|
78
|
-
exitCode: read(data, "expected-page-fault-address", 0),
|
|
79
|
-
};
|
|
80
|
-
try {
|
|
81
|
-
assert.deepStrictEqual({
|
|
82
|
-
...result,
|
|
83
|
-
status,
|
|
84
|
-
}, expected);
|
|
85
|
-
console.log(`${OK} ${data.name}`);
|
|
86
|
-
}
|
|
87
|
-
catch (e) {
|
|
88
|
-
console.log(`${ERR} ${data.name}`);
|
|
89
|
-
throw e;
|
|
90
|
-
}
|
|
91
|
-
return data;
|
|
92
|
-
}
|
|
93
|
-
function asChunks(chunks) {
|
|
94
|
-
return chunks.map((chunk) => {
|
|
95
|
-
chunk.data = read(chunk, "contents");
|
|
96
|
-
delete chunk.contents;
|
|
97
|
-
return chunk;
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
var Access;
|
|
101
|
-
(function (Access) {
|
|
102
|
-
Access[Access["Read"] = 1] = "Read";
|
|
103
|
-
Access[Access["Write"] = 2] = "Write";
|
|
104
|
-
})(Access || (Access = {}));
|
|
105
|
-
function asPageMap(pages) {
|
|
106
|
-
return pages.map((page) => {
|
|
107
|
-
page.access = read(page, "is-writable") ? Access.Write : Access.Read;
|
|
108
|
-
return page;
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
function statusAsString(status) {
|
|
112
|
-
const map = {
|
|
113
|
-
255: "ok",
|
|
114
|
-
0: "halt",
|
|
115
|
-
1: "panic",
|
|
116
|
-
2: "page-fault",
|
|
117
|
-
3: "host",
|
|
118
|
-
4: "oog",
|
|
119
|
-
};
|
|
120
|
-
return map[status] || `unknown(${status})`;
|
|
121
|
-
}
|
|
2
|
+
import * as pvm from "../build/release.js";
|
|
3
|
+
import { runW3fTests } from "./test-w3f-common.js";
|
|
4
|
+
runW3fTests(pvm);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluffylabs/anan-as",
|
|
3
3
|
"description": "AssemblyScript PVM interpreter.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0-0eb791a",
|
|
5
5
|
"main": "./dist/bin/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"anan-as": "./dist/bin/index.js"
|
|
@@ -32,12 +32,18 @@
|
|
|
32
32
|
"qa": "biome ci",
|
|
33
33
|
"qa-fix": "npm run format; npm run lint",
|
|
34
34
|
"start": "tsx ./bin/index.ts",
|
|
35
|
-
|
|
36
|
-
"tsbuild": "tsc",
|
|
35
|
+
"test": "npm run asbuild:test && tsx ./test/test-as.ts && tsx ./test/test-trace-format.ts && tsx ./test/test-trace-replay.ts",
|
|
36
|
+
"tsbuild": "tsc && npm run tsbuild:portable",
|
|
37
|
+
"tsbuild:portable": "tsc --project portable/tsconfig.json && esbuild dist/build/js/portable/index.js --bundle --format=esm --platform=node --outfile=dist/build/js/portable-bundle.js",
|
|
37
38
|
"test:w3f": "tsx ./test/test-w3f.ts",
|
|
39
|
+
"test:w3f-portable": "tsx ./test/test-w3f-portable.ts",
|
|
38
40
|
"test:gas-cost": "tsx ./test/test-gas-cost.ts",
|
|
39
41
|
"update-version": "tsx ./web/bump-version.ts $GITHUB_SHA",
|
|
40
|
-
"web": "npx live-server ./web"
|
|
42
|
+
"web": "npx live-server ./web",
|
|
43
|
+
"bench": "tsx bench/run.ts --traces ./bench/traces --iterations 5 --warmup 1",
|
|
44
|
+
"bench:ci": "tsx bench/run.ts --traces ./bench/traces --iterations 5 --warmup 1 --output ./bench/results.json",
|
|
45
|
+
"bench:baseline": "tsx bench/run.ts --traces ./bench/traces --iterations 5 --warmup 1 --output ./bench/baseline.json",
|
|
46
|
+
"bench:compare": "tsx bench/compare.ts"
|
|
41
47
|
},
|
|
42
48
|
"type": "module",
|
|
43
49
|
"keywords": [],
|
|
@@ -47,13 +53,14 @@
|
|
|
47
53
|
"node": ">=18.3.0"
|
|
48
54
|
},
|
|
49
55
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "^2.
|
|
51
|
-
"@typeberry/lib": "^0.
|
|
52
|
-
"@types/node": "^25.
|
|
53
|
-
"assemblyscript": "^0.28.
|
|
56
|
+
"@biomejs/biome": "^2.4.10",
|
|
57
|
+
"@typeberry/lib": "^0.6.0",
|
|
58
|
+
"@types/node": "^25.3.3",
|
|
59
|
+
"assemblyscript": "^0.28.9",
|
|
60
|
+
"esbuild": "^0.28.0",
|
|
54
61
|
"json-bigint-patch": "^0.0.8",
|
|
55
|
-
"tsx": "^4.
|
|
56
|
-
"typescript": "^
|
|
62
|
+
"tsx": "^4.21.0",
|
|
63
|
+
"typescript": "^6.0.2"
|
|
57
64
|
},
|
|
58
65
|
"files": [
|
|
59
66
|
"dist/**/*.wasm",
|
|
@@ -111,6 +118,10 @@
|
|
|
111
118
|
"./release.wasm": "./dist/build/release.wasm",
|
|
112
119
|
"./release-mini.wasm": "./dist/build/release-mini.wasm",
|
|
113
120
|
"./release-stub.wasm": "./dist/build/release-stub.wasm",
|
|
114
|
-
"./compiler.wasm": "./dist/build/compiler.wasm"
|
|
121
|
+
"./compiler.wasm": "./dist/build/compiler.wasm",
|
|
122
|
+
"./js": {
|
|
123
|
+
"import": "./dist/build/js/portable-bundle.js",
|
|
124
|
+
"types": "./dist/build/js/portable/index.d.ts"
|
|
125
|
+
}
|
|
115
126
|
}
|
|
116
127
|
}
|