Skip to content

Commit

Permalink
Merge pull request #6129 from NomicFoundation/build-system-cache
Browse files Browse the repository at this point in the history
feat: implement the solidity compilation cache
  • Loading branch information
galargh authored Feb 7, 2025
2 parents 84d1e81 + ec80460 commit 1ec485f
Show file tree
Hide file tree
Showing 37 changed files with 1,185 additions and 1,020 deletions.
16 changes: 9 additions & 7 deletions v-next/hardhat-utils/src/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { createHash } from "node:crypto";

import { keccak256 as keccak256Impl } from "ethereum-cryptography/keccak";

/**
Expand All @@ -17,17 +15,21 @@ export async function keccak256(bytes: Uint8Array): Promise<Uint8Array> {
*
* 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<string> {
const message = new TextEncoder().encode(data);
const buffer = await crypto.subtle.digest("SHA-1", message);
return Buffer.from(buffer).toString("hex");
}
44 changes: 44 additions & 0 deletions v-next/hardhat-utils/src/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,50 @@ export async function getChangeTime(absolutePath: string): Promise<Date> {
}
}

/**
* 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<Date> {
try {
const stats = await fsPromises.stat(absolutePath);
return stats.atime;
} catch (e) {
ensureError<NodeJS.ErrnoException>(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<number> {
try {
const stats = await fsPromises.stat(absolutePath);
return stats.size;
} catch (e) {
ensureError<NodeJS.ErrnoException>(e);
if (e.code === "ENOENT") {
throw new FileNotFoundError(absolutePath, e);
}

throw new FileSystemAccessError(e.message, e);
}
}

/**
* Checks if a file or directory exists.
*
Expand Down
6 changes: 3 additions & 3 deletions v-next/hardhat-utils/test/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
);
});
});
Expand Down
61 changes: 61 additions & 0 deletions v-next/hardhat-utils/test/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
writeJsonFile,
writeUtf8File,
readBinaryFile,
getAccessTime,
getFileSize,
} from "../src/fs.js";

import { useTmpDir } from "./helpers/fs.js";
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ declare module "@ignored/hardhat-vnext/types/artifacts" {
}`;
}

export function getBuildInfo(
export async function getBuildInfo(
compilationJob: CompilationJob,
): SolidityBuildInfo {
): Promise<SolidityBuildInfo> {
const publicSourceNameMap = Object.fromEntries(
[...compilationJob.dependencyGraph.getRoots().entries()].map(
([publicSourceName, root]) => [publicSourceName, root.sourceName],
Expand All @@ -115,7 +115,7 @@ export function getBuildInfo(

const buildInfo: Required<BuildInfo> = {
_format: "hh3-sol-build-info-1",
id: compilationJob.getBuildId(),
id: await compilationJob.getBuildId(),
solcVersion: compilationJob.solcConfig.version,
solcLongVersion: compilationJob.solcLongVersion,
publicSourceNameMap,
Expand All @@ -125,13 +125,13 @@ export function getBuildInfo(
return buildInfo;
}

export function getBuildInfoOutput(
export async function getBuildInfoOutput(
compilationJob: CompilationJob,
compilerOutput: CompilerOutput,
): SolidityBuildInfoOutput {
): Promise<SolidityBuildInfoOutput> {
const buildInfoOutput: Required<SolidityBuildInfoOutput> = {
_format: "hh3-sol-build-info-output-1",
id: compilationJob.getBuildId(),
id: await compilationJob.getBuildId(),
output: compilerOutput,
};

Expand Down
Loading

0 comments on commit 1ec485f

Please sign in to comment.