hardhat 2.19.3 → 2.19.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/builtin-tasks/compile.js +11 -2
- package/builtin-tasks/compile.js.map +1 -1
- package/internal/cli/analytics.d.ts +2 -0
- package/internal/cli/analytics.d.ts.map +1 -1
- package/internal/cli/analytics.js +37 -3
- package/internal/cli/analytics.js.map +1 -1
- package/internal/cli/cli.js +34 -4
- package/internal/cli/cli.js.map +1 -1
- package/internal/cli/project-creation.d.ts.map +1 -1
- package/internal/cli/project-creation.js +7 -10
- package/internal/cli/project-creation.js.map +1 -1
- package/internal/cli/version-notifier.d.ts +2 -0
- package/internal/cli/version-notifier.d.ts.map +1 -0
- package/internal/cli/version-notifier.js +217 -0
- package/internal/cli/version-notifier.js.map +1 -0
- package/internal/core/config/config-loading.d.ts.map +1 -1
- package/internal/core/config/config-loading.js +3 -3
- package/internal/core/config/config-loading.js.map +1 -1
- package/internal/core/config/config-resolution.d.ts.map +1 -1
- package/internal/core/config/config-resolution.js +10 -6
- package/internal/core/config/config-resolution.js.map +1 -1
- package/internal/core/config/config-validation.d.ts +2 -2
- package/internal/core/config/config-validation.d.ts.map +1 -1
- package/internal/core/config/config-validation.js +2 -2
- package/internal/core/config/config-validation.js.map +1 -1
- package/internal/core/providers/gas-providers.d.ts.map +1 -1
- package/internal/core/providers/gas-providers.js +7 -0
- package/internal/core/providers/gas-providers.js.map +1 -1
- package/internal/hardhat-network/stack-traces/panic-errors.js +1 -1
- package/internal/hardhat-network/stack-traces/panic-errors.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.js +13 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.js.map +1 -1
- package/internal/solidity/compiler/downloader.d.ts.map +1 -1
- package/internal/solidity/compiler/downloader.js +2 -2
- package/internal/solidity/compiler/downloader.js.map +1 -1
- package/internal/solidity/compiler/index.d.ts +2 -1
- package/internal/solidity/compiler/index.d.ts.map +1 -1
- package/internal/solidity/compiler/index.js +25 -2
- package/internal/solidity/compiler/index.js.map +1 -1
- package/internal/util/fs-utils.d.ts +1 -1
- package/internal/util/fs-utils.js +1 -1
- package/internal/util/multi-process-mutex.d.ts +12 -0
- package/internal/util/multi-process-mutex.d.ts.map +1 -0
- package/internal/util/multi-process-mutex.js +116 -0
- package/internal/util/multi-process-mutex.js.map +1 -0
- package/internal/util/report-telemetry-consent.d.ts +2 -0
- package/internal/util/report-telemetry-consent.d.ts.map +1 -0
- package/internal/util/report-telemetry-consent.js +15 -0
- package/internal/util/report-telemetry-consent.js.map +1 -0
- package/package.json +2 -1
- package/src/builtin-tasks/compile.ts +20 -2
- package/src/internal/cli/analytics.ts +82 -6
- package/src/internal/cli/cli.ts +16 -9
- package/src/internal/cli/project-creation.ts +9 -19
- package/src/internal/cli/version-notifier.ts +268 -0
- package/src/internal/core/config/config-loading.ts +2 -1
- package/src/internal/core/config/config-resolution.ts +7 -1
- package/src/internal/core/config/config-validation.ts +9 -2
- package/src/internal/core/providers/gas-providers.ts +8 -0
- package/src/internal/hardhat-network/stack-traces/panic-errors.ts +1 -1
- package/src/internal/hardhat-network/stack-traces/solidity-errors.ts +17 -1
- package/src/internal/sentry/transport.ts +1 -1
- package/src/internal/solidity/compiler/downloader.ts +2 -2
- package/src/internal/solidity/compiler/index.ts +22 -2
- package/src/internal/util/fs-utils.ts +1 -1
- package/src/internal/util/multi-process-mutex.ts +133 -0
- package/src/internal/util/report-telemetry-consent.ts +19 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
|
|
2
|
+
import debug from "debug";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
|
|
7
|
+
// Logic explanation: the fs.writeFile function, when used with the wx+ flag, performs an atomic operation to create a file.
|
|
8
|
+
// If multiple processes try to create the same file simultaneously, only one will succeed.
|
|
9
|
+
// This logic can be utilized to implement a mutex.
|
|
10
|
+
// ATTENTION: in the current implementation, there's still a risk of two processes running simultaneously.
|
|
11
|
+
// For example, if processA has locked the mutex and is running, processB will wait.
|
|
12
|
+
// During this wait, processB continuously checks the elapsed time since the mutex lock file was created.
|
|
13
|
+
// If an excessive amount of time has passed, processB will assume ownership of the mutex to avoid stale locks.
|
|
14
|
+
// However, there's a possibility that processB might take ownership because the mutex creation file is outdated, even though processA is still running
|
|
15
|
+
// For more info check the Nomic Notion page (internal link).
|
|
16
|
+
|
|
17
|
+
const log = debug("hardhat:util:multi-process-mutex");
|
|
18
|
+
const DEFAULT_MAX_MUTEX_LIFESPAN_IN_MS = 60000;
|
|
19
|
+
const MUTEX_LOOP_WAITING_TIME_IN_MS = 100;
|
|
20
|
+
|
|
21
|
+
export class MultiProcessMutex {
|
|
22
|
+
private _mutexFilePath: string;
|
|
23
|
+
private _mutexLifespanInMs: number;
|
|
24
|
+
|
|
25
|
+
constructor(mutexName: string, maxMutexLifespanInMs?: number) {
|
|
26
|
+
log(`Creating mutex with name '${mutexName}'`);
|
|
27
|
+
|
|
28
|
+
this._mutexFilePath = path.join(os.tmpdir(), `${mutexName}.txt`);
|
|
29
|
+
this._mutexLifespanInMs =
|
|
30
|
+
maxMutexLifespanInMs ?? DEFAULT_MAX_MUTEX_LIFESPAN_IN_MS;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async use<T>(f: () => Promise<T>): Promise<T> {
|
|
34
|
+
log(`Starting mutex process with mutex file '${this._mutexFilePath}'`);
|
|
35
|
+
|
|
36
|
+
while (true) {
|
|
37
|
+
if (await this._tryToAcquireMutex()) {
|
|
38
|
+
// Mutex has been acquired
|
|
39
|
+
return this._executeFunctionAndReleaseMutex(f);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Mutex not acquired
|
|
43
|
+
if (this._isMutexFileTooOld()) {
|
|
44
|
+
// If the mutex file is too old, it likely indicates a stale lock, so the file should be removed
|
|
45
|
+
log(
|
|
46
|
+
`Current mutex file is too old, removing it at path '${this._mutexFilePath}'`
|
|
47
|
+
);
|
|
48
|
+
this._deleteMutexFile();
|
|
49
|
+
} else {
|
|
50
|
+
// wait
|
|
51
|
+
await this._waitMs();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private async _tryToAcquireMutex() {
|
|
57
|
+
try {
|
|
58
|
+
// Create a file only if it does not exist
|
|
59
|
+
fs.writeFileSync(this._mutexFilePath, "", { flag: "wx+" });
|
|
60
|
+
return true;
|
|
61
|
+
} catch (error: any) {
|
|
62
|
+
if (error.code === "EEXIST") {
|
|
63
|
+
// File already exists, so the mutex is already acquired
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private async _executeFunctionAndReleaseMutex<T>(
|
|
72
|
+
f: () => Promise<T>
|
|
73
|
+
): Promise<T> {
|
|
74
|
+
log(`Mutex acquired at path '${this._mutexFilePath}'`);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const res = await f();
|
|
78
|
+
|
|
79
|
+
// Release the mutex
|
|
80
|
+
log(`Mutex released at path '${this._mutexFilePath}'`);
|
|
81
|
+
this._deleteMutexFile();
|
|
82
|
+
|
|
83
|
+
log(`Mutex released at path '${this._mutexFilePath}'`);
|
|
84
|
+
|
|
85
|
+
return res;
|
|
86
|
+
} catch (error: any) {
|
|
87
|
+
// Catch any error to avoid stale locks.
|
|
88
|
+
// Remove the mutex file and re-throw the error
|
|
89
|
+
this._deleteMutexFile();
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private _isMutexFileTooOld(): boolean {
|
|
95
|
+
let fileStat;
|
|
96
|
+
try {
|
|
97
|
+
fileStat = fs.statSync(this._mutexFilePath);
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
if (error.code === "ENOENT") {
|
|
100
|
+
// The file might have been deleted by another process while this function was trying to access it.
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const now = new Date();
|
|
108
|
+
const fileDate = new Date(fileStat.ctime);
|
|
109
|
+
const diff = now.getTime() - fileDate.getTime();
|
|
110
|
+
|
|
111
|
+
return diff > this._mutexLifespanInMs;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _deleteMutexFile() {
|
|
115
|
+
try {
|
|
116
|
+
log(`Deleting mutex file at path '${this._mutexFilePath}'`);
|
|
117
|
+
fs.unlinkSync(this._mutexFilePath);
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
if (error.code === "ENOENT") {
|
|
120
|
+
// The file might have been deleted by another process while this function was trying to access it.
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private async _waitMs() {
|
|
129
|
+
return new Promise((resolve) =>
|
|
130
|
+
setTimeout(resolve, MUTEX_LOOP_WAITING_TIME_IN_MS)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Analytics } from "../cli/analytics";
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
// This default value shouldn't be necessary, but we add one to make it
|
|
5
|
+
// easier to recognize if the telemetry consent value is not passed.
|
|
6
|
+
const [telemetryConsent = "<undefined-telemetry-consent>"] =
|
|
7
|
+
process.argv.slice(2);
|
|
8
|
+
|
|
9
|
+
// we pass undefined as the telemetryConsent value because
|
|
10
|
+
// this hit is done before the consent is saved
|
|
11
|
+
const analytics = await Analytics.getInstance(undefined);
|
|
12
|
+
|
|
13
|
+
const [_, consentHitPromise] = await analytics.sendTelemetryConsentHit(
|
|
14
|
+
telemetryConsent as "yes" | "no"
|
|
15
|
+
);
|
|
16
|
+
await consentHitPromise;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
main().catch(() => {});
|