Test coverage (#30)

* added task tests

* added circom-compiler-downloader.test.ts, made some fixes

* fix timeout issue

* debug ci

* fixed ETXTBSY error

* fixed ETXTBSY error without setTimeout

* created tests with os mock, added verifyCompiler flag

* added keys verification and circuits with libs compilation inside tasks tests

* multiple workspaces with the same name fix

* added ptau downloader tests

* prevented native compiler usage inside tests, modified mocha timeout

* added semver and tsconfig paths

* moved semver to dependencies, modified eslint settings

* restricted semver version, updated package version
This commit is contained in:
Mllw Chrry
2024-09-26 02:54:42 -07:00
committed by GitHub
parent b63318cb42
commit 8abd3cf041
49 changed files with 1638 additions and 389 deletions

View File

@@ -47,7 +47,15 @@ module.exports = {
},
],
"no-multiple-empty-lines": [2, { max: 1, maxEOF: 0, maxBOF: 0 }],
"import/no-named-as-default-member": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
},
settings: {
"import/resolver": {
"typescript": {
"project": "./tsconfig.json",
},
},
},
};

View File

@@ -2,5 +2,5 @@
"file": ["test/setup.ts"],
"require": "ts-node/register/files",
"ignore": ["test/fixture-projects/**/*"],
"timeout": 10000
"timeout": 60000
}

357
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@solarity/hardhat-zkit",
"version": "0.4.1",
"version": "0.4.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@solarity/hardhat-zkit",
"version": "0.4.1",
"version": "0.4.2",
"license": "MIT",
"workspaces": [
"test/fixture-projects/*"
@@ -23,12 +23,14 @@
"lodash": "4.17.21",
"ora": "5.4.1",
"resolve": "1.22.8",
"semver": "7.6.3",
"snarkjs": "0.7.3",
"uuid": "9.0.1",
"zod": "3.23.8"
},
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "3.0.5",
"@solarity/chai-zkit": "^0.2.5",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0",
"@types/chai": "^4.3.12",
@@ -40,6 +42,7 @@
"@types/lodash": "4.17.5",
"@types/mocha": "^10.0.6",
"@types/resolve": "^1.20.6",
"@types/sinon": "^17.0.3",
"@types/snarkjs": "^0.7.8",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^6.20.0",
@@ -47,7 +50,8 @@
"chai": "^4.4.1",
"chai-as-promised": "^7.1.1",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.1.1",
"ethers": "6.11.1",
@@ -56,7 +60,9 @@
"mocha": "^10.3.0",
"nyc": "^15.1.0",
"prettier": "^3.2.5",
"sinon": "^19.0.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typechain": "^8.3.2",
"typescript": "5.3.3"
},
@@ -1319,6 +1325,15 @@
"node": ">= 8"
}
},
"node_modules/@nolyfill/is-core-module": {
"version": "1.0.39",
"resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
"integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
"dev": true,
"engines": {
"node": ">=12.4.0"
}
},
"node_modules/@nomicfoundation/ethereumjs-block": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.4.tgz",
@@ -2066,6 +2081,102 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/@sinonjs/commons": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
"integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
"dev": true,
"dependencies": {
"type-detect": "4.0.8"
}
},
"node_modules/@sinonjs/commons/node_modules/type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/@sinonjs/fake-timers": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.2.tgz",
"integrity": "sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^3.0.1"
}
},
"node_modules/@sinonjs/samsam": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz",
"integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^3.0.1",
"lodash.get": "^4.4.2",
"type-detect": "^4.1.0"
}
},
"node_modules/@sinonjs/text-encoding": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz",
"integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==",
"dev": true
},
"node_modules/@solarity/chai-zkit": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@solarity/chai-zkit/-/chai-zkit-0.2.5.tgz",
"integrity": "sha512-VRl6YXd/uQruz0U48B85hmeA7sMn1WUjUcGtMMKovFJjFY4xKjUrtGAuXfUCM8ZB9nt6iuTulsPEijLWgayIHg==",
"dev": true,
"dependencies": {
"chai-as-promised": "7.1.1"
},
"peerDependencies": {
"@solarity/hardhat-zkit": ">=0.3.1 <0.5.0",
"@solarity/zkit": ">=0.2.4 <0.4.0",
"chai": "^4.0.0"
}
},
"node_modules/@solarity/chai-zkit/node_modules/chai-as-promised": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
"integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
"dev": true,
"dependencies": {
"check-error": "^1.0.2"
},
"peerDependencies": {
"chai": ">= 2.1.2 < 5"
}
},
"node_modules/@solarity/hardhat-zkit": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@solarity/hardhat-zkit/-/hardhat-zkit-0.4.1.tgz",
"integrity": "sha512-dA2jJtnM1m01v1EKQJFCf0Fr8OB59Ep/8CpW3ZJYOudQZWiVo+qgfWao7Y4P9cH2qPC3XJmQlIggkOvOMESjfw==",
"dev": true,
"peer": true,
"dependencies": {
"@distributedlab/circom-parser": "0.1.2",
"@distributedlab/circom2": "0.2.18-rc.4",
"@solarity/zkit": "0.2.6",
"@solarity/zktype": "0.3.1",
"chalk": "4.1.2",
"cli-progress": "3.12.0",
"cli-table3": "0.6.5",
"debug": "4.3.5",
"lodash": "4.17.21",
"ora": "5.4.1",
"resolve": "1.22.8",
"snarkjs": "0.7.3",
"uuid": "9.0.1",
"zod": "3.23.8"
},
"peerDependencies": {
"hardhat": "^2.16.0"
}
},
"node_modules/@solarity/zkit": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/@solarity/zkit/-/zkit-0.2.6.tgz",
@@ -2315,6 +2426,21 @@
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true
},
"node_modules/@types/sinon": {
"version": "17.0.3",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz",
"integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==",
"dev": true,
"dependencies": {
"@types/sinonjs__fake-timers": "*"
}
},
"node_modules/@types/sinonjs__fake-timers": {
"version": "8.1.5",
"resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz",
"integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==",
"dev": true
},
"node_modules/@types/snarkjs": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/@types/snarkjs/-/snarkjs-0.7.8.tgz",
@@ -3994,6 +4120,19 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/enquirer": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
@@ -4337,6 +4476,41 @@
"ms": "^2.1.1"
}
},
"node_modules/eslint-import-resolver-typescript": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz",
"integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==",
"dev": true,
"dependencies": {
"@nolyfill/is-core-module": "1.0.39",
"debug": "^4.3.5",
"enhanced-resolve": "^5.15.0",
"eslint-module-utils": "^2.8.1",
"fast-glob": "^3.3.2",
"get-tsconfig": "^4.7.5",
"is-bun-module": "^1.0.2",
"is-glob": "^4.0.3"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts"
},
"peerDependencies": {
"eslint": "*",
"eslint-plugin-import": "*",
"eslint-plugin-import-x": "*"
},
"peerDependenciesMeta": {
"eslint-plugin-import": {
"optional": true
},
"eslint-plugin-import-x": {
"optional": true
}
}
},
"node_modules/eslint-module-utils": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz",
@@ -4426,6 +4600,18 @@
"node": ">=0.10.0"
}
},
"node_modules/eslint-plugin-import/node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/eslint-plugin-import/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -4447,6 +4633,27 @@
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-import/node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/eslint-plugin-import/node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz",
@@ -5182,6 +5389,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-tsconfig": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
"integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
"dev": true,
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
"funding": {
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
"node_modules/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -5388,10 +5607,22 @@
"resolved": "test/fixture-projects/hardhat-project-circuits-with-libraries",
"link": true
},
"node_modules/hardhat-project-compiler-config": {
"resolved": "test/fixture-projects/hardhat-project-compiler-config",
"link": true
},
"node_modules/hardhat-project-compiler-incorrect-config": {
"resolved": "test/fixture-projects/hardhat-project-compiler-incorrect-config",
"link": true
},
"node_modules/hardhat-project-defined-config": {
"resolved": "test/fixture-projects/hardhat-project-defined-config",
"link": true
},
"node_modules/hardhat-project-invalid-circuits": {
"resolved": "test/fixture-projects/hardhat-project-invalid-circuits",
"link": true
},
"node_modules/hardhat-project-undefined-config": {
"resolved": "test/fixture-projects/hardhat-project-undefined-config",
"link": true
@@ -6031,6 +6262,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-bun-module": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz",
"integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==",
"dev": true,
"dependencies": {
"semver": "^7.6.3"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -6597,6 +6837,12 @@
"underscore": "1.12.1"
}
},
"node_modules/just-extend": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz",
"integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==",
"dev": true
},
"node_modules/keccak": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz",
@@ -6675,6 +6921,12 @@
"integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
"dev": true
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
"dev": true
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
@@ -7000,6 +7252,19 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/nise": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz",
"integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^3.0.1",
"@sinonjs/fake-timers": "^13.0.1",
"@sinonjs/text-encoding": "^0.7.3",
"just-extend": "^6.2.0",
"path-to-regexp": "^8.1.0"
}
},
"node_modules/node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
@@ -7516,6 +7781,15 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-to-regexp": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.1.0.tgz",
"integrity": "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==",
"dev": true,
"engines": {
"node": ">=16"
}
},
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -7882,6 +8156,15 @@
"node": ">=4"
}
},
"node_modules/resolve-pkg-maps": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -8064,7 +8347,6 @@
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -8187,6 +8469,33 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/sinon": {
"version": "19.0.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz",
"integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^3.0.1",
"@sinonjs/fake-timers": "^13.0.2",
"@sinonjs/samsam": "^8.0.1",
"diff": "^7.0.0",
"nise": "^6.1.1",
"supports-color": "^7.2.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/sinon"
}
},
"node_modules/sinon/node_modules/diff": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
"integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -8600,6 +8909,15 @@
"node": ">=8"
}
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/tar": {
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/tar/-/tar-5.0.11.tgz",
@@ -8804,27 +9122,17 @@
}
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"dev": true,
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
"json5": "^2.2.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
"engines": {
"node": ">=6"
}
},
"node_modules/tsconfig-paths/node_modules/strip-bom": {
@@ -9560,9 +9868,18 @@
"circomlib": "^2.0.5"
}
},
"test/fixture-projects/hardhat-project-compiler-config": {
"version": "1.0.0"
},
"test/fixture-projects/hardhat-project-compiler-incorrect-config": {
"version": "1.0.0"
},
"test/fixture-projects/hardhat-project-defined-config": {
"version": "1.0.0"
},
"test/fixture-projects/hardhat-project-invalid-circuits": {
"version": "1.0.0"
},
"test/fixture-projects/hardhat-project-undefined-config": {
"version": "1.0.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@solarity/hardhat-zkit",
"version": "0.4.1",
"version": "0.4.2",
"description": "The ultimate TypeScript environment for Circom development",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
@@ -61,6 +61,7 @@
"lodash": "4.17.21",
"ora": "5.4.1",
"resolve": "1.22.8",
"semver": "7.6.3",
"snarkjs": "0.7.3",
"uuid": "9.0.1",
"zod": "3.23.8"
@@ -70,6 +71,7 @@
},
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "3.0.5",
"@solarity/chai-zkit": "^0.2.5",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0",
"@types/chai": "^4.3.12",
@@ -81,6 +83,7 @@
"@types/lodash": "4.17.5",
"@types/mocha": "^10.0.6",
"@types/resolve": "^1.20.6",
"@types/sinon": "^17.0.3",
"@types/snarkjs": "^0.7.8",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^6.20.0",
@@ -88,7 +91,8 @@
"chai": "^4.4.1",
"chai-as-promised": "^7.1.1",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.1.1",
"ethers": "6.11.1",
@@ -97,7 +101,9 @@
"mocha": "^10.3.0",
"nyc": "^15.1.0",
"prettier": "^3.2.5",
"sinon": "^19.0.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typechain": "^8.3.2",
"typescript": "5.3.3"
}

View File

@@ -1,6 +1,7 @@
import path from "path";
import os from "os";
import fs from "fs";
import semver from "semver";
import fsExtra from "fs-extra";
import { v4 as uuid } from "uuid";
@@ -11,7 +12,7 @@ import { HardhatZKitError } from "../../errors";
import { CIRCUIT_ARTIFACT_VERSION, NODE_MODULES } from "../../constants";
import { Reporter } from "../../reporter";
import { getHighestVersion, isVersionValid, isVersionHigherOrEqual } from "../compiler/versioning";
import { getHighestVersion, isVersionValid } from "../compiler/versioning";
import { getNormalizedFullPath, renameFilesRecursively, readDirRecursively } from "../../utils/path-utils";
import { ZKitConfig } from "../../types/zkit-config";
@@ -59,7 +60,7 @@ export class CompilationProcessor {
let version = highestCircomVersion;
if (this._zkitConfig.compilerVersion && isVersionValid(this._zkitConfig.compilerVersion)) {
if (!isVersionHigherOrEqual(this._zkitConfig.compilerVersion, highestCircomVersion)) {
if (!semver.gte(this._zkitConfig.compilerVersion, highestCircomVersion)) {
throw new HardhatZKitError(
`Unable to compile a circuit with Circom version ${highestCircomVersion} using compiler version ${this._zkitConfig.compilerVersion} specified in the config`,
);

View File

@@ -2,6 +2,7 @@ import os from "os";
import path from "path";
import fs from "fs-extra";
import https from "https";
import semver from "semver";
import { promisify } from "util";
import { execFile } from "child_process";
@@ -18,7 +19,7 @@ import { HardhatZKitError } from "../../errors";
import { CompilerInfo, CompilerPlatformBinary } from "../../types/core";
import { downloadFile } from "../../utils/utils";
import { getHighestVersion, isVersionHigherOrEqual } from "./versioning";
import { getHighestVersion } from "./versioning";
import { MultiProcessMutex } from "hardhat/internal/util/multi-process-mutex";
@@ -67,14 +68,14 @@ export class CircomCompilerDownloader {
return (await fs.pathExists(downloadPath)) || fs.pathExists(downloadPathWasm);
}
const latestDownloadedVersion = await this._getLatestDownloadedCircomVersion();
const latestDownloadedVersion = this._getLatestDownloadedCircomVersion();
return isVersionHigherOrEqual(latestDownloadedVersion, version);
return semver.gte(latestDownloadedVersion, version);
}
public async getCompilerBinary(version: string, isVersionStrict: boolean): Promise<CompilerInfo> {
if (!isVersionStrict) {
version = await this._getLatestDownloadedCircomVersion();
version = this._getLatestDownloadedCircomVersion();
if (!version || version === "0.0.0") {
throw new HardhatZKitError("No latest compiler found");
@@ -84,18 +85,18 @@ export class CircomCompilerDownloader {
const compilerBinaryPath = this._getCompilerDownloadPath(version);
const wasmCompilerBinaryPath = this._getWasmCompilerDownloadPath(version);
if (await fs.pathExists(compilerBinaryPath)) {
return { binaryPath: compilerBinaryPath, version: version, isWasm: false };
}
if (await fs.pathExists(wasmCompilerBinaryPath)) {
return { binaryPath: wasmCompilerBinaryPath, version: version, isWasm: true };
}
if (await fs.pathExists(compilerBinaryPath)) {
return { binaryPath: compilerBinaryPath, version: version, isWasm: false };
}
throw new HardhatZKitError(`Trying to get a Circom compiler v${version} before it was downloaded`);
}
public async downloadCompiler(version: string, isVersionStrict: boolean): Promise<void> {
public async downloadCompiler(version: string, isVersionStrict: boolean, verifyCompiler: boolean): Promise<void> {
await this._mutex.use(async () => {
const versionToDownload = isVersionStrict ? version : await this._getLatestCircomVersion();
@@ -110,25 +111,27 @@ export class CircomCompilerDownloader {
try {
downloadPath = await this._downloadCompiler(versionToDownload);
} catch (error: any) {
throw new HardhatZKitError(error);
throw new HardhatZKitError(error.message);
}
await this._postProcessCompilerDownload(downloadPath);
if (verifyCompiler) {
await this._postProcessCompilerDownload(downloadPath);
}
});
}
private async _getLatestDownloadedCircomVersion(): Promise<string> {
private _getLatestDownloadedCircomVersion(): string {
try {
const entries = await fs.promises.readdir(this._compilersDir, { withFileTypes: true });
const entries = fs.readdirSync(this._compilersDir, { withFileTypes: true });
const versions = entries
.filter(async (entry) => {
.filter((entry) => {
if (!entry.isDirectory()) {
return false;
}
const dirPath = path.join(this._compilersDir, entry.name);
const files = await fs.promises.readdir(dirPath);
const files = fs.readdirSync(dirPath);
return files.includes(this._platform) || files.includes("circom.wasm");
})

View File

@@ -1,6 +1,7 @@
import os from "os";
import path from "path";
import fs from "fs-extra";
import semver from "semver";
import { promisify } from "util";
import { exec } from "child_process";
@@ -11,16 +12,18 @@ import { LATEST_SUPPORTED_CIRCOM_VERSION, OLDEST_SUPPORTED_ARM_CIRCOM_VERSION }
import { BinaryCircomCompiler, WASMCircomCompiler } from "./CircomCompiler";
import { CircomCompilerDownloader } from "./CircomCompilerDownloader";
import { isVersionHigherOrEqual } from "./versioning";
import { CompilerInfo, CompilerPlatformBinary, ICircomCompiler, NativeCompiler } from "../../types/core";
// eslint-disable-next-line
const { Context } = require("@distributedlab/circom2");
export class BaseCircomCompilerFactory {
public async createCircomCompiler(version: string, isVersionStrict: boolean): Promise<ICircomCompiler> {
if (!isVersionHigherOrEqual(LATEST_SUPPORTED_CIRCOM_VERSION, version)) {
public async createCircomCompiler(
version: string,
isVersionStrict: boolean,
verifyCompiler: boolean = true,
): Promise<ICircomCompiler> {
if (!semver.gte(LATEST_SUPPORTED_CIRCOM_VERSION, version)) {
throw new HardhatZKitError(`Unsupported Circom compiler version - ${version}. Please provide another version.`);
}
@@ -34,23 +37,19 @@ export class BaseCircomCompilerFactory {
// Utilize binary translators like Rosetta (macOS) or Prism (Windows)
// to run x64 binaries on arm64 systems when no arm64 versions are available.
if (
isVersionStrict &&
os.arch() === "arm64" &&
!isVersionHigherOrEqual(version, OLDEST_SUPPORTED_ARM_CIRCOM_VERSION)
) {
if (isVersionStrict && os.arch() === "arm64" && !semver.gte(version, OLDEST_SUPPORTED_ARM_CIRCOM_VERSION)) {
compilerPlatformBinary = CircomCompilerDownloader.getCompilerPlatformBinary("x64");
}
if (compilerPlatformBinary !== CompilerPlatformBinary.WASM) {
compiler = await this._tryCreateBinaryCompiler(compilerPlatformBinary, version, isVersionStrict);
compiler = await this._tryCreateBinaryCompiler(compilerPlatformBinary, version, isVersionStrict, verifyCompiler);
if (compiler) {
return compiler;
}
}
return this._createWasmCompiler(version, isVersionStrict);
return this._createWasmCompiler(version, isVersionStrict, verifyCompiler);
}
private async _tryCreateNativeCompiler(
@@ -65,7 +64,7 @@ export class BaseCircomCompilerFactory {
const isValidVersion = isVersionStrict
? nativeCompiler.version === version
: isVersionHigherOrEqual(nativeCompiler.version, version);
: semver.gte(nativeCompiler.version, version);
if (isValidVersion) {
Reporter!.reportCompilerVersion(nativeCompiler.version);
@@ -78,9 +77,10 @@ export class BaseCircomCompilerFactory {
platform: CompilerPlatformBinary,
version: string,
isVersionStrict: boolean,
verifyCompiler: boolean,
): Promise<ICircomCompiler | undefined> {
try {
const compilerInfo = await this._getBinaryCompiler(platform, version, isVersionStrict);
const compilerInfo = await this._getBinaryCompiler(platform, version, isVersionStrict, verifyCompiler);
if (compilerInfo.isWasm) {
return new WASMCircomCompiler(this._getWasmCompiler(compilerInfo.binaryPath));
@@ -92,8 +92,17 @@ export class BaseCircomCompilerFactory {
}
}
private async _createWasmCompiler(version: string, isVersionStrict: boolean): Promise<ICircomCompiler> {
const compilerInfo = await this._getBinaryCompiler(CompilerPlatformBinary.WASM, version, isVersionStrict);
private async _createWasmCompiler(
version: string,
isVersionStrict: boolean,
verifyCompiler: boolean,
): Promise<ICircomCompiler> {
const compilerInfo = await this._getBinaryCompiler(
CompilerPlatformBinary.WASM,
version,
isVersionStrict,
verifyCompiler,
);
return new WASMCircomCompiler(this._getWasmCompiler(compilerInfo.binaryPath));
}
@@ -130,12 +139,13 @@ export class BaseCircomCompilerFactory {
platform: CompilerPlatformBinary,
version: string,
isVersionStrict: boolean,
verifyCompiler: boolean,
): Promise<CompilerInfo> {
const compilersDir = await this._getCompilersDir();
const downloader = CircomCompilerDownloader.getCircomCompilerDownloader(platform, compilersDir);
if (!(await downloader.isCompilerDownloaded(version, isVersionStrict))) {
await downloader.downloadCompiler(version, isVersionStrict);
await downloader.downloadCompiler(version, isVersionStrict, verifyCompiler);
}
const compilerBinaryInfo = await downloader.getCompilerBinary(version, isVersionStrict);

View File

@@ -1,13 +1,15 @@
import semver from "semver";
import { CircomResolvedFileInfo } from "../../types/core";
export function getHighestVersion(circomVersions: CircomResolvedFileInfo[] | string[]) {
let highestVersion = "";
let highestVersion = "0.0.0";
for (const info of circomVersions) {
const circomVersion =
typeof info == "string" ? info : info.resolvedFile.fileData.parsedFileData.pragmaInfo.compilerVersion;
if (isVersionHigherOrEqual(circomVersion, highestVersion)) {
if (semver.gte(circomVersion, highestVersion)) {
highestVersion = circomVersion;
}
}
@@ -15,35 +17,6 @@ export function getHighestVersion(circomVersions: CircomResolvedFileInfo[] | str
return highestVersion;
}
export function isVersionHigherOrEqual(version1: string, version2: string): boolean {
if (!version1 && version2) {
return false;
}
if (!version2 || (!version1 && !version2)) {
return true;
}
const [v1Major, v1Minor, v1Patch] = version1.split(".").map(Number);
const [v2Major, v2Minor, v2Patch] = version2.split(".").map(Number);
if (v1Major !== v2Major) {
return v1Major > v2Major;
}
if (v1Minor !== v2Minor) {
return v1Minor > v2Minor;
}
return v1Patch >= v2Patch;
}
export function isVersionValid(version: string) {
const versionParts = version.trim().split(".");
if (versionParts.length !== 3) {
return false;
}
return !isNaN(Number(versionParts[0])) && !isNaN(Number(versionParts[1])) && !isNaN(Number(versionParts[2]));
export function isVersionValid(version: string): boolean {
return semver.valid(version) === version;
}

View File

@@ -23,60 +23,67 @@ export async function downloadFile(
onFinishReporter: () => void,
onErrorReporter: () => void,
): Promise<boolean> {
await fs.ensureFile(file);
try {
await fs.ensureFile(file);
const fileStream = fs.createWriteStream(file);
const fileStream = fs.createWriteStream(file);
return new Promise((resolve, reject) => {
const handleRequest = (currentUrl: string) => {
const request = https.get(currentUrl, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
const redirectUrl = response.headers.location;
if (redirectUrl) {
handleRequest(redirectUrl);
} else {
onErrorReporter();
fs.unlink(file, () => reject(new Error("Invalid redirect response")));
return new Promise((resolve) => {
const handleRequest = (currentUrl: string) => {
const request = https.get(currentUrl, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
const redirectUrl = response.headers.location;
if (redirectUrl) {
handleRequest(redirectUrl);
} else {
onErrorReporter();
fs.unlink(file, () => resolve(false));
}
return;
}
return;
}
if (response.statusCode !== 200) {
onErrorReporter();
fs.unlink(file, () => reject(new Error(`Failed to download file with status code: ${response.statusCode}`)));
return;
}
const totalSize = parseInt(response.headers["content-length"] || "0", 10);
Reporter!.reportStartFileDownloadingWithProgressBar(totalSize, 0);
response.pipe(fileStream);
response
.on("data", (chunk) => {
Reporter!.updateProgressBarValue(chunk.length);
})
.on("error", (err) => {
if (response.statusCode !== 200) {
onErrorReporter();
fs.unlink(file, () => reject(err));
})
.on("end", () => {
onFinishReporter();
resolve(true);
});
});
fs.unlink(file, () => resolve(false));
return;
}
request.on("error", (err) => {
fs.unlink(file, () => reject(err));
});
};
const totalSize = parseInt(response.headers["content-length"] || "0", 10);
Reporter!.reportStartFileDownloadingWithProgressBar(totalSize, 0);
handleRequest(url);
});
response.pipe(fileStream);
response
.on("data", (chunk) => {
Reporter!.updateProgressBarValue(chunk.length);
})
.on("error", () => {
onErrorReporter();
fs.unlink(file, () => resolve(false));
});
fileStream
.on("finish", () => {
fileStream.close(() => {
onFinishReporter();
resolve(true);
});
})
.on("error", () => {
onErrorReporter();
fs.unlink(file, () => resolve(false));
});
});
request.on("error", () => {
fs.unlink(file, () => resolve(false));
});
};
handleRequest(url);
});
} catch (error: any) {
return false;
}
}
export async function execCall(execFile: string, callArgs: string[]): Promise<ExecCallResult> {

14
test/constants.ts Normal file
View File

@@ -0,0 +1,14 @@
import { CompileFlags, ContributionSettings } from "../src/types/core";
export const defaultCompileFlags: CompileFlags = {
r1cs: true,
wasm: true,
sym: true,
c: false,
json: false,
};
export const defaultContributionSettings: ContributionSettings = {
provingSystem: "groth16",
contributions: 1,
};

View File

@@ -14,4 +14,4 @@ template Hash2(){
out <== h.out;
}
component main = Hash2();
component main = Hash2();

View File

@@ -0,0 +1,7 @@
/cache
/artifacts
generated-types
compilers
contracts/verifiers
zkit

View File

@@ -0,0 +1,9 @@
pragma circom 2.0.0;
template Multiplier2(){
signal input in1;
signal input in2;
signal output out;
out <== in1 * in2;
}

View File

@@ -0,0 +1,10 @@
pragma circom 2.0.0;
template SumMul(){
signal input in1;
signal input in2;
signal input in3;
signal output out;
out <== in1 + in2 * in3;
}

View File

@@ -0,0 +1,6 @@
pragma circom 2.0.0;
include "../base/mul2Base.circom";
include "../base/sumMul.circom";
component main = Multiplier2();

View File

@@ -0,0 +1,25 @@
import { HardhatUserConfig } from "hardhat/config";
import config from "../hardhat.config";
const defaultConfig: HardhatUserConfig = {
...config,
zkit: {
compilerVersion: "2.1.9",
circuitsDir: "circuits",
compilationSettings: {
artifactsDir: "zkit/artifacts",
skipFiles: ["vendor"],
},
setupSettings: {
ptauDir: "zkit/ptau",
ptauDownload: true,
},
quiet: true,
verifiersSettings: {
verifiersDir: "contracts/verifiers",
},
},
};
export default defaultConfig;

View File

@@ -0,0 +1,8 @@
{
"name": "hardhat-project-compiler-config",
"version": "1.0.0",
"scripts": {
"compile": "hardhat compile --force",
"clean": "hardhat clean && rm -rf artifacts && rm -rf cache"
}
}

View File

@@ -0,0 +1,7 @@
/cache
/artifacts
generated-types
compilers
contracts/verifiers
zkit

View File

@@ -0,0 +1,9 @@
pragma circom 2.1.9;
template Multiplier2(){
signal input in1;
signal input in2;
signal output out;
out <== in1 * in2;
}

View File

@@ -0,0 +1,10 @@
pragma circom 2.1.9;
template SumMul(){
signal input in1;
signal input in2;
signal input in3;
signal output out;
out <== in1 + in2 * in3;
}

View File

@@ -0,0 +1,6 @@
pragma circom 2.1.9;
include "../base/mul2Base.circom";
include "../base/sumMul.circom";
component main = Multiplier2();

View File

@@ -0,0 +1,25 @@
import { HardhatUserConfig } from "hardhat/config";
import config from "../hardhat.config";
const defaultConfig: HardhatUserConfig = {
...config,
zkit: {
compilerVersion: "2.1.8",
circuitsDir: "circuits",
compilationSettings: {
artifactsDir: "zkit/artifacts",
skipFiles: ["vendor"],
},
setupSettings: {
ptauDir: "zkit/ptau",
ptauDownload: true,
},
quiet: true,
verifiersSettings: {
verifiersDir: "contracts/verifiers",
},
},
};
export default defaultConfig;

View File

@@ -0,0 +1,8 @@
{
"name": "hardhat-project-compiler-incorrect-config",
"version": "1.0.0",
"scripts": {
"compile": "hardhat compile --force",
"clean": "hardhat clean && rm -rf artifacts && rm -rf cache"
}
}

View File

@@ -0,0 +1,5 @@
/cache
/artifacts
contracts/verifiers
zkit

View File

@@ -0,0 +1,17 @@
pragma circom 2.0.0;
include "/absolute/path/to/circuit.circom";
template Hash2(){
signal input in1;
signal input in2;
signal output out;
component h = Poseidon(2);
h.inputs[0] <== in1;
h.inputs[1] <== in2;
out <== h.out;
}
component main = Hash2();

View File

@@ -0,0 +1,23 @@
import { HardhatUserConfig } from "hardhat/config";
import config from "../hardhat.config";
const defaultConfig: HardhatUserConfig = {
...config,
zkit: {
circuitsDir: "circuits",
compilationSettings: {
artifactsDir: "zkit/artifacts",
},
setupSettings: {
ptauDir: "zkit/ptau",
ptauDownload: true,
},
quiet: true,
verifiersSettings: {
verifiersDir: "contracts/verifiers",
},
},
};
export default defaultConfig;

View File

@@ -0,0 +1,8 @@
{
"name": "hardhat-project-invalid-circuits",
"version": "1.0.0",
"scripts": {
"compile": "hardhat compile --force",
"clean": "hardhat clean && rm -rf artifacts && rm -rf cache"
}
}

View File

@@ -2,5 +2,6 @@
/artifacts
generated-types
compilers
contracts/verifiers
zkit
zkit

View File

@@ -4,5 +4,6 @@ template Multiplier2(){
signal input in1;
signal input in2;
signal output out;
out <== in1 * in2;
}
}

View File

@@ -1,4 +1,4 @@
pragma circom 2.0.0;
pragma circom 2.1.8;
template Multiplier3Arr(){
signal input in[3];
@@ -9,4 +9,4 @@ template Multiplier3Arr(){
out <== tmp * in[2];
}
component main = Multiplier3Arr();
component main = Multiplier3Arr();

View File

@@ -1,32 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
interface IMul2Verifier {
function verifyProof(
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[1] calldata pubSignals_
) external view;
}
contract Mul2ProofVerifier {
IMul2Verifier public verifier;
mapping (address => bool) public isVerified;
constructor (address verifierAddr_) {
verifier = IMul2Verifier(verifierAddr_);
}
function verifyProof(
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[1] calldata pubSignals_
) external {
verifier.verifyProof(pA_, pB_, pC_, pubSignals_);
isVerified[msg.sender] = true;
}
}

View File

@@ -1,32 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
interface IMul3ArrVerifier {
function verifyProof(
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[1] calldata pubSignals_
) external view;
}
contract Mul3ArrProofVerifier {
IMul3ArrVerifier public verifier;
mapping (address => bool) public isVerified;
constructor (address verifierAddr_) {
verifier = IMul3ArrVerifier(verifierAddr_);
}
function verifyProof(
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[1] calldata pubSignals_
) external {
verifier.verifyProof(pA_, pB_, pC_, pubSignals_);
isVerified[msg.sender] = true;
}
}

View File

@@ -1,5 +1,6 @@
/cache
/artifacts
compilers
contracts/verifiers
zkit
zkit

View File

@@ -5,8 +5,9 @@ import { resetHardhatContext } from "hardhat/plugins-testing";
import { TASK_COMPILE } from "hardhat/builtin-tasks/task-names";
import { getNormalizedFullPath } from "../src/utils/path-utils";
import { resetCircuitsCompileCache, resetCircuitsSetupCache } from "../src/cache";
export function useEnvironment(fixtureProjectName: string, networkName = "hardhat") {
export function useEnvironment(fixtureProjectName: string, withCleanUp: boolean = false, networkName = "hardhat") {
beforeEach("Loading hardhat environment", async function () {
const prefix = "hardhat-project-";
process.chdir(join(__dirname, "fixture-projects", prefix + fixtureProjectName));
@@ -14,6 +15,12 @@ export function useEnvironment(fixtureProjectName: string, networkName = "hardha
this.hre = require("hardhat");
if (withCleanUp) {
cleanUp(this.hre.config.paths.root);
return;
}
await this.hre.run(TASK_COMPILE, { quiet: true });
});
@@ -28,3 +35,21 @@ export function useEnvironment(fixtureProjectName: string, networkName = "hardha
export function getProjectRootPath(): string {
return dirname(__dirname);
}
export function cleanUp(rootPath: string) {
resetCircuitsCompileCache();
resetCircuitsSetupCache();
const directoriesToRemove = [
"generated-types/zkit",
"cache",
"zkit",
"artifacts",
"contracts/verifiers",
"compilers",
].map((dir) => getNormalizedFullPath(rootPath, dir));
directoriesToRemove.forEach((dir) => {
fsExtra.rmSync(dir, { recursive: true, force: true });
});
}

View File

@@ -4,9 +4,9 @@ import { extendConfig } from "hardhat/config";
import { useEnvironment } from "../../helpers";
import { zkitConfigExtender } from "../../../src/config/config";
import { zkitConfigExtender } from "@src/config/config";
import { ZKitConfig } from "../../../src/types/zkit-config";
import { ZKitConfig } from "@src/types/zkit-config";
describe("config", () => {
describe("loading", () => {

View File

@@ -0,0 +1,341 @@
import os from "os";
import path from "path";
import fsExtra from "fs-extra";
import { execSync } from "child_process";
import "@solarity/chai-zkit";
import { expect } from "chai";
import { before } from "mocha";
import { stub, SinonStub } from "sinon";
import { HardhatUserConfig } from "hardhat/config";
import {
TASK_CIRCUITS_COMPILE,
TASK_CIRCUITS_MAKE,
TASK_CIRCUITS_SETUP,
TASK_GENERATE_VERIFIERS,
TASK_ZKIT_CLEAN,
ZKIT_SCOPE_NAME,
} from "@src/task-names";
import { CircuitsCompileCache, CircuitsSetupCache } from "@src/cache";
import { CompileCacheEntry, SetupCacheEntry } from "@src/types/cache";
import { cleanUp, useEnvironment } from "@test-helpers";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { getCompileCacheEntry, getSetupCacheEntry } from "../utils";
import { HardhatZKit } from "@src/types/hardhat-zkit";
import { BaseCircomCompilerFactory } from "@src/core";
import { CircomCompilerDownloader } from "@src/core/compiler/CircomCompilerDownloader";
describe("ZKit tasks", async function () {
const circuitNames = ["Multiplier2", "Multiplier3Arr"];
const sourceNames = ["circuits/main/mul2.circom", "circuits/main/Multiplier3Arr.circom"];
let nativeCompilerStub: SinonStub;
before(() => {
nativeCompilerStub = stub(BaseCircomCompilerFactory.prototype, "_tryCreateNativeCompiler" as any).callsFake(
async () => {
return undefined;
},
);
});
after(() => {
nativeCompilerStub.restore();
});
function getZkitCircuitFullPaths(config: HardhatUserConfig): string[] {
const circuitFullPaths: string[] = [];
sourceNames.forEach((sourceName) => {
circuitFullPaths.push(
getNormalizedFullPath(config.paths!.root!, `${config.zkit!.compilationSettings!.artifactsDir}/${sourceName}`),
);
});
return circuitFullPaths;
}
async function checkMake(config: HardhatUserConfig, zkit: HardhatZKit) {
const cacheFullPath: string = getNormalizedFullPath(config.paths!.root!, "cache");
expect(fsExtra.readdirSync(cacheFullPath)).to.be.deep.eq([
"circuits-compile-cache.json",
"circuits-setup-cache.json",
]);
CircuitsSetupCache!.getEntries().forEach(async (entry: SetupCacheEntry) => {
expect(entry).to.be.deep.eq(await getSetupCacheEntry(entry.circuitSourceName, entry.r1csSourcePath));
});
getZkitCircuitFullPaths(config).forEach((path, index) => {
expect(fsExtra.readdirSync(path)).to.be.deep.eq([
`${circuitNames[index]}.r1cs`,
`${circuitNames[index]}.sym`,
`${circuitNames[index]}.vkey.json`,
`${circuitNames[index]}.zkey`,
`${circuitNames[index]}_artifacts.json`,
`${circuitNames[index]}_js`,
]);
});
const ptauFullPath: string = getNormalizedFullPath(config.paths!.root!, "zkit/ptau");
expect(fsExtra.readdirSync(ptauFullPath)).to.be.deep.eq(["powers-of-tau-8.ptau"]);
const circuit = await zkit.getCircuit("Multiplier2");
await expect(circuit).with.witnessInputs({ in1: "3", in2: "7" }).to.have.witnessOutputs(["21"]);
const proof = await circuit.generateProof({ in1: "4", in2: "2" });
await expect(circuit).to.verifyProof(proof);
}
function updateInclude(filePath: string, newIncludePath: string) {
const fileContent = fsExtra.readFileSync(filePath, "utf-8");
const updatedContent = fileContent.replace(/include\s*".*";/, `include "${newIncludePath}";`);
fsExtra.writeFileSync(filePath, updatedContent, "utf-8");
}
describe("compile", async function () {
describe("no config compiler version", async function () {
useEnvironment("with-circuits", true);
it("should correctly compile circuits", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE });
const cacheFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "cache");
expect(fsExtra.readdirSync(cacheFullPath)).to.be.deep.eq(["circuits-compile-cache.json"]);
CircuitsCompileCache!.getEntries().forEach(async (entry: CompileCacheEntry) => {
expect(entry).to.be.deep.eq(await getCompileCacheEntry(this.hre.config.paths.root, entry.sourceName));
});
getZkitCircuitFullPaths(this.hre.config).forEach((path, index) => {
expect(fsExtra.readdirSync(path)).to.be.deep.eq([
`${circuitNames[index]}.r1cs`,
`${circuitNames[index]}.sym`,
`${circuitNames[index]}_artifacts.json`,
`${circuitNames[index]}_js`,
]);
});
});
it("should correctly compile circuits with task arguments", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE }, { json: true, c: true });
const cacheFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "cache");
expect(fsExtra.readdirSync(cacheFullPath)).to.be.deep.eq(["circuits-compile-cache.json"]);
CircuitsCompileCache!.getEntries().forEach(async (entry: CompileCacheEntry) => {
expect(entry).to.be.deep.eq(await getCompileCacheEntry(this.hre.config.paths.root, entry.sourceName));
});
getZkitCircuitFullPaths(this.hre.config).forEach((path, index) => {
expect(fsExtra.readdirSync(path)).to.be.deep.eq([
`${circuitNames[index]}.r1cs`,
`${circuitNames[index]}.sym`,
`${circuitNames[index]}_artifacts.json`,
`${circuitNames[index]}_constraints.json`,
`${circuitNames[index]}_cpp`,
`${circuitNames[index]}_js`,
]);
});
});
});
describe("config compiler version", async function () {
useEnvironment("compiler-config", true);
it("should correctly compile circuits with the specified version of the compiler", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE });
const artifactsPath = getNormalizedFullPath(
this.hre.config.paths.root,
`${this.hre.config.zkit!.compilationSettings!.artifactsDir}/circuits/main/mul2.circom`,
);
expect(fsExtra.readdirSync(artifactsPath)).to.be.deep.eq([
"Multiplier2.r1cs",
"Multiplier2.sym",
"Multiplier2_artifacts.json",
"Multiplier2_js",
]);
const compilerPath = path.join(os.homedir(), ".zkit", "compilers", this.hre.config.zkit.compilerVersion);
expect(fsExtra.readdirSync(compilerPath)).to.be.deep.equal([
CircomCompilerDownloader.getCompilerPlatformBinary(),
]);
});
});
describe("incorrect config compiler version", async function () {
useEnvironment("compiler-incorrect-config", true);
it("should throw an error when the specified config compiler version is lower that the circuit one", async function () {
await expect(this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE })).to.be.rejectedWith(
"Unable to compile a circuit with Circom version 2.1.9 using compiler version 2.1.8 specified in the config",
);
});
});
describe("with libraries", async function () {
describe("valid circuits", function () {
useEnvironment("circuits-with-libraries", true);
it("should correctly compile circuits that include libraries", async function () {
const root = this.hre.config.paths.root;
execSync("npm install --no-workspaces", { cwd: root });
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE });
const cacheFullPath: string = getNormalizedFullPath(root, "cache");
expect(fsExtra.readdirSync(cacheFullPath)).to.be.deep.eq(["circuits-compile-cache.json"]);
CircuitsCompileCache!.getEntries().forEach(async (entry: CompileCacheEntry) => {
expect(entry).to.be.deep.eq(await getCompileCacheEntry(root, entry.sourceName));
});
const circuitPath = getNormalizedFullPath(
root,
`${this.hre.config.zkit.compilationSettings.artifactsDir}/circuits/hash2.circom`,
);
expect(fsExtra.readdirSync(circuitPath)).to.be.deep.eq([
`Hash2.r1cs`,
`Hash2.sym`,
`Hash2_artifacts.json`,
`Hash2_js`,
]);
fsExtra.rmSync(`${root}/node_modules`, { recursive: true, force: true });
fsExtra.rmSync(`${root}/package-lock.json`, { recursive: true, force: true });
});
});
describe("invalid circuits", function () {
useEnvironment("invalid-circuits", true);
it("should throw an error if circuit include statement is URI", async function () {
const circuitPath = "circuits/invalidImportCircuit.circom";
const circuitFullPath = path.join(this.hre.config.paths.root, circuitPath);
const invalidImportPath = "http://example.com/circuit.circom";
updateInclude(circuitFullPath, invalidImportPath);
await expect(this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE })).to.be.rejectedWith(
`Invalid import ${invalidImportPath} from ${circuitPath}. Hardhat doesn't support imports via http`,
);
});
it("should throw an error if circuit include statement includes backslashes", async function () {
const circuitPath = "circuits/invalidImportCircuit.circom";
const circuitFullPath = path.join(this.hre.config.paths.root, circuitPath);
const invalidImportPath = "circomlib/circuits\\poseidon.circom";
updateInclude(circuitFullPath, invalidImportPath);
await expect(this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE })).to.be.rejectedWith(
`Invalid import ${invalidImportPath} from ${circuitPath}. Imports must use / instead of \\, even in Windows`,
);
});
it("should throw an error if circuit include statement is absolute path", async function () {
const circuitPath = "circuits/invalidImportCircuit.circom";
const circuitFullPath = path.join(this.hre.config.paths.root, circuitPath);
const invalidImportPath = "/absolute/path/to/circuit.circom";
updateInclude(circuitFullPath, invalidImportPath);
await expect(this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE })).to.be.rejectedWith(
` Invalid import ${invalidImportPath} from ${circuitPath}. Hardhat doesn't support imports with absolute paths.`,
);
});
});
});
});
describe("setup", async function () {
useEnvironment("with-circuits", true);
it("should not generate vkey, zkey files without compiled circuits", async function () {
cleanUp(this.hre.config.paths.root);
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_SETUP });
const cacheFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "cache");
expect(fsExtra.readdirSync(cacheFullPath)).to.be.deep.eq(["circuits-setup-cache.json"]);
expect(CircuitsSetupCache!.getEntries()).to.be.deep.eq([]);
});
it("should generate correct vkey, zkey files for compiled circuits", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE });
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_SETUP });
await checkMake(this.hre.config, this.hre.zkit);
});
});
describe("make", async function () {
useEnvironment("with-circuits", true);
it("should correctly compile circuits and generate vkey, zkey files", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_MAKE });
await checkMake(this.hre.config, this.hre.zkit);
});
});
describe("verifiers", async function () {
useEnvironment("with-circuits", true);
it("should correctly generate verifiers after running the verifiers task", async function () {
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS });
await checkMake(this.hre.config, this.hre.zkit);
const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers");
expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq(circuitNames.map((name) => `${name}Verifier.sol`));
});
});
describe("clean", async function () {
useEnvironment("with-circuits", true);
it("should correctly clean up the generated artifacts, types, etc", async function () {
expect(fsExtra.readdirSync(this.hre.config.paths.root)).to.be.deep.eq([
".gitignore",
"circuits",
"contracts",
"generated-types",
"hardhat.config.ts",
"package.json",
]);
expect(fsExtra.readdirSync(getNormalizedFullPath(this.hre.config.paths.root, "generated-types"))).to.be.deep.eq(
[],
);
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_MAKE });
const typesDir: string = getNormalizedFullPath(this.hre.config.paths.root, "generated-types");
const cacheDir: string = getNormalizedFullPath(this.hre.config.paths.root, "cache");
const zkitDir: string = getNormalizedFullPath(this.hre.config.paths.root, "zkit");
await checkMake(this.hre.config, this.hre.zkit);
await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_ZKIT_CLEAN });
expect(fsExtra.readdirSync(cacheDir)).to.be.deep.eq([]);
expect(fsExtra.readdirSync(typesDir)).to.be.deep.eq([]);
expect(fsExtra.readdirSync(zkitDir)).to.be.deep.eq(["ptau"]);
});
});
});

View File

@@ -2,57 +2,19 @@ import fsExtra from "fs-extra";
import { expect } from "chai";
import { useEnvironment } from "../../helpers";
import { CircuitsCompileCache, createCircuitsCompileCache, resetCircuitsCompileCache } from "../../../src/cache";
import { getNormalizedFullPath } from "../../../src/utils/path-utils";
import { CIRCUITS_COMPILE_CACHE_FILENAME, CIRCUIT_COMPILE_CACHE_VERSION } from "../../../src/constants";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "../../../src/task-names";
import { getFileHash } from "../../../src/utils/utils";
import { useEnvironment } from "@test-helpers";
import { getCompileCacheEntry } from "../../utils";
import { getFileHash } from "@src/utils/utils";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CompileFlags, ResolvedFileData } from "../../../src/types/core";
import { CompileCacheEntry } from "../../../src/types/cache";
import { CircomFilesParser } from "../../../src/core";
import { defaultCompileFlags } from "../../constants";
import { CompileCacheEntry } from "@src/types/cache";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "@src/task-names";
import { CIRCUITS_COMPILE_CACHE_FILENAME, CIRCUIT_COMPILE_CACHE_VERSION } from "@src/constants";
import { CircuitsCompileCache, createCircuitsCompileCache, resetCircuitsCompileCache } from "@src/cache";
describe("CircuitsCompileCache", () => {
const defaultCompileFlags: CompileFlags = {
r1cs: true,
wasm: true,
sym: true,
c: false,
json: false,
};
async function getCacheEntry(
projectRoot: string,
sourceName: string,
compileFlags: CompileFlags = defaultCompileFlags,
contentHash?: string,
): Promise<CompileCacheEntry> {
const circuitPath = getNormalizedFullPath(projectRoot, sourceName);
if (!contentHash) {
contentHash = getFileHash(circuitPath);
}
const parser: CircomFilesParser = new CircomFilesParser();
const fileData: ResolvedFileData = parser.parse(
fsExtra.readFileSync(circuitPath, "utf-8"),
circuitPath,
contentHash,
);
const stats = await fsExtra.stat(circuitPath);
const lastModificationDate: Date = new Date(stats.ctime);
return {
sourceName,
contentHash,
lastModificationDate: lastModificationDate.valueOf(),
compileFlags,
fileData,
};
}
describe("createEmpty", () => {
it("should correctly create empty CircuitsCompileCache instance", async () => {
resetCircuitsCompileCache();
@@ -69,7 +31,7 @@ describe("CircuitsCompileCache", () => {
it("should correctly create CircuitsCompileCache instance from file", async function () {
CircuitsCompileCache!.getEntries().forEach(async (entry: CompileCacheEntry) => {
expect(entry).to.be.deep.eq(await getCacheEntry(this.hre.config.paths.root, entry.sourceName));
expect(entry).to.be.deep.eq(await getCompileCacheEntry(this.hre.config.paths.root, entry.sourceName));
});
});

View File

@@ -2,41 +2,20 @@ import fsExtra from "fs-extra";
import { expect } from "chai";
import { TASK_CIRCUITS_MAKE, ZKIT_SCOPE_NAME } from "../../../src/task-names";
import { useEnvironment } from "../../helpers";
import { CircuitsSetupCache, createCircuitsSetupCache, resetCircuitsSetupCache } from "../../../src/cache";
import { getNormalizedFullPath } from "../../../src/utils/path-utils";
import { CIRCUITS_SETUP_CACHE_FILENAME, CIRCUIT_SETUP_CACHE_VERSION } from "../../../src/constants";
import { getFileHash } from "../../../src/utils/utils";
import { useEnvironment } from "@test-helpers";
import { getSetupCacheEntry } from "../../utils";
import { getFileHash } from "@src/utils/utils";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { ContributionSettings } from "../../../src/types/core";
import { SetupCacheEntry } from "../../../src/types/cache";
import { CircuitArtifact } from "../../../src/types/artifacts/circuit-artifacts";
import { defaultContributionSettings } from "../../constants";
import { SetupCacheEntry } from "@src/types/cache";
import { CircuitArtifact } from "@src/types/artifacts/circuit-artifacts";
import { TASK_CIRCUITS_MAKE, ZKIT_SCOPE_NAME } from "@src/task-names";
import { CIRCUITS_SETUP_CACHE_FILENAME, CIRCUIT_SETUP_CACHE_VERSION } from "@src/constants";
import { CircuitsSetupCache, createCircuitsSetupCache, resetCircuitsSetupCache } from "@src/cache";
describe("CircuitsSetupCache", () => {
const defaultContributionSettings: ContributionSettings = {
provingSystem: "groth16",
contributions: 1,
};
async function getCacheEntry(
sourceName: string,
r1csSourcePath: string,
contributionSettings: ContributionSettings = defaultContributionSettings,
r1csContentHash?: string,
): Promise<SetupCacheEntry> {
if (!r1csContentHash) {
r1csContentHash = getFileHash(r1csSourcePath);
}
return {
circuitSourceName: sourceName,
r1csSourcePath,
r1csContentHash,
contributionSettings,
};
}
describe("createEmpty", () => {
it("should correctly create empty CircuitsSetupCache instance", async () => {
resetCircuitsSetupCache();
@@ -53,7 +32,7 @@ describe("CircuitsSetupCache", () => {
it("should correctly create CircuitsSetupCache instance from file", async function () {
CircuitsSetupCache!.getEntries().forEach(async (entry: SetupCacheEntry) => {
expect(entry).to.be.deep.eq(await getCacheEntry(entry.circuitSourceName, entry.r1csSourcePath));
expect(entry).to.be.deep.eq(await getSetupCacheEntry(entry.circuitSourceName, entry.r1csSourcePath));
});
});

View File

@@ -1,63 +0,0 @@
import fsExtra from "fs-extra";
import { expect } from "chai";
import { useEnvironment } from "../../../helpers";
import { CircomCompilerFactory, createCircomCompilerFactory } from "../../../../src/core";
import { getNormalizedFullPath } from "../../../../src/utils/path-utils";
import { CompileFlags, ICircomCompiler } from "../../../../src/types/core";
describe("CircomCompilerFactory", () => {
const defaultCompileFlags: CompileFlags = {
r1cs: true,
wasm: true,
c: false,
json: false,
sym: false,
};
describe("createCircomCompiler", () => {
useEnvironment("with-circuits");
it("should correctly create circom compiler instance", async function () {
createCircomCompilerFactory();
const compiler: ICircomCompiler = await CircomCompilerFactory!.createCircomCompiler("0.2.18", false);
const circuitFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "circuits/main/mul2.circom");
const artifactsFullPath: string = getNormalizedFullPath(
this.hre.config.paths.root,
"zkit/artifacts/test/mul2.circom",
);
const errorFileFullPath: string = getNormalizedFullPath(artifactsFullPath, "errors.log");
const typesDir: string = getNormalizedFullPath(this.hre.config.paths.root, "generated-types/zkit");
fsExtra.rmSync(artifactsFullPath, { recursive: true, force: true });
fsExtra.mkdirSync(artifactsFullPath, { recursive: true });
await compiler.compile({
circuitFullPath,
artifactsFullPath,
errorFileFullPath,
linkLibraries: [],
compileFlags: { ...defaultCompileFlags, sym: true },
quiet: true,
});
fsExtra.rmSync(errorFileFullPath, { force: true });
expect(fsExtra.readdirSync(artifactsFullPath)).to.be.deep.eq(["mul2.r1cs", "mul2.sym", "mul2_js"]);
fsExtra.rmSync(typesDir, { recursive: true, force: true });
});
it("should correctly throw error if pass invalid version", async function () {
const invalidVersion = "2.1.10";
const reason = `Unsupported Circom compiler version - ${invalidVersion}. Please provide another version.`;
createCircomCompilerFactory();
await expect(CircomCompilerFactory!.createCircomCompiler(invalidVersion, false)).to.be.rejectedWith(reason);
});
});
});

View File

@@ -1,5 +1,5 @@
import { CircomFilesResolver, CompilationFilesResolver, DependencyGraph } from "../../../../src/core";
import { CompileFlags, CircomResolvedFileInfo, CircomResolvedFile } from "../../../../src/types/core";
import { CircomFilesResolver, CompilationFilesResolver, DependencyGraph } from "@src/core";
import { CompileFlags, CircomResolvedFileInfo, CircomResolvedFile } from "@src/types/core";
export class CompilationFilesResolverMock extends CompilationFilesResolver {
public filterResolvedFiles(

View File

@@ -0,0 +1,199 @@
import os from "os";
import fsExtra from "fs-extra";
import { spy } from "sinon";
import { expect } from "chai";
import { cleanUp, useEnvironment } from "@test-helpers";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CompilerPlatformBinary } from "@src/types/core";
import { createReporter, Reporter } from "@src/reporter";
import { LATEST_SUPPORTED_CIRCOM_VERSION } from "@src/constants";
import { CircomCompilerDownloader } from "@src/core/compiler/CircomCompilerDownloader";
describe("CircomCompilerDownloader", () => {
createReporter(true);
describe("isCompilerDownloaded", () => {
useEnvironment("with-circuits");
it("should correctly identify whether the latest compatible compiler is downloaded", async function () {
cleanUp(this.hre.config.paths.root);
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CircomCompilerDownloader.getCompilerPlatformBinary(),
compilersDir,
);
expect(await circomCompilerDownloader.isCompilerDownloaded("2.1.1", false)).to.be.false;
await circomCompilerDownloader.downloadCompiler("2.1.1", false, true);
expect(await circomCompilerDownloader.isCompilerDownloaded("2.1.1", false)).to.be.true;
});
it("should correctly identify whether the specific compiler version is downloaded", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CompilerPlatformBinary.WASM,
compilersDir,
);
expect(await circomCompilerDownloader.isCompilerDownloaded("2.1.8", true)).to.be.false;
await circomCompilerDownloader.downloadCompiler("2.1.8", true, true);
expect(await circomCompilerDownloader.isCompilerDownloaded("2.1.8", true)).to.be.true;
});
});
describe("getCompilerBinary", () => {
useEnvironment("with-circuits");
it("should return a correct compiler binary path", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const platform = CircomCompilerDownloader.getCompilerPlatformBinary();
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(platform, compilersDir);
expect(await circomCompilerDownloader.getCompilerBinary("2.0.0", false)).to.be.deep.equal({
binaryPath: `${compilersDir}/${LATEST_SUPPORTED_CIRCOM_VERSION}/${platform}`,
version: LATEST_SUPPORTED_CIRCOM_VERSION,
isWasm: false,
});
});
it("should return a correct specific version compiler binary path", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const platform = CompilerPlatformBinary.WASM;
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(platform, compilersDir);
expect(await circomCompilerDownloader.getCompilerBinary("2.1.8", true)).to.be.deep.equal({
binaryPath: `${compilersDir}/2.1.8/${platform}`,
version: "2.1.8",
isWasm: true,
});
});
it("should throw an error if the correct compiler is not downloaded", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CircomCompilerDownloader.getCompilerPlatformBinary(),
compilersDir,
);
await expect(circomCompilerDownloader.getCompilerBinary("2.1.7", true)).to.be.rejectedWith(
"Trying to get a Circom compiler v2.1.7 before it was downloaded",
);
});
it("should throw an error if no latest compiler is found", async function () {
cleanUp(this.hre.config.paths.root);
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CircomCompilerDownloader.getCompilerPlatformBinary(),
compilersDir,
);
await expect(circomCompilerDownloader.getCompilerBinary("2.1.6", false)).to.be.rejectedWith(
"No latest compiler found",
);
});
});
describe("downloadCompiler", () => {
useEnvironment("with-circuits", true);
it("should download the latest available compiler properly", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const platform = CircomCompilerDownloader.getCompilerPlatformBinary();
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(platform, compilersDir);
await circomCompilerDownloader.downloadCompiler("2.0.0", false, true);
expect(fsExtra.readdirSync(`${compilersDir}/${LATEST_SUPPORTED_CIRCOM_VERSION}`)).to.be.deep.equal([platform]);
expect(await circomCompilerDownloader.isCompilerDownloaded(LATEST_SUPPORTED_CIRCOM_VERSION, true)).to.be.true;
});
it("should download the specific compiler version properly", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const platform = CompilerPlatformBinary.WASM;
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(platform, compilersDir);
await circomCompilerDownloader.downloadCompiler("2.1.8", true, true);
expect(fsExtra.readdirSync(`${compilersDir}/2.1.8`)).to.be.deep.equal([platform]);
expect(await circomCompilerDownloader.isCompilerDownloaded("2.1.8", true)).to.be.true;
});
it("should return without downloading if the needed compiler is downloaded", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CircomCompilerDownloader.getCompilerPlatformBinary(),
compilersDir,
);
await circomCompilerDownloader.downloadCompiler("2.1.9", true, true);
const reporterSpy = spy(Reporter!, "reportCircomCompilerDownloadingInfo");
await circomCompilerDownloader.downloadCompiler("2.1.9", true, true);
expect(reporterSpy.called).to.be.false;
});
it("should throw an error if the downloaded compiler is not working", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const targetPlatform =
os.platform() === "win32" ? CompilerPlatformBinary.MACOS_ARM : CompilerPlatformBinary.WINDOWS_ARM;
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
targetPlatform,
compilersDir,
);
await expect(circomCompilerDownloader.downloadCompiler("2.0.0", false, true)).to.be.rejectedWith(
"Downloaded compiler is not working",
);
});
it("should throw an error if compiler downloading was not successful", async function () {
const compilersDir = getNormalizedFullPath(this.hre.config.paths.root, "compilers");
await fsExtra.ensureDir(compilersDir);
const circomCompilerDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CompilerPlatformBinary.MACOS_ARM,
compilersDir,
);
await expect(circomCompilerDownloader.downloadCompiler("2.1.8", true, true)).to.be.rejectedWith(
"Failed to download Circom compiler v2.1.8. Please try again or download manually.",
);
});
});
});

View File

@@ -0,0 +1,209 @@
import os from "os";
import path from "path";
import fsExtra from "fs-extra";
import { expect } from "chai";
import { before } from "mocha";
import { stub, SinonStub } from "sinon";
import { useEnvironment } from "@test-helpers";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CompilerPlatformBinary, ICircomCompiler } from "@src/types/core";
import {
BaseCircomCompilerFactory,
BinaryCircomCompiler,
CircomCompilerFactory,
createCircomCompilerFactory,
WASMCircomCompiler,
} from "@src/core";
import { CircomCompilerDownloader } from "@src/core/compiler/CircomCompilerDownloader";
import { defaultCompileFlags } from "../../../../constants";
import { LATEST_SUPPORTED_CIRCOM_VERSION } from "@src/constants";
describe("CircomCompilerFactory", () => {
let nativeCompilerStub: SinonStub;
before(() => {
nativeCompilerStub = stub(BaseCircomCompilerFactory.prototype, "_tryCreateNativeCompiler" as any).callsFake(
async () => {
return undefined;
},
);
});
after(() => {
nativeCompilerStub.restore();
});
async function checkPlatformSpecificCompiler(osType: NodeJS.Platform) {
const compilerDir = path.join(os.homedir(), ".zkit", "compilers", LATEST_SUPPORTED_CIRCOM_VERSION);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
const platformStub = stub(os, "platform").callsFake(() => {
return osType;
});
const compiler = await CircomCompilerFactory!.createCircomCompiler("2.0.0", false, false);
const platform = CircomCompilerDownloader.getCompilerPlatformBinary();
if (platform === CompilerPlatformBinary.WASM) {
expect(compiler).to.be.instanceof(WASMCircomCompiler);
} else {
expect(compiler).to.be.instanceof(BinaryCircomCompiler);
}
expect(fsExtra.readdirSync(compilerDir)).to.be.deep.equal([platform]);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
platformStub.restore();
}
describe("createCircomCompiler", () => {
useEnvironment("with-circuits");
it("should correctly create circom compiler instance", async function () {
createCircomCompilerFactory();
const compiler: ICircomCompiler = await CircomCompilerFactory!.createCircomCompiler("0.2.18", false);
const circuitFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "circuits/main/mul2.circom");
const artifactsFullPath: string = getNormalizedFullPath(
this.hre.config.paths.root,
"zkit/artifacts/test/mul2.circom",
);
const errorFileFullPath: string = getNormalizedFullPath(artifactsFullPath, "errors.log");
const typesDir: string = getNormalizedFullPath(this.hre.config.paths.root, "generated-types/zkit");
fsExtra.rmSync(artifactsFullPath, { recursive: true, force: true });
fsExtra.mkdirSync(artifactsFullPath, { recursive: true });
await compiler.compile({
circuitFullPath,
artifactsFullPath,
errorFileFullPath,
linkLibraries: [],
compileFlags: { ...defaultCompileFlags, sym: true },
quiet: true,
});
fsExtra.rmSync(errorFileFullPath, { force: true });
expect(fsExtra.readdirSync(artifactsFullPath)).to.be.deep.eq(["mul2.r1cs", "mul2.sym", "mul2_js"]);
fsExtra.rmSync(typesDir, { recursive: true, force: true });
});
it("should correctly throw error if pass invalid version", async function () {
const invalidVersion = "2.1.10";
const reason = `Unsupported Circom compiler version - ${invalidVersion}. Please provide another version.`;
createCircomCompilerFactory();
await expect(CircomCompilerFactory!.createCircomCompiler(invalidVersion, false)).to.be.rejectedWith(reason);
});
it("should create compiler for each platform properly", async function () {
let archStub = stub(os, "arch").callsFake(() => {
return "x64";
});
await checkPlatformSpecificCompiler("linux");
await checkPlatformSpecificCompiler("darwin");
await checkPlatformSpecificCompiler("win32");
await checkPlatformSpecificCompiler("freebsd");
archStub.restore();
archStub = stub(os, "arch").callsFake(() => {
return "arm64";
});
await checkPlatformSpecificCompiler("linux");
await checkPlatformSpecificCompiler("darwin");
await checkPlatformSpecificCompiler("win32");
archStub.restore();
archStub = stub(os, "arch").callsFake(() => {
return "mips";
});
await checkPlatformSpecificCompiler("linux");
archStub.restore();
});
it("should create amd compiler if arm compiler with specific version is unavailable", async function () {
const archStub = stub(os, "arch").callsFake(() => {
return "arm64";
});
const platformStub = stub(os, "platform").callsFake(() => {
return "darwin";
});
const compilerDir = path.join(os.homedir(), ".zkit", "compilers", "2.1.7");
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
const compiler = await CircomCompilerFactory!.createCircomCompiler("2.1.7", true, false);
const platform = CompilerPlatformBinary.MACOS_AMD;
expect(compiler).to.be.instanceof(BinaryCircomCompiler);
expect(fsExtra.readdirSync(compilerDir)).to.be.deep.equal([platform]);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
platformStub.restore();
archStub.restore();
});
it("should create wasm compiler if the downloaded platform compiler is not working", async function () {
const archStub = stub(os, "arch").callsFake(() => {
return "arm64";
});
const mockPlatform = os.platform() === "win32" ? "darwin" : "win32";
const platformStub = stub(os, "platform").callsFake(() => mockPlatform);
const compilerDir = path.join(os.homedir(), ".zkit", "compilers", LATEST_SUPPORTED_CIRCOM_VERSION);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
const compiler = await CircomCompilerFactory!.createCircomCompiler("2.0.0", false, true);
const platform = CompilerPlatformBinary.WASM;
expect(compiler).to.be.instanceof(WASMCircomCompiler);
expect(fsExtra.readdirSync(compilerDir)).to.be.deep.equal([platform]);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
platformStub.restore();
archStub.restore();
});
it("should not download a platform compiler if there already is a wasm one", async function () {
createCircomCompilerFactory();
const compilerDir = path.join(os.homedir(), ".zkit", "compilers");
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
const wasmDownloader = CircomCompilerDownloader.getCircomCompilerDownloader(
CompilerPlatformBinary.WASM,
compilerDir,
);
await wasmDownloader.downloadCompiler(LATEST_SUPPORTED_CIRCOM_VERSION, true, true);
const platformStub = stub(os, "platform").callsFake(() => {
return "darwin";
});
const compiler = await CircomCompilerFactory!.createCircomCompiler(LATEST_SUPPORTED_CIRCOM_VERSION, true, false);
const platform = CompilerPlatformBinary.WASM;
expect(compiler).to.be.instanceof(WASMCircomCompiler);
expect(fsExtra.readdirSync(`${compilerDir}/${LATEST_SUPPORTED_CIRCOM_VERSION}`)).to.be.deep.equal([platform]);
fsExtra.rmSync(compilerDir, { recursive: true, force: true });
platformStub.restore();
});
});
});

View File

@@ -2,12 +2,12 @@ import fsExtra from "fs-extra";
import { expect } from "chai";
import { getProjectRootPath, useEnvironment } from "../../../helpers";
import { getNormalizedFullPath } from "../../../../src/utils/path-utils";
import { WASMCircomCompiler } from "../../../../src/core";
import { NODE_MODULES } from "../../../../src/constants";
import { getProjectRootPath, useEnvironment } from "@test-helpers";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CircomCompilerFactory, createCircomCompilerFactory, WASMCircomCompiler } from "@src/core";
import { CompileFlags } from "../../../../src/types/core";
import { NODE_MODULES } from "@src/constants";
import { CompileFlags } from "@src/types/core";
describe("WASMCircomCompiler", () => {
const defaultCompileFlags: CompileFlags = {
@@ -68,18 +68,33 @@ describe("WASMCircomCompiler", () => {
);
const errorFileFullPath: string = getNormalizedFullPath(artifactsFullPath, "errors.log");
const compilationArgs = {
circuitFullPath,
artifactsFullPath,
errorFileFullPath,
linkLibraries: [],
compileFlags: defaultCompileFlags,
quiet: true,
};
const reason: string = "Compilation failed.\nHardhatZKitError: Error during compiler execution. Exit code: 1.";
await expect(
circomCompiler.compile({
circuitFullPath,
artifactsFullPath,
errorFileFullPath,
linkLibraries: [],
compileFlags: defaultCompileFlags,
quiet: true,
}),
).to.be.rejectedWith(reason);
await expect(circomCompiler.compile(compilationArgs)).to.be.rejectedWith(reason);
createCircomCompilerFactory();
const platformCompiler = await CircomCompilerFactory!.createCircomCompiler("2.0.0", false);
await expect(platformCompiler.compile(compilationArgs)).to.be.rejected;
try {
await platformCompiler.compile(compilationArgs);
} catch (error: any) {
const message = error.message;
expect(message).to.include("Compilation failed.");
expect(message).to.include("Command failed");
expect(message).to.include("No main specified in the project structure");
}
});
it("should correctly throw error with quiet=false", async function () {
@@ -123,7 +138,7 @@ describe("WASMCircomCompiler", () => {
);
});
it("should correctly compile circuit with library inclue", async function () {
it("should correctly compile circuit with library include", async function () {
const circuitFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "circuits/hash2.circom");
const artifactsFullPath: string = getNormalizedFullPath(
this.hre.config.paths.root,

View File

@@ -7,14 +7,14 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { getAllFilesMatching } from "hardhat/internal/util/fs-utils";
import { CompilationFilesResolverMock } from "./CompilationFilesResolverMock";
import { useEnvironment } from "../../../helpers";
import { CircuitsCompileCache } from "../../../../src/cache";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "../../../../src/task-names";
import { DependencyGraph, CircomFilesResolver, CircomFilesParser } from "../../../../src/core";
import { getNormalizedFullPath } from "../../../../src/utils/path-utils";
import { CIRCUITS_COMPILE_CACHE_FILENAME } from "../../../../src/constants";
import { useEnvironment } from "@test-helpers";
import { CircuitsCompileCache } from "@src/cache";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "@src/task-names";
import { DependencyGraph, CircomFilesResolver, CircomFilesParser } from "@src/core";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CIRCUITS_COMPILE_CACHE_FILENAME } from "@src/constants";
import { CircomResolvedFileInfo, CircomResolvedFile } from "../../../../src/types/core";
import { CircomResolvedFileInfo, CircomResolvedFile } from "@src/types/core";
describe("CompilationFilesResolver", () => {
function getCompilationFilesManagerMock(hre: HardhatRuntimeEnvironment): CompilationFilesResolverMock {

View File

@@ -3,15 +3,15 @@ import { expect } from "chai";
import { createNonCryptographicHashBasedIdentifier } from "hardhat/internal/util/hash";
import { useEnvironment } from "../../../helpers";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "../../../../src/task-names";
import { CircomFilesParser } from "../../../../src/core/dependencies";
import { getNormalizedFullPath } from "../../../../src/utils/path-utils";
import { CIRCUITS_COMPILE_CACHE_FILENAME } from "../../../../src/constants";
import { createCircuitsCompileCache } from "../../../../src/cache";
import { createReporter } from "../../../../src/reporter";
import { useEnvironment } from "@test-helpers";
import { CircomFilesParser } from "@src/core";
import { TASK_CIRCUITS_COMPILE, ZKIT_SCOPE_NAME } from "@src/task-names";
import { getNormalizedFullPath } from "@src/utils/path-utils";
import { CIRCUITS_COMPILE_CACHE_FILENAME } from "@src/constants";
import { createCircuitsCompileCache } from "@src/cache";
import { createReporter } from "@src/reporter";
import { ResolvedFileData } from "../../../../src/types/core";
import { ResolvedFileData } from "@src/types/core";
describe("CircomFilesParser", () => {
describe("parse", () => {

View File

@@ -0,0 +1,33 @@
import fsExtra from "fs-extra";
import { expect } from "chai";
import { PtauDownloader } from "@src/core";
import { useEnvironment } from "@test-helpers";
describe("PtauDownloader", () => {
describe("downloadPtau", () => {
useEnvironment("with-circuits", true);
it("should download ptau file correctly", async function () {
const ptauPath = this.hre.config.zkit.setupSettings.ptauDir;
await PtauDownloader.downloadPtau(ptauPath, 16);
expect(fsExtra.readdirSync(ptauPath)).to.be.deep.eq(["powers-of-tau-16.ptau"]);
});
it("should throw an error if ptauId is too big", async function () {
const maxPtauId = PtauDownloader.getMaxPtauID();
await expect(
PtauDownloader.downloadPtau(this.hre.config.zkit.setupSettings.ptauDir, maxPtauId + 1),
).to.be.rejectedWith(
`Circuits has too many constraints. The maximum ptauId to download is ${maxPtauId}. Consider passing "ptauDir=PATH_TO_LOCAL_DIR" with existing ptau files.`,
);
});
it("should throw an error if ptauId is less than 8", async function () {
await expect(PtauDownloader.downloadPtau(this.hre.config.zkit.setupSettings.ptauDir, 0)).to.be.rejectedWith(
"Failed to download a Ptau file. Please try again or download manually.",
);
});
});
});

View File

@@ -0,0 +1,27 @@
import { expect } from "chai";
import { getHighestVersion, isVersionValid } from "@src/core/compiler/versioning";
describe("Versioning", () => {
describe("isVersionValid", () => {
it("should correctly identify whether circom version is correct", async function () {
expect(isVersionValid("2.1.9")).to.be.true;
expect(isVersionValid("2.0.0")).to.be.true;
expect(isVersionValid("")).to.be.false;
expect(isVersionValid("1")).to.be.false;
expect(isVersionValid("2.1")).to.be.false;
expect(isVersionValid("2.a.1")).to.be.false;
expect(isVersionValid("2.1.b")).to.be.false;
expect(isVersionValid("^2.1.3")).to.be.false;
});
});
describe("getHighestVersion", () => {
it("should correctly get the highest version", async function () {
expect(getHighestVersion(["2.1.9", "0.1.1", "2.1.9", "2.0.0", "2.1.8"])).to.be.equal("2.1.9");
expect(getHighestVersion(["2.0.0", "2.0.0"])).to.be.equal("2.0.0");
expect(getHighestVersion([])).to.be.equal("0.0.0");
});
});
});

54
test/utils.ts Normal file
View File

@@ -0,0 +1,54 @@
import fsExtra from "fs-extra";
import { CircomFilesParser } from "../src/core";
import { getFileHash } from "../src/utils/utils";
import { getNormalizedFullPath } from "../src/utils/path-utils";
import { CompileCacheEntry, SetupCacheEntry } from "../src/types/cache";
import { CompileFlags, ContributionSettings, ResolvedFileData } from "../src/types/core";
import { defaultCompileFlags, defaultContributionSettings } from "./constants";
export async function getCompileCacheEntry(
projectRoot: string,
sourceName: string,
compileFlags: CompileFlags = defaultCompileFlags,
contentHash?: string,
): Promise<CompileCacheEntry> {
const circuitPath = getNormalizedFullPath(projectRoot, sourceName);
if (!contentHash) {
contentHash = getFileHash(circuitPath);
}
const parser: CircomFilesParser = new CircomFilesParser();
const fileData: ResolvedFileData = parser.parse(fsExtra.readFileSync(circuitPath, "utf-8"), circuitPath, contentHash);
const stats = await fsExtra.stat(circuitPath);
const lastModificationDate: Date = new Date(stats.ctime);
return {
sourceName,
contentHash,
lastModificationDate: lastModificationDate.valueOf(),
compileFlags,
fileData,
};
}
export async function getSetupCacheEntry(
sourceName: string,
r1csSourcePath: string,
contributionSettings: ContributionSettings = defaultContributionSettings,
r1csContentHash?: string,
): Promise<SetupCacheEntry> {
if (!r1csContentHash) {
r1csContentHash = getFileHash(r1csSourcePath);
}
return {
circuitSourceName: sourceName,
r1csSourcePath,
r1csContentHash,
contributionSettings,
};
}

View File

@@ -1,4 +1,7 @@
{
"ts-node": {
"require": ["tsconfig-paths/register"]
},
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
@@ -14,7 +17,11 @@
"experimentalDecorators": true,
"types": [
"@nomicfoundation/hardhat-ethers"
]
],
"paths": {
"@src/*": ["./src/*"],
"@test-helpers": ["./test/helpers"]
}
},
"exclude": [
"./dist",