@theqrl/hypc 0.0.2
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/LICENSE +0 -0
- package/README.md +361 -0
- package/abi.js +80 -0
- package/bindings/compile.js +157 -0
- package/bindings/core.js +116 -0
- package/bindings/helpers.js +35 -0
- package/bindings/index.js +16 -0
- package/build/clean.js +6 -0
- package/build/pack-publish-block.js +10 -0
- package/build/postbuild.js +3 -0
- package/common/helpers.js +24 -0
- package/common/types.js +2 -0
- package/contractA_hyp_A.bin +1 -0
- package/contractB_hyp_B.bin +1 -0
- package/downloadCurrentVersion.js +93 -0
- package/formatters.js +17 -0
- package/hypc.js +259 -0
- package/hypjson.js +1733 -0
- package/importA_hyp_C.bin +1 -0
- package/importB_hyp_D.bin +1 -0
- package/index.js +7 -0
- package/libX_hyp_X.bin +1 -0
- package/libY_hyp_Y.bin +1 -0
- package/libZ_hyp_Z.bin +1 -0
- package/linker.js +156 -0
- package/package.json +74 -0
- package/smtchecker.js +39 -0
- package/smtsolver.js +89 -0
- package/test/abi.js +77 -0
- package/test/cli.js +245 -0
- package/test/compiler.js +791 -0
- package/test/index.js +36 -0
- package/test/linker.js +132 -0
- package/test/resources/fixtureAsmJson.hyp +8 -0
- package/test/resources/fixtureAsmJson.json +528 -0
- package/test/resources/fixtureAsmJson.output +101 -0
- package/test/resources/fixtureIncorrectSource.hyp +1 -0
- package/test/resources/fixtureSmoke.hyp +5 -0
- package/test/resources/importA.hyp +7 -0
- package/test/resources/importB.hyp +5 -0
- package/test/resources/importCallback/base/contractA.hyp +8 -0
- package/test/resources/importCallback/base/contractB.hyp +6 -0
- package/test/resources/importCallback/contractC.hyp +4 -0
- package/test/resources/importCallback/includeA/libX.hyp +4 -0
- package/test/resources/importCallback/includeA/libY.hyp +6 -0
- package/test/resources/importCallback/includeA/utils.hyp +4 -0
- package/test/resources/importCallback/includeB/libZ.hyp +4 -0
- package/test/resources/smtChecker/loop.hyp +8 -0
- package/test/resources/smtChecker/smoke.hyp +5 -0
- package/test/resources/smtChecker/smoke_with_engine.hyp +6 -0
- package/test/resources/smtChecker/smoke_with_multi_engine.hyp +8 -0
- package/test/smtcallback.js +221 -0
- package/test/smtchecker.js +83 -0
- package/test/translate.js +83 -0
- package/test_resources_fixtureSmoke_hyp_C.abi +1 -0
- package/test_resources_fixtureSmoke_hyp_C.bin +1 -0
- package/test_resources_importA_hyp_C.bin +1 -0
- package/test_resources_importB_hyp_D.bin +1 -0
- package/translate.js +186 -0
- package/tsconfig.json +25 -0
- package/utils_hyp_Utils.bin +1 -0
- package/verifyVersion.js +43 -0
- package/wrapper.js +143 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6080604052348015600e575f80fd5b5060ab8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806326121ff014602a575b5f80fd5b60306044565b604051603b9190605e565b60405180910390f35b5f90565b5f819050919050565b6058816048565b82525050565b5f602082019050606f5f8301846051565b9291505056fea264697066735822122003aa2795a073c7ca2063308c3a8a13fb3a1ce6028c399f889636bd9eabe1f73f6468797063430000020033
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6080604052348015600e575f80fd5b5060ab8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806326121ff014602a575b5f80fd5b60306044565b604051603b9190605e565b60405180910390f35b5f90565b5f819050919050565b6058816048565b82525050565b5f602082019050606f5f8301846051565b9291505056fea2646970667358221220f96d6c685f4fe201ee93ca17a8b69d8182984a86c16908f46d7becc54efcfb846468797063430000020033
|
package/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
const wrapper_1 = __importDefault(require("./wrapper"));
|
|
6
|
+
const hypjson = require('./hypjson.js');
|
|
7
|
+
module.exports = (0, wrapper_1.default)(hypjson);
|
package/libX_hyp_X.bin
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6055604b600b8282823980515f1a607314603f577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220e78306f3d7dc80c45acbd51f639ead3e6f620f10144ea624b2c7e88c6c1504e96468797063430000020033
|
package/libY_hyp_Y.bin
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6055604b600b8282823980515f1a607314603f577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220fe2cbe5e62e395650d519ac764d3d5271e9af30d3e271d1c291677812e14d7ce6468797063430000020033
|
package/libZ_hyp_Z.bin
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6055604b600b8282823980515f1a607314603f577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212208cf9773d6268fc017aed7c3282d7e4ec482fd3b5d956250412103e5d65854bfc6468797063430000020033
|
package/linker.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
const assert_1 = __importDefault(require("assert"));
|
|
6
|
+
const js_sha3_1 = require("js-sha3");
|
|
7
|
+
const helpers_1 = require("./common/helpers");
|
|
8
|
+
/**
|
|
9
|
+
* Generates a new-style library placeholder from a fully-qualified library name.
|
|
10
|
+
*
|
|
11
|
+
* Newer versions of the compiler use hashed names instead of just truncating the name
|
|
12
|
+
* before putting it in a placeholder.
|
|
13
|
+
*
|
|
14
|
+
* @param fullyQualifiedLibraryName Fully qualified library name.
|
|
15
|
+
*/
|
|
16
|
+
function libraryHashPlaceholder(fullyQualifiedLibraryName) {
|
|
17
|
+
return `$${(0, js_sha3_1.keccak256)(fullyQualifiedLibraryName).slice(0, 34)}$`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Finds all placeholders corresponding to the specified library label and replaces them
|
|
21
|
+
* with a concrete address. Works with both hex-encoded and binary bytecode as long as
|
|
22
|
+
* the address is in the same format.
|
|
23
|
+
*
|
|
24
|
+
* @param bytecode Bytecode string.
|
|
25
|
+
*
|
|
26
|
+
* @param label Library label, either old- or new-style. Must exactly match the part between `__` markers in the
|
|
27
|
+
* placeholders. Will be padded with `_` characters if too short or truncated if too long.
|
|
28
|
+
*
|
|
29
|
+
* @param address Address to replace placeholders with. Must be the right length.
|
|
30
|
+
* It will **not** be padded with zeros if too short.
|
|
31
|
+
*/
|
|
32
|
+
function replacePlaceholder(bytecode, label, address) {
|
|
33
|
+
// truncate to 36 characters
|
|
34
|
+
const truncatedName = label.slice(0, 36);
|
|
35
|
+
const libLabel = `__${truncatedName.padEnd(36, '_')}__`;
|
|
36
|
+
while (bytecode.indexOf(libLabel) >= 0) {
|
|
37
|
+
bytecode = bytecode.replace(libLabel, address);
|
|
38
|
+
}
|
|
39
|
+
return bytecode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Finds and all library placeholders in the provided bytecode and replaces them with actual addresses.
|
|
43
|
+
* Supports both old- and new-style placeholders (even both in the same file).
|
|
44
|
+
* See [Library Linking](https://docs.soliditylang.org/en/latest/using-the-compiler.html#library-linking)
|
|
45
|
+
* for a full explanation of the linking process.
|
|
46
|
+
*
|
|
47
|
+
* Example of a legacy placeholder: `__lib.hyp:L_____________________________`
|
|
48
|
+
* Example of a new-style placeholder: `__$7484607a72fb0587588e5a1e608f0b16de$__`
|
|
49
|
+
*
|
|
50
|
+
* @param bytecode Hex-encoded bytecode string. All 40-byte substrings starting and ending with
|
|
51
|
+
* `__` will be interpreted as placeholders.
|
|
52
|
+
*
|
|
53
|
+
* @param libraries Mapping between fully qualified library names and the hex-encoded
|
|
54
|
+
* addresses they should be replaced with. Addresses shorter than 40 characters are automatically padded with zeros.
|
|
55
|
+
*
|
|
56
|
+
* @returns bytecode Hex-encoded bytecode string with placeholders replaced with addresses.
|
|
57
|
+
* Note that some placeholders may remain in the bytecode if `libraries` does not provide addresses for all of them.
|
|
58
|
+
*/
|
|
59
|
+
function linkBytecode(bytecode, libraries) {
|
|
60
|
+
(0, assert_1.default)(typeof bytecode === 'string');
|
|
61
|
+
(0, assert_1.default)(typeof libraries === 'object');
|
|
62
|
+
// NOTE: for backwards compatibility support old compiler which didn't use file names
|
|
63
|
+
const librariesComplete = {};
|
|
64
|
+
for (const [fullyQualifiedLibraryName, libraryObjectOrAddress] of Object.entries(libraries)) {
|
|
65
|
+
if ((0, helpers_1.isNil)(libraryObjectOrAddress)) {
|
|
66
|
+
throw new Error(`No address provided for library ${fullyQualifiedLibraryName}`);
|
|
67
|
+
}
|
|
68
|
+
// API compatible with the standard JSON i/o
|
|
69
|
+
// {"lib.hyp": {"L": "Z..."}}
|
|
70
|
+
if ((0, helpers_1.isObject)(libraryObjectOrAddress)) {
|
|
71
|
+
for (const [unqualifiedLibraryName, address] of Object.entries(libraryObjectOrAddress)) {
|
|
72
|
+
librariesComplete[unqualifiedLibraryName] = address;
|
|
73
|
+
librariesComplete[`${fullyQualifiedLibraryName}:${unqualifiedLibraryName}`] = address;
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// backwards compatible API for early hypc-js versions
|
|
78
|
+
const parsed = fullyQualifiedLibraryName.match(/^(?<sourceUnitName>[^:]+):(?<unqualifiedLibraryName>.+)$/);
|
|
79
|
+
const libraryAddress = libraryObjectOrAddress;
|
|
80
|
+
if (!(0, helpers_1.isNil)(parsed)) {
|
|
81
|
+
const { unqualifiedLibraryName } = parsed.groups;
|
|
82
|
+
librariesComplete[unqualifiedLibraryName] = libraryAddress;
|
|
83
|
+
}
|
|
84
|
+
librariesComplete[fullyQualifiedLibraryName] = libraryAddress;
|
|
85
|
+
}
|
|
86
|
+
for (const libraryName in librariesComplete) {
|
|
87
|
+
let hexAddress = librariesComplete[libraryName];
|
|
88
|
+
if (!hexAddress.startsWith('Z') || hexAddress.length > 41) {
|
|
89
|
+
throw new Error(`Invalid address specified for ${libraryName}`);
|
|
90
|
+
}
|
|
91
|
+
// remove 0x prefix
|
|
92
|
+
hexAddress = hexAddress.slice(1).padStart(40, '0');
|
|
93
|
+
bytecode = replacePlaceholder(bytecode, libraryName, hexAddress);
|
|
94
|
+
bytecode = replacePlaceholder(bytecode, libraryHashPlaceholder(libraryName), hexAddress);
|
|
95
|
+
}
|
|
96
|
+
return bytecode;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Finds locations of all library address placeholders in the hex-encoded bytecode.
|
|
100
|
+
* Returns information in a format matching `zvm.bytecode.linkReferences` output
|
|
101
|
+
* in Standard JSON.
|
|
102
|
+
*
|
|
103
|
+
* See [Library Linking](https://docs.soliditylang.org/en/latest/using-the-compiler.html#library-linking)
|
|
104
|
+
* for a full explanation of library placeholders and linking process.
|
|
105
|
+
*
|
|
106
|
+
* WARNING: The output matches `zvm.bytecode.linkReferences` exactly only in
|
|
107
|
+
* case of old-style placeholders created from fully qualified library names
|
|
108
|
+
* of no more than 36 characters, and even then only if the name does not start
|
|
109
|
+
* or end with an underscore. This is different from
|
|
110
|
+
* `zvm.bytecode.linkReferences`, which uses fully qualified library names.
|
|
111
|
+
* This is a limitation of the placeholder format - the fully qualified names
|
|
112
|
+
* are not preserved in the compiled bytecode and cannot be reconstructed
|
|
113
|
+
* without external information.
|
|
114
|
+
*
|
|
115
|
+
* @param bytecode Hex-encoded bytecode string.
|
|
116
|
+
*
|
|
117
|
+
* @returns linkReferences A mapping between library labels and their locations
|
|
118
|
+
* in the bytecode. In case of old-style placeholders the label is a fully
|
|
119
|
+
* qualified library name truncated to 36 characters. For new-style placeholders
|
|
120
|
+
* it's the first 34 characters of the hex-encoded hash of the fully qualified
|
|
121
|
+
* library name, with a leading and trailing $ character added. Note that the
|
|
122
|
+
* offsets and lengths refer to the *binary* (not hex-encoded) bytecode, just
|
|
123
|
+
* like in `zvm.bytecode.linkReferences`.
|
|
124
|
+
*/
|
|
125
|
+
function findLinkReferences(bytecode) {
|
|
126
|
+
(0, assert_1.default)(typeof bytecode === 'string');
|
|
127
|
+
// find 40 bytes in the pattern of __...<36 digits>...__
|
|
128
|
+
// e.g. __Lib.hyp:L_____________________________
|
|
129
|
+
const linkReferences = {};
|
|
130
|
+
let offset = 0;
|
|
131
|
+
while (true) {
|
|
132
|
+
const found = bytecode.match(/__(.{36})__/);
|
|
133
|
+
if (!found) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
const start = found.index;
|
|
137
|
+
// trim trailing underscores
|
|
138
|
+
// NOTE: this has no way of knowing if the trailing underscore was part of the name
|
|
139
|
+
const libraryName = found[1].replace(/_+$/gm, '');
|
|
140
|
+
if (!linkReferences[libraryName]) {
|
|
141
|
+
linkReferences[libraryName] = [];
|
|
142
|
+
}
|
|
143
|
+
// offsets are in bytes in binary representation (and not hex)
|
|
144
|
+
linkReferences[libraryName].push({
|
|
145
|
+
start: (offset + start) / 2,
|
|
146
|
+
length: 20
|
|
147
|
+
});
|
|
148
|
+
offset += start + 20;
|
|
149
|
+
bytecode = bytecode.slice(start + 20);
|
|
150
|
+
}
|
|
151
|
+
return linkReferences;
|
|
152
|
+
}
|
|
153
|
+
module.exports = {
|
|
154
|
+
linkBytecode,
|
|
155
|
+
findLinkReferences
|
|
156
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theqrl/hypc",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Hyperion compiler",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"hypcjs": "hypc.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"postbuild": "node build/postbuild.js && cp README.md LICENSE dist/",
|
|
12
|
+
"lint": "eslint --ext .js,.ts .",
|
|
13
|
+
"lint:fix": "eslint --fix --ext .js,.ts .",
|
|
14
|
+
"updateBinary": "node build/clean.js && ts-node ./downloadCurrentVersion.ts && ts-node ./verifyVersion.ts",
|
|
15
|
+
"prepack": "node build/pack-publish-block.js",
|
|
16
|
+
"build:tarball": "npm run updateBinary && npm run build && BYPASS_SAFETY_CHECK=true npm pack ./dist",
|
|
17
|
+
"publish:tarball": "tarball=$(npm run --silent tarballName) && ls \"$tarball\" && BYPASS_SAFETY_CHECK=true npm publish --access public \"$tarball\"",
|
|
18
|
+
"tarballName": "jq --raw-output '.name + \"-\" + .version + \".tgz\"' package.json",
|
|
19
|
+
"copyTestFiles": "cp -r ./test/resources ./dist/test/",
|
|
20
|
+
"pretest": "npm run lint && npm run build && npm run copyTestFiles",
|
|
21
|
+
"test": "cd dist && tape ./test/index.js",
|
|
22
|
+
"coverage": "nyc npm run test",
|
|
23
|
+
"coveralls": "npm run coverage && coveralls <coverage/lcov.info"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/theQRL/hypc-js.git"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"zond",
|
|
31
|
+
"hyperion",
|
|
32
|
+
"compiler"
|
|
33
|
+
],
|
|
34
|
+
"author": "",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/theQRL/hypc-js/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/theQRL/hypc-js#readme",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"command-exists": "^1.2.8",
|
|
42
|
+
"commander": "^8.1.0",
|
|
43
|
+
"follow-redirects": "^1.12.1",
|
|
44
|
+
"js-sha3": "0.8.0",
|
|
45
|
+
"memorystream": "^0.3.1",
|
|
46
|
+
"semver": "^5.5.0",
|
|
47
|
+
"tmp": "0.0.33"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^16.11.7",
|
|
51
|
+
"@types/semver": "^7.3.9",
|
|
52
|
+
"@types/tape": "^4.13.2",
|
|
53
|
+
"@types/tmp": "^0.2.3",
|
|
54
|
+
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
|
55
|
+
"@typescript-eslint/parser": "^5.8.0",
|
|
56
|
+
"coveralls": "^3.0.0",
|
|
57
|
+
"eslint": "^7.32.0",
|
|
58
|
+
"eslint-config-standard": "^16.0.3",
|
|
59
|
+
"eslint-plugin-import": "^2.25.3",
|
|
60
|
+
"eslint-plugin-node": "^11.1.0",
|
|
61
|
+
"eslint-plugin-promise": "^5.1.1",
|
|
62
|
+
"nyc": "^15.1.0",
|
|
63
|
+
"tape": "^4.11.0",
|
|
64
|
+
"tape-spawn": "^1.4.2",
|
|
65
|
+
"ts-node": "^10.4.0",
|
|
66
|
+
"typescript": "^4.5.4"
|
|
67
|
+
},
|
|
68
|
+
"nyc": {
|
|
69
|
+
"exclude": [
|
|
70
|
+
"hypjson.js",
|
|
71
|
+
"dist"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|
package/smtchecker.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// This function checks the standard JSON output for auxiliaryInputRequested,
|
|
3
|
+
// where smtlib2queries represent the queries created by the SMTChecker.
|
|
4
|
+
// The function runs an SMT solver on each query and adjusts the input for
|
|
5
|
+
// another run.
|
|
6
|
+
// Returns null if no solving is requested.
|
|
7
|
+
function handleSMTQueries(inputJSON, outputJSON, solverFunction, solver) {
|
|
8
|
+
const auxInputReq = outputJSON.auxiliaryInputRequested;
|
|
9
|
+
if (!auxInputReq) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const queries = auxInputReq.smtlib2queries;
|
|
13
|
+
if (!queries || Object.keys(queries).length === 0) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const responses = {};
|
|
17
|
+
for (const query in queries) {
|
|
18
|
+
responses[query] = solverFunction(queries[query], solver);
|
|
19
|
+
}
|
|
20
|
+
// Note: all existing solved queries are replaced.
|
|
21
|
+
// This assumes that all necessary queries are quested above.
|
|
22
|
+
inputJSON.auxiliaryInput = { smtlib2responses: responses };
|
|
23
|
+
return inputJSON;
|
|
24
|
+
}
|
|
25
|
+
function smtCallback(solverFunction, solver) {
|
|
26
|
+
return function (query) {
|
|
27
|
+
try {
|
|
28
|
+
const result = solverFunction(query, solver);
|
|
29
|
+
return { contents: result };
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return { error: err };
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
module.exports = {
|
|
37
|
+
handleSMTQueries,
|
|
38
|
+
smtCallback
|
|
39
|
+
};
|
package/smtsolver.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
const command_exists_1 = require("command-exists");
|
|
26
|
+
const child_process_1 = require("child_process");
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
28
|
+
const tmp = __importStar(require("tmp"));
|
|
29
|
+
// Timeout in ms.
|
|
30
|
+
const timeout = 10000;
|
|
31
|
+
const potentialSolvers = [
|
|
32
|
+
{
|
|
33
|
+
name: 'z3',
|
|
34
|
+
command: 'z3',
|
|
35
|
+
params: '-smt2 rlimit=20000000 rewriter.pull_cheap_ite=true fp.spacer.q3.use_qgen=true fp.spacer.mbqi=false fp.spacer.ground_pobs=false'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'Eldarica',
|
|
39
|
+
command: 'eld',
|
|
40
|
+
params: '-horn -t:' + (timeout / 1000) // Eldarica takes timeout in seconds.
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'cvc4',
|
|
44
|
+
command: 'cvc4',
|
|
45
|
+
params: '--lang=smt2 --tlimit=' + timeout
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
const solvers = potentialSolvers.filter(solver => (0, command_exists_1.sync)(solver.command));
|
|
49
|
+
function solve(query, solver) {
|
|
50
|
+
if (solver === undefined) {
|
|
51
|
+
if (solvers.length === 0) {
|
|
52
|
+
throw new Error('No SMT solver available. Assertion checking will not be performed.');
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
solver = solvers[0];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const tmpFile = tmp.fileSync({ postfix: '.smt2' });
|
|
59
|
+
fs.writeFileSync(tmpFile.name, query);
|
|
60
|
+
let solverOutput;
|
|
61
|
+
try {
|
|
62
|
+
solverOutput = (0, child_process_1.execSync)(solver.command + ' ' + solver.params + ' ' + tmpFile.name, {
|
|
63
|
+
encoding: 'utf8',
|
|
64
|
+
maxBuffer: 1024 * 1024 * 1024,
|
|
65
|
+
stdio: 'pipe',
|
|
66
|
+
timeout: timeout // Enforce timeout on the process, since solvers can sometimes go around it.
|
|
67
|
+
}).toString();
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
// execSync throws if the process times out or returns != 0.
|
|
71
|
+
// The latter might happen with z3 if the query asks for a model
|
|
72
|
+
// for an UNSAT formula. We can still use stdout.
|
|
73
|
+
solverOutput = e.stdout.toString();
|
|
74
|
+
if (!solverOutput.startsWith('sat') &&
|
|
75
|
+
!solverOutput.startsWith('unsat') &&
|
|
76
|
+
!solverOutput.startsWith('unknown') &&
|
|
77
|
+
!solverOutput.startsWith('(error') && // Eldarica reports errors in an sexpr, for example: '(error "Failed to reconstruct array model")'
|
|
78
|
+
!solverOutput.startsWith('error')) {
|
|
79
|
+
throw new Error('Failed to solve SMT query. ' + e.toString());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Trigger early manual cleanup
|
|
83
|
+
tmpFile.removeCallback();
|
|
84
|
+
return solverOutput;
|
|
85
|
+
}
|
|
86
|
+
module.exports = {
|
|
87
|
+
smtSolver: solve,
|
|
88
|
+
availableSolvers: solvers
|
|
89
|
+
};
|
package/test/abi.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const tape_1 = __importDefault(require("tape"));
|
|
7
|
+
const abi_1 = __importDefault(require("../abi"));
|
|
8
|
+
(0, tape_1.default)('ABI translator', function (t) {
|
|
9
|
+
t.test('Empty ABI', function (st) {
|
|
10
|
+
st.deepEqual(abi_1.default.update('0.4.0', []), []);
|
|
11
|
+
st.end();
|
|
12
|
+
});
|
|
13
|
+
t.test('0.1.1 (no constructor)', function (st) {
|
|
14
|
+
st.deepEqual(abi_1.default.update('0.1.1', []), [{ inputs: [], payable: true, stateMutability: 'payable', type: 'constructor' }, { payable: true, stateMutability: 'payable', type: 'fallback' }]);
|
|
15
|
+
st.end();
|
|
16
|
+
});
|
|
17
|
+
t.test('0.3.6 (constructor)', function (st) {
|
|
18
|
+
const input = [{ inputs: [], type: 'constructor' }];
|
|
19
|
+
st.deepEqual(abi_1.default.update('0.3.6', input), [{ inputs: [], payable: true, stateMutability: 'payable', type: 'constructor' }, { payable: true, stateMutability: 'payable', type: 'fallback' }]);
|
|
20
|
+
st.end();
|
|
21
|
+
});
|
|
22
|
+
t.test('0.3.6 (non-constant function)', function (st) {
|
|
23
|
+
const input = [{ inputs: [], type: 'function' }];
|
|
24
|
+
st.deepEqual(abi_1.default.update('0.3.6', input), [{ inputs: [], payable: true, stateMutability: 'payable', type: 'function' }, { payable: true, stateMutability: 'payable', type: 'fallback' }]);
|
|
25
|
+
st.end();
|
|
26
|
+
});
|
|
27
|
+
t.test('0.3.6 (constant function)', function (st) {
|
|
28
|
+
const input = [{ inputs: [], type: 'function', constant: true }];
|
|
29
|
+
st.deepEqual(abi_1.default.update('0.3.6', input), [{ inputs: [], constant: true, stateMutability: 'view', type: 'function' }, { payable: true, stateMutability: 'payable', type: 'fallback' }]);
|
|
30
|
+
st.end();
|
|
31
|
+
});
|
|
32
|
+
t.test('0.3.6 (event)', function (st) {
|
|
33
|
+
const input = [{ inputs: [], type: 'event' }];
|
|
34
|
+
st.deepEqual(abi_1.default.update('0.3.6', input), [{ inputs: [], type: 'event' }, { payable: true, stateMutability: 'payable', type: 'fallback' }]);
|
|
35
|
+
st.end();
|
|
36
|
+
});
|
|
37
|
+
t.test('0.3.6 (has no fallback)', function (st) {
|
|
38
|
+
const input = [{ inputs: [], type: 'constructor' }];
|
|
39
|
+
st.deepEqual(abi_1.default.update('0.3.6', input), [{ inputs: [], type: 'constructor', payable: true, stateMutability: 'payable' }, { type: 'fallback', payable: true, stateMutability: 'payable' }]);
|
|
40
|
+
st.end();
|
|
41
|
+
});
|
|
42
|
+
t.test('0.4.0 (has fallback)', function (st) {
|
|
43
|
+
const input = [{ inputs: [], type: 'constructor' }, { type: 'fallback' }];
|
|
44
|
+
st.deepEqual(abi_1.default.update('0.4.0', input), [{ inputs: [], type: 'constructor', payable: true, stateMutability: 'payable' }, { type: 'fallback', stateMutability: 'nonpayable' }]);
|
|
45
|
+
st.end();
|
|
46
|
+
});
|
|
47
|
+
t.test('0.4.0 (non-constant function)', function (st) {
|
|
48
|
+
const input = [{ inputs: [], type: 'function' }];
|
|
49
|
+
st.deepEqual(abi_1.default.update('0.4.0', input), [{ inputs: [], stateMutability: 'nonpayable', type: 'function' }]);
|
|
50
|
+
st.end();
|
|
51
|
+
});
|
|
52
|
+
t.test('0.4.0 (constant function)', function (st) {
|
|
53
|
+
const input = [{ inputs: [], type: 'function', constant: true }];
|
|
54
|
+
st.deepEqual(abi_1.default.update('0.4.0', input), [{ inputs: [], constant: true, stateMutability: 'view', type: 'function' }]);
|
|
55
|
+
st.end();
|
|
56
|
+
});
|
|
57
|
+
t.test('0.4.0 (payable function)', function (st) {
|
|
58
|
+
const input = [{ inputs: [], payable: true, type: 'function' }];
|
|
59
|
+
st.deepEqual(abi_1.default.update('0.4.0', input), [{ inputs: [], payable: true, stateMutability: 'payable', type: 'function' }]);
|
|
60
|
+
st.end();
|
|
61
|
+
});
|
|
62
|
+
t.test('0.4.1 (constructor not payable)', function (st) {
|
|
63
|
+
const input = [{ inputs: [], payable: false, type: 'constructor' }];
|
|
64
|
+
st.deepEqual(abi_1.default.update('0.4.1', input), [{ inputs: [], payable: true, stateMutability: 'payable', type: 'constructor' }]);
|
|
65
|
+
st.end();
|
|
66
|
+
});
|
|
67
|
+
t.test('0.4.5 (constructor payable)', function (st) {
|
|
68
|
+
const input = [{ inputs: [], payable: false, type: 'constructor' }];
|
|
69
|
+
st.deepEqual(abi_1.default.update('0.4.5', input), [{ inputs: [], payable: false, stateMutability: 'nonpayable', type: 'constructor' }]);
|
|
70
|
+
st.end();
|
|
71
|
+
});
|
|
72
|
+
t.test('0.4.16 (statemutability)', function (st) {
|
|
73
|
+
const input = [{ inputs: [], payable: false, stateMutability: 'pure', type: 'function' }];
|
|
74
|
+
st.deepEqual(abi_1.default.update('0.4.16', input), [{ inputs: [], payable: false, stateMutability: 'pure', type: 'function' }]);
|
|
75
|
+
st.end();
|
|
76
|
+
});
|
|
77
|
+
});
|