diff --git a/v-next/hardhat-utils/src/crypto.ts b/v-next/hardhat-utils/src/crypto.ts index 02366f1f80..db80e2efa8 100644 --- a/v-next/hardhat-utils/src/crypto.ts +++ b/v-next/hardhat-utils/src/crypto.ts @@ -1,5 +1,3 @@ -import { createHash } from "node:crypto"; - import { keccak256 as keccak256Impl } from "ethereum-cryptography/keccak"; /** @@ -17,17 +15,21 @@ export async function keccak256(bytes: Uint8Array): Promise { * * This function is primarily intended for generating unique identifiers from * a given input string. - * It uses the MD5 hash algorithm, which is not cryptographically secure, but + * It uses the SHA-1 hash algorithm, which is not cryptographically secure, but * is sufficient for this use case as long as the input is not generated by an * attacker. * - * Note: The exact algorithm used (MD5) is not crucial for the function's + * Note: The exact algorithm used (SHA-1) is not crucial for the function's * purpose of generating unique identifiers, and could be replaced if needed. * * @param data The input string to be hashed. - * @returns The MD5 hash of the input string, represented as a + * @returns The SHA-1 hash of the input string, represented as a * hexadecimal string. */ -export function createNonCryptographicHashId(data: string): string { - return createHash("md5").update(data).digest("hex"); +export async function createNonCryptographicHashId( + data: string, +): Promise { + const message = new TextEncoder().encode(data); + const buffer = await crypto.subtle.digest("SHA-1", message); + return Buffer.from(buffer).toString("hex"); } diff --git a/v-next/hardhat-utils/src/fs.ts b/v-next/hardhat-utils/src/fs.ts index f38224e3fa..e3f3eb4997 100644 --- a/v-next/hardhat-utils/src/fs.ts +++ b/v-next/hardhat-utils/src/fs.ts @@ -407,6 +407,50 @@ export async function getChangeTime(absolutePath: string): Promise { } } +/** + * Retrieves the last access time of a file or directory's properties. + * + * @param absolutePath The absolute path to the file or directory. + * @returns The time of the last access as a Date object. + * @throws FileNotFoundError if the path does not exist. + * @throws FileSystemAccessError for any other error. + */ +export async function getAccessTime(absolutePath: string): Promise { + try { + const stats = await fsPromises.stat(absolutePath); + return stats.atime; + } catch (e) { + ensureError(e); + if (e.code === "ENOENT") { + throw new FileNotFoundError(absolutePath, e); + } + + throw new FileSystemAccessError(e.message, e); + } +} + +/** + * Retrieves the size of a file. + * + * @param absolutePath The absolute path to the file. + * @returns The size of the file in bytes. + * @throws FileNotFoundError if the path does not exist. + * @throws FileSystemAccessError for any other error. + */ +export async function getFileSize(absolutePath: string): Promise { + try { + const stats = await fsPromises.stat(absolutePath); + return stats.size; + } catch (e) { + ensureError(e); + if (e.code === "ENOENT") { + throw new FileNotFoundError(absolutePath, e); + } + + throw new FileSystemAccessError(e.message, e); + } +} + /** * Checks if a file or directory exists. * diff --git a/v-next/hardhat-utils/test/crypto.ts b/v-next/hardhat-utils/test/crypto.ts index 77e4aca079..ac990f9b20 100644 --- a/v-next/hardhat-utils/test/crypto.ts +++ b/v-next/hardhat-utils/test/crypto.ts @@ -16,10 +16,10 @@ describe("crypto", () => { }); describe("createNonCryptographicHashId", () => { - it("Should create a non-cryptographic hash-based identifier", () => { + it("Should create a non-cryptographic hash-based identifier", async () => { assert.equal( - createNonCryptographicHashId("hello"), - "5d41402abc4b2a76b9719d911017c592", + await createNonCryptographicHashId("hello"), + "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", ); }); }); diff --git a/v-next/hardhat-utils/test/fs.ts b/v-next/hardhat-utils/test/fs.ts index b08aed91b0..e77d580b26 100644 --- a/v-next/hardhat-utils/test/fs.ts +++ b/v-next/hardhat-utils/test/fs.ts @@ -26,6 +26,8 @@ import { writeJsonFile, writeUtf8File, readBinaryFile, + getAccessTime, + getFileSize, } from "../src/fs.js"; import { useTmpDir } from "./helpers/fs.js"; @@ -735,6 +737,65 @@ describe("File system utils", () => { }); }); + describe("getAccessTime", () => { + it("Should return the access time of a file", async () => { + const filePath = path.join(getTmpDir(), "file.txt"); + await createFile(filePath); + + const stats = await fsPromises.stat(filePath); + + assert.equal( + stats.atime.getTime(), + (await getAccessTime(filePath)).getTime(), + ); + }); + + it("Should throw FileNotFoundError if the file doesn't exist", async () => { + const filePath = path.join(getTmpDir(), "not-exists.txt"); + + await assert.rejects(getAccessTime(filePath), { + name: "FileNotFoundError", + message: `File ${filePath} not found`, + }); + }); + + it("Should throw FileSystemAccessError if a different error is thrown", async () => { + const invalidPath = "\0"; + + await assert.rejects(getAccessTime(invalidPath), { + name: "FileSystemAccessError", + }); + }); + }); + + describe("getSize", () => { + it("Should return the size of a file", async () => { + const filePath = path.join(getTmpDir(), "file.txt"); + await createFile(filePath); + + const stats = await fsPromises.stat(filePath); + + assert.equal(stats.size, await getFileSize(filePath)); + }); + + it("Should throw FileNotFoundError if the file doesn't exist", async () => { + const filePath = path.join(getTmpDir(), "not-exists.txt"); + + await assert.rejects(getFileSize(filePath), { + name: "FileNotFoundError", + message: `File ${filePath} not found`, + }); + }); + + it("Should throw FileSystemAccessError if a different error is thrown", async () => { + const invalidPath = "\0"; + + await assert.rejects(getFileSize(invalidPath), { + name: "FileSystemAccessError", + }); + }); + }); + describe("exists", () => { it("Should return true if the file exists", async () => { const filePath = path.join(getTmpDir(), "file.txt"); diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/artifacts.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/artifacts.ts index c4d8735db3..ae3de814c4 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/artifacts.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/artifacts.ts @@ -104,9 +104,9 @@ declare module "@ignored/hardhat-vnext/types/artifacts" { }`; } -export function getBuildInfo( +export async function getBuildInfo( compilationJob: CompilationJob, -): SolidityBuildInfo { +): Promise { const publicSourceNameMap = Object.fromEntries( [...compilationJob.dependencyGraph.getRoots().entries()].map( ([publicSourceName, root]) => [publicSourceName, root.sourceName], @@ -115,7 +115,7 @@ export function getBuildInfo( const buildInfo: Required = { _format: "hh3-sol-build-info-1", - id: compilationJob.getBuildId(), + id: await compilationJob.getBuildId(), solcVersion: compilationJob.solcConfig.version, solcLongVersion: compilationJob.solcLongVersion, publicSourceNameMap, @@ -125,13 +125,13 @@ export function getBuildInfo( return buildInfo; } -export function getBuildInfoOutput( +export async function getBuildInfoOutput( compilationJob: CompilationJob, compilerOutput: CompilerOutput, -): SolidityBuildInfoOutput { +): Promise { const buildInfoOutput: Required = { _format: "hh3-sol-build-info-output-1", - id: compilationJob.getBuildId(), + id: await compilationJob.getBuildId(), output: compilerOutput, }; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts index d76f86ac5a..ccfffada20 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts @@ -45,6 +45,7 @@ import { getContractArtifact, getDuplicatedContractNamesDeclarationFile, } from "./artifacts.js"; +import { ObjectCache } from "./cache.js"; import { CompilationJobImplementation } from "./compilation-job.js"; import { downloadConfiguredCompilers, getCompiler } from "./compiler/index.js"; import { buildDependencyGraph } from "./dependency-graph-building.js"; @@ -58,6 +59,12 @@ import { SolcConfigSelector } from "./solc-config-selection.js"; const log = debug("hardhat:core:solidity:build-system"); +interface CompilationResult { + compilationJob: CompilationJob; + compilerOutput: CompilerOutput; + cached: boolean; +} + export interface SolidityBuildSystemOptions { readonly solidityConfig: SolidityConfig; readonly projectRoot: string; @@ -69,12 +76,18 @@ export interface SolidityBuildSystemOptions { export class SolidityBuildSystemImplementation implements SolidityBuildSystem { readonly #hooks: HookManager; readonly #options: SolidityBuildSystemOptions; + readonly #compilerOutputCache: ObjectCache; readonly #defaultConcurrency = Math.max(os.cpus().length - 1, 1); #downloadedCompilers = false; constructor(hooks: HookManager, options: SolidityBuildSystemOptions) { this.#hooks = hooks; this.#options = options; + this.#compilerOutputCache = new ObjectCache( + options.cachePath, + "compiler-output", + "v1", + ); } public async getRootFilePaths(): Promise { @@ -118,11 +131,46 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { const compilationJobs = [...new Set(compilationJobsPerFile.values())]; - // TODO: Filter the compilation jobs based on the cache + // NOTE: We precompute the build ids in parallel here, which are cached + // internally in each compilation job + await Promise.all( + compilationJobs.map(async (compilationJob) => + compilationJob.getBuildId(), + ), + ); - const results: CompilerOutput[] = await pMap( + const runCompilationJobOptions: RunCompilationJobOptions = { + quiet: options?.quiet, + }; + const results: CompilationResult[] = await pMap( compilationJobs, - (compilationJob) => this.runCompilationJob(compilationJob), + async (compilationJob) => { + const buildId = await compilationJob.getBuildId(); + + if (options?.force !== true) { + const cachedCompilerOutput = + await this.#compilerOutputCache.get(buildId); + if (cachedCompilerOutput !== undefined) { + log(`Using cached compiler output for build ${buildId}`); + return { + compilationJob, + compilerOutput: cachedCompilerOutput, + cached: true, + }; + } + } + + const compilerOutput = await this.runCompilationJob( + compilationJob, + runCompilationJobOptions, + ); + + return { + compilationJob, + compilerOutput, + cached: false, + }; + }, { concurrency: options?.concurrency ?? this.#defaultConcurrency, // An error when running the compiler is not a compilation failure, but @@ -131,10 +179,16 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { }, ); - const isSuccessfulBuild = results.every( - (result) => !this.#hasCompilationErrors(result), + const uncachedResults = results.filter((result) => !result.cached); + const uncachedSuccessfulResults = uncachedResults.filter( + (result) => !this.#hasCompilationErrors(result.compilerOutput), ); + this.#cacheCompilationResults(uncachedSuccessfulResults); + + const isSuccessfulBuild = + uncachedResults.length === uncachedSuccessfulResults.length; + const contractArtifactsGeneratedByCompilationJob: Map< CompilationJob, ReadonlyMap @@ -143,14 +197,14 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { if (isSuccessfulBuild) { log("Emitting artifacts of successful build"); await Promise.all( - compilationJobs.map(async (compilationJob, i) => { + results.map(async (result) => { const artifactsPerFile = await this.emitArtifacts( - compilationJob, - results[i], + result.compilationJob, + result.compilerOutput, ); contractArtifactsGeneratedByCompilationJob.set( - compilationJob, + result.compilationJob, artifactsPerFile, ); }), @@ -166,12 +220,9 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { const resultsMap: Map = new Map(); - for (let i = 0; i < results.length; i++) { - const compilationJob = compilationJobs[i]; - const result = results[i]; - + for (const result of results) { const contractArtifactsGenerated = isSuccessfulBuild - ? contractArtifactsGeneratedByCompilationJob.get(compilationJob) + ? contractArtifactsGeneratedByCompilationJob.get(result.compilationJob) : new Map(); assertHardhatInvariant( @@ -179,21 +230,24 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { "We emitted contract artifacts for all the jobs if the build was successful", ); - const buildId = compilationJob.getBuildId(); + const buildId = await result.compilationJob.getBuildId(); const errors = await Promise.all( - (result.errors ?? []).map((error) => - this.remapCompilerError(compilationJob, error, true), + (result.compilerOutput.errors ?? []).map((error) => + this.remapCompilerError(result.compilationJob, error, true), ), ); this.#printSolcErrorsAndWarnings(errors); - const successfulResult = !this.#hasCompilationErrors(result); + const successfulResult = !this.#hasCompilationErrors( + result.compilerOutput, + ); - for (const [publicSourceName, root] of compilationJob.dependencyGraph - .getRoots() - .entries()) { + for (const [ + publicSourceName, + root, + ] of result.compilationJob.dependencyGraph.getRoots().entries()) { if (!successfulResult) { resultsMap.set(formatRootPath(publicSourceName, root), { type: FileBuildResultType.BUILD_FAILURE, @@ -204,6 +258,18 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { continue; } + if (result.cached) { + resultsMap.set(formatRootPath(publicSourceName, root), { + type: FileBuildResultType.CACHE_HIT, + buildId, + contractArtifactsGenerated: + contractArtifactsGenerated.get(publicSourceName) ?? [], + warnings: errors, + }); + + continue; + } + resultsMap.set(formatRootPath(publicSourceName, root), { type: FileBuildResultType.BUILD_SUCCESS, buildId, @@ -385,6 +451,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { compilerOutput: CompilerOutput, ): Promise> { const result = new Map(); + const buildId = await compilationJob.getBuildId(); // We emit the artifacts for each root file, first emitting one artifact // for each contract, and then one declaration file for the entire file, @@ -414,7 +481,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { ); const artifact = getContractArtifact( - compilationJob.getBuildId(), + buildId, publicSourceName, root.sourceName, contractName, @@ -448,7 +515,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { // Once we have emitted all the contract artifacts and its declaration // file, we emit the build info file and its output file. - const buildInfoId = compilationJob.getBuildId(); + const buildInfoId = buildId; const buildInfoPath = path.join( this.#options.artifactsPath, @@ -466,7 +533,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { // concurrently, and keep their lifetimes sperated and small. await Promise.all([ (async () => { - const buildInfo = getBuildInfo(compilationJob); + const buildInfo = await getBuildInfo(compilationJob); await writeUtf8File( buildInfoPath, @@ -476,7 +543,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { ); })(), (async () => { - const buildInfoOutput = getBuildInfoOutput( + const buildInfoOutput = await getBuildInfoOutput( compilationJob, compilerOutput, ); @@ -643,6 +710,34 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { return `${error.type}: ${error.message}`.replace(/[:\s]*$/g, "").trim(); } + /** This function caches the compilation results in the compiler output cache. + * + * Please note that it does **NOT** wait for the writes/clean to finish. This + * is because we don't want to hold up the compilation process. + * + * We accept that some of the writes might fail. This is only safe because + * the write operation first writes to a temporary file, and only once that + * is done, it moves the file to the final location. + * + * If we notice that the amount of write failures is too high, or that the + * cache is not getting cleaned up often enough, we should reconsider this + * approach. + * + * @param compilationResults + */ + #cacheCompilationResults(compilationResults: CompilationResult[]): void { + void Promise.all( + compilationResults.map(async (result) => { + return this.#compilerOutputCache.set( + await result.compilationJob.getBuildId(), + result.compilerOutput, + ); + }), + ).then(() => { + return this.#compilerOutputCache.clean(); + }); + } + #printSolcErrorsAndWarnings(errors?: CompilerOutputError[]): void { if (errors === undefined) { return; @@ -687,8 +782,9 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { for (const job of compilationJobs) { const solcVersion = job.solcConfig.version; + const solcInput = job.getSolcInput(); const evmVersion = - job.getSolcInput().settings.evmVersion ?? + solcInput.settings.evmVersion ?? `Check solc ${solcVersion}'s doc for its default evm version`; let jobsPerVersion = jobsPerVersionAndEvmVersion.get(solcVersion); diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/cache.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/cache.ts new file mode 100644 index 0000000000..bdf52b3728 --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/cache.ts @@ -0,0 +1,85 @@ +import path from "node:path"; + +import { + exists, + getAccessTime, + getAllFilesMatching, + getFileSize, + move, + readJsonFile, + remove, + writeJsonFile, +} from "@ignored/hardhat-vnext-utils/fs"; + +export class ObjectCache { + readonly #path: string; + readonly #defaultMaxAgeMs: number; + readonly #defaultMaxSize: number; + + constructor( + basePath: string, + namespace: string, + version: string, + defaultMaxAgeMs: number = 7 * 24 * 60 * 60 * 1000, // 1 week + defaultMaxSize: number = 2 * 1024 * 1024 * 1024, // 2 GB + ) { + this.#path = path.join(basePath, namespace, version); + this.#defaultMaxAgeMs = defaultMaxAgeMs; + this.#defaultMaxSize = defaultMaxSize; + } + + public async set(key: string, value: T): Promise { + const filePath = path.join(this.#path, `${key}.json`); + const tmpPath = `${filePath}.tmp`; + + // NOTE: We are writing to a temporary file first because the value might + // be large and we don't want to end up with corrupted files in the cache. + await writeJsonFile(tmpPath, value); + await move(tmpPath, filePath); + } + + public async get(key: string): Promise { + const filePath = path.join(this.#path, `${key}.json`); + return (await exists(filePath)) ? readJsonFile(filePath) : undefined; + } + + public async clean(maxAgeMs?: number, maxSize?: number): Promise { + maxAgeMs ??= this.#defaultMaxAgeMs; + maxSize ??= this.#defaultMaxSize; + + const files = await getAllFilesMatching(this.#path, (file) => + file.endsWith(".json"), + ); + const fileInfos = await Promise.all( + files.map(async (file) => ({ + file, + atimeMs: (await getAccessTime(file)).getTime(), + size: await getFileSize(file), + })), + ); + + const sortedFileInfos = fileInfos.sort((a, b) => a.atimeMs - b.atimeMs); + + let size = sortedFileInfos.reduce( + (acc, fileInfo) => acc + fileInfo.size, + 0, + ); + const minAtimeMs = new Date().getTime() - maxAgeMs; + + const filesToRemove: string[] = await getAllFilesMatching( + this.#path, + (file) => file.endsWith(".json.tmp"), + ); + + for (const fileInfo of sortedFileInfos) { + if (fileInfo.atimeMs < minAtimeMs || size > maxSize) { + filesToRemove.push(fileInfo.file); + size -= fileInfo.size; + } else { + break; + } + } + + await Promise.all(filesToRemove.map(async (file) => remove(file))); + } +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/compilation-job.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/compilation-job.ts index 417b340995..4d1e237832 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/compilation-job.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/compilation-job.ts @@ -5,6 +5,7 @@ import type { SolcConfig } from "../../../../types/config.js"; import type { CompilationJob } from "../../../../types/solidity/compilation-job.js"; import type { CompilerInput } from "../../../../types/solidity/compiler-io.js"; import type { DependencyGraph } from "../../../../types/solidity/dependency-graph.js"; +import type { ResolvedFile } from "../../../../types/solidity.js"; import { createNonCryptographicHashId } from "@ignored/hardhat-vnext-utils/crypto"; @@ -20,6 +21,8 @@ export class CompilationJobImplementation implements CompilationJob { #buildId: string | undefined; #solcInput: CompilerInput | undefined; + #solcInputWithoutSources: Omit | undefined; + #resolvedFiles: ResolvedFile[] | undefined; constructor( dependencyGraph: DependencyGraphImplementation, @@ -41,21 +44,39 @@ export class CompilationJobImplementation implements CompilationJob { return this.#solcInput; } - public getBuildId(): string { + public async getBuildId(): Promise { if (this.#buildId === undefined) { - this.#buildId = this.#computeBuildId(); + this.#buildId = await this.#computeBuildId(); } return this.#buildId; } + #getSolcInputWithoutSources(): Omit { + if (this.#solcInputWithoutSources === undefined) { + this.#solcInputWithoutSources = this.#buildSolcInputWithoutSources(); + } + + return this.#solcInputWithoutSources; + } + + #getResolvedFiles(): ResolvedFile[] { + if (this.#resolvedFiles === undefined) { + // we sort the files so that we always get the same compilation input + this.#resolvedFiles = [...this.dependencyGraph.getAllFiles()].sort( + (a, b) => a.sourceName.localeCompare(b.sourceName), + ); + } + + return this.#resolvedFiles; + } + #buildSolcInput(): CompilerInput { + const solcInputWithoutSources = this.#getSolcInputWithoutSources(); + const sources: { [sourceName: string]: { content: string } } = {}; - // we sort the files so that we always get the same compilation input - const resolvedFiles = [...this.dependencyGraph.getAllFiles()].sort((a, b) => - a.sourceName.localeCompare(b.sourceName), - ); + const resolvedFiles = this.#getResolvedFiles(); for (const file of resolvedFiles) { sources[file.sourceName] = { @@ -63,6 +84,13 @@ export class CompilationJobImplementation implements CompilationJob { }; } + return { + ...solcInputWithoutSources, + sources, + }; + } + + #buildSolcInputWithoutSources(): Omit { const settings = this.solcConfig.settings; // Ideally we would be more selective with the output selection, so that @@ -90,7 +118,6 @@ export class CompilationJobImplementation implements CompilationJob { return { language: "Solidity", - sources, settings: { ...settings, evmVersion: @@ -102,18 +129,36 @@ export class CompilationJobImplementation implements CompilationJob { }; } - #computeBuildId(): string { + async #computeBuildId(): Promise { // NOTE: We type it this way so that this stop compiling if we ever change // the format of the BuildInfo type. const format: BuildInfo["_format"] = "hh3-sol-build-info-1"; + const sources: { [sourceName: string]: { hash: string } } = {}; + const resolvedFiles = this.#getResolvedFiles(); + + await Promise.all( + resolvedFiles.map(async (file) => { + sources[file.sourceName] = { + hash: await file.getContentHash(), + }; + }), + ); + + // NOTE: We need to sort the sources because the sources map might be + // populated out of order which does affect serialisation. + const sortedSources = Object.fromEntries( + Object.entries(sources).sort((a, b) => a[0].localeCompare(b[0])), + ); + // The preimage should include all the information that makes this // compilation job unique, and as this is used to identify the build info // file, it also includes its format string. const preimage = format + this.solcLongVersion + - JSON.stringify(this.getSolcInput()) + + JSON.stringify(this.#getSolcInputWithoutSources()) + + JSON.stringify(sortedSources) + JSON.stringify(this.solcConfig); return createNonCryptographicHashId(preimage); diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolved-file.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolved-file.ts new file mode 100644 index 0000000000..1cb6e10d1c --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolved-file.ts @@ -0,0 +1,66 @@ +import type { + FileContent, + NpmPackageResolvedFile, + ProjectResolvedFile, + ResolvedNpmPackage, +} from "../../../../types/solidity.js"; + +import { createNonCryptographicHashId } from "@ignored/hardhat-vnext-utils/crypto"; + +import { ResolvedFileType } from "../../../../types/solidity.js"; + +export class ProjectResolvedFileImplementation implements ProjectResolvedFile { + public readonly type: ResolvedFileType.PROJECT_FILE = + ResolvedFileType.PROJECT_FILE; + + public readonly sourceName: string; + public readonly fsPath: string; + public readonly content: FileContent; + + #contentHash?: string; + + constructor(options: Omit) { + this.sourceName = options.sourceName; + this.fsPath = options.fsPath; + this.content = options.content; + } + + public async getContentHash(): Promise { + if (this.#contentHash === undefined) { + this.#contentHash = await createNonCryptographicHashId(this.content.text); + } + + return this.#contentHash; + } +} + +export class NpmPackageResolvedFileImplementation + implements NpmPackageResolvedFile +{ + public readonly type: ResolvedFileType.NPM_PACKAGE_FILE = + ResolvedFileType.NPM_PACKAGE_FILE; + + public readonly sourceName: string; + public readonly fsPath: string; + public readonly content: FileContent; + public readonly package: ResolvedNpmPackage; + + #contentHash?: string; + + constructor( + options: Omit, + ) { + this.sourceName = options.sourceName; + this.fsPath = options.fsPath; + this.content = options.content; + this.package = options.package; + } + + public async getContentHash(): Promise { + if (this.#contentHash === undefined) { + this.#contentHash = await createNonCryptographicHashId(this.content.text); + } + + return this.#contentHash; + } +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts index 7b6130a253..c3ac1537a6 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts @@ -2,9 +2,9 @@ import type { Remapping, Resolver } from "./types.js"; import type { ResolvedNpmPackage, ResolvedFile, + FileContent, ProjectResolvedFile, NpmPackageResolvedFile, - FileContent, } from "../../../../../types/solidity/resolved-file.js"; import path from "node:path"; @@ -31,6 +31,10 @@ import * as resolve from "resolve.exports"; import { ResolvedFileType } from "../../../../../types/solidity/resolved-file.js"; import { AsyncMutex } from "../../../../core/async-mutex.js"; +import { + NpmPackageResolvedFileImplementation, + ProjectResolvedFileImplementation, +} from "../resolved-file.js"; import { applyValidRemapping, @@ -235,12 +239,12 @@ export class ResolverImplementation implements Resolver { trueCaseFsPath, ); - const resolvedFile: ProjectResolvedFile = { - type: ResolvedFileType.PROJECT_FILE, - sourceName, - fsPath: fsPathWithTheRightCasing, - content: await readFileContent(fsPathWithTheRightCasing), - }; + const resolvedFile: ProjectResolvedFile = + new ProjectResolvedFileImplementation({ + sourceName, + fsPath: fsPathWithTheRightCasing, + content: await readFileContent(fsPathWithTheRightCasing), + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -329,13 +333,13 @@ export class ResolverImplementation implements Resolver { const fsPath = path.join(npmPackage.rootFsPath, trueCaseFsPath); - const resolvedFile: NpmPackageResolvedFile = { - type: ResolvedFileType.NPM_PACKAGE_FILE, - sourceName, - fsPath, - content: await readFileContent(fsPath), - package: npmPackage, - }; + const resolvedFile: NpmPackageResolvedFile = + new NpmPackageResolvedFileImplementation({ + sourceName, + fsPath, + content: await readFileContent(fsPath), + package: npmPackage, + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -809,12 +813,12 @@ export class ResolverImplementation implements Resolver { const fsPath = path.join(this.#projectRoot, fsPathWithinTheProject); - const resolvedFile: ProjectResolvedFile = { - type: ResolvedFileType.PROJECT_FILE, - sourceName, - fsPath, - content: await readFileContent(fsPath), - }; + const resolvedFile: ProjectResolvedFile = + new ProjectResolvedFileImplementation({ + sourceName, + fsPath, + content: await readFileContent(fsPath), + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -874,13 +878,13 @@ export class ResolverImplementation implements Resolver { resolvedSubpath, ); - const resolvedFile: NpmPackageResolvedFile = { - type: ResolvedFileType.NPM_PACKAGE_FILE, - sourceName, - fsPath, - content: await readFileContent(fsPath), - package: remapping.targetNpmPackage, - }; + const resolvedFile: NpmPackageResolvedFile = + new NpmPackageResolvedFileImplementation({ + sourceName, + fsPath, + content: await readFileContent(fsPath), + package: remapping.targetNpmPackage, + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -927,13 +931,13 @@ export class ResolverImplementation implements Resolver { const filePath = path.join(from.package.rootFsPath, relativePath); - const resolvedFile: NpmPackageResolvedFile = { - type: ResolvedFileType.NPM_PACKAGE_FILE, - sourceName, - fsPath: filePath, - content: await readFileContent(filePath), - package: from.package, - }; + const resolvedFile: NpmPackageResolvedFile = + new NpmPackageResolvedFileImplementation({ + sourceName, + fsPath: filePath, + content: await readFileContent(filePath), + package: from.package, + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -982,13 +986,13 @@ export class ResolverImplementation implements Resolver { const fsPath = path.join(from.package.rootFsPath, relativeFsPath); - const resolvedFile: NpmPackageResolvedFile = { - type: ResolvedFileType.NPM_PACKAGE_FILE, - sourceName, - fsPath, - content: await readFileContent(fsPath), - package: from.package, - }; + const resolvedFile: NpmPackageResolvedFile = + new NpmPackageResolvedFileImplementation({ + sourceName, + fsPath, + content: await readFileContent(fsPath), + package: from.package, + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -1042,13 +1046,13 @@ export class ResolverImplementation implements Resolver { const fsPath = path.join(importedPackage.rootFsPath, resolvedSubpath); - const resolvedFile: NpmPackageResolvedFile = { - type: ResolvedFileType.NPM_PACKAGE_FILE, - sourceName, - fsPath, - content: await readFileContent(fsPath), - package: importedPackage, - }; + const resolvedFile: NpmPackageResolvedFile = + new NpmPackageResolvedFileImplementation({ + sourceName, + fsPath, + content: await readFileContent(fsPath), + package: importedPackage, + }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); diff --git a/v-next/hardhat/src/types/solidity/build-system.ts b/v-next/hardhat/src/types/solidity/build-system.ts index f10aaa5b4f..bb1cf09671 100644 --- a/v-next/hardhat/src/types/solidity/build-system.ts +++ b/v-next/hardhat/src/types/solidity/build-system.ts @@ -147,13 +147,9 @@ export type FileBuildResult = export interface CacheHitFileBuildResult { type: FileBuildResultType.CACHE_HIT; - // TODO: Should we remove this? It is a buildId of an already existing build - // info. - // NOTE: The buildId and contractArtifactsGenerated are useful when one uses - // the build system programatically and wants to find out what artifacts - // were generated for a given file, and with what configuration. buildId: string; contractArtifactsGenerated: string[]; + warnings: CompilerOutputError[]; } export interface SuccessfulFileBuildResult { diff --git a/v-next/hardhat/src/types/solidity/compilation-job.ts b/v-next/hardhat/src/types/solidity/compilation-job.ts index fab052de6e..d2d2aca951 100644 --- a/v-next/hardhat/src/types/solidity/compilation-job.ts +++ b/v-next/hardhat/src/types/solidity/compilation-job.ts @@ -37,5 +37,5 @@ export interface CompilationJob { * While deterministic, it shouldn't be expected to be stable across different * versions of Hardhat. */ - getBuildId(): string; + getBuildId(): Promise; } diff --git a/v-next/hardhat/src/types/solidity/resolved-file.ts b/v-next/hardhat/src/types/solidity/resolved-file.ts index 37380698f2..024ce1754d 100644 --- a/v-next/hardhat/src/types/solidity/resolved-file.ts +++ b/v-next/hardhat/src/types/solidity/resolved-file.ts @@ -48,6 +48,7 @@ export enum ResolvedFileType { */ export interface ProjectResolvedFile { type: ResolvedFileType.PROJECT_FILE; + /** * The source name of a project files is its relative path from the Hardhat * project root. @@ -63,6 +64,11 @@ export interface ProjectResolvedFile { * The file contents. */ content: FileContent; + + /** + * Return the non-cryptographic hash id of the file contents. + */ + getContentHash(): Promise; } /** @@ -90,6 +96,11 @@ export interface NpmPackageResolvedFile { * The package this file belongs to. */ package: ResolvedNpmPackage; + + /** + * Return the non-cryptographic hash id of the file contents. + */ + getContentHash(): Promise; } /** diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/.gitignore b/v-next/hardhat/test/fixture-projects/solidity/example-project/.gitignore new file mode 100644 index 0000000000..e7f801166c --- /dev/null +++ b/v-next/hardhat/test/fixture-projects/solidity/example-project/.gitignore @@ -0,0 +1,2 @@ +artifacts/ +cache/ diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/artifacts.d.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.json deleted file mode 100644 index f5fbb9e436..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "_format": "hh3-sol-build-info-1", - "id": "217a3c654dd9a8cdd3a7470ec31c8ccd", - "solcVersion": "0.7.1", - "solcLongVersion": "0.7.1+commit.f4a555be", - "publicSourceNameMap": { - "contracts/NoImports.sol": "contracts/NoImports.sol" - }, - "input": { - "language": "Solidity", - "sources": { - "contracts/NoImports.sol": { - "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.7.0;\n\ncontract NoImports {}\n" - } - }, - "settings": { - "evmVersion": "istanbul", - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata" - ], - "": ["ast"] - } - }, - "remappings": [ - "remapped/=npm/@openzeppelin/contracts@5.1.0/access/", - "@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/" - ] - } - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.output.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.output.json deleted file mode 100644 index 1002cfbefb..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/217a3c654dd9a8cdd3a7470ec31c8ccd.output.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "_format": "hh3-sol-build-info-output-1", - "id": "217a3c654dd9a8cdd3a7470ec31c8ccd", - "output": { - "contracts": { - "contracts/NoImports.sol": { - "NoImports": { - "abi": [], - "evm": { - "bytecode": { - "linkReferences": {}, - "object": "6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x3F DUP1 PUSH1 0x1D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH3 0x2FF1F9 0x2F 0xB7 GAS CALLVALUE DIV PUSH24 0xCC69A6F9FCBBD9518F40D01C4ED0FC96C42F94E05C5A6473 PUSH16 0x6C634300070100330000000000000000 ", - "sourceMap": "76:21:0:-:0;;;;;;;;;;;;;;;;;;;" - }, - "deployedBytecode": { - "immutableReferences": {}, - "linkReferences": {}, - "object": "6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH3 0x2FF1F9 0x2F 0xB7 GAS CALLVALUE DIV PUSH24 0xCC69A6F9FCBBD9518F40D01C4ED0FC96C42F94E05C5A6473 PUSH16 0x6C634300070100330000000000000000 ", - "sourceMap": "76:21:0:-:0;;;;;" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/NoImports.sol\":\"NoImports\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"contracts/NoImports.sol\":{\"keccak256\":\"0x3a28c66ec59da4cb822584ed8f391ddaff26410fb89766d49d577497823bc5ea\",\"license\":\"SEE LICENSE IN LICENSE\",\"urls\":[\"bzz-raw://fb9c7244739857b5c2b14000e0cdf717a521671457ed04d73bf4dfce002cf454\",\"dweb:/ipfs/QmZH2Ky7fy8Q87bsf7g9wcMnM1qNJQLzjcyQSG8nX84yPY\"]}},\"version\":1}" - } - } - }, - "sources": { - "contracts/NoImports.sol": { - "ast": { - "absolutePath": "contracts/NoImports.sol", - "exportedSymbols": { "NoImports": [2] }, - "id": 3, - "license": "SEE LICENSE IN LICENSE", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 1, - "literals": ["solidity", "^", "0.7", ".0"], - "nodeType": "PragmaDirective", - "src": "51:23:0" - }, - { - "abstract": false, - "baseContracts": [], - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 2, - "linearizedBaseContracts": [2], - "name": "NoImports", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 3, - "src": "76:21:0" - } - ], - "src": "51:47:0" - }, - "id": 0 - } - } - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.json deleted file mode 100644 index 1af118f1b1..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "_format": "hh3-sol-build-info-1", - "id": "652e717a54777ac28e86bc7084fcbc8f", - "solcVersion": "0.8.22", - "solcLongVersion": "0.8.22+commit.4fc1097e", - "publicSourceNameMap": { - "contracts/A.sol": "contracts/A.sol", - "contracts/B.sol": "contracts/B.sol", - "contracts/C.sol": "contracts/C.sol", - "contracts/D.sol": "contracts/D.sol", - "contracts/E.sol": "contracts/E.sol", - "contracts/UserRemappedImport.sol": "contracts/UserRemappedImport.sol" - }, - "input": { - "language": "Solidity", - "sources": { - "contracts/A.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\npragma solidity *;\n\nimport \"./B.sol\";\n\ncontract A is B {}\n" - }, - "contracts/B.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract B {}\n" - }, - "contracts/C.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"./B.sol\";\n\ncontract C {}\n\ncontract C2 {}\n" - }, - "contracts/D.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport \"./C.sol\";\n" - }, - "contracts/E.sol": { - "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport \"./C.sol\";\n" - }, - "contracts/UserRemappedImport.sol": { - "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.0;\n\nimport \"remapped/Ownable.sol\";\n" - }, - "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nabstract contract Ownable {}\n" - } - }, - "settings": { - "evmVersion": "shanghai", - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata" - ], - "": ["ast"] - } - }, - "remappings": [ - "remapped/=npm/@openzeppelin/contracts@5.1.0/access/", - "@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/" - ] - } - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.output.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.output.json deleted file mode 100644 index 74f415580d..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/build-info/652e717a54777ac28e86bc7084fcbc8f.output.json +++ /dev/null @@ -1,468 +0,0 @@ -{ - "_format": "hh3-sol-build-info-output-1", - "id": "652e717a54777ac28e86bc7084fcbc8f", - "output": { - "contracts": { - "contracts/A.sol": { - "A": { - "abi": [], - "evm": { - "bytecode": { - "functionDebugData": {}, - "generatedSources": [], - "linkReferences": {}, - "object": "6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xE JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x3E DUP1 PUSH1 0x1A PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 STATICCALL DUP1 CALLDATACOPY PUSH27 0x8A97AD93CCB004C8BA5B1944699D70AD3012DE9351C0BCA77D019 PUSH7 0x64736F6C634300 ADDMOD AND STOP CALLER ", - "sourceMap": "102:18:0:-:0;;;;;;;;;;;;;;;;;;;" - }, - "deployedBytecode": { - "functionDebugData": {}, - "generatedSources": [], - "immutableReferences": {}, - "linkReferences": {}, - "object": "60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 STATICCALL DUP1 CALLDATACOPY PUSH27 0x8A97AD93CCB004C8BA5B1944699D70AD3012DE9351C0BCA77D019 PUSH7 0x64736F6C634300 ADDMOD AND STOP CALLER ", - "sourceMap": "102:18:0:-:0;;;;;" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.8.22+commit.4fc1097e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/A.sol\":\"A\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"contracts/A.sol\":{\"keccak256\":\"0x0b6baab6b8f8c894f2ae3b4a30aa03687f5e1b5efdc79fc746d7001bc61ac2ae\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://4745a08025dd5ecdc31adc7db51210d16b9034dc41f2ed7241f98961c687e905\",\"dweb:/ipfs/QmYGbMN118xuYMR3p2YjyTMAn781mWPZXgBtG2jsYDYcPW\"]},\"contracts/B.sol\":{\"keccak256\":\"0xe3bfba24c7ab781173f217b2a770a1bf762950f485d589fef5066493a9781575\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://0265cd6edebc0e6ce4d1ed1107e40d1d0a79ad6ffc532269a9ac648a850e03b6\",\"dweb:/ipfs/QmaGSjd8xq5KotjZW1CWSRNEzXY4kWrBpDeGw16cuqNgpY\"]},\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":{\"keccak256\":\"0x8bb13fdfb1cc614eed7de55fe3b8deb01cf864a125a43b0bb083f029698b834d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98a23f280b79fe5ee104c3748e3caf90c846d8dd41c9e1b333f500ec94c6dbea\",\"dweb:/ipfs/QmTD9zsov5nahn894F69rvUKcEphBXGR51f8Qy4Z67BLyx\"]}},\"version\":1}" - } - }, - "contracts/B.sol": { - "B": { - "abi": [], - "evm": { - "bytecode": { - "functionDebugData": {}, - "generatedSources": [], - "linkReferences": {}, - "object": "6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xE JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x3E DUP1 PUSH1 0x1A PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 GASPRICE PUSH24 0x298304D45A01CB3629A2F032DA51FB0FE9D9C0B8148D8AA PUSH5 0xF0DD779C85 PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ", - "sourceMap": "118:13:1:-:0;;;;;;;;;;;;;;;;;;;" - }, - "deployedBytecode": { - "functionDebugData": {}, - "generatedSources": [], - "immutableReferences": {}, - "linkReferences": {}, - "object": "60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 GASPRICE PUSH24 0x298304D45A01CB3629A2F032DA51FB0FE9D9C0B8148D8AA PUSH5 0xF0DD779C85 PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ", - "sourceMap": "118:13:1:-:0;;;;;" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.8.22+commit.4fc1097e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/B.sol\":\"B\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"contracts/B.sol\":{\"keccak256\":\"0xe3bfba24c7ab781173f217b2a770a1bf762950f485d589fef5066493a9781575\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://0265cd6edebc0e6ce4d1ed1107e40d1d0a79ad6ffc532269a9ac648a850e03b6\",\"dweb:/ipfs/QmaGSjd8xq5KotjZW1CWSRNEzXY4kWrBpDeGw16cuqNgpY\"]},\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":{\"keccak256\":\"0x8bb13fdfb1cc614eed7de55fe3b8deb01cf864a125a43b0bb083f029698b834d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98a23f280b79fe5ee104c3748e3caf90c846d8dd41c9e1b333f500ec94c6dbea\",\"dweb:/ipfs/QmTD9zsov5nahn894F69rvUKcEphBXGR51f8Qy4Z67BLyx\"]}},\"version\":1}" - } - }, - "contracts/C.sol": { - "C": { - "abi": [], - "evm": { - "bytecode": { - "functionDebugData": {}, - "generatedSources": [], - "linkReferences": {}, - "object": "6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xE JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x3E DUP1 PUSH1 0x1A PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH7 0x220FC59F0E456B INVALID 0xED DUP1 0x4B GASLIMIT LOG0 SWAP2 0xEA SWAP12 PUSH5 0x289092EC82 SELFBALANCE PUSH7 0xFEE8AF886447DE PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ", - "sourceMap": "83:13:2:-:0;;;;;;;;;;;;;;;;;;;" - }, - "deployedBytecode": { - "functionDebugData": {}, - "generatedSources": [], - "immutableReferences": {}, - "linkReferences": {}, - "object": "60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH7 0x220FC59F0E456B INVALID 0xED DUP1 0x4B GASLIMIT LOG0 SWAP2 0xEA SWAP12 PUSH5 0x289092EC82 SELFBALANCE PUSH7 0xFEE8AF886447DE PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ", - "sourceMap": "83:13:2:-:0;;;;;" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.8.22+commit.4fc1097e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/C.sol\":\"C\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"contracts/B.sol\":{\"keccak256\":\"0xe3bfba24c7ab781173f217b2a770a1bf762950f485d589fef5066493a9781575\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://0265cd6edebc0e6ce4d1ed1107e40d1d0a79ad6ffc532269a9ac648a850e03b6\",\"dweb:/ipfs/QmaGSjd8xq5KotjZW1CWSRNEzXY4kWrBpDeGw16cuqNgpY\"]},\"contracts/C.sol\":{\"keccak256\":\"0xc59a3c8bafbab383c5b64ed325f6a3a61ec9fe36d5a375f2723cfd272c819675\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://294d208fbc2235f9e93c60f0caca7723bf4a08397cc5932783a89d72a2319c42\",\"dweb:/ipfs/QmUn6fonDgB3rZ84UjUNnY65vRm28qPTMKknFcVY6r7E28\"]},\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":{\"keccak256\":\"0x8bb13fdfb1cc614eed7de55fe3b8deb01cf864a125a43b0bb083f029698b834d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98a23f280b79fe5ee104c3748e3caf90c846d8dd41c9e1b333f500ec94c6dbea\",\"dweb:/ipfs/QmTD9zsov5nahn894F69rvUKcEphBXGR51f8Qy4Z67BLyx\"]}},\"version\":1}" - }, - "C2": { - "abi": [], - "evm": { - "bytecode": { - "functionDebugData": {}, - "generatedSources": [], - "linkReferences": {}, - "object": "6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xE JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x3E DUP1 PUSH1 0x1A PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xC7 0x2A 0xEA PUSH6 0xF1253BB034AD PUSH5 0x6E28FF9B53 0xB7 0xA7 0xEF REVERT CREATE RETURNDATASIZE REVERT PC PUSH19 0x6D59B7083D8D9C64736F6C6343000816003300 ", - "sourceMap": "98:14:2:-:0;;;;;;;;;;;;;;;;;;;" - }, - "deployedBytecode": { - "functionDebugData": {}, - "generatedSources": [], - "immutableReferences": {}, - "linkReferences": {}, - "object": "60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xC7 0x2A 0xEA PUSH6 0xF1253BB034AD PUSH5 0x6E28FF9B53 0xB7 0xA7 0xEF REVERT CREATE RETURNDATASIZE REVERT PC PUSH19 0x6D59B7083D8D9C64736F6C6343000816003300 ", - "sourceMap": "98:14:2:-:0;;;;;" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.8.22+commit.4fc1097e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/C.sol\":\"C2\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"contracts/B.sol\":{\"keccak256\":\"0xe3bfba24c7ab781173f217b2a770a1bf762950f485d589fef5066493a9781575\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://0265cd6edebc0e6ce4d1ed1107e40d1d0a79ad6ffc532269a9ac648a850e03b6\",\"dweb:/ipfs/QmaGSjd8xq5KotjZW1CWSRNEzXY4kWrBpDeGw16cuqNgpY\"]},\"contracts/C.sol\":{\"keccak256\":\"0xc59a3c8bafbab383c5b64ed325f6a3a61ec9fe36d5a375f2723cfd272c819675\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://294d208fbc2235f9e93c60f0caca7723bf4a08397cc5932783a89d72a2319c42\",\"dweb:/ipfs/QmUn6fonDgB3rZ84UjUNnY65vRm28qPTMKknFcVY6r7E28\"]},\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":{\"keccak256\":\"0x8bb13fdfb1cc614eed7de55fe3b8deb01cf864a125a43b0bb083f029698b834d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98a23f280b79fe5ee104c3748e3caf90c846d8dd41c9e1b333f500ec94c6dbea\",\"dweb:/ipfs/QmTD9zsov5nahn894F69rvUKcEphBXGR51f8Qy4Z67BLyx\"]}},\"version\":1}" - } - }, - "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol": { - "Ownable": { - "abi": [], - "evm": { - "bytecode": { - "functionDebugData": {}, - "generatedSources": [], - "linkReferences": {}, - "object": "", - "opcodes": "", - "sourceMap": "" - }, - "deployedBytecode": { - "functionDebugData": {}, - "generatedSources": [], - "immutableReferences": {}, - "linkReferences": {}, - "object": "", - "opcodes": "", - "sourceMap": "" - }, - "methodIdentifiers": {} - }, - "metadata": "{\"compiler\":{\"version\":\"0.8.22+commit.4fc1097e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":\"Ownable\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.1.0/\",\":remapped/=npm/@openzeppelin/contracts@5.1.0/access/\"]},\"sources\":{\"npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol\":{\"keccak256\":\"0x8bb13fdfb1cc614eed7de55fe3b8deb01cf864a125a43b0bb083f029698b834d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98a23f280b79fe5ee104c3748e3caf90c846d8dd41c9e1b333f500ec94c6dbea\",\"dweb:/ipfs/QmTD9zsov5nahn894F69rvUKcEphBXGR51f8Qy4Z67BLyx\"]}},\"version\":1}" - } - } - }, - "sources": { - "contracts/A.sol": { - "ast": { - "absolutePath": "contracts/A.sol", - "exportedSymbols": { "A": [6], "B": [10], "Ownable": [27] }, - "id": 7, - "license": "UNLICENSED", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 1, - "literals": ["solidity", "^", "0.8", ".0"], - "nodeType": "PragmaDirective", - "src": "39:23:0" - }, - { - "id": 2, - "literals": ["solidity", "*"], - "nodeType": "PragmaDirective", - "src": "63:18:0" - }, - { - "absolutePath": "contracts/B.sol", - "file": "./B.sol", - "id": 3, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 7, - "sourceUnit": 11, - "src": "83:17:0", - "symbolAliases": [], - "unitAlias": "" - }, - { - "abstract": false, - "baseContracts": [ - { - "baseName": { - "id": 4, - "name": "B", - "nameLocations": ["116:1:0"], - "nodeType": "IdentifierPath", - "referencedDeclaration": 10, - "src": "116:1:0" - }, - "id": 5, - "nodeType": "InheritanceSpecifier", - "src": "116:1:0" - } - ], - "canonicalName": "A", - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 6, - "linearizedBaseContracts": [6, 10], - "name": "A", - "nameLocation": "111:1:0", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 7, - "src": "102:18:0", - "usedErrors": [], - "usedEvents": [] - } - ], - "src": "39:82:0" - }, - "id": 0 - }, - "contracts/B.sol": { - "ast": { - "absolutePath": "contracts/B.sol", - "exportedSymbols": { "B": [10], "Ownable": [27] }, - "id": 11, - "license": "UNLICENSED", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 8, - "literals": ["solidity", "^", "0.8", ".0"], - "nodeType": "PragmaDirective", - "src": "39:23:1" - }, - { - "absolutePath": "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol", - "file": "@openzeppelin/contracts/access/Ownable.sol", - "id": 9, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 11, - "sourceUnit": 28, - "src": "64:52:1", - "symbolAliases": [], - "unitAlias": "" - }, - { - "abstract": false, - "baseContracts": [], - "canonicalName": "B", - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 10, - "linearizedBaseContracts": [10], - "name": "B", - "nameLocation": "127:1:1", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 11, - "src": "118:13:1", - "usedErrors": [], - "usedEvents": [] - } - ], - "src": "39:93:1" - }, - "id": 1 - }, - "contracts/C.sol": { - "ast": { - "absolutePath": "contracts/C.sol", - "exportedSymbols": { - "B": [10], - "C": [14], - "C2": [15], - "Ownable": [27] - }, - "id": 16, - "license": "UNLICENSED", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 12, - "literals": ["solidity", "^", "0.8", ".0"], - "nodeType": "PragmaDirective", - "src": "39:23:2" - }, - { - "absolutePath": "contracts/B.sol", - "file": "./B.sol", - "id": 13, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 16, - "sourceUnit": 11, - "src": "64:17:2", - "symbolAliases": [], - "unitAlias": "" - }, - { - "abstract": false, - "baseContracts": [], - "canonicalName": "C", - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 14, - "linearizedBaseContracts": [14], - "name": "C", - "nameLocation": "92:1:2", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 16, - "src": "83:13:2", - "usedErrors": [], - "usedEvents": [] - }, - { - "abstract": false, - "baseContracts": [], - "canonicalName": "C2", - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 15, - "linearizedBaseContracts": [15], - "name": "C2", - "nameLocation": "107:2:2", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 16, - "src": "98:14:2", - "usedErrors": [], - "usedEvents": [] - } - ], - "src": "39:74:2" - }, - "id": 2 - }, - "contracts/D.sol": { - "ast": { - "absolutePath": "contracts/D.sol", - "exportedSymbols": { - "B": [10], - "C": [14], - "C2": [15], - "Ownable": [27] - }, - "id": 19, - "license": "UNLICENSED", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 17, - "literals": ["solidity", "^", "0.8", ".22"], - "nodeType": "PragmaDirective", - "src": "39:24:3" - }, - { - "absolutePath": "contracts/C.sol", - "file": "./C.sol", - "id": 18, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 19, - "sourceUnit": 16, - "src": "65:17:3", - "symbolAliases": [], - "unitAlias": "" - } - ], - "src": "39:44:3" - }, - "id": 3 - }, - "contracts/E.sol": { - "ast": { - "absolutePath": "contracts/E.sol", - "exportedSymbols": { - "B": [10], - "C": [14], - "C2": [15], - "Ownable": [27] - }, - "id": 22, - "license": "UNLICENSED", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 20, - "literals": ["solidity", "^", "0.8", ".22"], - "nodeType": "PragmaDirective", - "src": "39:24:4" - }, - { - "absolutePath": "contracts/C.sol", - "file": "./C.sol", - "id": 21, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 22, - "sourceUnit": 16, - "src": "65:17:4", - "symbolAliases": [], - "unitAlias": "" - } - ], - "src": "39:44:4" - }, - "id": 4 - }, - "contracts/UserRemappedImport.sol": { - "ast": { - "absolutePath": "contracts/UserRemappedImport.sol", - "exportedSymbols": { "Ownable": [27] }, - "id": 25, - "license": "SEE LICENSE IN LICENSE", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 23, - "literals": ["solidity", "^", "0.8", ".0"], - "nodeType": "PragmaDirective", - "src": "51:23:5" - }, - { - "absolutePath": "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol", - "file": "remapped/Ownable.sol", - "id": 24, - "nameLocation": "-1:-1:-1", - "nodeType": "ImportDirective", - "scope": 25, - "sourceUnit": 28, - "src": "76:30:5", - "symbolAliases": [], - "unitAlias": "" - } - ], - "src": "51:56:5" - }, - "id": 5 - }, - "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol": { - "ast": { - "absolutePath": "npm/@openzeppelin/contracts@5.1.0/access/Ownable.sol", - "exportedSymbols": { "Ownable": [27] }, - "id": 28, - "license": "MIT", - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 26, - "literals": ["solidity", "^", "0.8", ".20"], - "nodeType": "PragmaDirective", - "src": "102:24:6" - }, - { - "abstract": true, - "baseContracts": [], - "canonicalName": "Ownable", - "contractDependencies": [], - "contractKind": "contract", - "fullyImplemented": true, - "id": 27, - "linearizedBaseContracts": [27], - "name": "Ownable", - "nameLocation": "146:7:6", - "nodeType": "ContractDefinition", - "nodes": [], - "scope": 28, - "src": "128:28:6", - "usedErrors": [], - "usedEvents": [] - } - ], - "src": "102:55:6" - }, - "id": 6 - } - } - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/A.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/A.json deleted file mode 100644 index 4d2c2f78a7..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/A.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "A", - "sourceName": "contracts/A.sol", - "abi": [], - "bytecode": "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033", - "deployedBytecode": "0x60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "contracts/A.sol", - "buildInfoId": "652e717a54777ac28e86bc7084fcbc8f" -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/artifacts.d.ts deleted file mode 100644 index 8f6b7b4d2d..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/A.sol/artifacts.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file was autogenerated by Hardhat-viem, do not edit it. -// prettier-ignore -// tslint:disable -// eslint-disable -// biome-ignore format: see above - -export interface A$Type { - readonly _format: "hh3-artifact-1"; - readonly contractName: "A"; - readonly sourceName: "contracts/A.sol"; - readonly abi: []; - readonly bytecode: "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033"; - readonly deployedBytecode: "0x60806040525f80fdfea2646970667358221220fa80377a08a97ad93ccb004c8ba5b1944699d70ad3012de9351c0bca77d0196664736f6c63430008160033"; - readonly linkReferences: {}; - readonly deployedLinkReferences: {}; - readonly immutableReferences: {}; - readonly inputSourceName: "contracts/A.sol"; - readonly buildInfoId: "652e717a54777ac28e86bc7084fcbc8f"; -} - -import "@ignored/hardhat-vnext/types/artifacts"; -declare module "@ignored/hardhat-vnext/types/artifacts" { - interface ArtifactMap { - ["A"]: A$Type; - ["contracts/A.sol:A"]: A$Type; - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/B.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/B.json deleted file mode 100644 index c16143764f..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/B.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "B", - "sourceName": "contracts/B.sol", - "abi": [], - "bytecode": "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033", - "deployedBytecode": "0x60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "contracts/B.sol", - "buildInfoId": "652e717a54777ac28e86bc7084fcbc8f" -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/artifacts.d.ts deleted file mode 100644 index 6f296c3a8d..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/B.sol/artifacts.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file was autogenerated by Hardhat-viem, do not edit it. -// prettier-ignore -// tslint:disable -// eslint-disable -// biome-ignore format: see above - -export interface B$Type { - readonly _format: "hh3-artifact-1"; - readonly contractName: "B"; - readonly sourceName: "contracts/B.sol"; - readonly abi: []; - readonly bytecode: "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033"; - readonly deployedBytecode: "0x60806040525f80fdfea26469706673582212203a770298304d45a01cb3629a2f032da51fb0fe9d9c0b8148d8aa64f0dd779c8564736f6c63430008160033"; - readonly linkReferences: {}; - readonly deployedLinkReferences: {}; - readonly immutableReferences: {}; - readonly inputSourceName: "contracts/B.sol"; - readonly buildInfoId: "652e717a54777ac28e86bc7084fcbc8f"; -} - -import "@ignored/hardhat-vnext/types/artifacts"; -declare module "@ignored/hardhat-vnext/types/artifacts" { - interface ArtifactMap { - ["B"]: B$Type; - ["contracts/B.sol:B"]: B$Type; - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C.json deleted file mode 100644 index 6dd16a15f2..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "C", - "sourceName": "contracts/C.sol", - "abi": [], - "bytecode": "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033", - "deployedBytecode": "0x60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "contracts/C.sol", - "buildInfoId": "652e717a54777ac28e86bc7084fcbc8f" -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C2.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C2.json deleted file mode 100644 index 693b153716..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/C2.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "C2", - "sourceName": "contracts/C.sol", - "abi": [], - "bytecode": "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033", - "deployedBytecode": "0x60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "contracts/C.sol", - "buildInfoId": "652e717a54777ac28e86bc7084fcbc8f" -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/artifacts.d.ts deleted file mode 100644 index 1b7e70040a..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/C.sol/artifacts.d.ts +++ /dev/null @@ -1,43 +0,0 @@ -// This file was autogenerated by Hardhat-viem, do not edit it. -// prettier-ignore -// tslint:disable -// eslint-disable -// biome-ignore format: see above - -export interface C$Type { - readonly _format: "hh3-artifact-1"; - readonly contractName: "C"; - readonly sourceName: "contracts/C.sol"; - readonly abi: []; - readonly bytecode: "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033"; - readonly deployedBytecode: "0x60806040525f80fdfea264697066735822122066220fc59f0e456bfeed804b45a091ea9b64289092ec824766fee8af886447de64736f6c63430008160033"; - readonly linkReferences: {}; - readonly deployedLinkReferences: {}; - readonly immutableReferences: {}; - readonly inputSourceName: "contracts/C.sol"; - readonly buildInfoId: "652e717a54777ac28e86bc7084fcbc8f"; -} - -export interface C2$Type { - readonly _format: "hh3-artifact-1"; - readonly contractName: "C2"; - readonly sourceName: "contracts/C.sol"; - readonly abi: []; - readonly bytecode: "0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033"; - readonly deployedBytecode: "0x60806040525f80fdfea2646970667358221220c72aea65f1253bb034ad646e28ff9b53b7a7effdf03dfd58726d59b7083d8d9c64736f6c63430008160033"; - readonly linkReferences: {}; - readonly deployedLinkReferences: {}; - readonly immutableReferences: {}; - readonly inputSourceName: "contracts/C.sol"; - readonly buildInfoId: "652e717a54777ac28e86bc7084fcbc8f"; -} - -import "@ignored/hardhat-vnext/types/artifacts"; -declare module "@ignored/hardhat-vnext/types/artifacts" { - interface ArtifactMap { - ["C"]: C$Type; - ["C2"]: C2$Type; - ["contracts/C.sol:C"]: C$Type; - ["contracts/C.sol:C2"]: C2$Type; - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/D.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/D.sol/artifacts.d.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/E.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/E.sol/artifacts.d.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/NoImports.json b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/NoImports.json deleted file mode 100644 index a6f7a73941..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/NoImports.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "NoImports", - "sourceName": "contracts/NoImports.sol", - "abi": [], - "bytecode": "0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033", - "deployedBytecode": "0x6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "contracts/NoImports.sol", - "buildInfoId": "217a3c654dd9a8cdd3a7470ec31c8ccd" -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/artifacts.d.ts deleted file mode 100644 index ae83e2b9d4..0000000000 --- a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/NoImports.sol/artifacts.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file was autogenerated by Hardhat-viem, do not edit it. -// prettier-ignore -// tslint:disable -// eslint-disable -// biome-ignore format: see above - -export interface NoImports$Type { - readonly _format: "hh3-artifact-1"; - readonly contractName: "NoImports"; - readonly sourceName: "contracts/NoImports.sol"; - readonly abi: []; - readonly bytecode: "0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033"; - readonly deployedBytecode: "0x6080604052600080fdfea2646970667358221220622ff1f92fb75a340477cc69a6f9fcbbd9518f40d01c4ed0fc96c42f94e05c5a64736f6c63430007010033"; - readonly linkReferences: {}; - readonly deployedLinkReferences: {}; - readonly immutableReferences: {}; - readonly inputSourceName: "contracts/NoImports.sol"; - readonly buildInfoId: "217a3c654dd9a8cdd3a7470ec31c8ccd"; -} - -import "@ignored/hardhat-vnext/types/artifacts"; -declare module "@ignored/hardhat-vnext/types/artifacts" { - interface ArtifactMap { - ["NoImports"]: NoImports$Type; - ["contracts/NoImports.sol:NoImports"]: NoImports$Type; - } -} diff --git a/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/UserRemappedImport.sol/artifacts.d.ts b/v-next/hardhat/test/fixture-projects/solidity/example-project/artifacts/contracts/UserRemappedImport.sol/artifacts.d.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/build-system.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/build-system.ts index 8c71129fa6..3b6e048f72 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/build-system.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/build-system.ts @@ -1,4 +1,5 @@ -import type { HardhatRuntimeEnvironment } from "../../../../../src/types/hre.js"; +import type { SolidityConfig } from "../../../../../src/types/config.js"; +import type { HookContext } from "../../../../../src/types/hooks.js"; import type { SolidityBuildInfoOutput, SolidityBuildSystem, @@ -6,55 +7,41 @@ import type { import assert from "node:assert/strict"; import path from "node:path"; -import { beforeEach, describe, it } from "node:test"; +import { before, beforeEach, describe, it, mock } from "node:test"; import { exists, getAllFilesMatching, readJsonFile, + remove, } from "@ignored/hardhat-vnext-utils/fs"; import { getTmpDir, useFixtureProject, } from "@nomicfoundation/hardhat-test-utils"; -import { createHardhatRuntimeEnvironment } from "../../../../../src/hre.js"; +import { SolidityBuildSystemImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/build-system.js"; +import { HookManagerImplementation } from "../../../../../src/internal/core/hook-manager.js"; async function emitArtifacts(solidity: SolidityBuildSystem): Promise { const rootFilePaths = await solidity.getRootFilePaths(); const compilationJobs = await solidity.getCompilationJobs(rootFilePaths, { mergeCompilationJobs: true, - quiet: false, + quiet: true, }); assert.ok(compilationJobs instanceof Map, "compilationJobs should be a Map"); - const prebuiltArtifactsPath = path.join(process.cwd(), "artifacts"); + const artifactsPath = path.join(process.cwd(), "artifacts"); const buildIds = new Set(); for (const compilationJob of compilationJobs.values()) { - const buildId = compilationJob.getBuildId(); + const buildId = await compilationJob.getBuildId(); if (!buildIds.has(buildId)) { buildIds.add(buildId); - - const prebuiltOutputPath = path.join( - prebuiltArtifactsPath, - "build-info", - `${compilationJob.getBuildId()}.output.json`, + const buildInfoOutput = await readJsonFile( + path.join(artifactsPath, "build-info", `${buildId}.output.json`), ); - - if (!(await exists(prebuiltOutputPath))) { - throw new Error( - `This tests will fail as they expect the artifacts to be already built - -Try deleting the folder ${prebuiltArtifactsPath}, uncommenting the before in this file, and running again. -`, - ); - } - - const buildInfoOutput = - await readJsonFile(prebuiltOutputPath); - await solidity.emitArtifacts(compilationJob, buildInfoOutput.output); } } @@ -67,57 +54,76 @@ describe( skip: process.env.HARDHAT_DISABLE_SLOW_TESTS === "true", }, () => { - let artifactsPath: string; - let hre: HardhatRuntimeEnvironment; + let actualArtifactsPath: string; + let actualCachePath: string; + let expectedArtifactsPath: string; + let expectedCachePath: string; + let solidity: SolidityBuildSystemImplementation; useFixtureProject("solidity/example-project"); - const solidityConfig = { + const solidityConfig: SolidityConfig = { profiles: { default: { compilers: [ { version: "0.8.22", + settings: {}, }, { version: "0.7.1", + settings: {}, }, ], + overrides: {}, }, }, + dependenciesToCompile: [], remappings: ["remapped/=npm/@openzeppelin/contracts@5.1.0/access/"], }; - // Uncomment to recompile the prebuilt artifacts - // before(async () => { - // hre = await createHardhatRuntimeEnvironment( - // { - // solidity: solidityConfig, - // }, - // { config: path.join(process.cwd(), "hardhat.config.ts") }, - // ); - // - // await hre.tasks.getTask("compile").run({}); - // }); + before(async () => { + expectedArtifactsPath = path.join(process.cwd(), "artifacts"); + expectedCachePath = path.join(process.cwd(), "cache"); + await remove(expectedArtifactsPath); + await remove(expectedCachePath); + const hooks = new HookManagerImplementation(process.cwd(), []); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We don't care about hooks in this context + hooks.setContext({} as HookContext); + solidity = new SolidityBuildSystemImplementation(hooks, { + solidityConfig, + projectRoot: process.cwd(), + soliditySourcesPaths: [path.join(process.cwd(), "contracts")], + artifactsPath: expectedArtifactsPath, + cachePath: expectedCachePath, + }); + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + }); beforeEach(async () => { const tmpDir = await getTmpDir("solidity-build-system-implementation"); - artifactsPath = path.join(tmpDir, "artifacts"); - const cachePath = path.join(tmpDir, "cache"); - hre = await createHardhatRuntimeEnvironment({ - paths: { - artifacts: artifactsPath, - cache: cachePath, - }, - solidity: solidityConfig, + actualArtifactsPath = path.join(tmpDir, "artifacts"); + actualCachePath = path.join(tmpDir, "cache"); + const hooks = new HookManagerImplementation(process.cwd(), []); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We don't care about hooks in this context + hooks.setContext({} as HookContext); + solidity = new SolidityBuildSystemImplementation(hooks, { + solidityConfig, + projectRoot: process.cwd(), + soliditySourcesPaths: [path.join(process.cwd(), "contracts")], + artifactsPath: actualArtifactsPath, + cachePath: actualCachePath, }); }); describe("emitArtifacts", () => { it("should successfully emit the artifacts", async () => { - await emitArtifacts(hre.solidity); - - const expectedArtifactsPath = path.join(process.cwd(), "artifacts"); + await emitArtifacts(solidity); const expectedArtifactPaths = await getAllFilesMatching( expectedArtifactsPath, @@ -130,7 +136,7 @@ describe( expectedArtifactPath, ); const actualArtifactPath = path.join( - artifactsPath, + actualArtifactsPath, relativeArtifactPath, ); assert.ok( @@ -149,73 +155,226 @@ describe( }); describe("cleanupArtifacts", () => { - let artifactPathsBefore: string[]; + let actualArtifactPathsBefore: string[]; let duplicatedContractNamesDeclarationFilePath: string; beforeEach(async () => { - await emitArtifacts(hre.solidity); - artifactPathsBefore = await getAllFilesMatching(artifactsPath); + await emitArtifacts(solidity); + actualArtifactPathsBefore = + await getAllFilesMatching(actualArtifactsPath); duplicatedContractNamesDeclarationFilePath = path.join( - artifactsPath, + actualArtifactsPath, "artifacts.d.ts", ); }); it("should clean up no artifacts when given all root file paths", async () => { - await hre.solidity.cleanupArtifacts( - await hre.solidity.getRootFilePaths(), - ); + await solidity.cleanupArtifacts(await solidity.getRootFilePaths()); - const artifactPathsAfter = await getAllFilesMatching( - artifactsPath, + const actualArtifactPathsAfter = await getAllFilesMatching( + actualArtifactsPath, (f) => f !== duplicatedContractNamesDeclarationFilePath, ); assert.deepEqual( - artifactPathsAfter, - artifactPathsBefore, + actualArtifactPathsAfter, + actualArtifactPathsBefore, "No artifacts should be cleaned up", ); }); it("should not clean up some of the artifacts when given a subset of all root file paths", async () => { - const rootFilePaths = await hre.solidity.getRootFilePaths(); + const rootFilePaths = await solidity.getRootFilePaths(); const rootFilePathsToCleanUp = rootFilePaths.slice( 0, rootFilePaths.length - 1, ); - await hre.solidity.cleanupArtifacts(rootFilePathsToCleanUp); + await solidity.cleanupArtifacts(rootFilePathsToCleanUp); - const artifactPathsAfter = await getAllFilesMatching( - artifactsPath, + const actualArtifactPathsAfter = await getAllFilesMatching( + actualArtifactsPath, (f) => f !== duplicatedContractNamesDeclarationFilePath, ); assert.ok( - artifactPathsBefore.length > artifactPathsAfter.length, + actualArtifactPathsBefore.length > actualArtifactPathsAfter.length, "Some artifacts should be cleaned up", ); }); it("should clean up all the artifacts when given no root file paths", async () => { - await hre.solidity.cleanupArtifacts([]); + await solidity.cleanupArtifacts([]); - const artifactPathsAfter = await getAllFilesMatching( - artifactsPath, + const actualArtifactPathsAfter = await getAllFilesMatching( + actualArtifactsPath, (f) => f !== duplicatedContractNamesDeclarationFilePath, ); assert.ok( - artifactPathsBefore.length > 0, + actualArtifactPathsBefore.length > 0, "There should be some artifacts to clean up", ); assert.deepEqual( - artifactPathsAfter, + actualArtifactPathsAfter, [], "All artifacts should be cleaned up", ); }); }); + + describe("build", () => { + let expectedArtifactPaths: string[]; + let expectedCachePaths: string[]; + + before(async () => { + expectedArtifactPaths = ( + await getAllFilesMatching(expectedArtifactsPath) + ).map((f) => path.relative(expectedArtifactsPath, f)); + expectedCachePaths = (await getAllFilesMatching(expectedCachePath)).map( + (f) => path.relative(expectedCachePath, f), + ); + }); + + it("should build the project deterministically", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + const actualArtifactPaths = ( + await getAllFilesMatching(actualArtifactsPath) + ).map((f) => path.relative(actualArtifactsPath, f)); + const actualCachePaths = ( + await getAllFilesMatching(actualCachePath) + ).map((f) => path.relative(actualCachePath, f)); + + assert.deepEqual( + actualArtifactPaths, + expectedArtifactPaths, + "Artifacts should be the same", + ); + assert.deepEqual( + actualCachePaths, + expectedCachePaths, + "Cache should be the same", + ); + }); + + it("should not recompile the project when given the same input as in the previous call", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + const runCompilationJobSpy = mock.method(solidity, "runCompilationJob"); + + await solidity.build(rootFilePaths, { + force: false, + mergeCompilationJobs: true, + quiet: true, + }); + + assert.equal(runCompilationJobSpy.mock.callCount(), 0); + }); + + it("should recompile the project when given the same input as in the previous call but the force flag is set", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + const runCompilationJobSpy = mock.method(solidity, "runCompilationJob"); + + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + assert.equal(runCompilationJobSpy.mock.callCount(), 2); + }); + + it("should not recompile the project when the input changed but the generated compilation jobs are the subset of the previous ones", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + const runCompilationJobSpy = mock.method(solidity, "runCompilationJob"); + + await solidity.build( + rootFilePaths.filter((f) => path.basename(f) !== "NoImports.sol"), + { + force: false, + mergeCompilationJobs: true, + quiet: true, + }, + ); + + assert.equal(runCompilationJobSpy.mock.callCount(), 0); + }); + + it("should recompile the project when the input changed and the generated compilation jobs changed", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + const runCompilationJobSpy = mock.method(solidity, "runCompilationJob"); + + await solidity.build( + rootFilePaths.filter((f) => path.basename(f) !== "A.sol"), + { + force: false, + mergeCompilationJobs: true, + quiet: true, + }, + ); + + assert.equal(runCompilationJobSpy.mock.callCount(), 1); + }); + + it("should not recompile the project when the input is the same as in one of the previous calls", async () => { + const rootFilePaths = await solidity.getRootFilePaths(); + await solidity.build(rootFilePaths, { + force: true, + mergeCompilationJobs: true, + quiet: true, + }); + + await solidity.build( + rootFilePaths.filter((f) => path.basename(f) !== "A.sol"), + { + force: false, + mergeCompilationJobs: true, + quiet: true, + }, + ); + + const runCompilationJobSpy = mock.method(solidity, "runCompilationJob"); + + await solidity.build( + rootFilePaths.filter((f) => path.basename(f) !== "A.sol"), + { + force: false, + mergeCompilationJobs: true, + quiet: true, + }, + ); + + assert.equal(runCompilationJobSpy.mock.callCount(), 0); + }); + }); }, ); diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/cache.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/cache.ts new file mode 100644 index 0000000000..4d87a7d7e4 --- /dev/null +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/cache.ts @@ -0,0 +1,114 @@ +import assert from "node:assert/strict"; +import { randomUUID } from "node:crypto"; +import path from "node:path"; +import { beforeEach, describe, it } from "node:test"; + +import { + getAllFilesMatching, + getFileSize, +} from "@ignored/hardhat-vnext-utils/fs"; +import { useTmpDir } from "@nomicfoundation/hardhat-test-utils"; + +import { ObjectCache } from "../../../../../src/internal/builtin-plugins/solidity/build-system/cache.js"; + +describe("ObjectCache", () => { + let cache: ObjectCache; + let cachePath: string; + let testKey: string; + let testValue: string; + + useTmpDir("object-cache"); + + beforeEach(async () => { + cachePath = path.join(process.cwd(), "cache"); + cache = new ObjectCache(cachePath, "test", "v1"); + testKey = randomUUID(); + testValue = "testValue"; + await cache.set(testKey, testValue); + }); + + describe("get", () => { + it("should return undefined if the key is not present", async () => { + assert.equal(await cache.get(randomUUID()), undefined); + }); + it("should return the value if the key is present", async () => { + assert.equal(await cache.get(testKey), testValue); + }); + it("should return undefined if the key is present under a different namespace", async () => { + const newCache = new ObjectCache(cachePath, "newTest", "v1"); + assert.equal(await newCache.get(testKey), undefined); + }); + it("should return undefined if the key is present under a different version", async () => { + const newCache = new ObjectCache(cachePath, "test", "v2"); + assert.equal(await newCache.get(testKey), undefined); + }); + }); + + describe("set", () => { + it("should set the value if the key is not present", async () => { + const randomKey = randomUUID(); + assert.equal(await cache.get(randomKey), undefined); + await cache.set(randomKey, "randomValue"); + assert.equal(await cache.get(randomKey), "randomValue"); + }); + it("should overwrite the value if the key is present", async () => { + const randomKey = randomUUID(); + await cache.set(randomKey, "randomValue"); + assert.equal(await cache.get(randomKey), "randomValue"); + await cache.set(randomKey, "newRandomValue"); + assert.equal(await cache.get(randomKey), "newRandomValue"); + }); + }); + + describe("clean", () => { + it("should remove nothing with the default settings", async () => { + const filesBefore = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesBefore, []); + await cache.clean(); + const filesAfter = await getAllFilesMatching(cachePath); + assert.deepEqual(filesAfter, filesBefore); + }); + + it("should remove everything with the max age set to 0", async () => { + const filesBefore = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesBefore, []); + // NOTE: We're waiting a little so that the file's atime is different + await new Promise((resolve) => setTimeout(resolve, 10)); + await cache.clean(0); + const filesAfter = await getAllFilesMatching(cachePath); + assert.deepEqual(filesAfter, []); + }); + + it("should remove everything with the max size set to 0", async () => { + const filesBefore = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesBefore, []); + await cache.clean(undefined, 0); + const filesAfter = await getAllFilesMatching(cachePath); + assert.deepEqual(filesAfter, []); + }); + + it("should remove something with the max age set to some value", async () => { + const filesBefore = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesBefore, []); + // NOTE: We're waiting a little so that the file's atime is different + await new Promise((resolve) => setTimeout(resolve, 10)); + await cache.set(randomUUID(), testValue); + await cache.clean(10); + const filesAfter = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesAfter, []); + assert.notDeepEqual(filesAfter, filesBefore); + }); + + it("should remove something with the max size set to some value", async () => { + const filesBefore = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesBefore, []); + // NOTE: We're waiting a little so that the file's atime is different + await new Promise((resolve) => setTimeout(resolve, 10)); + await cache.set(randomUUID(), testValue); + await cache.clean(undefined, (await getFileSize(filesBefore[0])) * 1.5); + const filesAfter = await getAllFilesMatching(cachePath); + assert.notDeepEqual(filesAfter, []); + assert.notDeepEqual(filesAfter, filesBefore); + }); + }); +}); diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/compilation-job.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/compilation-job.ts new file mode 100644 index 0000000000..cf0628b1c0 --- /dev/null +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/compilation-job.ts @@ -0,0 +1,303 @@ +import type { Remapping } from "../../../../../src/internal/builtin-plugins/solidity/build-system/resolver/types.js"; +import type { SolcConfig } from "../../../../../src/types/config.js"; +import type { + NpmPackageResolvedFile, + ProjectResolvedFile, +} from "../../../../../src/types/solidity.js"; + +import assert from "node:assert/strict"; +import { beforeEach, describe, it } from "node:test"; + +import { CompilationJobImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/compilation-job.js"; +import { DependencyGraphImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/dependency-graph.js"; +import { + NpmPackageResolvedFileImplementation, + ProjectResolvedFileImplementation, +} from "../../../../../src/internal/builtin-plugins/solidity/build-system/resolved-file.js"; + +describe("CompilationJobImplementation", () => { + let dependencyGraph: DependencyGraphImplementation; + let rootFile: ProjectResolvedFile; + let npmDependencyFile: NpmPackageResolvedFile; + let projectDependencyFile: ProjectResolvedFile; + let solcConfig: SolcConfig; + let solcLongVersion: string; + let remappings: Remapping[]; + let compilationJob: CompilationJobImplementation; + + beforeEach(() => { + dependencyGraph = new DependencyGraphImplementation(); + rootFile = new ProjectResolvedFileImplementation({ + sourceName: "root.sol", + fsPath: "root.sol", + content: { + text: "contract Root {}", + importPaths: [], + versionPragmas: [], + }, + }); + npmDependencyFile = new NpmPackageResolvedFileImplementation({ + sourceName: "npm:dependency/1.0.0/dependency.sol", + fsPath: "dependency.sol", + package: { + name: "dependency", + version: "1.0.0", + rootFsPath: "dependency", + rootSourceName: "dependency.sol", + }, + content: { + text: "contract Dependency {}", + importPaths: [], + versionPragmas: [], + }, + }); + projectDependencyFile = new ProjectResolvedFileImplementation({ + sourceName: "dependency.sol", + fsPath: "dependency.sol", + content: { + text: "contract Dependency {}", + importPaths: [], + versionPragmas: [], + }, + }); + dependencyGraph.addRootFile(rootFile.sourceName, rootFile); + dependencyGraph.addDependency(rootFile, npmDependencyFile); + dependencyGraph.addDependency(rootFile, projectDependencyFile); + solcConfig = { + version: "0.8.0", + settings: {}, + }; + solcLongVersion = "0.8.0-c7dfd78"; + remappings = []; + compilationJob = new CompilationJobImplementation( + dependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + }); + + describe("getBuildId", () => { + describe("should change when", () => { + it("the solc long version changes", async () => { + const newCompilationJob = new CompilationJobImplementation( + dependencyGraph, + solcConfig, + "0.8.0-df193b1", + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the settings change", async () => { + const newCompilationJob = new CompilationJobImplementation( + dependencyGraph, + { + ...solcConfig, + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the remappings change", async () => { + const newCompilationJob = new CompilationJobImplementation( + dependencyGraph, + solcConfig, + solcLongVersion, + [ + { + context: "test", + prefix: "test", + target: "test", + }, + ], + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("there is an additional root file in the dependency graph", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newRootFile = new ProjectResolvedFileImplementation({ + ...rootFile, + sourceName: "newRoot.sol", + }); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, npmDependencyFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + newDependencyGraph.addRootFile("newRoot.sol", newRootFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("there is an additional dependency in the dependency graph", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newDependencyFile = new ProjectResolvedFileImplementation({ + ...projectDependencyFile, + sourceName: "newDependency.sol", + }); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, npmDependencyFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + newDependencyGraph.addDependency(rootFile, newDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the content of one of the root files changes", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newRootFile = new ProjectResolvedFileImplementation({ + ...rootFile, + content: { + ...rootFile.content, + text: "contract NewRoot {}", + }, + }); + newDependencyGraph.addRootFile(newRootFile.sourceName, newRootFile); + newDependencyGraph.addDependency(newRootFile, npmDependencyFile); + newDependencyGraph.addDependency(newRootFile, projectDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the content of one of the dependencies changes", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newDependencyFile = new NpmPackageResolvedFileImplementation({ + ...npmDependencyFile, + content: { + ...npmDependencyFile.content, + text: "contract NewDependency {}", + }, + }); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, newDependencyFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + compilationJob.getBuildId(), + newCompilationJob.getBuildId(), + ); + }); + it("the source name of one of the root files changes", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newRootFile = new ProjectResolvedFileImplementation({ + ...rootFile, + sourceName: "newRoot.sol", + }); + newDependencyGraph.addRootFile(newRootFile.sourceName, newRootFile); + newDependencyGraph.addDependency(newRootFile, npmDependencyFile); + newDependencyGraph.addDependency(newRootFile, projectDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the source name of one of the dependencies changes", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newDependencyFile = new NpmPackageResolvedFileImplementation({ + ...npmDependencyFile, + sourceName: "npm:dependency/1.0.0/newDependency.sol", + }); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, newDependencyFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.notEqual( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + }); + describe("should not change when", () => { + it("the version of one of the dependencies changes without it being reflected in the source name", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + const newDependencyFile = new NpmPackageResolvedFileImplementation({ + ...npmDependencyFile, + package: { + ...npmDependencyFile.package, + version: "2.0.0", + }, + }); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, newDependencyFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.equal( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + it("the order of the sources changes", async () => { + const newDependencyGraph = new DependencyGraphImplementation(); + newDependencyGraph.addRootFile(rootFile.sourceName, rootFile); + newDependencyGraph.addDependency(rootFile, projectDependencyFile); + newDependencyGraph.addDependency(rootFile, npmDependencyFile); + const newCompilationJob = new CompilationJobImplementation( + newDependencyGraph, + solcConfig, + solcLongVersion, + remappings, + ); + assert.equal( + await compilationJob.getBuildId(), + await newCompilationJob.getBuildId(), + ); + }); + }); + }); +}); diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph.ts index ee83bb60bc..0d73941f4f 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph.ts @@ -8,11 +8,10 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { assertThrowsHardhatError } from "@nomicfoundation/hardhat-test-utils"; import { DependencyGraphImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/dependency-graph.js"; -import { ResolvedFileType } from "../../../../../src/types/solidity.js"; +import { ProjectResolvedFileImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/resolved-file.js"; function createProjectResolvedFile(sourceName: string): ProjectResolvedFile { - return { - type: ResolvedFileType.PROJECT_FILE, + return new ProjectResolvedFileImplementation({ sourceName, fsPath: path.join(process.cwd(), sourceName), content: { @@ -20,7 +19,7 @@ function createProjectResolvedFile(sourceName: string): ProjectResolvedFile { importPaths: [], versionPragmas: [], }, - }; + }); } describe("DependencyGraphImplementation", () => { diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/root-paths-utils.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/root-paths-utils.ts index a52280805b..edad9f04ed 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/root-paths-utils.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/root-paths-utils.ts @@ -4,6 +4,10 @@ import type { ResolvedFile } from "../../../../../src/types/solidity.js"; import assert from "node:assert/strict"; import { describe, it } from "node:test"; +import { + NpmPackageResolvedFileImplementation, + ProjectResolvedFileImplementation, +} from "../../../../../src/internal/builtin-plugins/solidity/build-system/resolved-file.js"; import { formatRootPath, isNpmParsedRootPath, @@ -11,7 +15,6 @@ import { npmModuleToNpmRootPath, parseRootPath, } from "../../../../../src/internal/builtin-plugins/solidity/build-system/root-paths-utils.js"; -import { ResolvedFileType } from "../../../../../src/types/solidity.js"; interface TestRootPath { rootPath: string; @@ -31,8 +34,7 @@ const testRootPaths: TestRootPath[] = [ isNpm: true, npmModule: "ethers", publicSourceName: "ethers", - resolvedFile: { - type: ResolvedFileType.NPM_PACKAGE_FILE, + resolvedFile: new NpmPackageResolvedFileImplementation({ sourceName: "ethers", fsPath: "/Users/root/node_modules/ethers/index.js", content: { @@ -46,7 +48,7 @@ const testRootPaths: TestRootPath[] = [ rootFsPath: "/Users/root/node_modules/ethers", rootSourceName: "ethers", }, - }, + }), }, { rootPath: "npm:@openzeppelin/contracts", @@ -56,8 +58,7 @@ const testRootPaths: TestRootPath[] = [ isNpm: true, npmModule: "@openzeppelin/contracts", publicSourceName: "@openzeppelin/contracts", - resolvedFile: { - type: ResolvedFileType.NPM_PACKAGE_FILE, + resolvedFile: new NpmPackageResolvedFileImplementation({ sourceName: "@openzeppelin/contracts", fsPath: "/Users/root/node_modules/@openzeppelin/contracts/index.js", content: { @@ -71,7 +72,7 @@ const testRootPaths: TestRootPath[] = [ rootFsPath: "/Users/root/node_modules/@openzeppelin/contracts", rootSourceName: "@openzeppelin/contracts", }, - }, + }), }, { rootPath: "npm:@openzeppelin/contracts/token/ERC20/ERC20.sol", @@ -81,8 +82,7 @@ const testRootPaths: TestRootPath[] = [ isNpm: true, npmModule: "@openzeppelin/contracts/token/ERC20/ERC20.sol", publicSourceName: "@openzeppelin/contracts/token/ERC20/ERC20.sol", - resolvedFile: { - type: ResolvedFileType.NPM_PACKAGE_FILE, + resolvedFile: new NpmPackageResolvedFileImplementation({ sourceName: "@openzeppelin/contracts/token/ERC20/ERC20.sol", fsPath: "/Users/root/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol", @@ -97,7 +97,7 @@ const testRootPaths: TestRootPath[] = [ rootFsPath: "/Users/root/node_modules/@openzeppelin/contracts", rootSourceName: "@openzeppelin/contracts", }, - }, + }), }, { rootPath: "/Users/root/contracts/Contract.sol", @@ -107,8 +107,7 @@ const testRootPaths: TestRootPath[] = [ isNpm: false, npmModule: undefined, publicSourceName: "/Users/root/contracts/Contract.sol", - resolvedFile: { - type: ResolvedFileType.PROJECT_FILE, + resolvedFile: new ProjectResolvedFileImplementation({ sourceName: "/Users/root/contracts/Contract.sol", fsPath: "/Users/root/contracts/Contract.sol", content: { @@ -116,7 +115,7 @@ const testRootPaths: TestRootPath[] = [ importPaths: [], versionPragmas: [], }, - }, + }), }, { rootPath: "C:\\Users\\root\\contracts\\Contract.sol", @@ -126,8 +125,7 @@ const testRootPaths: TestRootPath[] = [ isNpm: false, npmModule: undefined, publicSourceName: "C:\\Users\\root\\contracts\\Contract.sol", - resolvedFile: { - type: ResolvedFileType.PROJECT_FILE, + resolvedFile: new ProjectResolvedFileImplementation({ sourceName: "C:\\Users\\root\\contracts\\Contract.sol", fsPath: "C:\\Users\\root\\contracts\\Contract.sol", content: { @@ -135,7 +133,7 @@ const testRootPaths: TestRootPath[] = [ importPaths: [], versionPragmas: [], }, - }, + }), }, ]; diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts index 77682f2c57..249349ccf1 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts @@ -9,18 +9,15 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { assertRejectsWithHardhatError } from "@nomicfoundation/hardhat-test-utils"; import { DependencyGraphImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/dependency-graph.js"; +import { ProjectResolvedFileImplementation } from "../../../../../src/internal/builtin-plugins/solidity/build-system/resolved-file.js"; import { SolcConfigSelector } from "../../../../../src/internal/builtin-plugins/solidity/build-system/solc-config-selection.js"; -import { - CompilationJobCreationErrorReason, - ResolvedFileType, -} from "../../../../../src/types/solidity.js"; +import { CompilationJobCreationErrorReason } from "../../../../../src/types/solidity.js"; function createProjectResolvedFile( sourceName: string, versionPragmas: string[], ): ProjectResolvedFile { - return { - type: ResolvedFileType.PROJECT_FILE, + return new ProjectResolvedFileImplementation({ sourceName, fsPath: path.join(process.cwd(), sourceName), content: { @@ -28,7 +25,7 @@ function createProjectResolvedFile( importPaths: [], versionPragmas, }, - }; + }); } describe("SolcConfigSelector", () => {