-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Only initialze EDR's ContractDecoder once per NetworkManager instance #8074
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "hardhat": patch | ||
| --- | ||
|
|
||
| Optimize the initialization of EDR Network Connections by only processing the build outputs once. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,14 +21,15 @@ import type { | |
| JsonRpcRequest, | ||
| JsonRpcResponse, | ||
| } from "../../../types/providers.js"; | ||
| import type { GasReportConfig } from "@nomicfoundation/edr"; | ||
| import type { ContractDecoder, GasReportConfig } from "@nomicfoundation/edr"; | ||
|
|
||
| import { | ||
| HardhatError, | ||
| assertHardhatInvariant, | ||
| } from "@nomicfoundation/hardhat-errors"; | ||
| import { exists, readBinaryFile } from "@nomicfoundation/hardhat-utils/fs"; | ||
| import { deepMerge } from "@nomicfoundation/hardhat-utils/lang"; | ||
| import { AsyncMutex } from "@nomicfoundation/hardhat-utils/synchronization"; | ||
|
|
||
| import { resolveUserConfigToHardhatConfig } from "../../core/hre.js"; | ||
| import { isSupportedChainType } from "../../edr/chain-type.js"; | ||
|
|
@@ -57,6 +58,8 @@ export class NetworkManagerImplementation implements NetworkManager { | |
| readonly #projectRoot: string; | ||
|
|
||
| #nextConnectionId = 0; | ||
| readonly #contractDecoderMutex = new AsyncMutex(); | ||
| #contractDecoder: ContractDecoder | undefined; | ||
|
|
||
| constructor( | ||
| defaultNetwork: string, | ||
|
|
@@ -233,6 +236,40 @@ export class NetworkManagerImplementation implements NetworkManager { | |
| }; | ||
| } | ||
|
|
||
| // We load the build infos and their outputs to create a contract | ||
| // decoder when the first provider is created. Successive providers will | ||
| // reuse the same decoder as a performance optimization. | ||
| // | ||
| // The trade-off here is that if you create an EDR provider, then | ||
| // compile new contracts, and create a new provider, the new contracts | ||
| // won't be loaded. | ||
| // | ||
| // Even without this optimization, we already had the problem of new | ||
| // contracts not being visible to existing providers. | ||
| // | ||
| // In practice, most workflows compile everything before creating | ||
| // any network connection. | ||
|
kanej marked this conversation as resolved.
|
||
| if (this.#contractDecoder === undefined) { | ||
| // We want to ensure that only one contract decoder is created so we | ||
| // protect the initialization with a mutex. | ||
| await this.#contractDecoderMutex.exclusiveRun(async () => { | ||
| // We check again if the decoder is undefined because another async | ||
| // execution context could have already initialized it while we were | ||
| // waiting for the mutex. | ||
| if (this.#contractDecoder === undefined) { | ||
| this.#contractDecoder = await EdrProvider.createContractDecoder({ | ||
| buildInfos: await this.#getBuildInfosAndOutputsAsBuffers(), | ||
| ignoreContracts: false, | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
|
Comment on lines
+252
to
+266
|
||
|
|
||
| assertHardhatInvariant( | ||
| this.#contractDecoder !== undefined, | ||
| "Contract decoder should have been initialized before creating the provider", | ||
| ); | ||
|
|
||
| return EdrProvider.create({ | ||
| chainDescriptors: this.#chainDescriptors, | ||
| // The resolvedNetworkConfig can have its chainType set to `undefined` | ||
|
|
@@ -249,10 +286,7 @@ export class NetworkManagerImplementation implements NetworkManager { | |
| chainType: resolvedChainType as ChainType, | ||
| }, | ||
| jsonRpcRequestWrapper, | ||
| tracingConfig: { | ||
| buildInfos: await this.#getBuildInfosAndOutputsAsBuffers(), | ||
| ignoreContracts: false, | ||
| }, | ||
| contractDecoder: this.#contractDecoder, | ||
|
||
| coverageConfig, | ||
| gasReportConfig, | ||
| }); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.