forked from bytecodealliance/wasmtime
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathrun-tests-zkasm.js
244 lines (214 loc) · 7.19 KB
/
run-tests-zkasm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/* eslint-disable no-restricted-syntax */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable no-use-before-define */
const path = require('path');
const fs = require('fs');
const zkasm = require('@0xpolygonhermez/zkasmcom');
const smMain = require('@0xpolygonhermez/zkevm-proverjs/src/sm/sm_main/sm_main');
const {
compile,
newCommitPolsArray
} = require('pilcom');
const buildPoseidon = require('@0xpolygonhermez/zkevm-commonjs').getPoseidon;
const AssertHelper = require('./assert_helper');
const InstructionTracer = require('./helpers/InstructionTracer');
const emptyInput = require('@0xpolygonhermez/zkevm-proverjs/test/inputs/empty_input.json');
// Global paths to build Main PIL to fill polynomials in tests
const pathMainPil = path.join(__dirname, 'node_modules/@0xpolygonhermez/zkevm-proverjs/pil/main.pil');
const fileCachePil = path.join(__dirname, 'node_modules/@0xpolygonhermez/zkevm-proverjs/cache-main-pil.json');
function value_to_json(key, value) {
if (typeof value === "bigint") {
return value.toString();
}
// Serialize exceptions by inlining all referenced fields.
if (value instanceof Error) {
return JSON.stringify(value, Object.getOwnPropertyNames(value));
}
return value;
}
/**
* Run this script with `--help` to print docs.
*/
async function main() {
require("yargs/yargs")(process.argv.slice(2))
.command({
command: "$0 <path> [outfile]",
desc: "the default command runs zkASM tests",
builder: (yargs) => {
yargs.positional("path", {
describe: "The zkASM file to run or a directory to search for zkASM files.",
type: "string"
})
yargs.positional("outfile", {
describe: "If provided, results are written to this file. Otherwise they are printed to stdout.",
type: "string"
})
},
handler: (argv) => runTestsCmd(argv.path, argv.outfile)
})
.command({
command: "profile-instructions <path> [outfile]",
desc: "profiles instructions executed at runtime, assuming zkASM was instrumented",
builder: (yargs) => {
yargs.positional("path", {
describe: "The instrumented zkASM file to execute.",
type: "string"
})
yargs.positional("outfile", {
describe: "If provided, results are written to this file. Otherwise they are printed to stdout.",
type: "string"
})
},
handler: (argv) => profileInstructions(argv.path, argv.outfile)
})
.parse();
}
/**
* Executes zkASM stored in files. Expects the following positional command line arguments:
*
* @param {string} path - The file or a directory to search for zkASM files.
* @param {string} [outfile] - If provided, results are written to this file. Otherwise they are
* printed to stdout.
*/
async function runTestsCmd(path, outfile) {
// Compile pil
const cmPols = await compilePil();
// Get all zkasm files
const files = await getTestFiles(path);
// Run all zkasm files
let testResults = [];
for (const file of files) {
if (file.includes('ignore'))
continue;
testResults.push(await runTest(file, cmPols));
}
if (outfile) {
const json = JSON.stringify(testResults, value_to_json);
fs.writeFileSync(outfile, json);
} else {
console.log(testResults);
}
}
async function compilePil() {
if (!fs.existsSync(fileCachePil)) {
const poseidon = await buildPoseidon();
const {
F
} = poseidon;
const pilConfig = {
defines: {
N: 4096
},
namespaces: ['Main', 'Global'],
disableUnusedError: true,
};
const p = await compile(F, pathMainPil, null, pilConfig);
fs.writeFileSync(fileCachePil, `${JSON.stringify(p, null, 1)}\n`, 'utf8');
}
const pil = JSON.parse(fs.readFileSync(fileCachePil));
return newCommitPolsArray(pil);
}
/**
* Returns the path of all zkasm test files in `pathZkasm`.
*
* @param {string} pathZkasm
* @returns {string[]}
*/
function getTestFiles(pathZkasm) {
if (!fs.existsSync(pathZkasm)) {
return [];
}
// check if path provided is a file or a directory
const stats = fs.statSync(pathZkasm);
if (!stats.isDirectory()) {
return [pathZkasm];
}
const filesNames = fs.readdirSync(pathZkasm).filter((name) => name.endsWith('.zkasm'));
return filesNames.map((fileName) => path.join(pathZkasm, fileName));
}
/**
* @returns {Object} Which indicates if the test run succeeded or failed. Contains additional data
* related to the test run.
*/
async function runTest(pathTest, cmPols) {
// Compile rom
const configZkasm = {
defines: [],
allowUndefinedLabels: true,
allowOverwriteLabels: true,
};
// TODO: this output file highly likely should be temporary and deleted once rust filetests
// will process it.
const assert_config = {
outputFile: 'testoutput.json'
}
let helper = new AssertHelper(assert_config);
const config = {
debug: true,
stepsN: 8388608,
assertOutputs: false,
helpers: [
helper
]
};
try {
const rom = await zkasm.compile(pathTest, null, configZkasm);
const result = await smMain.execute(cmPols.Main, emptyInput, rom, config);
helper.dump();
return {
path: pathTest,
status: "pass",
counters: result.counters,
output: result.output,
logs: result.logs,
}
} catch (e) {
return {
path: pathTest,
status: "runtime error",
error: e,
}
}
}
/**
* Executes a zkASM file instrumented for instruction tracing and produces the
* trace of executed instructions.
*
* @param {string} zkasmFile - Path to the zkASM file.
* @param {string} [outfile] - Path to a file where output is written. If not
* given, the trace is written to `stdout`.
*/
async function profileInstructions(zkasmFile, outfile) {
const configZkasm = {
defines: [],
allowUndefinedLabels: true,
allowOverwriteLabels: true,
};
// Construct helper classes.
const instructionTracer = new InstructionTracer();
// Compile rom.
const config = {
debug: true,
stepsN: 8388608,
assertOutputs: false,
helpers: [
instructionTracer
]
};
const cmPols = await compilePil();
const rom = await zkasm.compile(zkasmFile, null, configZkasm);
const result = await smMain.execute(cmPols.Main, emptyInput, rom, config);
console.log("Execution finished");
if (result.output) {
console.log(`Output: ${result.output}`)
}
if (result.logs && Object.keys(result.logs).length > 0) {
console.log(result.logs);
}
if (outfile) {
instructionTracer.writeRawTrace(outfile);
} else {
console.log(instructionTracer.rawTrace);
}
}
main();