Skip to content

Only initialze EDR's ContractDecoder once per NetworkManager instance#8074

Merged
alcuadrado merged 4 commits intomainfrom
single-contract-decoder
Mar 24, 2026
Merged

Only initialze EDR's ContractDecoder once per NetworkManager instance#8074
alcuadrado merged 4 commits intomainfrom
single-contract-decoder

Conversation

@alcuadrado
Copy link
Copy Markdown
Member

No description provided.

Copilot AI review requested due to automatic review settings March 21, 2026 16:19
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: d06cecf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
hardhat Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@alcuadrado alcuadrado force-pushed the single-contract-decoder branch from 477e1ee to 5373100 Compare March 21, 2026 16:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Optimizes EDR provider startup by reusing a single ContractDecoder per NetworkManagerImplementation instance, avoiding repeated build-info loading/decoder construction across successive connections.

Changes:

  • Cache and reuse an EDR ContractDecoder in NetworkManagerImplementation when creating EDR-simulated providers.
  • Update EdrProvider.create configuration to accept a prebuilt contractDecoder instead of building it internally.
  • Add EdrProvider.createContractDecoder helper for constructing a decoder from build info buffers.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts Lazily initializes and caches a ContractDecoder, then passes it into each EdrProvider.create call.
v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts Refactors provider creation to require an externally provided ContractDecoder and adds a helper constructor.

buildInfos: await this.#getBuildInfosAndOutputsAsBuffers(),
ignoreContracts: false,
},
contractDecoder: this.#contractDecoder,
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

this.#contractDecoder is typed as ContractDecoder | undefined, but EdrProvider.create now requires a non-optional contractDecoder. This will fail type-checking at this call site. Consider storing the initialized decoder in a local const (or changing the field to a non-optional type and using definite assignment) so the argument is guaranteed to be ContractDecoder here.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this type checks already

Comment on lines +250 to +255
if (this.#contractDecoder === undefined) {
this.#contractDecoder = await EdrProvider.createContractDecoder({
buildInfos: await this.#getBuildInfosAndOutputsAsBuffers(),
ignoreContracts: false,
});
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The lazy initialization of #contractDecoder isn't concurrency-safe: if two connections create an EDR provider at the same time, both can enter this if block and build/load the decoder in parallel (defeating the "once per NetworkManager" goal). Consider caching a single in-flight Promise (e.g., #contractDecoderPromise) or guarding initialization with a simple mutex to ensure only one initialization occurs.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The AsyncMutex here and the double guard should avoid the race condition. The call to EdrProvider.createContractDecoder happens with the mutex and must be complete before another callback can reach here because of the mutex.

@alcuadrado alcuadrado added no docs needed This PR doesn't require links to documentation no peer bump needed labels Mar 23, 2026
@alcuadrado alcuadrado requested a review from kanej March 23, 2026 17:14
Copilot AI review requested due to automatic review settings March 23, 2026 19:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Copy link
Copy Markdown
Member

@kanej kanej left a comment

Choose a reason for hiding this comment

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

I added a test out of completeness.

I have run this PR against the OpenZeppelin connectOnBefore branch to check that it is robust in the face of many network connection creations.

@NomicFoundation NomicFoundation deleted a comment from Dlove123 Mar 23, 2026
@alcuadrado alcuadrado added this pull request to the merge queue Mar 24, 2026
Merged via the queue into main with commit 2ba84bf Mar 24, 2026
217 checks passed
@alcuadrado alcuadrado deleted the single-contract-decoder branch March 24, 2026 11:42
@github-actions github-actions bot mentioned this pull request Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no docs needed This PR doesn't require links to documentation no peer bump needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants