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

Clonning era contracts repo and compiling locally system contracts #25

Merged
merged 31 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a94ab9e
download contract test working
May 15, 2024
693488c
extremely primitive version of clonning repo working
May 15, 2024
80d7409
added method to go to specific ref
May 16, 2024
f6966f2
better usage of new EraContractsRepo class
May 16, 2024
cacea50
Adapt code to new github client (async initialize). Remove github api…
May 16, 2024
a6cefa9
all commands working as before again
May 16, 2024
837ea6a
Added test for not found file
May 16, 2024
d0ac2ac
fmt and lint fixes
May 16, 2024
7b2c052
compiling from local repo
May 20, 2024
2fcbcd7
middle step. Test not passing
May 21, 2024
d2b4c1b
getting all contract hashes in a kind of straight forward way
May 21, 2024
eeb05c5
Replaced github client with era contracts repo
May 21, 2024
72fd3fa
added compile to pipeline
May 21, 2024
6ce76e5
taking default account and bootloader hashes from compiled versions
May 21, 2024
0052be9
fixing tests
May 22, 2024
c67c4ab
unit tests working again
May 22, 2024
c5fa141
little changes. wip
May 22, 2024
4a2bb0d
fmt and lint
calvogenerico May 28, 2024
e38a44d
ignore coverage in biome config
calvogenerico May 28, 2024
d5f7dea
wip
calvogenerico May 28, 2024
cb9c3d3
fixed download-diff tests
calvogenerico May 28, 2024
8f16e7a
fixed all tests
calvogenerico May 28, 2024
1aaafa2
fixed more tests
calvogenerico May 29, 2024
7052dd4
integration tests working again
calvogenerico May 29, 2024
eece625
lint and format fixes
calvogenerico May 29, 2024
49b967b
updated pnpm-lock.yaml
calvogenerico May 29, 2024
57a10b7
improved download code
calvogenerico May 30, 2024
89b7ce2
fmt:fix
calvogenerico May 30, 2024
2046dc4
fmt:fix
calvogenerico May 30, 2024
6795db1
Chore/fifty percent coverage (#28)
calvogenerico May 30, 2024
acc136a
removed fogotten debug line
calvogenerico May 31, 2024
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
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
"files": {
"include": ["*.js", "*.ts", "*.json", "*.yml", "*.md"],
"ignore": ["./dist/*", "./node_modules/*", "package.json", "**/__snapshots__/*"]
"ignore": ["./dist/*", "./node_modules/*", "package.json", "**/__snapshots__/*", "**/coverage/*"]
},
"organizeImports": {
"enabled": false
Expand Down
2 changes: 2 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
"chalk": "^5.3.0",
"cli-table3": "^0.6.4",
"dotenv": "^16.4.5",
"nochoices": "^1.1.4",
"ora": "^8.0.1",
"simple-git": "^3.24.0",
"tempy": "^3.1.0",
"tsup": "^8.0.2",
"tsx": "^4.7.2",
Expand Down
16 changes: 9 additions & 7 deletions cli/src/commands/check-command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { compareCurrentStateWith } from "../lib";
import { withSpinner } from "../lib/with-spinner.js";
import { calculateDiffWithUpgrade } from "../lib";
import type { EnvBuilder } from "../lib/env-builder.js";
import { withSpinner } from "../lib/with-spinner";

export async function checkCommand(env: EnvBuilder, upgradeDirectory: string): Promise<void> {
const { diff, l1Abis } = await withSpinner(
() => compareCurrentStateWith(env, upgradeDirectory),
"Gathering contract data"
const { diff } = await calculateDiffWithUpgrade(env, upgradeDirectory);

const report = await withSpinner(
async () => diff.toCliReport(env.l1Client(), upgradeDirectory, await env.contractsRepo()),
"Generating report"
);
const github = env.github();
console.log(await diff.toCliReport(l1Abis, upgradeDirectory, github));

console.log(report);
}
16 changes: 7 additions & 9 deletions cli/src/commands/contract-diff-command.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { compareCurrentStateWith } from "../lib";
import { calculateDiffWithUpgrade } from "../lib";
import { temporaryDirectory } from "tempy";
import { exec } from "node:child_process";
import { withSpinner } from "../lib/with-spinner.js";
import type { EnvBuilder } from "../lib/env-builder.js";

export const contractDiff = async (
env: EnvBuilder,
upgradeDirectory: string,
contractName: string
) => {
const github = env.github();
const repo = await env.contractsRepo();
const l2Client = env.l2Client();
const targetDir = await withSpinner(async (): Promise<string> => {
const { diff, l1Client } = await compareCurrentStateWith(env, upgradeDirectory);
const targetDir = temporaryDirectory({ prefix: "zksync-era-upgrade-check" });
await diff.writeCodeDiff(targetDir, [contractName], l1Client, l2Client, github);
return targetDir;
}, "Gathering contract data");

const targetDir = temporaryDirectory({ prefix: "zksync-era-upgrade-check" });
const l1Client = env.l1Client();
const { diff } = await calculateDiffWithUpgrade(env, upgradeDirectory);
await diff.writeCodeDiff(targetDir, [contractName], l1Client, l2Client, repo);

await new Promise((resolve, reject) => {
const res = exec(
Expand Down
15 changes: 6 additions & 9 deletions cli/src/commands/download-code-command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { compareCurrentStateWith } from "../lib";
import { calculateDiffWithUpgrade } from "../lib";

import { withSpinner } from "../lib/with-spinner.js";
import type { EnvBuilder } from "../lib/env-builder.js";
Expand All @@ -11,18 +11,15 @@ export async function downloadCode(
l1Filter: string[]
): Promise<void> {
await assertDirectoryExists(targetDir);
const { diff } = await calculateDiffWithUpgrade(env, upgradeDirectory);

const l2Client = env.l2Client();
const github = env.github();

const { diff, l1Client } = await withSpinner(
() => compareCurrentStateWith(env, upgradeDirectory),
"Gathering contract data"
);
const repo = await env.contractsRepo();

await withSpinner(
() => diff.writeCodeDiff(targetDir, l1Filter, l1Client, l2Client, github),
"Downloading source code"
() => diff.writeCodeDiff(targetDir, l1Filter, env.l1Client(), l2Client, repo),
"Downloading all source code"
);

console.log(`✅ Source code successfully downloaded in: ${targetDir}`);
}
45 changes: 0 additions & 45 deletions cli/src/lib/abi-set.ts

This file was deleted.

22 changes: 13 additions & 9 deletions cli/src/lib/block-explorer-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {
import { ERA_BLOCK_EXPLORER_ENDPOINTS, ETHERSCAN_ENDPOINTS, type Network } from "./constants.js";
import type { z, ZodType } from "zod";
import { ContractData } from "./contract-data.js";
import * as console from "node:console";
import { ContracNotVerified } from "./errors.js";
import { ContracNotVerified, ExternalApiError } from "./errors.js";
import { ContractAbi } from "./contract-abi";

export class BlockExplorerClient {
private apiKey: string;
baseUri: string;
private abiCache: Map<string, Abi>;
private abiCache: Map<string, ContractAbi>;
private sourceCache: Map<string, ContractData>;
private contractsNotVerified: Set<string>;
private callCount = 0;
Expand Down Expand Up @@ -43,15 +43,18 @@ export class BlockExplorerClient {

const response = await fetch(`${this.baseUri}?${query}`);
if (!response.ok) {
throw new Error(`Received error from block explorer: ${await response.text()}`);
throw new ExternalApiError(
"Block Explorer",
`error accessing api. url=${this.baseUri}, status=${response.status}.`
);
}

this.callCount++;

return parser.parse(await response.json());
}

async getAbi(rawAddress: string): Promise<Abi> {
async getAbi(rawAddress: string): Promise<ContractAbi> {
const existing = this.abiCache.get(rawAddress);
if (existing) {
return existing;
Expand All @@ -70,10 +73,10 @@ export class BlockExplorerClient {
);

if (message !== "OK") {
throw new Error(`Failed to fetch ABI for ${rawAddress}`);
throw new ExternalApiError("BlockExplorer", `Cannot get abi for ${rawAddress}`);
}

const abi = JSON.parse(result);
const abi = new ContractAbi(JSON.parse(result));
this.abiCache.set(rawAddress, abi);
return abi;
}
Expand Down Expand Up @@ -111,14 +114,15 @@ export class BlockExplorerClient {
throw new ContracNotVerified(rawAddress);
}

const abi = JSON.parse(result[0].ABI);
const abi = new ContractAbi(JSON.parse(result[0].ABI));
this.abiCache.set(rawAddress, abi);

try {
const rawSourceCode = result[0].SourceCode.replace(/^\{\{/, "{").replace(/}}$/, "}");
const SourceCode = sourceCodeSchema.parse(JSON.parse(rawSourceCode));
const data = new ContractData(result[0].ContractName, SourceCode.sources, contractAddr);
this.sourceCache.set(rawAddress, data);
data.remapKeys("cache/solpp-generated-contracts", "contracts");
return data;
} catch (e) {
// This means that the response was not an object, instead it was a string with the source code.
Expand Down Expand Up @@ -151,7 +155,7 @@ export class BlockExplorerClient {
}
}

static fromNetwork(apiKey: string, network: Network): BlockExplorerClient {
static forL1(apiKey: string, network: Network): BlockExplorerClient {
const baseUri = ETHERSCAN_ENDPOINTS[network];
return new BlockExplorerClient(apiKey, baseUri);
}
Expand Down
40 changes: 20 additions & 20 deletions cli/src/lib/cli.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import yargs from "yargs";
import yargs, { type Argv } from "yargs";
import { hideBin } from "yargs/helpers";
import { NetworkSchema } from ".";
import { downloadCode, checkCommand, contractDiff } from "../commands";
Expand All @@ -7,29 +7,25 @@ import { EnvBuilder } from "./env-builder.js";
import * as console from "node:console";
import { printError } from "./errors.js";

export const cli = async () => {
// printIntro();
export function buildCli(
args: string[],
checkCbk: typeof checkCommand,
diffCbk: typeof contractDiff,
downloadCodeCbk: typeof downloadCode
): Argv {
const env = new EnvBuilder();

const argParser = yargs(hideBin(process.argv))
const argParser = yargs(args)
.middleware((yargs) => {
if (!yargs.ethscankey) {
yargs.ethscankey = process.env.ETHERSCAN_API_KEY;
}
if (!yargs.githubApiKey) {
yargs.githubApiKey = process.env.API_KEY_GITHUB;
}
}, true)
.option("ethscankey", {
describe: "Api key for etherscan",
type: "string",
demandOption:
"Please provide a valid Etherscan api key. You can set ETHERSCAN_API_KEY env var or use the option --ethscankey",
})
.option("githubApiKey", {
describe: "Api key for github",
type: "string",
})
.option("network", {
alias: "n",
describe: "network to check",
Expand All @@ -52,7 +48,6 @@ export const cli = async () => {
env.withNetwork(NetworkSchema.parse(yargs.network));
env.withRpcUrl(yargs.rpcUrl);
env.withEtherscanApiKey(yargs.ethscankey);
env.withGithubApiKey(yargs.githubApiKey);
env.withRef(yargs.ref);
})
.command(
Expand All @@ -65,7 +60,7 @@ export const cli = async () => {
demandOption: true,
}),
async (yargs) => {
await checkCommand(env, yargs.upgradeDirectory);
await checkCbk(env, yargs.upgradeDirectory);
}
)
.command(
Expand All @@ -84,7 +79,7 @@ export const cli = async () => {
demandOption: true,
}),
async (yargs) => {
await contractDiff(env, yargs.upgradeDir, `facet:${yargs.facetName}`);
await diffCbk(env, yargs.upgradeDir, `facet:${yargs.facetName}`);
}
)
.command(
Expand All @@ -97,7 +92,7 @@ export const cli = async () => {
demandOption: true,
}),
async (yargs) => {
await contractDiff(env, yargs.upgradeDir, "verifier");
await diffCbk(env, yargs.upgradeDir, "verifier");
}
)
.command(
Expand Down Expand Up @@ -149,7 +144,7 @@ export const cli = async () => {
.map((sc) => `sc:${sc}`)
);

await downloadCode(env, yargs.upgradeDir, yargs.targetSourceCodeDir, filter);
await downloadCodeCbk(env, yargs.upgradeDir, yargs.targetSourceCodeDir, filter);
}
)
.demandCommand(1, "Please specify a command")
Expand All @@ -160,15 +155,20 @@ export const cli = async () => {
const help = await argParser.getHelp();
console.log(help);
console.log("");
// console.log(_yargs.help())
console.log(msg);
process.exit(1);
// process.exit(1);
return;
}

printError(err);
process.exit(1);
// process.exit(1);
})
.strict();

return argParser;
}

export const cli = async () => {
const argParser = buildCli(hideBin(process.argv), checkCommand, contractDiff, downloadCode);
await argParser.parseAsync();
};
45 changes: 22 additions & 23 deletions cli/src/lib/compare-current-state-with.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import { AbiSet, type BlockExplorerClient, ZkSyncEraState, type ZkSyncEraDiff } from ".";
import { ZkSyncEraState, type ZkSyncEraDiff } from ".";
import type { EnvBuilder } from "./env-builder.js";
import { withSpinner } from "./with-spinner";

type CreateDiffResponse = {
diff: ZkSyncEraDiff;
l1Abis: AbiSet;
l1Client: BlockExplorerClient;
};

export async function compareCurrentStateWith(
export async function calculateDiffWithUpgrade(
env: EnvBuilder,
upgradeDirectory: string
): Promise<CreateDiffResponse> {
const importer = env.importer();
): Promise<{ diff: ZkSyncEraDiff; state: ZkSyncEraState }> {
const changes = await withSpinner(async () => {
const importer = env.importer();
return importer.readFromFiles(upgradeDirectory, env.network);
}, "Reading proposed upgrade...");

const state = await withSpinner(async () => {
const l1Client = env.l1Client();
return ZkSyncEraState.create(env.network, l1Client, env.rpcL1(), env.rpcL2());
}, "Gathering contract data");

const changes = await importer.readFromFiles(upgradeDirectory, env.network);
const diff = await withSpinner(async () => {
return state.calculateDiff(changes, env.l1Client());
}, "Checking differences between versions");

const l1Client = env.l1Client();
const l1Abis = new AbiSet(l1Client);
const zkSyncState = await ZkSyncEraState.create(
env.network,
l1Client,
l1Abis,
env.rpcL1(),
env.rpcL2()
);
await withSpinner(async () => {
const repo = await env.contractsRepo();
await repo.compileSystemContracts();
}, "Compiling system contracts");

return {
diff: await zkSyncState.calculateDiff(changes, l1Client),
l1Abis,
l1Client,
diff,
state,
};
}
2 changes: 1 addition & 1 deletion cli/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const ETHERSCAN_ENDPOINTS = {

export const ERA_BLOCK_EXPLORER_ENDPOINTS = {
mainnet: "https://block-explorer-api.mainnet.zksync.io/api",
sepolia: "https://block-explorer-api.sepolia.zksync.dev",
sepolia: "https://block-explorer-api.sepolia.zksync.dev/api",
} as const;

export const NetworkSchema = z.enum(["mainnet", "sepolia"]);
Expand Down
Loading
Loading