-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathmain.mjs
86 lines (79 loc) · 2.69 KB
/
main.mjs
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
import { readdirSync, readFileSync, writeFileSync } from 'fs'
import { hrtime } from 'process'
import { contractInfo } from 'evmole'
const argv = process.argv;
if (argv.length < 5) {
console.log('Usage: node main.js MODE INPUT_DIR OUTPUT_FILE [SELECTORS_FILE]')
process.exit(1)
}
const mode = argv[2];
const indir = argv[3];
const outfile = argv[4];
const selectors = mode === 'mutability' || mode === 'arguments' ? JSON.parse(readFileSync(argv[5])) : {};
function timeit(fn) {
const start_ts = hrtime.bigint();
const r = fn();
const duration_us = Number((hrtime.bigint() - start_ts) / 1000n);
return [duration_us, r]
}
function extract(code, mode, fname) {
if (mode === 'selectors') {
let [duration_us, r] = timeit(() => contractInfo(code, {selectors: true}));
return [duration_us, r.functions.map((f) => f.selector)];
} else if (mode === 'arguments') {
let [duration_us, r] = timeit(() => contractInfo(code, {arguments: true}));
const by_sel = new Map(r.functions.map((f) => [f.selector, f.arguments]));
return [duration_us, Object.fromEntries(
selectors[fname][1].map((s) => [s, by_sel.get(s) ?? 'notfound'])
)];
} else if (mode === 'mutability') {
let [duration_us, r] = timeit(() => contractInfo(code, {stateMutability: true}));
const by_sel = new Map(r.functions.map((f) => [f.selector, f.stateMutability]));
return [duration_us, Object.fromEntries(
selectors[fname][1].map((s) => [s, by_sel.get(s) ?? 'notfound'])
)];
} else if (mode === 'flow') {
let [duration_us, r] = timeit(() => contractInfo(code, {controlFlowGraph: true}));
let ret = []
for (const b of r.controlFlowGraph.blocks) {
let bt = b.get('type');
let start = b.get('start');
let data = b.get('data');
if (bt === 'Jump') {
ret.push([start, data.to])
} else if (bt === 'Jumpi') {
ret.push([start, data.true_to])
ret.push([start, data.false_to])
} else if (bt === 'DynamicJump') {
for (let v of data.to) {
if(v.to) {
ret.push([start, v.to])
}
}
} else if (bt === 'DynamicJumpi') {
for (let v of data.true_to) {
if(v.to) {
ret.push([start, v.to])
}
}
ret.push([start, data.false_to])
} else if (bt === 'Terminate') {
// do nothing
} else {
throw `unknown block type ${bt}`;
}
}
return [duration_us, ret];
} else {
throw 'unsupported mode';
}
}
const res = Object.fromEntries(
readdirSync(indir).map(
file => [
file,
extract(JSON.parse(readFileSync(`${indir}/${file}`))['code'], mode, file)
]
)
);
writeFileSync(outfile, JSON.stringify(res), 'utf8');