Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in compilation when multiple versions are used with many contracts #4550

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/small-crews-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hardhat": patch
---

Added logic to avoid downloading the same compiler version multiple times
73 changes: 37 additions & 36 deletions packages/hardhat-core/src/builtin-tasks/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -580,26 +580,26 @@ subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD)
compilersCache
);

const isCompilerDownloaded = await downloader.isCompilerDownloaded(
solcVersion
await downloader.downloadCompiler(
solcVersion,
// callback called before compiler download
async (isCompilerDownloaded: boolean) => {
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
solcVersion,
isCompilerDownloaded,
quiet,
});
},
// callback called after compiler download
async (isCompilerDownloaded: boolean) => {
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
solcVersion,
isCompilerDownloaded,
quiet,
});
}
);

if (!isCompilerDownloaded) {
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
solcVersion,
isCompilerDownloaded,
quiet,
});

await downloader.downloadCompiler(solcVersion);

await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
solcVersion,
isCompilerDownloaded,
quiet,
});
}

const compiler = await downloader.getCompiler(solcVersion);

if (compiler !== undefined) {
Expand All @@ -615,24 +615,25 @@ subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD)
compilersCache
);

const isWasmCompilerDownloader =
await wasmDownloader.isCompilerDownloaded(solcVersion);

if (!isWasmCompilerDownloader) {
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
solcVersion,
isCompilerDownloaded,
quiet,
});

await wasmDownloader.downloadCompiler(solcVersion);

await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
solcVersion,
isCompilerDownloaded,
quiet,
});
}
await wasmDownloader.downloadCompiler(
solcVersion,
async (isCompilerDownloaded: boolean) => {
// callback called before compiler download
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
solcVersion,
isCompilerDownloaded,
quiet,
});
},
// callback called after compiler download
async (isCompilerDownloaded: boolean) => {
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
solcVersion,
isCompilerDownloaded,
quiet,
});
}
);

const wasmCompiler = await wasmDownloader.getCompiler(solcVersion);

Expand Down
26 changes: 24 additions & 2 deletions packages/hardhat-core/src/internal/solidity/compiler/downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ export interface ICompilerDownloader {
* Downloads the compiler for a given version, which can later be obtained
* with getCompiler.
*/
downloadCompiler(version: string): Promise<void>;
downloadCompiler(
version: string,
downloadStartedCb: (isCompilerDownloaded: boolean) => Promise<any>,
downloadEndedCb: (isCompilerDownloaded: boolean) => Promise<any>
): Promise<void>;

/**
* Returns the compiler, which MUST be downloaded before calling this function.
Expand Down Expand Up @@ -146,8 +150,24 @@ export class CompilerDownloader implements ICompilerDownloader {
return fsExtra.pathExists(downloadPath);
}

public async downloadCompiler(version: string): Promise<void> {
public async downloadCompiler(
version: string,
downloadStartedCb: (isCompilerDownloaded: boolean) => Promise<any>,
downloadEndedCb: (isCompilerDownloaded: boolean) => Promise<any>
): Promise<void> {
// Since only one process at a time can acquire the mutex, we avoid the risk of downloading the same compiler multiple times.
// This is because the mutex blocks access until a compiler has been fully downloaded, preventing any new process
// from checking whether that version of the compiler exists. Without mutex it might incorrectly
// return false, indicating that the compiler isn't present, even though it is currently being downloaded.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this!

await this._mutex.use(async () => {
const isCompilerDownloaded = await this.isCompilerDownloaded(version);

if (isCompilerDownloaded === true) {
return;
}

await downloadStartedCb(isCompilerDownloaded);

let build = await this._getCompilerBuild(version);

if (build === undefined && (await this._shouldDownloadCompilerList())) {
Expand Down Expand Up @@ -189,6 +209,8 @@ export class CompilerDownloader implements ICompilerDownloader {
}

await this._postProcessCompilerDownload(build, downloadPath);

await downloadEndedCb(isCompilerDownloaded);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ export async function downloadCompiler(solidityVersion: string) {

if (!isCompilerDownloaded) {
console.log("Downloading solc", solidityVersion);
await downloader.downloadCompiler(solidityVersion);
await downloader.downloadCompiler(
solidityVersion,
async () => {},
async () => {}
);
}
}
Loading
Loading