Skip to content

Commit c8adb6d

Browse files
authored
Merge pull request #6065 from NomicFoundation/edr-config-validation
EDR Config validation
2 parents 34e9feb + c74a693 commit c8adb6d

File tree

17 files changed

+644
-330
lines changed

17 files changed

+644
-330
lines changed

v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
1+
import type { SensitiveString } from "../../../../types/config.js";
2+
13
import { HardhatError } from "@ignored/hardhat-vnext-errors";
24
import { mnemonicToSeedSync } from "ethereum-cryptography/bip39";
35
import { HDKey } from "ethereum-cryptography/hdkey";
46

57
const HD_PATH_REGEX = /^m(:?\/\d+'?)+\/?$/;
68

7-
export const DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS = {
8-
initialIndex: 0,
9-
count: 20,
10-
path: "m/44'/60'/0'/0",
11-
passphrase: "",
12-
};
9+
export interface DefaultHDAccountsConfigParams {
10+
initialIndex: number;
11+
count: number;
12+
path: string;
13+
passphrase: SensitiveString;
14+
}
15+
16+
export const DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS: DefaultHDAccountsConfigParams =
17+
{
18+
initialIndex: 0,
19+
count: 20,
20+
path: "m/44'/60'/0'/0",
21+
passphrase: "",
22+
};
1323

1424
export function derivePrivateKeys(
1525
mnemonic: string,

v-next/hardhat/src/internal/builtin-plugins/network-manager/config-resolution.ts

+37-17
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import {
2727
DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS,
2828
EDR_NETWORK_DEFAULT_COINBASE,
2929
} from "./edr/edr-provider.js";
30-
import { HardforkName } from "./edr/types/hardfork.js";
31-
import { isHdAccountsConfig } from "./type-validation.js";
30+
import { HardforkName, LATEST_HARDFORK } from "./edr/types/hardfork.js";
31+
import { isHdAccountsUserConfig } from "./type-validation.js";
3232

3333
export function resolveGasConfig(value: GasUserConfig = "auto"): GasConfig {
3434
return value === "auto" ? value : BigInt(value);
@@ -48,10 +48,16 @@ export function resolveHttpNetworkAccounts(
4848
});
4949
}
5050

51-
if (isHdAccountsConfig(accounts)) {
51+
if (isHdAccountsUserConfig(accounts)) {
52+
const { passphrase: defaultPassphrase, ...defaultHdAccountRest } =
53+
DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS;
54+
const { mnemonic, passphrase, ...hdAccountRest } = accounts;
55+
5256
return {
53-
...DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS,
54-
...accounts,
57+
...defaultHdAccountRest,
58+
...hdAccountRest,
59+
mnemonic: resolveConfigurationVariable(mnemonic),
60+
passphrase: resolveConfigurationVariable(passphrase ?? defaultPassphrase),
5561
};
5662
}
5763

@@ -62,27 +68,41 @@ export function resolveEdrNetworkAccounts(
6268
accounts:
6369
| EdrNetworkAccountsUserConfig
6470
| undefined = DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS,
71+
resolveConfigurationVariable: ConfigurationResolver,
6572
): EdrNetworkAccountsConfig {
6673
if (Array.isArray(accounts)) {
67-
return accounts.map(({ privateKey, balance }) => ({
68-
privateKey: normalizeHexString(privateKey),
69-
balance: BigInt(balance),
70-
}));
74+
return accounts.map(({ privateKey, balance }) => {
75+
if (typeof privateKey === "string") {
76+
privateKey = normalizeHexString(privateKey);
77+
}
78+
79+
return {
80+
privateKey: resolveConfigurationVariable(privateKey),
81+
balance: BigInt(balance),
82+
};
83+
});
7184
}
7285

86+
const {
87+
mnemonic: defaultMnemonic,
88+
accountsBalance: defaultAccountsBalance,
89+
passphrase: defaultPassphrase,
90+
...defaultHdAccountRest
91+
} = DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS;
92+
const { mnemonic, passphrase, accountsBalance, ...hdAccountRest } = accounts;
7393
return {
74-
...DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS,
75-
...accounts,
76-
accountsBalance: BigInt(
77-
accounts.accountsBalance ??
78-
DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS.accountsBalance,
79-
),
94+
...defaultHdAccountRest,
95+
...hdAccountRest,
96+
mnemonic: resolveConfigurationVariable(mnemonic ?? defaultMnemonic),
97+
accountsBalance: BigInt(accountsBalance ?? defaultAccountsBalance),
98+
passphrase: resolveConfigurationVariable(passphrase ?? defaultPassphrase),
8099
};
81100
}
82101

83102
export function resolveForkingConfig(
84103
forkingUserConfig: EdrNetworkForkingUserConfig | undefined,
85104
cacheDir: string,
105+
resolveConfigurationVariable: ConfigurationResolver,
86106
): EdrNetworkForkingConfig | undefined {
87107
if (forkingUserConfig === undefined) {
88108
return undefined;
@@ -98,7 +118,7 @@ export function resolveForkingConfig(
98118

99119
return {
100120
enabled: forkingUserConfig.enabled ?? true,
101-
url: forkingUserConfig.url,
121+
url: resolveConfigurationVariable(forkingUserConfig.url),
102122
cacheDir: path.join(cacheDir, "edr-fork-cache"),
103123
blockNumber:
104124
forkingUserConfig.blockNumber !== undefined
@@ -274,7 +294,7 @@ export function resolveHardfork(
274294
}
275295

276296
if (enableTransientStorage === true) {
277-
return HardforkName.CANCUN;
297+
return LATEST_HARDFORK;
278298
} else {
279299
return HardforkName.SHANGHAI;
280300
}

v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts

+17-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import type { SolidityStackTrace } from "./stack-traces/solidity-stack-trace.js";
22
import type { LoggerConfig } from "./types/logger.js";
33
import type { TracingConfig } from "./types/node-types.js";
4-
import type {
5-
EdrNetworkConfig,
6-
EdrNetworkHDAccountsConfig,
7-
} from "../../../../types/config.js";
4+
import type { EdrNetworkConfig } from "../../../../types/config.js";
85
import type {
96
EthereumProvider,
107
EthSubscription,
@@ -18,6 +15,7 @@ import type {
1815
CompilerInput,
1916
CompilerOutput,
2017
} from "../../../../types/solidity/compiler-io.js";
18+
import type { DefaultHDAccountsConfigParams } from "../accounts/derive-private-keys.js";
2119
import type { JsonRpcRequestWrapperFunction } from "../network-manager.js";
2220
import type {
2321
RawTrace,
@@ -81,10 +79,16 @@ const log = debug("hardhat:core:hardhat-network:provider");
8179
export const EDR_NETWORK_DEFAULT_COINBASE =
8280
"0xc014ba5ec014ba5ec014ba5ec014ba5ec014ba5e";
8381

82+
interface EdrNetworkDefaultHDAccountsConfigParams
83+
extends DefaultHDAccountsConfigParams {
84+
mnemonic: string;
85+
accountsBalance: bigint;
86+
}
87+
8488
export const EDR_NETWORK_MNEMONIC =
8589
"test test test test test test test test test test test junk";
8690
export const DEFAULT_EDR_NETWORK_BALANCE = 10000000000000000000000n;
87-
export const DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS: EdrNetworkHDAccountsConfig =
91+
export const DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS: EdrNetworkDefaultHDAccountsConfigParams =
8892
{
8993
...DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS,
9094
mnemonic: EDR_NETWORK_MNEMONIC,
@@ -141,12 +145,14 @@ export class EdrProvider extends EventEmitter implements EthereumProvider {
141145

142146
const vmTraceDecoder = await createVmTraceDecoder();
143147

148+
const providerConfig = await getProviderConfig(networkConfig);
149+
144150
const context = await getGlobalEdrContext();
145151
const provider = await context.createProvider(
146152
networkConfig.chainType === "optimism"
147153
? OPTIMISM_CHAIN_TYPE
148154
: GENERIC_CHAIN_TYPE, // TODO: l1 is missing here
149-
getProviderConfig(networkConfig),
155+
providerConfig,
150156
{
151157
enable: loggerConfig.enabled,
152158
decodeConsoleLogInputsCallback: ConsoleLogger.getDecodedLogs,
@@ -537,7 +543,9 @@ export class EdrProvider extends EventEmitter implements EthereumProvider {
537543
}
538544
}
539545

540-
function getProviderConfig(networkConfig: EdrNetworkConfig): ProviderConfig {
546+
async function getProviderConfig(
547+
networkConfig: EdrNetworkConfig,
548+
): Promise<ProviderConfig> {
541549
return {
542550
allowBlocksWithSameTimestamp: networkConfig.allowBlocksWithSameTimestamp,
543551
allowUnlimitedContractSize: networkConfig.allowUnlimitedContractSize,
@@ -550,8 +558,8 @@ function getProviderConfig(networkConfig: EdrNetworkConfig): ProviderConfig {
550558
// TODO: remove this cast when EDR updates the interface to accept Uint8Array
551559
coinbase: Buffer.from(networkConfig.coinbase),
552560
enableRip7212: networkConfig.enableRip7212,
553-
fork: hardhatForkingConfigToEdrForkConfig(networkConfig.forking),
554-
genesisAccounts: hardhatAccountsToEdrGenesisAccounts(
561+
fork: await hardhatForkingConfigToEdrForkConfig(networkConfig.forking),
562+
genesisAccounts: await hardhatAccountsToEdrGenesisAccounts(
555563
networkConfig.accounts,
556564
),
557565
hardfork: hardhatHardforkToEdrSpecId(networkConfig.hardfork),

v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/types/hardfork.ts

+19
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,22 @@ export enum HardforkName {
1717
SHANGHAI = "shanghai",
1818
CANCUN = "cancun",
1919
}
20+
21+
const HARDFORK_ORDER = Object.values(HardforkName);
22+
23+
export const LATEST_HARDFORK: HardforkName =
24+
HARDFORK_ORDER[HARDFORK_ORDER.length - 1];
25+
26+
/**
27+
* Check if `hardforkA` is greater than or equal to `hardforkB`,
28+
* that is, if it includes all its changes.
29+
*/
30+
export function hardforkGte(
31+
hardforkA: HardforkName,
32+
hardforkB: HardforkName,
33+
): boolean {
34+
const indexA = HARDFORK_ORDER.lastIndexOf(hardforkA);
35+
const indexB = HARDFORK_ORDER.lastIndexOf(hardforkB);
36+
37+
return indexA >= indexB;
38+
}

v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts

+18-17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
} from "@ignored/edr-optimism";
3939
import { bytesToHexString } from "@ignored/hardhat-vnext-utils/bytes";
4040

41+
import { FixedValueConfigurationVariable } from "../../../../core/configuration-variables.js";
4142
import { derivePrivateKeys } from "../../accounts/derive-private-keys.js";
4243
import { DEFAULT_EDR_NETWORK_BALANCE } from "../edr-provider.js";
4344
import { HardforkName } from "../types/hardfork.js";
@@ -220,34 +221,34 @@ export function edrRpcDebugTraceToHardhat(
220221
};
221222
}
222223

223-
export function hardhatAccountsToEdrGenesisAccounts(
224+
export async function hardhatAccountsToEdrGenesisAccounts(
224225
accounts: EdrNetworkAccountsConfig,
225-
): GenesisAccount[] {
226-
const normalizedAccounts = normalizeEdrNetworkAccountsConfig(accounts);
226+
): Promise<GenesisAccount[]> {
227+
const normalizedAccounts = await normalizeEdrNetworkAccountsConfig(accounts);
227228

228-
return normalizedAccounts.map((account) => {
229-
return {
230-
secretKey: account.privateKey,
231-
balance: account.balance,
232-
};
233-
});
229+
const accountPromises = normalizedAccounts.map(async (account) => ({
230+
secretKey: await account.privateKey.getHexString(),
231+
balance: account.balance,
232+
}));
233+
234+
return Promise.all(accountPromises);
234235
}
235236

236-
function normalizeEdrNetworkAccountsConfig(
237+
async function normalizeEdrNetworkAccountsConfig(
237238
accounts: EdrNetworkAccountsConfig,
238-
): EdrNetworkAccountConfig[] {
239+
): Promise<EdrNetworkAccountConfig[]> {
239240
if (Array.isArray(accounts)) {
240241
return accounts;
241242
}
242243

243244
return derivePrivateKeys(
244-
accounts.mnemonic,
245+
await accounts.mnemonic.get(),
245246
accounts.path,
246247
accounts.initialIndex,
247248
accounts.count,
248-
accounts.passphrase,
249+
await accounts.passphrase.get(),
249250
).map((pk) => ({
250-
privateKey: bytesToHexString(pk),
251+
privateKey: new FixedValueConfigurationVariable(bytesToHexString(pk)),
251252
balance: accounts.accountsBalance ?? DEFAULT_EDR_NETWORK_BALANCE,
252253
}));
253254
}
@@ -278,13 +279,13 @@ export function hardhatChainsToEdrChains(
278279
return edrChains;
279280
}
280281

281-
export function hardhatForkingConfigToEdrForkConfig(
282+
export async function hardhatForkingConfigToEdrForkConfig(
282283
forkingConfig: EdrNetworkForkingConfig | undefined,
283-
): ForkConfig | undefined {
284+
): Promise<ForkConfig | undefined> {
284285
let fork: ForkConfig | undefined;
285286
if (forkingConfig !== undefined && forkingConfig.enabled === true) {
286287
fork = {
287-
jsonRpcUrl: forkingConfig.url,
288+
jsonRpcUrl: await forkingConfig.url.getUrl(),
288289
blockNumber: forkingConfig.blockNumber,
289290
httpHeaders: forkingConfig.httpHeaders,
290291
};

v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/config.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ import {
2525
resolveInitialBaseFeePerGas,
2626
resolveMiningConfig,
2727
} from "../config-resolution.js";
28-
import { validateUserConfig } from "../type-validation.js";
28+
import { validateNetworkUserConfig } from "../type-validation.js";
2929

3030
export default async (): Promise<Partial<ConfigHooks>> => ({
3131
extendUserConfig,
32-
validateUserConfig,
32+
validateUserConfig: validateNetworkUserConfig,
3333
resolveUserConfig,
3434
});
3535

@@ -113,7 +113,7 @@ export async function resolveUserConfig(
113113
gas: resolveGasConfig(networkConfig.gas),
114114
gasMultiplier: networkConfig.gasMultiplier ?? 1,
115115
gasPrice: resolveGasConfig(networkConfig.gasPrice),
116-
url: networkConfig.url,
116+
url: resolveConfigurationVariable(networkConfig.url),
117117
timeout: networkConfig.timeout ?? 20_000,
118118
httpHeaders: networkConfig.httpHeaders ?? {},
119119
};
@@ -124,7 +124,10 @@ export async function resolveUserConfig(
124124
if (networkConfig.type === "edr") {
125125
const resolvedNetworkConfig: EdrNetworkConfig = {
126126
type: "edr",
127-
accounts: resolveEdrNetworkAccounts(networkConfig.accounts),
127+
accounts: resolveEdrNetworkAccounts(
128+
networkConfig.accounts,
129+
resolveConfigurationVariable,
130+
),
128131
chainId: networkConfig.chainId ?? 31337,
129132
chainType: networkConfig.chainType,
130133
from: networkConfig.from,
@@ -144,6 +147,7 @@ export async function resolveUserConfig(
144147
forking: resolveForkingConfig(
145148
networkConfig.forking,
146149
resolvedConfig.paths.cache,
150+
resolveConfigurationVariable,
147151
),
148152
hardfork: resolveHardfork(
149153
networkConfig.hardfork,

v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export class NetworkManagerImplementation implements NetworkManager {
180180
}
181181

182182
return HttpProvider.create({
183-
url: resolvedNetworkConfig.url,
183+
url: await resolvedNetworkConfig.url.getUrl(),
184184
networkName: resolvedNetworkName,
185185
extraHeaders: resolvedNetworkConfig.httpHeaders,
186186
timeout: resolvedNetworkConfig.timeout,

v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/hanlders-array.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ export async function createHandlersArray<
100100
requestHandlers.push(
101101
new HDWalletHandler(
102102
networkConnection.provider,
103-
accounts.mnemonic,
103+
await accounts.mnemonic.get(),
104104
accounts.path,
105105
accounts.initialIndex,
106106
accounts.count,
107-
accounts.passphrase,
107+
await accounts.passphrase.get(),
108108
),
109109
);
110110
}

0 commit comments

Comments
 (0)