Skip to content

Commit c52a5d6

Browse files
Bug in compilation when multiple versions are used with many contracts (#4550)
1 parent ef4a94d commit c52a5d6

File tree

6 files changed

+242
-55
lines changed

6 files changed

+242
-55
lines changed

.changeset/small-crews-kiss.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"hardhat": patch
3+
---
4+
5+
Added logic to avoid downloading the same compiler version multiple times

packages/hardhat-core/src/builtin-tasks/compile.ts

+37-36
Original file line numberDiff line numberDiff line change
@@ -580,26 +580,26 @@ subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD)
580580
compilersCache
581581
);
582582

583-
const isCompilerDownloaded = await downloader.isCompilerDownloaded(
584-
solcVersion
583+
await downloader.downloadCompiler(
584+
solcVersion,
585+
// callback called before compiler download
586+
async (isCompilerDownloaded: boolean) => {
587+
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
588+
solcVersion,
589+
isCompilerDownloaded,
590+
quiet,
591+
});
592+
},
593+
// callback called after compiler download
594+
async (isCompilerDownloaded: boolean) => {
595+
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
596+
solcVersion,
597+
isCompilerDownloaded,
598+
quiet,
599+
});
600+
}
585601
);
586602

587-
if (!isCompilerDownloaded) {
588-
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
589-
solcVersion,
590-
isCompilerDownloaded,
591-
quiet,
592-
});
593-
594-
await downloader.downloadCompiler(solcVersion);
595-
596-
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
597-
solcVersion,
598-
isCompilerDownloaded,
599-
quiet,
600-
});
601-
}
602-
603603
const compiler = await downloader.getCompiler(solcVersion);
604604

605605
if (compiler !== undefined) {
@@ -615,24 +615,25 @@ subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD)
615615
compilersCache
616616
);
617617

618-
const isWasmCompilerDownloader =
619-
await wasmDownloader.isCompilerDownloaded(solcVersion);
620-
621-
if (!isWasmCompilerDownloader) {
622-
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
623-
solcVersion,
624-
isCompilerDownloaded,
625-
quiet,
626-
});
627-
628-
await wasmDownloader.downloadCompiler(solcVersion);
629-
630-
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
631-
solcVersion,
632-
isCompilerDownloaded,
633-
quiet,
634-
});
635-
}
618+
await wasmDownloader.downloadCompiler(
619+
solcVersion,
620+
async (isCompilerDownloaded: boolean) => {
621+
// callback called before compiler download
622+
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START, {
623+
solcVersion,
624+
isCompilerDownloaded,
625+
quiet,
626+
});
627+
},
628+
// callback called after compiler download
629+
async (isCompilerDownloaded: boolean) => {
630+
await run(TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_END, {
631+
solcVersion,
632+
isCompilerDownloaded,
633+
quiet,
634+
});
635+
}
636+
);
636637

637638
const wasmCompiler = await wasmDownloader.getCompiler(solcVersion);
638639

packages/hardhat-core/src/internal/solidity/compiler/downloader.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ export interface ICompilerDownloader {
6060
* Downloads the compiler for a given version, which can later be obtained
6161
* with getCompiler.
6262
*/
63-
downloadCompiler(version: string): Promise<void>;
63+
downloadCompiler(
64+
version: string,
65+
downloadStartedCb: (isCompilerDownloaded: boolean) => Promise<any>,
66+
downloadEndedCb: (isCompilerDownloaded: boolean) => Promise<any>
67+
): Promise<void>;
6468

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

149-
public async downloadCompiler(version: string): Promise<void> {
153+
public async downloadCompiler(
154+
version: string,
155+
downloadStartedCb: (isCompilerDownloaded: boolean) => Promise<any>,
156+
downloadEndedCb: (isCompilerDownloaded: boolean) => Promise<any>
157+
): Promise<void> {
158+
// Since only one process at a time can acquire the mutex, we avoid the risk of downloading the same compiler multiple times.
159+
// This is because the mutex blocks access until a compiler has been fully downloaded, preventing any new process
160+
// from checking whether that version of the compiler exists. Without mutex it might incorrectly
161+
// return false, indicating that the compiler isn't present, even though it is currently being downloaded.
150162
await this._mutex.use(async () => {
163+
const isCompilerDownloaded = await this.isCompilerDownloaded(version);
164+
165+
if (isCompilerDownloaded === true) {
166+
return;
167+
}
168+
169+
await downloadStartedCb(isCompilerDownloaded);
170+
151171
let build = await this._getCompilerBuild(version);
152172

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

191211
await this._postProcessCompilerDownload(build, downloadPath);
212+
213+
await downloadEndedCb(isCompilerDownloaded);
192214
});
193215
}
194216

packages/hardhat-core/test/internal/hardhat-network/stack-traces/compilation.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ export async function downloadCompiler(solidityVersion: string) {
190190

191191
if (!isCompilerDownloaded) {
192192
console.log("Downloading solc", solidityVersion);
193-
await downloader.downloadCompiler(solidityVersion);
193+
await downloader.downloadCompiler(
194+
solidityVersion,
195+
async () => {},
196+
async () => {}
197+
);
194198
}
195199
}

0 commit comments

Comments
 (0)