diff --git a/.mocharc.json b/.mocharc.json index 4118824..5e57811 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -2,5 +2,5 @@ "file": ["test/setup.ts"], "require": "ts-node/register/files", "ignore": ["test/fixture-projects/**/*"], - "timeout": 60000 + "timeout": 80000 } diff --git a/package-lock.json b/package-lock.json index 30e7602..4df1d9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@solarity/hardhat-zkit", - "version": "0.5.2", + "version": "0.5.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@solarity/hardhat-zkit", - "version": "0.5.2", + "version": "0.5.3", "license": "MIT", "workspaces": [ "test/fixture-projects/*" ], "dependencies": { "@distributedlab/circom-parser": "0.2.2", - "@solarity/zkit": "0.3.0", + "@solarity/zkit": "0.3.2", "@solarity/zktype": "0.4.2", "@wasmer/wasi": "0.12.0", "chalk": "4.1.2", @@ -361,7 +361,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/@distributedlab/circom-parser/-/circom-parser-0.2.2.tgz", "integrity": "sha512-HXxtg+v/4GPAG5n4e55cjQtmUgumITok8s58L9yWGX14EmVwxbZ8jFeLR9W3rAGI0HTCBF4UemZKPocqVQetSQ==", - "license": "MIT", "dependencies": { "antlr4": "4.13.1-patch-1", "ejs": "3.1.10" @@ -2069,7 +2068,7 @@ } }, "node_modules/@solarity/zkit": { - "version": "0.3.0", + "version": "0.3.2", "license": "MIT", "dependencies": { "ejs": "3.1.10", diff --git a/package.json b/package.json index 44e01f6..6b05dd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@solarity/hardhat-zkit", - "version": "0.5.2", + "version": "0.5.3", "description": "The ultimate TypeScript environment for Circom development", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -59,7 +59,7 @@ }, "dependencies": { "@distributedlab/circom-parser": "0.2.2", - "@solarity/zkit": "0.3.0", + "@solarity/zkit": "0.3.2", "@solarity/zktype": "0.4.2", "@wasmer/wasi": "0.12.0", "chalk": "4.1.2", diff --git a/src/artifacts/CircuitArtifacts.ts b/src/artifacts/CircuitArtifacts.ts index 5d9d6e2..01e0b22 100644 --- a/src/artifacts/CircuitArtifacts.ts +++ b/src/artifacts/CircuitArtifacts.ts @@ -75,7 +75,13 @@ export class CircuitArtifacts implements ICircuitArtifacts { const artifactPath = await this._getArtifactPath(circuitNameOrFullyQualifiedName); const fileContent = fsExtra.readFileSync(artifactPath, "utf-8"); - return JSON.parse(fileContent) as CircuitArtifact; + return JSON.parse(fileContent, (_key: string, value: any): any => { + if (value != null && typeof value === "object" && "__bigintval__" in value) { + return BigInt(value["__bigintval__"]); + } + + return value; + }) as CircuitArtifact; } /** @@ -233,7 +239,16 @@ export class CircuitArtifacts implements ICircuitArtifacts { Reporter!.verboseLog("circuit-artifacts", "Saving circuit artifact: %o", [circuitArtifact]); await fsExtra.ensureDir(path.dirname(artifactPath)); - await fsExtra.writeJSON(artifactPath, circuitArtifact, { spaces: 2 }); + await fsExtra.writeJSON(artifactPath, circuitArtifact, { + spaces: 2, + replacer: (_, value: any) => { + if (typeof value === "bigint") { + return { __bigintval__: value.toString() }; + } + + return value; + }, + }); } /** diff --git a/src/core/compile/CompilationProcessor.ts b/src/core/compile/CompilationProcessor.ts index f596053..853cd7b 100644 --- a/src/core/compile/CompilationProcessor.ts +++ b/src/core/compile/CompilationProcessor.ts @@ -194,6 +194,7 @@ export class CompilationProcessor { baseCircuitInfo: { constraintsNumber: 0, signals: [], + parameters: {}, }, compilerOutputFiles: {}, }; @@ -205,6 +206,7 @@ export class CompilationProcessor { circuitArtifact.baseCircuitInfo.constraintsNumber = info.constraintsNumber; circuitArtifact.baseCircuitInfo.signals = info.resolvedFile.fileData.mainComponentData.signals; + circuitArtifact.baseCircuitInfo.parameters = info.resolvedFile.fileData.mainComponentData.parameters; await this._circuitArtifacts.saveCircuitArtifact(circuitArtifact, this._getUpdatedArtifactFileTypes(), []); } diff --git a/src/core/dependencies/parser/CircomFilesParser.ts b/src/core/dependencies/parser/CircomFilesParser.ts index 287a13e..7b83b49 100644 --- a/src/core/dependencies/parser/CircomFilesParser.ts +++ b/src/core/dependencies/parser/CircomFilesParser.ts @@ -97,8 +97,8 @@ export class CircomFilesParser { parameterValues: Record, ): Record { const parsedFileData = circomResolvedFile.fileData.parsedFileData; - const values: CircomValueType[] = Object.keys(parameterValues).map((key) => parameterValues[key]); + const circomTemplateInputsVisitor = new CircomTemplateInputsVisitor( circomResolvedFile.absolutePath, parsedFileData.templates[templateName].context, diff --git a/src/index.ts b/src/index.ts index cbf7e90..f941309 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,9 @@ -import os from "os"; -import path from "path"; -import fs from "fs"; - import { lazyObject } from "hardhat/plugins"; import { extendConfig, extendEnvironment, scope, subtask, task, types } from "hardhat/config"; import { ActionType, HardhatRuntimeEnvironment, RunSuperFunction } from "hardhat/types"; -import { TASK_CLEAN, TASK_COMPILE_SOLIDITY_READ_FILE as TASK_READ_FILE } from "hardhat/builtin-tasks/task-names"; +import { TASK_CLEAN } from "hardhat/builtin-tasks/task-names"; -import { CircuitZKit, VerifierLanguageType, ProvingSystemType } from "@solarity/zkit"; +import { CircuitZKit, ProvingSystemType } from "@solarity/zkit"; import "./type-extensions"; @@ -23,38 +19,11 @@ import { import { zkitConfigExtender } from "./config/config"; -import { - CircuitsCompileCache, - CircuitsSetupCache, - createCircuitsCompileCache, - createCircuitsSetupCache, -} from "./cache"; -import { - CompilationProcessor, - CompilationFilesResolver, - TypeGenerationProcessor, - SetupProcessor, - SetupFilesResolver, - isVersionValid, - CircuitZKitBuilder, -} from "./core"; - -import { HardhatZKitError } from "./errors"; -import { Reporter, createReporter } from "./reporter"; +import { compile, setup, make, generateVerifiers, clean } from "./tasks"; +import { CircuitZKitBuilder } from "./core"; import { CircuitArtifacts } from "./artifacts/CircuitArtifacts"; -import { CIRCUITS_COMPILE_CACHE_FILENAME, CIRCUITS_SETUP_CACHE_FILENAME } from "./constants"; -import { getNormalizedFullPath, getUniqueProvingSystems } from "./utils"; -import { - MakeTaskConfig, - CompileTaskConfig, - GenerateVerifiersTaskConfig, - SetupTaskConfig, - GetCircuitZKitConfig, -} from "./types/tasks"; -import { CircuitArtifact } from "./types/artifacts/circuit-artifacts"; -import { CompileFlags, CircomResolvedFileInfo, CircuitSetupInfo, SetupContributionSettings } from "./types/core"; -import { ProvingSystemData } from "./types/cache"; +import { GetCircuitZKitConfig } from "./types/tasks"; const zkitScope = scope(ZKIT_SCOPE_NAME, "The ultimate TypeScript environment for Circom development"); @@ -78,254 +47,6 @@ extendEnvironment((hre) => { }); }); -const compile: ActionType = async (taskArgs: CompileTaskConfig, env: HardhatRuntimeEnvironment) => { - const circuitsCompileCacheFullPath: string = getNormalizedFullPath( - env.config.paths.cache, - CIRCUITS_COMPILE_CACHE_FILENAME, - ); - - createReporter(taskArgs.quiet || env.config.zkit.quiet); - await createCircuitsCompileCache(circuitsCompileCacheFullPath); - - const compilationFileResolver: CompilationFilesResolver = new CompilationFilesResolver( - (absolutePath: string) => env.run(TASK_READ_FILE, { absolutePath }), - env.zkit.circuitArtifacts, - env.config, - ); - - const optimization = taskArgs.optimization || env.config.zkit.compilationSettings.optimization; - - // Flags for specifying the necessary configurations during the setup process. - // R1CS, Wasm, and Sym flags are mandatory - const compileFlags: CompileFlags = { - r1cs: true, - wasm: true, - sym: true, - json: taskArgs.json || env.config.zkit.compilationSettings.json, - c: taskArgs.c || env.config.zkit.compilationSettings.c, - O0: optimization === "O0", - O1: optimization === "O1", - O2: optimization === "O2", - }; - - Reporter!.reportCircuitFilesResolvingProcessHeader(); - Reporter!.verboseLog("index", "Compile flags: %O", [compileFlags]); - - const resolvedFilesInfo: CircomResolvedFileInfo[] = await compilationFileResolver.getResolvedFilesToCompile( - compileFlags, - taskArgs.force, - ); - - const configCompilerVersion = env.config.zkit.compilerVersion; - - if (configCompilerVersion && !isVersionValid(configCompilerVersion)) { - throw new HardhatZKitError(`Invalid Circom compiler version ${configCompilerVersion} specified in the config`); - } - - if (resolvedFilesInfo.length > 0) { - const compilationProcessor: CompilationProcessor = new CompilationProcessor( - { - compileFlags, - quiet: taskArgs.quiet || env.config.zkit.quiet, - }, - env.zkit.circuitArtifacts, - env, - ); - - await compilationProcessor.compile(resolvedFilesInfo); - - for (const fileInfo of resolvedFilesInfo) { - for (const file of [fileInfo.resolvedFile, ...fileInfo.dependencies]) { - CircuitsCompileCache!.addFile(file.absolutePath, { - lastModificationDate: file.lastModificationDate.valueOf(), - contentHash: file.contentHash, - sourceName: file.sourceName, - compileFlags, - fileData: file.fileData, - }); - } - } - } else { - Reporter!.reportNothingToCompile(); - } - - await new TypeGenerationProcessor(env).generateAllTypes(); - - await CircuitsCompileCache!.writeToFile(circuitsCompileCacheFullPath); -}; - -const setup: ActionType = async (taskArgs: SetupTaskConfig, env: HardhatRuntimeEnvironment) => { - const circuitsSetupCacheFullPath: string = getNormalizedFullPath( - env.config.paths.cache, - CIRCUITS_SETUP_CACHE_FILENAME, - ); - - createReporter(taskArgs.quiet || env.config.zkit.quiet); - await createCircuitsSetupCache(circuitsSetupCacheFullPath); - - const setupFileResolver: SetupFilesResolver = new SetupFilesResolver(env.zkit.circuitArtifacts, env.config); - const setupContributionSettings: SetupContributionSettings = { - provingSystems: getUniqueProvingSystems(env.config.zkit.setupSettings.contributionSettings.provingSystem), - contributions: env.config.zkit.setupSettings.contributionSettings.contributions, - }; - - const circuitSetupInfoArr: CircuitSetupInfo[] = await setupFileResolver.getCircuitsInfoToSetup( - setupContributionSettings, - env.config.zkit.setupSettings, - taskArgs.force, - ); - - if (circuitSetupInfoArr.length > 0) { - let ptauDir = env.config.zkit.setupSettings.ptauDir; - - // If `ptauDir` is not specified in the configuration, - // the `.zkit/ptau` folder in the user's home directory is used as the default location - if (ptauDir) { - ptauDir = path.isAbsolute(ptauDir) ? ptauDir : getNormalizedFullPath(env.config.paths.root, ptauDir); - } else { - ptauDir = path.join(os.homedir(), ".zkit", "ptau"); - } - - const setupProcessor: SetupProcessor = new SetupProcessor(ptauDir, env.zkit.circuitArtifacts); - - await setupProcessor.setup(circuitSetupInfoArr, setupContributionSettings); - - for (const setupInfo of circuitSetupInfoArr) { - const currentSetupCacheEntry = CircuitsSetupCache!.getEntry(setupInfo.circuitArtifactFullPath); - - let currentProvingSystemsData: ProvingSystemData[] = []; - - if (currentSetupCacheEntry) { - // Getting untouched proving systems data - currentProvingSystemsData = currentSetupCacheEntry.provingSystemsData.filter((data: ProvingSystemData) => { - return !setupInfo.provingSystems.includes(data.provingSystem); - }); - } - - CircuitsSetupCache!.addFile(setupInfo.circuitArtifactFullPath, { - circuitSourceName: setupInfo.circuitArtifact.circuitSourceName, - r1csSourcePath: setupInfo.r1csSourcePath, - provingSystemsData: [ - ...currentProvingSystemsData, - ...setupContributionSettings.provingSystems.map((provingSystem) => { - return { - provingSystem, - lastR1CSFileHash: setupInfo.r1csContentHash, - }; - }), - ], - contributionsNumber: setupContributionSettings.contributions, - }); - } - } else { - Reporter!.reportNothingToSetup(); - } - - await new TypeGenerationProcessor(env).generateAllTypes(); - - await CircuitsSetupCache!.writeToFile(circuitsSetupCacheFullPath); -}; - -const make: ActionType = async (taskArgs: MakeTaskConfig, env: HardhatRuntimeEnvironment) => { - await env.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE }, taskArgs); - - Reporter!.reportCompilationBottomLine(); - - await env.run( - { scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_SETUP }, - { force: taskArgs.force, quiet: taskArgs.quiet }, - ); -}; - -const generateVerifiers: ActionType = async ( - taskArgs: GenerateVerifiersTaskConfig, - env: HardhatRuntimeEnvironment, -) => { - if (!taskArgs.noCompile) { - await env.run( - { scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_MAKE }, - { - quiet: taskArgs.quiet, - force: taskArgs.force, - }, - ); - } else { - createReporter(taskArgs.quiet || env.config.zkit.quiet); - } - - const verifiersDirFullPath: string = getNormalizedFullPath( - env.config.paths.root, - taskArgs.verifiersDir ?? env.config.zkit.verifiersSettings.verifiersDir, - ); - const verifiersType: VerifierLanguageType = taskArgs.verifiersType ?? env.config.zkit.verifiersSettings.verifiersType; - const provingSystems: ProvingSystemType[] = getUniqueProvingSystems( - env.config.zkit.setupSettings.contributionSettings.provingSystem, - ); - - Reporter!.verboseLog("index", "Verifiers generation dir - %s", [verifiersDirFullPath]); - - const allFullyQualifiedNames: string[] = await env.zkit.circuitArtifacts.getAllCircuitFullyQualifiedNames(); - let verifiersCount: number = 0; - - if (allFullyQualifiedNames.length > 0) { - Reporter!.reportVerifiersGenerationHeader(verifiersType); - - for (const name of allFullyQualifiedNames) { - const circuitArtifact: CircuitArtifact = await env.zkit.circuitArtifacts.readCircuitArtifact(name); - - for (const provingSystem of provingSystems) { - const spinnerId: string | null = Reporter!.reportVerifierGenerationStartWithSpinner( - circuitArtifact.circuitTemplateName, - verifiersType, - provingSystem, - ); - - ( - await env.zkit.circuitZKitBuilder.getCircuitZKit( - name, - provingSystems.length > 1 ? provingSystem : undefined, - taskArgs.verifiersDir, - ) - ).createVerifier(verifiersType); - - Reporter!.reportVerifierGenerationResult( - spinnerId, - circuitArtifact.circuitTemplateName, - verifiersType, - provingSystem, - ); - - verifiersCount++; - } - } - - Reporter!.reportVerifiersGenerationResult(verifiersType, verifiersCount); - } else { - Reporter!.reportNothingToGenerate(); - } -}; - -const clean: ActionType = async (_taskArgs: any, env: HardhatRuntimeEnvironment) => { - const circuitsCompileCacheFullPath: string = getNormalizedFullPath( - env.config.paths.cache, - CIRCUITS_COMPILE_CACHE_FILENAME, - ); - const circuitsSetupCacheFullPath: string = getNormalizedFullPath( - env.config.paths.cache, - CIRCUITS_SETUP_CACHE_FILENAME, - ); - const artifactsDirFullPath: string = getNormalizedFullPath( - env.config.paths.root, - env.config.zkit.compilationSettings.artifactsDir, - ); - const circuitTypesFullPath: string = getNormalizedFullPath(env.config.paths.root, env.config.zkit.typesDir); - - fs.rmSync(circuitsCompileCacheFullPath, { force: true }); - fs.rmSync(circuitsSetupCacheFullPath, { force: true }); - fs.rmSync(artifactsDirFullPath, { recursive: true, force: true }); - fs.rmSync(circuitTypesFullPath, { recursive: true, force: true }); -}; - const getCircuitZKit: ActionType = async ( taskArgs: GetCircuitZKitConfig, env: HardhatRuntimeEnvironment, @@ -344,17 +65,17 @@ task(TASK_CLEAN).setAction(async (_taskArgs: any, env: HardhatRuntimeEnvironment }); zkitScope - .task(TASK_CIRCUITS_MAKE, "Compile Circom circuits and generate all necessary artifacts") - .addFlag("json", "Outputs constraints in json file in the compilation artifacts directory.") - .addFlag("c", "Enables the generation of cpp files in the compilation artifacts directory.") - .addFlag("force", "Force compilation ignoring cache.") - .addFlag("quiet", "Suppresses logs during the compilation process.") + .task(TASK_CIRCUITS_MAKE, "Compile Circom circuits and setup proving and verification keys.") + .addFlag("json", "Output constraints in the 'json' file in the compilation artifacts directory.") + .addFlag("c", "Enable the generation of 'cpp' files in the compilation artifacts directory.") + .addFlag("force", "Force compilation and setup ignoring cache.") + .addFlag("quiet", "Suppress logs during the compilation and setup processes.") .setAction(make); zkitScope - .task(TASK_CIRCUITS_COMPILE, "Compile Circom circuits") - .addFlag("json", "Outputs constraints in json file in the compilation artifacts directory.") - .addFlag("c", "Enables the generation of cpp files in the compilation artifacts directory.") + .task(TASK_CIRCUITS_COMPILE, "Compile Circom circuits.") + .addFlag("json", "Output constraints in the 'json' file in the compilation artifacts directory.") + .addFlag("c", "Enable the generation of 'cpp' files in the compilation artifacts directory.") .addFlag("force", "Force compilation ignoring cache.") .addOptionalParam( "optimization", @@ -365,31 +86,31 @@ zkitScope .setAction(compile); zkitScope - .task(TASK_CIRCUITS_SETUP, "Create ZKey and Vkey files for compiled circuits") - .addFlag("force", "Force compilation ignoring cache.") - .addFlag("quiet", "Suppresses logs during the compilation process.") + .task(TASK_CIRCUITS_SETUP, "Setup ZKey and VKey keys for previously compiled circuits.") + .addFlag("force", "Force setup ignoring cache.") + .addFlag("quiet", "Suppress logs during the setup process.") .setAction(setup); zkitScope - .task(TASK_GENERATE_VERIFIERS, "Generate Solidity | Vyper verifier contracts for Circom circuits") + .task(TASK_GENERATE_VERIFIERS, "Generate Solidity | Vyper verifier contracts for Circom circuits.") .addOptionalParam( "verifiersDir", - "Relative path to the directory where the generated verifier contracts will be saved.", + "Relative path to the directory where to save the generated verifier contracts.", undefined, types.string, ) .addOptionalParam( "verifiersType", - "Verifier contracts laguage to generate. Use 'sol' for Solidity and 'vy' for Vyper", + "Verifier contracts language to generate. Use 'sol' for Solidity and 'vy' for Vyper.", undefined, types.string, ) .addFlag("noCompile", "Disable compilation before verifiers generation.") .addFlag("force", "Force compilation ignoring cache.") - .addFlag("quiet", "Suppresses logs during the verifier generation process.") + .addFlag("quiet", "Suppress logs during the verifier generation process.") .setAction(generateVerifiers); -zkitScope.task(TASK_ZKIT_CLEAN, "Clean all circuit artifacts, keys, types and etc").setAction(clean); +zkitScope.task(TASK_ZKIT_CLEAN, "Clean all zkit artifacts, circom generated files, keys, types, etc.").setAction(clean); subtask(SUBTASK_ZKIT_GET_CIRCUIT_ZKIT) .addOptionalParam("verifiersDir", undefined, undefined, types.string) diff --git a/src/tasks/clean.ts b/src/tasks/clean.ts new file mode 100644 index 0000000..d1c6306 --- /dev/null +++ b/src/tasks/clean.ts @@ -0,0 +1,27 @@ +import fs from "fs"; + +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types"; + +import { CIRCUITS_COMPILE_CACHE_FILENAME, CIRCUITS_SETUP_CACHE_FILENAME } from "../constants"; +import { getNormalizedFullPath } from "../utils"; + +export const clean: ActionType = async (_taskArgs: any, env: HardhatRuntimeEnvironment) => { + const circuitsCompileCacheFullPath: string = getNormalizedFullPath( + env.config.paths.cache, + CIRCUITS_COMPILE_CACHE_FILENAME, + ); + const circuitsSetupCacheFullPath: string = getNormalizedFullPath( + env.config.paths.cache, + CIRCUITS_SETUP_CACHE_FILENAME, + ); + const artifactsDirFullPath: string = getNormalizedFullPath( + env.config.paths.root, + env.config.zkit.compilationSettings.artifactsDir, + ); + const circuitTypesFullPath: string = getNormalizedFullPath(env.config.paths.root, env.config.zkit.typesDir); + + fs.rmSync(circuitsCompileCacheFullPath, { force: true }); + fs.rmSync(circuitsSetupCacheFullPath, { force: true }); + fs.rmSync(artifactsDirFullPath, { recursive: true, force: true }); + fs.rmSync(circuitTypesFullPath, { recursive: true, force: true }); +}; diff --git a/src/tasks/compile.ts b/src/tasks/compile.ts new file mode 100644 index 0000000..bdfacaa --- /dev/null +++ b/src/tasks/compile.ts @@ -0,0 +1,92 @@ +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types"; +import { TASK_COMPILE_SOLIDITY_READ_FILE as TASK_READ_FILE } from "hardhat/builtin-tasks/task-names"; + +import { CircuitsCompileCache, createCircuitsCompileCache } from "../cache"; +import { CompilationProcessor, CompilationFilesResolver, TypeGenerationProcessor, isVersionValid } from "../core"; + +import { HardhatZKitError } from "../errors"; +import { Reporter, createReporter } from "../reporter"; +import { CIRCUITS_COMPILE_CACHE_FILENAME } from "../constants"; +import { getNormalizedFullPath } from "../utils"; + +import { CompileTaskConfig } from "../types/tasks"; +import { CompileFlags, CircomResolvedFileInfo } from "../types/core"; + +export const compile: ActionType = async ( + taskArgs: CompileTaskConfig, + env: HardhatRuntimeEnvironment, +) => { + const circuitsCompileCacheFullPath: string = getNormalizedFullPath( + env.config.paths.cache, + CIRCUITS_COMPILE_CACHE_FILENAME, + ); + + createReporter(taskArgs.quiet || env.config.zkit.quiet); + await createCircuitsCompileCache(circuitsCompileCacheFullPath); + + const compilationFileResolver: CompilationFilesResolver = new CompilationFilesResolver( + (absolutePath: string) => env.run(TASK_READ_FILE, { absolutePath }), + env.zkit.circuitArtifacts, + env.config, + ); + + const optimization = taskArgs.optimization || env.config.zkit.compilationSettings.optimization; + + // Flags for specifying the necessary configurations during the setup process. + // R1CS, Wasm, and Sym flags are mandatory + const compileFlags: CompileFlags = { + r1cs: true, + wasm: true, + sym: true, + json: taskArgs.json || env.config.zkit.compilationSettings.json, + c: taskArgs.c || env.config.zkit.compilationSettings.c, + O0: optimization === "O0", + O1: optimization === "O1", + O2: optimization === "O2", + }; + + Reporter!.reportCircuitFilesResolvingProcessHeader(); + Reporter!.verboseLog("index", "Compile flags: %O", [compileFlags]); + + const resolvedFilesInfo: CircomResolvedFileInfo[] = await compilationFileResolver.getResolvedFilesToCompile( + compileFlags, + taskArgs.force, + ); + + const configCompilerVersion = env.config.zkit.compilerVersion; + + if (configCompilerVersion && !isVersionValid(configCompilerVersion)) { + throw new HardhatZKitError(`Invalid Circom compiler version ${configCompilerVersion} specified in the config`); + } + + if (resolvedFilesInfo.length > 0) { + const compilationProcessor: CompilationProcessor = new CompilationProcessor( + { + compileFlags, + quiet: taskArgs.quiet || env.config.zkit.quiet, + }, + env.zkit.circuitArtifacts, + env, + ); + + await compilationProcessor.compile(resolvedFilesInfo); + + for (const fileInfo of resolvedFilesInfo) { + for (const file of [fileInfo.resolvedFile, ...fileInfo.dependencies]) { + CircuitsCompileCache!.addFile(file.absolutePath, { + lastModificationDate: file.lastModificationDate.valueOf(), + contentHash: file.contentHash, + sourceName: file.sourceName, + compileFlags, + fileData: file.fileData, + }); + } + } + } else { + Reporter!.reportNothingToCompile(); + } + + await new TypeGenerationProcessor(env).generateAllTypes(); + + await CircuitsCompileCache!.writeToFile(circuitsCompileCacheFullPath); +}; diff --git a/src/tasks/generate-verifiers.ts b/src/tasks/generate-verifiers.ts new file mode 100644 index 0000000..401b1e2 --- /dev/null +++ b/src/tasks/generate-verifiers.ts @@ -0,0 +1,123 @@ +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types"; + +import { CircomValueType } from "@distributedlab/circom-parser"; + +import { VerifierLanguageType, ProvingSystemType } from "@solarity/zkit"; + +import { ZKIT_SCOPE_NAME, TASK_CIRCUITS_MAKE } from "../task-names"; + +import { Reporter, createReporter } from "../reporter"; +import { getNormalizedFullPath, getUniqueProvingSystems } from "../utils"; + +import { GenerateVerifiersTaskConfig } from "../types/tasks"; +import { CircuitArtifact } from "../types/artifacts/circuit-artifacts"; + +export const generateVerifiers: ActionType = async ( + taskArgs: GenerateVerifiersTaskConfig, + env: HardhatRuntimeEnvironment, +) => { + if (!taskArgs.noCompile) { + await env.run( + { scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_MAKE }, + { + quiet: taskArgs.quiet, + force: taskArgs.force, + }, + ); + } else { + createReporter(taskArgs.quiet || env.config.zkit.quiet); + } + + const verifiersDirFullPath: string = getNormalizedFullPath( + env.config.paths.root, + taskArgs.verifiersDir ?? env.config.zkit.verifiersSettings.verifiersDir, + ); + const verifiersType: VerifierLanguageType = taskArgs.verifiersType ?? env.config.zkit.verifiersSettings.verifiersType; + const provingSystems: ProvingSystemType[] = getUniqueProvingSystems( + env.config.zkit.setupSettings.contributionSettings.provingSystem, + ); + + Reporter!.verboseLog("index", "Verifiers generation dir - %s", [verifiersDirFullPath]); + + const allFullyQualifiedNames: string[] = await env.zkit.circuitArtifacts.getAllCircuitFullyQualifiedNames(); + let verifiersCount: number = 0; + + if (allFullyQualifiedNames.length > 0) { + Reporter!.reportVerifiersGenerationHeader(verifiersType); + + const templateNamesCount: { [key: string]: number } = {}; + const circuitArtifactsInfo = await Promise.all( + allFullyQualifiedNames.map(async (name: string) => { + const circuitArtifact: CircuitArtifact = await env.zkit.circuitArtifacts.readCircuitArtifact(name); + + // Count the number of uses of templates to determine whether a verifier file + // will need a suffix in case of non-uniqueness + templateNamesCount[circuitArtifact.circuitTemplateName] = + (templateNamesCount[circuitArtifact.circuitTemplateName] || 0) + 1; + + return { name, circuitArtifact }; + }), + ); + + for (const circuitArtifactInfo of circuitArtifactsInfo) { + for (const provingSystem of provingSystems) { + const spinnerId: string | null = Reporter!.reportVerifierGenerationStartWithSpinner( + circuitArtifactInfo.circuitArtifact.circuitTemplateName, + verifiersType, + provingSystem, + ); + + let verifierNameSuffix: string = ""; + + if (templateNamesCount[circuitArtifactInfo.circuitArtifact.circuitTemplateName] > 1) { + const flattenParametersArr: bigint[] = flattenParameters( + circuitArtifactInfo.circuitArtifact.baseCircuitInfo.parameters, + ); + + flattenParametersArr.forEach((param: bigint, index: number) => { + verifierNameSuffix += `_${param.toString()}${index === flattenParametersArr.length - 1 ? "_" : ""}`; + }); + } + + const currentCircuit = await env.zkit.circuitZKitBuilder.getCircuitZKit( + circuitArtifactInfo.name, + provingSystems.length > 1 ? provingSystem : undefined, + taskArgs.verifiersDir, + ); + + currentCircuit.createVerifier(verifiersType, verifierNameSuffix); + + Reporter!.reportVerifierGenerationResult( + spinnerId, + `${circuitArtifactInfo.circuitArtifact.circuitTemplateName}${verifierNameSuffix.slice(0, verifierNameSuffix.length - 1)}`, + verifiersType, + provingSystem, + ); + + verifiersCount++; + } + } + + Reporter!.reportVerifiersGenerationResult(verifiersType, verifiersCount); + } else { + Reporter!.reportNothingToGenerate(); + } +}; + +function flattenParameters(parameters: Record): bigint[] { + const flattenParametersArr: bigint[] = []; + + for (const parameterKey of Object.keys(parameters)) { + flattenParametersArr.push(...flattenParameter(parameters[parameterKey])); + } + + return flattenParametersArr; +} + +function flattenParameter(parameter: CircomValueType): bigint[] { + const flatValue = Array.isArray(parameter) + ? parameter.flatMap((parameter) => flattenParameter(parameter)) + : parameter; + + return Array.isArray(flatValue) ? flatValue : [flatValue]; +} diff --git a/src/tasks/index.ts b/src/tasks/index.ts new file mode 100644 index 0000000..87becab --- /dev/null +++ b/src/tasks/index.ts @@ -0,0 +1,5 @@ +export * from "./compile"; +export * from "./setup"; +export * from "./make"; +export * from "./generate-verifiers"; +export * from "./clean"; diff --git a/src/tasks/make.ts b/src/tasks/make.ts new file mode 100644 index 0000000..0763f20 --- /dev/null +++ b/src/tasks/make.ts @@ -0,0 +1,18 @@ +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types"; + +import { ZKIT_SCOPE_NAME, TASK_CIRCUITS_COMPILE, TASK_CIRCUITS_SETUP } from "../task-names"; + +import { Reporter } from "../reporter"; + +import { MakeTaskConfig } from "../types/tasks"; + +export const make: ActionType = async (taskArgs: MakeTaskConfig, env: HardhatRuntimeEnvironment) => { + await env.run({ scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_COMPILE }, taskArgs); + + Reporter!.reportCompilationBottomLine(); + + await env.run( + { scope: ZKIT_SCOPE_NAME, task: TASK_CIRCUITS_SETUP }, + { force: taskArgs.force, quiet: taskArgs.quiet }, + ); +}; diff --git a/src/tasks/setup.ts b/src/tasks/setup.ts new file mode 100644 index 0000000..5d7e316 --- /dev/null +++ b/src/tasks/setup.ts @@ -0,0 +1,87 @@ +import os from "os"; +import path from "path"; + +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types"; + +import { CircuitsSetupCache, createCircuitsSetupCache } from "../cache"; +import { TypeGenerationProcessor, SetupProcessor, SetupFilesResolver } from "../core"; + +import { Reporter, createReporter } from "../reporter"; +import { CIRCUITS_SETUP_CACHE_FILENAME } from "../constants"; +import { getNormalizedFullPath, getUniqueProvingSystems } from "../utils"; + +import { SetupTaskConfig } from "../types/tasks"; +import { CircuitSetupInfo, SetupContributionSettings } from "../types/core"; +import { ProvingSystemData } from "../types/cache"; + +export const setup: ActionType = async (taskArgs: SetupTaskConfig, env: HardhatRuntimeEnvironment) => { + const circuitsSetupCacheFullPath: string = getNormalizedFullPath( + env.config.paths.cache, + CIRCUITS_SETUP_CACHE_FILENAME, + ); + + createReporter(taskArgs.quiet || env.config.zkit.quiet); + await createCircuitsSetupCache(circuitsSetupCacheFullPath); + + const setupFileResolver: SetupFilesResolver = new SetupFilesResolver(env.zkit.circuitArtifacts, env.config); + const setupContributionSettings: SetupContributionSettings = { + provingSystems: getUniqueProvingSystems(env.config.zkit.setupSettings.contributionSettings.provingSystem), + contributions: env.config.zkit.setupSettings.contributionSettings.contributions, + }; + + const circuitSetupInfoArr: CircuitSetupInfo[] = await setupFileResolver.getCircuitsInfoToSetup( + setupContributionSettings, + env.config.zkit.setupSettings, + taskArgs.force, + ); + + if (circuitSetupInfoArr.length > 0) { + let ptauDir = env.config.zkit.setupSettings.ptauDir; + + // If `ptauDir` is not specified in the configuration, + // the `.zkit/ptau` folder in the user's home directory is used as the default location + if (ptauDir) { + ptauDir = path.isAbsolute(ptauDir) ? ptauDir : getNormalizedFullPath(env.config.paths.root, ptauDir); + } else { + ptauDir = path.join(os.homedir(), ".zkit", "ptau"); + } + + const setupProcessor: SetupProcessor = new SetupProcessor(ptauDir, env.zkit.circuitArtifacts); + + await setupProcessor.setup(circuitSetupInfoArr, setupContributionSettings); + + for (const setupInfo of circuitSetupInfoArr) { + const currentSetupCacheEntry = CircuitsSetupCache!.getEntry(setupInfo.circuitArtifactFullPath); + + let currentProvingSystemsData: ProvingSystemData[] = []; + + if (currentSetupCacheEntry) { + // Getting untouched proving systems data + currentProvingSystemsData = currentSetupCacheEntry.provingSystemsData.filter((data: ProvingSystemData) => { + return !setupInfo.provingSystems.includes(data.provingSystem); + }); + } + + CircuitsSetupCache!.addFile(setupInfo.circuitArtifactFullPath, { + circuitSourceName: setupInfo.circuitArtifact.circuitSourceName, + r1csSourcePath: setupInfo.r1csSourcePath, + provingSystemsData: [ + ...currentProvingSystemsData, + ...setupContributionSettings.provingSystems.map((provingSystem) => { + return { + provingSystem, + lastR1CSFileHash: setupInfo.r1csContentHash, + }; + }), + ], + contributionsNumber: setupContributionSettings.contributions, + }); + } + } else { + Reporter!.reportNothingToSetup(); + } + + await new TypeGenerationProcessor(env).generateAllTypes(); + + await CircuitsSetupCache!.writeToFile(circuitsSetupCacheFullPath); +}; diff --git a/src/types/artifacts/circuit-artifacts.ts b/src/types/artifacts/circuit-artifacts.ts index 87fdb4c..958ee97 100644 --- a/src/types/artifacts/circuit-artifacts.ts +++ b/src/types/artifacts/circuit-artifacts.ts @@ -1,4 +1,7 @@ +import { CircomValueType } from "@distributedlab/circom-parser"; + import { ProvingSystemType } from "@solarity/zkit"; + import { SignalInfo } from "../core"; export interface ICircuitArtifacts { @@ -45,6 +48,7 @@ export type CircuitArtifact = { export type BaseCircuitInfo = { constraintsNumber: number; signals: SignalInfo[]; + parameters: Record; }; export type CompilerOutputFileInfo = { diff --git a/src/types/tasks.ts b/src/types/tasks.ts deleted file mode 100644 index 944e66c..0000000 --- a/src/types/tasks.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ProvingSystemType, VerifierLanguageType } from "@solarity/zkit"; - -export type MakeTaskConfig = { - force: boolean; - json: boolean; - c: boolean; - quiet: boolean; -}; - -export type SetupTaskConfig = { - force: boolean; - quiet: boolean; -}; - -export type CompileTaskConfig = { - force: boolean; - json: boolean; - c: boolean; - quiet: boolean; - optimization?: "O0" | "O1" | "O2"; -}; - -export type GenerateVerifiersTaskConfig = { - verifiersDir?: string; - verifiersType?: VerifierLanguageType; - noCompile: boolean; - quiet: boolean; - force: boolean; -}; - -export type GetCircuitZKitConfig = { - circuitName: string; - verifiersDir?: string; - provingSystem?: ProvingSystemType; -}; diff --git a/src/types/tasks/compile.ts b/src/types/tasks/compile.ts new file mode 100644 index 0000000..368e5b8 --- /dev/null +++ b/src/types/tasks/compile.ts @@ -0,0 +1,7 @@ +export type CompileTaskConfig = { + force: boolean; + json: boolean; + c: boolean; + quiet: boolean; + optimization?: "O0" | "O1" | "O2"; +}; diff --git a/src/types/tasks/generate-verifiers.ts b/src/types/tasks/generate-verifiers.ts new file mode 100644 index 0000000..9d14ccd --- /dev/null +++ b/src/types/tasks/generate-verifiers.ts @@ -0,0 +1,9 @@ +import { VerifierLanguageType } from "@solarity/zkit"; + +export type GenerateVerifiersTaskConfig = { + verifiersDir?: string; + verifiersType?: VerifierLanguageType; + noCompile: boolean; + quiet: boolean; + force: boolean; +}; diff --git a/src/types/tasks/index.ts b/src/types/tasks/index.ts new file mode 100644 index 0000000..e44f10c --- /dev/null +++ b/src/types/tasks/index.ts @@ -0,0 +1,12 @@ +import { ProvingSystemType } from "@solarity/zkit"; + +export * from "./compile"; +export * from "./setup"; +export * from "./make"; +export * from "./generate-verifiers"; + +export type GetCircuitZKitConfig = { + circuitName: string; + verifiersDir?: string; + provingSystem?: ProvingSystemType; +}; diff --git a/src/types/tasks/make.ts b/src/types/tasks/make.ts new file mode 100644 index 0000000..38a1ce4 --- /dev/null +++ b/src/types/tasks/make.ts @@ -0,0 +1,6 @@ +export type MakeTaskConfig = { + force: boolean; + json: boolean; + c: boolean; + quiet: boolean; +}; diff --git a/src/types/tasks/setup.ts b/src/types/tasks/setup.ts new file mode 100644 index 0000000..07dde8a --- /dev/null +++ b/src/types/tasks/setup.ts @@ -0,0 +1,4 @@ +export type SetupTaskConfig = { + force: boolean; + quiet: boolean; +}; diff --git a/test/fixture-projects/hardhat-project-with-circuits-main-component/circuits/base/SomeCircuit2.circom b/test/fixture-projects/hardhat-project-with-circuits-main-component/circuits/base/SomeCircuit2.circom new file mode 100644 index 0000000..0adf905 --- /dev/null +++ b/test/fixture-projects/hardhat-project-with-circuits-main-component/circuits/base/SomeCircuit2.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "templates/SomeCircuit.circom"; + +component main {public [in1]} = SomeCircuit([5, 3, 2, 5], 4); diff --git a/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test.circom b/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test.circom new file mode 100644 index 0000000..eb6587b --- /dev/null +++ b/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.8; + +template Test(a){ + signal input in[a]; + signal output out; + + signal tmp <-- in[0] * in[1]; + + out <== tmp * in[2]; +} + +component main = Test(10); diff --git a/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test_2.circom b/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test_2.circom new file mode 100644 index 0000000..9d6b311 --- /dev/null +++ b/test/fixture-projects/hardhat-project-with-circuits/circuits/main/test_2.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.8; + +template Test(a){ + signal input in[a]; + signal output out; + + signal tmp <-- in[0] * in[1]; + + out <== tmp * in[2]; +} + +component main = Test(20); diff --git a/test/integration/tasks.test.ts b/test/integration/tasks.test.ts index b9556a5..818281b 100644 --- a/test/integration/tasks.test.ts +++ b/test/integration/tasks.test.ts @@ -442,56 +442,77 @@ describe("ZKit tasks", async function () { const plonkTypesDir = "zkit/types-plonk"; const groth16PlonkTypesDir = "zkit/types-groth16-plonk"; - useEnvironment("with-circuits", true); + describe("with simple circuits", async function () { + useEnvironment("with-circuits", true); - it("should correctly generate 'groth16' verifiers after running the verifiers task", async function () { - await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS }); + it("should correctly generate 'groth16' 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, ["groth16"]); + await checkMake(this.hre.config, this.hre.zkit, ["groth16"]); - const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); - expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq( - circuitNames.map((name) => `${name}Groth16Verifier.sol`), - ); + const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); + expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq([ + ...circuitNames.map((name) => `${name}Groth16Verifier.sol`), + "Test_10_Groth16Verifier.sol", + "Test_20_Groth16Verifier.sol", + ]); - updateProvingSystems(this.hre.config.paths.configFile, ["plonk"]); - updateTypesDir(this.hre.config.paths.configFile, defaultTypesDir, plonkTypesDir); - }); + updateProvingSystems(this.hre.config.paths.configFile, ["plonk"]); + updateTypesDir(this.hre.config.paths.configFile, defaultTypesDir, plonkTypesDir); + }); - it("should correctly generate 'plonk' verifiers after running the verifiers task", async function () { - await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS }); + it("should correctly generate 'plonk' 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, ["plonk"]); + await checkMake(this.hre.config, this.hre.zkit, ["plonk"]); - const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); - expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq( - circuitNames.map((name) => `${name}PlonkVerifier.sol`), - ); + const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); + expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq([ + ...circuitNames.map((name) => `${name}PlonkVerifier.sol`), + "Test_10_PlonkVerifier.sol", + "Test_20_PlonkVerifier.sol", + ]); - updateProvingSystems(this.hre.config.paths.configFile, ["groth16", "plonk"]); - updateTypesDir(this.hre.config.paths.configFile, plonkTypesDir, groth16PlonkTypesDir); - }); + updateProvingSystems(this.hre.config.paths.configFile, ["groth16", "plonk"]); + updateTypesDir(this.hre.config.paths.configFile, plonkTypesDir, groth16PlonkTypesDir); + }); - it("should correctly generate 'groth16' and 'plonk' verifiers after running the verifiers task", async function () { - const provingSystemsArr: ProvingSystemType[] = ["groth16", "plonk"]; + it("should correctly generate 'groth16' and 'plonk' verifiers after running the verifiers task", async function () { + const provingSystemsArr: ProvingSystemType[] = ["groth16", "plonk"]; - await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS }); + await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS }); - await checkMake(this.hre.config, this.hre.zkit, provingSystemsArr); + await checkMake(this.hre.config, this.hre.zkit, provingSystemsArr); - const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); - const verifiersNameArr: string[] = []; + const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); + const verifiersNameArr: string[] = []; - for (const circuitName of circuitNames) { - verifiersNameArr.push( - ...provingSystemsArr.map((provingSystem) => `${circuitName}${capitalize(provingSystem)}Verifier.sol`), - ); - } + for (const circuitName of [...circuitNames, "Test_10_", "Test_20_"]) { + verifiersNameArr.push( + ...provingSystemsArr.map((provingSystem) => `${circuitName}${capitalize(provingSystem)}Verifier.sol`), + ); + } - expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq(verifiersNameArr); + expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq(verifiersNameArr); - updateProvingSystems(this.hre.config.paths.configFile, ["groth16"]); - updateTypesDir(this.hre.config.paths.configFile, groth16PlonkTypesDir, defaultTypesDir); + updateProvingSystems(this.hre.config.paths.configFile, ["groth16"]); + updateTypesDir(this.hre.config.paths.configFile, groth16PlonkTypesDir, defaultTypesDir); + }); + }); + + describe("with complex main components", async function () { + useEnvironment("with-circuits-main-component", true); + + it("should correctly generate verifiers with custom verifier names", async function () { + await this.hre.run({ scope: ZKIT_SCOPE_NAME, task: TASK_GENERATE_VERIFIERS }); + + const expectedCircuitNames: string[] = ["SomeCircuit_5_3_2_5_3_", "SomeCircuit_5_3_2_5_4_"]; + + const verifiersFullPath: string = getNormalizedFullPath(this.hre.config.paths.root, "contracts/verifiers"); + expect(fsExtra.readdirSync(verifiersFullPath)).to.be.deep.eq([ + ...expectedCircuitNames.map((name) => `${name}Groth16Verifier.sol`), + ]); + }); }); }); diff --git a/test/unit/core/compile/compilation-files-resolver.test.ts b/test/unit/core/compile/compilation-files-resolver.test.ts index a9be9b5..3192ec2 100644 --- a/test/unit/core/compile/compilation-files-resolver.test.ts +++ b/test/unit/core/compile/compilation-files-resolver.test.ts @@ -65,9 +65,11 @@ describe("CompilationFilesResolver", () => { const expectedSourceNames: string[] = [ "circuits/main/Multiplier3Arr.circom", "circuits/main/mul2.circom", + "circuits/main/test.circom", + "circuits/main/test_2.circom", "circuits/vendor/SumMul.circom", ]; - const expectedCircuitNames: string[] = ["Multiplier3Arr", "Multiplier2", "SumMul"]; + const expectedCircuitNames: string[] = ["Multiplier3Arr", "Multiplier2", "Test", "Test", "SumMul"]; expect(filteredResolvedFilesInfo.length).to.be.eq(expectedSourceNames.length);