Skip to content
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

feat: set default version and handle github repo redirects #1577

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/hardhat-zksync-node/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export const ALLOWED_SHOW_VM_DETAILS_VALUES = ['none', 'all'];
export const ALLOWED_SHOW_GAS_DETAILS_VALUES = ['none', 'all'];

export const DEFAULT_RELEASE_VERSION_INFO_CACHE_PERIOD = 24 * 60 * 60 * 1000; // 24 hours
export const DEFAULT_RELEASE_CACHE_FILE_NAME = 'latestRelease.json';

export const DEFAULT_RELEASE_CACHE_FILE_NAME = 'list.json';
export const ERA_TEST_NODE_BINARY_VERSION = '0.1.0';
export const PLATFORM_MAP: Record<string, string> = {
darwin: 'apple-darwin',
linux: 'unknown-linux-gnu',
Expand Down Expand Up @@ -53,6 +53,8 @@ export const NETWORK_ETH = {
LOCALHOST: 'localhost',
};

export const DEFAULT_ZKSYNC_ANVIL_VERSION = '0.2.*';

export const DEFAULT_TIMEOUT_MILISECONDS = 30000;

// export const TOOLCHAIN_MAP: Record<string, string> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async function wrapTaskWithNode(taskArgs: TaskArguments, env: any, runSuper: Run
return await runSuper(taskArgs);
}
const zkSyncGlobal = global as ZKSyncTasksWithWrappedNode;
const { commandArgs, server, port } = await startServer();
const { commandArgs, server, port } = await startServer(env.config.zksyncAnvil.version);
try {
await server.listen(commandArgs, false);
await waitForNodeToBeReady(port);
Expand Down
18 changes: 13 additions & 5 deletions packages/hardhat-zksync-node/src/core/script-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { startServer, waitForNodeToBeReady } from '../utils';

export async function runScript(
scriptPath: string,
zksyncAnvilVersion: string,
scriptArgs: string[] = [],
extraNodeArgs: string[] = [],
extraEnvVars: { [name: string]: string } = {},
Expand All @@ -19,7 +20,7 @@ export async function runScript(
...extraNodeArgs,
];

const { commandArgs, server, port } = await startServer();
const { commandArgs, server, port } = await startServer(zksyncAnvilVersion);
await server.listen(commandArgs, false);
await waitForNodeToBeReady(port);

Expand All @@ -46,15 +47,22 @@ export async function runScript(

export async function runScriptWithHardhat(
hardhatArguments: HardhatArguments,
zksyncAnvilVersion: string,
scriptPath: string,
scriptArgs: string[] = [],
extraNodeArgs: string[] = [],
extraEnvVars: { [name: string]: string } = {},
): Promise<number> {
return runScript(scriptPath, scriptArgs, [...extraNodeArgs, '--require', path.join(__dirname, 'register')], {
...getEnvVariablesMap(hardhatArguments),
...extraEnvVars,
});
return runScript(
scriptPath,
zksyncAnvilVersion,
scriptArgs,
[...extraNodeArgs, '--require', path.join(__dirname, 'register')],
{
...getEnvVariablesMap(hardhatArguments),
...extraEnvVars,
},
);
}

function withFixedInspectArg(argv: string[]) {
Expand Down
132 changes: 52 additions & 80 deletions packages/hardhat-zksync-node/src/downloader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import fse from 'fs-extra';
import chalk from 'chalk';
import { download, getLatestRelease, getNodeUrl } from './utils';
import { download, getAllTags, getLatestRelease, getNodeUrl, resolveTag } from './utils';
import { ZkSyncNodePluginError } from './errors';
import {
DEFAULT_RELEASE_CACHE_FILE_NAME,
Expand All @@ -15,76 +15,41 @@ import {
} from './constants';

export class RPCServerDownloader {
private readonly _tagRegex: RegExp = /^\d+\.\d+\.(\d+)(-[A-Za-z0-9.]+)?$|^\d+\.\d+\.\*(?!-)[A-Za-z0-9.]*$/;
private readonly _binaryDir: string;
private readonly _tag: string;
private readonly _releaseInfoFile: string = DEFAULT_RELEASE_CACHE_FILE_NAME;
private readonly _releaseInfoFilePath: string;
private _tag?: string;
private readonly _initialTag: string;
private readonly _tagsInfoFile: string = DEFAULT_RELEASE_CACHE_FILE_NAME;
private readonly _tagsInfoFilePath: string;

constructor(binaryDir: string, tag: string) {
constructor(binaryDir: string, initialTag: string) {
this._binaryDir = binaryDir;
this._tag = tag;
this._releaseInfoFilePath = path.join(this._binaryDir, this._releaseInfoFile);
if (!this._tagRegex.test(initialTag) && initialTag !== 'latest') {
throw new ZkSyncNodePluginError(`Invalid tag format: ${initialTag}`);
}
this._initialTag = initialTag;
this._tagsInfoFilePath = path.join(this._binaryDir, this._tagsInfoFile);
}

public async downloadIfNeeded(force: boolean): Promise<void> {
if (!(await this._isTagsInfoValid()) || force) {
await this._downloadTagInfo();
}

const tagsInfo = await this._getTagsInfo();
this._tag = resolveTag(tagsInfo.tags, tagsInfo.latest, this._initialTag);

if (force) {
const releaseTag = this._isLatestTag()
? await getLatestRelease(
ZKNODE_BIN_OWNER,
ZKNODE_BIN_REPOSITORY_NAME,
USER_AGENT,
DEFAULT_TIMEOUT_MILISECONDS,
)
: this._tag;
await this._download(releaseTag);
await this._download(this._tag);
return;
}

if (this._isLatestTag()) {
if (!(await this._isLatestReleaseInfoValid())) {
const latestTag = await getLatestRelease(
ZKNODE_BIN_OWNER,
ZKNODE_BIN_REPOSITORY_NAME,
USER_AGENT,
DEFAULT_TIMEOUT_MILISECONDS,
);

if (await this._isBinaryPathExists(latestTag)) {
await this._postProcessDownload(latestTag);
return;
}

await this._download(latestTag);
return;
}

const info = await this._getLatestReleaseInfo();
if (info && (await this._isBinaryPathExists(info.latest))) {
return;
}

const latestTagForLatestRelease = await getLatestRelease(
ZKNODE_BIN_OWNER,
ZKNODE_BIN_REPOSITORY_NAME,
USER_AGENT,
DEFAULT_TIMEOUT_MILISECONDS,
);

if (
info &&
info.latest === latestTagForLatestRelease &&
(await this._isBinaryPathExists(latestTagForLatestRelease))
) {
await this._postProcessDownload(latestTagForLatestRelease);
return;
}
await this._download(latestTagForLatestRelease);
if (await this._isBinaryPathExists(this._tag)) {
await this._postProcessDownload(this._tag);
return;
}

if (!(await this._isBinaryPathExists(this._tag))) {
await this._download(this._tag);
}
await this._download(this._tag);
}

private async _download(tag: any): Promise<void> {
Expand All @@ -99,12 +64,15 @@ export class RPCServerDownloader {
}
}

private async _isBinaryPathExists(version?: string): Promise<boolean> {
return fse.existsSync(await this.getBinaryPath(version));
private async _isBinaryPathExists(tag?: string): Promise<boolean> {
return fse.existsSync(await this.getBinaryPath(tag));
}

public async getBinaryPath(version?: string): Promise<string> {
return path.join(this._binaryDir, version || (await this._getReleaseTag()));
public async getBinaryPath(tag?: string): Promise<string> {
if (!tag && !this._tag) {
throw new ZkSyncNodePluginError('Tag is not set');
}
return path.join(this._binaryDir, tag || this._tag!);
}

private async _createBinaryPath(version: string): Promise<string> {
Expand All @@ -114,40 +82,44 @@ export class RPCServerDownloader {
private async _postProcessDownload(tag: string): Promise<void> {
const binaryPath = await this.getBinaryPath(tag);
fse.chmodSync(binaryPath, 0o755);

if (this._isLatestTag()) {
await fse.writeJSON(this._releaseInfoFilePath, { latest: tag });
}
}

private async _getReleaseTag() {
return this._isLatestTag() ? (await this._getLatestReleaseInfo()).latest : this._tag;
}

private async _isLatestReleaseInfoValid() {
if (!fse.existsSync(this._releaseInfoFilePath)) {
private async _isTagsInfoValid() {
if (!(await this._isTagsInfoExists())) {
return false;
}

const stats = await fse.stat(this._releaseInfoFilePath);
const stats = await fse.stat(this._tagsInfoFilePath);
const age = new Date().valueOf() - stats.ctimeMs;

return age < DEFAULT_RELEASE_VERSION_INFO_CACHE_PERIOD;
}

private async _isLatestReleaseInfoExists() {
return fse.existsSync(this._releaseInfoFilePath);
private async _isTagsInfoExists() {
return fse.existsSync(this._tagsInfoFilePath);
}

private async _getLatestReleaseInfo() {
if (!(await this._isLatestReleaseInfoExists())) {
private async _getTagsInfo() {
if (!(await this._isTagsInfoValid())) {
return undefined;
}

return await fse.readJSON(this._releaseInfoFilePath);
return await fse.readJSON(this._tagsInfoFilePath);
}

private _isLatestTag() {
return this._tag === 'latest';
private async _downloadTagInfo() {
const allTags = await getAllTags(
ZKNODE_BIN_OWNER,
ZKNODE_BIN_REPOSITORY_NAME,
USER_AGENT,
DEFAULT_TIMEOUT_MILISECONDS,
);
const latestTag = await getLatestRelease(
ZKNODE_BIN_OWNER,
ZKNODE_BIN_REPOSITORY_NAME,
USER_AGENT,
DEFAULT_TIMEOUT_MILISECONDS,
);
await fse.writeJSON(this._tagsInfoFilePath, { tags: allTags, latest: latestTag });
}
}
15 changes: 11 additions & 4 deletions packages/hardhat-zksync-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { spawn } from 'child_process';
import { task, subtask, types } from 'hardhat/config';
import { task, subtask, types, extendConfig } from 'hardhat/config';
import {
TASK_COMPILE,
TASK_NODE,
Expand All @@ -13,6 +13,7 @@ import { HARDHAT_NETWORK_NAME } from 'hardhat/plugins';
import { TaskArguments } from 'hardhat/types';
import path from 'path';
import {
DEFAULT_ZKSYNC_ANVIL_VERSION,
MAX_PORT_ATTEMPTS,
START_PORT,
TASK_NODE_ZKSYNC,
Expand All @@ -35,13 +36,19 @@ import { ZkSyncNodePluginError } from './errors';
import { interceptAndWrapTasksWithNode } from './core/global-interceptor';
import { runScriptWithHardhat } from './core/script-runner';

extendConfig((config, userConfig) => {
config.zksyncAnvil = {
version: userConfig.zksyncAnvil?.version || DEFAULT_ZKSYNC_ANVIL_VERSION,
};
});

task(TASK_RUN).setAction(async (args, hre, runSuper) => {
if (!hre.network.zksync || hre.network.name !== HARDHAT_NETWORK_NAME) {
await runSuper(args, hre);
return;
}

await runScriptWithHardhat(hre.hardhatArguments, path.resolve(args.script));
await runScriptWithHardhat(hre.hardhatArguments, hre.config.zksyncAnvil.version!, path.resolve(args.script));
});

// Subtask to download the binary
Expand All @@ -61,9 +68,9 @@ subtask(TASK_NODE_ZKSYNC_DOWNLOAD_BINARY, 'Downloads the JSON-RPC server binary'
) => {
// Directory where the binaries are stored
const rpcServerBinaryDir = await getRPCServerBinariesDir();

const version = tag || _hre.config.zksyncAnvil.version!;
// Get the latest release of the binary
const downloader: RPCServerDownloader = new RPCServerDownloader(rpcServerBinaryDir, tag || 'latest');
const downloader: RPCServerDownloader = new RPCServerDownloader(rpcServerBinaryDir, version);

// Download binary if needed
await downloader.downloadIfNeeded(force);
Expand Down
8 changes: 8 additions & 0 deletions packages/hardhat-zksync-node/src/type-extensions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import 'hardhat/types/config';
import { ZkSyncAnvilConfig } from './types';

declare module 'hardhat/types/config' {
interface HardhatUserConfig {
zksyncAnvil?: Partial<ZkSyncAnvilConfig>;
}

interface HardhatConfig {
zksyncAnvil: ZkSyncAnvilConfig;
}
interface HardhatNetworkUserConfig {
zksync?: boolean;
ethNetwork?: string;
Expand Down
4 changes: 4 additions & 0 deletions packages/hardhat-zksync-node/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ export interface CommandArguments {
forkBlockNumber?: number;
replayTx?: string;
}

export interface ZkSyncAnvilConfig {
version?: string;
}
Loading
Loading