diff --git a/packages/hardhat-zksync-node/src/index.ts b/packages/hardhat-zksync-node/src/index.ts index fc91d2fb7..43f48011c 100644 --- a/packages/hardhat-zksync-node/src/index.ts +++ b/packages/hardhat-zksync-node/src/index.ts @@ -2,12 +2,14 @@ import { spawn } from 'child_process'; import { task, subtask, types } from 'hardhat/config'; import { TASK_COMPILE, + TASK_NODE, TASK_TEST, TASK_TEST_GET_TEST_FILES, TASK_TEST_RUN_MOCHA_TESTS, } from 'hardhat/builtin-tasks/task-names'; import { HARDHAT_NETWORK_NAME } from 'hardhat/plugins'; +import { TaskArguments } from 'hardhat/types'; import { MAX_PORT_ATTEMPTS, START_PORT, @@ -16,7 +18,7 @@ import { TASK_NODE_ZKSYNC_DOWNLOAD_BINARY, TASK_RUN_NODE_ZKSYNC_IN_SEPARATE_PROCESS, } from './constants'; -import { JsonRpcServer } from './server'; +import { JsonRpcServer, RpcServer } from './server'; import { adjustTaskArgsForPort, configureNetwork, @@ -75,9 +77,68 @@ subtask(TASK_NODE_ZKSYNC_CREATE_SERVER, 'Creates a JSON-RPC server for ZKsync no }, ); +task(TASK_NODE, 'Start a ZKSync Node') + .addOptionalParam('log', 'Log filter level (error, warn, info, debug) - default: info', undefined, types.string) + .addOptionalParam( + 'logFilePath', + 'Path to the file where logs should be written - default: `era_test_node.log`', + undefined, + types.string, + ) + .addOptionalParam('cache', 'Cache type (none, disk, memory) - default: disk', undefined, types.string) + .addOptionalParam( + 'cacheDir', + 'Cache directory location for `disk` cache - default: `.cache`', + undefined, + types.string, + ) + .addFlag('resetCache', 'Reset the local `disk` cache') + .addOptionalParam( + 'showCalls', + 'Show call debug information (none, user, system, all) - default: none', + undefined, + types.string, + ) + .addOptionalParam( + 'showStorageLogs', + 'Show storage log information (none, read, write, all) - default: none', + undefined, + types.string, + ) + .addOptionalParam( + 'showVmDetails', + 'Show VM details information (none, all) - default: none', + undefined, + types.string, + ) + .addOptionalParam( + 'showGasDetails', + 'Show Gas details information (none, all) - default: none', + undefined, + types.string, + ) + .addFlag( + 'resolveHashes', + 'Try to contact openchain to resolve the ABI & topic names. It enabled, it makes debug log more readable, but will decrease the performance', + ) + .addFlag( + 'devUseLocalContracts', + 'Loads the locally compiled system contracts (useful when doing changes to system contracts or bootloader)', + ) + .addOptionalParam('replayTx', 'Transaction hash to replay', undefined, types.string) + .addOptionalParam('tag', 'Specified node release for use', undefined) + // .addOptionalParam('force', 'Force download', undefined, types.boolean) + .setAction(async (args: TaskArguments, { network, run }, runSuper) => { + if (network.zksync !== true || network.name !== HARDHAT_NETWORK_NAME) { + return await runSuper(); + } + + await run(TASK_NODE_ZKSYNC, args); + }); + // Main task of the plugin. It starts the server and listens for requests. task(TASK_NODE_ZKSYNC, 'Starts a JSON-RPC server for ZKsync node') - .addOptionalParam('port', 'Port to listen on - default: 8011', undefined, types.int) + .addOptionalParam('port', 'Port to listen on - default: 8545', 8545, types.int) .addOptionalParam('log', 'Log filter level (error, warn, info, debug) - default: info', undefined, types.string) .addOptionalParam( 'logFilePath', @@ -196,7 +257,7 @@ task(TASK_NODE_ZKSYNC, 'Starts a JSON-RPC server for ZKsync node') const binaryPath: string = await run(TASK_NODE_ZKSYNC_DOWNLOAD_BINARY, { force: false, tag }); // Create the server - const server: JsonRpcServer = await run(TASK_NODE_ZKSYNC_CREATE_SERVER, { binaryPath }); + const server: RpcServer = await run(TASK_NODE_ZKSYNC_CREATE_SERVER, { binaryPath }); try { await server.listen(commandArgs); diff --git a/packages/hardhat-zksync-node/src/server.ts b/packages/hardhat-zksync-node/src/server.ts index 620a853fe..c9bf7e76f 100644 --- a/packages/hardhat-zksync-node/src/server.ts +++ b/packages/hardhat-zksync-node/src/server.ts @@ -3,7 +3,12 @@ import chalk from 'chalk'; import { PROCESS_TERMINATION_SIGNALS } from './constants'; -export class JsonRpcServer { +export interface RpcServer { + listen(args?: string[], blockProcess?: boolean): Promise; + stop(): Promise; +} + +export class JsonRpcServer implements RpcServer { private serverProcess: ChildProcess | null = null; // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/packages/hardhat-zksync-node/src/utils.ts b/packages/hardhat-zksync-node/src/utils.ts index e2aa8b59d..43a6aba63 100644 --- a/packages/hardhat-zksync-node/src/utils.ts +++ b/packages/hardhat-zksync-node/src/utils.ts @@ -19,16 +19,20 @@ import { ALLOWED_SHOW_STORAGE_LOGS_VALUES, ALLOWED_SHOW_VM_DETAILS_VALUES, BASE_URL, + MAX_PORT_ATTEMPTS, NETWORK_ACCOUNTS, NETWORK_ETH, NETWORK_GAS, NETWORK_GAS_PRICE, PLATFORM_MAP, + START_PORT, TEMP_FILE_PREFIX, ZKSYNC_ERA_TEST_NODE_NETWORK_NAME, } from './constants'; import { ZkSyncNodePluginError } from './errors'; import { CommandArguments } from './types'; +import { RPCServerDownloader } from './downloader'; +import { JsonRpcServer } from './server'; // Generates command arguments for running the era-test-node binary export function constructCommandArgs(args: CommandArguments): string[] { @@ -406,3 +410,25 @@ export async function configureNetwork(config: HardhatConfig, network: any, port config.networks[network.name] = network.config; network.provider = await createProvider(config, network.name); } + +export const startServer = async (tag?: string, force: boolean = false) => { + const platform = getPlatform(); + if (platform === 'windows' || platform === '') { + throw new ZkSyncNodePluginError(`Unsupported platform: ${platform}`); + } + const rpcServerBinaryDir = await getRPCServerBinariesDir(); + + const downloader: RPCServerDownloader = new RPCServerDownloader(rpcServerBinaryDir, tag || 'latest'); + + await downloader.downloadIfNeeded(force); + const binaryPath = await downloader.getBinaryPath(); + + const currentPort = await getAvailablePort(START_PORT, MAX_PORT_ATTEMPTS); + const commandArgs = constructCommandArgs({ port: currentPort }); + + return { + commandArgs, + server: new JsonRpcServer(binaryPath), + port: currentPort, + }; +};