circuitscan
Advanced tools
Comparing version
15
cli.js
@@ -5,3 +5,8 @@ #!/usr/bin/env node | ||
import {verify, deploy} from './index.js'; | ||
import {instanceSizes} from './src/utils.js'; | ||
import { | ||
instanceSizes, | ||
getPackageJson, | ||
formatBytes, | ||
MAX_POST_SIZE, | ||
} from './src/utils.js'; | ||
@@ -13,3 +18,3 @@ const program = new Command(); | ||
.description('CLI tool to verify verifier contracts by their circom sources') | ||
.version('0.0.1'); | ||
.version(getPackageJson().version); | ||
@@ -20,5 +25,6 @@ program | ||
.option('-p, --protocol <protocol>', 'Specify the protocol: groth16 (default), fflonk, plonk (overrides circomkit.json if available)') | ||
.option('-k, --proving-key <provingKey>', 'Specify the proving key url (optional, for Groth16 trusted setups)') | ||
.option('-k, --proving-key <provingKey>', `Specify the proving key filename or url (optional, for Groth16 trusted setups). Must be https hosted if >${formatBytes(MAX_POST_SIZE)}`) | ||
.option('-v, --circom-version <circomVersion>', 'Specify the Circom version (e.g. "v2.1.8")') | ||
.option('-i, --instance <memorySize>', `Specify the memory (GB) of compiler instance: ${Object.keys(instanceSizes).join(', ')} (default: 10GB lambda, faster init for small circuits)`) | ||
.option('-r, --resume <requestId>', 'In case of errors during compilation, reattach to a job and attempt a new deploy. Overrides all other options.') | ||
.action(verify); | ||
@@ -31,7 +37,8 @@ | ||
.option('-p, --protocol <protocol>', 'Specify the protocol: groth16 (default), fflonk, plonk (overrides circomkit.json if available)') | ||
.option('-k, --proving-key <provingKey>', 'Specify the proving key url (optional, for Groth16 trusted setups)') | ||
.option('-k, --proving-key <provingKey>', `Specify the proving key filename or url (optional, for Groth16 trusted setups). Must be https hosted if >${formatBytes(MAX_POST_SIZE)}`) | ||
.option('-v, --circom-version <circomVersion>', 'Specify the Circom version (e.g. "v2.1.8")') | ||
.option('-i, --instance <memorySize>', `Specify the memory (GB) of compiler instance: ${Object.keys(instanceSizes).join(', ')} (default: 10GB lambda, faster init for small circuits)`) | ||
.option('-r, --resume <requestId>', 'In case of errors during compilation, reattach to a job and attempt a new deploy. Overrides all other options.') | ||
.action(deploy); | ||
program.parse(process.argv); |
33
index.js
@@ -6,3 +6,9 @@ import {relative, dirname} from 'node:path'; | ||
import {findChain} from './src/chains.js'; | ||
import {generateRandomString, fetchJson, delay, instanceSizes} from './src/utils.js'; | ||
import { | ||
generateRandomString, | ||
fetchJson, | ||
delay, | ||
instanceSizes, | ||
prepareProvingKey, | ||
} from './src/utils.js'; | ||
import {StatusLogger} from './src/StatusLogger.js'; | ||
@@ -75,3 +81,19 @@ import { | ||
} | ||
async function resumeCompileFile(options) { | ||
const requestId = options.resume; | ||
if('instance' in options && !(options.instance in instanceSizes)) | ||
throw new Error('INVALID_INSTANCE_SIZE'); | ||
// status report during compilation | ||
const status = new StatusLogger(`${blobUrl}status/${requestId}.json`, 3000, Number(options.instance || 10)); | ||
while(!status.lastData || !status.lastData.find(x => x.msg === 'Complete.')) { | ||
await delay(5000); | ||
} | ||
status.stop(); | ||
return { pkgName: status.lastData[0].msg.slice(10, -3) }; | ||
} | ||
async function compileFile(file, options, {curCompilerURL}) { | ||
if(options.resume) return resumeCompileFile(options); | ||
const loaded = loadCircom(file); | ||
@@ -95,7 +117,7 @@ const shortFile = Object.keys(loaded.files)[0]; | ||
console.log(`# Request ID: ${requestId}`); | ||
// status report during compilation | ||
const status = new StatusLogger(`${blobUrl}status/${requestId}.json`, 3000, Number(options.instance || 10)); | ||
if('instance' in options && !(options.instance in instanceSizes)) | ||
throw new Error('INVALID_INSTANCE_SIZE'); | ||
const instanceType = options.instance ? instanceSizes[options.instance] : undefined; | ||
// status report during compilation | ||
const status = new StatusLogger(`${blobUrl}status/${requestId}.json`, 3000, Number(options.instance || 10)); | ||
@@ -108,4 +130,3 @@ const event = { | ||
files, | ||
// TODO support passing filename for base64 if small enough or temp upload otherwise | ||
finalZkey: options.provingKey, | ||
finalZkey: prepareProvingKey(options.provingKey), | ||
// TODO support custom snarkjs version | ||
@@ -144,3 +165,3 @@ snarkjsVersion: undefined, | ||
if(data.status === 'ok' && !('pkgName' in body)) { | ||
if(data.status === 'ok' && instanceType) { | ||
console.log('# Instance started. Wait a few minutes for initialization...'); | ||
@@ -147,0 +168,0 @@ while(!status.lastData || !status.lastData.find(x => x.msg === 'Complete.')) { |
{ | ||
"name": "circuitscan", | ||
"version": "0.0.6-alpha", | ||
"version": "0.0.7-alpha", | ||
"main": "index.js", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -19,2 +19,5 @@ # Circuitscan CLI | ||
> [!TIP] | ||
> Close a running compiler job, then use `--resume` later complete verification or deployment. Alternatively, use `--resume` to duplicate a verifier, avoiding waiting for the circuit to compile again. | ||
### verify | ||
@@ -29,6 +32,6 @@ | ||
-p, --protocol <protocol> Specify the protocol: groth16 (default), fflonk, plonk (overrides circomkit.json if available) | ||
-k, --proving-key <provingKey> Specify the proving key url (optional, for Groth16 trusted setups) | ||
-k, --proving-key <provingKey> Specify the proving key filename or url (optional, for Groth16 trusted setups). Must be https hosted if >6 MB | ||
-v, --circom-version <circomVersion> Specify the Circom version (e.g. "v2.1.8") | ||
-i, --instance <memorySize> Specify the memory (GB) of compiler instance: 4 for testing (default: 10GB lambda, faster init for small circuits) | ||
-l, --localhost <localPort> Use a circom compiler container running on a specific port | ||
-i, --instance <memorySize> Specify the memory (GB) of compiler instance: 4, 8, 16, 32, 64, 128, 256, 384, 512 (default: 10GB lambda, faster init for small circuits) | ||
-r, --resume <requestId> In case of errors during compilation, reattach to a job and attempt a new verification. Overrides all other options. | ||
-h, --help display help for command | ||
@@ -42,5 +45,2 @@ | ||
> [!NOTE] | ||
> [TODO: must be hosted on public https server](https://github.com/circuitscan/cli/blob/main/index.js#L131) | ||
``` | ||
@@ -84,6 +84,6 @@ $ circuitscan verify -k https://circuitscan-blobs.clonk.me/test-semaphore.zkey ~/semaphore/packages/circuits/src/main/semaphore.circom sepolia 0x73885e40715F6D77C4Ab2863756e4ee523f3be15 | ||
-p, --protocol <protocol> Specify the protocol: groth16 (default), fflonk, plonk (overrides circomkit.json if available) | ||
-k, --proving-key <provingKey> Specify the proving key url (optional, for Groth16 trusted setups) | ||
-k, --proving-key <provingKey> Specify the proving key filename or url (optional, for Groth16 trusted setups). Must be https hosted if >6 MB | ||
-v, --circom-version <circomVersion> Specify the Circom version (e.g. "v2.1.8") | ||
-i, --instance <memorySize> Specify the memory (GB) of compiler instance: 4 for testing (default: 10GB lambda, faster init for small circuits) | ||
-l, --localhost <localPort> Use a circom compiler container running on a specific port | ||
-i, --instance <memorySize> Specify the memory (GB) of compiler instance: 4, 8, 16, 32, 64, 128, 256, 384, 512 (default: 10GB lambda, faster init for small circuits) | ||
-r, --resume <requestId> In case of errors during compilation, reattach to a job and attempt a new deploy. Overrides all other options. | ||
-h, --help display help for command | ||
@@ -93,2 +93,7 @@ | ||
> [!TIP] | ||
> If there's a timeout waiting for a contract deployment transaction, wait for the transaction to be included on chain then use the `verify` command passing the new contract address. | ||
> | ||
> The contract will have to be verified manually on Etherscan. Find the contract source at `https://circuitscan-blob.s3.us-west-2.amazonaws.com/build/<build-name-adjective-animal>/verifier.sol` | ||
> [!IMPORTANT] | ||
@@ -95,0 +100,0 @@ > `DEPLOYER_PRIVATE_KEY` environment variable and a corresponding Etherscan API key is required |
@@ -1,4 +0,23 @@ | ||
import {accessSync} from 'node:fs'; | ||
import {accessSync, readFileSync} from 'node:fs'; | ||
import {dirname, join, resolve} from 'node:path'; | ||
export const MAX_POST_SIZE = 6 * 1024 ** 2; // 6 MB | ||
export function prepareProvingKey(input) { | ||
// Not specified | ||
if(!input) return undefined; | ||
// Externally hosted | ||
if(typeof input === 'string' && input.startsWith('https')) return input; | ||
const output = readFileSync(input).toString('base64'); | ||
if(output.length > MAX_POST_SIZE) | ||
throw new Error(`Proving key too large for inline upload. (Max ${formatBytes(MAX_POST_SIZE)}) Host on https server instead.`); | ||
// Send inline | ||
return output; | ||
} | ||
export function getPackageJson() { | ||
return JSON.parse(readFileSync('./package.json', 'utf8')); | ||
} | ||
export function findClosestFile(dir, filename) { | ||
@@ -68,2 +87,3 @@ const fullPath = resolve(dir); // Resolves the directory to an absolute path | ||
4: 't3.medium', | ||
8: 't3.large', | ||
16: 'r7i.large', | ||
@@ -75,3 +95,3 @@ 32: 'r7i.xlarge', | ||
384: 'r7i.12xlarge', | ||
1536: 'r7i.16xlarge', | ||
512: 'r7i.16xlarge', | ||
} | ||
@@ -78,0 +98,0 @@ |
38391
6.71%870
4.95%136
3.82%