Skip to content

Commit

Permalink
Merge pull request #6003 from NomicFoundation/network-manager-cleanup
Browse files Browse the repository at this point in the history
Network manager cleanup Pt1
  • Loading branch information
schaable authored Dec 6, 2024
2 parents e03d452 + 1f38ada commit 58a3d31
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
CompilerInput,
CompilerOutput,
} from "../../../../types/solidity/compiler-io.js";
import type { JsonRpcRequestWrapperFunction } from "../network-manager.js";
import type {
RawTrace,
SubscriptionEvent,
Expand Down Expand Up @@ -92,10 +93,12 @@ export async function getGlobalEdrContext(): Promise<EdrContext> {
return _globalEdrContext;
}

export type JsonRpcRequestWrapperFunction = (
request: JsonRpcRequest,
defaultBehavior: (r: JsonRpcRequest) => Promise<JsonRpcResponse>,
) => Promise<JsonRpcResponse>;
interface EdrProviderConfig {
networkConfig: EdrNetworkConfig;
loggerConfig?: LoggerConfig;
tracingConfig?: TracingConfig;
jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction;
}

export class EdrProvider extends EventEmitter implements EthereumProvider {
readonly #provider: Provider;
Expand All @@ -107,23 +110,25 @@ export class EdrProvider extends EventEmitter implements EthereumProvider {
#vmTracer?: VMTracerT;
#nextRequestId = 1;

// TODO: should take an object with all the config like the HTTP provider
public static async create(
config: EdrNetworkConfig,
loggerConfig: LoggerConfig,
tracingConfig?: TracingConfig,
jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction,
): Promise<EdrProvider> {
const coinbase = config.coinbase ?? DEFAULT_COINBASE;
/**
* Creates a new instance of `EdrProvider`.
*/
public static async create({
networkConfig,
loggerConfig = { enabled: false },
tracingConfig = {},
jsonRpcRequestWrapper,
}: EdrProviderConfig): Promise<EdrProvider> {
const coinbase = networkConfig.coinbase ?? DEFAULT_COINBASE;

let fork;
if (config.forkConfig !== undefined) {
if (networkConfig.forkConfig !== undefined) {
let httpHeaders: HttpHeader[] | undefined;
if (config.forkConfig.httpHeaders !== undefined) {
if (networkConfig.forkConfig.httpHeaders !== undefined) {
httpHeaders = [];

for (const [name, value] of Object.entries(
config.forkConfig.httpHeaders,
networkConfig.forkConfig.httpHeaders,
)) {
httpHeaders.push({
name,
Expand All @@ -133,66 +138,70 @@ export class EdrProvider extends EventEmitter implements EthereumProvider {
}

fork = {
jsonRpcUrl: config.forkConfig.jsonRpcUrl,
jsonRpcUrl: networkConfig.forkConfig.jsonRpcUrl,
blockNumber:
config.forkConfig.blockNumber !== undefined
? BigInt(config.forkConfig.blockNumber)
networkConfig.forkConfig.blockNumber !== undefined
? BigInt(networkConfig.forkConfig.blockNumber)
: undefined,
httpHeaders,
};
}

const initialDate =
config.initialDate !== undefined
? BigInt(Math.floor(config.initialDate.getTime() / 1000))
networkConfig.initialDate !== undefined
? BigInt(Math.floor(networkConfig.initialDate.getTime() / 1000))
: undefined;

const printLineFn = loggerConfig.printLineFn ?? printLine;
const replaceLastLineFn = loggerConfig.replaceLastLineFn ?? replaceLastLine;

const vmTraceDecoder = await createVmTraceDecoder();

const hardforkName = getHardforkName(config.hardfork);
const hardforkName = getHardforkName(networkConfig.hardfork);

const context = await getGlobalEdrContext();
const provider = await context.createProvider(
config.chainType === "optimism"
networkConfig.chainType === "optimism"
? OPTIMISM_CHAIN_TYPE
: GENERIC_CHAIN_TYPE, // TODO: l1 is missing here
{
allowBlocksWithSameTimestamp:
config.allowBlocksWithSameTimestamp ?? false,
allowUnlimitedContractSize: config.allowUnlimitedContractSize,
bailOnCallFailure: config.throwOnCallFailures,
bailOnTransactionFailure: config.throwOnTransactionFailures,
blockGasLimit: BigInt(config.blockGasLimit),
chainId: BigInt(config.chainId),
chains: this.#convertToEdrChains(config.chains),
cacheDir: config.forkCachePath,
networkConfig.allowBlocksWithSameTimestamp ?? false,
allowUnlimitedContractSize: networkConfig.allowUnlimitedContractSize,
bailOnCallFailure: networkConfig.throwOnCallFailures,
bailOnTransactionFailure: networkConfig.throwOnTransactionFailures,
blockGasLimit: BigInt(networkConfig.blockGasLimit),
chainId: BigInt(networkConfig.chainId),
chains: this.#convertToEdrChains(networkConfig.chains),
cacheDir: networkConfig.forkCachePath,
coinbase: Buffer.from(coinbase.slice(2), "hex"),
enableRip7212: config.enableRip7212,
enableRip7212: networkConfig.enableRip7212,
fork,
hardfork: ethereumsjsHardforkToEdrSpecId(hardforkName),
genesisAccounts: config.genesisAccounts.map((account) => {
genesisAccounts: networkConfig.genesisAccounts.map((account) => {
return {
secretKey: account.privateKey,
balance: BigInt(account.balance),
};
}),
initialDate,
initialBaseFeePerGas:
config.initialBaseFeePerGas !== undefined
? BigInt(config.initialBaseFeePerGas)
networkConfig.initialBaseFeePerGas !== undefined
? BigInt(networkConfig.initialBaseFeePerGas)
: undefined,
minGasPrice: config.minGasPrice,
minGasPrice: networkConfig.minGasPrice,
mining: {
autoMine: config.automine,
interval: ethereumjsIntervalMiningConfigToEdr(config.intervalMining),
autoMine: networkConfig.automine,
interval: ethereumjsIntervalMiningConfigToEdr(
networkConfig.intervalMining,
),
memPool: {
order: ethereumjsMempoolOrderToEdrMineOrdering(config.mempoolOrder),
order: ethereumjsMempoolOrderToEdrMineOrdering(
networkConfig.mempoolOrder,
),
},
},
networkId: BigInt(config.networkId),
networkId: BigInt(networkConfig.networkId),
},
{
enable: loggerConfig.enabled,
Expand Down Expand Up @@ -231,6 +240,13 @@ export class EdrProvider extends EventEmitter implements EthereumProvider {
return edrProvider;
}

/**
* @private
*
* This constructor is intended for internal use only.
* Use the static method {@link EdrProvider.create} to create an instance of
* `EdrProvider`.
*/
private constructor(
provider: Provider,
vmTraceDecoder: VmTraceDecoder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export async function extendUserConfig(
const networks: Record<string, NetworkUserConfig> =
extendedConfig.networks ?? {};

// TODO: we should address this casting when edr is implemented
const localhostConfig: Omit<HttpNetworkUserConfig, "url"> = {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- This is always http
...(networks.localhost as HttpNetworkUserConfig),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { JsonRpcRequestWrapperFunction } from "./network-manager.js";
import type {
EthereumProvider,
JsonRpcRequest,
Expand Down Expand Up @@ -39,10 +40,14 @@ const TOO_MANY_REQUEST_STATUS = 429;
const MAX_RETRIES = 6;
const MAX_RETRY_WAIT_TIME_SECONDS = 5;

export type JsonRpcRequestWrapperFunction = (
request: JsonRpcRequest,
defaultBehavior: (r: JsonRpcRequest) => Promise<JsonRpcResponse>,
) => Promise<JsonRpcResponse>;
interface HttpProviderConfig {
url: string;
networkName: string;
extraHeaders?: Record<string, string>;
timeout: number;
jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction;
testDispatcher?: Dispatcher;
}

export class HttpProvider extends EventEmitter implements EthereumProvider {
readonly #url: string;
Expand All @@ -62,20 +67,16 @@ export class HttpProvider extends EventEmitter implements EthereumProvider {
extraHeaders = {},
timeout,
jsonRpcRequestWrapper,
}: {
url: string;
networkName: string;
extraHeaders?: Record<string, string>;
timeout: number;
jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction;
}): Promise<HttpProvider> {
testDispatcher,
}: HttpProviderConfig): Promise<HttpProvider> {
if (!isValidUrl(url)) {
throw new HardhatError(HardhatError.ERRORS.NETWORK.INVALID_URL, {
value: url,
});
}

const dispatcher = await getHttpDispatcher(url, timeout);
const dispatcher =
testDispatcher ?? (await getHttpDispatcher(url, timeout));

const httpProvider = new HttpProvider(
url,
Expand All @@ -95,8 +96,7 @@ export class HttpProvider extends EventEmitter implements EthereumProvider {
* Use the static method {@link HttpProvider.create} to create an instance of
* `HttpProvider`.
*/
// TODO: make the constructor private, but we need to fix the tests first
constructor(
private constructor(
url: string,
networkName: string,
extraHeaders: Record<string, string>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@ import type {
ChainType,
DefaultChainType,
NetworkConnection,
NetworkManager,
} from "../../../types/network.js";
import type { EthereumProvider } from "../../../types/providers.js";
import type {
EthereumProvider,
JsonRpcRequest,
JsonRpcResponse,
} from "../../../types/providers.js";

import {
assertHardhatInvariant,
HardhatError,
} from "@ignored/hardhat-vnext-errors";
import { HardhatError } from "@ignored/hardhat-vnext-errors";

import { EdrProvider } from "./edr/edr-provider.js";
import { HttpProvider } from "./http-provider.js";
import { NetworkConnectionImplementation } from "./network-connection.js";
import { isNetworkConfig, validateNetworkConfig } from "./type-validation.js";

export class NetworkManagerImplementation {
export type JsonRpcRequestWrapperFunction = (
request: JsonRpcRequest,
defaultBehavior: (r: JsonRpcRequest) => Promise<JsonRpcResponse>,
) => Promise<JsonRpcResponse>;

export class NetworkManagerImplementation implements NetworkManager {
readonly #defaultNetwork: string;
readonly #defaultChainType: DefaultChainType;
readonly #networkConfigs: Readonly<Record<string, Readonly<NetworkConfig>>>;
Expand Down Expand Up @@ -136,11 +143,16 @@ export class NetworkManagerImplementation {
const createProvider = async (
networkConnection: NetworkConnectionImplementation<ChainTypeT>,
): Promise<EthereumProvider> => {
assertHardhatInvariant(
resolvedNetworkConfig.type === "edr" ||
resolvedNetworkConfig.type === "http",
`Invalid network type ${resolvedNetworkConfig.type}`,
);
const jsonRpcRequestWrapper: JsonRpcRequestWrapperFunction = (
request,
defaultBehavior,
) =>
hookManager.runHandlerChain(
"network",
"onRequest",
[networkConnection, request],
async (_context, _connection, req) => defaultBehavior(req),
);

if (resolvedNetworkConfig.type === "edr") {
if (
Expand All @@ -154,40 +166,25 @@ export class NetworkManagerImplementation {
);
}

return EdrProvider.create(
return EdrProvider.create({
// The resolvedNetworkConfig can have its chainType set to `undefined`
// so we default to the default chain type here.
{
networkConfig: {
...resolvedNetworkConfig,
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions --
This case is safe because we have a check above */
chainType: resolvedChainType as ChainType,
},
{ enabled: false },
{},
(request, defaultBehavior) => {
return hookManager.runHandlerChain(
"network",
"onRequest",
[networkConnection, request],
async (_context, _connection, req) => defaultBehavior(req),
);
},
);
jsonRpcRequestWrapper,
});
}

return HttpProvider.create({
url: resolvedNetworkConfig.url,
networkName: resolvedNetworkName,
extraHeaders: resolvedNetworkConfig.httpHeaders,
timeout: resolvedNetworkConfig.timeout,
jsonRpcRequestWrapper: (request, defaultBehavior) =>
hookManager.runHandlerChain(
"network",
"onRequest",
[networkConnection, request],
async (_context, _connection, req) => defaultBehavior(req),
),
jsonRpcRequestWrapper,
});
};

Expand Down
Loading

0 comments on commit 58a3d31

Please sign in to comment.